rsync-3.2.7/0000775000000000000000000000000014324367162011371 5ustar rootrootrsync-3.2.7/flist.c0000664000000000000000000026663414316341136012671 0ustar rootroot/* * Generate and receive file lists. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2002-2022 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" #include "rounding.h" #include "inums.h" #include "io.h" extern int am_root; extern int am_server; extern int am_daemon; extern int am_sender; extern int am_generator; extern int inc_recurse; extern int always_checksum; extern int module_id; extern int ignore_errors; extern int numeric_ids; extern int quiet; extern int recurse; extern int use_qsort; extern int xfer_dirs; extern int filesfrom_fd; extern int one_file_system; extern int copy_devices; extern int copy_dirlinks; extern int preserve_uid; extern int preserve_gid; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; extern int delete_during; extern int missing_args; extern int eol_nulls; extern int atimes_ndx; extern int crtimes_ndx; extern int relative_paths; extern int implied_dirs; extern int ignore_perishable; extern int non_perishable_cnt; extern int prune_empty_dirs; extern int copy_links; extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; extern int munge_symlinks; extern int use_safe_inc_flist; extern int need_unsorted_flist; extern int sender_symlink_iconv; extern int output_needs_newline; extern int sender_keeps_checksum; extern int trust_sender_filter; extern int unsort_ndx; extern uid_t our_uid; extern struct stats stats; extern char *filesfrom_host; extern char *usermap, *groupmap; extern struct name_num_item *file_sum_nni; extern char curr_dir[MAXPATHLEN]; extern struct chmod_mode_struct *chmod_modes; extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list; #ifdef ICONV_OPTION extern int filesfrom_convert; extern iconv_t ic_send, ic_recv; #endif #define PTR_SIZE (sizeof (struct file_struct *)) int io_error; int flist_csum_len; dev_t filesystem_dev; /* used to implement -x */ struct file_list *cur_flist, *first_flist, *dir_flist; int send_dir_ndx = -1, send_dir_depth = -1; int flist_cnt = 0; /* how many (non-tmp) file list objects exist */ int file_total = 0; /* total of all active items over all file-lists */ int file_old_total = 0; /* total of active items that will soon be gone */ int flist_eof = 0; /* all the file-lists are now known */ int xfer_flags_as_varint = 0; #define NORMAL_NAME 0 #define SLASH_ENDING_NAME 1 #define DOTDIR_NAME 2 #define MISSING_NAME 3 /* Starting from protocol version 26, we always use 64-bit ino_t and dev_t * internally, even if this platform does not allow files to have 64-bit inums. * The only exception is if we're on a platform with no 64-bit type at all. * * Because we use read_longint() to get these off the wire, if you transfer * devices or (for protocols < 30) hardlinks with dev or inum > 2**32 to a * machine with no 64-bit types then you will get an overflow error. * * Note that if you transfer devices from a 64-bit-devt machine (say, Solaris) * to a 32-bit-devt machine (say, Linux-2.2/x86) then the device numbers will * be truncated. But it's a kind of silly thing to do anyhow. */ /* The tmp_* vars are used as a cache area by make_file() to store data * that the sender doesn't need to remember in its file list. The data * will survive just long enough to be used by send_file_entry(). */ static dev_t tmp_rdev; #ifdef SUPPORT_HARD_LINKS static int64 tmp_dev = -1, tmp_ino; #endif static char tmp_sum[MAX_DIGEST_LEN]; static char empty_sum[MAX_DIGEST_LEN]; static int flist_count_offset; /* for --delete --progress */ static int show_filelist_progress; static struct file_list *flist_new(int flags, const char *msg); static void flist_sort_and_clean(struct file_list *flist, int strip_root); static void output_flist(struct file_list *flist); void init_flist(void) { if (DEBUG_GTE(FLIST, 4)) { rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n", (int)FILE_STRUCT_LEN, (int)EXTRA_LEN); } /* Note that this isn't identical to file_sum_len in the case of CSUM_MD4_ARCHAIC: */ flist_csum_len = csum_len_for_type(file_sum_nni->num, 1); show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse; } static void start_filelist_progress(char *kind) { if (quiet) return; rprintf(FCLIENT, "%s ... ", kind); output_needs_newline = 1; rflush(FINFO); } static void emit_filelist_progress(int count) { if (quiet) return; if (output_needs_newline == 2) /* avoid a newline in the middle of this filelist-progress output */ output_needs_newline = 0; rprintf(FCLIENT, " %d files...\r", count); output_needs_newline = 2; } static void maybe_emit_filelist_progress(int count) { if (INFO_GTE(FLIST, 2) && show_filelist_progress && (count % 100) == 0) emit_filelist_progress(count); } static void finish_filelist_progress(const struct file_list *flist) { output_needs_newline = 0; if (INFO_GTE(FLIST, 2)) { /* This overwrites the progress line */ rprintf(FINFO, "%d file%sto consider\n", flist->used, flist->used == 1 ? " " : "s "); } else { rprintf(FINFO, "done\n"); } } void show_flist_stats(void) { /* Nothing yet */ } /* Stat either a symlink or its referent, depending on the settings of * copy_links, copy_unsafe_links, etc. Returns -1 on error, 0 on success. * * If path is the name of a symlink, then the linkbuf buffer (which must hold * MAXPATHLEN chars) will be set to the symlink's target string. * * The stat structure pointed to by stp will contain information about the * link or the referent as appropriate, if they exist. */ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) { #ifdef SUPPORT_LINKS if (link_stat(path, stp, copy_dirlinks) < 0) return -1; if (S_ISLNK(stp->st_mode)) { int llen = do_readlink(path, linkbuf, MAXPATHLEN - 1); if (llen < 0) return -1; linkbuf[llen] = '\0'; if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) { if (INFO_GTE(SYMSAFE, 1)) { rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n", path, linkbuf); } return x_stat(path, stp, NULL); } if (munge_symlinks && am_sender && llen > SYMLINK_PREFIX_LEN && strncmp(linkbuf, SYMLINK_PREFIX, SYMLINK_PREFIX_LEN) == 0) { memmove(linkbuf, linkbuf + SYMLINK_PREFIX_LEN, llen - SYMLINK_PREFIX_LEN + 1); } } return 0; #else return x_stat(path, stp, NULL); #endif } int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) { #ifdef SUPPORT_LINKS if (copy_links) return x_stat(path, stp, NULL); if (x_lstat(path, stp, NULL) < 0) return -1; if (follow_dirlinks && S_ISLNK(stp->st_mode)) { STRUCT_STAT st; if (x_stat(path, &st, NULL) == 0 && S_ISDIR(st.st_mode)) *stp = st; } return 0; #else return x_stat(path, stp, NULL); #endif } static inline int path_is_daemon_excluded(char *path, int ignore_filename) { if (daemon_filter_list.head) { char *slash = path; while ((slash = strchr(slash+1, '/')) != NULL) { int ret; *slash = '\0'; ret = check_filter(&daemon_filter_list, FLOG, path, 1); *slash = '/'; if (ret < 0) { errno = ENOENT; return 1; } } if (!ignore_filename && check_filter(&daemon_filter_list, FLOG, path, 1) < 0) { errno = ENOENT; return 1; } } return 0; } static inline int is_excluded(const char *fname, int is_dir, int filter_level) { return name_is_excluded(fname, is_dir ? NAME_IS_DIR : NAME_IS_FILE, filter_level); } static void send_directory(int f, struct file_list *flist, char *fbuf, int len, int flags); static const char *pathname, *orig_dir; static int pathname_len; /* Make sure flist can hold at least flist->used + extra entries. */ static void flist_expand(struct file_list *flist, int extra) { struct file_struct **new_ptr; if (flist->used + extra <= flist->malloced) return; if (flist->malloced < FLIST_START) flist->malloced = FLIST_START; else if (flist->malloced >= FLIST_LINEAR) flist->malloced += FLIST_LINEAR; else if (flist->malloced < FLIST_START_LARGE/16) flist->malloced *= 4; else flist->malloced *= 2; /* In case count jumped or we are starting the list * with a known size just set it. */ if (flist->malloced < flist->used + extra) flist->malloced = flist->used + extra; new_ptr = realloc_array(flist->files, struct file_struct *, flist->malloced); if (DEBUG_GTE(FLIST, 1) && flist->files) { rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n", who_am_i(), big_num(sizeof flist->files[0] * flist->malloced), (new_ptr == flist->files) ? " not" : ""); } flist->files = new_ptr; } static void flist_done_allocating(struct file_list *flist) { void *ptr = pool_boundary(flist->file_pool, 8*1024); if (flist->pool_boundary == ptr) flist->pool_boundary = NULL; /* list didn't use any pool memory */ else flist->pool_boundary = ptr; } /* 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 * indicating that strdup(dir) should be called and then the -dirlen length * value checked to ensure that it is not daemon-excluded. */ int change_pathname(struct file_struct *file, const char *dir, int dirlen) { if (dirlen < 0) { char *cpy = strdup(dir); if (*cpy != '/') change_dir(orig_dir, CD_SKIP_CHDIR); if (path_is_daemon_excluded(cpy, 0)) goto chdir_error; dir = cpy; dirlen = -dirlen; } else { if (file) { if (pathname == F_PATHNAME(file)) return 1; dir = F_PATHNAME(file); if (dir) dirlen = strlen(dir); } else if (pathname == dir) return 1; if (dir && *dir != '/') change_dir(orig_dir, CD_SKIP_CHDIR); } pathname = dir; pathname_len = dirlen; if (!dir) dir = orig_dir; if (!change_dir(dir, CD_NORMAL)) { chdir_error: io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "change_dir %s failed", full_fname(dir)); if (dir != orig_dir) change_dir(orig_dir, CD_NORMAL); pathname = NULL; pathname_len = 0; return 0; } return 1; } static void send_file_entry(int f, const char *fname, struct file_struct *file, #ifdef SUPPORT_LINKS const char *symlink_name, int symlink_len, #endif int ndx, int first_ndx) { static time_t modtime, atime; #ifdef SUPPORT_CRTIMES static time_t crtime; #endif static mode_t mode; #ifdef SUPPORT_HARD_LINKS static int64 dev; #endif static dev_t rdev; static uint32 rdev_major; static uid_t uid; static gid_t gid; static const char *user_name, *group_name; static char lastname[MAXPATHLEN]; #ifdef SUPPORT_HARD_LINKS int first_hlink_ndx = -1; #endif int l1, l2; int xflags; /* Initialize starting value of xflags and adjust counts. */ if (S_ISREG(file->mode)) xflags = 0; else if (S_ISDIR(file->mode)) { stats.num_dirs++; if (protocol_version >= 30) { if (file->flags & FLAG_CONTENT_DIR) xflags = file->flags & FLAG_TOP_DIR; else if (file->flags & FLAG_IMPLIED_DIR) xflags = XMIT_TOP_DIR | XMIT_NO_CONTENT_DIR; else xflags = XMIT_NO_CONTENT_DIR; } else xflags = file->flags & FLAG_TOP_DIR; /* FLAG_TOP_DIR == XMIT_TOP_DIR */ } else { if (S_ISLNK(file->mode)) stats.num_symlinks++; else if (IS_DEVICE(file->mode)) stats.num_devices++; else if (IS_SPECIAL(file->mode)) stats.num_specials++; xflags = 0; } if (file->mode == mode) xflags |= XMIT_SAME_MODE; else mode = file->mode; if (preserve_devices && IS_DEVICE(mode)) { if (protocol_version < 28) { if (tmp_rdev == rdev) xflags |= XMIT_SAME_RDEV_pre28; else rdev = tmp_rdev; } else { rdev = tmp_rdev; if ((uint32)major(rdev) == rdev_major) xflags |= XMIT_SAME_RDEV_MAJOR; else rdev_major = major(rdev); if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu) xflags |= XMIT_RDEV_MINOR_8_pre30; } } else if (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31) { /* Special files don't need an rdev number, so just make * the historical transmission of the value efficient. */ if (protocol_version < 28) xflags |= XMIT_SAME_RDEV_pre28; else { rdev = MAKEDEV(rdev_major, 0); xflags |= XMIT_SAME_RDEV_MAJOR; if (protocol_version < 30) xflags |= XMIT_RDEV_MINOR_8_pre30; } } else if (protocol_version < 28) rdev = MAKEDEV(0, 0); if (!preserve_uid || ((uid_t)F_OWNER(file) == uid && *lastname)) xflags |= XMIT_SAME_UID; else { uid = F_OWNER(file); if (!numeric_ids) { user_name = add_uid(uid); if (inc_recurse && user_name) xflags |= XMIT_USER_NAME_FOLLOWS; } } if (!preserve_gid || ((gid_t)F_GROUP(file) == gid && *lastname)) xflags |= XMIT_SAME_GID; else { gid = F_GROUP(file); if (!numeric_ids) { group_name = add_gid(gid); if (inc_recurse && group_name) xflags |= XMIT_GROUP_NAME_FOLLOWS; } } if (file->modtime == modtime) xflags |= XMIT_SAME_TIME; else modtime = file->modtime; if (NSEC_BUMP(file) && protocol_version >= 31) xflags |= XMIT_MOD_NSEC; if (atimes_ndx && !S_ISDIR(mode)) { if (F_ATIME(file) == atime) xflags |= XMIT_SAME_ATIME; else atime = F_ATIME(file); } #ifdef SUPPORT_CRTIMES if (crtimes_ndx) { crtime = F_CRTIME(file); if (crtime == modtime) xflags |= XMIT_CRTIME_EQ_MTIME; } #endif #ifdef SUPPORT_HARD_LINKS if (tmp_dev != -1) { if (protocol_version >= 30) { struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino); first_hlink_ndx = (int32)(long)np->data; /* is -1 when new */ if (first_hlink_ndx < 0) { np->data = (void*)(long)(first_ndx + ndx); xflags |= XMIT_HLINK_FIRST; } if (DEBUG_GTE(HLINK, 1)) { if (first_hlink_ndx >= 0) { rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n", who_am_i(), first_ndx + ndx, first_hlink_ndx, first_hlink_ndx >= first_ndx ? "" : "un"); } else if (DEBUG_GTE(HLINK, 3)) { rprintf(FINFO, "[%s] dev:inode for #%d is %s:%s\n", who_am_i(), first_ndx + ndx, big_num(tmp_dev), big_num(tmp_ino)); } } } else { if (tmp_dev == dev) { if (protocol_version >= 28) xflags |= XMIT_SAME_DEV_pre30; } else dev = tmp_dev; } xflags |= XMIT_HLINKED; } #endif for (l1 = 0; lastname[l1] && (fname[l1] == lastname[l1]) && (l1 < 255); l1++) {} l2 = strlen(fname+l1); if (l1 > 0) xflags |= XMIT_SAME_NAME; if (l2 > 255) xflags |= XMIT_LONG_NAME; /* We must avoid sending a flag value of 0 (or an initial byte of * 0 for the older xflags protocol) or it will signal the end of * the list. Note that the use of XMIT_TOP_DIR on a non-dir has * no meaning, so it's a harmless way to add a bit to the first * flag byte. */ if (xfer_flags_as_varint) write_varint(f, xflags ? xflags : XMIT_EXTENDED_FLAGS); else if (protocol_version >= 28) { if (!xflags && !S_ISDIR(mode)) xflags |= XMIT_TOP_DIR; if ((xflags & 0xFF00) || !xflags) { xflags |= XMIT_EXTENDED_FLAGS; write_shortint(f, xflags); } else write_byte(f, xflags); } else { if (!(xflags & 0xFF)) xflags |= S_ISDIR(mode) ? XMIT_LONG_NAME : XMIT_TOP_DIR; write_byte(f, xflags); } if (xflags & XMIT_SAME_NAME) write_byte(f, l1); if (xflags & XMIT_LONG_NAME) write_varint30(f, l2); else write_byte(f, l2); write_buf(f, fname + l1, l2); #ifdef SUPPORT_HARD_LINKS if (first_hlink_ndx >= 0) { write_varint(f, first_hlink_ndx); if (first_hlink_ndx >= first_ndx) goto the_end; } #endif write_varlong30(f, F_LENGTH(file), 3); if (!(xflags & XMIT_SAME_TIME)) { if (protocol_version >= 30) write_varlong(f, modtime, 4); else write_int(f, modtime); } if (xflags & XMIT_MOD_NSEC) write_varint(f, F_MOD_NSEC(file)); #ifdef SUPPORT_CRTIMES if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME)) write_varlong(f, crtime, 4); #endif if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) write_varlong(f, atime, 4); if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) write_int(f, uid); else { write_varint(f, uid); if (xflags & XMIT_USER_NAME_FOLLOWS) { int len = strlen(user_name); write_byte(f, len); write_buf(f, user_name, len); } } } if (preserve_gid && !(xflags & XMIT_SAME_GID)) { if (protocol_version < 30) write_int(f, gid); else { write_varint(f, gid); if (xflags & XMIT_GROUP_NAME_FOLLOWS) { int len = strlen(group_name); write_byte(f, len); write_buf(f, group_name, len); } } } if ((preserve_devices && IS_DEVICE(mode)) || (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31)) { if (protocol_version < 28) { if (!(xflags & XMIT_SAME_RDEV_pre28)) write_int(f, (int)rdev); } else { if (!(xflags & XMIT_SAME_RDEV_MAJOR)) write_varint30(f, major(rdev)); if (protocol_version >= 30) write_varint(f, minor(rdev)); else if (xflags & XMIT_RDEV_MINOR_8_pre30) write_byte(f, minor(rdev)); else write_int(f, minor(rdev)); } } #ifdef SUPPORT_LINKS if (symlink_len) { write_varint30(f, symlink_len); write_buf(f, symlink_name, symlink_len); } #endif #ifdef SUPPORT_HARD_LINKS if (tmp_dev != -1 && protocol_version < 30) { /* Older protocols expect the dev number to be transmitted * 1-incremented so that it is never zero. */ if (protocol_version < 26) { /* 32-bit dev_t and ino_t */ write_int(f, (int32)(dev+1)); write_int(f, (int32)tmp_ino); } else { /* 64-bit dev_t and ino_t */ if (!(xflags & XMIT_SAME_DEV_pre30)) write_longint(f, dev+1); write_longint(f, tmp_ino); } } #endif if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) { const char *sum; if (S_ISREG(mode)) sum = tmp_sum; else { /* Prior to 28, we sent a useless set of nulls. */ sum = empty_sum; } write_buf(f, sum, flist_csum_len); } #ifdef SUPPORT_HARD_LINKS the_end: #endif strlcpy(lastname, fname, MAXPATHLEN); if (S_ISREG(mode) || S_ISLNK(mode)) stats.total_size += F_LENGTH(file); } static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags) { static int64 modtime, atime; #ifdef SUPPORT_CRTIMES static time_t crtime; #endif static mode_t mode; #ifdef SUPPORT_HARD_LINKS static int64 dev; #endif static dev_t rdev; static uint32 rdev_major; static uid_t uid; static gid_t gid; static uint16 gid_flags; static char lastname[MAXPATHLEN], *lastdir; static int lastdir_depth, lastdir_len = -1; static unsigned int del_hier_name_len = 0; static int in_del_hier = 0; char thisname[MAXPATHLEN]; unsigned int l1 = 0, l2 = 0; int alloc_len, basename_len, linkname_len; int extra_len = file_extra_cnt * EXTRA_LEN; int first_hlink_ndx = -1; char real_ISREG_entry; int64 file_length; #ifdef CAN_SET_NSEC uint32 modtime_nsec; #endif const char *basename; struct file_struct *file; alloc_pool_t *pool; char *bp; if (xflags & XMIT_SAME_NAME) l1 = read_byte(f); if (xflags & XMIT_LONG_NAME) l2 = read_varint30(f); else l2 = read_byte(f); if (l2 >= MAXPATHLEN - l1) { rprintf(FERROR, "overflow: xflags=0x%x l1=%d l2=%d lastname=%s [%s]\n", xflags, l1, l2, lastname, who_am_i()); overflow_exit("recv_file_entry"); } strlcpy(thisname, lastname, l1 + 1); read_sbuf(f, &thisname[l1], l2); thisname[l1 + l2] = 0; /* Abuse basename_len for a moment... */ basename_len = strlcpy(lastname, thisname, MAXPATHLEN); #ifdef ICONV_OPTION if (ic_recv != (iconv_t)-1) { xbuf outbuf, inbuf; INIT_CONST_XBUF(outbuf, thisname); INIT_XBUF(inbuf, lastname, basename_len, (size_t)-1); if (iconvbufs(ic_recv, &inbuf, &outbuf, ICB_INIT) < 0) { io_error |= IOERR_GENERAL; rprintf(FERROR_UTF8, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), lastname, strerror(errno)); outbuf.len = 0; } thisname[outbuf.len] = '\0'; } #endif if (*thisname && (clean_fname(thisname, CFN_REFUSE_DOT_DOT_DIRS) < 0 || (!relative_paths && *thisname == '/'))) { rprintf(FERROR, "ABORTING due to unsafe pathname from sender: %s\n", thisname); exit_cleanup(RERR_UNSUPPORTED); } if (sanitize_paths) sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); if ((basename = strrchr(thisname, '/')) != NULL) { int len = basename++ - thisname; if (len != lastdir_len || memcmp(thisname, lastdir, len) != 0) { lastdir = new_array(char, len + 1); memcpy(lastdir, thisname, len); lastdir[len] = '\0'; lastdir_len = len; lastdir_depth = count_dir_elements(lastdir); } } else basename = thisname; basename_len = strlen(basename) + 1; /* count the '\0' */ #ifdef SUPPORT_HARD_LINKS if (protocol_version >= 30 && BITS_SETnUNSET(xflags, XMIT_HLINKED, XMIT_HLINK_FIRST)) { first_hlink_ndx = read_varint(f); if (first_hlink_ndx < 0 || first_hlink_ndx >= flist->ndx_start + flist->used) { rprintf(FERROR, "hard-link reference out of range: %d (%d)\n", first_hlink_ndx, flist->ndx_start + flist->used); exit_cleanup(RERR_PROTOCOL); } if (DEBUG_GTE(HLINK, 1)) { rprintf(FINFO, "[%s] #%d hard-links #%d (%sabbrev)\n", who_am_i(), flist->used+flist->ndx_start, first_hlink_ndx, first_hlink_ndx >= flist->ndx_start ? "" : "un"); } if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; file_length = F_LENGTH(first); modtime = first->modtime; #ifdef CAN_SET_NSEC modtime_nsec = F_MOD_NSEC_or_0(first); #endif mode = first->mode; if (atimes_ndx && !S_ISDIR(mode)) atime = F_ATIME(first); #ifdef SUPPORT_CRTIMES if (crtimes_ndx) crtime = F_CRTIME(first); #endif if (preserve_uid) uid = F_OWNER(first); if (preserve_gid) gid = F_GROUP(first); if (preserve_devices && IS_DEVICE(mode)) { uint32 *devp = F_RDEV_P(first); rdev_major = DEV_MAJOR(devp); rdev = MAKEDEV(rdev_major, DEV_MINOR(devp)); extra_len += DEV_EXTRA_CNT * EXTRA_LEN; } if (preserve_links && S_ISLNK(mode)) linkname_len = strlen(F_SYMLINK(first)) + 1; else linkname_len = 0; real_ISREG_entry = S_ISREG(mode) ? 1 : 0; goto create_object; } } #endif file_length = read_varlong30(f, 3); if (!(xflags & XMIT_SAME_TIME)) { if (protocol_version >= 30) { modtime = read_varlong(f, 4); #if SIZEOF_TIME_T < SIZEOF_INT64 if (!am_generator && (int64)(time_t)modtime != modtime) { rprintf(FERROR_XFER, "Time value of %s truncated on receiver.\n", lastname); } #endif } else modtime = read_uint(f); } if (xflags & XMIT_MOD_NSEC) #ifndef CAN_SET_NSEC (void)read_varint(f); #else modtime_nsec = read_varint(f); else modtime_nsec = 0; #endif #ifdef SUPPORT_CRTIMES if (crtimes_ndx) { if (xflags & XMIT_CRTIME_EQ_MTIME) crtime = modtime; else crtime = read_varlong(f, 4); #if SIZEOF_TIME_T < SIZEOF_INT64 if (!am_generator && (int64)(time_t)crtime != crtime) { rprintf(FERROR_XFER, "Create time value of %s truncated on receiver.\n", lastname); } #endif } #endif if (!(xflags & XMIT_SAME_MODE)) mode = from_wire_mode(read_int(f)); if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) { atime = read_varlong(f, 4); #if SIZEOF_TIME_T < SIZEOF_INT64 if (!am_generator && (int64)(time_t)atime != atime) { rprintf(FERROR_XFER, "Access time value of %s truncated on receiver.\n", lastname); } #endif } if (chmod_modes && !S_ISLNK(mode) && mode) mode = tweak_mode(mode, chmod_modes); if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) uid = (uid_t)read_int(f); else { uid = (uid_t)read_varint(f); if (xflags & XMIT_USER_NAME_FOLLOWS) uid = recv_user_name(f, uid); else if (inc_recurse && am_root && (!numeric_ids || usermap)) uid = match_uid(uid); } } if (preserve_gid && !(xflags & XMIT_SAME_GID)) { if (protocol_version < 30) gid = (gid_t)read_int(f); else { gid = (gid_t)read_varint(f); gid_flags = 0; if (xflags & XMIT_GROUP_NAME_FOLLOWS) gid = recv_group_name(f, gid, &gid_flags); else if (inc_recurse && (!am_root || !numeric_ids || groupmap)) gid = match_gid(gid, &gid_flags); } } if ((preserve_devices && IS_DEVICE(mode)) || (preserve_specials && IS_SPECIAL(mode) && protocol_version < 31)) { if (protocol_version < 28) { if (!(xflags & XMIT_SAME_RDEV_pre28)) rdev = (dev_t)read_int(f); } else { uint32 rdev_minor; if (!(xflags & XMIT_SAME_RDEV_MAJOR)) rdev_major = read_varint30(f); if (protocol_version >= 30) rdev_minor = read_varint(f); else if (xflags & XMIT_RDEV_MINOR_8_pre30) rdev_minor = read_byte(f); else rdev_minor = read_int(f); rdev = MAKEDEV(rdev_major, rdev_minor); } if (IS_DEVICE(mode)) extra_len += DEV_EXTRA_CNT * EXTRA_LEN; file_length = 0; } else if (protocol_version < 28) rdev = MAKEDEV(0, 0); #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(mode)) { linkname_len = read_varint30(f) + 1; /* count the '\0' */ if (linkname_len <= 0 || linkname_len > MAXPATHLEN) { rprintf(FERROR, "overflow: linkname_len=%d\n", linkname_len - 1); overflow_exit("recv_file_entry"); } #ifdef ICONV_OPTION /* We don't know how much extra room we need to convert * the as-yet-unread symlink data, so let's hope that a * double-size buffer is plenty. */ if (sender_symlink_iconv) linkname_len *= 2; #endif if (munge_symlinks) linkname_len += SYMLINK_PREFIX_LEN; } else #endif linkname_len = 0; if (copy_devices && IS_DEVICE(mode)) { /* This is impossible in the official release, but some pre-release patches * didn't convert the device into a file before sending, so we'll do it here * (even though the length is typically 0 and any checksum data is zeros). */ mode = S_IFREG | (mode & ACCESSPERMS); modtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */ real_ISREG_entry = 0; } else real_ISREG_entry = S_ISREG(mode) ? 1 : 0; #ifdef SUPPORT_HARD_LINKS create_object: if (preserve_hard_links) { if (protocol_version < 28 && real_ISREG_entry) xflags |= XMIT_HLINKED; if (xflags & XMIT_HLINKED) extra_len += (inc_recurse+1) * EXTRA_LEN; } #endif #ifdef SUPPORT_ACLS /* Directories need an extra int32 for the default ACL. */ if (preserve_acls && S_ISDIR(mode)) extra_len += EXTRA_LEN; #endif if (always_checksum && S_ISREG(mode)) extra_len += SUM_EXTRA_CNT * EXTRA_LEN; #if SIZEOF_INT64 >= 8 if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) extra_len += EXTRA_LEN; #endif #ifdef CAN_SET_NSEC if (modtime_nsec) extra_len += EXTRA_LEN; #endif if (file_length < 0) { rprintf(FERROR, "Offset underflow: file-length is negative\n"); exit_cleanup(RERR_UNSUPPORTED); } if (*thisname == '/' ? thisname[1] != '.' || thisname[2] != '\0' : *thisname != '.' || thisname[1] != '\0') { int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE; if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */ && filter_list.head && check_server_filter(&filter_list, FINFO, thisname, filt_flags) < 0) { rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname); exit_cleanup(RERR_UNSUPPORTED); } if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) { rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname); exit_cleanup(RERR_UNSUPPORTED); } } if (inc_recurse && S_ISDIR(mode)) { if (one_file_system) { /* Room to save the dir's device for -x */ extra_len += DEV_EXTRA_CNT * EXTRA_LEN; } pool = dir_flist->file_pool; } else pool = flist->file_pool; #if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN; #endif alloc_len = FILE_STRUCT_LEN + extra_len + basename_len + linkname_len; bp = pool_alloc(pool, alloc_len, "recv_file_entry"); memset(bp, 0, extra_len + FILE_STRUCT_LEN); bp += extra_len; file = (struct file_struct *)bp; bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); #ifdef SUPPORT_HARD_LINKS if (xflags & XMIT_HLINKED #ifndef CAN_HARDLINK_SYMLINK && !S_ISLNK(mode) #endif #ifndef CAN_HARDLINK_SPECIAL && !IS_SPECIAL(mode) && !IS_DEVICE(mode) #endif ) file->flags |= FLAG_HLINKED; #endif file->modtime = (time_t)modtime; #ifdef CAN_SET_NSEC if (modtime_nsec) { file->flags |= FLAG_MOD_NSEC; F_MOD_NSEC(file) = modtime_nsec; } #endif file->len32 = (uint32)file_length; #if SIZEOF_INT64 >= 8 if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) { #if SIZEOF_CAPITAL_OFF_T < 8 rprintf(FERROR, "Offset overflow: attempted 64-bit file-length\n"); exit_cleanup(RERR_UNSUPPORTED); #else file->flags |= FLAG_LENGTH64; F_HIGH_LEN(file) = (uint32)(file_length >> 32); #endif } #endif file->mode = mode; if (preserve_uid) F_OWNER(file) = uid; if (preserve_gid) { F_GROUP(file) = gid; file->flags |= gid_flags; } if (atimes_ndx && !S_ISDIR(mode)) F_ATIME(file) = atime; #ifdef SUPPORT_CRTIMES if (crtimes_ndx) F_CRTIME(file) = crtime; #endif if (unsort_ndx) F_NDX(file) = flist->used + flist->ndx_start; if (basename != thisname) { file->dirname = lastdir; F_DEPTH(file) = lastdir_depth + 1; } else F_DEPTH(file) = 1; if (S_ISDIR(mode)) { if (basename_len == 1+1 && *basename == '.') /* +1 for '\0' */ F_DEPTH(file)--; if (protocol_version >= 30) { if (!(xflags & XMIT_NO_CONTENT_DIR)) { if (xflags & XMIT_TOP_DIR) file->flags |= FLAG_TOP_DIR; file->flags |= FLAG_CONTENT_DIR; } else if (xflags & XMIT_TOP_DIR) file->flags |= FLAG_IMPLIED_DIR; } else if (xflags & XMIT_TOP_DIR) { in_del_hier = recurse; del_hier_name_len = F_DEPTH(file) == 0 ? 0 : l1 + l2; if (relative_paths && del_hier_name_len > 2 && lastname[del_hier_name_len-1] == '.' && lastname[del_hier_name_len-2] == '/') del_hier_name_len -= 2; file->flags |= FLAG_TOP_DIR | FLAG_CONTENT_DIR; } else if (in_del_hier) { if (!relative_paths || !del_hier_name_len || (l1 >= del_hier_name_len && lastname[del_hier_name_len] == '/')) file->flags |= FLAG_CONTENT_DIR; else in_del_hier = 0; } } if (preserve_devices && IS_DEVICE(mode)) { uint32 *devp = F_RDEV_P(file); DEV_MAJOR(devp) = major(rdev); DEV_MINOR(devp) = minor(rdev); } #ifdef SUPPORT_LINKS if (linkname_len) { bp += basename_len; if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SYMLINK(first), linkname_len); } else { if (munge_symlinks) { strlcpy(bp, SYMLINK_PREFIX, linkname_len); bp += SYMLINK_PREFIX_LEN; linkname_len -= SYMLINK_PREFIX_LEN; } #ifdef ICONV_OPTION if (sender_symlink_iconv) { xbuf outbuf, inbuf; alloc_len = linkname_len; linkname_len /= 2; /* Read the symlink data into the end of our double-sized * buffer and then convert it into the right spot. */ INIT_XBUF(inbuf, bp + alloc_len - linkname_len, linkname_len - 1, (size_t)-1); read_sbuf(f, inbuf.buf, inbuf.len); INIT_XBUF(outbuf, bp, 0, alloc_len); if (iconvbufs(ic_recv, &inbuf, &outbuf, ICB_INIT) < 0) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "[%s] cannot convert symlink data for: %s (%s)\n", who_am_i(), full_fname(thisname), strerror(errno)); bp = (char*)file->basename; *bp++ = '\0'; outbuf.len = 0; } bp[outbuf.len] = '\0'; } else #endif read_sbuf(f, bp, linkname_len - 1); if (sanitize_paths && !munge_symlinks && *bp) sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT); } } #endif #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && xflags & XMIT_HLINKED) { if (protocol_version >= 30) { if (xflags & XMIT_HLINK_FIRST) { F_HL_GNUM(file) = flist->ndx_start + flist->used; } else F_HL_GNUM(file) = first_hlink_ndx; } else { static int32 cnt = 0; struct ht_int64_node *np; int64 ino; int32 ndx; if (protocol_version < 26) { dev = read_int(f); ino = read_int(f); } else { if (!(xflags & XMIT_SAME_DEV_pre30)) dev = read_longint(f); ino = read_longint(f); } np = idev_find(dev, ino); ndx = (int32)(long)np->data; /* is -1 when new */ if (ndx < 0) { np->data = (void*)(long)cnt; ndx = cnt++; } F_HL_GNUM(file) = ndx; } } #endif if (always_checksum && (real_ISREG_entry || protocol_version < 28)) { if (real_ISREG_entry) bp = F_SUM(file); else { /* Prior to 28, we get a useless set of nulls. */ bp = tmp_sum; } if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SUM(first), flist_csum_len); } else read_buf(f, bp, flist_csum_len); } #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(mode)) receive_acl(f, file); #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) receive_xattr(f, file); #endif if (S_ISREG(mode) || S_ISLNK(mode)) stats.total_size += file_length; return file; } /* Create a file_struct for a named file by reading its stat() information * and performing extensive checks against global options. * * Returns a pointer to the new file struct, or NULL if there was an error * or this file should be excluded. * * Note: Any error (here or in send_file_name) that results in the omission of * an existent source file from the file list should set * "io_error |= IOERR_GENERAL" to avoid deletion of the file from the * destination if --delete is on. */ struct file_struct *make_file(const char *fname, struct file_list *flist, STRUCT_STAT *stp, int flags, int filter_level) { static char *lastdir; static int lastdir_len = -1; struct file_struct *file; char thisname[MAXPATHLEN]; char linkname[MAXPATHLEN]; int alloc_len, basename_len, linkname_len; int extra_len = file_extra_cnt * EXTRA_LEN; const char *basename; alloc_pool_t *pool; STRUCT_STAT st; char *bp; if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "skipping overly long name: %s\n", fname); return NULL; } clean_fname(thisname, 0); if (sanitize_paths) sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); if (stp && (S_ISDIR(stp->st_mode) || IS_MISSING_FILE(*stp))) { /* This is needed to handle a "symlink/." with a --relative * dir, or a request to delete a specific file. */ st = *stp; *linkname = '\0'; /* make IBM code checker happy */ } else if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; /* See if file is excluded before reporting an error. */ if (filter_level != NO_FILTERS && (is_excluded(thisname, 0, filter_level) || is_excluded(thisname, 1, filter_level))) { if (ignore_perishable && save_errno != ENOENT) non_perishable_cnt++; return NULL; } if (save_errno == ENOENT) { #ifdef SUPPORT_LINKS /* When our options tell us to follow a symlink that * points nowhere, tell the user about the symlink * instead of giving a "vanished" message. We only * dereference a symlink if one of the --copy*links * options was specified, so there's no need for the * extra lstat() if one of these options isn't on. */ if ((copy_links || copy_unsafe_links || copy_dirlinks) && x_lstat(thisname, &st, NULL) == 0 && S_ISLNK(st.st_mode)) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "symlink has no referent: %s\n", full_fname(thisname)); } else #endif { enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING; io_error |= IOERR_VANISHED; rprintf(c, "file has vanished: %s\n", full_fname(thisname)); } } else { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed", full_fname(thisname)); } return NULL; } else if (IS_MISSING_FILE(st)) { io_error |= IOERR_GENERAL; rprintf(FINFO, "skipping file with bogus (zero) st_mode: %s\n", full_fname(thisname)); return NULL; } if (filter_level == NO_FILTERS) goto skip_filters; if (S_ISDIR(st.st_mode)) { if (!xfer_dirs) { rprintf(FINFO, "skipping directory %s\n", thisname); return NULL; } /* -x only affects dirs because we need to avoid recursing * into a mount-point directory, not to avoid copying a * symlinked file if -L (or similar) was specified. */ if (one_file_system && st.st_dev != filesystem_dev && BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) { if (one_file_system > 1) { if (INFO_GTE(MOUNT, 1)) { rprintf(FINFO, "[%s] skipping mount-point dir %s\n", who_am_i(), thisname); } return NULL; } flags |= FLAG_MOUNT_DIR; flags &= ~FLAG_CONTENT_DIR; } } else flags &= ~FLAG_CONTENT_DIR; if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) { if (ignore_perishable) non_perishable_cnt++; return NULL; } if (lp_ignore_nonreadable(module_id)) { #ifdef SUPPORT_LINKS if (!S_ISLNK(st.st_mode)) #endif if (access(thisname, R_OK) != 0) return NULL; } skip_filters: /* Only divert a directory in the main transfer. */ if (flist) { if (flist->prev && S_ISDIR(st.st_mode) && flags & FLAG_DIVERT_DIRS) { /* Room for parent/sibling/next-child info. */ extra_len += DIRNODE_EXTRA_CNT * EXTRA_LEN; if (relative_paths) extra_len += PTR_EXTRA_CNT * EXTRA_LEN; pool = dir_flist->file_pool; } else pool = flist->file_pool; } else { #ifdef SUPPORT_ACLS /* Directories need an extra int32 for the default ACL. */ if (preserve_acls && S_ISDIR(st.st_mode)) extra_len += EXTRA_LEN; #endif pool = NULL; } if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] make_file(%s,*,%d)\n", who_am_i(), thisname, filter_level); } if ((basename = strrchr(thisname, '/')) != NULL) { int len = basename++ - thisname; if (len != lastdir_len || memcmp(thisname, lastdir, len) != 0) { lastdir = new_array(char, len + 1); memcpy(lastdir, thisname, len); lastdir[len] = '\0'; lastdir_len = len; } } else basename = thisname; basename_len = strlen(basename) + 1; /* count the '\0' */ #ifdef SUPPORT_LINKS linkname_len = S_ISLNK(st.st_mode) ? strlen(linkname) + 1 : 0; #else linkname_len = 0; #endif if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) { if (st.st_size == 0) { int fd = do_open(fname, O_RDONLY, 0); if (fd >= 0) { st.st_size = get_device_size(fd, fname); close(fd); } } st.st_mode = S_IFREG | (st.st_mode & ACCESSPERMS); st.st_mtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */ } #ifdef ST_MTIME_NSEC if (st.ST_MTIME_NSEC && protocol_version >= 31) extra_len += EXTRA_LEN; #endif #if SIZEOF_CAPITAL_OFF_T >= 8 if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) extra_len += EXTRA_LEN; #endif if (always_checksum && am_sender && S_ISREG(st.st_mode)) { file_checksum(thisname, &st, tmp_sum); if (sender_keeps_checksum) extra_len += SUM_EXTRA_CNT * EXTRA_LEN; } #if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN; #endif alloc_len = FILE_STRUCT_LEN + extra_len + basename_len + linkname_len; if (pool) bp = pool_alloc(pool, alloc_len, "make_file"); else bp = new_array(char, alloc_len); memset(bp, 0, extra_len + FILE_STRUCT_LEN); bp += extra_len; file = (struct file_struct *)bp; bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && flist && flist->prev) { if (protocol_version >= 28 ? (!S_ISDIR(st.st_mode) && st.st_nlink > 1) : S_ISREG(st.st_mode)) { tmp_dev = (int64)st.st_dev; tmp_ino = (int64)st.st_ino; } else tmp_dev = -1; } #endif #ifdef HAVE_STRUCT_STAT_ST_RDEV if (IS_DEVICE(st.st_mode)) { tmp_rdev = st.st_rdev; st.st_size = 0; } else if (IS_SPECIAL(st.st_mode)) st.st_size = 0; #endif file->flags = flags; file->modtime = st.st_mtime; #ifdef ST_MTIME_NSEC if (st.ST_MTIME_NSEC && protocol_version >= 31) { file->flags |= FLAG_MOD_NSEC; F_MOD_NSEC(file) = st.ST_MTIME_NSEC; } #endif file->len32 = (uint32)st.st_size; #if SIZEOF_CAPITAL_OFF_T >= 8 if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) { file->flags |= FLAG_LENGTH64; F_HIGH_LEN(file) = (uint32)(st.st_size >> 32); } #endif file->mode = st.st_mode; if (preserve_uid) F_OWNER(file) = st.st_uid; if (preserve_gid) F_GROUP(file) = st.st_gid; if (am_generator && st.st_uid == our_uid) file->flags |= FLAG_OWNED_BY_US; if (atimes_ndx && !S_ISDIR(file->mode)) F_ATIME(file) = st.st_atime; #ifdef SUPPORT_CRTIMES if (crtimes_ndx) F_CRTIME(file) = get_create_time(fname, &st); #endif if (basename != thisname) file->dirname = lastdir; #ifdef SUPPORT_LINKS if (linkname_len) memcpy(bp + basename_len, linkname, linkname_len); #endif if (am_sender) F_PATHNAME(file) = pathname; else if (!pool) F_DEPTH(file) = extra_len / EXTRA_LEN; if (basename_len == 0+1) { if (!pool) unmake_file(file); return NULL; } if (sender_keeps_checksum && S_ISREG(st.st_mode)) memcpy(F_SUM(file), tmp_sum, flist_csum_len); if (unsort_ndx) F_NDX(file) = stats.num_dirs; return file; } OFF_T get_device_size(int fd, const char *fname) { OFF_T off = lseek(fd, 0, SEEK_END); if (off == (OFF_T) -1) { rsyserr(FERROR, errno, "failed to get device size via seek: %s", fname); return 0; } if (lseek(fd, 0, SEEK_SET) != 0) rsyserr(FERROR, errno, "failed to seek device back to start: %s", fname); return off; } /* Only called for temporary file_struct entries created by make_file(). */ void unmake_file(struct file_struct *file) { free(REQ_EXTRA(file, F_DEPTH(file))); } static struct file_struct *send_file_name(int f, struct file_list *flist, const char *fname, STRUCT_STAT *stp, int flags, int filter_level) { struct file_struct *file; file = make_file(fname, flist, stp, flags, filter_level); if (!file) return NULL; if (chmod_modes && !S_ISLNK(file->mode) && file->mode) file->mode = tweak_mode(file->mode, chmod_modes); if (f >= 0) { char fbuf[MAXPATHLEN]; #ifdef SUPPORT_LINKS const char *symlink_name; int symlink_len; #ifdef ICONV_OPTION char symlink_buf[MAXPATHLEN]; #endif #endif #if defined SUPPORT_ACLS || defined SUPPORT_XATTRS stat_x sx; init_stat_x(&sx); #endif #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { symlink_name = F_SYMLINK(file); symlink_len = strlen(symlink_name); if (symlink_len == 0) { io_error |= IOERR_GENERAL; f_name(file, fbuf); rprintf(FERROR_XFER, "skipping symlink with 0-length value: %s\n", full_fname(fbuf)); return NULL; } } else { symlink_name = NULL; symlink_len = 0; } #endif #ifdef ICONV_OPTION if (ic_send != (iconv_t)-1) { xbuf outbuf, inbuf; INIT_CONST_XBUF(outbuf, fbuf); if (file->dirname) { INIT_XBUF_STRLEN(inbuf, (char*)file->dirname); outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */ if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0) goto convert_error; outbuf.size += 2; fbuf[outbuf.len++] = '/'; } INIT_XBUF_STRLEN(inbuf, (char*)file->basename); if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0) { convert_error: io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), f_name(file, fbuf), strerror(errno)); return NULL; } fbuf[outbuf.len] = '\0'; #ifdef SUPPORT_LINKS if (symlink_len && sender_symlink_iconv) { INIT_XBUF(inbuf, (char*)symlink_name, symlink_len, (size_t)-1); INIT_CONST_XBUF(outbuf, symlink_buf); if (iconvbufs(ic_send, &inbuf, &outbuf, ICB_INIT) < 0) { io_error |= IOERR_GENERAL; f_name(file, fbuf); rprintf(FERROR_XFER, "[%s] cannot convert symlink data for: %s (%s)\n", who_am_i(), full_fname(fbuf), strerror(errno)); return NULL; } symlink_buf[outbuf.len] = '\0'; symlink_name = symlink_buf; symlink_len = outbuf.len; } #endif } else #endif f_name(file, fbuf); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { sx.st.st_mode = file->mode; if (get_acl(fname, &sx) < 0) { io_error |= IOERR_GENERAL; return NULL; } } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { sx.st.st_mode = file->mode; if (get_xattr(fname, &sx) < 0) { io_error |= IOERR_GENERAL; return NULL; } } #endif send_file_entry(f, fbuf, file, #ifdef SUPPORT_LINKS symlink_name, symlink_len, #endif flist->used, flist->ndx_start); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { send_acl(f, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { F_XATTR(file) = send_xattr(f, &sx); free_xattr(&sx); } #endif } maybe_emit_filelist_progress(flist->used + flist_count_offset); flist_expand(flist, 1); flist->files[flist->used++] = file; return file; } static void send_if_directory(int f, struct file_list *flist, struct file_struct *file, char *fbuf, unsigned int ol, int flags) { char is_dot_dir = fbuf[ol-1] == '.' && (ol == 1 || fbuf[ol-2] == '/'); if (S_ISDIR(file->mode) && !(file->flags & FLAG_MOUNT_DIR) && f_name(file, fbuf)) { void *save_filters; unsigned int len = strlen(fbuf); if (len > 1 && fbuf[len-1] == '/') fbuf[--len] = '\0'; save_filters = push_local_filters(fbuf, len); send_directory(f, flist, fbuf, len, flags); pop_local_filters(save_filters); fbuf[ol] = '\0'; if (is_dot_dir) fbuf[ol-1] = '.'; } } static int file_compare(const void *file1, const void *file2) { return f_name_cmp(*(struct file_struct **)file1, *(struct file_struct **)file2); } /* The guts of a merge-sort algorithm. This was derived from the glibc * version, but I (Wayne) changed the merge code to do less copying and * to require only half the amount of temporary memory. */ static void fsort_tmp(struct file_struct **fp, size_t num, struct file_struct **tmp) { struct file_struct **f1, **f2, **t; size_t n1, n2; n1 = num / 2; n2 = num - n1; f1 = fp; f2 = fp + n1; if (n1 > 1) fsort_tmp(f1, n1, tmp); if (n2 > 1) fsort_tmp(f2, n2, tmp); while (f_name_cmp(*f1, *f2) <= 0) { if (!--n1) return; f1++; } t = tmp; memcpy(t, f1, n1 * PTR_SIZE); *f1++ = *f2++, n2--; while (n1 > 0 && n2 > 0) { if (f_name_cmp(*t, *f2) <= 0) *f1++ = *t++, n1--; else *f1++ = *f2++, n2--; } if (n1 > 0) memcpy(f1, t, n1 * PTR_SIZE); } /* This file-struct sorting routine makes sure that any identical names in * the file list stay in the same order as they were in the original list. * This is particularly vital in inc_recurse mode where we expect a sort * on the flist to match the exact order of a sort on the dir_flist. */ static void fsort(struct file_struct **fp, size_t num) { if (num <= 1) return; if (use_qsort) qsort(fp, num, PTR_SIZE, file_compare); else { struct file_struct **tmp = new_array(struct file_struct *, (num+1) / 2); fsort_tmp(fp, num, tmp); free(tmp); } } /* We take an entire set of sibling dirs from the sorted flist and link them * into the tree, setting the appropriate parent/child/sibling pointers. */ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist, int dir_cnt) { int i; int32 *dp = NULL; int32 *parent_dp = parent_ndx < 0 ? NULL : F_DIR_NODE_P(dir_flist->sorted[parent_ndx]); /* The sending side is adding entries to dir_flist in sorted order, so sorted & files are the same. */ flist_expand(dir_flist, dir_cnt); dir_flist->sorted = dir_flist->files; for (i = 0; dir_cnt; i++) { struct file_struct *file = from_flist->sorted[i]; if (!S_ISDIR(file->mode)) continue; dir_flist->files[dir_flist->used++] = file; dir_cnt--; if (file->basename[0] == '.' && file->basename[1] == '\0') continue; if (dp) DIR_NEXT_SIBLING(dp) = dir_flist->used - 1; else if (parent_dp) DIR_FIRST_CHILD(parent_dp) = dir_flist->used - 1; else send_dir_ndx = dir_flist->used - 1; dp = F_DIR_NODE_P(file); DIR_PARENT(dp) = parent_ndx; DIR_FIRST_CHILD(dp) = -1; } if (dp) DIR_NEXT_SIBLING(dp) = -1; } static void interpret_stat_error(const char *fname, int is_dir) { if (errno == ENOENT) { io_error |= IOERR_VANISHED; rprintf(FWARNING, "%s has vanished: %s\n", is_dir ? "directory" : "file", full_fname(fname)); } else { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "link_stat %s failed", full_fname(fname)); } } /* This function is normally called by the sender, but the receiving side also * calls it from get_dirlist() with f set to -1 so that we just construct the * file list in memory without sending it over the wire. Also, get_dirlist() * might call this with f set to -2, which also indicates that local filter * rules should be ignored. */ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, int flags) { struct dirent *di; unsigned remainder; char *p; DIR *d; int divert_dirs = (flags & FLAG_DIVERT_DIRS) != 0; int start = flist->used; int filter_level = f == -2 ? SERVER_FILTERS : ALL_FILTERS; assert(flist != NULL); if (!(d = opendir(fbuf))) { if (errno == ENOENT) { if (am_sender) /* Can abuse this for vanished error w/ENOENT: */ interpret_stat_error(fbuf, True); return; } if (errno == ENOTDIR && (flags & FLAG_PERHAPS_DIR)) return; io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf)); return; } p = fbuf + len; if (len == 1 && *fbuf == '/') remainder = MAXPATHLEN - 1; else if (len < MAXPATHLEN-1) { *p++ = '/'; *p = '\0'; remainder = MAXPATHLEN - (len + 1); } else remainder = 0; for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { unsigned name_len; char *dname = d_name(di); if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) continue; name_len = strlcpy(p, dname, remainder); if (name_len >= remainder) { char save = fbuf[len]; fbuf[len] = '\0'; io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "filename overflows max-path len by %u: %s/%s\n", name_len - remainder + 1, fbuf, dname); fbuf[len] = save; continue; } if (dname[0] == '\0') { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "cannot send file with empty name in %s\n", full_fname(fbuf)); continue; } send_file_name(f, flist, fbuf, NULL, flags, filter_level); } fbuf[len] = '\0'; if (errno) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "readdir(%s)", full_fname(fbuf)); } closedir(d); if (f >= 0 && recurse && !divert_dirs) { int i, end = flist->used - 1; /* send_if_directory() bumps flist->used, so use "end". */ for (i = start; i <= end; i++) send_if_directory(f, flist, flist->files[i], fbuf, len, flags); } } static void send_implied_dirs(int f, struct file_list *flist, char *fname, char *start, char *limit, int flags, char name_type) { static char lastpath[MAXPATHLEN] = ""; static int lastpath_len = 0; static struct file_struct *lastpath_struct = NULL; struct file_struct *file; item_list *relname_list; relnamecache **rnpp; int len, need_new_dir, depth = 0; filter_rule_list save_filter_list = filter_list; flags = (flags | FLAG_IMPLIED_DIR) & ~(FLAG_TOP_DIR | FLAG_CONTENT_DIR); filter_list.head = filter_list.tail = NULL; /* Don't filter implied dirs. */ if (inc_recurse) { if (lastpath_struct && F_PATHNAME(lastpath_struct) == pathname && lastpath_len == limit - fname && strncmp(lastpath, fname, lastpath_len) == 0) need_new_dir = 0; else need_new_dir = 1; } else { char *tp = fname, *lp = lastpath; /* Skip any initial directories in our path that we * have in common with lastpath. */ assert(start == fname); for ( ; ; tp++, lp++) { if (tp == limit) { if (*lp == '/' || *lp == '\0') goto done; break; } if (*lp != *tp) break; if (*tp == '/') { start = tp; depth++; } } need_new_dir = 1; } if (need_new_dir) { int save_copy_links = copy_links; int save_xfer_dirs = xfer_dirs; char *slash; copy_links = xfer_dirs = 1; *limit = '\0'; for (slash = start; (slash = strchr(slash+1, '/')) != NULL; ) { *slash = '\0'; file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS); depth++; if (!inc_recurse && file && S_ISDIR(file->mode)) change_local_filter_dir(fname, strlen(fname), depth); *slash = '/'; } file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS); if (inc_recurse) { if (file && !S_ISDIR(file->mode)) file = NULL; lastpath_struct = file; } else if (file && S_ISDIR(file->mode)) change_local_filter_dir(fname, strlen(fname), ++depth); strlcpy(lastpath, fname, sizeof lastpath); lastpath_len = limit - fname; *limit = '/'; copy_links = save_copy_links; xfer_dirs = save_xfer_dirs; if (!inc_recurse) goto done; } if (!lastpath_struct) goto done; /* dir must have vanished */ len = strlen(limit+1); memcpy(&relname_list, F_DIR_RELNAMES_P(lastpath_struct), sizeof relname_list); if (!relname_list) { relname_list = new0(item_list); memcpy(F_DIR_RELNAMES_P(lastpath_struct), &relname_list, sizeof relname_list); } rnpp = EXPAND_ITEM_LIST(relname_list, relnamecache *, 32); *rnpp = (relnamecache*)new_array(char, RELNAMECACHE_LEN + len + 1); (*rnpp)->name_type = name_type; strlcpy((*rnpp)->fname, limit+1, len + 1); done: filter_list = save_filter_list; } static NORETURN void fatal_unsafe_io_error(void) { /* This (sadly) can only happen when pushing data because * the sender does not know about what kind of delete * is in effect on the receiving side when pulling. */ rprintf(FERROR_XFER, "FATAL I/O ERROR: dying to avoid a --delete-%s issue with a pre-3.0.7 receiver.\n", delete_during == 2 ? "delay" : "during"); exit_cleanup(RERR_UNSUPPORTED); } static void send1extra(int f, struct file_struct *file, struct file_list *flist) { char fbuf[MAXPATHLEN]; item_list *relname_list; int len, dlen, flags = FLAG_DIVERT_DIRS | FLAG_CONTENT_DIR; size_t j; f_name(file, fbuf); dlen = strlen(fbuf); if (!change_pathname(file, NULL, 0)) exit_cleanup(RERR_FILESELECT); change_local_filter_dir(fbuf, dlen, send_dir_depth); if (file->flags & FLAG_CONTENT_DIR) { if (one_file_system) { STRUCT_STAT st; if (link_stat(fbuf, &st, copy_dirlinks) != 0) { interpret_stat_error(fbuf, True); return; } filesystem_dev = st.st_dev; } send_directory(f, flist, fbuf, dlen, flags); } if (!relative_paths) return; memcpy(&relname_list, F_DIR_RELNAMES_P(file), sizeof relname_list); if (!relname_list) return; for (j = 0; j < relname_list->count; j++) { char *slash; relnamecache *rnp = ((relnamecache**)relname_list->items)[j]; char name_type = rnp->name_type; fbuf[dlen] = '/'; len = strlcpy(fbuf + dlen + 1, rnp->fname, sizeof fbuf - dlen - 1); free(rnp); if (len >= (int)sizeof fbuf) continue; /* Impossible... */ slash = strchr(fbuf+dlen+1, '/'); if (slash) { send_implied_dirs(f, flist, fbuf, fbuf+dlen+1, slash, flags, name_type); continue; } if (name_type != NORMAL_NAME) { STRUCT_STAT st; if (name_type == MISSING_NAME) memset(&st, 0, sizeof st); else if (link_stat(fbuf, &st, 1) != 0) { interpret_stat_error(fbuf, True); continue; } send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS); } else send_file_name(f, flist, fbuf, NULL, FLAG_TOP_DIR | flags, ALL_FILTERS); } free(relname_list); } static void write_end_of_flist(int f, int send_io_error) { if (xfer_flags_as_varint) { write_varint(f, 0); write_varint(f, send_io_error ? io_error : 0); } else if (send_io_error) { write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); write_varint(f, io_error); } else write_byte(f, 0); } void send_extra_file_list(int f, int at_least) { struct file_list *flist; int64 start_write; uint16 prev_flags; int save_io_error = io_error; if (flist_eof) return; if (at_least < 0) at_least = file_total - file_old_total + 1; /* Keep sending data until we have the requested number of * files in the upcoming file-lists. */ while (file_total - file_old_total < at_least) { struct file_struct *file = dir_flist->sorted[send_dir_ndx]; int dir_ndx, dstart = stats.num_dirs; const char *pathname = F_PATHNAME(file); int32 *dp; flist = flist_new(0, "send_extra_file_list"); start_write = stats.total_written; if (unsort_ndx) dir_ndx = F_NDX(file); else dir_ndx = send_dir_ndx; write_ndx(f, NDX_FLIST_OFFSET - dir_ndx); flist->parent_ndx = send_dir_ndx; /* the sending side must remember the sorted ndx value */ send1extra(f, file, flist); prev_flags = file->flags; dp = F_DIR_NODE_P(file); /* If there are any duplicate directory names that follow, we * send all the dirs together in one file-list. The dir_flist * tree links all the child subdirs onto the last dup dir. */ while ((dir_ndx = DIR_NEXT_SIBLING(dp)) >= 0 && dir_flist->sorted[dir_ndx]->flags & FLAG_DUPLICATE) { send_dir_ndx = dir_ndx; file = dir_flist->sorted[dir_ndx]; /* Try to avoid some duplicate scanning of identical dirs. */ if (F_PATHNAME(file) == pathname && prev_flags & FLAG_CONTENT_DIR) file->flags &= ~FLAG_CONTENT_DIR; send1extra(f, file, flist); prev_flags = file->flags; dp = F_DIR_NODE_P(file); } if (io_error == save_io_error || ignore_errors) write_end_of_flist(f, 0); else if (use_safe_inc_flist) write_end_of_flist(f, 1); else { if (delete_during) fatal_unsafe_io_error(); write_end_of_flist(f, 0); } if (need_unsorted_flist) { flist->sorted = new_array(struct file_struct *, flist->used); memcpy(flist->sorted, flist->files, flist->used * PTR_SIZE); } else flist->sorted = flist->files; flist_sort_and_clean(flist, 0); add_dirs_to_tree(send_dir_ndx, flist, stats.num_dirs - dstart); flist_done_allocating(flist); file_total += flist->used; stats.flist_size += stats.total_written - start_write; stats.num_files += flist->used; if (DEBUG_GTE(FLIST, 3)) output_flist(flist); if (DIR_FIRST_CHILD(dp) >= 0) { send_dir_ndx = DIR_FIRST_CHILD(dp); send_dir_depth++; } else { while (DIR_NEXT_SIBLING(dp) < 0) { if ((send_dir_ndx = DIR_PARENT(dp)) < 0) { write_ndx(f, NDX_FLIST_EOF); flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); change_local_filter_dir(NULL, 0, 0); goto finish; } send_dir_depth--; file = dir_flist->sorted[send_dir_ndx]; dp = F_DIR_NODE_P(file); } send_dir_ndx = DIR_NEXT_SIBLING(dp); } } finish: if (io_error != save_io_error && protocol_version == 30 && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); } struct file_list *send_file_list(int f, int argc, char *argv[]) { static const char *lastdir; static int lastdir_len = -1; int len, dirlen; STRUCT_STAT st; char *p, *dir; struct file_list *flist; struct timeval start_tv, end_tv; int64 start_write; int use_ff_fd = 0; int disable_buffering, reenable_multiplex = -1; int flags = recurse ? FLAG_CONTENT_DIR : 0; int reading_remotely = filesfrom_host != NULL; int rl_flags = (reading_remotely ? 0 : RL_DUMP_COMMENTS) #ifdef ICONV_OPTION | (filesfrom_convert ? RL_CONVERT : 0) #endif | (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0); int implied_dot_dir = 0; rprintf(FLOG, "building file list\n"); if (show_filelist_progress) start_filelist_progress("building file list"); else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server) rprintf(FCLIENT, "sending incremental file list\n"); start_write = stats.total_written; gettimeofday(&start_tv, NULL); if (relative_paths && protocol_version >= 30) implied_dirs = 1; /* We send flagged implied dirs */ #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !cur_flist) init_hard_links(); #endif flist = cur_flist = flist_new(0, "send_file_list"); flist_expand(flist, FLIST_START_LARGE); if (inc_recurse) { dir_flist = flist_new(FLIST_TEMP, "send_file_list"); flist_expand(dir_flist, FLIST_START_LARGE); flags |= FLAG_DIVERT_DIRS; } else dir_flist = cur_flist; disable_buffering = io_start_buffering_out(f); if (filesfrom_fd >= 0) { if (argv[0] && !change_dir(argv[0], CD_NORMAL)) { rsyserr(FERROR_XFER, errno, "change_dir %s failed", full_fname(argv[0])); exit_cleanup(RERR_FILESELECT); } if (protocol_version < 31) { /* Older protocols send the files-from data w/o packaging * it in multiplexed I/O packets, so temporarily switch * to buffered I/O to match this behavior. */ reenable_multiplex = io_end_multiplex_in(MPLX_TO_BUFFERED); } use_ff_fd = 1; } if (!orig_dir) orig_dir = strdup(curr_dir); while (1) { char fbuf[MAXPATHLEN], *fn, name_type; if (use_ff_fd) { if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0) break; sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS); } else { if (argc-- == 0) break; strlcpy(fbuf, *argv++, MAXPATHLEN); if (sanitize_paths) sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS); } len = strlen(fbuf); if (relative_paths) { /* We clean up fbuf below. */ name_type = NORMAL_NAME; } else if (!len || fbuf[len - 1] == '/') { if (len == 2 && fbuf[0] == '.') { /* Turn "./" into just "." rather than "./." */ fbuf[--len] = '\0'; } else { if (len + 1 >= MAXPATHLEN) overflow_exit("send_file_list"); fbuf[len++] = '.'; fbuf[len] = '\0'; } name_type = DOTDIR_NAME; } else if (len > 1 && fbuf[len-1] == '.' && fbuf[len-2] == '.' && (len == 2 || fbuf[len-3] == '/')) { if (len + 2 >= MAXPATHLEN) overflow_exit("send_file_list"); fbuf[len++] = '/'; fbuf[len++] = '.'; fbuf[len] = '\0'; name_type = DOTDIR_NAME; } else if (fbuf[len-1] == '.' && (len == 1 || fbuf[len-2] == '/')) name_type = DOTDIR_NAME; else name_type = NORMAL_NAME; dir = NULL; if (!relative_paths) { p = strrchr(fbuf, '/'); if (p) { *p = '\0'; if (p == fbuf) dir = "/"; else dir = fbuf; len -= p - fbuf + 1; fn = p + 1; } else fn = fbuf; } else { if ((p = strstr(fbuf, "/./")) != NULL) { *p = '\0'; if (p == fbuf) dir = "/"; else { dir = fbuf; clean_fname(dir, 0); } fn = p + 3; while (*fn == '/') fn++; if (!*fn) *--fn = '\0'; /* ensure room for '.' */ } else fn = fbuf; /* A leading ./ can be used in relative mode to affect * the dest dir without its name being in the path. */ if (*fn == '.' && fn[1] == '/' && fn[2] && !implied_dot_dir) implied_dot_dir = -1; len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH | CFN_DROP_TRAILING_DOT_DIR); if (len == 1) { if (fn[0] == '/') { fn = "/."; len = 2; name_type = DOTDIR_NAME; } else if (fn[0] == '.') name_type = DOTDIR_NAME; } else if (fn[len-1] == '/') { fn[--len] = '\0'; if (len == 1 && *fn == '.') name_type = DOTDIR_NAME; else name_type = SLASH_ENDING_NAME; } /* Reject a ".." dir in the active part of the path. */ for (p = fn; (p = strstr(p, "..")) != NULL; p += 2) { if ((p[2] == '/' || p[2] == '\0') && (p == fn || p[-1] == '/')) { rprintf(FERROR, "found \"..\" dir in relative path: %s\n", fn); exit_cleanup(RERR_SYNTAX); } } } if (!*fn) { len = 1; fn = "."; name_type = DOTDIR_NAME; } dirlen = dir ? strlen(dir) : 0; if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) { if (!change_pathname(NULL, dir, -dirlen)) goto bad_path; lastdir = pathname; lastdir_len = pathname_len; } else if (!change_pathname(NULL, lastdir, lastdir_len)) { bad_path: if (implied_dot_dir < 0) implied_dot_dir = 0; continue; } if (implied_dot_dir < 0) { implied_dot_dir = 1; send_file_name(f, flist, ".", NULL, (flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR, ALL_FILTERS); } if (fn != fbuf) memmove(fbuf, fn, len + 1); if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0 || (name_type != DOTDIR_NAME && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, SERVER_FILTERS)) || (relative_paths && path_is_daemon_excluded(fbuf, 1))) { if (errno != ENOENT || missing_args == 0) { /* This is a transfer error, but inhibit deletion * only if we might be omitting an existing file. */ if (errno != ENOENT) io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "link_stat %s failed", full_fname(fbuf)); continue; } else if (missing_args == 1) { /* Just ignore the arg. */ continue; } else /* (missing_args == 2) */ { /* Send the arg as a "missing" entry with * mode 0, which tells the generator to delete it. */ memset(&st, 0, sizeof st); } } /* A dot-dir should not be excluded! */ if (name_type != DOTDIR_NAME && st.st_mode != 0 && is_excluded(fbuf, S_ISDIR(st.st_mode) != 0, ALL_FILTERS)) continue; if (S_ISDIR(st.st_mode) && !xfer_dirs) { rprintf(FINFO, "skipping directory %s\n", fbuf); continue; } if (inc_recurse && relative_paths && *fbuf) { if ((p = strchr(fbuf+1, '/')) != NULL) { if (p - fbuf == 1 && *fbuf == '.') { if ((fn = strchr(p+1, '/')) != NULL) p = fn; } else fn = p; send_implied_dirs(f, flist, fbuf, fbuf, p, flags, IS_MISSING_FILE(st) ? MISSING_NAME : name_type); if (fn == p) continue; } } else if (implied_dirs && (p=strrchr(fbuf,'/')) && p != fbuf) { /* Send the implied directories at the start of the * source spec, so we get their permissions right. */ send_implied_dirs(f, flist, fbuf, fbuf, p, flags, 0); } if (one_file_system) filesystem_dev = st.st_dev; if (recurse || (xfer_dirs && name_type != NORMAL_NAME)) { struct file_struct *file; file = send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags, NO_FILTERS); if (!file) continue; if (inc_recurse) { if (name_type == DOTDIR_NAME) { if (send_dir_depth < 0) { send_dir_depth = 0; change_local_filter_dir(fbuf, len, send_dir_depth); } send_directory(f, flist, fbuf, len, flags); } } else send_if_directory(f, flist, file, fbuf, len, flags); } else send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS); } if (reenable_multiplex >= 0) io_start_multiplex_in(reenable_multiplex); gettimeofday(&end_tv, NULL); stats.flist_buildtime = (int64)(end_tv.tv_sec - start_tv.tv_sec) * 1000 + (end_tv.tv_usec - start_tv.tv_usec) / 1000; if (stats.flist_buildtime == 0) stats.flist_buildtime = 1; start_tv = end_tv; /* Indicate end of file list */ if (io_error == 0 || ignore_errors) write_end_of_flist(f, 0); else if (use_safe_inc_flist) write_end_of_flist(f, 1); else { if (delete_during && inc_recurse) fatal_unsafe_io_error(); write_end_of_flist(f, 0); } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !inc_recurse) idev_destroy(); #endif if (show_filelist_progress) finish_filelist_progress(flist); gettimeofday(&end_tv, NULL); stats.flist_xfertime = (int64)(end_tv.tv_sec - start_tv.tv_sec) * 1000 + (end_tv.tv_usec - start_tv.tv_usec) / 1000; /* When converting names, both sides keep an unsorted file-list array * because the names will differ on the sending and receiving sides * (both sides will use the unsorted index number for each item). */ /* Sort the list without removing any duplicates. This allows the * receiving side to ask for whatever name it kept. For incremental * recursion mode, the sender marks duplicate dirs so that it can * send them together in a single file-list. */ if (need_unsorted_flist) { flist->sorted = new_array(struct file_struct *, flist->used); memcpy(flist->sorted, flist->files, flist->used * PTR_SIZE); } else flist->sorted = flist->files; flist_sort_and_clean(flist, 0); file_total += flist->used; file_old_total += flist->used; if (numeric_ids <= 0 && !inc_recurse) send_id_lists(f); /* send the io_error flag */ if (protocol_version < 30) write_int(f, ignore_errors ? 0 : io_error); else if (!use_safe_inc_flist && io_error && !ignore_errors) send_msg_int(MSG_IO_ERROR, io_error); if (disable_buffering) io_end_buffering_out(IOBUF_FREE_BUFS); stats.flist_size = stats.total_written - start_write; stats.num_files = flist->used; if (DEBUG_GTE(FLIST, 3)) output_flist(flist); if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "send_file_list done\n"); if (inc_recurse) { send_dir_depth = 1; add_dirs_to_tree(-1, flist, stats.num_dirs); if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0) flist->parent_ndx = -1; flist_done_allocating(flist); if (send_dir_ndx < 0) { write_ndx(f, NDX_FLIST_EOF); flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); } else if (file_total == 1) { /* If we're creating incremental file-lists and there * was just 1 item in the first file-list, send 1 more * file-list to check if this is a 1-file xfer. */ send_extra_file_list(f, 1); } } else { flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); } return flist; } struct file_list *recv_file_list(int f, int dir_ndx) { const char *good_dirname = NULL; struct file_list *flist; int dstart, flags; int64 start_read; if (!first_flist) { if (show_filelist_progress) start_filelist_progress("receiving file list"); else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server) rprintf(FCLIENT, "receiving incremental file list\n"); rprintf(FLOG, "receiving file list\n"); if (usermap) parse_name_map(usermap, True); if (groupmap) parse_name_map(groupmap, False); } start_read = stats.total_read; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && !first_flist) init_hard_links(); #endif flist = flist_new(0, "recv_file_list"); flist_expand(flist, FLIST_START_LARGE); if (inc_recurse) { if (flist->ndx_start == 1) { dir_flist = flist_new(FLIST_TEMP, "recv_file_list"); flist_expand(dir_flist, FLIST_START_LARGE); } dstart = dir_flist->used; } else { dir_flist = flist; dstart = 0; } while (1) { struct file_struct *file; if (xfer_flags_as_varint) { if ((flags = read_varint(f)) == 0) { int err = read_varint(f); if (!ignore_errors) io_error |= err; break; } } else { if ((flags = read_byte(f)) == 0) break; if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS)) flags |= read_byte(f) << 8; if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) { int err; if (!use_safe_inc_flist) { rprintf(FERROR, "Invalid flist flag: %x\n", flags); exit_cleanup(RERR_PROTOCOL); } err = read_varint(f); if (!ignore_errors) io_error |= err; break; } } flist_expand(flist, 1); file = recv_file_entry(f, flist, flags); if (inc_recurse) { static const char empty_dir[] = "\0"; const char *cur_dir = file->dirname ? file->dirname : empty_dir; if (relative_paths && *cur_dir == '/') cur_dir++; if (cur_dir != good_dirname) { const char *d = dir_ndx >= 0 ? f_name(dir_flist->files[dir_ndx], NULL) : empty_dir; if (strcmp(cur_dir, d) != 0) { rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n", cur_dir, file->basename); exit_cleanup(RERR_UNSUPPORTED); } good_dirname = cur_dir; } } if (S_ISREG(file->mode)) { /* Already counted */ } else if (S_ISDIR(file->mode)) { if (inc_recurse) { flist_expand(dir_flist, 1); dir_flist->files[dir_flist->used++] = file; } stats.num_dirs++; } else if (S_ISLNK(file->mode)) stats.num_symlinks++; else if (IS_DEVICE(file->mode)) stats.num_symlinks++; else stats.num_specials++; flist->files[flist->used++] = file; maybe_emit_filelist_progress(flist->used); if (DEBUG_GTE(FLIST, 2)) { char *name = f_name(file, NULL); rprintf(FINFO, "recv_file_name(%s)\n", NS(name)); } } file_total += flist->used; if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "received %d names\n", flist->used); if (show_filelist_progress) finish_filelist_progress(flist); if (need_unsorted_flist) { /* Create an extra array of index pointers that we can sort for * the generator's use (for wading through the files in sorted * order and for calling flist_find()). We keep the "files" * list unsorted for our exchange of index numbers with the * other side (since their names may not sort the same). */ flist->sorted = new_array(struct file_struct *, flist->used); memcpy(flist->sorted, flist->files, flist->used * PTR_SIZE); if (inc_recurse && dir_flist->used > dstart) { static int dir_flist_malloced = 0; if (dir_flist_malloced < dir_flist->malloced) { dir_flist->sorted = realloc_array(dir_flist->sorted, struct file_struct *, dir_flist->malloced); dir_flist_malloced = dir_flist->malloced; } memcpy(dir_flist->sorted + dstart, dir_flist->files + dstart, (dir_flist->used - dstart) * PTR_SIZE); fsort(dir_flist->sorted + dstart, dir_flist->used - dstart); } } else { flist->sorted = flist->files; if (inc_recurse && dir_flist->used > dstart) { dir_flist->sorted = dir_flist->files; fsort(dir_flist->sorted + dstart, dir_flist->used - dstart); } } if (inc_recurse) flist_done_allocating(flist); else if (f >= 0) { recv_id_list(f, flist); flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); } /* The --relative option sends paths with a leading slash, so we need * to specify the strip_root option here. We rejected leading slashes * for a non-relative transfer in recv_file_entry(). */ flist_sort_and_clean(flist, relative_paths); if (protocol_version < 30) { /* Recv the io_error flag */ int err = read_int(f); if (!ignore_errors) io_error |= err; } else if (inc_recurse && flist->ndx_start == 1) { if (!file_total || strcmp(flist->sorted[flist->low]->basename, ".") != 0) flist->parent_ndx = -1; } if (DEBUG_GTE(FLIST, 3)) output_flist(flist); if (DEBUG_GTE(FLIST, 2)) rprintf(FINFO, "recv_file_list done\n"); stats.flist_size += stats.total_read - start_read; stats.num_files += flist->used; return flist; } /* This is only used once by the receiver if the very first file-list * has exactly one item in it. */ void recv_additional_file_list(int f) { struct file_list *flist; int ndx = read_ndx(f); if (ndx == NDX_FLIST_EOF) { flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); change_local_filter_dir(NULL, 0, 0); } else { ndx = NDX_FLIST_OFFSET - ndx; if (ndx < 0 || ndx >= dir_flist->used) { ndx = NDX_FLIST_OFFSET - ndx; rprintf(FERROR, "[%s] Invalid dir index: %d (%d - %d)\n", who_am_i(), ndx, NDX_FLIST_OFFSET, NDX_FLIST_OFFSET - dir_flist->used + 1); exit_cleanup(RERR_PROTOCOL); } if (DEBUG_GTE(FLIST, 3)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } flist = recv_file_list(f, ndx); flist->parent_ndx = ndx; } } /* Search for an identically-named item in the file list. Note that the * items must agree in their directory-ness, or no match is returned. */ int flist_find(struct file_list *flist, struct file_struct *f) { int low = flist->low, high = flist->high; int diff, mid, mid_up; while (low <= high) { mid = (low + high) / 2; if (F_IS_ACTIVE(flist->sorted[mid])) mid_up = mid; else { /* Scan for the next non-empty entry using the cached * distance values. If the value isn't fully up-to- * date, update it. */ mid_up = mid + F_DEPTH(flist->sorted[mid]); if (!F_IS_ACTIVE(flist->sorted[mid_up])) { do { mid_up += F_DEPTH(flist->sorted[mid_up]); } while (!F_IS_ACTIVE(flist->sorted[mid_up])); F_DEPTH(flist->sorted[mid]) = mid_up - mid; } if (mid_up > high) { /* If there's nothing left above us, set high to * a non-empty entry below us and continue. */ high = mid - (int)flist->sorted[mid]->len32; if (!F_IS_ACTIVE(flist->sorted[high])) { do { high -= (int)flist->sorted[high]->len32; } while (!F_IS_ACTIVE(flist->sorted[high])); flist->sorted[mid]->len32 = mid - high; } continue; } } diff = f_name_cmp(flist->sorted[mid_up], f); if (diff == 0) { if (protocol_version < 29 && S_ISDIR(flist->sorted[mid_up]->mode) != S_ISDIR(f->mode)) return -1; return mid_up; } if (diff < 0) low = mid_up + 1; else high = mid - 1; } return -1; } /* Search for a name in the file list. You must specify want_dir_match as: * 1=match directories, 0=match non-directories, or -1=match either. */ int flist_find_name(struct file_list *flist, const char *fname, int want_dir_match) { static struct file_struct *f; char fbuf[MAXPATHLEN]; const char *slash = strrchr(fname, '/'); const char *basename = slash ? slash+1 : fname; if (!f) f = (struct file_struct*)new_array(char, FILE_STRUCT_LEN + MAXPATHLEN + 1); memset(f, 0, FILE_STRUCT_LEN); memcpy((void*)f->basename, basename, strlen(basename)+1); if (slash) { strlcpy(fbuf, fname, slash - fname + 1); f->dirname = fbuf; } else f->dirname = NULL; f->mode = want_dir_match > 0 ? S_IFDIR : S_IFREG; if (want_dir_match < 0) return flist_find_ignore_dirness(flist, f); return flist_find(flist, f); } /* Search for an identically-named item in the file list. Differs from * flist_find in that an item that agrees with "f" in directory-ness is * preferred but one that does not is still found. */ int flist_find_ignore_dirness(struct file_list *flist, struct file_struct *f) { mode_t save_mode; int ndx; /* First look for an item that agrees in directory-ness. */ ndx = flist_find(flist, f); if (ndx >= 0) return ndx; /* Temporarily flip f->mode to look for an item of opposite * directory-ness. */ save_mode = f->mode; f->mode = S_ISDIR(f->mode) ? S_IFREG : S_IFDIR; ndx = flist_find(flist, f); f->mode = save_mode; return ndx; } /* * Free up any resources a file_struct has allocated * and clear the file. */ void clear_file(struct file_struct *file) { /* The +1 zeros out the first char of the basename. */ memset(file, 0, FILE_STRUCT_LEN + 1); /* In an empty entry, F_DEPTH() is an offset to the next non-empty * entry. Likewise for len32 in the opposite direction. We assume * that we're alone for now since flist_find() will adjust the counts * it runs into that aren't up-to-date. */ file->len32 = F_DEPTH(file) = 1; } /* Allocate a new file list. */ static struct file_list *flist_new(int flags, const char *msg) { struct file_list *flist; flist = new0(struct file_list); if (flags & FLIST_TEMP) { if (!(flist->file_pool = pool_create(SMALL_EXTENT, 0, _out_of_memory, POOL_INTERN))) out_of_memory(msg); } else { /* This is a doubly linked list with prev looping back to * the end of the list, but the last next pointer is NULL. */ if (!first_flist) { if (!(flist->file_pool = pool_create(NORMAL_EXTENT, 0, _out_of_memory, POOL_INTERN))) out_of_memory(msg); flist->ndx_start = flist->flist_num = inc_recurse ? 1 : 0; first_flist = cur_flist = flist->prev = flist; } else { struct file_list *prev = first_flist->prev; flist->file_pool = first_flist->file_pool; flist->ndx_start = prev->ndx_start + prev->used + 1; flist->flist_num = prev->flist_num + 1; flist->prev = prev; prev->next = first_flist->prev = flist; } flist->pool_boundary = pool_boundary(flist->file_pool, 0); flist_cnt++; } return flist; } /* Free up all elements in a flist. */ void flist_free(struct file_list *flist) { if (!flist->prev) { /* Was FLIST_TEMP dir-list. */ } else if (flist == flist->prev) { first_flist = cur_flist = NULL; file_total = 0; flist_cnt = 0; } else { if (flist == cur_flist) cur_flist = flist->next; if (flist == first_flist) first_flist = first_flist->next; else { flist->prev->next = flist->next; if (!flist->next) flist->next = first_flist; } flist->next->prev = flist->prev; file_total -= flist->used; flist_cnt--; } if (!flist->prev || !flist_cnt) pool_destroy(flist->file_pool); else pool_free_old(flist->file_pool, flist->pool_boundary); if (flist->sorted && flist->sorted != flist->files) free(flist->sorted); free(flist->files); free(flist); } /* This routine ensures we don't have any duplicate names in our file list. * duplicate names can cause corruption because of the pipelining. */ static void flist_sort_and_clean(struct file_list *flist, int strip_root) { char fbuf[MAXPATHLEN]; int i, prev_i; if (!flist) return; if (flist->used == 0) { flist->high = -1; flist->low = 0; return; } fsort(flist->sorted, flist->used); if (!am_sender || inc_recurse) { for (i = prev_i = 0; i < flist->used; i++) { if (F_IS_ACTIVE(flist->sorted[i])) { prev_i = i; break; } } flist->low = prev_i; } else { i = prev_i = flist->used - 1; flist->low = 0; } while (++i < flist->used) { int j; struct file_struct *file = flist->sorted[i]; if (!F_IS_ACTIVE(file)) continue; if (f_name_cmp(file, flist->sorted[prev_i]) == 0) j = prev_i; else if (protocol_version >= 29 && S_ISDIR(file->mode)) { int save_mode = file->mode; /* Make sure that this directory doesn't duplicate a * non-directory earlier in the list. */ flist->high = prev_i; file->mode = S_IFREG; j = flist_find(flist, file); file->mode = save_mode; } else j = -1; if (j >= 0) { int keep, drop; /* 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. */ if (S_ISDIR(file->mode)) { struct file_struct *fp = flist->sorted[j]; if (!S_ISDIR(fp->mode)) keep = i, drop = j; else { if (am_sender) file->flags |= FLAG_DUPLICATE; else { /* Make sure we merge our vital flags. */ fp->flags |= file->flags & (FLAG_TOP_DIR|FLAG_CONTENT_DIR); fp->flags &= file->flags | ~FLAG_IMPLIED_DIR; } keep = j, drop = i; } } else keep = j, drop = i; if (!am_sender) { if (DEBUG_GTE(DUP, 1)) { rprintf(FINFO, "removing duplicate name %s from file list (%d)\n", f_name(file, fbuf), drop + flist->ndx_start); } clear_file(flist->sorted[drop]); } if (keep == i) { if (flist->low == drop) { for (j = drop + 1; j < i && !F_IS_ACTIVE(flist->sorted[j]); j++) {} flist->low = j; } prev_i = i; } } else prev_i = i; } flist->high = prev_i; if (strip_root) { /* We need to strip off the leading slashes for relative * paths, but this must be done _after_ the sorting phase. */ for (i = flist->low; i <= flist->high; i++) { struct file_struct *file = flist->sorted[i]; if (!file->dirname) continue; while (*file->dirname == '/') file->dirname++; if (!*file->dirname) file->dirname = NULL; } } if (prune_empty_dirs && !am_sender) { int j, prev_depth = 0; prev_i = 0; /* It's OK that this isn't really true. */ for (i = flist->low; i <= flist->high; i++) { struct file_struct *fp, *file = flist->sorted[i]; /* This temporarily abuses the F_DEPTH() value for a * directory that is in a chain that might get pruned. * We restore the old value if it gets a reprieve. */ if (S_ISDIR(file->mode) && F_DEPTH(file)) { /* Dump empty dirs when coming back down. */ for (j = prev_depth; j >= F_DEPTH(file); j--) { fp = flist->sorted[prev_i]; if (F_DEPTH(fp) >= 0) break; prev_i = -F_DEPTH(fp)-1; clear_file(fp); } prev_depth = F_DEPTH(file); if (is_excluded(f_name(file, fbuf), 1, ALL_FILTERS)) { /* Keep dirs through this dir. */ for (j = prev_depth-1; ; j--) { fp = flist->sorted[prev_i]; if (F_DEPTH(fp) >= 0) break; prev_i = -F_DEPTH(fp)-1; F_DEPTH(fp) = j; } } else F_DEPTH(file) = -prev_i-1; prev_i = i; } else { /* Keep dirs through this non-dir. */ for (j = prev_depth; ; j--) { fp = flist->sorted[prev_i]; if (F_DEPTH(fp) >= 0) break; prev_i = -F_DEPTH(fp)-1; F_DEPTH(fp) = j; } } } /* Dump all remaining empty dirs. */ while (1) { struct file_struct *fp = flist->sorted[prev_i]; if (F_DEPTH(fp) >= 0) break; prev_i = -F_DEPTH(fp)-1; clear_file(fp); } for (i = flist->low; i <= flist->high; i++) { if (F_IS_ACTIVE(flist->sorted[i])) break; } flist->low = i; for (i = flist->high; i >= flist->low; i--) { if (F_IS_ACTIVE(flist->sorted[i])) break; } flist->high = i; } } static void output_flist(struct file_list *flist) { char uidbuf[16], gidbuf[16], depthbuf[16]; struct file_struct *file; const char *root, *dir, *slash, *name, *trail; const char *who = who_am_i(); int i; rprintf(FINFO, "[%s] flist start=%d, used=%d, low=%d, high=%d\n", who, flist->ndx_start, flist->used, flist->low, flist->high); for (i = 0; i < flist->used; i++) { file = flist->files[i]; if ((am_root || am_sender) && uid_ndx) { snprintf(uidbuf, sizeof uidbuf, " uid=%u", F_OWNER(file)); } else *uidbuf = '\0'; if (gid_ndx) { static char parens[] = "(\0)\0\0\0"; char *pp = parens + (file->flags & FLAG_SKIP_GROUP ? 0 : 3); snprintf(gidbuf, sizeof gidbuf, " gid=%s%u%s", pp, F_GROUP(file), pp + 2); } else *gidbuf = '\0'; if (!am_sender) snprintf(depthbuf, sizeof depthbuf, "%d", F_DEPTH(file)); if (F_IS_ACTIVE(file)) { root = am_sender ? NS(F_PATHNAME(file)) : depthbuf; if ((dir = file->dirname) == NULL) dir = slash = ""; else slash = "/"; name = file->basename; trail = S_ISDIR(file->mode) ? "/" : ""; } else root = dir = slash = name = trail = ""; rprintf(FINFO, "[%s] i=%d %s %s%s%s%s mode=0%o len=%s%s%s flags=%x\n", who, i + flist->ndx_start, root, dir, slash, name, trail, (int)file->mode, comma_num(F_LENGTH(file)), uidbuf, gidbuf, file->flags); } } enum fnc_state { s_DIR, s_SLASH, s_BASE, s_TRAILING }; enum fnc_type { t_PATH, t_ITEM }; static int found_prefix; /* Compare the names of two file_struct entities, similar to how strcmp() * would do if it were operating on the joined strings. * * Some differences beginning with protocol_version 29: (1) directory names * are compared with an assumed trailing slash so that they compare in a * way that would cause them to sort immediately prior to any content they * may have; (2) a directory of any name compares after a non-directory of * any name at the same depth; (3) a directory with name "." compares prior * to anything else. These changes mean that a directory and a non-dir * with the same name will not compare as equal (protocol_version >= 29). * * The dirname component can be an empty string, but the basename component * cannot (and never is in the current codebase). The basename component * may be NULL (for a removed item), in which case it is considered to be * after any existing item. */ int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2) { int dif; const uchar *c1, *c2; enum fnc_state state1, state2; enum fnc_type type1, type2; enum fnc_type t_path = protocol_version >= 29 ? t_PATH : t_ITEM; if (!f1 || !F_IS_ACTIVE(f1)) { if (!f2 || !F_IS_ACTIVE(f2)) return 0; return -1; } if (!f2 || !F_IS_ACTIVE(f2)) return 1; c1 = (uchar*)f1->dirname; c2 = (uchar*)f2->dirname; if (c1 == c2) c1 = c2 = NULL; if (!c1) { type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; c1 = (const uchar*)f1->basename; if (type1 == t_PATH && *c1 == '.' && !c1[1]) { type1 = t_ITEM; state1 = s_TRAILING; c1 = (uchar*)""; } else state1 = s_BASE; } else { type1 = t_path; state1 = s_DIR; } if (!c2) { type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; c2 = (const uchar*)f2->basename; if (type2 == t_PATH && *c2 == '.' && !c2[1]) { type2 = t_ITEM; state2 = s_TRAILING; c2 = (uchar*)""; } else state2 = s_BASE; } else { type2 = t_path; state2 = s_DIR; } if (type1 != type2) return type1 == t_PATH ? 1 : -1; do { if (!*c1) { switch (state1) { case s_DIR: state1 = s_SLASH; c1 = (uchar*)"/"; break; case s_SLASH: type1 = S_ISDIR(f1->mode) ? t_path : t_ITEM; c1 = (const uchar*)f1->basename; if (type1 == t_PATH && *c1 == '.' && !c1[1]) { type1 = t_ITEM; state1 = s_TRAILING; c1 = (uchar*)""; } else state1 = s_BASE; break; case s_BASE: state1 = s_TRAILING; if (type1 == t_PATH) { c1 = (uchar*)"/"; break; } /* FALL THROUGH */ case s_TRAILING: type1 = t_ITEM; break; } if (*c2 && type1 != type2) return type1 == t_PATH ? 1 : -1; } if (!*c2) { switch (state2) { case s_DIR: state2 = s_SLASH; c2 = (uchar*)"/"; break; case s_SLASH: type2 = S_ISDIR(f2->mode) ? t_path : t_ITEM; c2 = (const uchar*)f2->basename; if (type2 == t_PATH && *c2 == '.' && !c2[1]) { type2 = t_ITEM; state2 = s_TRAILING; c2 = (uchar*)""; } else state2 = s_BASE; break; case s_BASE: state2 = s_TRAILING; if (type2 == t_PATH) { c2 = (uchar*)"/"; break; } /* FALL THROUGH */ case s_TRAILING: found_prefix = 1; if (!*c1) return 0; type2 = t_ITEM; break; } if (type1 != type2) return type1 == t_PATH ? 1 : -1; } } while ((dif = (int)*c1++ - (int)*c2++) == 0); return dif; } /* Returns 1 if f1's filename has all of f2's filename as a prefix. This does * not match if f2's basename is not an exact match of a path element in f1. * E.g. /path/foo is not a prefix of /path/foobar/baz, but /path/foobar is. */ int f_name_has_prefix(const struct file_struct *f1, const struct file_struct *f2) { found_prefix = 0; f_name_cmp(f1, f2); return found_prefix; } char *f_name_buf(void) { static char names[5][MAXPATHLEN]; static unsigned int n; n = (n + 1) % (sizeof names / sizeof names[0]); return names[n]; } /* Return a copy of the full filename of a flist entry, using the indicated * buffer or one of 5 static buffers if fbuf is NULL. No size-checking is * done because we checked the size when creating the file_struct entry. */ char *f_name(const struct file_struct *f, char *fbuf) { if (!f || !F_IS_ACTIVE(f)) return NULL; if (!fbuf) fbuf = f_name_buf(); if (f->dirname) { int len = strlen(f->dirname); memcpy(fbuf, f->dirname, len); fbuf[len] = '/'; strlcpy(fbuf + len + 1, f->basename, MAXPATHLEN - (len + 1)); } else strlcpy(fbuf, f->basename, MAXPATHLEN); return fbuf; } /* Do a non-recursive scan of the named directory, possibly ignoring all * exclude rules except for the daemon's. If "dlen" is >=0, it is the length * of the dirname string, and also indicates that "dirname" is a MAXPATHLEN * buffer (the functions we call will append names onto the end, but the old * dir value will be restored on exit). */ struct file_list *get_dirlist(char *dirname, int dlen, int flags) { struct file_list *dirlist; char dirbuf[MAXPATHLEN]; int save_recurse = recurse; int save_xfer_dirs = xfer_dirs; int save_prune_empty_dirs = prune_empty_dirs; int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1; int senddir_flags = FLAG_CONTENT_DIR; if (dlen < 0) { dlen = strlcpy(dirbuf, dirname, MAXPATHLEN); if (dlen >= MAXPATHLEN) return NULL; dirname = dirbuf; } dirlist = flist_new(FLIST_TEMP, "get_dirlist"); if (flags & GDL_PERHAPS_DIR) senddir_flags |= FLAG_PERHAPS_DIR; recurse = 0; xfer_dirs = 1; send_directory(senddir_fd, dirlist, dirname, dlen, senddir_flags); xfer_dirs = save_xfer_dirs; recurse = save_recurse; if (INFO_GTE(PROGRESS, 1)) flist_count_offset += dirlist->used; prune_empty_dirs = 0; dirlist->sorted = dirlist->files; flist_sort_and_clean(dirlist, 0); prune_empty_dirs = save_prune_empty_dirs; if (DEBUG_GTE(FLIST, 3)) output_flist(dirlist); return dirlist; } rsync-3.2.7/syscall.c0000664000000000000000000003654714213416160013214 0ustar rootroot/* * Syscall wrappers to ensure that nothing gets done in dry_run mode * and to handle system peculiarities. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2022 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" #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H #include #endif #ifdef HAVE_SYS_ATTR_H #include #endif #if defined HAVE_SYS_FALLOCATE && !defined HAVE_FALLOCATE #include #endif extern int dry_run; extern int am_root; extern int am_sender; extern int read_only; extern int list_only; extern int inplace; extern int preallocate_files; extern int preserve_perms; extern int preserve_executability; extern int open_noatime; #ifndef S_BLKSIZE # if defined hpux || defined __hpux__ || defined __hpux # define S_BLKSIZE 1024 # elif defined _AIX && defined _I386 # define S_BLKSIZE 4096 # else # define S_BLKSIZE 512 # endif #endif #ifdef SUPPORT_CRTIMES #ifdef HAVE_GETATTRLIST #pragma pack(push, 4) struct create_time { uint32 length; struct timespec crtime; }; #pragma pack(pop) #elif defined __CYGWIN__ #include #endif #endif #define RETURN_ERROR_IF(x,e) \ do { \ if (x) { \ errno = (e); \ return -1; \ } \ } while (0) #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS) int do_unlink(const char *path) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return unlink(path); } #ifdef SUPPORT_LINKS int do_symlink(const char *lnk, const char *path) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS /* For --fake-super, we create a normal file with mode 0600 * and write the lnk into it. */ if (am_root < 0) { int ok, len = strlen(lnk); int fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); if (fd < 0) return -1; ok = write(fd, lnk, len) == len; if (close(fd) < 0) ok = 0; return ok ? 0 : -1; } #endif return symlink(lnk, path); } #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS ssize_t do_readlink(const char *path, char *buf, size_t bufsiz) { /* For --fake-super, we read the link from the file. */ if (am_root < 0) { int fd = do_open_nofollow(path, O_RDONLY); if (fd >= 0) { int len = read(fd, buf, bufsiz); close(fd); return len; } if (errno != ELOOP) return -1; /* A real symlink needs to be turned into a fake one on the receiving * side, so tell the generator that the link has no length. */ if (!am_sender) return 0; /* Otherwise fall through and let the sender report the real length. */ } return readlink(path, buf, bufsiz); } #endif #endif #if defined HAVE_LINK || defined HAVE_LINKAT int do_link(const char *old_path, const char *new_path) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #ifdef HAVE_LINKAT return linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); #else return link(old_path, new_path); #endif } #endif int do_lchown(const char *path, uid_t owner, gid_t group) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #ifndef HAVE_LCHOWN #define lchown chown #endif return lchown(path, owner, group); } int do_mknod(const char *pathname, mode_t mode, dev_t dev) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; /* For --fake-super, we create a normal file with mode 0600. */ if (am_root < 0) { int fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); if (fd < 0 || close(fd) < 0) return -1; return 0; } #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO if (S_ISFIFO(mode)) return mkfifo(pathname, mode); #endif #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H if (S_ISSOCK(mode)) { int sock; struct sockaddr_un saddr; unsigned int len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path); if (len >= sizeof saddr.sun_path) { errno = ENAMETOOLONG; return -1; } #ifdef HAVE_SOCKADDR_UN_LEN saddr.sun_len = len + 1; #endif saddr.sun_family = AF_UNIX; if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 || (unlink(pathname) < 0 && errno != ENOENT) || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0) return -1; close(sock); #ifdef HAVE_CHMOD return do_chmod(pathname, mode); #else return 0; #endif } #endif #ifdef HAVE_MKNOD return mknod(pathname, mode, dev); #else return -1; #endif } int do_rmdir(const char *pathname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return rmdir(pathname); } int do_open(const char *pathname, int flags, mode_t mode) { if (flags != O_RDONLY) { RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF_RO_OR_LO; } #ifdef O_NOATIME if (open_noatime) flags |= O_NOATIME; #endif return open(pathname, flags | O_BINARY, mode); } #ifdef HAVE_CHMOD int do_chmod(const char *path, mode_t mode) { static int switch_step = 0; int code; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; switch (switch_step) { #ifdef HAVE_LCHMOD case 0: if ((code = lchmod(path, mode & CHMOD_BITS)) == 0) break; if (errno == ENOSYS) switch_step++; else if (errno != ENOTSUP) break; #endif /* FALLTHROUGH */ default: if (S_ISLNK(mode)) { # if defined HAVE_SETATTRLIST struct attrlist attrList; uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */ memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_ACCESSMASK; if ((code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW)) == 0) break; if (errno == ENOTSUP) code = 1; # else code = 1; # endif } else code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ break; } if (code != 0 && (preserve_perms || preserve_executability)) return code; return 0; } #endif int do_rename(const char *old_path, const char *new_path) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return rename(old_path, new_path); } #ifdef HAVE_FTRUNCATE int do_ftruncate(int fd, OFF_T size) { int ret; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; do { ret = ftruncate(fd, size); } while (ret < 0 && errno == EINTR); return ret; } #endif void trim_trailing_slashes(char *name) { int l; /* Some BSD systems cannot make a directory if the name * contains a trailing slash. * */ /* Don't change empty string; and also we can't improve on * "/" */ l = strlen(name); while (l > 1) { if (name[--l] != '/') break; name[l] = '\0'; } } int do_mkdir(char *path, mode_t mode) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; trim_trailing_slashes(path); return mkdir(path, mode); } /* like mkstemp but forces permissions */ int do_mkstemp(char *template, mode_t perms) { RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF(read_only, EROFS); perms |= S_IWUSR; #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64) { int fd = mkstemp(template); if (fd == -1) return -1; if (fchmod(fd, perms) != 0 && preserve_perms) { int errno_save = errno; close(fd); unlink(template); errno = errno_save; return -1; } #if defined HAVE_SETMODE && O_BINARY setmode(fd, O_BINARY); #endif return fd; } #else if (!mktemp(template)) return -1; return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms); #endif } int do_stat(const char *path, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS return stat64(path, st); #else return stat(path, st); #endif } int do_lstat(const char *path, STRUCT_STAT *st) { #ifdef SUPPORT_LINKS # ifdef USE_STAT64_FUNCS return lstat64(path, st); # else return lstat(path, st); # endif #else return do_stat(path, st); #endif } int do_fstat(int fd, STRUCT_STAT *st) { #ifdef USE_STAT64_FUNCS return fstat64(fd, st); #else return fstat(fd, st); #endif } OFF_T do_lseek(int fd, OFF_T offset, int whence) { #ifdef HAVE_LSEEK64 #if !SIZEOF_OFF64_T OFF_T lseek64(); #else off64_t lseek64(); #endif return lseek64(fd, offset, whence); #else return lseek(fd, offset, whence); #endif } #ifdef HAVE_SETATTRLIST int do_setattrlist_times(const char *path, STRUCT_STAT *stp) { struct attrlist attrList; struct timespec ts[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; /* Yes, this is in the opposite order of utime and similar. */ ts[0].tv_sec = stp->st_mtime; ts[0].tv_nsec = stp->ST_MTIME_NSEC; ts[1].tv_sec = stp->st_atime; ts[1].tv_nsec = stp->ST_ATIME_NSEC; memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME; return setattrlist(path, &attrList, ts, sizeof ts, FSOPT_NOFOLLOW); } #ifdef SUPPORT_CRTIMES int do_setattrlist_crtime(const char *path, time_t crtime) { struct attrlist attrList; struct timespec ts; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; ts.tv_sec = crtime; ts.tv_nsec = 0; memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_CRTIME; return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW); } #endif #endif /* HAVE_SETATTRLIST */ #ifdef SUPPORT_CRTIMES time_t get_create_time(const char *path, STRUCT_STAT *stp) { #ifdef HAVE_GETATTRLIST static struct create_time attrBuf; struct attrlist attrList; (void)stp; memset(&attrList, 0, sizeof attrList); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_CRTIME; if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0) return 0; return attrBuf.crtime.tv_sec; #elif defined __CYGWIN__ (void)path; return stp->st_birthtime; #else #error Unknown crtimes implementation #endif } #if defined __CYGWIN__ int do_SetFileTime(const char *path, time_t crtime) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; int cnt = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); if (cnt == 0) return -1; WCHAR *pathw = new_array(WCHAR, cnt); if (!pathw) return -1; MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw, cnt); HANDLE handle = CreateFileW(pathw, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); free(pathw); if (handle == INVALID_HANDLE_VALUE) return -1; int64 temp_time = Int32x32To64(crtime, 10000000) + 116444736000000000LL; FILETIME birth_time; birth_time.dwLowDateTime = (DWORD)temp_time; birth_time.dwHighDateTime = (DWORD)(temp_time >> 32); int ok = SetFileTime(handle, &birth_time, NULL, NULL); CloseHandle(handle); return ok ? 0 : -1; } #endif #endif /* SUPPORT_CRTIMES */ #ifdef HAVE_UTIMENSAT int do_utimensat(const char *path, STRUCT_STAT *stp) { struct timespec t[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; t[0].tv_sec = stp->st_atime; #ifdef ST_ATIME_NSEC t[0].tv_nsec = stp->ST_ATIME_NSEC; #else t[0].tv_nsec = 0; #endif t[1].tv_sec = stp->st_mtime; #ifdef ST_MTIME_NSEC t[1].tv_nsec = stp->ST_MTIME_NSEC; #else t[1].tv_nsec = 0; #endif return utimensat(AT_FDCWD, path, t, AT_SYMLINK_NOFOLLOW); } #endif #ifdef HAVE_LUTIMES int do_lutimes(const char *path, STRUCT_STAT *stp) { struct timeval t[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; t[0].tv_sec = stp->st_atime; #ifdef ST_ATIME_NSEC t[0].tv_usec = stp->ST_ATIME_NSEC / 1000; #else t[0].tv_usec = 0; #endif t[1].tv_sec = stp->st_mtime; #ifdef ST_MTIME_NSEC t[1].tv_usec = stp->ST_MTIME_NSEC / 1000; #else t[1].tv_usec = 0; #endif return lutimes(path, t); } #endif #ifdef HAVE_UTIMES int do_utimes(const char *path, STRUCT_STAT *stp) { struct timeval t[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; t[0].tv_sec = stp->st_atime; #ifdef ST_ATIME_NSEC t[0].tv_usec = stp->ST_ATIME_NSEC / 1000; #else t[0].tv_usec = 0; #endif t[1].tv_sec = stp->st_mtime; #ifdef ST_MTIME_NSEC t[1].tv_usec = stp->ST_MTIME_NSEC / 1000; #else t[1].tv_usec = 0; #endif return utimes(path, t); } #elif defined HAVE_UTIME int do_utime(const char *path, STRUCT_STAT *stp) { #ifdef HAVE_STRUCT_UTIMBUF struct utimbuf tbuf; #else time_t t[2]; #endif if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; # ifdef HAVE_STRUCT_UTIMBUF tbuf.actime = stp->st_atime; tbuf.modtime = stp->st_mtime; return utime(path, &tbuf); # else t[0] = stp->st_atime; t[1] = stp->st_mtime; return utime(path, t); # endif } #else #error Need utimes or utime function. #endif #ifdef SUPPORT_PREALLOCATION #ifdef FALLOC_FL_KEEP_SIZE #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE #else #define DO_FALLOC_OPTIONS 0 #endif OFF_T do_fallocate(int fd, OFF_T offset, OFF_T length) { int opts = inplace || preallocate_files ? DO_FALLOC_OPTIONS : 0; int ret; RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF_RO_OR_LO; if (length & 1) /* make the length not match the desired length */ length++; else length--; #if defined HAVE_FALLOCATE ret = fallocate(fd, opts, offset, length); #elif defined HAVE_SYS_FALLOCATE ret = syscall(SYS_fallocate, fd, opts, (loff_t)offset, (loff_t)length); #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE ret = posix_fallocate(fd, offset, length); #else #error Coding error in SUPPORT_PREALLOCATION logic. #endif if (ret < 0) return ret; if (opts == 0) { STRUCT_STAT st; if (do_fstat(fd, &st) < 0) return length; return st.st_blocks * S_BLKSIZE; } return 0; } #endif /* Punch a hole at pos for len bytes. The current file position must be at pos and will be * changed to be at pos + len. */ int do_punch_hole(int fd, OFF_T pos, OFF_T len) { #ifdef HAVE_FALLOCATE # ifdef HAVE_FALLOC_FL_PUNCH_HOLE if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, pos, len) == 0) { if (do_lseek(fd, len, SEEK_CUR) != pos + len) return -1; return 0; } # endif # ifdef HAVE_FALLOC_FL_ZERO_RANGE if (fallocate(fd, FALLOC_FL_ZERO_RANGE, pos, len) == 0) { if (do_lseek(fd, len, SEEK_CUR) != pos + len) return -1; return 0; } # endif #else (void)pos; #endif { char zeros[4096]; memset(zeros, 0, sizeof zeros); while (len > 0) { int chunk = len > (int)sizeof zeros ? (int)sizeof zeros : len; int wrote = write(fd, zeros, chunk); if (wrote <= 0) { if (wrote < 0 && errno == EINTR) continue; return -1; } len -= wrote; } } return 0; } int do_open_nofollow(const char *pathname, int flags) { #ifndef O_NOFOLLOW STRUCT_STAT f_st, l_st; #endif int fd; if (flags != O_RDONLY) { RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF_RO_OR_LO; #ifndef O_NOFOLLOW /* This function doesn't support write attempts w/o O_NOFOLLOW. */ errno = EINVAL; return -1; #endif } #ifdef O_NOFOLLOW fd = open(pathname, flags|O_NOFOLLOW); #else if (do_lstat(pathname, &l_st) < 0) return -1; if (S_ISLNK(l_st.st_mode)) { errno = ELOOP; return -1; } if ((fd = open(pathname, flags)) < 0) return fd; if (do_fstat(fd, &f_st) < 0) { close_and_return_error: { int save_errno = errno; close(fd); errno = save_errno; } return -1; } if (l_st.st_dev != f_st.st_dev || l_st.st_ino != f_st.st_ino) { errno = EINVAL; goto close_and_return_error; } #endif return fd; } rsync-3.2.7/io.c0000664000000000000000000020267314316341136012150 0ustar rootroot/* * Socket and pipe I/O utilities used in rsync. * * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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. */ /* Rsync provides its own multiplexing system, which is used to send * stderr and stdout over a single socket. * * For historical reasons this is off during the start of the * connection, but it's switched on quite early using * io_start_multiplex_out() and io_start_multiplex_in(). */ #include "rsync.h" #include "ifuncs.h" #include "inums.h" /** If no timeout is specified then use a 60 second select timeout */ #define SELECT_TIMEOUT 60 extern int bwlimit; extern size_t bwlimit_writemax; extern int io_timeout; extern int am_server; extern int am_sender; extern int am_receiver; extern int am_generator; extern int local_server; extern int msgs2stderr; extern int inc_recurse; extern int io_error; extern int batch_fd; extern int eol_nulls; extern int flist_eof; extern int file_total; extern int file_old_total; extern int list_only; extern int read_batch; extern int compat_flags; extern int protect_args; extern int checksum_seed; extern int daemon_connection; extern int protocol_version; extern int remove_source_files; extern int preserve_hard_links; extern BOOL extra_flist_sending_enabled; extern BOOL flush_ok_after_signal; extern struct stats stats; extern time_t stop_at_utime; extern struct file_list *cur_flist; #ifdef ICONV_OPTION extern int filesfrom_convert; extern iconv_t ic_send, ic_recv; #endif int csum_length = SHORT_SUM_LENGTH; /* initial value */ int allowed_lull = 0; int msgdone_cnt = 0; int forward_flist_data = 0; BOOL flist_receiving_enabled = False; /* Ignore an EOF error if non-zero. See whine_about_eof(). */ int kluge_around_eof = 0; int got_kill_signal = -1; /* is set to 0 only after multiplexed I/O starts */ int sock_f_in = -1; int sock_f_out = -1; int64 total_data_read = 0; int64 total_data_written = 0; char num_dev_ino_buf[4 + 8 + 8]; static struct { xbuf in, out, msg; int in_fd; int out_fd; /* Both "out" and "msg" go to this fd. */ int in_multiplexed; unsigned out_empty_len; size_t raw_data_header_pos; /* in the out xbuf */ size_t raw_flushing_ends_before; /* in the out xbuf */ size_t raw_input_ends_before; /* in the in xbuf */ } iobuf = { .in_fd = -1, .out_fd = -1 }; static time_t last_io_in; static time_t last_io_out; static int write_batch_monitor_in = -1; static int write_batch_monitor_out = -1; static int ff_forward_fd = -1; static int ff_reenable_multiplex = -1; static char ff_lastchar = '\0'; static xbuf ff_xb = EMPTY_XBUF; #ifdef ICONV_OPTION static xbuf iconv_buf = EMPTY_XBUF; #endif static int select_timeout = SELECT_TIMEOUT; static int active_filecnt = 0; static OFF_T active_bytecnt = 0; static int first_message = 1; static char int_byte_extra[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* (00 - 3F)/4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* (40 - 7F)/4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* (80 - BF)/4 */ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6, /* (C0 - FF)/4 */ }; /* Our I/O buffers are sized with no bits on in the lowest byte of the "size" * (indeed, our rounding of sizes in 1024-byte units assures more than this). * This allows the code that is storing bytes near the physical end of a * circular buffer to temporarily reduce the buffer's size (in order to make * some storing idioms easier), while also making it simple to restore the * buffer's actual size when the buffer's "pos" wraps around to the start (we * just round the buffer's size up again). */ #define IOBUF_WAS_REDUCED(siz) ((siz) & 0xFF) #define IOBUF_RESTORE_SIZE(siz) (((siz) | 0xFF) + 1) #define IN_MULTIPLEXED (iobuf.in_multiplexed != 0) #define IN_MULTIPLEXED_AND_READY (iobuf.in_multiplexed > 0) #define OUT_MULTIPLEXED (iobuf.out_empty_len != 0) #define PIO_NEED_INPUT (1<<0) /* The *_NEED_* flags are mutually exclusive. */ #define PIO_NEED_OUTROOM (1<<1) #define PIO_NEED_MSGROOM (1<<2) #define PIO_CONSUME_INPUT (1<<4) /* Must becombined with PIO_NEED_INPUT. */ #define PIO_INPUT_AND_CONSUME (PIO_NEED_INPUT | PIO_CONSUME_INPUT) #define PIO_NEED_FLAGS (PIO_NEED_INPUT | PIO_NEED_OUTROOM | PIO_NEED_MSGROOM) #define REMOTE_OPTION_ERROR "rsync: on remote machine: -" #define REMOTE_OPTION_ERROR2 ": unknown option" #define FILESFROM_BUFLEN 2048 enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND }; static flist_ndx_list redo_list, hlink_list; static void read_a_msg(void); static void drain_multiplex_messages(void); static void sleep_for_bwlimit(int bytes_written); static void check_timeout(BOOL allow_keepalive, int keepalive_flags) { time_t t, chk; /* On the receiving side, the generator is now the one that decides * when a timeout has occurred. When it is sifting through a lot of * files looking for work, it will be sending keep-alive messages to * the sender, and even though the receiver won't be sending/receiving * anything (not even keep-alive messages), the successful writes to * the sender will keep things going. If the receiver is actively * receiving data, it will ensure that the generator knows that it is * not idle by sending the generator keep-alive messages (since the * generator might be blocked trying to send checksums, it needs to * know that the receiver is active). Thus, as long as one or the * other is successfully doing work, the generator will not timeout. */ if (!io_timeout) return; t = time(NULL); if (allow_keepalive) { /* This may put data into iobuf.msg w/o flushing. */ maybe_send_keepalive(t, keepalive_flags); } if (!last_io_in) last_io_in = t; if (am_receiver) return; chk = MAX(last_io_out, last_io_in); if (t - chk >= io_timeout) { if (am_server) msgs2stderr = 1; rprintf(FERROR, "[%s] io timeout after %d seconds -- exiting\n", who_am_i(), (int)(t-chk)); exit_cleanup(RERR_TIMEOUT); } } /* It's almost always an error to get an EOF when we're trying to read from the * network, because the protocol is (for the most part) self-terminating. * * There is one case for the receiver when it is at the end of the transfer * (hanging around reading any keep-alive packets that might come its way): if * the sender dies before the generator's kill-signal comes through, we can end * up here needing to loop until the kill-signal arrives. In this situation, * kluge_around_eof will be < 0. * * There is another case for older protocol versions (< 24) where the module * listing was not terminated, so we must ignore an EOF error in that case and * exit. In this situation, kluge_around_eof will be > 0. */ static NORETURN void whine_about_eof(BOOL allow_kluge) { if (kluge_around_eof && allow_kluge) { int i; if (kluge_around_eof > 0) exit_cleanup(0); /* If we're still here after 10 seconds, exit with an error. */ for (i = 10*1000/20; i--; ) msleep(20); } rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed " "(%s bytes received so far) [%s]\n", big_num(stats.total_read), who_am_i()); exit_cleanup(RERR_STREAMIO); } /* Do a safe read, handling any needed looping and error handling. * Returns the count of the bytes read, which will only be different * from "len" if we encountered an EOF. This routine is not used on * the socket except very early in the transfer. */ static size_t safe_read(int fd, char *buf, size_t len) { size_t got = 0; assert(fd != iobuf.in_fd); while (1) { struct timeval tv; fd_set r_fds, e_fds; int cnt; FD_ZERO(&r_fds); FD_SET(fd, &r_fds); FD_ZERO(&e_fds); FD_SET(fd, &e_fds); tv.tv_sec = select_timeout; tv.tv_usec = 0; cnt = select(fd+1, &r_fds, NULL, &e_fds, &tv); if (cnt <= 0) { if (cnt < 0 && errno == EBADF) { rsyserr(FERROR, errno, "safe_read select failed"); exit_cleanup(RERR_FILEIO); } check_timeout(1, MSK_ALLOW_FLUSH); continue; } /*if (FD_ISSET(fd, &e_fds)) rprintf(FINFO, "select exception on fd %d\n", fd); */ if (FD_ISSET(fd, &r_fds)) { ssize_t n = read(fd, buf + got, len - got); if (DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] safe_read(%d)=%" SIZE_T_FMT_MOD "d\n", who_am_i(), fd, (SIZE_T_FMT_CAST)n); } if (n == 0) break; if (n < 0) { if (errno == EINTR) continue; rsyserr(FERROR, errno, "safe_read failed to read %" SIZE_T_FMT_MOD "d bytes", (SIZE_T_FMT_CAST)len); exit_cleanup(RERR_STREAMIO); } if ((got += (size_t)n) == len) break; } } return got; } static const char *what_fd_is(int fd) { static char buf[20]; if (fd == sock_f_out) return "socket"; else if (fd == iobuf.out_fd) return "message fd"; else if (fd == batch_fd) return "batch file"; else { snprintf(buf, sizeof buf, "fd %d", fd); return buf; } } /* Do a safe write, handling any needed looping and error handling. * Returns only if everything was successfully written. This routine * is not used on the socket except very early in the transfer. */ static void safe_write(int fd, const char *buf, size_t len) { ssize_t n; assert(fd != iobuf.out_fd); n = write(fd, buf, len); if ((size_t)n == len) return; if (n < 0) { if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) { write_failed: rsyserr(FERROR, errno, "safe_write failed to write %" SIZE_T_FMT_MOD "d bytes to %s", (SIZE_T_FMT_CAST)len, what_fd_is(fd)); exit_cleanup(RERR_STREAMIO); } } else { buf += n; len -= n; } while (len) { struct timeval tv; fd_set w_fds; int cnt; FD_ZERO(&w_fds); FD_SET(fd, &w_fds); tv.tv_sec = select_timeout; tv.tv_usec = 0; cnt = select(fd + 1, NULL, &w_fds, NULL, &tv); if (cnt <= 0) { if (cnt < 0 && errno == EBADF) { rsyserr(FERROR, errno, "safe_write select failed on %s", what_fd_is(fd)); exit_cleanup(RERR_FILEIO); } if (io_timeout) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); continue; } if (FD_ISSET(fd, &w_fds)) { n = write(fd, buf, len); if (n < 0) { if (errno == EINTR) continue; goto write_failed; } buf += n; len -= n; } } } /* This is only called when files-from data is known to be available. We read * a chunk of data and put it into the output buffer. */ static void forward_filesfrom_data(void) { ssize_t len; len = read(ff_forward_fd, ff_xb.buf + ff_xb.len, ff_xb.size - ff_xb.len); if (len <= 0) { if (len == 0 || errno != EINTR) { /* Send end-of-file marker */ ff_forward_fd = -1; write_buf(iobuf.out_fd, "\0\0", ff_lastchar ? 2 : 1); free_xbuf(&ff_xb); if (ff_reenable_multiplex >= 0) io_start_multiplex_out(ff_reenable_multiplex); free_implied_include_partial_string(); } return; } if (DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] files-from read=%" SIZE_T_FMT_MOD "d\n", who_am_i(), (SIZE_T_FMT_CAST)len); } #ifdef ICONV_OPTION len += ff_xb.len; #endif if (!eol_nulls) { char *s = ff_xb.buf + len; /* Transform CR and/or LF into '\0' */ while (s-- > ff_xb.buf) { if (*s == '\n' || *s == '\r') *s = '\0'; } } if (ff_lastchar) ff_xb.pos = 0; else { char *s = ff_xb.buf; /* Last buf ended with a '\0', so don't let this buf start with one. */ while (len && *s == '\0') s++, len--; ff_xb.pos = s - ff_xb.buf; } #ifdef ICONV_OPTION if (filesfrom_convert && len) { char *sob = ff_xb.buf + ff_xb.pos, *s = sob; char *eob = sob + len; int flags = ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_CIRCULAR_OUT; if (ff_lastchar == '\0') flags |= ICB_INIT; /* Convert/send each null-terminated string separately, skipping empties. */ while (s != eob) { if (*s++ == '\0') { ff_xb.len = s - sob - 1; add_implied_include(sob, 0); if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) exit_cleanup(RERR_PROTOCOL); /* impossible? */ write_buf(iobuf.out_fd, s-1, 1); /* Send the '\0'. */ while (s != eob && *s == '\0') s++; sob = s; ff_xb.pos = sob - ff_xb.buf; flags |= ICB_INIT; } } if ((ff_xb.len = s - sob) == 0) ff_lastchar = '\0'; else { /* Handle a partial string specially, saving any incomplete chars. */ implied_include_partial_string(sob, s); flags &= ~ICB_INCLUDE_INCOMPLETE; if (iconvbufs(ic_send, &ff_xb, &iobuf.out, flags) < 0) { if (errno == E2BIG) exit_cleanup(RERR_PROTOCOL); /* impossible? */ if (ff_xb.pos) memmove(ff_xb.buf, ff_xb.buf + ff_xb.pos, ff_xb.len); } ff_lastchar = 'x'; /* Anything non-zero. */ } } else #endif if (len) { char *f = ff_xb.buf + ff_xb.pos; char *t = ff_xb.buf; char *eob = f + len; char *cur = t; /* Eliminate any multi-'\0' runs. */ while (f != eob) { if (!(*t++ = *f++)) { add_implied_include(cur, 0); cur = t; while (f != eob && *f == '\0') f++; } } implied_include_partial_string(cur, t); ff_lastchar = f[-1]; if ((len = t - ff_xb.buf) != 0) { /* This will not circle back to perform_io() because we only get * called when there is plenty of room in the output buffer. */ write_buf(iobuf.out_fd, ff_xb.buf, len); } } } void reduce_iobuf_size(xbuf *out, size_t new_size) { if (new_size < out->size) { /* Avoid weird buffer interactions by only outputting this to stderr. */ if (msgs2stderr == 1 && DEBUG_GTE(IO, 4)) { const char *name = out == &iobuf.out ? "iobuf.out" : out == &iobuf.msg ? "iobuf.msg" : NULL; if (name) { rprintf(FINFO, "[%s] reduced size of %s (-%d)\n", who_am_i(), name, (int)(out->size - new_size)); } } out->size = new_size; } } void restore_iobuf_size(xbuf *out) { if (IOBUF_WAS_REDUCED(out->size)) { size_t new_size = IOBUF_RESTORE_SIZE(out->size); /* Avoid weird buffer interactions by only outputting this to stderr. */ if (msgs2stderr == 1 && DEBUG_GTE(IO, 4)) { const char *name = out == &iobuf.out ? "iobuf.out" : out == &iobuf.msg ? "iobuf.msg" : NULL; if (name) { rprintf(FINFO, "[%s] restored size of %s (+%d)\n", who_am_i(), name, (int)(new_size - out->size)); } } out->size = new_size; } } static void handle_kill_signal(BOOL flush_ok) { got_kill_signal = -1; flush_ok_after_signal = flush_ok; exit_cleanup(RERR_SIGNAL); } /* Perform buffered input and/or output until specified conditions are met. * When given a "needed" read or write request, this returns without doing any * I/O if the needed input bytes or write space is already available. Once I/O * is needed, this will try to do whatever reading and/or writing is currently * possible, up to the maximum buffer allowances, no matter if this is a read * or write request. However, the I/O stops as soon as the required input * bytes or output space is available. If this is not a read request, the * routine may also do some advantageous reading of messages from a multiplexed * input source (which ensures that we don't jam up with everyone in their * "need to write" code and nobody reading the accumulated data that would make * writing possible). * * The iobuf.in, .out and .msg buffers are all circular. Callers need to be * aware that some data copies will need to be split when the bytes wrap around * from the end to the start. In order to help make writing into the output * buffers easier for some operations (such as the use of SIVAL() into the * buffer) a buffer may be temporarily shortened by a small amount, but the * original size will be automatically restored when the .pos wraps to the * start. See also the 3 raw_* iobuf vars that are used in the handling of * MSG_DATA bytes as they are read-from/written-into the buffers. * * When writing, we flush data in the following priority order: * * 1. Finish writing any in-progress MSG_DATA sequence from iobuf.out. * * 2. Write out all the messages from the message buf (if iobuf.msg is active). * Yes, this means that a PIO_NEED_OUTROOM call will completely flush any * messages before getting to the iobuf.out flushing (except for rule 1). * * 3. Write out the raw data from iobuf.out, possibly filling in the multiplexed * MSG_DATA header that was pre-allocated (when output is multiplexed). * * TODO: items for possible future work: * * - Make this routine able to read the generator-to-receiver batch flow? * * Unlike the old routines that this replaces, it is OK to read ahead as far as * we can because the read_a_msg() routine now reads its bytes out of the input * buffer. In the old days, only raw data was in the input buffer, and any * unused raw data in the buf would prevent the reading of socket data. */ static char *perform_io(size_t needed, int flags) { fd_set r_fds, e_fds, w_fds; struct timeval tv; int cnt, max_fd; size_t empty_buf_len = 0; xbuf *out; char *data; if (iobuf.in.len == 0 && iobuf.in.pos != 0) { if (iobuf.raw_input_ends_before) iobuf.raw_input_ends_before -= iobuf.in.pos; iobuf.in.pos = 0; } switch (flags & PIO_NEED_FLAGS) { case PIO_NEED_INPUT: /* We never resize the circular input buffer. */ if (iobuf.in.size < needed) { rprintf(FERROR, "need to read %" SIZE_T_FMT_MOD "d bytes," " iobuf.in.buf is only %" SIZE_T_FMT_MOD "d bytes.\n", (SIZE_T_FMT_CAST)needed, (SIZE_T_FMT_CAST)iobuf.in.size); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr == 1 && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%" SIZE_T_FMT_MOD "d, %sinput)\n", who_am_i(), (SIZE_T_FMT_CAST)needed, flags & PIO_CONSUME_INPUT ? "consume&" : ""); } break; case PIO_NEED_OUTROOM: /* We never resize the circular output buffer. */ if (iobuf.out.size - iobuf.out_empty_len < needed) { fprintf(stderr, "need to write %" SIZE_T_FMT_MOD "d bytes," " iobuf.out.buf is only %" SIZE_T_FMT_MOD "d bytes.\n", (SIZE_T_FMT_CAST)needed, (SIZE_T_FMT_CAST)(iobuf.out.size - iobuf.out_empty_len)); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr == 1 && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%" SIZE_T_FMT_MOD "d," " outroom) needs to flush %" SIZE_T_FMT_MOD "d\n", who_am_i(), (SIZE_T_FMT_CAST)needed, iobuf.out.len + needed > iobuf.out.size ? (SIZE_T_FMT_CAST)(iobuf.out.len + needed - iobuf.out.size) : (SIZE_T_FMT_CAST)0); } break; case PIO_NEED_MSGROOM: /* We never resize the circular message buffer. */ if (iobuf.msg.size < needed) { fprintf(stderr, "need to write %" SIZE_T_FMT_MOD "d bytes," " iobuf.msg.buf is only %" SIZE_T_FMT_MOD "d bytes.\n", (SIZE_T_FMT_CAST)needed, (SIZE_T_FMT_CAST)iobuf.msg.size); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr == 1 && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%" SIZE_T_FMT_MOD "d," " msgroom) needs to flush %" SIZE_T_FMT_MOD "d\n", who_am_i(), (SIZE_T_FMT_CAST)needed, iobuf.msg.len + needed > iobuf.msg.size ? (SIZE_T_FMT_CAST)(iobuf.msg.len + needed - iobuf.msg.size) : (SIZE_T_FMT_CAST)0); } break; case 0: if (msgs2stderr == 1 && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%" SIZE_T_FMT_MOD "d, %d)\n", who_am_i(), (SIZE_T_FMT_CAST)needed, flags); } break; default: exit_cleanup(RERR_UNSUPPORTED); } while (1) { switch (flags & PIO_NEED_FLAGS) { case PIO_NEED_INPUT: if (iobuf.in.len >= needed) goto double_break; break; case PIO_NEED_OUTROOM: /* Note that iobuf.out_empty_len doesn't factor into this check * because iobuf.out.len already holds any needed header len. */ if (iobuf.out.len + needed <= iobuf.out.size) goto double_break; break; case PIO_NEED_MSGROOM: if (iobuf.msg.len + needed <= iobuf.msg.size) goto double_break; break; } max_fd = -1; FD_ZERO(&r_fds); FD_ZERO(&e_fds); if (iobuf.in_fd >= 0 && iobuf.in.size - iobuf.in.len) { if (!read_batch || batch_fd >= 0) { FD_SET(iobuf.in_fd, &r_fds); FD_SET(iobuf.in_fd, &e_fds); } if (iobuf.in_fd > max_fd) max_fd = iobuf.in_fd; } /* Only do more filesfrom processing if there is enough room in the out buffer. */ if (ff_forward_fd >= 0 && iobuf.out.size - iobuf.out.len > FILESFROM_BUFLEN*2) { FD_SET(ff_forward_fd, &r_fds); if (ff_forward_fd > max_fd) max_fd = ff_forward_fd; } FD_ZERO(&w_fds); if (iobuf.out_fd >= 0) { if (iobuf.raw_flushing_ends_before || (!iobuf.msg.len && iobuf.out.len > iobuf.out_empty_len && !(flags & PIO_NEED_MSGROOM))) { if (OUT_MULTIPLEXED && !iobuf.raw_flushing_ends_before) { /* The iobuf.raw_flushing_ends_before value can point off the end * of the iobuf.out buffer for a while, for easier subtracting. */ iobuf.raw_flushing_ends_before = iobuf.out.pos + iobuf.out.len; SIVAL(iobuf.out.buf + iobuf.raw_data_header_pos, 0, ((MPLEX_BASE + (int)MSG_DATA)<<24) + iobuf.out.len - 4); if (msgs2stderr == 1 && DEBUG_GTE(IO, 1)) { rprintf(FINFO, "[%s] send_msg(%d, %" SIZE_T_FMT_MOD "d)\n", who_am_i(), (int)MSG_DATA, (SIZE_T_FMT_CAST)iobuf.out.len - 4); } /* reserve room for the next MSG_DATA header */ iobuf.raw_data_header_pos = iobuf.raw_flushing_ends_before; if (iobuf.raw_data_header_pos >= iobuf.out.size) iobuf.raw_data_header_pos -= iobuf.out.size; else if (iobuf.raw_data_header_pos + 4 > iobuf.out.size) { /* The 4-byte header won't fit at the end of the buffer, * so we'll temporarily reduce the output buffer's size * and put the header at the start of the buffer. */ reduce_iobuf_size(&iobuf.out, iobuf.raw_data_header_pos); iobuf.raw_data_header_pos = 0; } /* Yes, it is possible for this to make len > size for a while. */ iobuf.out.len += 4; } empty_buf_len = iobuf.out_empty_len; out = &iobuf.out; } else if (iobuf.msg.len) { empty_buf_len = 0; out = &iobuf.msg; } else out = NULL; if (out) { FD_SET(iobuf.out_fd, &w_fds); if (iobuf.out_fd > max_fd) max_fd = iobuf.out_fd; } } else out = NULL; if (max_fd < 0) { switch (flags & PIO_NEED_FLAGS) { case PIO_NEED_INPUT: iobuf.in.len = 0; if (kluge_around_eof == 2) exit_cleanup(0); if (iobuf.in_fd == -2) whine_about_eof(True); rprintf(FERROR, "error in perform_io: no fd for input.\n"); exit_cleanup(RERR_PROTOCOL); case PIO_NEED_OUTROOM: case PIO_NEED_MSGROOM: msgs2stderr = 1; drain_multiplex_messages(); if (iobuf.out_fd == -2) whine_about_eof(True); rprintf(FERROR, "error in perform_io: no fd for output.\n"); exit_cleanup(RERR_PROTOCOL); default: /* No stated needs, so I guess this is OK. */ break; } break; } if (got_kill_signal > 0) handle_kill_signal(True); if (extra_flist_sending_enabled) { if (file_total - file_old_total < MAX_FILECNT_LOOKAHEAD && IN_MULTIPLEXED_AND_READY) tv.tv_sec = 0; else { extra_flist_sending_enabled = False; tv.tv_sec = select_timeout; } } else tv.tv_sec = select_timeout; tv.tv_usec = 0; cnt = select(max_fd + 1, &r_fds, &w_fds, &e_fds, &tv); if (cnt <= 0) { if (cnt < 0 && errno == EBADF) { msgs2stderr = 1; exit_cleanup(RERR_SOCKETIO); } if (extra_flist_sending_enabled) { extra_flist_sending_enabled = False; send_extra_file_list(sock_f_out, -1); extra_flist_sending_enabled = !flist_eof; } else check_timeout((flags & PIO_NEED_INPUT) != 0, 0); FD_ZERO(&r_fds); /* Just in case... */ FD_ZERO(&w_fds); } if (iobuf.in_fd >= 0 && FD_ISSET(iobuf.in_fd, &r_fds)) { size_t len, pos = iobuf.in.pos + iobuf.in.len; ssize_t n; if (pos >= iobuf.in.size) { pos -= iobuf.in.size; len = iobuf.in.size - iobuf.in.len; } else len = iobuf.in.size - pos; if ((n = read(iobuf.in_fd, iobuf.in.buf + pos, len)) <= 0) { if (n == 0) { /* Signal that input has become invalid. */ if (!read_batch || batch_fd < 0 || am_generator) iobuf.in_fd = -2; batch_fd = -1; continue; } if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) n = 0; else { /* Don't write errors on a dead socket. */ if (iobuf.in_fd == sock_f_in) { if (am_sender) msgs2stderr = 1; rsyserr(FERROR_SOCKET, errno, "read error"); } else rsyserr(FERROR, errno, "read error"); exit_cleanup(RERR_SOCKETIO); } } if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] recv=%" SIZE_T_FMT_MOD "d\n", who_am_i(), (SIZE_T_FMT_CAST)n); } if (io_timeout) { last_io_in = time(NULL); if (io_timeout && flags & PIO_NEED_INPUT) maybe_send_keepalive(last_io_in, 0); } stats.total_read += n; iobuf.in.len += n; } if (stop_at_utime && time(NULL) >= stop_at_utime) { rprintf(FERROR, "stopping at requested limit\n"); exit_cleanup(RERR_TIMEOUT); } if (out && FD_ISSET(iobuf.out_fd, &w_fds)) { size_t len = iobuf.raw_flushing_ends_before ? iobuf.raw_flushing_ends_before - out->pos : out->len; ssize_t n; if (bwlimit_writemax && len > bwlimit_writemax) len = bwlimit_writemax; if (out->pos + len > out->size) len = out->size - out->pos; if ((n = write(iobuf.out_fd, out->buf + out->pos, len)) <= 0) { if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) n = 0; else { /* Don't write errors on a dead socket. */ msgs2stderr = 1; iobuf.out_fd = -2; iobuf.out.len = iobuf.msg.len = iobuf.raw_flushing_ends_before = 0; rsyserr(FERROR_SOCKET, errno, "write error"); drain_multiplex_messages(); exit_cleanup(RERR_SOCKETIO); } } if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] %s sent=%" SIZE_T_FMT_MOD "d\n", who_am_i(), out == &iobuf.out ? "out" : "msg", (SIZE_T_FMT_CAST)n); } if (io_timeout) last_io_out = time(NULL); stats.total_written += n; if (bwlimit_writemax) sleep_for_bwlimit(n); if ((out->pos += n) == out->size) { if (iobuf.raw_flushing_ends_before) iobuf.raw_flushing_ends_before -= out->size; out->pos = 0; restore_iobuf_size(out); } else if (out->pos == iobuf.raw_flushing_ends_before) iobuf.raw_flushing_ends_before = 0; if ((out->len -= n) == empty_buf_len) { out->pos = 0; restore_iobuf_size(out); if (empty_buf_len) iobuf.raw_data_header_pos = 0; } } if (got_kill_signal > 0) handle_kill_signal(True); /* We need to help prevent deadlock by doing what reading * we can whenever we are here trying to write. */ if (IN_MULTIPLEXED_AND_READY && !(flags & PIO_NEED_INPUT)) { while (!iobuf.raw_input_ends_before && iobuf.in.len > 512) read_a_msg(); if (flist_receiving_enabled && iobuf.in.len > 512) wait_for_receiver(); /* generator only */ } if (ff_forward_fd >= 0 && FD_ISSET(ff_forward_fd, &r_fds)) { /* This can potentially flush all output and enable * multiplexed output, so keep this last in the loop * and be sure to not cache anything that would break * such a change. */ forward_filesfrom_data(); } } double_break: if (got_kill_signal > 0) handle_kill_signal(True); data = iobuf.in.buf + iobuf.in.pos; if (flags & PIO_CONSUME_INPUT) { iobuf.in.len -= needed; iobuf.in.pos += needed; if (iobuf.in.pos == iobuf.raw_input_ends_before) iobuf.raw_input_ends_before = 0; if (iobuf.in.pos >= iobuf.in.size) { iobuf.in.pos -= iobuf.in.size; if (iobuf.raw_input_ends_before) iobuf.raw_input_ends_before -= iobuf.in.size; } } return data; } static void raw_read_buf(char *buf, size_t len) { size_t pos = iobuf.in.pos; char *data = perform_io(len, PIO_INPUT_AND_CONSUME); if (iobuf.in.pos <= pos && len) { size_t siz = len - iobuf.in.pos; memcpy(buf, data, siz); memcpy(buf + siz, iobuf.in.buf, iobuf.in.pos); } else memcpy(buf, data, len); } static int32 raw_read_int(void) { char *data, buf[4]; if (iobuf.in.size - iobuf.in.pos >= 4) data = perform_io(4, PIO_INPUT_AND_CONSUME); else raw_read_buf(data = buf, 4); return IVAL(data, 0); } void noop_io_until_death(void) { char buf[1024]; if (!iobuf.in.buf || !iobuf.out.buf || iobuf.in_fd < 0 || iobuf.out_fd < 0 || kluge_around_eof) return; /* If we're talking to a daemon over a socket, don't short-circuit this logic */ if (msgs2stderr && daemon_connection >= 0) return; kluge_around_eof = 2; /* Setting an I/O timeout ensures that if something inexplicably weird * happens, we won't hang around forever. */ if (!io_timeout) set_io_timeout(60); while (1) read_buf(iobuf.in_fd, buf, sizeof buf); } /* Buffer a message for the multiplexed output stream. Is not used for (normal) MSG_DATA. */ int send_msg(enum msgcode code, const char *buf, size_t len, int convert) { char *hdr; size_t needed, pos; BOOL want_debug = DEBUG_GTE(IO, 1) && convert >= 0 && (msgs2stderr == 1 || code != MSG_INFO); if (!OUT_MULTIPLEXED) return 0; if (want_debug) { rprintf(FINFO, "[%s] send_msg(%d, %" SIZE_T_FMT_MOD "d)\n", who_am_i(), (int)code, (SIZE_T_FMT_CAST)len); } /* When checking for enough free space for this message, we need to * make sure that there is space for the 4-byte header, plus we'll * assume that we may waste up to 3 bytes (if the header doesn't fit * at the physical end of the buffer). */ #ifdef ICONV_OPTION if (convert > 0 && ic_send == (iconv_t)-1) convert = 0; if (convert > 0) { /* Ensuring double-size room leaves space for maximal conversion expansion. */ needed = len*2 + 4 + 3; } else #endif needed = len + 4 + 3; if (iobuf.msg.len + needed > iobuf.msg.size) { if (am_sender) perform_io(needed, PIO_NEED_MSGROOM); else { /* We sometimes allow the iobuf.msg size to increase to avoid a deadlock. */ size_t old_size = iobuf.msg.size; restore_iobuf_size(&iobuf.msg); realloc_xbuf(&iobuf.msg, iobuf.msg.size * 2); if (iobuf.msg.pos + iobuf.msg.len > old_size) memcpy(iobuf.msg.buf + old_size, iobuf.msg.buf, iobuf.msg.pos + iobuf.msg.len - old_size); } } pos = iobuf.msg.pos + iobuf.msg.len; /* Must be set after any flushing. */ if (pos >= iobuf.msg.size) pos -= iobuf.msg.size; else if (pos + 4 > iobuf.msg.size) { /* The 4-byte header won't fit at the end of the buffer, * so we'll temporarily reduce the message buffer's size * and put the header at the start of the buffer. */ reduce_iobuf_size(&iobuf.msg, pos); pos = 0; } hdr = iobuf.msg.buf + pos; iobuf.msg.len += 4; /* Allocate room for the coming header bytes. */ #ifdef ICONV_OPTION if (convert > 0) { xbuf inbuf; INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1); len = iobuf.msg.len; iconvbufs(ic_send, &inbuf, &iobuf.msg, ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_CIRCULAR_OUT | ICB_INIT); if (inbuf.len > 0) { rprintf(FERROR, "overflowed iobuf.msg buffer in send_msg"); exit_cleanup(RERR_UNSUPPORTED); } len = iobuf.msg.len - len; } else #endif { size_t siz; if ((pos += 4) == iobuf.msg.size) pos = 0; /* Handle a split copy if we wrap around the end of the circular buffer. */ if (pos >= iobuf.msg.pos && (siz = iobuf.msg.size - pos) < len) { memcpy(iobuf.msg.buf + pos, buf, siz); memcpy(iobuf.msg.buf, buf + siz, len - siz); } else memcpy(iobuf.msg.buf + pos, buf, len); iobuf.msg.len += len; } SIVAL(hdr, 0, ((MPLEX_BASE + (int)code)<<24) + len); if (want_debug && convert > 0) { rprintf(FINFO, "[%s] converted msg len=%" SIZE_T_FMT_MOD "d\n", who_am_i(), (SIZE_T_FMT_CAST)len); } return 1; } void send_msg_int(enum msgcode code, int num) { char numbuf[4]; if (DEBUG_GTE(IO, 1)) rprintf(FINFO, "[%s] send_msg_int(%d, %d)\n", who_am_i(), (int)code, num); SIVAL(numbuf, 0, num); send_msg(code, numbuf, 4, -1); } void send_msg_success(const char *fname, int num) { if (local_server) { STRUCT_STAT st; if (DEBUG_GTE(IO, 1)) rprintf(FINFO, "[%s] send_msg_success(%d)\n", who_am_i(), num); if (stat(fname, &st) < 0) memset(&st, 0, sizeof (STRUCT_STAT)); SIVAL(num_dev_ino_buf, 0, num); SIVAL64(num_dev_ino_buf, 4, st.st_dev); SIVAL64(num_dev_ino_buf, 4+8, st.st_ino); send_msg(MSG_SUCCESS, num_dev_ino_buf, sizeof num_dev_ino_buf, -1); } else send_msg_int(MSG_SUCCESS, num); } static void got_flist_entry_status(enum festatus status, int ndx) { struct file_list *flist = flist_for_ndx(ndx, "got_flist_entry_status"); if (remove_source_files) { active_filecnt--; active_bytecnt -= F_LENGTH(flist->files[ndx - flist->ndx_start]); } if (inc_recurse) flist->in_progress--; switch (status) { case FES_SUCCESS: if (remove_source_files) { if (local_server) send_msg(MSG_SUCCESS, num_dev_ino_buf, sizeof num_dev_ino_buf, -1); else send_msg_int(MSG_SUCCESS, ndx); } /* FALL THROUGH */ case FES_NO_SEND: #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links) { struct file_struct *file = flist->files[ndx - flist->ndx_start]; if (F_IS_HLINKED(file)) { if (status == FES_NO_SEND) flist_ndx_push(&hlink_list, -2); /* indicates a failure follows */ flist_ndx_push(&hlink_list, ndx); if (inc_recurse) flist->in_progress++; } } #endif break; case FES_REDO: if (read_batch) { if (inc_recurse) flist->in_progress++; break; } if (inc_recurse) flist->to_redo++; flist_ndx_push(&redo_list, ndx); break; } } /* Note the fds used for the main socket (which might really be a pipe * for a local transfer, but we can ignore that). */ void io_set_sock_fds(int f_in, int f_out) { sock_f_in = f_in; sock_f_out = f_out; } void set_io_timeout(int secs) { io_timeout = secs; allowed_lull = (io_timeout + 1) / 2; if (!io_timeout || allowed_lull > SELECT_TIMEOUT) select_timeout = SELECT_TIMEOUT; else select_timeout = allowed_lull; if (read_batch) allowed_lull = 0; } static void check_for_d_option_error(const char *msg) { static char rsync263_opts[] = "BCDHIKLPRSTWabceghlnopqrtuvxz"; char *colon; int saw_d = 0; if (*msg != 'r' || strncmp(msg, REMOTE_OPTION_ERROR, sizeof REMOTE_OPTION_ERROR - 1) != 0) return; msg += sizeof REMOTE_OPTION_ERROR - 1; if (*msg == '-' || (colon = strchr(msg, ':')) == NULL || strncmp(colon, REMOTE_OPTION_ERROR2, sizeof REMOTE_OPTION_ERROR2 - 1) != 0) return; for ( ; *msg != ':'; msg++) { if (*msg == 'd') saw_d = 1; else if (*msg == 'e') break; else if (strchr(rsync263_opts, *msg) == NULL) return; } if (saw_d) { rprintf(FWARNING, "*** Try using \"--old-d\" if remote rsync is <= 2.6.3 ***\n"); } } /* This is used by the generator to limit how many file transfers can * be active at once when --remove-source-files is specified. Without * this, sender-side deletions were mostly happening at the end. */ void increment_active_files(int ndx, int itemizing, enum logcode code) { while (1) { /* TODO: tune these limits? */ int limit = active_bytecnt >= 128*1024 ? 10 : 50; if (active_filecnt < limit) break; check_for_finished_files(itemizing, code, 0); if (active_filecnt < limit) break; wait_for_receiver(); } active_filecnt++; active_bytecnt += F_LENGTH(cur_flist->files[ndx - cur_flist->ndx_start]); } int get_redo_num(void) { return flist_ndx_pop(&redo_list); } int get_hlink_num(void) { return flist_ndx_pop(&hlink_list); } /* When we're the receiver and we have a local --files-from list of names * that needs to be sent over the socket to the sender, we have to do two * things at the same time: send the sender a list of what files we're * processing and read the incoming file+info list from the sender. We do * this by making recv_file_list() call forward_filesfrom_data(), which * will ensure that we forward data to the sender until we get some data * for recv_file_list() to use. */ void start_filesfrom_forwarding(int fd) { if (protocol_version < 31 && OUT_MULTIPLEXED) { /* Older protocols send the files-from data w/o packaging * it in multiplexed I/O packets, so temporarily switch * to buffered I/O to match this behavior. */ iobuf.msg.pos = iobuf.msg.len = 0; /* Be extra sure no messages go out. */ ff_reenable_multiplex = io_end_multiplex_out(MPLX_TO_BUFFERED); } ff_forward_fd = fd; alloc_xbuf(&ff_xb, FILESFROM_BUFLEN); } /* Read a line into the "buf" buffer. */ int read_line(int fd, char *buf, size_t bufsiz, int flags) { char ch, *s, *eob; #ifdef ICONV_OPTION if (flags & RL_CONVERT && iconv_buf.size < bufsiz) realloc_xbuf(&iconv_buf, ROUND_UP_1024(bufsiz) + 1024); #endif start: #ifdef ICONV_OPTION s = flags & RL_CONVERT ? iconv_buf.buf : buf; #else s = buf; #endif eob = s + bufsiz - 1; while (1) { /* We avoid read_byte() for files because files can return an EOF. */ if (fd == iobuf.in_fd) ch = read_byte(fd); else if (safe_read(fd, &ch, 1) == 0) break; if (flags & RL_EOL_NULLS ? ch == '\0' : (ch == '\r' || ch == '\n')) { /* Skip empty lines if dumping comments. */ if (flags & RL_DUMP_COMMENTS && s == buf) continue; break; } if (s < eob) *s++ = ch; } *s = '\0'; if (flags & RL_DUMP_COMMENTS && (*buf == '#' || *buf == ';')) goto start; #ifdef ICONV_OPTION if (flags & RL_CONVERT) { xbuf outbuf; INIT_XBUF(outbuf, buf, 0, bufsiz); iconv_buf.pos = 0; iconv_buf.len = s - iconv_buf.buf; iconvbufs(ic_recv, &iconv_buf, &outbuf, ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_INIT); outbuf.buf[outbuf.len] = '\0'; return outbuf.len; } #endif return s - buf; } void read_args(int f_in, char *mod_name, char *buf, size_t bufsiz, int rl_nulls, char ***argv_p, int *argc_p, char **request_p) { int maxargs = MAX_ARGS; int dot_pos = 0, argc = 0, request_len = 0; char **argv, *p; int rl_flags = (rl_nulls ? RL_EOL_NULLS : 0); #ifdef ICONV_OPTION rl_flags |= (protect_args && ic_recv != (iconv_t)-1 ? RL_CONVERT : 0); #endif argv = new_array(char *, maxargs); if (mod_name && !protect_args) argv[argc++] = "rsyncd"; if (request_p) *request_p = NULL; while (1) { if (read_line(f_in, buf, bufsiz, rl_flags) == 0) break; if (argc == maxargs-1) { maxargs += MAX_ARGS; argv = realloc_array(argv, char *, maxargs); } if (dot_pos) { if (request_p && request_len < 1024) { int len = strlen(buf); if (request_len) request_p[0][request_len++] = ' '; *request_p = realloc_array(*request_p, char, request_len + len + 1); memcpy(*request_p + request_len, buf, len + 1); request_len += len; } if (mod_name) glob_expand_module(mod_name, buf, &argv, &argc, &maxargs); else glob_expand(buf, &argv, &argc, &maxargs); } else { p = strdup(buf); argv[argc++] = p; if (*p == '.' && p[1] == '\0') dot_pos = argc; } } argv[argc] = NULL; glob_expand(NULL, NULL, NULL, NULL); *argc_p = argc; *argv_p = argv; } BOOL io_start_buffering_out(int f_out) { if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_start_buffering_out(%d)\n", who_am_i(), f_out); if (iobuf.out.buf) { if (iobuf.out_fd == -1) iobuf.out_fd = f_out; else assert(f_out == iobuf.out_fd); return False; } alloc_xbuf(&iobuf.out, ROUND_UP_1024(IO_BUFFER_SIZE * 2)); iobuf.out_fd = f_out; return True; } BOOL io_start_buffering_in(int f_in) { if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_start_buffering_in(%d)\n", who_am_i(), f_in); if (iobuf.in.buf) { if (iobuf.in_fd == -1) iobuf.in_fd = f_in; else assert(f_in == iobuf.in_fd); return False; } alloc_xbuf(&iobuf.in, ROUND_UP_1024(IO_BUFFER_SIZE)); iobuf.in_fd = f_in; return True; } void io_end_buffering_in(BOOL free_buffers) { if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] io_end_buffering_in(IOBUF_%s_BUFS)\n", who_am_i(), free_buffers ? "FREE" : "KEEP"); } if (free_buffers) free_xbuf(&iobuf.in); else iobuf.in.pos = iobuf.in.len = 0; iobuf.in_fd = -1; } void io_end_buffering_out(BOOL free_buffers) { if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] io_end_buffering_out(IOBUF_%s_BUFS)\n", who_am_i(), free_buffers ? "FREE" : "KEEP"); } io_flush(FULL_FLUSH); if (free_buffers) { free_xbuf(&iobuf.out); free_xbuf(&iobuf.msg); } iobuf.out_fd = -1; } void maybe_flush_socket(int important) { if (flist_eof && iobuf.out.buf && iobuf.out.len > iobuf.out_empty_len && (important || time(NULL) - last_io_out >= 5)) io_flush(NORMAL_FLUSH); } /* Older rsync versions used to send either a MSG_NOOP (protocol 30) or a * raw-data-based keep-alive (protocol 29), both of which implied forwarding of * the message through the sender. Since the new timeout method does not need * any forwarding, we just send an empty MSG_DATA message, which works with all * rsync versions. This avoids any message forwarding, and leaves the raw-data * stream alone (since we can never be quite sure if that stream is in the * right state for a keep-alive message). */ void maybe_send_keepalive(time_t now, int flags) { if (flags & MSK_ACTIVE_RECEIVER) last_io_in = now; /* Fudge things when we're working hard on the files. */ /* Early in the transfer (before the receiver forks) the receiving side doesn't * care if it hasn't sent data in a while as long as it is receiving data (in * fact, a pre-3.1.0 rsync would die if we tried to send it a keep alive during * this time). So, if we're an early-receiving proc, just return and let the * incoming data determine if we timeout. */ if (!am_sender && !am_receiver && !am_generator) return; if (now - last_io_out >= allowed_lull) { /* The receiver is special: it only sends keep-alive messages if it is * actively receiving data. Otherwise, it lets the generator timeout. */ if (am_receiver && now - last_io_in >= io_timeout) return; if (!iobuf.msg.len && iobuf.out.len == iobuf.out_empty_len) send_msg(MSG_DATA, "", 0, 0); if (!(flags & MSK_ALLOW_FLUSH)) { /* Let the caller worry about writing out the data. */ } else if (iobuf.msg.len) perform_io(iobuf.msg.size - iobuf.msg.len + 1, PIO_NEED_MSGROOM); else if (iobuf.out.len > iobuf.out_empty_len) io_flush(NORMAL_FLUSH); } } void start_flist_forward(int ndx) { write_int(iobuf.out_fd, ndx); forward_flist_data = 1; } void stop_flist_forward(void) { forward_flist_data = 0; } /* Read a message from a multiplexed source. */ static void read_a_msg(void) { char data[BIGPATHBUFLEN]; int tag, val; size_t msg_bytes; /* This ensures that perform_io() does not try to do any message reading * until we've read all of the data for this message. We should also * try to avoid calling things that will cause data to be written via * perform_io() prior to this being reset to 1. */ iobuf.in_multiplexed = -1; tag = raw_read_int(); msg_bytes = tag & 0xFFFFFF; tag = (tag >> 24) - MPLEX_BASE; if (msgs2stderr == 1 && DEBUG_GTE(IO, 1)) { rprintf(FINFO, "[%s] got msg=%d, len=%" SIZE_T_FMT_MOD "d\n", who_am_i(), (int)tag, (SIZE_T_FMT_CAST)msg_bytes); } switch (tag) { case MSG_DATA: assert(iobuf.raw_input_ends_before == 0); /* Though this does not yet read the data, we do mark where in * the buffer the msg data will end once it is read. It is * possible that this points off the end of the buffer, in * which case the gradual reading of the input stream will * cause this value to wrap around and eventually become real. */ if (msg_bytes) iobuf.raw_input_ends_before = iobuf.in.pos + msg_bytes; iobuf.in_multiplexed = 1; break; case MSG_STATS: if (msg_bytes != sizeof stats.total_read || !am_generator) goto invalid_msg; raw_read_buf((char*)&stats.total_read, sizeof stats.total_read); iobuf.in_multiplexed = 1; break; case MSG_REDO: if (msg_bytes != 4 || !am_generator) goto invalid_msg; val = raw_read_int(); iobuf.in_multiplexed = 1; got_flist_entry_status(FES_REDO, val); break; case MSG_IO_ERROR: if (msg_bytes != 4) goto invalid_msg; val = raw_read_int(); iobuf.in_multiplexed = 1; io_error |= val; if (am_receiver) send_msg_int(MSG_IO_ERROR, val); break; case MSG_IO_TIMEOUT: if (msg_bytes != 4 || am_server || am_generator) goto invalid_msg; val = raw_read_int(); iobuf.in_multiplexed = 1; if (!io_timeout || io_timeout > val) { if (INFO_GTE(MISC, 2)) rprintf(FINFO, "Setting --timeout=%d to match server\n", val); set_io_timeout(val); } break; case MSG_NOOP: /* Support protocol-30 keep-alive method. */ if (msg_bytes != 0) goto invalid_msg; iobuf.in_multiplexed = 1; if (am_sender) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); break; case MSG_DELETED: if (msg_bytes >= sizeof data) goto overflow; if (am_generator) { raw_read_buf(data, msg_bytes); iobuf.in_multiplexed = 1; send_msg(MSG_DELETED, data, msg_bytes, 1); break; } #ifdef ICONV_OPTION if (ic_recv != (iconv_t)-1) { xbuf outbuf, inbuf; char ibuf[512]; int add_null = 0; int flags = ICB_INCLUDE_BAD | ICB_INIT; INIT_CONST_XBUF(outbuf, data); INIT_XBUF(inbuf, ibuf, 0, (size_t)-1); while (msg_bytes) { size_t len = msg_bytes > sizeof ibuf - inbuf.len ? sizeof ibuf - inbuf.len : msg_bytes; raw_read_buf(ibuf + inbuf.len, len); inbuf.pos = 0; inbuf.len += len; if (!(msg_bytes -= len) && !ibuf[inbuf.len-1]) inbuf.len--, add_null = 1; if (iconvbufs(ic_send, &inbuf, &outbuf, flags) < 0) { if (errno == E2BIG) goto overflow; /* Buffer ended with an incomplete char, so move the * bytes to the start of the buffer and continue. */ memmove(ibuf, ibuf + inbuf.pos, inbuf.len); } flags &= ~ICB_INIT; } if (add_null) { if (outbuf.len == outbuf.size) goto overflow; outbuf.buf[outbuf.len++] = '\0'; } msg_bytes = outbuf.len; } else #endif raw_read_buf(data, msg_bytes); iobuf.in_multiplexed = 1; /* A directory name was sent with the trailing null */ if (msg_bytes > 0 && !data[msg_bytes-1]) log_delete(data, S_IFDIR); else { data[msg_bytes] = '\0'; log_delete(data, S_IFREG); } break; case MSG_SUCCESS: if (msg_bytes != (local_server ? 4+8+8 : 4)) { invalid_msg: rprintf(FERROR, "invalid multi-message %d:%lu [%s%s]\n", tag, (unsigned long)msg_bytes, who_am_i(), inc_recurse ? "/inc" : ""); exit_cleanup(RERR_STREAMIO); } raw_read_buf(num_dev_ino_buf, msg_bytes); val = IVAL(num_dev_ino_buf, 0); iobuf.in_multiplexed = 1; if (am_generator) got_flist_entry_status(FES_SUCCESS, val); else successful_send(val); break; case MSG_NO_SEND: if (msg_bytes != 4) goto invalid_msg; val = raw_read_int(); iobuf.in_multiplexed = 1; if (am_generator) got_flist_entry_status(FES_NO_SEND, val); else send_msg_int(MSG_NO_SEND, val); break; case MSG_ERROR_SOCKET: case MSG_ERROR_UTF8: case MSG_CLIENT: case MSG_LOG: if (!am_generator) goto invalid_msg; if (tag == MSG_ERROR_SOCKET) msgs2stderr = 1; /* FALL THROUGH */ case MSG_INFO: case MSG_ERROR: case MSG_ERROR_XFER: case MSG_WARNING: if (msg_bytes >= sizeof data) { overflow: rprintf(FERROR, "multiplexing overflow %d:%lu [%s%s]\n", tag, (unsigned long)msg_bytes, who_am_i(), inc_recurse ? "/inc" : ""); exit_cleanup(RERR_STREAMIO); } raw_read_buf(data, msg_bytes); /* We don't set in_multiplexed value back to 1 before writing this message * because the write might loop back and read yet another message, over and * over again, while waiting for room to put the message in the msg buffer. */ rwrite((enum logcode)tag, data, msg_bytes, !am_generator); iobuf.in_multiplexed = 1; if (first_message) { if (list_only && !am_sender && tag == 1 && msg_bytes < sizeof data) { data[msg_bytes] = '\0'; check_for_d_option_error(data); } first_message = 0; } break; case MSG_ERROR_EXIT: if (msg_bytes == 4) val = raw_read_int(); else if (msg_bytes == 0) val = 0; else goto invalid_msg; iobuf.in_multiplexed = 1; if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] got MSG_ERROR_EXIT with %" SIZE_T_FMT_MOD "d bytes\n", who_am_i(), (SIZE_T_FMT_CAST)msg_bytes); } if (msg_bytes == 0) { if (!am_sender && !am_generator) { if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT (len 0)\n", who_am_i()); } send_msg(MSG_ERROR_EXIT, "", 0, 0); io_flush(FULL_FLUSH); } } else if (protocol_version >= 31) { if (am_generator || am_receiver) { if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n", who_am_i(), val); } send_msg_int(MSG_ERROR_EXIT, val); } else { if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT (len 0)\n", who_am_i()); } send_msg(MSG_ERROR_EXIT, "", 0, 0); } } /* Send a negative linenum so that we don't end up * with a duplicate exit message. */ _exit_cleanup(val, __FILE__, 0 - __LINE__); default: rprintf(FERROR, "unexpected tag %d [%s%s]\n", tag, who_am_i(), inc_recurse ? "/inc" : ""); exit_cleanup(RERR_STREAMIO); } assert(iobuf.in_multiplexed > 0); } static void drain_multiplex_messages(void) { while (IN_MULTIPLEXED_AND_READY && iobuf.in.len) { if (iobuf.raw_input_ends_before) { size_t raw_len = iobuf.raw_input_ends_before - iobuf.in.pos; iobuf.raw_input_ends_before = 0; if (raw_len >= iobuf.in.len) { iobuf.in.len = 0; break; } iobuf.in.len -= raw_len; if ((iobuf.in.pos += raw_len) >= iobuf.in.size) iobuf.in.pos -= iobuf.in.size; } read_a_msg(); } } void wait_for_receiver(void) { if (!iobuf.raw_input_ends_before) read_a_msg(); if (iobuf.raw_input_ends_before) { int ndx = read_int(iobuf.in_fd); if (ndx < 0) { switch (ndx) { case NDX_FLIST_EOF: flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); break; case NDX_DONE: msgdone_cnt++; break; default: exit_cleanup(RERR_STREAMIO); } } else { struct file_list *flist; flist_receiving_enabled = False; if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } flist = recv_file_list(iobuf.in_fd, ndx); flist->parent_ndx = ndx; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links) match_hard_links(flist); #endif flist_receiving_enabled = True; } } } unsigned short read_shortint(int f) { char b[2]; read_buf(f, b, 2); return (UVAL(b, 1) << 8) + UVAL(b, 0); } int32 read_int(int f) { char b[4]; int32 num; read_buf(f, b, 4); num = IVAL(b, 0); #if SIZEOF_INT32 > 4 if (num & (int32)0x80000000) num |= ~(int32)0xffffffff; #endif return num; } uint32 read_uint(int f) { char b[4]; read_buf(f, b, 4); return IVAL(b, 0); } int32 read_varint(int f) { union { char b[5]; int32 x; } u; uchar ch; int extra; u.x = 0; ch = read_byte(f); extra = int_byte_extra[ch / 4]; if (extra) { uchar bit = ((uchar)1<<(8-extra)); if (extra >= (int)sizeof u.b) { rprintf(FERROR, "Overflow in read_varint()\n"); exit_cleanup(RERR_STREAMIO); } read_buf(f, u.b, extra); u.b[extra] = ch & (bit-1); } else u.b[0] = ch; #if CAREFUL_ALIGNMENT u.x = IVAL(u.b,0); #endif #if SIZEOF_INT32 > 4 if (u.x & (int32)0x80000000) u.x |= ~(int32)0xffffffff; #endif return u.x; } int64 read_varlong(int f, uchar min_bytes) { union { char b[9]; int64 x; } u; char b2[8]; int extra; #if SIZEOF_INT64 < 8 memset(u.b, 0, 8); #else u.x = 0; #endif read_buf(f, b2, min_bytes); memcpy(u.b, b2+1, min_bytes-1); extra = int_byte_extra[CVAL(b2, 0) / 4]; if (extra) { uchar bit = ((uchar)1<<(8-extra)); if (min_bytes + extra > (int)sizeof u.b) { rprintf(FERROR, "Overflow in read_varlong()\n"); exit_cleanup(RERR_STREAMIO); } read_buf(f, u.b + min_bytes - 1, extra); u.b[min_bytes + extra - 1] = CVAL(b2, 0) & (bit-1); #if SIZEOF_INT64 < 8 if (min_bytes + extra > 5 || u.b[4] || CVAL(u.b,3) & 0x80) { rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); } #endif } else u.b[min_bytes + extra - 1] = CVAL(b2, 0); #if SIZEOF_INT64 < 8 u.x = IVAL(u.b,0); #elif CAREFUL_ALIGNMENT u.x = IVAL64(u.b,0); #endif return u.x; } int64 read_longint(int f) { #if SIZEOF_INT64 >= 8 char b[9]; #endif int32 num = read_int(f); if (num != (int32)0xffffffff) return num; #if SIZEOF_INT64 < 8 rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); #else read_buf(f, b, 8); return IVAL(b,0) | (((int64)IVAL(b,4))<<32); #endif } /* Debugging note: this will be named read_buf_() when using an external zlib. */ void read_buf(int f, char *buf, size_t len) { if (f != iobuf.in_fd) { if (safe_read(f, buf, len) != len) whine_about_eof(False); /* Doesn't return. */ goto batch_copy; } if (!IN_MULTIPLEXED) { raw_read_buf(buf, len); total_data_read += len; if (forward_flist_data) write_buf(iobuf.out_fd, buf, len); batch_copy: if (f == write_batch_monitor_in) safe_write(batch_fd, buf, len); return; } while (1) { size_t siz; while (!iobuf.raw_input_ends_before) read_a_msg(); siz = MIN(len, iobuf.raw_input_ends_before - iobuf.in.pos); if (siz >= iobuf.in.size) siz = iobuf.in.size; raw_read_buf(buf, siz); total_data_read += siz; if (forward_flist_data) write_buf(iobuf.out_fd, buf, siz); if (f == write_batch_monitor_in) safe_write(batch_fd, buf, siz); if ((len -= siz) == 0) break; buf += siz; } } void read_sbuf(int f, char *buf, size_t len) { read_buf(f, buf, len); buf[len] = '\0'; } uchar read_byte(int f) { uchar c; read_buf(f, (char*)&c, 1); return c; } int read_vstring(int f, char *buf, int bufsize) { int len = read_byte(f); if (len & 0x80) len = (len & ~0x80) * 0x100 + read_byte(f); if (len >= bufsize) { rprintf(FERROR, "over-long vstring received (%d > %d)\n", len, bufsize - 1); return -1; } if (len) read_buf(f, buf, len); buf[len] = '\0'; return len; } /* Populate a sum_struct with values from the socket. This is * called by both the sender and the receiver. */ void read_sum_head(int f, struct sum_struct *sum) { int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE; sum->count = read_int(f); if (sum->count < 0) { rprintf(FERROR, "Invalid checksum count %ld [%s]\n", (long)sum->count, who_am_i()); exit_cleanup(RERR_PROTOCOL); } sum->blength = read_int(f); if (sum->blength < 0 || sum->blength > max_blength) { rprintf(FERROR, "Invalid block length %ld [%s]\n", (long)sum->blength, who_am_i()); exit_cleanup(RERR_PROTOCOL); } sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f); if (sum->s2length < 0 || sum->s2length > MAX_DIGEST_LEN) { rprintf(FERROR, "Invalid checksum length %d [%s]\n", sum->s2length, who_am_i()); exit_cleanup(RERR_PROTOCOL); } sum->remainder = read_int(f); if (sum->remainder < 0 || sum->remainder > sum->blength) { rprintf(FERROR, "Invalid remainder length %ld [%s]\n", (long)sum->remainder, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } /* Send the values from a sum_struct over the socket. Set sum to * NULL if there are no checksums to send. This is called by both * the generator and the sender. */ void write_sum_head(int f, struct sum_struct *sum) { static struct sum_struct null_sum; if (sum == NULL) sum = &null_sum; write_int(f, sum->count); write_int(f, sum->blength); if (protocol_version >= 27) write_int(f, sum->s2length); write_int(f, sum->remainder); } /* Sleep after writing to limit I/O bandwidth usage. * * @todo Rather than sleeping after each write, it might be better to * use some kind of averaging. The current algorithm seems to always * use a bit less bandwidth than specified, because it doesn't make up * for slow periods. But arguably this is a feature. In addition, we * ought to take the time used to write the data into account. * * During some phases of big transfers (file FOO is uptodate) this is * called with a small bytes_written every time. As the kernel has to * round small waits up to guarantee that we actually wait at least the * requested number of microseconds, this can become grossly inaccurate. * We therefore keep track of the bytes we've written over time and only * sleep when the accumulated delay is at least 1 tenth of a second. */ static void sleep_for_bwlimit(int bytes_written) { static struct timeval prior_tv; static long total_written = 0; struct timeval tv, start_tv; long elapsed_usec, sleep_usec; #define ONE_SEC 1000000L /* # of microseconds in a second */ total_written += bytes_written; gettimeofday(&start_tv, NULL); if (prior_tv.tv_sec) { elapsed_usec = (start_tv.tv_sec - prior_tv.tv_sec) * ONE_SEC + (start_tv.tv_usec - prior_tv.tv_usec); total_written -= (int64)elapsed_usec * bwlimit / (ONE_SEC/1024); if (total_written < 0) total_written = 0; } sleep_usec = total_written * (ONE_SEC/1024) / bwlimit; if (sleep_usec < ONE_SEC / 10) { prior_tv = start_tv; return; } tv.tv_sec = sleep_usec / ONE_SEC; tv.tv_usec = sleep_usec % ONE_SEC; select(0, NULL, NULL, NULL, &tv); gettimeofday(&prior_tv, NULL); elapsed_usec = (prior_tv.tv_sec - start_tv.tv_sec) * ONE_SEC + (prior_tv.tv_usec - start_tv.tv_usec); total_written = (sleep_usec - elapsed_usec) * bwlimit / (ONE_SEC/1024); } void io_flush(int flush_type) { if (iobuf.out.len > iobuf.out_empty_len) { if (flush_type == FULL_FLUSH) /* flush everything in the output buffers */ perform_io(iobuf.out.size - iobuf.out_empty_len, PIO_NEED_OUTROOM); else if (flush_type == NORMAL_FLUSH) /* flush at least 1 byte */ perform_io(iobuf.out.size - iobuf.out.len + 1, PIO_NEED_OUTROOM); /* MSG_FLUSH: flush iobuf.msg only */ } if (iobuf.msg.len) perform_io(iobuf.msg.size, PIO_NEED_MSGROOM); } void write_shortint(int f, unsigned short x) { char b[2]; b[0] = (char)x; b[1] = (char)(x >> 8); write_buf(f, b, 2); } void write_int(int f, int32 x) { char b[4]; SIVAL(b, 0, x); write_buf(f, b, 4); } void write_varint(int f, int32 x) { char b[5]; uchar bit; int cnt; SIVAL(b, 1, x); for (cnt = 4; cnt > 1 && b[cnt] == 0; cnt--) {} bit = ((uchar)1<<(7-cnt+1)); if (CVAL(b, cnt) >= bit) { cnt++; *b = ~(bit-1); } else if (cnt > 1) *b = b[cnt] | ~(bit*2-1); else *b = b[1]; write_buf(f, b, cnt); } void write_varlong(int f, int64 x, uchar min_bytes) { char b[9]; uchar bit; int cnt = 8; #if SIZEOF_INT64 >= 8 SIVAL64(b, 1, x); #else SIVAL(b, 1, x); if (x <= 0x7FFFFFFF && x >= 0) memset(b + 5, 0, 4); else { rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); } #endif while (cnt > min_bytes && b[cnt] == 0) cnt--; bit = ((uchar)1<<(7-cnt+min_bytes)); if (CVAL(b, cnt) >= bit) { cnt++; *b = ~(bit-1); } else if (cnt > min_bytes) *b = b[cnt] | ~(bit*2-1); else *b = b[cnt]; write_buf(f, b, cnt); } /* * Note: int64 may actually be a 32-bit type if ./configure couldn't find any * 64-bit types on this platform. */ void write_longint(int f, int64 x) { char b[12], * const s = b+4; SIVAL(s, 0, x); if (x <= 0x7FFFFFFF && x >= 0) { write_buf(f, s, 4); return; } #if SIZEOF_INT64 < 8 rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); #else memset(b, 0xFF, 4); SIVAL(s, 4, x >> 32); write_buf(f, b, 12); #endif } void write_bigbuf(int f, const char *buf, size_t len) { size_t half_max = (iobuf.out.size - iobuf.out_empty_len) / 2; while (len > half_max + 1024) { write_buf(f, buf, half_max); buf += half_max; len -= half_max; } write_buf(f, buf, len); } void write_buf(int f, const char *buf, size_t len) { size_t pos, siz; if (f != iobuf.out_fd) { safe_write(f, buf, len); goto batch_copy; } if (iobuf.out.len + len > iobuf.out.size) perform_io(len, PIO_NEED_OUTROOM); pos = iobuf.out.pos + iobuf.out.len; /* Must be set after any flushing. */ if (pos >= iobuf.out.size) pos -= iobuf.out.size; /* Handle a split copy if we wrap around the end of the circular buffer. */ if (pos >= iobuf.out.pos && (siz = iobuf.out.size - pos) < len) { memcpy(iobuf.out.buf + pos, buf, siz); memcpy(iobuf.out.buf, buf + siz, len - siz); } else memcpy(iobuf.out.buf + pos, buf, len); iobuf.out.len += len; total_data_written += len; batch_copy: if (f == write_batch_monitor_out) safe_write(batch_fd, buf, len); } /* Write a string to the connection */ void write_sbuf(int f, const char *buf) { write_buf(f, buf, strlen(buf)); } void write_byte(int f, uchar c) { write_buf(f, (char *)&c, 1); } void write_vstring(int f, const char *str, int len) { uchar lenbuf[3], *lb = lenbuf; if (len > 0x7F) { if (len > 0x7FFF) { rprintf(FERROR, "attempting to send over-long vstring (%d > %d)\n", len, 0x7FFF); exit_cleanup(RERR_PROTOCOL); } *lb++ = len / 0x100 + 0x80; } *lb = len; write_buf(f, (char*)lenbuf, lb - lenbuf + 1); if (len) write_buf(f, str, len); } /* Send a file-list index using a byte-reduction method. */ void write_ndx(int f, int32 ndx) { static int32 prev_positive = -1, prev_negative = 1; int32 diff, cnt = 0; char b[6]; if (protocol_version < 30 || read_batch) { write_int(f, ndx); return; } /* Send NDX_DONE as a single-byte 0 with no side effects. Send * negative nums as a positive after sending a leading 0xFF. */ if (ndx >= 0) { diff = ndx - prev_positive; prev_positive = ndx; } else if (ndx == NDX_DONE) { *b = 0; write_buf(f, b, 1); return; } else { b[cnt++] = (char)0xFF; ndx = -ndx; diff = ndx - prev_negative; prev_negative = ndx; } /* A diff of 1 - 253 is sent as a one-byte diff; a diff of 254 - 32767 * or 0 is sent as a 0xFE + a two-byte diff; otherwise we send 0xFE * & all 4 bytes of the (non-negative) num with the high-bit set. */ if (diff < 0xFE && diff > 0) b[cnt++] = (char)diff; else if (diff < 0 || diff > 0x7FFF) { b[cnt++] = (char)0xFE; b[cnt++] = (char)((ndx >> 24) | 0x80); b[cnt++] = (char)ndx; b[cnt++] = (char)(ndx >> 8); b[cnt++] = (char)(ndx >> 16); } else { b[cnt++] = (char)0xFE; b[cnt++] = (char)(diff >> 8); b[cnt++] = (char)diff; } write_buf(f, b, cnt); } /* Receive a file-list index using a byte-reduction method. */ int32 read_ndx(int f) { static int32 prev_positive = -1, prev_negative = 1; int32 *prev_ptr, num; char b[4]; if (protocol_version < 30) return read_int(f); read_buf(f, b, 1); if (CVAL(b, 0) == 0xFF) { read_buf(f, b, 1); prev_ptr = &prev_negative; } else if (CVAL(b, 0) == 0) return NDX_DONE; else prev_ptr = &prev_positive; if (CVAL(b, 0) == 0xFE) { read_buf(f, b, 2); if (CVAL(b, 0) & 0x80) { b[3] = CVAL(b, 0) & ~0x80; b[0] = b[1]; read_buf(f, b+1, 2); num = IVAL(b, 0); } else num = (UVAL(b,0)<<8) + UVAL(b,1) + *prev_ptr; } else num = UVAL(b, 0) + *prev_ptr; *prev_ptr = num; if (prev_ptr == &prev_negative) num = -num; return num; } /* Read a line of up to bufsiz-1 characters into buf. Strips * the (required) trailing newline and all carriage returns. * Returns 1 for success; 0 for I/O error or truncation. */ int read_line_old(int fd, char *buf, size_t bufsiz, int eof_ok) { assert(fd != iobuf.in_fd); bufsiz--; /* leave room for the null */ while (bufsiz > 0) { if (safe_read(fd, buf, 1) == 0) { if (eof_ok) break; return 0; } if (*buf == '\0') return 0; if (*buf == '\n') break; if (*buf != '\r') { buf++; bufsiz--; } } *buf = '\0'; return bufsiz > 0; } void io_printf(int fd, const char *format, ...) { va_list ap; char buf[BIGPATHBUFLEN]; int len; va_start(ap, format); len = vsnprintf(buf, sizeof buf, format, ap); va_end(ap); if (len < 0) exit_cleanup(RERR_PROTOCOL); if (len >= (int)sizeof buf) { rprintf(FERROR, "io_printf() was too long for the buffer.\n"); exit_cleanup(RERR_PROTOCOL); } write_sbuf(fd, buf); } /* Setup for multiplexing a MSG_* stream with the data stream. */ void io_start_multiplex_out(int fd) { io_flush(FULL_FLUSH); if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_start_multiplex_out(%d)\n", who_am_i(), fd); if (!iobuf.msg.buf) alloc_xbuf(&iobuf.msg, ROUND_UP_1024(IO_BUFFER_SIZE)); iobuf.out_empty_len = 4; /* See also OUT_MULTIPLEXED */ io_start_buffering_out(fd); got_kill_signal = 0; iobuf.raw_data_header_pos = iobuf.out.pos + iobuf.out.len; iobuf.out.len += 4; } /* Setup for multiplexing a MSG_* stream with the data stream. */ void io_start_multiplex_in(int fd) { if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_start_multiplex_in(%d)\n", who_am_i(), fd); iobuf.in_multiplexed = 1; /* See also IN_MULTIPLEXED */ io_start_buffering_in(fd); } int io_end_multiplex_in(int mode) { int ret = iobuf.in_multiplexed ? iobuf.in_fd : -1; if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_end_multiplex_in(mode=%d)\n", who_am_i(), mode); iobuf.in_multiplexed = 0; if (mode == MPLX_SWITCHING) iobuf.raw_input_ends_before = 0; else assert(iobuf.raw_input_ends_before == 0); if (mode != MPLX_TO_BUFFERED) io_end_buffering_in(mode); return ret; } int io_end_multiplex_out(int mode) { int ret = iobuf.out_empty_len ? iobuf.out_fd : -1; if (msgs2stderr == 1 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] io_end_multiplex_out(mode=%d)\n", who_am_i(), mode); if (mode != MPLX_TO_BUFFERED) io_end_buffering_out(mode); else io_flush(FULL_FLUSH); iobuf.out.len = 0; iobuf.out_empty_len = 0; if (got_kill_signal > 0) /* Just in case... */ handle_kill_signal(False); got_kill_signal = -1; return ret; } void start_write_batch(int fd) { /* Some communication has already taken place, but we don't * enable batch writing until here so that we can write a * canonical record of the communication even though the * actual communication so far depends on whether a daemon * is involved. */ write_int(batch_fd, protocol_version); if (protocol_version >= 30) write_varint(batch_fd, compat_flags); write_int(batch_fd, checksum_seed); if (am_sender) write_batch_monitor_out = fd; else write_batch_monitor_in = fd; } void stop_write_batch(void) { write_batch_monitor_out = -1; write_batch_monitor_in = -1; } rsync-3.2.7/util1.c0000664000000000000000000012337114310656342012576 0ustar rootroot/* * Utility routines used in rsync. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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" #include "itypes.h" #include "inums.h" extern int dry_run; extern int module_id; extern int do_fsync; extern int protect_args; extern int modify_window; extern int relative_paths; extern int preserve_xattrs; extern int omit_link_times; extern int preallocate_files; extern char *module_dir; extern unsigned int module_dirlen; extern char *partial_dir; extern filter_rule_list daemon_filter_list; int sanitize_paths = 0; char curr_dir[MAXPATHLEN]; unsigned int curr_dir_len; int curr_dir_depth; /* This is only set for a sanitizing daemon. */ /* Set a fd into nonblocking mode. */ void set_nonblocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL)) == -1) return; if (!(val & NONBLOCK_FLAG)) { val |= NONBLOCK_FLAG; fcntl(fd, F_SETFL, val); } } /* Set a fd into blocking mode. */ void set_blocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL)) == -1) return; if (val & NONBLOCK_FLAG) { val &= ~NONBLOCK_FLAG; fcntl(fd, F_SETFL, val); } } /** * Create a file descriptor pair - like pipe() but use socketpair if * possible (because of blocking issues on pipes). * * Always set non-blocking. */ int fd_pair(int fd[2]) { int ret; #ifdef HAVE_SOCKETPAIR ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); #else ret = pipe(fd); #endif if (ret == 0) { set_nonblocking(fd[0]); set_nonblocking(fd[1]); } return ret; } void print_child_argv(const char *prefix, char **cmd) { int cnt = 0; rprintf(FCLIENT, "%s ", prefix); for (; *cmd; cmd++) { /* Look for characters that ought to be quoted. This * is not a great quoting algorithm, but it's * sufficient for a log message. */ if (strspn(*cmd, "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ",.-_=+@/") != strlen(*cmd)) { rprintf(FCLIENT, "\"%s\" ", *cmd); } else { rprintf(FCLIENT, "%s ", *cmd); } cnt++; } rprintf(FCLIENT, " (%d args)\n", cnt); } /* This returns 0 for success, 1 for a symlink if symlink time-setting * is not possible, or -1 for any other error. */ int set_times(const char *fname, STRUCT_STAT *stp) { static int switch_step = 0; if (DEBUG_GTE(TIME, 1)) { rprintf(FINFO, "set modtime, atime of %s to (%ld) %s, (%ld) %s\n", fname, (long)stp->st_mtime, timestring(stp->st_mtime), (long)stp->st_atime, timestring(stp->st_atime)); } switch (switch_step) { #ifdef HAVE_SETATTRLIST #include "case_N.h" if (do_setattrlist_times(fname, stp) == 0) break; if (errno != ENOSYS) return -1; switch_step++; #endif #ifdef HAVE_UTIMENSAT #include "case_N.h" if (do_utimensat(fname, stp) == 0) break; if (errno != ENOSYS) return -1; switch_step++; #endif #ifdef HAVE_LUTIMES #include "case_N.h" if (do_lutimes(fname, stp) == 0) break; if (errno != ENOSYS) return -1; switch_step++; #endif #include "case_N.h" switch_step++; if (!omit_link_times) { omit_link_times = 1; if (S_ISLNK(stp->st_mode)) return 1; } #include "case_N.h" #ifdef HAVE_UTIMES if (do_utimes(fname, stp) == 0) break; #else if (do_utime(fname, stp) == 0) break; #endif return -1; } return 0; } /* Create any necessary directories in fname. Any missing directories are * created with default permissions. Returns < 0 on error, or the number * of directories created. */ int make_path(char *fname, int flags) { char *end, *p; int ret = 0; if (flags & MKP_SKIP_SLASH) { while (*fname == '/') fname++; } while (*fname == '.' && fname[1] == '/') fname += 2; if (flags & MKP_DROP_NAME) { end = strrchr(fname, '/'); if (!end || end == fname) return 0; *end = '\0'; } else end = fname + strlen(fname); /* Try to find an existing dir, starting from the deepest dir. */ for (p = end; ; ) { if (dry_run) { STRUCT_STAT st; if (do_stat(fname, &st) == 0) { if (S_ISDIR(st.st_mode)) errno = EEXIST; else errno = ENOTDIR; } } else if (do_mkdir(fname, ACCESSPERMS) == 0) { ret++; break; } if (errno != ENOENT) { STRUCT_STAT st; if (errno != EEXIST || (do_stat(fname, &st) == 0 && !S_ISDIR(st.st_mode))) ret = -ret - 1; break; } while (1) { if (p == fname) { /* We got a relative path that doesn't exist, so assume that '.' * is there and just break out and create the whole thing. */ p = NULL; goto double_break; } if (*--p == '/') { if (p == fname) { /* We reached the "/" dir, which we assume is there. */ goto double_break; } *p = '\0'; break; } } } double_break: /* Make all the dirs that we didn't find on the way here. */ while (p != end) { if (p) *p = '/'; else p = fname; p += strlen(p); if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */ continue; if (do_mkdir(fname, ACCESSPERMS) < 0) ret = -ret - 1; else ret++; } if (flags & MKP_DROP_NAME) *end = '/'; return ret; } /** * Write @p len bytes at @p ptr to descriptor @p desc, retrying if * interrupted. * * @retval len upon success * * @retval <0 write's (negative) error code * * Derived from GNU C's cccp.c. */ int full_write(int desc, const char *ptr, size_t len) { int total_written; total_written = 0; while (len > 0) { int written = write(desc, ptr, len); if (written < 0) { if (errno == EINTR) continue; return written; } total_written += written; ptr += written; len -= written; } return total_written; } /** * Read @p len bytes at @p ptr from descriptor @p desc, retrying if * interrupted. * * @retval >0 the actual number of bytes read * * @retval 0 for EOF * * @retval <0 for an error. * * Derived from GNU C's cccp.c. */ static int safe_read(int desc, char *ptr, size_t len) { int n_chars; if (len == 0) return len; do { n_chars = read(desc, ptr, len); } while (n_chars < 0 && errno == EINTR); return n_chars; } /* Remove existing file @dest and reopen, creating a new file with @mode */ static int unlink_and_reopen(const char *dest, mode_t mode) { int ofd; if (robust_unlink(dest) && errno != ENOENT) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); errno = save_errno; return -1; } #ifdef SUPPORT_XATTRS if (preserve_xattrs) mode |= S_IWUSR; #endif mode &= INITACCESSPERMS; if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); errno = save_errno; return -1; } return ofd; } /* Copy contents of file @source to file @dest with mode @mode. * * If @tmpfilefd is < 0, copy_file unlinks @dest and then opens a new * file with name @dest. * * Otherwise, copy_file writes to and closes the provided file * descriptor. * * In either case, if --xattrs are being preserved, the dest file will * have its xattrs set from the source file. * * This is used in conjunction with the --temp-dir, --backup, and * --copy-dest options. */ int copy_file(const char *source, const char *dest, int tmpfilefd, mode_t mode) { int ifd, ofd; char buf[1024 * 8]; int len; /* Number of bytes read into `buf'. */ OFF_T prealloc_len = 0, offset = 0; if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "open %s", full_fname(source)); errno = save_errno; return -1; } if (tmpfilefd >= 0) { ofd = tmpfilefd; } else { ofd = unlink_and_reopen(dest, mode); if (ofd < 0) { int save_errno = errno; close(ifd); errno = save_errno; return -1; } } #ifdef SUPPORT_PREALLOCATION if (preallocate_files) { STRUCT_STAT srcst; /* Try to preallocate enough space for file's eventual length. Can * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */ if (do_fstat(ifd, &srcst) < 0) rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); else if (srcst.st_size > 0) { prealloc_len = do_fallocate(ofd, 0, srcst.st_size); if (prealloc_len < 0) rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); } } #endif while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { if (full_write(ofd, buf, len) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest)); close(ifd); close(ofd); errno = save_errno; return -1; } offset += len; } if (len < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "read %s", full_fname(source)); close(ifd); close(ofd); errno = save_errno; return -1; } if (close(ifd) < 0) { rsyserr(FWARNING, errno, "close failed on %s", full_fname(source)); } /* Source file might have shrunk since we fstatted it. * Cut off any extra preallocated zeros from dest file. */ if (offset < prealloc_len) { #ifdef HAVE_FTRUNCATE /* If we fail to truncate, the dest file may be wrong, so we * must trigger the "partial transfer" error. */ if (do_ftruncate(ofd, offset) < 0) rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); #else rprintf(FERROR_XFER, "no ftruncate for over-long pre-alloc: %s", full_fname(dest)); #endif } if (do_fsync && fsync(ofd) < 0) { int save_errno = errno; rsyserr(FERROR, errno, "fsync failed on %s", full_fname(dest)); close(ofd); errno = save_errno; return -1; } if (close(ofd) < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "close failed on %s", full_fname(dest)); errno = save_errno; return -1; } #ifdef SUPPORT_XATTRS if (preserve_xattrs) copy_xattrs(source, dest); #endif return 0; } /* MAX_RENAMES should be 10**MAX_RENAMES_DIGITS */ #define MAX_RENAMES_DIGITS 3 #define MAX_RENAMES 1000 /** * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so * rename to /.rsyncNNN instead. * * Note that successive rsync runs will shuffle the filenames around a * bit as long as the file is still busy; this is because this function * does not know if the unlink call is due to a new file coming in, or * --delete trying to remove old .rsyncNNN files, hence it renames it * each time. **/ int robust_unlink(const char *fname) { #ifndef ETXTBSY return do_unlink(fname); #else static int counter = 1; int rc, pos, start; char path[MAXPATHLEN]; rc = do_unlink(fname); if (rc == 0 || errno != ETXTBSY) return rc; if ((pos = strlcpy(path, fname, MAXPATHLEN)) >= MAXPATHLEN) pos = MAXPATHLEN - 1; while (pos > 0 && path[pos-1] != '/') pos--; pos += strlcpy(path+pos, ".rsync", MAXPATHLEN-pos); if (pos > (MAXPATHLEN-MAX_RENAMES_DIGITS-1)) { errno = ETXTBSY; return -1; } /* start where the last one left off to reduce chance of clashes */ start = counter; do { snprintf(&path[pos], MAX_RENAMES_DIGITS+1, "%03d", counter); if (++counter >= MAX_RENAMES) counter = 1; } while ((rc = access(path, 0)) == 0 && counter != start); if (INFO_GTE(MISC, 1)) { rprintf(FWARNING, "renaming %s to %s because of text busy\n", fname, path); } /* maybe we should return rename()'s exit status? Nah. */ if (do_rename(fname, path) != 0) { errno = ETXTBSY; return -1; } return 0; #endif } /* Returns 0 on successful rename, 1 if we successfully copied the file * across filesystems, -2 if copy_file() failed, and -1 on other errors. * If partialptr is not NULL and we need to do a copy, copy the file into * the active partial-dir instead of over the destination file. */ int robust_rename(const char *from, const char *to, const char *partialptr, int mode) { int tries = 4; /* A resumed in-place partial-dir transfer might call us with from and * to pointing to the same buf if the transfer failed yet again. */ if (from == to) return 0; while (tries--) { if (do_rename(from, to) == 0) return 0; switch (errno) { #ifdef ETXTBSY case ETXTBSY: if (robust_unlink(to) != 0) { errno = ETXTBSY; return -1; } errno = ETXTBSY; break; #endif case EXDEV: if (partialptr) { if (!handle_partial_dir(partialptr,PDIR_CREATE)) return -2; to = partialptr; } if (copy_file(from, to, -1, mode) != 0) return -2; do_unlink(from); return 1; default: return -1; } } return -1; } static pid_t all_pids[10]; static int num_pids; /** Fork and record the pid of the child. **/ pid_t do_fork(void) { pid_t newpid = fork(); if (newpid != 0 && newpid != -1) { all_pids[num_pids++] = newpid; } return newpid; } /** * Kill all children. * * @todo It would be kind of nice to make sure that they are actually * all our children before we kill them, because their pids may have * been recycled by some other process. Perhaps when we wait for a * child, we should remove it from this array. Alternatively we could * perhaps use process groups, but I think that would not work on * ancient Unix versions that don't support them. **/ void kill_all(int sig) { int i; for (i = 0; i < num_pids; i++) { /* Let's just be a little careful where we * point that gun, hey? See kill(2) for the * magic caused by negative values. */ pid_t p = all_pids[i]; if (p == getpid()) continue; if (p <= 0) continue; kill(p, sig); } } /** Lock a byte range in a open file */ int lock_range(int fd, int offset, int len) { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = offset; lock.l_len = len; lock.l_pid = 0; return fcntl(fd,F_SETLK,&lock) == 0; } #define ENSURE_MEMSPACE(buf, type, sz, req) \ do { if ((req) > sz) buf = realloc_array(buf, type, sz = MAX(sz * 2, req)); } while(0) static inline void call_glob_match(const char *name, int len, int from_glob, char *arg, int abpos, int fbpos); static struct glob_data { char *arg_buf, *filt_buf, **argv; int absize, fbsize, maxargs, argc; } glob; static void glob_match(char *arg, int abpos, int fbpos) { int len; char *slash; while (*arg == '.' && arg[1] == '/') { if (fbpos < 0) { ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, glob.absize); memcpy(glob.filt_buf, glob.arg_buf, abpos + 1); fbpos = abpos; } ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 3); glob.arg_buf[abpos++] = *arg++; glob.arg_buf[abpos++] = *arg++; glob.arg_buf[abpos] = '\0'; } if ((slash = strchr(arg, '/')) != NULL) { *slash = '\0'; len = slash - arg; } else len = strlen(arg); if (strpbrk(arg, "*?[")) { struct dirent *di; DIR *d; if (!(d = opendir(abpos ? glob.arg_buf : "."))) return; while ((di = readdir(d)) != NULL) { char *dname = d_name(di); if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))) continue; if (!wildmatch(arg, dname)) continue; call_glob_match(dname, strlen(dname), 1, slash ? arg + len + 1 : NULL, abpos, fbpos); } closedir(d); } else { call_glob_match(arg, len, 0, slash ? arg + len + 1 : NULL, abpos, fbpos); } if (slash) *slash = '/'; } static inline void call_glob_match(const char *name, int len, int from_glob, char *arg, int abpos, int fbpos) { char *use_buf; ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + len + 2); memcpy(glob.arg_buf + abpos, name, len); abpos += len; glob.arg_buf[abpos] = '\0'; if (fbpos >= 0) { ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, fbpos + len + 2); memcpy(glob.filt_buf + fbpos, name, len); fbpos += len; glob.filt_buf[fbpos] = '\0'; use_buf = glob.filt_buf; } else use_buf = glob.arg_buf; if (from_glob || (arg && len)) { STRUCT_STAT st; int is_dir; if (do_stat(glob.arg_buf, &st) != 0) return; is_dir = S_ISDIR(st.st_mode) != 0; if (arg && !is_dir) return; if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0) return; } if (arg) { glob.arg_buf[abpos++] = '/'; glob.arg_buf[abpos] = '\0'; if (fbpos >= 0) { glob.filt_buf[fbpos++] = '/'; glob.filt_buf[fbpos] = '\0'; } glob_match(arg, abpos, fbpos); } else { ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1); glob.argv[glob.argc++] = strdup(glob.arg_buf); } } /* This routine performs wild-card expansion of the pathname in "arg". Any * daemon-excluded files/dirs will not be matched by the wildcards. Returns 0 * if a wild-card string is the only returned item (due to matching nothing). */ int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p) { int ret, save_argc; char *s; if (!arg) { if (glob.filt_buf) free(glob.filt_buf); free(glob.arg_buf); memset(&glob, 0, sizeof glob); return -1; } if (sanitize_paths) s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS); else { s = strdup(arg); clean_fname(s, CFN_KEEP_DOT_DIRS | CFN_KEEP_TRAILING_SLASH | CFN_COLLAPSE_DOT_DOT_DIRS); } ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN); *glob.arg_buf = '\0'; glob.argc = save_argc = *argc_p; glob.argv = *argv_p; glob.maxargs = *maxargs_p; ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100); glob_match(s, 0, -1); /* The arg didn't match anything, so add the failed arg to the list. */ if (glob.argc == save_argc) { ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1); glob.argv[glob.argc++] = s; ret = 0; } else { free(s); ret = 1; } *maxargs_p = glob.maxargs; *argv_p = glob.argv; *argc_p = glob.argc; return ret; } /* This routine is only used in daemon mode. */ void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p) { char *p, *s; char *base = base1; int base_len = strlen(base); if (!arg || !*arg) return; if (strncmp(arg, base, base_len) == 0) arg += base_len; if (protect_args) { glob_expand(arg, argv_p, argc_p, maxargs_p); return; } arg = strdup(arg); if (asprintf(&base," %s/", base1) < 0) out_of_memory("glob_expand_module"); base_len++; for (s = arg; *s; s = p + base_len) { if ((p = strstr(s, base)) != NULL) *p = '\0'; /* split it at this point */ glob_expand(s, argv_p, argc_p, maxargs_p); if (!p) break; } free(arg); free(base); } /** * Convert a string to lower case **/ void strlower(char *s) { while (*s) { if (isUpper(s)) *s = toLower(s); s++; } } /** * Split a string into tokens based (usually) on whitespace & commas. If the * string starts with a comma (after skipping any leading whitespace), then * splitting is done only on commas. No empty tokens are ever returned. */ char *conf_strtok(char *str) { static int commas_only = 0; if (str) { while (isSpace(str)) str++; if (*str == ',') { commas_only = 1; str++; } else commas_only = 0; } while (commas_only) { char *end, *tok = strtok(str, ","); if (!tok) return NULL; /* Trim just leading and trailing whitespace. */ while (isSpace(tok)) tok++; end = tok + strlen(tok); while (end > tok && isSpace(end-1)) *--end = '\0'; if (*tok) return tok; str = NULL; } return strtok(str, " ,\t\r\n"); } /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If * p1 ends with a '/', no extra '/' is inserted.) Returns the length of both * strings + 1 (if '/' was inserted), regardless of whether the null-terminated * string fits into destsize. */ size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2) { size_t len = strlcpy(dest, p1, destsize); if (len < destsize - 1) { if (!len || dest[len-1] != '/') dest[len++] = '/'; if (len < destsize - 1) len += strlcpy(dest + len, p2, destsize - len); else { dest[len] = '\0'; len += strlen(p2); } } else len += strlen(p2) + 1; /* Assume we'd insert a '/'. */ return len; } /* Join any number of strings together, putting them in "dest". The return * value is the length of all the strings, regardless of whether the null- * terminated whole fits in destsize. Your list of string pointers must end * with a NULL to indicate the end of the list. */ size_t stringjoin(char *dest, size_t destsize, ...) { va_list ap; size_t len, ret = 0; const char *src; va_start(ap, destsize); while (1) { if (!(src = va_arg(ap, const char *))) break; len = strlen(src); ret += len; if (destsize > 1) { if (len >= destsize) len = destsize - 1; memcpy(dest, src, len); destsize -= len; dest += len; } } *dest = '\0'; va_end(ap); return ret; } int count_dir_elements(const char *p) { int cnt = 0, new_component = 1; while (*p) { if (*p++ == '/') new_component = (*p != '.' || (p[1] != '/' && p[1] != '\0')); else if (new_component) { new_component = 0; cnt++; } } return cnt; } /* Turns multiple adjacent slashes into a single slash (possible exception: * the preserving of two leading slashes at the start), drops all leading or * interior "." elements unless CFN_KEEP_DOT_DIRS is flagged. Will also drop * a trailing '.' after a '/' if CFN_DROP_TRAILING_DOT_DIR is flagged, removes * a trailing slash (perhaps after removing the aforementioned dot) unless * CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements * (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the * resulting name would be empty, returns ".". */ int clean_fname(char *name, int flags) { char *limit = name - 1, *t = name, *f = name; int anchored; if (!name) return 0; #define DOT_IS_DOT_DOT_DIR(bp) (bp[1] == '.' && (bp[2] == '/' || !bp[2])) if ((anchored = *f == '/') != 0) { *t++ = *f++; #ifdef __CYGWIN__ /* If there are exactly 2 slashes at the start, preserve * them. Would break daemon excludes unless the paths are * really treated differently, so used this sparingly. */ if (*f == '/' && f[1] != '/') *t++ = *f++; #endif } else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') { *t++ = *f++; *t++ = *f++; } else if (flags & CFN_REFUSE_DOT_DOT_DIRS && *f == '.' && DOT_IS_DOT_DOT_DIR(f)) return -1; while (*f) { /* discard extra slashes */ if (*f == '/') { f++; continue; } if (*f == '.') { /* discard interior "." dirs */ if (f[1] == '/' && !(flags & CFN_KEEP_DOT_DIRS)) { f += 2; continue; } if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR) break; /* collapse ".." dirs */ if (flags & (CFN_COLLAPSE_DOT_DOT_DIRS|CFN_REFUSE_DOT_DOT_DIRS) && DOT_IS_DOT_DOT_DIR(f)) { char *s = t - 1; if (flags & CFN_REFUSE_DOT_DOT_DIRS) return -1; if (s == name && anchored) { f += 2; continue; } while (s > limit && *--s != '/') {} if (s != t - 1 && (s < name || *s == '/')) { t = s + 1; f += 2; continue; } limit = t + 2; } } while (*f && (*t++ = *f++) != '/') {} } if (t > name+anchored && t[-1] == '/' && !(flags & CFN_KEEP_TRAILING_SLASH)) t--; if (t == name) *t++ = '.'; *t = '\0'; #undef DOT_IS_DOT_DOT_DIR return t - name; } /* Make path appear as if a chroot had occurred. This handles a leading * "/" (either removing it or expanding it) and any leading or embedded * ".." components that attempt to escape past the module's top dir. * * If dest is NULL, a buffer is allocated to hold the result. It is legal * to call with the dest and the path (p) pointing to the same buffer, but * rootdir will be ignored to avoid expansion of the string. * * The rootdir string contains a value to use in place of a leading slash. * Specify NULL to get the default of "module_dir". * * The depth var is a count of how many '..'s to allow at the start of the * path. * * We also clean the path in a manner similar to clean_fname() but with a * few differences: * * Turns multiple adjacent slashes into a single slash, gets rid of "." dir * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and * ALWAYS collapses ".." elements (except for those at the start of the * string up to "depth" deep). If the resulting name would be empty, * change it into a ".". */ char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags) { char *start, *sanp; int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS); if (dest != p) { int plen = strlen(p); /* the path len INCLUDING any separating slash */ if (*p == '/') { if (!rootdir) rootdir = module_dir; rlen = strlen(rootdir); depth = 0; p++; } if (!dest) dest = new_array(char, MAX(rlen + plen + 1, 2)); else if (rlen + plen + 1 >= MAXPATHLEN) return NULL; if (rlen) { /* only true if p previously started with a slash */ memcpy(dest, rootdir, rlen); if (rlen > 1) /* a rootdir of len 1 is "/", so this avoids a 2nd slash */ dest[rlen++] = '/'; } } if (drop_dot_dirs) { while (*p == '.' && p[1] == '/') p += 2; } start = sanp = dest + rlen; /* This loop iterates once per filename component in p, pointing at * the start of the name (past any prior slash) for each iteration. */ while (*p) { /* discard leading or extra slashes */ if (*p == '/') { p++; continue; } if (drop_dot_dirs) { if (*p == '.' && (p[1] == '/' || p[1] == '\0')) { /* skip "." component */ p++; continue; } } if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) { /* ".." component followed by slash or end */ if (depth <= 0 || sanp != start) { p += 2; if (sanp != start) { /* back up sanp one level */ --sanp; /* now pointing at slash */ while (sanp > start && sanp[-1] != '/') sanp--; } continue; } /* allow depth levels of .. at the beginning */ depth--; /* move the virtual beginning to leave the .. alone */ start = sanp + 3; } /* copy one component through next slash */ while (*p && (*sanp++ = *p++) != '/') {} } if (sanp == dest) { /* ended up with nothing, so put in "." component */ *sanp++ = '.'; } *sanp = '\0'; return dest; } /* Like chdir(), but it keeps track of the current directory (in the * global "curr_dir"), and ensures that the path size doesn't overflow. * Also cleans the path using the clean_fname() function. */ int change_dir(const char *dir, int set_path_only) { static int initialised, skipped_chdir; unsigned int len; if (!initialised) { initialised = 1; if (getcwd(curr_dir, sizeof curr_dir - 1) == NULL) { rsyserr(FERROR, errno, "getcwd()"); exit_cleanup(RERR_FILESELECT); } curr_dir_len = strlen(curr_dir); } if (!dir) /* this call was probably just to initialize */ return 0; len = strlen(dir); if (len == 1 && *dir == '.' && (!skipped_chdir || set_path_only)) return 1; if (*dir == '/') { if (len >= sizeof curr_dir) { errno = ENAMETOOLONG; return 0; } if (!set_path_only && chdir(dir)) return 0; skipped_chdir = set_path_only; memcpy(curr_dir, dir, len + 1); } else { unsigned int save_dir_len = curr_dir_len; if (curr_dir_len + 1 + len >= sizeof curr_dir) { errno = ENAMETOOLONG; return 0; } if (!(curr_dir_len && curr_dir[curr_dir_len-1] == '/')) curr_dir[curr_dir_len++] = '/'; memcpy(curr_dir + curr_dir_len, dir, len + 1); if (!set_path_only && chdir(curr_dir)) { curr_dir_len = save_dir_len; curr_dir[curr_dir_len] = '\0'; return 0; } skipped_chdir = set_path_only; } curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); if (sanitize_paths) { if (module_dirlen > curr_dir_len) module_dirlen = curr_dir_len; curr_dir_depth = count_dir_elements(curr_dir + module_dirlen); } if (DEBUG_GTE(CHDIR, 1) && !set_path_only) rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir); return 1; } /* This will make a relative path absolute and clean it up via clean_fname(). * Returns the string, which might be newly allocated, or NULL on error. */ char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr) { unsigned int len; if (*path != '/') { /* Make path absolute. */ int len = strlen(path); if (curr_dir_len + 1 + len >= sizeof curr_dir) return NULL; curr_dir[curr_dir_len] = '/'; memcpy(curr_dir + curr_dir_len + 1, path, len + 1); path = strdup(curr_dir); curr_dir[curr_dir_len] = '\0'; } else if (force_newbuf) path = strdup(path); len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); if (len_ptr) *len_ptr = len; return path; } /** * Return a quoted string with the full pathname of the indicated filename. * The string " (in MODNAME)" may also be appended. The returned pointer * remains valid until the next time full_fname() is called. **/ char *full_fname(const char *fn) { static char *result = NULL; char *m1, *m2, *m3; char *p1, *p2; if (result) free(result); if (*fn == '/') p1 = p2 = ""; else { p1 = curr_dir + module_dirlen; for (p2 = p1; *p2 == '/'; p2++) {} if (*p2) p2 = "/"; } if (module_id >= 0) { m1 = " (in "; m2 = lp_name(module_id); m3 = ")"; } else m1 = m2 = m3 = ""; if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) < 0) out_of_memory("full_fname"); return result; } static char partial_fname[MAXPATHLEN]; char *partial_dir_fname(const char *fname) { char *t = partial_fname; int sz = sizeof partial_fname; const char *fn; if ((fn = strrchr(fname, '/')) != NULL) { fn++; if (*partial_dir != '/') { int len = fn - fname; strncpy(t, fname, len); /* safe */ t += len; sz -= len; } } else fn = fname; if ((int)pathjoin(t, sz, partial_dir, fn) >= sz) return NULL; if (daemon_filter_list.head) { t = strrchr(partial_fname, '/'); *t = '\0'; if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0) return NULL; *t = '/'; if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0) return NULL; } return partial_fname; } /* If no --partial-dir option was specified, we don't need to do anything * (the partial-dir is essentially '.'), so just return success. */ int handle_partial_dir(const char *fname, int create) { char *fn, *dir; if (fname != partial_fname) return 1; if (!create && *partial_dir == '/') return 1; if (!(fn = strrchr(partial_fname, '/'))) return 1; *fn = '\0'; dir = partial_fname; if (create) { STRUCT_STAT st; int statret = do_lstat(dir, &st); if (statret == 0 && !S_ISDIR(st.st_mode)) { if (do_unlink(dir) < 0) { *fn = '/'; return 0; } statret = -1; } if (statret < 0 && do_mkdir(dir, 0700) < 0) { *fn = '/'; return 0; } } else do_rmdir(dir); *fn = '/'; return 1; } /* Determine if a symlink points outside the current directory tree. * This is considered "unsafe" because e.g. when mirroring somebody * else's machine it might allow them to establish a symlink to * /etc/passwd, and then read it through a web server. * * Returns 1 if unsafe, 0 if safe. * * Null symlinks and absolute symlinks are always unsafe. * * Basically here we are concerned with symlinks whose target contains * "..", because this might cause us to walk back up out of the * transferred directory. We are not allowed to go back up and * reenter. * * "dest" is the target of the symlink in question. * * "src" is the top source directory currently applicable at the level * of the referenced symlink. This is usually the symlink's full path * (including its name), as referenced from the root of the transfer. */ int unsafe_symlink(const char *dest, const char *src) { const char *name, *slash; int depth = 0; /* all absolute and null symlinks are unsafe */ if (!dest || !*dest || *dest == '/') return 1; /* find out what our safety margin is */ for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) { /* ".." segment starts the count over. "." segment is ignored. */ if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) { if (name[1] == '.') depth = 0; } else depth++; while (slash[1] == '/') slash++; /* just in case src isn't clean */ } if (*name == '.' && name[1] == '.' && name[2] == '\0') depth = 0; for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) { if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) { if (name[1] == '.') { /* if at any point we go outside the current directory then stop - it is unsafe */ if (--depth < 0) return 1; } } else depth++; while (slash[1] == '/') slash++; } if (*name == '.' && name[1] == '.' && name[2] == '\0') depth--; return depth < 0; } /* Return the date and time as a string. Some callers tweak returned buf. */ char *timestring(time_t t) { static int ndx = 0; static char buffers[4][20]; /* We support 4 simultaneous timestring results. */ char *TimeBuf = buffers[ndx = (ndx + 1) % 4]; struct tm *tm = localtime(&t); int len = snprintf(TimeBuf, sizeof buffers[0], "%4d/%02d/%02d %02d:%02d:%02d", (int)tm->tm_year + 1900, (int)tm->tm_mon + 1, (int)tm->tm_mday, (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec); assert(len > 0); /* Silence gcc warning */ return TimeBuf; } /* Determine if two time_t values are equivalent (either exact, or in * the modification timestamp window established by --modify-window). * Returns 1 if the times the "same", or 0 if they are different. */ int same_time(time_t f1_sec, unsigned long f1_nsec, time_t f2_sec, unsigned long f2_nsec) { if (modify_window == 0) return f1_sec == f2_sec; if (modify_window < 0) return f1_sec == f2_sec && f1_nsec == f2_nsec; /* The nanoseconds do not figure into these checks -- time windows don't care about that. */ if (f2_sec > f1_sec) return f2_sec - f1_sec <= modify_window; return f1_sec - f2_sec <= modify_window; } #ifdef __INSURE__XX #include /** This routine is a trick to immediately catch errors when debugging with insure. A xterm with a gdb is popped up when insure catches a error. It is Linux specific. **/ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) { static int (*fn)(); int ret, pid_int = getpid(); char *cmd; if (asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; " "gdb /proc/%d/exe %d'", pid_int, pid_int, pid_int) < 0) return -1; if (!fn) { static void *h; h = dlopen("/usr/local/parasoft/insure++lite/lib.linux2/libinsure.so", RTLD_LAZY); fn = dlsym(h, "_Insure_trap_error"); } ret = fn(a1, a2, a3, a4, a5, a6); system(cmd); free(cmd); return ret; } #endif /* Take a filename and filename length and return the most significant * filename suffix we can find. This ignores suffixes such as "~", * ".bak", ".orig", ".~1~", etc. */ const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr) { const char *suf, *s; BOOL had_tilde; int s_len; /* One or more dots at the start aren't a suffix. */ while (fn_len && *fn == '.') fn++, fn_len--; /* Ignore the ~ in a "foo~" filename. */ if (fn_len > 1 && fn[fn_len-1] == '~') fn_len--, had_tilde = True; else had_tilde = False; /* Assume we don't find an suffix. */ suf = ""; *len_ptr = 0; /* Find the last significant suffix. */ for (s = fn + fn_len; fn_len > 1; ) { while (*--s != '.' && s != fn) {} if (s == fn) break; s_len = fn_len - (s - fn); fn_len = s - fn; if (s_len == 4) { if (strcmp(s+1, "bak") == 0 || strcmp(s+1, "old") == 0) continue; } else if (s_len == 5) { if (strcmp(s+1, "orig") == 0) continue; } else if (s_len > 2 && had_tilde && s[1] == '~' && isDigit(s + 2)) continue; *len_ptr = s_len; suf = s; if (s_len == 1) break; /* Determine if the suffix is all digits. */ for (s++, s_len--; s_len > 0; s++, s_len--) { if (!isDigit(s)) return suf; } /* An all-digit suffix may not be that significant. */ s = suf; } return suf; } /* This is an implementation of the Levenshtein distance algorithm. It * was implemented to avoid needing a two-dimensional matrix (to save * memory). It was also tweaked to try to factor in the ASCII distance * between changed characters as a minor distance quantity. The normal * Levenshtein units of distance (each signifying a single change between * the two strings) are defined as a "UNIT". */ #define UNIT (1 << 16) uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2, uint32 upperlimit) { uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; int32 cost; unsigned i1, i2; /* Check to see if the Levenshtein distance must be greater than the * upper limit defined by the previously found lowest distance using * the heuristic that the Levenshtein distance is greater than the * difference in length of the two strings */ if ((len1 > len2 ? len1 - len2 : len2 - len1) * UNIT > upperlimit) return 0xFFFFU * UNIT + 1; if (!len1 || !len2) { if (!len1) { s1 = s2; len1 = len2; } for (i1 = 0, cost = 0; i1 < len1; i1++) cost += s1[i1]; return (int32)len1 * UNIT + cost; } for (i2 = 0; i2 < len2; i2++) a[i2] = (i2+1) * UNIT; for (i1 = 0; i1 < len1; i1++) { diag = i1 * UNIT; above = (i1+1) * UNIT; for (i2 = 0; i2 < len2; i2++) { left = a[i2]; if ((cost = *((uchar*)s1+i1) - *((uchar*)s2+i2)) != 0) { if (cost < 0) cost = UNIT - cost; else cost = UNIT + cost; } diag_inc = diag + cost; left_inc = left + UNIT + *((uchar*)s1+i1); above_inc = above + UNIT + *((uchar*)s2+i2); a[i2] = above = left < above ? (left_inc < diag_inc ? left_inc : diag_inc) : (above_inc < diag_inc ? above_inc : diag_inc); diag = left; } } return a[len2-1]; } #define BB_SLOT_SIZE (16*1024) /* Desired size in bytes */ #define BB_PER_SLOT_BITS (BB_SLOT_SIZE * 8) /* Number of bits per slot */ #define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */ struct bitbag { uint32 **bits; int slot_cnt; }; struct bitbag *bitbag_create(int max_ndx) { struct bitbag *bb = new(struct bitbag); bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS; bb->bits = new_array0(uint32*, bb->slot_cnt); return bb; } void bitbag_set_bit(struct bitbag *bb, int ndx) { int slot = ndx / BB_PER_SLOT_BITS; ndx %= BB_PER_SLOT_BITS; if (!bb->bits[slot]) bb->bits[slot] = new_array0(uint32, BB_PER_SLOT_INTS); bb->bits[slot][ndx/32] |= 1u << (ndx % 32); } #if 0 /* not needed yet */ void bitbag_clear_bit(struct bitbag *bb, int ndx) { int slot = ndx / BB_PER_SLOT_BITS; ndx %= BB_PER_SLOT_BITS; if (!bb->bits[slot]) return; bb->bits[slot][ndx/32] &= ~(1u << (ndx % 32)); } int bitbag_check_bit(struct bitbag *bb, int ndx) { int slot = ndx / BB_PER_SLOT_BITS; ndx %= BB_PER_SLOT_BITS; if (!bb->bits[slot]) return 0; return bb->bits[slot][ndx/32] & (1u << (ndx % 32)) ? 1 : 0; } #endif /* Call this with -1 to start checking from 0. Returns -1 at the end. */ int bitbag_next_bit(struct bitbag *bb, int after) { uint32 bits, mask; int i, ndx = after + 1; int slot = ndx / BB_PER_SLOT_BITS; ndx %= BB_PER_SLOT_BITS; mask = (1u << (ndx % 32)) - 1; for (i = ndx / 32; slot < bb->slot_cnt; slot++, i = mask = 0) { if (!bb->bits[slot]) continue; for ( ; i < BB_PER_SLOT_INTS; i++, mask = 0) { if (!(bits = bb->bits[slot][i] & ~mask)) continue; /* The xor magic figures out the lowest enabled bit in * bits, and the switch quickly computes log2(bit). */ switch (bits ^ (bits & (bits-1))) { #define LOG2(n) case 1u << n: return slot*BB_PER_SLOT_BITS + i*32 + n LOG2(0); LOG2(1); LOG2(2); LOG2(3); LOG2(4); LOG2(5); LOG2(6); LOG2(7); LOG2(8); LOG2(9); LOG2(10); LOG2(11); LOG2(12); LOG2(13); LOG2(14); LOG2(15); LOG2(16); LOG2(17); LOG2(18); LOG2(19); LOG2(20); LOG2(21); LOG2(22); LOG2(23); LOG2(24); LOG2(25); LOG2(26); LOG2(27); LOG2(28); LOG2(29); LOG2(30); LOG2(31); } return -1; /* impossible... */ } } return -1; } void flist_ndx_push(flist_ndx_list *lp, int ndx) { struct flist_ndx_item *item; item = new(struct flist_ndx_item); item->next = NULL; item->ndx = ndx; if (lp->tail) lp->tail->next = item; else lp->head = item; lp->tail = item; } int flist_ndx_pop(flist_ndx_list *lp) { struct flist_ndx_item *next; int ndx; if (!lp->head) return -1; ndx = lp->head->ndx; next = lp->head->next; free(lp->head); lp->head = next; if (!next) lp->tail = NULL; return ndx; } /* Make sure there is room for one more item in the item list. If there * is not, expand the list as indicated by the value of "incr": * - if incr < 0 then increase the malloced size by -1 * incr * - if incr >= 0 then either make the malloced size equal to "incr" * or (if that's not large enough) double the malloced size * After the size check, the list's count is incremented by 1 and a pointer * to the "new" list item is returned. */ void *expand_item_list(item_list *lp, size_t item_size, const char *desc, int incr) { /* First time through, 0 <= 0, so list is expanded. */ if (lp->malloced <= lp->count) { void *new_ptr; size_t expand_size; if (incr < 0) expand_size = -incr; /* increase slowly */ else if (lp->malloced < (size_t)incr) expand_size = incr - lp->malloced; else if (lp->malloced) expand_size = lp->malloced; /* double in size */ else expand_size = 1; if (SIZE_MAX/item_size - expand_size < lp->malloced) overflow_exit("expand_item_list"); expand_size += lp->malloced; new_ptr = realloc_buf(lp->items, expand_size * item_size); if (DEBUG_GTE(FLIST, 3)) { rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", who_am_i(), desc, big_num(expand_size * item_size), new_ptr == lp->items ? " not" : ""); } lp->items = new_ptr; lp->malloced = expand_size; } return (char*)lp->items + (lp->count++ * item_size); } /* This zeroing of memory won't be optimized away by the compiler. */ void force_memzero(void *buf, size_t len) { volatile uchar *z = buf; while (len-- > 0) *z++ = '\0'; } rsync-3.2.7/socket.c0000664000000000000000000005270613675270555013046 0ustar rootroot/* * Socket functions used in rsync. * * Copyright (C) 1992-2001 Andrew Tridgell * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2020 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. */ /* This file is now converted to use the new-style getaddrinfo() * interface, which supports IPv6 but is also supported on recent * IPv4-only machines. On systems that don't have that interface, we * emulate it using the KAME implementation. */ #include "rsync.h" #include "itypes.h" #include "ifuncs.h" #ifdef HAVE_NETINET_IN_SYSTM_H #include #endif #ifdef HAVE_NETINET_IP_H #include #endif #include extern char *bind_address; extern char *sockopts; extern int default_af_hint; extern int connect_timeout; extern int pid_file_fd; #ifdef HAVE_SIGACTION static struct sigaction sigact; #endif static int sock_exec(const char *prog); /* Establish a proxy connection on an open socket to a web proxy by using the * CONNECT method. If proxy_user and proxy_pass are not NULL, they are used to * authenticate to the proxy using the "Basic" proxy-authorization protocol. */ static int establish_proxy_connection(int fd, char *host, int port, char *proxy_user, char *proxy_pass) { char *cp, buffer[1024]; char *authhdr, authbuf[1024]; int len; if (proxy_user && proxy_pass) { stringjoin(buffer, sizeof buffer, proxy_user, ":", proxy_pass, NULL); len = strlen(buffer); if ((len*8 + 5) / 6 >= (int)sizeof authbuf - 3) { rprintf(FERROR, "authentication information is too long\n"); return -1; } base64_encode(buffer, len, authbuf, 1); authhdr = "\r\nProxy-Authorization: Basic "; } else { *authbuf = '\0'; authhdr = ""; } len = snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", host, port, authhdr, authbuf); assert(len > 0 && len < (int)sizeof buffer); if (write(fd, buffer, len) != len) { rsyserr(FERROR, errno, "failed to write to proxy"); return -1; } for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) { if (read(fd, cp, 1) != 1) { rsyserr(FERROR, errno, "failed to read from proxy"); return -1; } if (*cp == '\n') break; } if (*cp != '\n') cp++; *cp-- = '\0'; if (*cp == '\r') *cp = '\0'; if (strncmp(buffer, "HTTP/", 5) != 0) { rprintf(FERROR, "bad response from proxy -- %s\n", buffer); return -1; } for (cp = &buffer[5]; isDigit(cp) || *cp == '.'; cp++) {} while (*cp == ' ') cp++; if (*cp != '2') { rprintf(FERROR, "bad response from proxy -- %s\n", buffer); return -1; } /* throw away the rest of the HTTP header */ while (1) { for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) { if (read(fd, cp, 1) != 1) { rsyserr(FERROR, errno, "failed to read from proxy"); return -1; } if (*cp == '\n') break; } if (cp > buffer && *cp == '\n') cp--; if (cp == buffer && (*cp == '\n' || *cp == '\r')) break; } return 0; } /* Try to set the local address for a newly-created socket. * Return -1 if this fails. */ int try_bind_local(int s, int ai_family, int ai_socktype, const char *bind_addr) { int error; struct addrinfo bhints, *bres_all, *r; memset(&bhints, 0, sizeof bhints); bhints.ai_family = ai_family; bhints.ai_socktype = ai_socktype; bhints.ai_flags = AI_PASSIVE; if ((error = getaddrinfo(bind_addr, NULL, &bhints, &bres_all))) { rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n", bind_addr, gai_strerror(error)); return -1; } for (r = bres_all; r; r = r->ai_next) { if (bind(s, r->ai_addr, r->ai_addrlen) == -1) continue; freeaddrinfo(bres_all); return s; } /* no error message; there might be some problem that allows * creation of the socket but not binding, perhaps if the * machine has no ipv6 address of this name. */ freeaddrinfo(bres_all); return -1; } /* connect() timeout handler based on alarm() */ static void contimeout_handler(UNUSED(int val)) { connect_timeout = -1; } /* Open a socket to a tcp remote host with the specified port. * * Based on code from Warren. Proxy support by Stephen Rothwell. * getaddrinfo() rewrite contributed by KAME.net. * * Now that we support IPv6 we need to look up the remote machine's address * first, using af_hint to set a preference for the type of address. Then * depending on whether it has v4 or v6 addresses we try to open a connection. * * The loop allows for machines with some addresses which may not be reachable, * perhaps because we can't e.g. route ipv6 to that network but we can get ip4 * packets through. * * bind_addr: local address to use. Normally NULL to bind the wildcard address. * * af_hint: address family, e.g. AF_INET or AF_INET6. */ int open_socket_out(char *host, int port, const char *bind_addr, int af_hint) { int type = SOCK_STREAM; int error, s, j, addr_cnt, *errnos; struct addrinfo hints, *res0, *res; char portbuf[10]; char *h, *cp; int proxied = 0; char buffer[1024]; char *proxy_user = NULL, *proxy_pass = NULL; /* if we have a RSYNC_PROXY env variable then redirect our * connection via a web proxy at the given address. */ h = getenv("RSYNC_PROXY"); proxied = h != NULL && *h != '\0'; if (proxied) { strlcpy(buffer, h, sizeof buffer); /* Is the USER:PASS@ prefix present? */ if ((cp = strrchr(buffer, '@')) != NULL) { *cp++ = '\0'; /* The remainder is the HOST:PORT part. */ h = cp; if ((cp = strchr(buffer, ':')) == NULL) { rprintf(FERROR, "invalid proxy specification: should be USER:PASS@HOST:PORT\n"); return -1; } *cp++ = '\0'; proxy_user = buffer; proxy_pass = cp; } else { /* The whole buffer is the HOST:PORT part. */ h = buffer; } if ((cp = strchr(h, ':')) == NULL) { rprintf(FERROR, "invalid proxy specification: should be HOST:PORT\n"); return -1; } *cp++ = '\0'; strlcpy(portbuf, cp, sizeof portbuf); if (DEBUG_GTE(CONNECT, 1)) { rprintf(FINFO, "connection via http proxy %s port %s\n", h, portbuf); } } else { snprintf(portbuf, sizeof portbuf, "%d", port); h = host; } memset(&hints, 0, sizeof hints); hints.ai_family = af_hint; hints.ai_socktype = type; error = getaddrinfo(h, portbuf, &hints, &res0); if (error) { rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n", h, portbuf, gai_strerror(error)); return -1; } for (res = res0, addr_cnt = 0; res; res = res->ai_next, addr_cnt++) {} errnos = new_array0(int, addr_cnt); s = -1; /* Try to connect to all addresses for this machine until we get * through. It might e.g. be multi-homed, or have both IPv4 and IPv6 * addresses. We need to create a socket for each record, since the * address record tells us what protocol to use to try to connect. */ for (res = res0, j = 0; res; res = res->ai_next, j++) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) continue; if (bind_addr && try_bind_local(s, res->ai_family, type, bind_addr) == -1) { close(s); s = -1; continue; } if (connect_timeout > 0) { SIGACTION(SIGALRM, contimeout_handler); alarm(connect_timeout); } set_socket_options(s, sockopts); while (connect(s, res->ai_addr, res->ai_addrlen) < 0) { if (connect_timeout < 0) exit_cleanup(RERR_CONTIMEOUT); if (errno == EINTR) continue; close(s); s = -1; break; } if (connect_timeout > 0) alarm(0); if (s < 0) { errnos[j] = errno; continue; } if (proxied && establish_proxy_connection(s, host, port, proxy_user, proxy_pass) != 0) { close(s); s = -1; continue; } if (DEBUG_GTE(CONNECT, 2)) { char buf[2048]; if ((error = getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof buf, NULL, 0, NI_NUMERICHOST)) != 0) snprintf(buf, sizeof buf, "*getnameinfo failure: %s*", gai_strerror(error)); rprintf(FINFO, "Connected to %s (%s)\n", h, buf); } break; } if (s < 0 || DEBUG_GTE(CONNECT, 2)) { char buf[2048]; for (res = res0, j = 0; res; res = res->ai_next, j++) { if (errnos[j] == 0) continue; if ((error = getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof buf, NULL, 0, NI_NUMERICHOST)) != 0) snprintf(buf, sizeof buf, "*getnameinfo failure: %s*", gai_strerror(error)); rsyserr(FERROR, errnos[j], "failed to connect to %s (%s)", h, buf); } if (s < 0) s = -1; } freeaddrinfo(res0); free(errnos); return s; } /* Open an outgoing socket, but allow for it to be intercepted by * $RSYNC_CONNECT_PROG, which will execute a program across a TCP * socketpair rather than really opening a socket. * * We use this primarily in testing to detect TCP flow bugs, but not * cause security problems by really opening remote connections. * * This is based on the Samba LIBSMB_PROG feature. * * bind_addr: local address to use. Normally NULL to get the stack default. */ int open_socket_out_wrapped(char *host, int port, const char *bind_addr, int af_hint) { char *prog = getenv("RSYNC_CONNECT_PROG"); if (prog && strchr(prog, '%')) { int hlen = strlen(host); int len = strlen(prog) + 1; char *f, *t; for (f = prog; *f; f++) { if (*f != '%') continue; /* Compute more than enough room. */ if (f[1] == '%') f++; else len += hlen; } f = prog; prog = new_array(char, len); for (t = prog; *f; f++) { if (*f == '%') { switch (*++f) { case '%': /* Just skips the extra '%'. */ break; case 'H': memcpy(t, host, hlen); t += hlen; continue; default: f--; /* pass % through */ break; } } *t++ = *f; } *t = '\0'; } if (DEBUG_GTE(CONNECT, 1)) { rprintf(FINFO, "%sopening tcp connection to %s port %d\n", prog ? "Using RSYNC_CONNECT_PROG instead of " : "", host, port); } if (prog) return sock_exec(prog); return open_socket_out(host, port, bind_addr, af_hint); } /* Open one or more sockets for incoming data using the specified type, * port, and address. * * The getaddrinfo() call may return several address results, e.g. for * the machine's IPv4 and IPv6 name. * * We return an array of file-descriptors to the sockets, with a trailing * -1 value to indicate the end of the list. * * bind_addr: local address to bind, or NULL to allow it to default. */ static int *open_socket_in(int type, int port, const char *bind_addr, int af_hint) { int one = 1; int s, *socks, maxs, i, ecnt; struct addrinfo hints, *all_ai, *resp; char portbuf[10], **errmsgs; int error; memset(&hints, 0, sizeof hints); hints.ai_family = af_hint; hints.ai_socktype = type; hints.ai_flags = AI_PASSIVE; snprintf(portbuf, sizeof portbuf, "%d", port); error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai); if (error) { rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n", bind_addr, gai_strerror(error)); return NULL; } /* Count max number of sockets we might open. */ for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {} socks = new_array(int, maxs + 1); errmsgs = new_array(char *, maxs); /* We may not be able to create the socket, if for example the * machine knows about IPv6 in the C library, but not in the * kernel. */ for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) { s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol); if (s == -1) { int r = asprintf(&errmsgs[ecnt++], "socket(%d,%d,%d) failed: %s\n", (int)resp->ai_family, (int)resp->ai_socktype, (int)resp->ai_protocol, strerror(errno)); if (r < 0) out_of_memory("open_socket_in"); /* See if there's another address that will work... */ continue; } setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof one); if (sockopts) set_socket_options(s, sockopts); else set_socket_options(s, lp_socket_options()); #ifdef IPV6_V6ONLY if (resp->ai_family == AF_INET6) { if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof one) < 0 && default_af_hint != AF_INET6) { close(s); continue; } } #endif /* Now we've got a socket - we need to bind it. */ if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) { /* Nope, try another */ int r = asprintf(&errmsgs[ecnt++], "bind() failed: %s (address-family %d)\n", strerror(errno), (int)resp->ai_family); if (r < 0) out_of_memory("open_socket_in"); close(s); continue; } socks[i++] = s; } socks[i] = -1; if (all_ai) freeaddrinfo(all_ai); /* Only output the socket()/bind() messages if we were totally * unsuccessful, or if the daemon is being run with -vv. */ for (s = 0; s < ecnt; s++) { if (!i || DEBUG_GTE(BIND, 1)) rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0); free(errmsgs[s]); } free(errmsgs); if (!i) { rprintf(FERROR, "unable to bind any inbound sockets on port %d\n", port); free(socks); return NULL; } return socks; } /* Determine if a file descriptor is in fact a socket. */ int is_a_socket(int fd) { int v; socklen_t l = sizeof (int); /* Parameters to getsockopt, setsockopt etc are very * unstandardized across platforms, so don't be surprised if * there are compiler warnings on e.g. SCO OpenSwerver or AIX. * It seems they all eventually get the right idea. * * Debian says: ``The fifth argument of getsockopt and * setsockopt is in reality an int [*] (and this is what BSD * 4.* and libc4 and libc5 have). Some POSIX confusion * resulted in the present socklen_t. The draft standard has * not been adopted yet, but glibc2 already follows it and * also has socklen_t [*]. See also accept(2).'' * * We now return to your regularly scheduled programming. */ return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0; } static void sigchld_handler(UNUSED(int val)) { #ifdef WNOHANG while (waitpid(-1, NULL, WNOHANG) > 0) {} #endif #ifndef HAVE_SIGACTION signal(SIGCHLD, sigchld_handler); #endif } void start_accept_loop(int port, int (*fn)(int, int)) { fd_set deffds; int *sp, maxfd, i; #ifdef HAVE_SIGACTION sigact.sa_flags = SA_NOCLDSTOP; #endif /* open an incoming socket */ sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); if (sp == NULL) exit_cleanup(RERR_SOCKETIO); /* ready to listen */ FD_ZERO(&deffds); for (i = 0, maxfd = -1; sp[i] >= 0; i++) { if (listen(sp[i], lp_listen_backlog()) < 0) { rsyserr(FERROR, errno, "listen() on socket failed"); #ifdef INET6 if (errno == EADDRINUSE && i > 0) { rprintf(FINFO, "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); } #endif exit_cleanup(RERR_SOCKETIO); } FD_SET(sp[i], &deffds); if (maxfd < sp[i]) maxfd = sp[i]; } /* now accept incoming connections - forking a new process * for each incoming connection */ while (1) { fd_set fds; pid_t pid; int fd; struct sockaddr_storage addr; socklen_t addrlen = sizeof addr; /* close log file before the potentially very long select so * file can be trimmed by another process instead of growing * forever */ logfile_close(); #ifdef FD_COPY FD_COPY(&deffds, &fds); #else fds = deffds; #endif if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) continue; for (i = 0, fd = -1; sp[i] >= 0; i++) { if (FD_ISSET(sp[i], &fds)) { fd = accept(sp[i], (struct sockaddr *)&addr, &addrlen); break; } } if (fd < 0) continue; SIGACTION(SIGCHLD, sigchld_handler); if ((pid = fork()) == 0) { int ret; if (pid_file_fd >= 0) close(pid_file_fd); for (i = 0; sp[i] >= 0; i++) close(sp[i]); /* Re-open log file in child before possibly giving * up privileges (see logfile_close() above). */ logfile_reopen(); ret = fn(fd, fd); close_all(); _exit(ret); } else if (pid < 0) { rsyserr(FERROR, errno, "could not create child server process"); close(fd); /* This might have happened because we're * overloaded. Sleep briefly before trying to * accept again. */ sleep(2); } else { /* Parent doesn't need this fd anymore. */ close(fd); } } } enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON}; struct { char *name; int level; int option; int value; int opttype; } socket_options[] = { {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL}, {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL}, #ifdef SO_BROADCAST {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL}, #endif #ifdef TCP_NODELAY {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL}, #endif #ifdef IPTOS_LOWDELAY {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON}, #endif #ifdef IPTOS_THROUGHPUT {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON}, #endif #ifdef SO_SNDBUF {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT}, #endif #ifdef SO_RCVBUF {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT}, #endif #ifdef SO_SNDLOWAT {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT}, #endif #ifdef SO_RCVLOWAT {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, #endif #ifdef SO_SNDTIMEO {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT}, #endif #ifdef SO_RCVTIMEO {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT}, #endif {NULL,0,0,0,0} }; /* Set user socket options. */ void set_socket_options(int fd, char *options) { char *tok; if (!options || !*options) return; options = strdup(options); for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) { int ret=0,i; int value = 1; char *p; int got_value = 0; if ((p = strchr(tok,'='))) { *p = 0; value = atoi(p+1); got_value = 1; } for (i = 0; socket_options[i].name; i++) { if (strcmp(socket_options[i].name,tok)==0) break; } if (!socket_options[i].name) { rprintf(FERROR,"Unknown socket option %s\n",tok); continue; } switch (socket_options[i].opttype) { case OPT_BOOL: case OPT_INT: ret = setsockopt(fd,socket_options[i].level, socket_options[i].option, (char *)&value, sizeof (int)); break; case OPT_ON: if (got_value) rprintf(FERROR,"syntax error -- %s does not take a value\n",tok); { int on = socket_options[i].value; ret = setsockopt(fd,socket_options[i].level, socket_options[i].option, (char *)&on, sizeof (int)); } break; } if (ret != 0) { rsyserr(FERROR, errno, "failed to set socket option %s", tok); } } free(options); } /* This is like socketpair but uses tcp. The function guarantees that nobody * else can attach to the socket, or if they do that this function fails and * the socket gets closed. Returns 0 on success, -1 on failure. The resulting * file descriptors are symmetrical. Currently only for RSYNC_CONNECT_PROG. */ static int socketpair_tcp(int fd[2]) { int listener; struct sockaddr_in sock; struct sockaddr_in sock2; socklen_t socklen = sizeof sock; int connect_done = 0; fd[0] = fd[1] = listener = -1; memset(&sock, 0, sizeof sock); if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; memset(&sock2, 0, sizeof sock2); #ifdef HAVE_SOCKADDR_IN_LEN sock2.sin_len = sizeof sock2; #endif sock2.sin_family = PF_INET; sock2.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(listener, (struct sockaddr *)&sock2, sizeof sock2) != 0 || listen(listener, 1) != 0 || getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0 || (fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; set_nonblocking(fd[1]); sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) { if (errno != EINPROGRESS) goto failed; } else connect_done = 1; if ((fd[0] = accept(listener, (struct sockaddr *)&sock2, &socklen)) == -1) goto failed; close(listener); listener = -1; set_blocking(fd[1]); if (connect_done == 0) { if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 && errno != EISCONN) goto failed; } /* all OK! */ return 0; failed: if (fd[0] != -1) close(fd[0]); if (fd[1] != -1) close(fd[1]); if (listener != -1) close(listener); return -1; } /* Run a program on a local tcp socket, so that we can talk to it's stdin and * stdout. This is used to fake a connection to a daemon for testing -- not * for the normal case of running SSH. * * Returns a socket which is attached to a subprocess running "prog". stdin and * stdout are attached. stderr is left attached to the original stderr. */ static int sock_exec(const char *prog) { pid_t pid; int fd[2]; if (socketpair_tcp(fd) != 0) { rsyserr(FERROR, errno, "socketpair_tcp failed"); return -1; } if (DEBUG_GTE(CMD, 1)) rprintf(FINFO, "Running socket program: \"%s\"\n", prog); pid = fork(); if (pid < 0) { rsyserr(FERROR, errno, "fork"); exit_cleanup(RERR_IPC); } if (pid == 0) { close(fd[0]); if (dup2(fd[1], STDIN_FILENO) < 0 || dup2(fd[1], STDOUT_FILENO) < 0) { fprintf(stderr, "Failed to run \"%s\"\n", prog); exit(1); } exit(shell_exec(prog)); } close(fd[1]); return fd[0]; } rsync-3.2.7/testsuite/0000775000000000000000000000000014324367162013422 5ustar rootrootrsync-3.2.7/testsuite/exclude-lsh.test0000777000000000000000000000000014324143545021062 2exclude.testustar rootrootrsync-3.2.7/testsuite/alt-dest.test0000664000000000000000000000345514217643330016042 0ustar rootroot#!/bin/sh # Copyright (C) 2004-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of --compare-dest and similar options. . "$suitedir/rsync.fns" alt1dir="$tmpdir/alt1" alt2dir="$tmpdir/alt2" alt3dir="$tmpdir/alt3" SSH="$scratchdir/src/support/lsh.sh" # Build some files/dirs/links to copy hands_setup # Setup the alt and chk dirs $RSYNC -av --include=text --include='*/' --exclude='*' "$fromdir/" "$alt1dir/" $RSYNC -av --include=etc-ltr-list --include='*/' --exclude='*' "$fromdir/" "$alt2dir/" # Create a side dir where there is a candidate destfile of the same name as a sourcefile echo "This is a test file" >"$fromdir/likely" mkdir "$alt3dir" echo "This is a test file" >"$alt3dir/likely" sleep 1 touch "$fromdir/dir/text" "$fromdir/likely" $RSYNC -av --exclude=/text --exclude=etc-ltr-list "$fromdir/" "$chkdir/" # Let's do it! checkit "$RSYNC -avv --no-whole-file \ --compare-dest='$alt1dir' --compare-dest='$alt2dir' \ '$fromdir/' '$todir/'" "$chkdir" "$todir" rm -rf "$todir" checkit "$RSYNC -avv --no-whole-file \ --copy-dest='$alt1dir' --copy-dest='$alt2dir' \ '$fromdir/' '$todir/'" "$fromdir" "$todir" # Test that copy_file() works correctly with tmpfiles for maybe_inplace in '' --inplace; do rm -rf "$todir" checkit "$RSYNC -av $maybe_inplace --copy-dest='$alt3dir' \ '$fromdir/' '$todir/'" "$fromdir" "$todir" for srchost in '' 'localhost:'; do if [ -z "$srchost" ]; then desthost='localhost:' else desthost='' fi rm -rf "$todir" checkit "$RSYNC -ave '$SSH' --rsync-path='$RSYNC' $maybe_inplace \ --copy-dest='$alt3dir' '$srchost$fromdir/' '$desthost$todir/'" \ "$fromdir" "$todir" done done # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/exclude.test0000664000000000000000000001727114324143545015761 0ustar rootroot#!/bin/sh # Copyright (C) 2003-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of exclude/include directives. # Test some of the more obscure wildcard handling of exclude/include # processing. . "$suitedir/rsync.fns" CVSIGNORE='*.junk' export CVSIGNORE case $0 in *-lsh.*) RSYNC_RSH="$scratchdir/src/support/lsh.sh" export RSYNC_RSH rpath=" --rsync-path='$RSYNC'" host='lh:' ;; *) rpath='' host='' ;; esac # Build some files/dirs/links to copy makepath "$fromdir/foo/down/to/you" makepath "$fromdir/foo/sub" makepath "$fromdir/bar/down/to/foo/too" makepath "$fromdir/bar/down/to/bar/baz" makepath "$fromdir/mid/for/foo/and/that/is/who" makepath "$fromdir/new/keep/this" makepath "$fromdir/new/lose/this" cat >"$fromdir/.filt" <"$fromdir/foo/file1" echo removed >"$fromdir/foo/file2" echo cvsout >"$fromdir/foo/file2.old" cat >"$fromdir/foo/.filt" <"$fromdir/foo/sub/file1" cat >"$fromdir/bar/.filt" <"$fromdir/bar/down/to/home-cvs-exclude" cat >"$fromdir/bar/down/to/.filt2" <"$fromdir/bar/down/to/foo/.filt2" <"$fromdir/bar/down/to/foo/file1" echo cvsout >"$fromdir/bar/down/to/foo/file1.bak" echo gone >"$fromdir/bar/down/to/foo/file3" echo lost >"$fromdir/bar/down/to/foo/file4" echo weird >"$fromdir/bar/down/to/foo/+ file3" echo cvsout-but-filtin >"$fromdir/bar/down/to/foo/file4.junk" echo smashed >"$fromdir/bar/down/to/foo/to" cat >"$fromdir/bar/down/to/bar/.filt2" <"$fromdir/bar/down/to/bar/baz/file5.deep" # This one should be ineffectual cat >"$fromdir/mid/.filt2" <"$fromdir/mid/one-in-one-out" echo one-in-one-out >"$fromdir/mid/.cvsignore" echo cvsin >"$fromdir/mid/one-for-all" cat >"$fromdir/mid/.filt" <"$fromdir/mid/for/one-in-one-out" echo expunged >"$fromdir/mid/for/foo/extra" echo retained >"$fromdir/mid/for/foo/keep" # Setup our test exclude/include files. excl="$scratchdir/exclude-from" cat >"$excl" <"$scratchdir/.cvsignore" <"$todir"/bar/down/to/bar/baz/nodel.deep cp_touch "$todir"/bar/down/to/bar/baz/nodel.deep "$chkdir"/bar/down/to/bar/baz $RSYNC -av --rsync-path="$RSYNC" --existing --filter='-! */' "$host$fromdir/" "$chkdir/" # Now, test if rsync excludes the same files, this time with a merge-exclude # file. checkit "sed '/!/d' '$excl' | $RSYNC -avv$rpath -f dir-merge_.filt -f merge_- \ --delete-during '$host$fromdir/' '$todir/'" "$chkdir" "$todir" # Remove the files that will be deleted. rm "$chkdir"/.filt rm "$chkdir"/bar/.filt rm "$chkdir"/bar/down/to/.filt2 rm "$chkdir"/bar/down/to/foo/.filt2 rm "$chkdir"/bar/down/to/bar/.filt2 rm "$chkdir"/mid/.filt $RSYNC -av --rsync-path="$RSYNC" --existing --include='*/' --exclude='*' "$host$fromdir/" "$chkdir/" # Now, try the prior command with --delete-before and some side-specific # rules. checkit "sed '/!/d' '$excl' | $RSYNC -avv$rpath -f :s_.filt -f .s_- -f P_nodel.deep \ --delete-before '$host$fromdir/' '$todir/'" "$chkdir" "$todir" # Next, we'll test some rule-restricted filter files. cat >"$fromdir/bar/down/.excl" <"$fromdir/bar/down/to/foo/.excl" <f$all_plus extra-src .f$allspace same-newness >f..t.$dots src-newness EOT # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/delay-updates.test0000664000000000000000000000074214124204403017051 0ustar rootroot#!/bin/sh # Test rsync --delay-updates . "$suitedir/rsync.fns" mkdir "$fromdir" echo 1 > "$fromdir/foo" checkit "$RSYNC -aiv --delay-updates \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" mkdir "$todir/.~tmp~" echo 2 > "$todir/.~tmp~/foo" touch -r .. "$todir/.~tmp~/foo" "$todir/foo" echo 3 > "$fromdir/foo" checkit "$RSYNC -aiv --delay-updates \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/ssh-basic.test0000664000000000000000000000176414124204403016171 0ustar rootroot#!/bin/sh # Copyright (C) 1998,1999 Philip Hands # Copyright (C) 2001 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING) # This script tests ssh, if possible. It's called by runtests.sh . "$suitedir/rsync.fns" SSH="$scratchdir/src/support/lsh.sh" if test x"$rsync_enable_ssh_tests" = xyes; then if type ssh >/dev/null; then SSH=ssh fi fi if [ "`$SSH -o'BatchMode yes' localhost echo yes`" != "yes" ]; then test_skipped "Skipping SSH tests because ssh connection to localhost not authorised" fi echo "Using remote shell: $SSH" # Create some files for rsync to copy hands_setup runtest "ssh: basic test" 'checkit "$RSYNC -avH -e \"$SSH\" --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' mv "$todir/text" "$todir/ThisShouldGo" runtest "ssh: renamed file" 'checkit "$RSYNC --delete -avH -e \"$SSH\" --rsync-path=\"$RSYNC\" \"$fromdir/\" \"localhost:$todir\"" "$fromdir/" "$todir"' rsync-3.2.7/testsuite/backup.test0000664000000000000000000000435714170671375015604 0ustar rootroot#!/bin/sh # Copyright (C) 2004-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that the --backup option works right. . "$suitedir/rsync.fns" bakdir="$tmpdir/bak" makepath "$fromdir/deep" "$bakdir/dname" name1="$fromdir/deep/name1" name2="$fromdir/deep/name2" cat "$srcdir"/[gr]*.[ch] > "$name1" cat "$srcdir"/[et]*.[ch] > "$name2" checkit "$RSYNC -ai --info=backup '$fromdir/' '$todir/'" "$fromdir" "$todir" checkit "$RSYNC -ai --info=backup '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" cat "$srcdir"/[fgpr]*.[ch] > "$name1" cat "$srcdir"/[etw]*.[ch] > "$name2" checktee "$RSYNC -ai --info=backup --no-whole-file --backup '$fromdir/' '$todir/'" for fn in deep/name1 deep/name2; do grep "backed up $fn to $fn~" "$outfile" >/dev/null || test_fail "no backup message output for $fn" diff $diffopt "$fromdir/$fn" "$todir/$fn" || test_fail "copy of $fn failed" diff $diffopt "$chkdir/$fn" "$todir/$fn~" || test_fail "backup of $fn to $fn~ failed" mv "$todir/$fn~" "$todir/$fn" done echo deleted-file >"$todir/dname" cp_touch "$todir/dname" "$chkdir" checkit "$RSYNC -ai --info=backup --no-whole-file --delete-delay \ --backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ | tee "$outfile" for fn in deep/name1 deep/name2; do grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn" done diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus" rm "$bakdir/dname" checkit "$RSYNC -ai --info=backup --del '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" cat "$srcdir"/[efgr]*.[ch] > "$name1" cat "$srcdir"/[ew]*.[ch] > "$name2" checkit "$RSYNC -ai --info=backup --inplace --no-whole-file --backup --backup-dir='$bakdir' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ | tee "$outfile" for fn in deep/name1 deep/name2; do grep "backed up $fn to .*/$fn$" "$outfile" >/dev/null || test_fail "no backup message output for $fn" done diff -r $diffopt "$chkdir" "$bakdir" || test_fail "backup dir contents are bogus" checkit "$RSYNC -ai --info=backup --inplace --no-whole-file '$fromdir/' '$bakdir/'" "$fromdir" "$bakdir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/daemon.test0000664000000000000000000000533314324271266015571 0ustar rootroot#!/bin/sh # Copyright (C) 2001 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING) # We don't really want to start the server listening, because that # might interfere with the security or operation of the test machine. # Instead we use the fake-connect feature to dynamically assign a pair # of ports. # Having started the server we try some basic operations against it: # getting a list of module # listing files in a module # retrieving a module # uploading to a module # checking the log file # password authentication . "$suitedir/rsync.fns" SSH="src/support/lsh.sh --no-cd" FILE_REPL='s/^\([^d][^ ]*\) *\(..........[0-9]\) /\1 \2 /' DIR_REPL='s/^\(d[^ ]*\) *[0-9][.,0-9]* /\1 DIR /' LS_REPL='s;[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ;####/##/## ##:##:## ;g' build_rsyncd_conf makepath "$fromdir/foo" "$fromdir/bar/baz" makepath "$todir" echo one >"$fromdir/foo/one" echo two >"$fromdir/bar/two" echo three >"$fromdir/bar/baz/three" cd "$scratchdir" ln -s test-rsyncd.conf rsyncd.conf my_uid=`get_testuid` root_uid=`get_rootuid` confopt='' if test x"$my_uid" = x"$root_uid"; then # Root needs to specify the config file, or it uses /etc/rsyncd.conf. echo "Forcing --config=$conf" confopt=" --config=$conf" fi # These have a space-padded 15-char name, then a tab, then a comment. sed 's/NOCOMMENT//' <"$chkfile" test-from r/o test-to r/w test-scratch NOCOMMENT EOT checkdiff2 "$RSYNC -ve '$SSH' --rsync-path='$RSYNC$confopt' localhost::" echo '====' RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG checkdiff2 "$RSYNC -v localhost::" echo '====' checkdiff "$RSYNC -r localhost::test-hidden" \ "sed -e '$FILE_REPL' -e '$DIR_REPL' -e '$LS_REPL'" </dev/null; then checkdiff "$RSYNC -rU localhost::test-from/f*" \ "sed -e '$FILE_REPL' -e '$DIR_REPL' -e '$LS_REPL'" < # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync's --write-batch and --read-batch options . "$suitedir/rsync.fns" hands_setup cd "$tmpdir" # Build chkdir for the daemon tests using a normal rsync and an --exclude. $RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" $RSYNC -av --only-write-batch=BATCH --exclude=foobar.baz "$fromdir/" "$todir/missing/" test -d "$todir/missing" && test_fail "--only-write-batch should not have created destination dir" runtest "--read-batch (only)" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"' rm -rf "$todir" BATCH* runtest "local --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' rm -rf "$todir" runtest "--read-batch" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$fromdir" "$todir"' build_rsyncd_conf RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG rm -rf "$todir" runtest "daemon sender --write-batch" 'checkit "$RSYNC -av --write-batch=BATCH rsync://localhost/test-from/ \"$todir\"" "$chkdir" "$todir"' rm -rf "$todir" runtest "--read-batch from daemon" 'checkit "$RSYNC -av --read-batch=BATCH \"$todir\"" "$chkdir" "$todir"' rm -rf "$todir" runtest "BATCH.sh use of --read-batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"' runtest "do-nothing re-run of batch" 'checkit "./BATCH.sh" "$chkdir" "$todir"' rm -rf "$todir" mkdir "$todir" || test_fail "failed to restore empty destination directory" runtest "daemon recv --write-batch" 'checkit "\"$ignore23\" $RSYNC -av --write-batch=BATCH \"$fromdir/\" rsync://localhost/test-to" "$chkdir" "$todir"' # The script would have aborted on error, so getting here means we pass. exit 0 rsync-3.2.7/testsuite/wildmatch.test0000664000000000000000000000130014170671375016274 0ustar rootroot#!/bin/sh # Copyright (C) 2003-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test the wildmatch functionality . "$suitedir/rsync.fns" # This test exercises the wildmatch() function (with no options) and the # wildmatch_join() function (using -x and/or -e). for opts in "" -x1 "-x1 -e1" "-x1 -e1se" -x2 "-x2 -ese" -x3 "-x3 -e1" -x4 "-x4 -e2e" -x5 "-x5 -es"; do echo Running wildtest with "$opts" "$TOOLDIR/wildtest" $opts "$srcdir/wildtest.txt" >"$scratchdir/wild.out" diff $diffopt "$scratchdir/wild.out" - < # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that the --chmod option functions correctly. . $suitedir/rsync.fns # Build some files fromdir="$scratchdir/from" todir="$scratchdir/to" checkdir="$scratchdir/check" mkdir "$fromdir" name1="$fromdir/name1" name2="$fromdir/name2" dir1="$fromdir/dir1" dir2="$fromdir/dir2" echo "This is the file" > "$name1" echo "This is the other file" > "$name2" mkdir "$dir1" "$dir2" chmod 4700 "$name1" || test_skipped "Can't chmod" chmod 700 "$dir1" chmod 770 "$dir2" # Copy the files we've created over to another directory checkit "$RSYNC -avv '$fromdir/' '$checkdir/'" "$fromdir" "$checkdir" # And then manually make the changes which should occur umask 002 chmod ug-s,a+rX "$checkdir"/* chmod +w "$checkdir" "$checkdir"/dir* checkit "$RSYNC -avv --chmod ug-s,a+rX,D+w '$fromdir/' '$todir/'" "$checkdir" "$todir" rm -r "$fromdir" "$checkdir" "$todir" makepath "$todir" "$fromdir/foo" touch "$fromdir/bar" checkit "$RSYNC -avv '$fromdir/' '$checkdir/'" "$fromdir" "$checkdir" chmod o+x "$fromdir"/bar checkit "$RSYNC -avv --chmod=Fo-x '$fromdir/' '$todir/'" "$checkdir" "$todir" # Tickle a bug in rsync 2.6.8: if you push a new directory with --perms off to # a daemon with an incoming chmod, the daemon pretends the directory is a file # for the purposes of the second application of the incoming chmod. build_rsyncd_conf cat >>"$scratchdir/test-rsyncd.conf" </dev/null; then L=hL sym_dots="$allspace" L_sym_dots=".L$allspace" is_uptodate='is uptodate' touch "$chkfile.extra" else L=cL sym_dots="c.t.$dots" L_sym_dots="cL$sym_dots" is_uptodate='-> ../bar/baz/rsync' echo "cL$sym_dots foo/sym $is_uptodate" >"$chkfile.extra" fi # Check if rsync can preserve time on symlinks case "$RSYNC" in *protocol=2*) T=.T ;; *) if $RSYNC -VV | grep '"symtimes": true' >/dev/null; then T=.t else T=.T fi ;; esac checkdiff "$RSYNC -iplr '$fromdir/' '$todir/'" <f$all_plus bar/baz/rsync cd$all_plus foo/ >f$all_plus foo/config1 >f$all_plus foo/config2 >f$all_plus foo/extra cL$all_plus foo/sym -> ../bar/baz/rsync EOT # Ensure there are no accidental directory-time problems. $RSYNC -a -f '-! */' "$fromdir/" "$todir" cp_p "$srcdir/configure.ac" "$fromdir/foo/config2" chmod 601 "$fromdir/foo/config2" checkdiff "$RSYNC -iplrH '$fromdir/' '$todir/'" <f..T.$dots bar/baz/rsync >f..T.$dots foo/config1 >f.sTp$dots foo/config2 hf..T.$dots foo/extra => foo/config1 EOT $RSYNC -a -f '-! */' "$fromdir/" "$todir" cp_p "$srcdir/config.sub" "$fromdir/foo/config2" sleep 1 # For directory mod below to ensure time difference rm "$todir/foo/sym" umask 0 ln -s ../bar/baz "$todir/foo/sym" umask 022 chmod 600 "$fromdir/foo/config2" chmod 777 "$todir/bar/baz/rsync" checkdiff "$RSYNC -iplrtc '$fromdir/' '$todir/'" <fcstp$dots foo/config2 cLc$T.$dots foo/sym -> ../bar/baz/rsync EOT cp_p "$srcdir/configure.ac" "$fromdir/foo/config2" chmod 600 "$fromdir/foo/config2" # Lack of -t is for unchanged hard-link stress-test! checkdiff "$RSYNC -vvplrH '$fromdir/' '$todir/'" \ v_filt <f..t.$dots foo/config2 hf$allspace foo/extra .L$allspace foo/sym -> ../bar/baz/rsync EOT chmod 757 "$todir/foo/config1" touch "$todir/foo/config2" checkdiff "$RSYNC -vplrtH '$fromdir/' '$todir/'" \ v_filt <f..t.$dots foo/config2 EOT checkdiff "$RSYNC -ivvplrtH --copy-dest=../to '$fromdir/' '$to2dir/'" \ v_filt < foo/config1 cL$sym_dots foo/sym -> ../bar/baz/rsync EOT rm -rf "$to2dir" cat - "$chkfile.extra" <"$chkfile" created directory $to2dir hf$allspace foo/extra => foo/config1 EOT checkdiff2 "$RSYNC -iplrtH --copy-dest=../to '$fromdir/' '$to2dir/'" rm -rf "$to2dir" checkdiff "$RSYNC -vvplrtH --copy-dest='$todir' '$fromdir/' '$to2dir/'" \ v_filt < foo/config1 EOT rm -rf "$to2dir" checkdiff "$RSYNC -ivvplrtH --link-dest='$todir' '$fromdir/' '$to2dir/'" \ v_filt < foo/config1 $L$sym_dots foo/sym -> ../bar/baz/rsync EOT rm -rf "$to2dir" cat - "$chkfile.extra" <"$chkfile" created directory $to2dir EOT checkdiff2 "$RSYNC -iplrtH --dry-run --link-dest=../to '$fromdir/' '$to2dir/'" rm -rf "$to2dir" checkdiff2 "$RSYNC -iplrtH --link-dest=../to '$fromdir/' '$to2dir/'" rm -rf "$to2dir" checkdiff "$RSYNC -vvplrtH --link-dest='$todir' '$fromdir/' '$to2dir/'" \ v_filt < ../bar/baz/rsync EOT rm -rf "$to2dir" cat - "$chkfile.extra" <"$chkfile" created directory $to2dir EOT checkdiff2 "$RSYNC -iplrtH --compare-dest='$todir' '$fromdir/' '$to2dir/'" rm -rf "$to2dir" checkdiff "$RSYNC -vvplrtH --compare-dest='$todir' '$fromdir/' '$to2dir/'" \ v_filt < # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync's somewhat over-featured symlink control: the default # behaviour is that symlinks should not be copied at all. . "$suitedir/rsync.fns" build_symlinks || test_fail "failed to build symlinks" # Copy recursively, but without -l or -L or -a, and all the symlinks # should be missing. $RSYNC -r "$fromdir/" "$todir" || test_fail "$RSYNC returned $?" [ -f "$todir/referent" ] || test_fail "referent was not copied" [ -d "$todir/from" ] && test_fail "extra level of directories" if is_a_link "$todir/dangling"; then test_fail "dangling symlink was copied" fi if is_a_link "$todir/relative"; then test_fail "relative symlink was copied" fi if is_a_link "$todir/absolute"; then test_fail "absolute symlink was copied" fi # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/delete.test0000664000000000000000000000362314170671375015574 0ustar rootroot#!/bin/sh # Copyright (C) 2005-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of various delete directives. . "$suitedir/rsync.fns" hands_setup makepath "$chkdir" "$todir/extradir" "$todir/emptydir/subdir" echo extra >"$todir"/remove1 echo extra >"$todir"/remove2 echo extra >"$todir"/extradir/remove3 echo extra >"$todir"/emptydir/subdir/remove4 # Create two chk dirs, one with a copy of the source files, and one with # what we expect to be left behind by the copy using --remove-source-files. # Also, make sure that --dry-run --del doesn't output anything extraneous. $RSYNC -av "$fromdir/" "$chkdir/copy/" >"$tmpdir/copy.out" 2>&1 cat "$tmpdir/copy.out" grep -E -v '^(created directory|sent|total size) ' "$tmpdir/copy.out" >"$tmpdir/copy.new" mv "$tmpdir/copy.new" "$tmpdir/copy.out" $RSYNC -avn --del "$fromdir/" "$chkdir/copy2/" >"$tmpdir/copy2.out" 2>&1 || true cat "$tmpdir/copy2.out" grep -E -v '^(created directory|sent|total size) ' "$tmpdir/copy2.out" >"$tmpdir/copy2.new" mv "$tmpdir/copy2.new" "$tmpdir/copy2.out" diff $diffopt "$tmpdir/copy.out" "$tmpdir/copy2.out" $RSYNC -av -f 'exclude,! */' "$fromdir/" "$chkdir/empty/" checkit "$RSYNC -avv --del --remove-source-files '$fromdir/' '$todir/'" "$chkdir/copy" "$todir" diff -r "$chkdir/empty" "$fromdir" # Make sure that "P" but not "-" per-dir merge-file filters take effect with # --delete-excluded. cat >"$todir/filters" < # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of devices. This can only run if you're root. . "$suitedir/rsync.fns" # Build some hardlinks case $0 in *fake*) $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" RSYNC="$RSYNC --fake-super" TLS_ARGS="$TLS_ARGS --fake-super" case "$HOST_OS" in darwin*) mknod() { fn="$1" case "$2" in p) mode=10644 ;; c) mode=20644 ;; b) mode=60644 ;; esac maj="${3:-0}" min="${4:-0}" touch "$fn" xattr -s 'rsync.%stat' "$mode $maj,$min 0:0" "$fn" } ;; solaris*) mknod() { fn="$1" case "$2" in p) mode=10644 ;; c) mode=20644 ;; b) mode=60644 ;; esac maj="${3:-0}" min="${4:-0}" touch "$fn" runat "$fn" "$SHELL_PATH" < rsync.%stat EOF } ;; freebsd*) mknod() { fn="$1" case "$2" in p) mode=10644 ;; c) mode=20644 ;; b) mode=60644 ;; esac maj="${3:-0}" min="${4:-0}" touch "$fn" setextattr -h user "rsync.%stat" "$mode $maj,$min 0:0" "$fn" } ;; *) mknod() { fn="$1" case "$2" in p) mode=10644 ;; c) mode=20644 ;; b) mode=60644 ;; esac maj="${3:-0}" min="${4:-0}" touch "$fn" setfattr -n 'user.rsync.%stat' -v "$mode $maj,$min 0:0" "$fn" } ;; esac ;; *) my_uid=`get_testuid` root_uid=`get_rootuid` if test x"$my_uid" = x; then : # If "id" failed, try to continue... elif test x"$my_uid" != x"$root_uid"; then if [ -e "$FAKEROOT_PATH" ]; then echo "Let's try re-running the script under fakeroot..." exec "$FAKEROOT_PATH" "$SHELL_PATH" $RUNSHFLAGS "$0" fi test_skipped "Rsync needs root/fakeroot for device tests" fi ;; esac # TODO: Need to test whether hardlinks are possible on this OS/filesystem $RSYNC -VV | grep '"hardlink_specials": true' >/dev/null && CAN_HLINK_SPECIAL=yes || CAN_HLINK_SPECIAL=no mkdir "$fromdir" mkdir "$todir" mknod "$fromdir/char" c 41 67 || test_skipped "Can't create char device node" mknod "$fromdir/char2" c 42 68 || test_skipped "Can't create char device node" mknod "$fromdir/char3" c 42 69 || test_skipped "Can't create char device node" mknod "$fromdir/block" b 42 69 || test_skipped "Can't create block device node" mknod "$fromdir/block2" b 42 73 || test_skipped "Can't create block device node" mknod "$fromdir/block3" b 105 73 || test_skipped "Can't create block device node" if test "$CAN_HLINK_SPECIAL" = yes; then ln "$fromdir/block3" "$fromdir/block3.5" else echo "Skipping hard-linked device test..." fi mkfifo "$fromdir/fifo" || mknod "$fromdir/fifo" p || test_skipped "Can't run mkfifo" # Work around time rounding/truncating issue by touching both files. touch -r "$fromdir/block" "$fromdir/block" "$fromdir/block2" checkdiff "$RSYNC -ai '$fromdir/block' '$todir/block2'" <"$chkfile" < block3 cD$all_plus char cD$all_plus char2 cD$all_plus char3 cS$all_plus fifo EOT if test "$CAN_HLINK_SPECIAL" = no; then grep -v block3.5 <"$chkfile" >"$chkfile.new" mv "$chkfile.new" "$chkfile" fi checkdiff2 "$RSYNC -aiHvv '$fromdir/' '$todir/'" v_filt echo "check how the directory listings compare with diff:" echo "" ( cd "$fromdir" && rsync_ls_lR . ) > "$tmpdir/ls-from" ( cd "$todir" && rsync_ls_lR . ) > "$tmpdir/ls-to" diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" if test "$CAN_HLINK_SPECIAL" = yes; then set -x checkdiff "$RSYNC -aii --link-dest='$todir' '$fromdir/' '$chkdir/'" < # General-purpose test functions for rsync. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version # 2 as published by the Free Software Foundation. # # 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. tmpdir="$scratchdir" fromdir="$tmpdir/from" todir="$tmpdir/to" chkdir="$tmpdir/chk" chkfile="$scratchdir/rsync.chk" outfile="$scratchdir/rsync.out" # For itemized output: all_plus='+++++++++' allspace=' ' dots='.....' # trailing dots after changes tab_ch=' ' # a single tab character # Berkley's nice. PATH="$PATH:/usr/ucb" if diff -u "$suitedir/rsync.fns" "$suitedir/rsync.fns" >/dev/null 2>&1; then diffopt="-u" else diffopt="-c" fi HOME="$scratchdir" export HOME runtest() { echo $ECHO_N "Test $1: $ECHO_C" if eval "$2"; then echo "$ECHO_T done." return 0 else echo "$ECHO_T failed!" return 1 fi } set_cp_destdir() { while test $# -gt 1; do shift done destdir="$1" } # Perform a "cp -p", making sure that timestamps are really the same, # even if the copy rounded microsecond times on the destination file. cp_touch() { cp_p "${@}" if test $# -gt 2 || test -d "$2"; then set_cp_destdir "${@}" # sets destdir var while test $# -gt 1; do destname="$destdir/`basename $1`" touch -r "$destname" "$1" "$destname" shift done else touch -r "$2" "$1" "$2" fi } # Call this if you want to filter (stdin -> stdout) verbose messages (-v or # -vv) from an rsync run (whittling the output down to just the file messages). # This isn't needed if you use -i without -v. v_filt() { sed -e '/^building file list /d' \ -e '/^sending incremental file list/d' \ -e '/^created directory /d' \ -e '/^done$/d' \ -e '/ --whole-file$/d' \ -e '/^total: /d' \ -e '/^client charset: /d' \ -e '/^server charset: /d' \ -e '/^$/,$d' } printmsg() { echo "$1" } rsync_ls_lR() { find "$@" -name .git -prune -o -name auto-build-save -prune -o -print | \ sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS } get_testuid() { uid=`id -u 2>/dev/null || true` case "$uid" in [0-9]*) echo "$uid" ;; *) id 2>/dev/null | sed 's/^[^0-9]*\([0-9][0-9]*\).*/\1/' ;; esac } get_rootuid() { uid=`id -u root 2>/dev/null || true` case "$uid" in [0-9]*) echo "$uid" ;; *) echo 0 ;; esac } get_rootgid() { gid=`id -g root 2>/dev/null || true` case "$gid" in [0-9]*) echo "$gid" ;; *) echo 0 ;; esac } # When copying via "cp -p", we want to ensure that a non-root user does not # preserve ownership (we want our files to be created as the testing user). # For instance, a Cygwin CI run might have git files owned by a different # user than the (admin) user running the tests. cp_cmd="cp -p" if test x`get_testuid` != x0; then case `cp --help 2>/dev/null` in *--no-preserve=*) cp_cmd="cp -p --no-preserve=ownership" ;; esac fi cp_p() { $cp_cmd "${@}" || test_fail "$cp_cmd failed" } check_perms() { perms=`"$TOOLDIR/tls" "$1" | sed 's/^[-d]\(.........\).*/\1/'` if test $perms = $2; then return 0 fi echo "permissions: $perms on $1" echo "should be: $2" test_fail "failed test $3" } rsync_getgroups() { "$TOOLDIR/getgroups" } #################### # Build test directories $todir and $fromdir, with $fromdir full of files. hands_setup() { # Clean before creation rm -rf "$fromdir" rm -rf "$todir" [ -d "$tmpdir" ] || mkdir "$tmpdir" [ -d "$fromdir" ] || mkdir "$fromdir" [ -d "$todir" ] || mkdir "$todir" # On some BSD systems, the umask affects the mode of created # symlinks, even though the mode apparently has no effect on how # the links behave in the future, and it cannot be changed using # chmod! rsync always sets its umask to 000 so that it can # accurately recreate permissions, but this script is probably run # with a different umask. # This causes a little problem that "ls -l" of the two will not be # the same. So, we need to set our umask before doing any creations. # set up test data touch "$fromdir/empty" mkdir "$fromdir/emptydir" # a hundred lines of text or so rsync_ls_lR "$srcdir" > "$fromdir/filelist" echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf" umask 0 ln -s nolf "$fromdir/nolf-symlink" umask 022 cat "$srcdir"/*.c > "$fromdir/text" mkdir "$fromdir/dir" cp "$fromdir/text" "$fromdir/dir" mkdir "$fromdir/dir/subdir" echo some data > "$fromdir/dir/subdir/foobar.baz" mkdir "$fromdir/dir/subdir/subsubdir" if [ -r /etc ]; then ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" else ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" fi mkdir "$fromdir/dir/subdir/subsubdir2" if [ -r /bin ]; then ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" else ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" fi # echo testing head: # ls -lR "$srcdir" | head -10 || echo failed } #################### # Many machines do not have "mkdir -p", so we have to build up long paths. # How boring. makepath() { for p in "${@}"; do (echo " makepath $p" # Absolute Unix path. if echo $p | grep '^/' >/dev/null; then cd / fi # This will break if $p contains a space. for c in `echo $p | tr '/' ' '`; do if [ -d "$c" ] || mkdir "$c"; then cd "$c" || return $? else echo "failed to create $c" >&2; return $? fi done) done } ########################### # Run a test (in '$1') then compare directories $2 and $3 to see if # there are any difference. If there are, explain them. # So normally basically $1 should be an rsync command, and $2 and $3 # the source and destination directories. This is only good when you # expect to transfer the whole directory exactly as is. If some files # should be excluded, you might need to use something else. checkit() { failed= # We can just write everything to stdout/stderr, because the # wrapper hides it unless there is a problem. case "x$TLS_ARGS" in *--atimes*) ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" ;; *) ;; esac echo "Running: \"$1\"" eval "$1" status=$? if [ $status != 0 ]; then failed="$failed status=$status" fi case "x$TLS_ARGS" in *--atimes*) ;; *) ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" ;; esac echo "-------------" echo "check how the directory listings compare with diff:" echo "" ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to" diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff" echo "-------------" echo "check how the files compare with diff:" echo "" if [ "x$4" != x ]; then echo " === Skipping (as directed) ===" else diff -r $diffopt "$2" "$3" || failed="$failed file-diff" fi echo "-------------" if [ -z "$failed" ]; then return 0 fi echo "Failed: $failed" return 1 } # Run a test in $1 and make sure it has a zero exit status. Capture the # output into $outfile and echo it to stdout. checktee() { echo "Running: \"$1\"" eval "$1" >"$outfile" status=$? cat "$outfile" if [ $status != 0 ]; then echo "Failed: status=$status" return 1 fi return 0 } # Slurp stdin into $chkfile and then call checkdiff2(). checkdiff() { cat >"$chkfile" # Save off stdin checkdiff2 "${@}" } # Run a test in $1 and make sure it has a zero exit status. Capture the output # into $outfile. If $2 is set, use it to filter the outfile. If resulting # outfile differs from the chkfile data, fail with an error. checkdiff2() { failed= echo "Running: \"$1\"" eval "$1" >"$outfile" status=$? cat "$outfile" if [ $status != 0 ]; then failed="$failed status=$status" fi if [ -n "$2" ]; then eval "cat '$outfile' | $2 >'$outfile.new'" mv "$outfile.new" "$outfile" fi diff $diffopt "$chkfile" "$outfile" || failed="$failed output differs" if [ -n "$failed" ]; then echo "Failed:$failed" return 1 fi return 0 } build_rsyncd_conf() { # Build an appropriate configuration file conf="$scratchdir/test-rsyncd.conf" echo "building configuration $conf" port=2612 pidfile="$scratchdir/rsyncd.pid" logfile="$scratchdir/rsyncd.log" hostname=`uname -n` my_uid=`get_testuid` root_uid=`get_rootuid` root_gid=`get_rootgid` uid_setting="uid = $root_uid" gid_setting="gid = $root_gid" if test x"$my_uid" != x"$root_uid"; then # Non-root cannot specify uid & gid settings uid_setting="#$uid_setting" gid_setting="#$gid_setting" fi cat >"$conf" <"$ignore23" <<'EOT' if "${@}"; then exit fi ret=$? if test $ret = 23; then exit fi exit $ret EOT chmod +x "$ignore23" } build_symlinks() { mkdir "$fromdir" date >"$fromdir/referent" ln -s referent "$fromdir/relative" ln -s "$fromdir/referent" "$fromdir/absolute" ln -s nonexistent "$fromdir/dangling" ln -s "$srcdir/rsync.c" "$fromdir/unsafe" } test_fail() { echo "$@" >&2 exit 1 } test_skipped() { echo "$@" >&2 echo "$@" > "$tmpdir/whyskipped" exit 77 } # It failed, but we expected that. Don't dump out error logs, # because most users won't want to see them. But do leave # the working directory around. test_xfail() { echo "$@" >&2 exit 78 } # Determine what shell command will appropriately test for links. ln -s foo "$scratchdir/testlink" for cmd in test /bin/test /usr/bin/test /usr/ucb/bin/test /usr/ucb/test; do for switch in -h -L; do if $cmd $switch "$scratchdir/testlink" 2>/dev/null; then # how nice TEST_SYMLINK_CMD="$cmd $switch" # i wonder if break 2 is portable? break 2 fi done done # ok, now get rid of it rm "$scratchdir/testlink" if [ "x$TEST_SYMLINK_CMD" = 'x' ]; then test_fail "Couldn't determine how to test for symlinks" else echo "Testing for symlinks using '$TEST_SYMLINK_CMD'" fi # Test whether something is a link, allowing for shell peculiarities is_a_link() { # note the variable contains the first option and therefore is not quoted $TEST_SYMLINK_CMD "$1" } # We need to set the umask to be reproducible. Note also that when we # do some daemon tests as root, we will setuid() and therefore the # directory has to be writable by the nobody user in some cases. The # best thing is probably to explicitly chmod those directories after # creation. umask 022 rsync-3.2.7/testsuite/daemon-gzip-upload.test0000664000000000000000000000163212324545773020025 0ustar rootroot#!/bin/sh # Copyright (C) 2001, 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING) # We don't really want to start the server listening, because that # might interfere with the security or operation of the test machine. # Instead we use the fake-connect feature to dynamically assign a pair # of ports. # This test tries to upload a file over a compressed connection to the # server. This ought to exercise (exorcise?) a bug in 2.5.3. . "$suitedir/rsync.fns" build_rsyncd_conf RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG hands_setup # Build chkdir with a normal rsync and an --exclude. $RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" checkit "'$ignore23' $RSYNC -avvvvzz '$fromdir/' localhost::test-to/" "$chkdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/files-from.test0000664000000000000000000000227013671117460016365 0ustar rootroot#!/bin/sh # Copyright (C) 2008-2020 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that --files-from=FILE works right. . "$suitedir/rsync.fns" SSH="$scratchdir/src/support/lsh.sh" hands_setup # This list of files skips the contents of "subsubdir" but includes # the contents of "subsubdir2" due to its trailing slash. cat >"$scratchdir/filelist" < # 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 2 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, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # This test tries to download a tree over a compressed connection from # the server. This ought to exercise (exorcise?) a bug in 2.5.3. . "$suitedir/rsync.fns" build_rsyncd_conf RSYNC_CONNECT_PROG="$RSYNC --config=$conf --daemon" export RSYNC_CONNECT_PROG hands_setup # Build chkdir with a normal rsync and an --exclude. $RSYNC -av --exclude=foobar.baz "$fromdir/" "$chkdir/" checkit "$RSYNC -avvvvzz localhost::test-from/ '$todir/'" "$chkdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/acls-default.test0000664000000000000000000000430714324271266016672 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that rsync obeys default ACLs. -- Matt McCutchen . $suitedir/rsync.fns $RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support" case "$setfacl_nodef" in true) test_skipped "I don't know how to use your setfacl command" ;; *-k*) opts='-dm u::7,g::5,o:5' ;; *) opts='-m d:u::7,d:g::5,d:o:5' ;; esac setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled" # Call as: testit testit() { todir="$scratchdir/$1" mkdir "$todir" $setfacl_nodef "$todir" if [ -n "$2" ]; then case "$setfacl_nodef" in *-k*) opts="-dm $2" ;; *) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`" esac setfacl $opts "$todir" fi # Make sure we obey ACLs when creating a directory to hold multiple transferred files, # even though the directory itself is outside the transfer $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/" check_perms "$todir/to" $4 "Target $1" check_perms "$todir/to/dir" $4 "Target $1" check_perms "$todir/to/file" $3 "Target $1" check_perms "$todir/to/program" $4 "Target $1" # Make sure get_local_name doesn't mess us up when transferring only one file $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile" check_perms "$todir/to/anotherfile" $3 "Target $1" # Make sure we obey default ACLs when not transferring a regular file $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/" check_perms "$todir/to/anotherdir" $4 "Target $1" } mkdir "$scratchdir/dir" echo "File!" >"$scratchdir/file" echo "#!/bin/sh" >"$scratchdir/program" chmod 777 "$scratchdir/dir" chmod 666 "$scratchdir/file" chmod 777 "$scratchdir/program" # Test some target directories umask 0077 testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x testit da750 u::7,g::5,o:0 rw-r----- rwxr-x--- testit da750mask u::7,u:0:7,g::7,m:5,o:0 rw-r----- rwxr-x--- testit noda1 '' rw------- rwx------ umask 0000 testit noda2 '' rw-rw-rw- rwxrwxrwx umask 0022 testit noda3 '' rw-r--r-- rwxr-xr-x # Hooray exit 0 rsync-3.2.7/testsuite/relative.test0000664000000000000000000000350113732206751016133 0ustar rootroot#!/bin/sh # Copyright (C) 2005-2020 Wayne Davison # # This program is distributable under the terms of the GNU GPL (see COPYING) . "$suitedir/rsync.fns" deepstr='down/3/deep' deepdir="$fromdir/$deepstr" extradir="$fromdir/extra" makepath "$deepdir" "$extradir/$deepstr" "$chkdir" fromdir="$deepdir" hands_setup fromdir="$tmpdir/from" extrafile="$extradir/./$deepstr/extra.added.value" echo wowza >"$extrafile" $RSYNC -av --existing --include='*/' --exclude='*' "$fromdir/" "$extradir/" cd "$fromdir" # Main script starts here $RSYNC -ai --include=/down/ --exclude='/*' "$fromdir/" "$chkdir/" sleep 1 runtest "basic relative" 'checkit "$RSYNC -avR ./$deepstr \"$todir\"" "$chkdir" "$todir"' ln $deepstr/filelist $deepstr/dir ln ../chk/$deepstr/filelist ../chk/$deepstr/dir # Work around time rounding/truncating issue by touching both dirs. touch -r $deepstr/dir $deepstr/dir ../chk/$deepstr/dir runtest "hard links" 'checkit "$RSYNC -avHR ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' cp "$deepdir/text" "$todir/$deepstr/ThisShouldGo" cp "$deepdir/text" "$todir/$deepstr/dir/ThisShouldGoToo" runtest "deletion" 'checkit "$RSYNC -avHR --del ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' runtest "non-deletion" 'checkit "$RSYNC -aiHR --del ./$deepstr/ \"$todir\"" "$chkdir" "$todir"' \ | tee "$outfile" # Make sure no files were deleted grep 'deleting ' "$outfile" && test_fail "Erroneous deletions occurred!" # Relative with merging. $RSYNC -ai "$extradir/down" "$chkdir/" checkit "$RSYNC -aiR $deepstr '$extrafile' '$todir'" "$chkdir" "$todir" checkit "$RSYNC -aiR --del $deepstr '$extrafile' '$todir'" "$chkdir" "$todir" \ | tee "$outfile" # Make sure no files were deleted grep 'deleting ' "$outfile" && test_fail "Erroneous deletions occurred! (2)" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/00-hello.test0000664000000000000000000000247114172327441015644 0ustar rootroot#!/bin/sh # Test some foundational things. . "$suitedir/rsync.fns" RSYNC_RSH="$scratchdir/src/support/lsh.sh" export RSYNC_RSH echo $0 running $RSYNC --version || test_fail '--version output failed' $RSYNC --info=help || test_fail '--info=help output failed' $RSYNC --debug=help || test_fail '--debug=help output failed' weird_name="A weird)name" mkdir "$fromdir" mkdir "$fromdir/$weird_name" append_line() { echo "$1" echo "$1" >>"$fromdir/$weird_name/file" } append_line test1 checkit "$RSYNC -ai '$fromdir/' '$todir/'" "$fromdir" "$todir" copy_weird() { checkit "$RSYNC $1 --rsync-path='$RSYNC' '$2$fromdir/$weird_name/' '$3$todir/$weird_name'" "$fromdir" "$todir" } append_line test2 copy_weird '-ai' 'lh:' '' append_line test3 copy_weird '-ai' '' 'lh:' append_line test4 copy_weird '-ais' 'lh:' '' append_line test5 copy_weird '-ais' '' 'lh:' echo test6 touch "$fromdir/one" "$fromdir/two" (cd "$fromdir" && $RSYNC -ai --old-args --rsync-path="$RSYNC" lh:'one two' "$todir/") if [ ! -f "$todir/one" ] || [ ! -f "$todir/two" ]; then test_fail "old-args copy of 'one two' failed" fi echo test7 rm "$todir/one" "$todir/two" (cd "$fromdir" && RSYNC_OLD_ARGS=1 $RSYNC -ai --rsync-path="$RSYNC" lh:'one two' "$todir/") # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/mkpath.test0000664000000000000000000000271214124204403015573 0ustar rootroot#!/bin/sh . "$suitedir/rsync.fns" makepath "$fromdir" makepath "$todir" cp_p "$srcdir/rsync.h" "$fromdir/text" cp_p "$srcdir/configure.ac" "$fromdir/extra" cd "$tmpdir" deep_dir=to/foo/bar/baz/down/deep # Check that we can create several levels of dest dir $RSYNC -aiv --mkpath from/text $deep_dir/new test -f $deep_dir/new || test_fail "'new' file not found in $deep_dir dir" rm -rf to/foo $RSYNC -aiv --mkpath from/text $deep_dir/ test -f $deep_dir/text || test_fail "'text' file not found in $deep_dir dir" rm $deep_dir/text # Make sure we can handle an existing path mkdir $deep_dir/new $RSYNC -aiv --mkpath from/text $deep_dir/new test -f $deep_dir/new/text || test_fail "'text' file not found in $deep_dir/new dir" # ... and an existing path when an alternate dest filename is specified $RSYNC -aiv --mkpath from/text $deep_dir/new/text2 test -f $deep_dir/new/text2 || test_fail "'text2' file not found in $deep_dir/new dir" rm -rf to/foo # Try the tests again with multiple source args $RSYNC -aiv --mkpath from/ $deep_dir test -f $deep_dir/extra || test_fail "'extra' file not found in $deep_dir dir" rm -rf to/foo $RSYNC -aiv --mkpath from/ $deep_dir/ test -f $deep_dir/text || test_fail "'text' file not found in $deep_dir dir" # Make sure that we can handle no path $RSYNC -aiv --mkpath from/text to_text test -f to_text || test_fail "'to_text' file not found in current dir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/chmod.test0000664000000000000000000000170114170671375015417 0ustar rootroot#!/bin/sh # Copyright (C) 2004-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that various read-only and set[ug]id permissions work properly, # even when using a --temp-dir option (which we try to point at a # different filesystem than the destination dir). . "$suitedir/rsync.fns" hands_setup chmod 440 "$fromdir/text" chmod 500 "$fromdir/dir/text" e="$fromdir/dir/subdir/foobar.baz" chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e" e="$fromdir/dir/subdir/subsubdir/etc-ltr-list" chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e" # First a normal copy. runtest "normal copy" 'checkit "$RSYNC -avv \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' # Then we update all the files. runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/hardlinks.test0000664000000000000000000000560614124204403016273 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of hardlinks. By default, rsync does not detect # hard links and they get sent as separate files. If you specify -H, # then hard links are detected and linked together on the receiver. . "$suitedir/rsync.fns" SSH="$scratchdir/src/support/lsh.sh" # Build some hardlinks fromdir="$scratchdir/from" todir="$scratchdir/to" # TODO: Need to test whether hardlinks are possible on this OS/filesystem mkdir "$fromdir" name1="$fromdir/name1" name2="$fromdir/name2" name3="$fromdir/name3" name4="$fromdir/name4" echo "This is the file" > "$name1" ln "$name1" "$name2" || test_skipped "Can't create hardlink" ln "$name2" "$name3" || test_fail "Can't create hardlink" cp "$name2" "$name4" || test_fail "Can't copy file" cat $srcdir/*.c >"$fromdir/text" checkit "$RSYNC -aHivv --debug=HLINK5 '$fromdir/' '$todir/'" "$fromdir" "$todir" echo "extra extra" >>"$todir/name1" checkit "$RSYNC -aHivv --debug=HLINK5 --no-whole-file '$fromdir/' '$todir/'" "$fromdir" "$todir" # Add a new link in a new subdirectory to test that we don't try to link # the files before the directory gets created. We also create a bunch of # extra files to ensure that an incremental-recursion transfer works across # distant files. makepath "$fromdir/subdir/down/deep" files='' for x in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do for y in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9; do files="$files $x$y" done done (cd "$fromdir/subdir"; touch $files) ln "$name1" "$fromdir/subdir/down/deep/new-file" rm "$todir/text" checkit "$RSYNC -aHivve '$SSH' --debug=HLINK5 --rsync-path='$RSYNC' '$fromdir/' localhost:'$todir/'" "$fromdir" "$todir" # Do some duplicate copies using --link-dest and --copy-dest to test that # we hard-link all locally-inherited items. checkit "$RSYNC -aHivv --debug=HLINK5 --link-dest='$todir' '$fromdir/' '$chkdir/'" "$todir" "$chkdir" rm -rf "$chkdir" checkit "$RSYNC -aHivv --debug=HLINK5 --copy-dest='$todir' '$fromdir/' '$chkdir/'" "$fromdir" "$chkdir" # Create a hard link that has only one part in the hierarchy. echo "This is another file" >"$fromdir/solo" ln "$fromdir/solo" "$chkdir/solo" || test_fail "Can't create hardlink" # Make sure that the checksum data doesn't slide due to an HLINK_BUMP() change. checktee "$RSYNC -aHivc --debug=HLINK5 '$fromdir/' '$chkdir/'" grep solo "$outfile" && test_fail "Erroneous copy of solo file occurred!" # Make sure there's nothing wrong with sending a single file with -H # enabled (this has broken twice so far, so we need this test). rm -rf "$todir" $RSYNC -aHivv --debug=HLINK5 "$name1" "$todir/" diff $diffopt "$name1" "$todir" || test_fail "solo copy of name1 failed" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/longdir.test0000664000000000000000000000155510667071016015763 0ustar rootroot#!/bin/sh # Copyright (C) 1998,1999 Philip Hands # Copyright (C) 2001 by Martin Pool # # This program is distributable under the terms of the GNU GPL (see COPYING) . "$suitedir/rsync.fns" hands_setup longname=This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job longdir="$fromdir/$longname/$longname/$longname" makepath "$longdir" || test_skipped "unable to create long directory" touch "$longdir/1" || test_skipped "unable to create files in long directory" date > "$longdir/1" if [ -r /etc ]; then ls -la /etc >"$longdir/2" else ls -la / >"$longdir/2" fi checkit "$RSYNC --delete -avH '$fromdir/' '$todir'" "$fromdir/" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/chgrp.test0000664000000000000000000000127314124204403015413 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that rsync with -gr will preserve groups when the user running # the test is a member of them. Hopefully they're in at least one # test. . "$suitedir/rsync.fns" # Build some hardlinks mygrps="`rsync_getgroups`" || test_fail "Can't get groups" mkdir "$fromdir" for g in $mygrps; do name="$fromdir/foo-$g" date > "$name" chgrp "$g" "$name" || test_fail "Can't chgrp" done sleep 2 checkit "$RSYNC -rtgpvvv '$fromdir/' '$todir/'" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/fuzzy.test0000664000000000000000000000103614170671375015515 0ustar rootroot#!/bin/sh # Copyright (C) 2005-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of the --fuzzy option. . "$suitedir/rsync.fns" mkdir "$fromdir" mkdir "$todir" cp_p "$srcdir"/rsync.c "$fromdir"/rsync.c cp_touch "$fromdir"/rsync.c "$todir"/rsync2.c sleep 1 # Let's do it! checkit "$RSYNC -avvi --no-whole-file --fuzzy --delete-delay \ '$fromdir/' '$todir/'" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/crtimes.test0000664000000000000000000000125614324271266015774 0ustar rootroot#!/bin/sh # Test rsync copying create times . "$suitedir/rsync.fns" $RSYNC -VV | grep '"crtimes": true' >/dev/null || test_skipped "Rsync is configured without crtimes support" # Setting an older time via touch sets the create time to the mtime. # Setting it to a newer time affects just the mtime. mkdir "$fromdir" echo hiho >"$fromdir/foo" touch -t 200101011111.11 "$fromdir" touch -t 200202022222.22 "$fromdir" touch -t 200111111111.11 "$fromdir/foo" touch -t 200212122222.22 "$fromdir/foo" TLS_ARGS=--crtimes checkit "$RSYNC -rtgvvv --crtimes \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/chown.test0000664000000000000000000000365314324271266015447 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that when rsync is running as root and has -a it correctly sets # the ownership of the destination. # We don't know what users will be present on this system, so we just # use random numeric uids and gids. . "$suitedir/rsync.fns" case $0 in *fake*) $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync needs xattrs for fake device tests" RSYNC="$RSYNC --fake-super" TLS_ARGS="$TLS_ARGS --fake-super" case "$HOST_OS" in darwin*) chown() { own=$1 shift xattr -s 'rsync.%stat' "100644 0,0 $own" "${@}" } ;; solaris*) chown() { own=$1 shift for fn in "${@}"; do runat "$fn" "$SHELL_PATH" < rsync.%stat EOF done } ;; freebsd*) chown() { own=$1 shift setextattr -h user "rsync.%stat" "100644 0,0 $own" "${@}" } ;; *) chown() { own=$1 shift setfattr -n 'user.rsync.%stat' -v "100644 0,0 $own" "${@}" } ;; esac ;; *) RSYNC="$RSYNC --super" my_uid=`get_testuid` root_uid=`get_rootuid` if test x"$my_uid" = x; then : # If "id" failed, try to continue... elif test x"$my_uid" != x"$root_uid"; then if [ -e "$FAKEROOT_PATH" ]; then echo "Let's try re-running the script under fakeroot..." exec "$FAKEROOT_PATH" "$SHELL_PATH" "$0" fi fi ;; esac # Build some hardlinks mkdir "$fromdir" name1="$fromdir/name1" name2="$fromdir/name2" echo "This is the file" > "$name1" echo "This is the other file" > "$name2" chown 5000:5002 "$name1" || test_skipped "Can't chown (probably need root)" chown 5001:5003 "$name2" || test_skipped "Can't chown (probably need root)" cd "$fromdir/.." checkit "$RSYNC -aHvv from/ to/" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/unsafe-byname.test0000664000000000000000000000345314124204403017044 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # Call directly into unsafe_symlink and test its handling of various filenames . "$suitedir/rsync.fns" test_unsafe() { # $1 is the target of a symlink # $2 is the directory we're copying # $3 is the expected outcome: "safe" if the link lies within $2, # or "unsafe" otherwise result=`"$TOOLDIR/t_unsafe" "$1" "$2"` || test_fail "Failed to check $1 $2" if [ "$result" != "$3" ]; then test_fail "t_unsafe $1 $2 returned \"$result\", expected \"$3\"" fi } test_unsafe file from safe test_unsafe dir/file from safe test_unsafe dir/./file from safe test_unsafe dir/. from safe test_unsafe dir/ from safe test_unsafe /etc/passwd from unsafe test_unsafe //../etc/passwd from unsafe test_unsafe //./etc/passwd from unsafe test_unsafe ./foo from safe test_unsafe ../foo from unsafe test_unsafe ./../foo from unsafe test_unsafe .//../foo from unsafe test_unsafe ./../foo from/.. unsafe test_unsafe ../dest from/dir safe test_unsafe ../../dest from//dir unsafe test_unsafe ..//../dest from/dir unsafe test_unsafe .. from/file safe test_unsafe ../.. from/file unsafe test_unsafe ..//.. from//file unsafe test_unsafe dir/.. from safe test_unsafe dir/../.. from unsafe test_unsafe dir/..//.. from unsafe test_unsafe '' from unsafe # Based on tests from unsafe-links by Vladimír Michl test_unsafe ../../unsafe/unsafefile from/safe unsafe test_unsafe ..//../unsafe/unsafefile from/safe unsafe test_unsafe ../files/file1 from/safe safe test_unsafe ../../unsafe/unsafefile safe unsafe test_unsafe ../files/file1 safe unsafe test_unsafe ../../unsafe/unsafefile `pwd`/from/safe safe test_unsafe ../files/file1 `pwd`/from/safe safe rsync-3.2.7/testsuite/executability.test0000664000000000000000000000164714124204403017170 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test the --executability or -E option. -- Matt McCutchen . $suitedir/rsync.fns # Put some files in the From directory mkdir "$fromdir" cat <"$fromdir/1" #!/bin/sh echo 'Program One!' EOF cat <"$fromdir/2" #!/bin/sh echo 'Program Two!' EOF chmod 1700 "$fromdir/1" || test_skipped "Can't chmod" chmod 600 "$fromdir/2" $RSYNC -rvv "$fromdir/" "$todir/" check_perms "$todir/1" rwx------ 1 check_perms "$todir/2" rw------- 1 # Mix up the permissions a bit chmod 600 "$fromdir/1" chmod 601 "$fromdir/2" chmod 604 "$todir/2" $RSYNC -rvv "$fromdir/" "$todir/" # No -E, so nothing should have changed check_perms "$todir/1" rwx------ 2 check_perms "$todir/2" rw----r-- 2 $RSYNC -rvvE "$fromdir/" "$todir/" # Now things should have happened! check_perms "$todir/1" rw------- 3 check_perms "$todir/2" rwx---r-x 3 # Hooray exit 0 rsync-3.2.7/testsuite/dir-sgid.test0000664000000000000000000000313514124204403016011 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that rsync obeys directory setgid. -- Matt McCutchen . $suitedir/rsync.fns umask 077 # Call as: testit testit() { todir="$scratchdir/$1" mkdir "$todir" chmod $2 "$todir" # Make sure we obey directory setgid when creating a directory to hold multiple transferred files, # even though the directory itself is outside the transfer $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/" check_perms "$todir/to" $5 "Target $1" check_perms "$todir/to/dir" $5 "Target $1" check_perms "$todir/to/file" $3 "Target $1" check_perms "$todir/to/program" $4 "Target $1" } mkdir "$scratchdir/dir" # Cygwin has a persistent default dir ACL that ruins this test. case `getfacl "$scratchdir/dir" 2>/dev/null || true` in *default:user::*) test_skipped "The default ACL mode interferes with this test" ;; esac echo "File!" >"$scratchdir/file" echo "#!/bin/sh" >"$scratchdir/program" chmod u=rwx,g=rw,g+s,o=r "$scratchdir/dir" || test_skipped "Can't chmod" chmod 664 "$scratchdir/file" chmod 775 "$scratchdir/program" [ -g "$scratchdir/dir" ] || test_skipped "The directory setgid bit vanished!" mkdir "$scratchdir/dir/blah" [ -g "$scratchdir/dir/blah" ] || test_skipped "Your filesystem doesn't use directory setgid; maybe it's BSD." # Test some target directories testit setgid-off 700 rw------- rwx------ rwx------ testit setgid-on u=rwx,g=rw,g+s,o-rwx rw------- rwx------ rwx--S--- # Hooray exit 0 rsync-3.2.7/testsuite/missing.test0000664000000000000000000000211714124204403015757 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test three bugs fixed by my redoing of the missing_below logic. . $suitedir/rsync.fns makepath "$fromdir/subdir" "$todir" echo data >"$fromdir/subdir/file" echo data >"$todir/other" # Test 1: Too much "not creating new..." output on a dry run $RSYNC -n -r --ignore-non-existing -vv "$fromdir/" "$todir/" | tee "$scratchdir/out" if grep 'not creating new.*subdir/file' "$scratchdir/out" >/dev/null; then test_fail 'test 1 failed' fi case "$RSYNC" in *protocol=29*) # FIXME can we get past the new flist sanity check in protocol 29? echo "Skipped test 2 for protocol 29." ;; *) # Test 2: Attempt to make a fuzzy dirlist for a dir not created on a dry run $RSYNC -n -r -R --no-implied-dirs -y "$fromdir/./subdir/file" "$todir/" \ || test_fail 'test 2 failed' ;; esac # Test 3: --delete-after pass skipped when last dir is dry-missing $RSYNC -n -r --delete-after -i "$fromdir/" "$todir/" | tee "$scratchdir/out" grep '^\*deleting * other' "$scratchdir/out" >/dev/null \ || test_fail 'test 3 failed' rsync-3.2.7/testsuite/chmod-temp-dir.test0000664000000000000000000000253314170671375017142 0ustar rootroot#!/bin/sh # Copyright (C) 2004-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that various read-only and set[ug]id permissions work properly, # even when using a --temp-dir option (which we try to point at a # different filesystem than the destination dir). . "$suitedir/rsync.fns" hands_setup sdev=`$TOOLDIR/getfsdev $scratchdir` tdev=$sdev for tmpdir2 in "${RSYNC_TEST_TMP:-/override-tmp-not-specified}" /run/shm /var/tmp /tmp; do [ -d "$tmpdir2" ] && [ -w "$tmpdir2" ] || continue tdev=`$TOOLDIR/getfsdev "$tmpdir2"` [ x$sdev != x$tdev ] && break done [ x$sdev = x$tdev ] && test_skipped "Can't find a tmp dir on a different file system" chmod 440 "$fromdir/text" chmod 500 "$fromdir/dir/text" e="$fromdir/dir/subdir/foobar.baz" chmod 6450 "$e" || chmod 2450 "$e" || chmod 1450 "$e" || chmod 450 "$e" e="$fromdir/dir/subdir/subsubdir/etc-ltr-list" chmod 2670 "$e" || chmod 1670 "$e" || chmod 670 "$e" # First a normal copy. runtest "normal copy" 'checkit "$RSYNC -avv --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' # Then we update all the files. runtest "update copy" 'checkit "$RSYNC -avvI --no-whole-file --temp-dir=\"$tmpdir2\" \"$fromdir/\" \"$todir\"" "$fromdir" "$todir"' # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/protected-regular.test0000664000000000000000000000220114133100330017722 0ustar rootroot#!/bin/sh # Copyright (C) 2021 by Achim Leitner # This program is distributable under the terms of the GNU GPL (see COPYING) # # Modern linux systems have the protected_regular feature set to 1 or 2 # See https://www.kernel.org/doc/Documentation/sysctl/fs.txt # Make sure we can still write these files in --inplace mode . "$suitedir/rsync.fns" test -f /proc/sys/fs/protected_regular || test_skipped "Can't find protected_regular setting (only available on Linux)" pr_lvl=`cat /proc/sys/fs/protected_regular 2>/dev/null` || test_skipped "Can't check if fs.protected_regular is enabled (probably need root)" test "$pr_lvl" != 0 || test_skipped "fs.protected_regular is not enabled" workdir="$tmpdir/files" mkdir "$workdir" chmod 1777 "$workdir" echo "Source" > "$workdir/src" echo "" > "$workdir/dst" chown 5001 "$workdir/dst" || test_skipped "Can't chown (probably need root)" # Output is only shown in case of an error echo "Contents of $workdir:" ls -al "$workdir" $RSYNC --inplace "$workdir/src" "$workdir/dst" || test_fail # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/README.testsuite0000664000000000000000000000247114124204403016320 0ustar rootrootautomatic testsuite for rsync -*- text -*- We're trying to develop some more substantial tests to prevent rsync regressions. Ideally, all code changes or bug reports would come with an appropriate test suite. You can run these tests by typing "make check" in the build directory. The tests will run using the rsync binary in the build directory, so you do not need to do "make install" first. Indeed, you probably should not install rsync before running the tests. If you instead type "make installcheck" then the suite will test the rsync binary from its installed location (e.g. /usr/local/bin/rsync). You can use this to test a distribution build, or perhaps to run a new test suite against an old version of rsync. Note that in accordance with the GNU Standards, installcheck does not look for rsync on the path. If the tests pass, you should see a report to that effect. Some tests require being root or some other precondition, and so will normally not be checked -- look at the test scripts for more information. If the tests fail, you will see rather more output. The scratch directory will remain in the build directory. It would be useful if you could include the log messages when reporting a failure. These tests also run automatically on the build farm, and you can see the results on http://build.samba.org/. rsync-3.2.7/testsuite/trimslash.test0000664000000000000000000000121214124204403016307 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test tiny function to trim trailing slashes. . "$suitedir/rsync.fns" "$TOOLDIR/trimslash" "/usr/local/bin" "/usr/local/bin/" "/usr/local/bin///" \ "//a//" "////" \ "/Users/Weird Macintosh Name/// Ooh, translucent plastic/" \ > "$scratchdir/slash.out" diff $diffopt "$scratchdir/slash.out" - < # Copyright (C) 2001, 2002 by Martin Pool # # This program is distributable under the terms of the GNU GPL (see COPYING) . "$suitedir/rsync.fns" hands_setup DEBUG_OPTS="--debug=all0,deltasum0" # Main script starts here runtest "basic operation" 'checkit "$RSYNC -av \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' ln "$fromdir/filelist" "$fromdir/dir" runtest "hard links" 'checkit "$RSYNC -avH --bwlimit=0 $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' rm "$todir/text" runtest "one file" 'checkit "$RSYNC -avH $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' echo "extra line" >> "$todir/text" runtest "extra data" 'checkit "$RSYNC -avH $DEBUG_OPTS --no-whole-file \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' cp "$fromdir/text" "$todir/ThisShouldGo" runtest " --delete" 'checkit "$RSYNC --delete -avH $DEBUG_OPTS \"$fromdir/\" \"$todir\"" "$fromdir/" "$todir"' cd "$tmpdir" rm -rf to from/*dir # Do the real copy, touch up the parent-dir's time, and then check the copy. $RSYNC -av from/* to/ checkit "$RSYNC -av --exclude='*' from/ to/" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/merge.test0000664000000000000000000000326614170671375015434 0ustar rootroot#!/bin/sh # Copyright (C) 2004-2022 Wayne Davison # This program is distributable under the terms of the GNU GPL (see # COPYING). # Make sure we can merge files from multiple directories into one. . "$suitedir/rsync.fns" # Build some files/dirs/links to copy # Use local dirnames to better exercise the arg-parsing code. cd "$tmpdir" mkdir from1 from2 from3 deep mkdir from2/sub1 from3/sub1 mkdir from3/sub2 from1/dir-and-not-dir mkdir chk chk/sub1 chk/sub2 chk/dir-and-not-dir echo "one" >from1/one cp_touch from1/one from2/one cp_touch from1/one from3/one echo "two" >from1/two echo "three" >from2/three echo "four" >from3/four echo "five" >from1/five echo "six" >from3/six echo "sub1" >from2/sub1/uno cp_touch from2/sub1/uno from3/sub1/uno echo "sub2" >from3/sub1/dos echo "sub3" >from2/sub1/tres echo "subby" >from3/sub2/subby echo "extra" >from1/dir-and-not-dir/inside echo "not-dir" >from3/dir-and-not-dir echo "arg-test" >deep/arg-test echo "shallow" >shallow cp_touch from1/one from1/two from2/three from3/four from1/five from3/six chk cp_touch deep/arg-test shallow chk cp_touch from1/dir-and-not-dir/inside chk/dir-and-not-dir cp_touch from2/sub1/uno from3/sub1/dos from2/sub1/tres chk/sub1 cp_touch from3/sub2/subby chk/sub2 # Make sure that time has moved on. sleep 1 # Get rid of any directory-time differences $RSYNC -av --existing -f 'exclude,! */' from1/ from2/ $RSYNC -av --existing -f 'exclude,! */' from2/ from3/ $RSYNC -av --existing -f 'exclude,! */' from1/ chk/ $RSYNC -av --existing -f 'exclude,! */' from3/ chk/ checkit "$RSYNC -avv deep/arg-test shallow from1/ from2/ from3/ to/" "$chkdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/acls.test0000664000000000000000000000316514324271266015251 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that rsync handles basic ACL preservation. . $suitedir/rsync.fns $RSYNC -VV | grep '"ACLs": true' >/dev/null || test_skipped "Rsync is configured without ACL support" makepath "$fromdir/foo" echo something >"$fromdir/file1" echo else >"$fromdir/file2" files='foo file1 file2' case "$setfacl_nodef" in true) if ! chmod --help 2>&1 | grep -F +a >/dev/null; then test_skipped "I don't know how to use setfacl or chmod for ACLs" fi chmod +a "root allow read,write,execute" "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled" chmod +a "root allow read,execute" "$fromdir/file1" chmod +a "admin allow read" "$fromdir/file1" chmod +a "daemon allow read,write" "$fromdir/file1" chmod +a "root allow read,execute" "$fromdir/file2" see_acls() { ls -le "${@}" } ;; *) setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled" setfacl -m g:1:5 "$fromdir/foo" setfacl -m g:2:1 "$fromdir/foo" setfacl -m g:0:7 "$fromdir/foo" setfacl -m u:2:1 "$fromdir/foo" setfacl -m u:1:5 "$fromdir/foo" setfacl -m u:0:5 "$fromdir/file1" setfacl -m g:0:4 "$fromdir/file1" setfacl -m u:1:6 "$fromdir/file1" setfacl -m u:0:5 "$fromdir/file2" see_acls() { getfacl "${@}" } ;; esac cd "$fromdir" $RSYNC -avvA $files "$todir/" see_acls $files >"$scratchdir/acls.txt" cd "$todir" see_acls $files | diff $diffopt "$scratchdir/acls.txt" - # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/unsafe-links.test0000664000000000000000000000276214124204403016713 0ustar rootroot#!/bin/sh # Originally by Vladimír Michl . "$suitedir/rsync.fns" test_symlink() { is_a_link "$1" || test_fail "File $1 is not a symlink" } test_regular() { if [ ! -f "$1" ]; then test_fail "File $1 is not regular file or not exists" fi } cd "$tmpdir" mkdir from mkdir "from/safe" mkdir "from/unsafe" mkdir "from/safe/files" mkdir "from/safe/links" touch "from/safe/files/file1" touch "from/safe/files/file2" touch "from/unsafe/unsafefile" ln -s ../files/file1 "from/safe/links/" ln -s ../files/file2 "from/safe/links/" ln -s ../../unsafe/unsafefile "from/safe/links/" echo "rsync with relative path and just -a" $RSYNC -avv from/safe/ to test_symlink to/links/file1 test_symlink to/links/file2 test_symlink to/links/unsafefile echo "rsync with relative path and -a --copy-links" $RSYNC -avv --copy-links from/safe/ to test_regular to/links/file1 test_regular to/links/file2 test_regular to/links/unsafefile echo "rsync with relative path and --copy-unsafe-links" $RSYNC -avv --copy-unsafe-links from/safe/ to test_symlink to/links/file1 test_symlink to/links/file2 test_regular to/links/unsafefile rm -rf to echo "rsync with relative2 path" (cd from; $RSYNC -avv --copy-unsafe-links safe/ ../to) test_symlink to/links/file1 test_symlink to/links/file2 test_regular to/links/unsafefile rm -rf to echo "rsync with absolute path" $RSYNC -avv --copy-unsafe-links `pwd`/from/safe/ to test_symlink to/links/file1 test_symlink to/links/file2 test_regular to/links/unsafefile rsync-3.2.7/testsuite/atimes.test0000664000000000000000000000065614324271266015613 0ustar rootroot#!/bin/sh # Test rsync copying atimes . "$suitedir/rsync.fns" $RSYNC -VV | grep '"atimes": true' >/dev/null || test_skipped "Rsync is configured without atimes support" mkdir "$fromdir" touch "$fromdir/foo" touch -a -t 200102031717.42 "$fromdir/foo" TLS_ARGS=--atimes checkit "$RSYNC -rtUgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir" # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/xattrs.test0000664000000000000000000001360114324271266015650 0ustar rootroot#!/bin/sh # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test that rsync handles basic xattr preservation. . $suitedir/rsync.fns lnkdir="$tmpdir/lnk" $RSYNC -VV | grep '"xattrs": true' >/dev/null || test_skipped "Rsync is configured without xattr support" case "$HOST_OS" in darwin*) xset() { xnam="$1" xval="$2" shift 2 xattr -s "$xnam" "$xval" "${@}" } xls() { xattr -l "${@}" | sed "s/^[ $tab_ch]*//" } RSYNC_PREFIX='rsync' RUSR='rsync.nonuser' ;; solaris*) xset() { xnam="$1" xval="$2" shift 2 for fn in "${@}"; do runat "$fn" "$SHELL_PATH" < "${xnam}" EOF done } xls() { for fn in "${@}"; do runat "$fn" "$SHELL_PATH" <"$fromdir/file0" echo something >"$fromdir/file1" echo else >"$fromdir/file2" echo deep >"$fromdir/foo/file3" echo normal >"$fromdir/file4" echo deeper >"$fromdir/foo/bar/file5" makepath "$chkdir/foo" echo wow >"$chkdir/file1" cp_touch "$fromdir/foo/file3" "$chkdir/foo" dirs='foo foo/bar' files='file0 file1 file2 foo/file3 file4 foo/bar/file5' uid_gid=`"$TOOLDIR/tls" "$fromdir/foo" | sed 's/^.* \([0-9][0-9]*\)\.\([0-9][0-9]*\) .*/\1:\2/'` cd "$fromdir" xset user.foo foo file0 2>/dev/null || test_skipped "Unable to set an xattr" xset user.bar bar file0 xset user.short 'this is short' file1 xset user.long 'this is a long attribute that will be truncated in the initial data send' file1 xset user.good 'this is good' file1 xset user.nice 'this is nice' file1 xset user.foo foo file2 xset user.bar bar file2 xset user.long 'a long attribute for our new file that tests to ensure that this works' file2 xset user.dir1 'need to test directory xattrs too' foo xset user.dir2 'another xattr' foo xset user.dir3 'this is one last one for the moment' foo xset user.dir4 'another dir test' foo/bar xset user.dir5 'one last one' foo/bar xset user.foo 'new foo' foo/file3 foo/bar/file5 xset user.bar 'new bar' foo/file3 foo/bar/file5 xset user.long 'this is also a long attribute that will be truncated in the initial data send' foo/file3 foo/bar/file5 xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' foo/file3 foo/bar/file5 xset user.dir0 'old extra value' "$chkdir/foo" xset user.dir1 'old dir value' "$chkdir/foo" xset user.short 'old short' "$chkdir/file1" xset user.extra 'remove me' "$chkdir/file1" xset user.foo 'old foo' "$chkdir/foo/file3" xset $RUSR.equal 'this long attribute should remain the same and not need to be transferred' "$chkdir/foo/file3" case $0 in *hlink*) ln foo/bar/file5 foo/bar/file6 || test_skipped "Can't create hardlink" files="$files foo/bar/file6" dashH='-H' altDest='--link-dest' ;; *) dashH='' altDest='--copy-dest' ;; esac xls $dirs $files >"$scratchdir/xattrs.txt" XFILT='-f-x_system.* -f-x_security.*' # OK, let's try a simple xattr copy. checkit "$RSYNC -avX $XFILT $dashH --super . '$chkdir/'" "$fromdir" "$chkdir" cd "$chkdir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - cd "$fromdir" if [ -n "$dashH" ]; then for fn in $files; do name=`basename $fn` ln $fn ../lnk/$name done fi checkit "$RSYNC -aiX $XFILT $dashH --super $altDest=../chk . ../to" "$fromdir" "$todir" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - [ -n "$dashH" ] && rm -rf "$lnkdir" cd "$fromdir" rm -rf "$todir" xset user.nice 'this is nice, but different' file1 xls $dirs $files >"$scratchdir/xattrs.txt" checkit "$RSYNC -aiX $XFILT $dashH --fake-super --link-dest=../chk . ../to" "$chkdir" "$todir" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - sed -n -e '/^[^d ][^ ]* *[^ ][^ ]* *[^ ][^ ]* *1 /p' "$scratchdir/ls-to" >"$scratchdir/ls-diff-all" grep -F -v './file1' "$scratchdir/ls-diff-all" >"$scratchdir/ls-diff" || : if [ -s "$scratchdir/ls-diff" ]; then echo "Missing hard links on:" cat "$scratchdir/ls-diff" exit 1 fi if [ ! -s "$scratchdir/ls-diff-all" ]; then echo "Too many hard links on file1!" exit 1 fi cd "$chkdir" chmod go-rwx . $dirs $files xset user.nice 'this is nice, but different' file1 xset $RSYNC_PREFIX.%stat "40000 0,0 $uid_gid" $dirs xset $RSYNC_PREFIX.%stat "100000 0,0 $uid_gid" $files xls $dirs $files >"$scratchdir/xattrs.txt" cd "$fromdir" rm -rf "$todir" # When run by a non-root tester, this checks if no-user-perm files/dirs can be copied. checkit "$RSYNC -aiX $XFILT $dashH --fake-super --chmod=a= . ../to" "$chkdir" "$todir" # 2>"$scratchdir/errors.txt" cd "$todir" xls $dirs $files | diff $diffopt "$scratchdir/xattrs.txt" - cd "$fromdir" rm -rf "$todir" "$chkdir" $RSYNC -aX file1 file2 $RSYNC -aX file1 file2 ../chk/ $RSYNC -aX --del ../chk/ . $RSYNC -aX file1 ../lnk/ [ -n "$dashH" ] && ln "$chkdir/file1" ../lnk/extra-link xls file1 file2 >"$scratchdir/xattrs.txt" checkit "$RSYNC -aiiX $XFILT $dashH $altDest=../lnk . ../to" "$chkdir" "$todir" [ -n "$dashH" ] && rm ../lnk/extra-link cd "$todir" xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" - cd "$fromdir" rm "$todir/file2" echo extra >file1 $RSYNC -aX . ../chk/ checkit "$RSYNC -aiiX $XFILT . ../to" "$chkdir" "$todir" cd "$todir" xls file1 file2 | diff $diffopt "$scratchdir/xattrs.txt" - # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/testsuite/duplicates.test0000664000000000000000000000302014124204403016435 0ustar rootroot#!/bin/sh # Copyright (C) 2002 by Martin Pool # This program is distributable under the terms of the GNU GPL (see # COPYING). # Test rsync handling of duplicate filenames. # It's quite possible that the user might specify the same source file # more than once on the command line, perhaps through shell variables # or wildcard expansions. It might cause problems for rsync if the # same name occurred more than once in the file list, because we might # be trying to update the first copy and generate checksums for the # second copy at the same time. See clean_flist() for the implementation. # We don't need to worry about hardlinks or symlinks. Because we # always rename-and-replace the new copy, they can't affect us. # This test is not great, because it is a timing-dependent bug. . "$suitedir/rsync.fns" # Build some hardlinks mkdir "$fromdir" name1="$fromdir/name1" name2="$fromdir/name2" echo "This is the file" > "$name1" ln -s "$name1" "$name2" || test_fail "can't create symlink" checkit "$RSYNC -avv '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$fromdir/' '$todir/'" "$fromdir" "$todir" \ | tee "$outfile" # Make sure each file was only copied once... if [ `grep -c '^name1$' "$outfile"` != 1 ]; then test_fail "name1 was not copied exactly once" fi if [ `grep -c '^name2 -> ' "$outfile"` != 1 ]; then test_fail "name2 was not copied exactly once" fi # The script would have aborted on error, so getting here means we've won. exit 0 rsync-3.2.7/md-convert0000775000000000000000000005404114301252410013361 0ustar rootroot#!/usr/bin/env python3 # This script transforms markdown files into html and (optionally) nroff. The # output files are written into the current directory named for the input file # without the .md suffix and either the .html suffix or no suffix. # # If the input .md file has a section number at the end of the name (e.g., # rsync.1.md) a nroff file is also output (PROJ.NUM.md -> PROJ.NUM). # # The markdown input format has one extra extension: if a numbered list starts # at 0, it is turned into a description list. The dl's dt tag is taken from the # contents of the first tag inside the li, which is usually a p, code, or # strong tag. # # The cmarkgfm or commonmark lib is used to transforms the input file into # html. Then, the html.parser is used as a state machine that lets us tweak # the html and (optionally) output nroff data based on the html tags. # # If the string @USE_GFM_PARSER@ exists in the file, the string is removed and # a github-flavored-markup parser is used to parse the file. # # The man-page .md files also get the vars @VERSION@, @BINDIR@, and @LIBDIR@ # substituted. Some of these values depend on the Makefile $(prefix) (see the # generated Makefile). If the maintainer wants to build files for /usr/local # while creating release-ready man-page files for /usr, use the environment to # set RSYNC_OVERRIDE_PREFIX=/usr. # Copyright (C) 2020 - 2021 Wayne Davison # # This program is freely redistributable. import os, sys, re, argparse, subprocess, time from html.parser import HTMLParser VALID_PAGES = 'README INSTALL COPYING rsync.1 rrsync.1 rsync-ssl.1 rsyncd.conf.5'.split() CONSUMES_TXT = set('h1 h2 h3 p li pre'.split()) HTML_START = """\ %TITLE% """ TABLE_STYLE = """\ table { border-color: grey; border-spacing: 0; } tr { border-top: 1px solid grey; } tr:nth-child(2n) { background-color: #f6f8fa; } th, td { border: 1px solid #dfe2e5; text-align: center; padding-left: 1em; padding-right: 1em; } """ MAN_HTML_END = """\

%s

""" HTML_END = """\ """ MAN_START = r""" .TH "%s" "%s" "%s" "%s" "User Commands" .\" prefix=%s """.lstrip() MAN_END = """\ """ NORM_FONT = ('\1', r"\fP") BOLD_FONT = ('\2', r"\fB") UNDR_FONT = ('\3', r"\fI") NBR_DASH = ('\4', r"\-") NBR_SPACE = ('\xa0', r"\ ") FILENAME_RE = re.compile(r'^(?P(?P.+/)?(?P(?P[^/]+?)(\.(?P\d+))?)\.md)$') ASSIGNMENT_RE = re.compile(r'^(\w+)=(.+)') VER_RE = re.compile(r'^#define\s+RSYNC_VERSION\s+"(\d.+?)"', re.M) TZ_RE = re.compile(r'^#define\s+MAINTAINER_TZ_OFFSET\s+(-?\d+(\.\d+)?)', re.M) VAR_REF_RE = re.compile(r'\$\{(\w+)\}') VERSION_RE = re.compile(r' (\d[.\d]+)[, ]') BIN_CHARS_RE = re.compile(r'[\1-\7]+') SPACE_DOUBLE_DASH_RE = re.compile(r'\s--(\s)') NON_SPACE_SINGLE_DASH_RE = re.compile(r'(^|\W)-') WHITESPACE_RE = re.compile(r'\s') CODE_BLOCK_RE = re.compile(r'[%s]([^=%s]+)[=%s]' % (BOLD_FONT[0], NORM_FONT[0], NORM_FONT[0])) NBR_DASH_RE = re.compile(r'[%s]' % NBR_DASH[0]) INVALID_TARGET_CHARS_RE = re.compile(r'[^-A-Za-z0-9._]') INVALID_START_CHAR_RE = re.compile(r'^([^A-Za-z0-9])') MANIFY_LINESTART_RE = re.compile(r"^(['.])", flags=re.M) md_parser = None env_subs = { } warning_count = 0 def main(): for mdfn in args.mdfiles: parse_md_file(mdfn) if args.test: print("The test was successful.") def parse_md_file(mdfn): fi = FILENAME_RE.match(mdfn) if not fi: die('Failed to parse a md input file name:', mdfn) fi = argparse.Namespace(**fi.groupdict()) fi.want_manpage = not not fi.sect if fi.want_manpage: fi.title = fi.prog + '(' + fi.sect + ') manpage' else: fi.title = fi.prog + ' for rsync' if fi.want_manpage: if not env_subs: find_man_substitutions() prog_ver = 'rsync ' + env_subs['VERSION'] if fi.prog != 'rsync': prog_ver = fi.prog + ' from ' + prog_ver fi.man_headings = (fi.prog, fi.sect, env_subs['date'], prog_ver, env_subs['prefix']) with open(mdfn, 'r', encoding='utf-8') as fh: txt = fh.read() use_gfm_parser = '@USE_GFM_PARSER@' in txt if use_gfm_parser: txt = txt.replace('@USE_GFM_PARSER@', '') if fi.want_manpage: txt = (txt.replace('@VERSION@', env_subs['VERSION']) .replace('@BINDIR@', env_subs['bindir']) .replace('@LIBDIR@', env_subs['libdir'])) if use_gfm_parser: if not gfm_parser: die('Input file requires cmarkgfm parser:', mdfn) fi.html_in = gfm_parser(txt) else: fi.html_in = md_parser(txt) txt = None TransformHtml(fi) if args.test: return output_list = [ (fi.name + '.html', fi.html_out) ] if fi.want_manpage: output_list += [ (fi.name, fi.man_out) ] for fn, txt in output_list: if args.dest and args.dest != '.': fn = os.path.join(args.dest, fn) if os.path.lexists(fn): os.unlink(fn) print("Wrote:", fn) with open(fn, 'w', encoding='utf-8') as fh: fh.write(txt) def find_man_substitutions(): srcdir = os.path.dirname(sys.argv[0]) + '/' mtime = 0 git_dir = srcdir + '.git' if os.path.lexists(git_dir): mtime = int(subprocess.check_output(['git', '--git-dir', git_dir, 'log', '-1', '--format=%at'])) # Allow "prefix" to be overridden via the environment: env_subs['prefix'] = os.environ.get('RSYNC_OVERRIDE_PREFIX', None) if args.test: env_subs['VERSION'] = '1.0.0' env_subs['bindir'] = '/usr/bin' env_subs['libdir'] = '/usr/lib/rsync' tz_offset = 0 else: for fn in (srcdir + 'version.h', 'Makefile'): try: st = os.lstat(fn) except OSError: die('Failed to find', srcdir + fn) if not mtime: mtime = st.st_mtime with open(srcdir + 'version.h', 'r', encoding='utf-8') as fh: txt = fh.read() m = VER_RE.search(txt) env_subs['VERSION'] = m.group(1) m = TZ_RE.search(txt) # the tzdata lib may not be installed, so we use a simple hour offset tz_offset = float(m.group(1)) * 60 * 60 with open('Makefile', 'r', encoding='utf-8') as fh: for line in fh: m = ASSIGNMENT_RE.match(line) if not m: continue var, val = (m.group(1), m.group(2)) if var == 'prefix' and env_subs[var] is not None: continue while VAR_REF_RE.search(val): val = VAR_REF_RE.sub(lambda m: env_subs[m.group(1)], val) env_subs[var] = val if var == 'srcdir': break env_subs['date'] = time.strftime('%d %b %Y', time.gmtime(mtime + tz_offset)).lstrip('0') def html_via_commonmark(txt): return commonmark.HtmlRenderer().render(commonmark.Parser().parse(txt)) class TransformHtml(HTMLParser): def __init__(self, fi): HTMLParser.__init__(self, convert_charrefs=True) self.fn = fi.fn st = self.state = argparse.Namespace( list_state = [ ], p_macro = ".P\n", at_first_tag_in_li = False, at_first_tag_in_dd = False, dt_from = None, in_pre = False, in_code = False, html_out = [ HTML_START.replace('%TITLE%', fi.title) ], man_out = [ ], txt = '', want_manpage = fi.want_manpage, created_hashtags = set(), derived_hashtags = set(), referenced_hashtags = set(), bad_hashtags = set(), latest_targets = [ ], opt_prefix = 'opt', a_txt_start = None, target_suf = '', ) if st.want_manpage: st.man_out.append(MAN_START % fi.man_headings) if '' in fi.html_in: st.html_out[0] = st.html_out[0].replace('', TABLE_STYLE + '') self.feed(fi.html_in) fi.html_in = None if st.want_manpage: st.html_out.append(MAN_HTML_END % env_subs['date']) st.html_out.append(HTML_END) st.man_out.append(MAN_END) fi.html_out = ''.join(st.html_out) st.html_out = None fi.man_out = ''.join(st.man_out) st.man_out = None for tgt, txt in st.derived_hashtags: derived = txt2target(txt, tgt) if derived not in st.created_hashtags: txt = BIN_CHARS_RE.sub('', txt.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' ')) warn('Unknown derived hashtag link in', self.fn, 'based on:', (tgt, txt)) for bad in st.bad_hashtags: if bad in st.created_hashtags: warn('Missing "#" in hashtag link in', self.fn + ':', bad) else: warn('Unknown non-hashtag link in', self.fn + ':', bad) for bad in st.referenced_hashtags - st.created_hashtags: warn('Unknown hashtag link in', self.fn + ':', '#' + bad) def handle_starttag(self, tag, attrs_list): st = self.state if args.debug: self.output_debug('START', (tag, attrs_list)) if st.at_first_tag_in_li: if st.list_state[-1] == 'dl': st.dt_from = tag if tag == 'p': tag = 'dt' else: st.html_out.append('
') elif tag == 'p': st.at_first_tag_in_dd = True # Kluge to suppress a .P at the start of an li. st.at_first_tag_in_li = False if tag == 'p': if not st.at_first_tag_in_dd: st.man_out.append(st.p_macro) elif tag == 'li': st.at_first_tag_in_li = True lstate = st.list_state[-1] if lstate == 'dl': return if lstate == 'o': st.man_out.append(".IP o\n") else: st.man_out.append(".IP " + str(lstate) + ".\n") st.list_state[-1] += 1 elif tag == 'blockquote': st.man_out.append(".RS 4\n") elif tag == 'pre': st.in_pre = True st.man_out.append(st.p_macro + ".nf\n") elif tag == 'code' and not st.in_pre: st.in_code = True st.txt += BOLD_FONT[0] elif tag == 'strong' or tag == 'b': st.txt += BOLD_FONT[0] elif tag == 'em' or tag == 'i': if st.want_manpage: tag = 'u' # Change it into underline to be more like the manpage st.txt += UNDR_FONT[0] elif tag == 'ol': start = 1 for var, val in attrs_list: if var == 'start': start = int(val) # We only support integers. break if st.list_state: st.man_out.append(".RS\n") if start == 0: tag = 'dl' attrs_list = [ ] st.list_state.append('dl') else: st.list_state.append(start) st.man_out.append(st.p_macro) st.p_macro = ".IP\n" elif tag == 'ul': st.man_out.append(st.p_macro) if st.list_state: st.man_out.append(".RS\n") st.p_macro = ".IP\n" st.list_state.append('o') elif tag == 'hr': st.man_out.append(".l\n") st.html_out.append("
") return elif tag == 'a': st.a_href = None for var, val in attrs_list: if var == 'href': if val.startswith(('https://', 'http://', 'mailto:', 'ftp:')): pass # nothing to check elif '#' in val: pg, tgt = val.split('#', 1) if pg and pg not in VALID_PAGES or '#' in tgt: st.bad_hashtags.add(val) elif tgt in ('', 'opt', 'dopt'): st.a_href = val elif pg == '': st.referenced_hashtags.add(tgt) if tgt in st.latest_targets: warn('Found link to the current section in', self.fn + ':', val) elif val not in VALID_PAGES: st.bad_hashtags.add(val) st.a_txt_start = len(st.txt) st.html_out.append('<' + tag + ''.join(' ' + var + '="' + htmlify(val) + '"' for var, val in attrs_list) + '>') st.at_first_tag_in_dd = False def handle_endtag(self, tag): st = self.state if args.debug: self.output_debug('END', (tag,)) if tag in CONSUMES_TXT or st.dt_from == tag: txt = st.txt.strip() st.txt = '' else: txt = None add_to_txt = None if tag == 'h1': tgt = txt target_suf = '' if tgt.startswith('NEWS for '): m = VERSION_RE.search(tgt) if m: tgt = m.group(1) st.target_suf = '-' + tgt self.add_targets(tag, tgt) elif tag == 'h2': st.man_out.append(st.p_macro + '.SH "' + manify(txt) + '"\n') self.add_targets(tag, txt, st.target_suf) st.opt_prefix = 'dopt' if txt == 'DAEMON OPTIONS' else 'opt' elif tag == 'h3': st.man_out.append(st.p_macro + '.SS "' + manify(txt) + '"\n') self.add_targets(tag, txt, st.target_suf) elif tag == 'p': if st.dt_from == 'p': tag = 'dt' st.man_out.append('.IP "' + manify(txt) + '"\n') if txt.startswith(BOLD_FONT[0]): self.add_targets(tag, txt) st.dt_from = None elif txt != '': st.man_out.append(manify(txt) + "\n") elif tag == 'li': if st.list_state[-1] == 'dl': if st.at_first_tag_in_li: die("Invalid 0. -> td translation") tag = 'dd' if txt != '': st.man_out.append(manify(txt) + "\n") st.at_first_tag_in_li = False elif tag == 'blockquote': st.man_out.append(".RE\n") elif tag == 'pre': st.in_pre = False st.man_out.append(manify(txt) + "\n.fi\n") elif (tag == 'code' and not st.in_pre): st.in_code = False add_to_txt = NORM_FONT[0] elif tag == 'strong' or tag == 'b': add_to_txt = NORM_FONT[0] elif tag == 'em' or tag == 'i': if st.want_manpage: tag = 'u' # Change it into underline to be more like the manpage add_to_txt = NORM_FONT[0] elif tag == 'ol' or tag == 'ul': if st.list_state.pop() == 'dl': tag = 'dl' if st.list_state: st.man_out.append(".RE\n") else: st.p_macro = ".P\n" st.at_first_tag_in_dd = False elif tag == 'hr': return elif tag == 'a': if st.a_href: atxt = st.txt[st.a_txt_start:] find = 'href="' + st.a_href + '"' for j in range(len(st.html_out)-1, 0, -1): if find in st.html_out[j]: pg, tgt = st.a_href.split('#', 1) derived = txt2target(atxt, tgt) if pg == '': if derived in st.latest_targets: warn('Found link to the current section in', self.fn + ':', st.a_href) st.derived_hashtags.add((tgt, atxt)) st.html_out[j] = st.html_out[j].replace(find, 'href="' + pg + '#' + derived + '"') break else: die('INTERNAL ERROR: failed to find href in html data:', find) st.html_out.append('') if add_to_txt: if txt is None: st.txt += add_to_txt else: txt += add_to_txt if st.dt_from == tag: st.man_out.append('.IP "' + manify(txt) + '"\n') st.html_out.append('
') st.at_first_tag_in_dd = True st.dt_from = None elif tag == 'dt': st.html_out.append('
') st.at_first_tag_in_dd = True def handle_data(self, txt): st = self.state if '](' in txt: warn('Malformed link in', self.fn + ':', txt) if args.debug: self.output_debug('DATA', (txt,)) if st.in_pre: html = htmlify(txt) else: txt = SPACE_DOUBLE_DASH_RE.sub(NBR_SPACE[0] + r'--\1', txt).replace('--', NBR_DASH[0]*2) txt = NON_SPACE_SINGLE_DASH_RE.sub(r'\1' + NBR_DASH[0], txt) html = htmlify(txt) if st.in_code: txt = WHITESPACE_RE.sub(NBR_SPACE[0], txt) html = html.replace(NBR_DASH[0], '-').replace(NBR_SPACE[0], ' ') # is non-breaking in CSS st.html_out.append(html.replace(NBR_SPACE[0], ' ').replace(NBR_DASH[0], '-⁠')) st.txt += txt def add_targets(self, tag, txt, suf=None): st = self.state tag = '<' + tag + '>' targets = CODE_BLOCK_RE.findall(txt) if not targets: targets = [ txt ] tag_pos = 0 for txt in targets: txt = txt2target(txt, st.opt_prefix) if not txt: continue if suf: txt += suf if txt in st.created_hashtags: for j in range(2, 1000): chk = txt + '-' + str(j) if chk not in st.created_hashtags: print('Made link target unique:', chk) txt = chk break if tag_pos == 0: tag_pos -= 1 while st.html_out[tag_pos] != tag: tag_pos -= 1 st.html_out[tag_pos] = tag[:-1] + ' id="' + txt + '">' st.html_out.append('') tag_pos -= 1 # take into account the append else: st.html_out[tag_pos] = '' + st.html_out[tag_pos] st.created_hashtags.add(txt) st.latest_targets = targets def output_debug(self, event, extra): import pprint st = self.state if args.debug < 2: st = argparse.Namespace(**vars(st)) if len(st.html_out) > 2: st.html_out = ['...'] + st.html_out[-2:] if len(st.man_out) > 2: st.man_out = ['...'] + st.man_out[-2:] print(event, extra) pprint.PrettyPrinter(indent=2).pprint(vars(st)) def txt2target(txt, opt_prefix): txt = txt.strip().rstrip(':') m = CODE_BLOCK_RE.search(txt) if m: txt = m.group(1) txt = NBR_DASH_RE.sub('-', txt) txt = BIN_CHARS_RE.sub('', txt) txt = INVALID_TARGET_CHARS_RE.sub('_', txt) if opt_prefix and txt.startswith('-'): txt = opt_prefix + txt else: txt = INVALID_START_CHAR_RE.sub(r't\1', txt) return txt def manify(txt): return MANIFY_LINESTART_RE.sub(r'\&\1', txt.replace('\\', '\\\\') .replace(NBR_SPACE[0], NBR_SPACE[1]) .replace(NBR_DASH[0], NBR_DASH[1]) .replace(NORM_FONT[0], NORM_FONT[1]) .replace(BOLD_FONT[0], BOLD_FONT[1]) .replace(UNDR_FONT[0], UNDR_FONT[1])) def htmlify(txt): return txt.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"') def warn(*msg): print(*msg, file=sys.stderr) global warning_count warning_count += 1 def die(*msg): warn(*msg) sys.exit(1) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Convert markdown into html and (optionally) nroff. Each input filename must have a .md suffix, which is changed to .html for the output filename. If the input filename ends with .num.md (e.g. foo.1.md) then a nroff file is also output with the input filename's .md suffix removed (e.g. foo.1).", add_help=False) parser.add_argument('--test', action='store_true', help="Just test the parsing without outputting any files.") parser.add_argument('--dest', metavar='DIR', help="Create files in DIR instead of the current directory.") parser.add_argument('--debug', '-D', action='count', default=0, help='Output copious info on the html parsing. Repeat for even more.') parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") parser.add_argument("mdfiles", metavar='FILE.md', nargs='+', help="One or more .md files to convert.") args = parser.parse_args() try: import cmarkgfm md_parser = cmarkgfm.markdown_to_html gfm_parser = cmarkgfm.github_flavored_markdown_to_html except: try: import commonmark md_parser = html_via_commonmark except: die("Failed to find cmarkgfm or commonmark for python3.") gfm_parser = None main() if warning_count: sys.exit(1) rsync-3.2.7/backup.c0000664000000000000000000002216714170671375013015 0ustar rootroot/* * Backup handling code. * * Copyright (C) 1999 Andrew Tridgell * Copyright (C) 2003-2022 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" extern int am_root; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_devices; extern int preserve_specials; extern int preserve_links; extern int safe_symlinks; extern int backup_dir_len; extern unsigned int backup_dir_remainder; extern char backup_dir_buf[MAXPATHLEN]; extern char *backup_suffix; extern char *backup_dir; /* Returns -1 on error, 0 on missing dir, and 1 on present dir. */ static int validate_backup_dir(void) { STRUCT_STAT st; if (do_lstat(backup_dir_buf, &st) < 0) { if (errno == ENOENT) return 0; rsyserr(FERROR, errno, "backup lstat %s failed", backup_dir_buf); return -1; } if (!S_ISDIR(st.st_mode)) { int flags = get_del_for_flag(st.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE; if (delete_item(backup_dir_buf, st.st_mode, flags) == 0) return 0; return -1; } return 1; } /* Create a backup path from the given fname, putting the result into * backup_dir_buf. Any new directories (compared to the prior backup * path) are ensured to exist as directories, replacing anything else * that may be in the way (e.g. a symlink). */ static BOOL copy_valid_path(const char *fname) { const char *f; int val; BOOL ret = True; stat_x sx; char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel; for (f = fname, b = rel; *f && *f == *b; f++, b++) { if (*b == '/') name = b + 1; } if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) { rprintf(FERROR, "backup filename too long\n"); *name = '\0'; return False; } for ( ; ; name = b + 1) { if ((b = strchr(name, '/')) == NULL) return True; *b = '\0'; val = validate_backup_dir(); if (val == 0) break; if (val < 0) { *name = '\0'; return False; } *b = '/'; } init_stat_x(&sx); for ( ; b; name = b + 1, b = strchr(name, '/')) { *b = '\0'; while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) { if (errno == EEXIST) { val = validate_backup_dir(); if (val > 0) break; if (val == 0) continue; } else rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf); *name = '\0'; ret = False; goto cleanup; } /* Try to transfer the directory settings of the actual dir * that the files are coming from. */ if (x_stat(rel, &sx.st, NULL) < 0) rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel)); else { struct file_struct *file; if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) continue; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(rel, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(rel, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif set_file_attrs(backup_dir_buf, file, NULL, NULL, 0); unmake_file(file); } *b = '/'; } cleanup: #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return ret; } /* Make a complete pathname for backup file and verify any new path elements. */ char *get_backup_name(const char *fname) { if (backup_dir) { static int initialized = 0; if (!initialized) { int ret; if (backup_dir_len > 1) backup_dir_buf[backup_dir_len-1] = '\0'; ret = make_path(backup_dir_buf, 0); if (backup_dir_len > 1) backup_dir_buf[backup_dir_len-1] = '/'; if (ret < 0) return NULL; initialized = 1; } /* copy fname into backup_dir_buf while validating the dirs. */ if (copy_valid_path(fname)) return backup_dir_buf; /* copy_valid_path() has printed an error message. */ return NULL; } if (stringjoin(backup_dir_buf, MAXPATHLEN, fname, backup_suffix, NULL) < MAXPATHLEN) return backup_dir_buf; rprintf(FERROR, "backup filename too long\n"); return NULL; } /* Has same return codes as make_backup(). */ static inline int link_or_rename(const char *from, const char *to, BOOL prefer_rename, STRUCT_STAT *stp) { #ifdef SUPPORT_HARD_LINKS if (!prefer_rename) { #ifndef CAN_HARDLINK_SYMLINK if (S_ISLNK(stp->st_mode)) return 0; /* Use copy code. */ #endif #ifndef CAN_HARDLINK_SPECIAL if (IS_SPECIAL(stp->st_mode) || IS_DEVICE(stp->st_mode)) return 0; /* Use copy code. */ #endif if (do_link(from, to) == 0) { if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: HLINK %s successful.\n", from); return 2; } /* We prefer to rename a regular file rather than copy it. */ if (!S_ISREG(stp->st_mode) || errno == EEXIST || errno == EISDIR) return 0; } #endif if (do_rename(from, to) == 0) { if (stp->st_nlink > 1 && !S_ISDIR(stp->st_mode)) { /* If someone has hard-linked the file into the backup * dir, rename() might return success but do nothing! */ robust_unlink(from); /* Just in case... */ } if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: RENAME %s successful.\n", from); return 1; } return 0; } /* Hard-link, rename, or copy an item to the backup name. Returns 0 for * failure, 1 if item was moved, 2 if item was duplicated or hard linked * into backup area, or 3 if item doesn't exist or isn't a regular file. */ int make_backup(const char *fname, BOOL prefer_rename) { stat_x sx; struct file_struct *file; int save_preserve_xattrs; char *buf; int ret = 0; init_stat_x(&sx); /* Return success if no file to keep. */ if (x_lstat(fname, &sx.st, NULL) < 0) return 3; if (!(buf = get_backup_name(fname))) return 0; /* Try a hard-link or a rename first. Using rename is not atomic, but * is more efficient than forcing a copy for larger files when no hard- * linking is possible. */ if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) goto success; if (errno == EEXIST || errno == EISDIR) { STRUCT_STAT bakst; if (do_lstat(buf, &bakst) == 0) { int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE; if (delete_item(buf, bakst.st_mode, flags) != 0) return 0; } if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) goto success; } /* Fall back to making a copy. */ if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS))) return 3; /* the file could have disappeared */ #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(fname, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(fname, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif /* Check to see if this is a device file, or link */ if ((am_root && preserve_devices && IS_DEVICE(file->mode)) || (preserve_specials && IS_SPECIAL(file->mode))) { if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf)); else if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname); ret = 2; } #ifdef SUPPORT_LINKS if (!ret && preserve_links && S_ISLNK(file->mode)) { const char *sl = F_SYMLINK(file); if (safe_symlinks && unsafe_symlink(sl, fname)) { if (INFO_GTE(SYMSAFE, 1)) { rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n", fname, sl); } ret = 2; } else { if (do_symlink(sl, buf) < 0) rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl); else if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname); ret = 2; } } #endif if (!ret && !S_ISREG(file->mode)) { if (INFO_GTE(NONREG, 1)) rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 3; } /* Copy to backup tree if a file. */ if (!ret) { if (copy_file(fname, buf, -1, file->mode) < 0) { rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"", full_fname(fname), buf); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 0; } if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: COPY %s successful.\n", fname); ret = 2; } save_preserve_xattrs = preserve_xattrs; preserve_xattrs = 0; set_file_attrs(buf, file, NULL, fname, ATTRS_ACCURATE_TIME); preserve_xattrs = save_preserve_xattrs; unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif success: if (INFO_GTE(BACKUP, 1)) rprintf(FINFO, "backed up %s to %s\n", fname, buf); return ret; } rsync-3.2.7/log.c0000664000000000000000000006030514307154751012321 0ustar rootroot/* * Logging and utility functions. * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000-2001 Martin Pool * Copyright (C) 2003-2022 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 "itypes.h" #include "inums.h" extern int dry_run; extern int am_daemon; extern int am_server; extern int am_sender; extern int am_generator; extern int local_server; extern int quiet; extern int module_id; extern int allow_8bit_chars; extern int protocol_version; extern int always_checksum; extern int preserve_mtimes; extern int msgs2stderr; extern int stdout_format_has_i; extern int stdout_format_has_o_or_i; extern int logfile_format_has_i; extern int logfile_format_has_o_or_i; extern int receiver_symlink_times; extern int64 total_data_written; extern int64 total_data_read; extern mode_t orig_umask; extern char *auth_user; extern char *stdout_format; extern char *logfile_format; extern char *logfile_name; #ifdef ICONV_CONST extern iconv_t ic_chck; #endif #ifdef ICONV_OPTION extern iconv_t ic_recv; #endif extern char curr_dir[MAXPATHLEN]; extern char *full_module_path; extern unsigned int module_dirlen; extern char sender_file_sum[MAX_DIGEST_LEN]; extern const char undetermined_hostname[]; extern struct name_num_item *xfer_sum_nni, *file_sum_nni; static int log_initialised; static int logfile_was_closed; static FILE *logfile_fp; struct stats stats; int got_xfer_error = 0; int output_needs_newline = 0; int send_msgs_to_gen = 0; static int64 initial_data_written; static int64 initial_data_read; struct { int code; char const *name; } const rerr_names[] = { { RERR_SYNTAX , "syntax or usage error" }, { RERR_PROTOCOL , "protocol incompatibility" }, { RERR_FILESELECT , "errors selecting input/output files, dirs" }, { RERR_UNSUPPORTED, "requested action not supported" }, { RERR_STARTCLIENT, "error starting client-server protocol" }, { RERR_SOCKETIO , "error in socket IO" }, { RERR_FILEIO , "error in file IO" }, { RERR_STREAMIO , "error in rsync protocol data stream" }, { RERR_MESSAGEIO , "errors with program diagnostics" }, { RERR_IPC , "error in IPC code" }, { RERR_CRASHED , "sibling process crashed" }, { RERR_TERMINATED , "sibling process terminated abnormally" }, { RERR_SIGNAL1 , "received SIGUSR1" }, { RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" }, { RERR_WAITCHILD , "waitpid() failed" }, { RERR_MALLOC , "error allocating core memory buffers" }, { RERR_PARTIAL , "some files/attrs were not transferred (see previous errors)" }, { RERR_VANISHED , "some files vanished before they could be transferred" }, { RERR_DEL_LIMIT , "the --max-delete limit stopped deletions" }, { RERR_TIMEOUT , "timeout in data send/receive" }, { RERR_CONTIMEOUT , "timeout waiting for daemon connection" }, { RERR_CMD_FAILED , "remote shell failed" }, { RERR_CMD_KILLED , "remote shell killed" }, { RERR_CMD_RUN , "remote command could not be run" }, { RERR_CMD_NOTFOUND,"remote command not found" }, { 0, NULL } }; /* * Map from rsync error code to name, or return NULL. */ static char const *rerr_name(int code) { int i; for (i = 0; rerr_names[i].name; i++) { if (rerr_names[i].code == code) return rerr_names[i].name; } return NULL; } static void logit(int priority, const char *buf) { if (logfile_was_closed) logfile_reopen(); if (logfile_fp) { fprintf(logfile_fp, "%s [%d] %s", timestring(time(NULL)), (int)getpid(), buf); fflush(logfile_fp); } else { syslog(priority, "%s", buf); } } static void syslog_init() { int options = LOG_PID; #ifdef LOG_NDELAY options |= LOG_NDELAY; #endif #ifdef LOG_DAEMON openlog(lp_syslog_tag(module_id), options, lp_syslog_facility(module_id)); #else openlog(lp_syslog_tag(module_id), options); #endif #ifndef LOG_NDELAY logit(LOG_INFO, "rsyncd started\n"); #endif } static void logfile_open(void) { mode_t old_umask = umask(022 | orig_umask); logfile_fp = fopen(logfile_name, "a"); umask(old_umask); if (!logfile_fp) { int fopen_errno = errno; /* Rsync falls back to using syslog on failure. */ syslog_init(); rsyserr(FERROR, fopen_errno, "failed to open log-file %s", logfile_name); rprintf(FINFO, "Ignoring \"log file\" setting.\n"); logfile_name = ""; } } void log_init(int restart) { if (log_initialised) { if (!restart) /* Note: a restart only happens with am_daemon */ return; assert(logfile_name); /* all am_daemon procs got at least an empty string */ if (strcmp(logfile_name, lp_log_file(module_id)) != 0) { if (logfile_fp) { fclose(logfile_fp); logfile_fp = NULL; } else closelog(); logfile_name = NULL; } else if (*logfile_name) return; /* unchanged, non-empty "log file" names */ else if (lp_syslog_facility(-1) != lp_syslog_facility(module_id) || strcmp(lp_syslog_tag(-1), lp_syslog_tag(module_id)) != 0) closelog(); else return; /* unchanged syslog settings */ } else log_initialised = 1; /* This looks pointless, but it is needed in order for the * C library on some systems to fetch the timezone info * before the chroot. */ timestring(time(NULL)); /* Optionally use a log file instead of syslog. (Non-daemon * rsyncs will have already set logfile_name, as needed.) */ if (am_daemon && !logfile_name) logfile_name = lp_log_file(module_id); if (logfile_name && *logfile_name) logfile_open(); else syslog_init(); } /* Note that this close & reopen idiom intentionally ignores syslog logging. */ void logfile_close(void) { if (logfile_fp) { logfile_was_closed = 1; fclose(logfile_fp); logfile_fp = NULL; } } void logfile_reopen(void) { if (logfile_was_closed) { logfile_was_closed = 0; logfile_open(); } } static void filtered_fwrite(FILE *f, const char *in_buf, int in_len, int use_isprint, char end_char) { char outbuf[1024], *ob = outbuf; const char *end = in_buf + in_len; while (in_buf < end) { if (ob - outbuf >= (int)sizeof outbuf - 10) { if (fwrite(outbuf, ob - outbuf, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO); ob = outbuf; } if ((in_buf < end - 4 && *in_buf == '\\' && in_buf[1] == '#' && isDigit(in_buf + 2) && isDigit(in_buf + 3) && isDigit(in_buf + 4)) || (*in_buf != '\t' && ((use_isprint && !isPrint(in_buf)) || *(uchar*)in_buf < ' '))) ob += snprintf(ob, 6, "\\#%03o", *(uchar*)in_buf++); else *ob++ = *in_buf++; } if (end_char) /* The "- 10" above means that there is always room for one more char here. */ *ob++ = end_char; if (ob != outbuf && fwrite(outbuf, ob - outbuf, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO); } /* this is the underlying (unformatted) rsync debugging function. Call * it with FINFO, FERROR_*, FWARNING, FLOG, or FCLIENT. Note: recursion * can happen with certain fatal conditions. */ void rwrite(enum logcode code, const char *buf, int len, int is_utf8) { char trailing_CR_or_NL; FILE *f = msgs2stderr == 1 ? stderr : stdout; #ifdef ICONV_OPTION iconv_t ic = is_utf8 && ic_recv != (iconv_t)-1 ? ic_recv : ic_chck; #else #ifdef ICONV_CONST iconv_t ic = ic_chck; #endif #endif if (len < 0) exit_cleanup(RERR_MESSAGEIO); if (msgs2stderr == 1) { /* A normal daemon can get msgs2stderr set if the socket is busted, so we * change the message destination into an FLOG message in order to try to * get some info about an abnormal-exit into the log file. An rsh daemon * can have this set via user request, so we'll leave the code alone so * that the msg gets logged and then sent to stderr after that. */ if (am_daemon > 0 && code != FCLIENT) code = FLOG; } else if (send_msgs_to_gen) { assert(!is_utf8); /* Pass the message to our sibling in native charset. */ send_msg((enum msgcode)code, buf, len, 0); return; } if (code == FERROR_SOCKET) /* This gets simplified for a non-sibling. */ code = FERROR; else if (code == FERROR_UTF8) { is_utf8 = 1; code = FERROR; } if (code == FCLIENT) code = FINFO; else if (am_daemon || logfile_name) { static int in_block; char msg[2048]; int priority = code == FINFO || code == FLOG ? LOG_INFO : LOG_WARNING; if (in_block) return; in_block = 1; if (!log_initialised) log_init(0); strlcpy(msg, buf, MIN((int)sizeof msg, len + 1)); logit(priority, msg); in_block = 0; if (code == FLOG || (am_daemon && !am_server)) return; } else if (code == FLOG) return; switch (code) { case FERROR_XFER: got_xfer_error = 1; /* FALL THROUGH */ case FERROR: case FWARNING: f = stderr; break; case FINFO: if (quiet) return; break; /*case FLOG:*/ /*case FCLIENT:*/ /*case FERROR_UTF8:*/ /*case FERROR_SOCKET:*/ default: fprintf(stderr, "Bad logcode in rwrite(): %d [%s]\n", (int)code, who_am_i()); exit_cleanup(RERR_MESSAGEIO); } if (am_server && msgs2stderr != 1 && (msgs2stderr != 2 || f != stderr)) { enum msgcode msg = (enum msgcode)code; if (protocol_version < 30) { if (msg == MSG_ERROR) msg = MSG_ERROR_XFER; else if (msg == MSG_WARNING) msg = MSG_INFO; } /* Pass the message to the non-server side. */ if (send_msg(msg, buf, len, !is_utf8)) return; if (am_daemon > 0) { /* TODO: can we send the error to the user somehow? */ return; } f = stderr; } if (output_needs_newline) { fputc('\n', f); output_needs_newline = 0; } trailing_CR_or_NL = len && (buf[len-1] == '\n' || buf[len-1] == '\r') ? buf[--len] : '\0'; if (len && buf[0] == '\r') { fputc('\r', f); buf++; len--; } #ifdef ICONV_CONST if (ic != (iconv_t)-1) { xbuf outbuf, inbuf; char convbuf[1024]; int ierrno; INIT_CONST_XBUF(outbuf, convbuf); INIT_XBUF(inbuf, (char*)buf, len, (size_t)-1); while (inbuf.len) { iconvbufs(ic, &inbuf, &outbuf, inbuf.pos ? 0 : ICB_INIT); ierrno = errno; if (outbuf.len) { char trailing = inbuf.len ? '\0' : trailing_CR_or_NL; filtered_fwrite(f, convbuf, outbuf.len, 0, trailing); if (trailing) { trailing_CR_or_NL = '\0'; fflush(f); } outbuf.len = 0; } /* Log one byte of illegal/incomplete sequence and continue with * the next character. Check that the buffer is non-empty for the * sake of robustness. */ if ((ierrno == EILSEQ || ierrno == EINVAL) && inbuf.len) { fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++)); inbuf.len--; } } if (trailing_CR_or_NL) { fputc(trailing_CR_or_NL, f); fflush(f); } } else #endif { filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL); if (trailing_CR_or_NL) fflush(f); } } /* This is the rsync debugging function. Call it with FINFO, FERROR_*, * FWARNING, FLOG, or FCLIENT. */ void rprintf(enum logcode code, const char *format, ...) { va_list ap; char buf[BIGPATHBUFLEN]; size_t len; va_start(ap, format); len = vsnprintf(buf, sizeof buf, format, ap); va_end(ap); /* Deal with buffer overruns. Instead of panicking, just * truncate the resulting string. (Note that configure ensures * that we have a vsnprintf() that doesn't ever return -1.) */ if (len > sizeof buf - 1) { static const char ellipsis[] = "[...]"; /* Reset length, and zero-terminate the end of our buffer */ len = sizeof buf - 1; buf[len] = '\0'; /* Copy the ellipsis to the end of the string, but give * us one extra character: * * v--- null byte at buf[sizeof buf - 1] * abcdefghij0 * -> abcd[...]00 <-- now two null bytes at end * * If the input format string has a trailing newline, * we copy it into that extra null; if it doesn't, well, * all we lose is one byte. */ memcpy(buf+len-sizeof ellipsis, ellipsis, sizeof ellipsis); if (format[strlen(format)-1] == '\n') { buf[len-1] = '\n'; } } rwrite(code, buf, len, 0); } /* This is like rprintf, but it also tries to print some * representation of the error code. Normally errcode = errno. * * Unlike rprintf, this always adds a newline and there should not be * one in the format string. * * Note that since strerror might involve dynamically loading a * message catalog we need to call it once before chroot-ing. */ void rsyserr(enum logcode code, int errcode, const char *format, ...) { va_list ap; char buf[BIGPATHBUFLEN]; size_t len; len = snprintf(buf, sizeof buf, RSYNC_NAME ": [%s] ", who_am_i()); va_start(ap, format); len += vsnprintf(buf + len, sizeof buf - len, format, ap); va_end(ap); if (len < sizeof buf) { len += snprintf(buf + len, sizeof buf - len, ": %s (%d)\n", strerror(errcode), errcode); } if (len >= sizeof buf) exit_cleanup(RERR_MESSAGEIO); rwrite(code, buf, len, 0); } void rflush(enum logcode code) { FILE *f; if (am_daemon || code == FLOG) return; if (!am_server && (code == FINFO || code == FCLIENT)) f = stdout; else f = stderr; fflush(f); } void remember_initial_stats(void) { initial_data_read = total_data_read; initial_data_written = total_data_written; } /* A generic logging routine for send/recv, with parameter substitiution. */ static void log_formatted(enum logcode code, const char *format, const char *op, struct file_struct *file, const char *fname, int iflags, const char *hlink) { char buf[MAXPATHLEN+1024], buf2[MAXPATHLEN], fmt[32]; char *p, *s, *c; const char *n; size_t len, total; int64 b; *fmt = '%'; /* We expand % codes one by one in place in buf. We don't * copy in the terminating null of the inserted strings, but * rather keep going until we reach the null of the format. */ total = strlcpy(buf, format, sizeof buf); if (total > MAXPATHLEN) { rprintf(FERROR, "log-format string is WAY too long!\n"); exit_cleanup(RERR_MESSAGEIO); } buf[total++] = '\n'; buf[total] = '\0'; for (p = buf; (p = strchr(p, '%')) != NULL; ) { int humanize = 0; s = p++; c = fmt + 1; while (*p == '\'') { humanize++; p++; } if (*p == '-') *c++ = *p++; while (isDigit(p) && c - fmt < (int)(sizeof fmt) - 8) *c++ = *p++; while (*p == '\'') { humanize++; p++; } if (!*p) break; *c = '\0'; n = NULL; /* Note for %h and %a: it doesn't matter what fd we pass to * client_{name,addr} because rsync_module will already have * forced the answer to be cached (assuming, of course, for %h * that lp_reverse_lookup(module_id) is true). */ switch (*p) { case 'h': if (am_daemon) { n = lp_reverse_lookup(module_id) ? client_name(0) : undetermined_hostname; } break; case 'a': if (am_daemon) n = client_addr(0); break; case 'l': strlcat(fmt, "s", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, do_big_num(F_LENGTH(file), humanize, NULL)); n = buf2; break; case 'U': strlcat(fmt, "u", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, uid_ndx ? F_OWNER(file) : 0); n = buf2; break; case 'G': if (!gid_ndx || file->flags & FLAG_SKIP_GROUP) n = "DEFAULT"; else { strlcat(fmt, "u", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, F_GROUP(file)); n = buf2; } break; case 'p': strlcat(fmt, "d", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, (int)getpid()); n = buf2; break; case 'M': n = c = timestring(file->modtime); while ((c = strchr(c, ' ')) != NULL) *c = '-'; break; case 'B': c = buf2 + MAXPATHLEN - PERMSTRING_SIZE - 1; permstring(c, file->mode); n = c + 1; /* skip the type char */ break; case 'o': n = op; break; case 'f': if (fname) { c = f_name_buf(); strlcpy(c, fname, MAXPATHLEN); } else c = f_name(file, NULL); if (am_sender && F_PATHNAME(file)) { pathjoin(buf2, sizeof buf2, F_PATHNAME(file), c); clean_fname(buf2, 0); if (fmt[1]) { strlcpy(c, buf2, MAXPATHLEN); n = c; } else n = buf2; } else if (am_daemon && *c != '/') { pathjoin(buf2, sizeof buf2, curr_dir + module_dirlen, c); clean_fname(buf2, 0); if (fmt[1]) { strlcpy(c, buf2, MAXPATHLEN); n = c; } else n = buf2; } else { clean_fname(c, 0); n = c; } if (*n == '/') n++; break; case 'n': if (fname) { c = f_name_buf(); strlcpy(c, fname, MAXPATHLEN); } else c = f_name(file, NULL); if (S_ISDIR(file->mode)) strlcat(c, "/", MAXPATHLEN); n = c; break; case 'L': if (hlink && *hlink) { n = hlink; strlcpy(buf2, " => ", sizeof buf2); } else if (S_ISLNK(file->mode) && !fname) { n = F_SYMLINK(file); strlcpy(buf2, " -> ", sizeof buf2); } else { n = ""; if (!fmt[1]) break; strlcpy(buf2, " ", sizeof buf2); } strlcat(fmt, "s", sizeof fmt); snprintf(buf2 + 4, sizeof buf2 - 4, fmt, n); n = buf2; break; case 'm': n = lp_name(module_id); break; case 't': n = timestring(time(NULL)); break; case 'P': n = full_module_path; break; case 'u': n = auth_user; break; case 'b': case 'c': if (!(iflags & ITEM_TRANSFER)) b = 0; else if ((!!am_sender) ^ (*p == 'c')) b = total_data_written - initial_data_written; else b = total_data_read - initial_data_read; strlcat(fmt, "s", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, do_big_num(b, humanize, NULL)); n = buf2; break; case 'C': n = NULL; if (S_ISREG(file->mode)) { if (always_checksum) n = sum_as_hex(file_sum_nni->num, F_SUM(file), 1); else if (iflags & ITEM_TRANSFER) n = sum_as_hex(xfer_sum_nni->num, sender_file_sum, 0); } if (!n) { int sum_len = csum_len_for_type(always_checksum ? file_sum_nni->num : xfer_sum_nni->num, always_checksum); memset(buf2, ' ', sum_len*2); buf2[sum_len*2] = '\0'; n = buf2; } break; case 'i': if (iflags & ITEM_DELETED) { n = "*deleting "; break; } n = c = buf2 + MAXPATHLEN - 32; c[0] = iflags & ITEM_LOCAL_CHANGE ? iflags & ITEM_XNAME_FOLLOWS ? 'h' : 'c' : !(iflags & ITEM_TRANSFER) ? '.' : !local_server && *op == 's' ? '<' : '>'; if (S_ISLNK(file->mode)) { c[1] = 'L'; c[3] = '.'; c[4] = !(iflags & ITEM_REPORT_TIME) ? '.' : !preserve_mtimes || !receiver_symlink_times || (iflags & ITEM_REPORT_TIMEFAIL) ? 'T' : 't'; } else { c[1] = S_ISDIR(file->mode) ? 'd' : IS_SPECIAL(file->mode) ? 'S' : IS_DEVICE(file->mode) ? 'D' : 'f'; c[3] = !(iflags & ITEM_REPORT_SIZE) ? '.' : 's'; c[4] = !(iflags & ITEM_REPORT_TIME) ? '.' : !preserve_mtimes ? 'T' : 't'; } c[2] = !(iflags & ITEM_REPORT_CHANGE) ? '.' : 'c'; c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; c[8] = !(iflags & (ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME)) ? '.' : BITS_SET(iflags, ITEM_REPORT_ATIME|ITEM_REPORT_CRTIME) ? 'b' : iflags & ITEM_REPORT_ATIME ? 'u' : 'n'; c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; c[11] = '\0'; if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) { char ch = iflags & ITEM_IS_NEW ? '+' : '?'; int i; for (i = 2; c[i]; i++) c[i] = ch; } else if (c[0] == '.' || c[0] == 'h' || c[0] == 'c') { int i; for (i = 2; c[i]; i++) { if (c[i] != '.') break; } if (!c[i]) { for (i = 2; c[i]; i++) c[i] = ' '; } } break; } /* "n" is the string to be inserted in place of this % code. */ if (!n) continue; if (n != buf2 && fmt[1]) { strlcat(fmt, "s", sizeof fmt); snprintf(buf2, sizeof buf2, fmt, n); n = buf2; } len = strlen(n); /* Subtract the length of the escape from the string's size. */ total -= p - s + 1; if (len + total >= (size_t)sizeof buf) { rprintf(FERROR, "buffer overflow expanding %%%c -- exiting\n", p[0]); exit_cleanup(RERR_MESSAGEIO); } /* Shuffle the rest of the string along to make space for n */ if (len != (size_t)(p - s + 1)) memmove(s + len, p + 1, total - (s - buf) + 1); total += len; /* Insert the contents of string "n", but NOT its null. */ if (len) memcpy(s, n, len); /* Skip over inserted string; continue looking */ p = s + len; } rwrite(code, buf, total, 0); } /* Return 1 if the format escape is in the log-format string (e.g. look for * the 'b' in the "%9b" format escape). */ int log_format_has(const char *format, char esc) { const char *p; if (!format) return 0; for (p = format; (p = strchr(p, '%')) != NULL; ) { for (p++; *p == '\''; p++) {} /*SHARED ITERATOR*/ if (*p == '-') p++; while (isDigit(p)) p++; while (*p == '\'') p++; if (!*p) break; if (*p == esc) return 1; } return 0; } /* Log the transfer of a file. If the code is FCLIENT, the output just goes * to stdout. If it is FLOG, it just goes to the log file. Otherwise we * output to both. */ void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink) { const char *s_or_r = am_sender ? "send" : "recv"; if (code != FLOG && stdout_format && !am_server) log_formatted(FCLIENT, stdout_format, s_or_r, file, NULL, iflags, hlink); if (code != FCLIENT && logfile_format && *logfile_format) log_formatted(FLOG, logfile_format, s_or_r, file, NULL, iflags, hlink); } void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf) { int significant_flags = iflags & SIGNIFICANT_ITEM_FLAGS; int see_item = itemizing && (significant_flags || *buf || stdout_format_has_i > 1 || (INFO_GTE(NAME, 2) && stdout_format_has_i)); int local_change = iflags & ITEM_LOCAL_CHANGE && significant_flags; if (am_server) { if (logfile_name && !dry_run && see_item && (significant_flags || logfile_format_has_i)) log_item(FLOG, file, iflags, buf); } else if (see_item || local_change || *buf || (S_ISDIR(file->mode) && significant_flags)) { enum logcode code = significant_flags || logfile_format_has_i ? FINFO : FCLIENT; log_item(code, file, iflags, buf); } } void log_delete(const char *fname, int mode) { static struct file_struct *file = NULL; int len = strlen(fname); const char *fmt; if (!file) { int extra_len = (file_extra_cnt + 2) * EXTRA_LEN; char *bp; #if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN; #endif bp = new_array0(char, FILE_STRUCT_LEN + extra_len + 1); bp += extra_len; file = (struct file_struct *)bp; } file->mode = mode; if (am_server && protocol_version >= 29 && len < MAXPATHLEN) { if (S_ISDIR(mode)) len++; /* directories include trailing null */ send_msg(MSG_DELETED, fname, len, am_generator); } else if (!INFO_GTE(DEL, 1) && !stdout_format) ; else { fmt = stdout_format_has_o_or_i ? stdout_format : "deleting %n"; log_formatted(FCLIENT, fmt, "del.", file, fname, ITEM_DELETED, NULL); } if (!logfile_name || dry_run || !logfile_format) return; fmt = logfile_format_has_o_or_i ? logfile_format : "deleting %n"; log_formatted(FLOG, fmt, "del.", file, fname, ITEM_DELETED, NULL); } /* * Called when the transfer is interrupted for some reason. * * Code is one of the RERR_* codes from errcode.h, or terminating * successfully. */ void log_exit(int code, const char *file, int line) { /* The receiving side's stats are split between 2 procs until the * end of the run, so only the sender can output non-final info. */ if (code == 0 || am_sender) { rprintf(FLOG,"sent %s bytes received %s bytes total size %s\n", big_num(stats.total_written), big_num(stats.total_read), big_num(stats.total_size)); } if (code != 0 && am_server != 2) { const char *name; name = rerr_name(code); if (!name) name = "unexplained error"; /* VANISHED is not an error, only a warning */ if (code == RERR_VANISHED) { rprintf(FWARNING, "rsync warning: %s (code %d) at %s(%d) [%s=%s]\n", name, code, src_file(file), line, who_am_i(), rsync_version()); } else { rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n", name, code, src_file(file), line, who_am_i(), rsync_version()); } } } rsync-3.2.7/rsync.10000664000000000000000000071024614324367163012624 0ustar rootroot.TH "rsync" "1" "20 Oct 2022" "rsync 3.2.7" "User Commands" .\" prefix=/usr .P .SH "NAME" .P rsync \- a fast, versatile, remote (and local) file-copying tool .P .SH "SYNOPSIS" .P .nf Local: rsync [OPTION...] SRC... [DEST] Access via remote shell: Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST:DEST Access via rsync daemon: Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST] rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST::DEST rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST) .fi .P Usages with just one SRC arg and no DEST arg will list the source files instead of copying. .P The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rsync.1. .P .SH "DESCRIPTION" .P Rsync is a fast and extraordinarily versatile file copying tool. It can copy locally, to/from another host over any remote shell, or to/from a remote rsync daemon. It offers a large number of options that control every aspect of its behavior and permit very flexible specification of the set of files to be copied. It is famous for its delta-transfer algorithm, which reduces the amount of data sent over the network by sending only the differences between the source files and the existing files in the destination. Rsync is widely used for backups and mirroring and as an improved copy command for everyday use. .P Rsync finds files that need to be transferred using a "quick check" algorithm (by default) that looks for files that have changed in size or in last-modified time. Any changes in the other preserved attributes (as requested by options) are made on the destination file directly when the quick check indicates that the file's data does not need to be updated. .P Some of the additional features of rsync are: .P .IP o support for copying links, devices, owners, groups, and permissions .IP o exclude and exclude-from options similar to GNU tar .IP o a CVS exclude mode for ignoring the same files that CVS would ignore .IP o can use any transparent remote shell, including ssh or rsh .IP o does not require super-user privileges .IP o pipelining of file transfers to minimize latency costs .IP o support for anonymous or authenticated rsync daemons (ideal for mirroring) .P .SH "GENERAL" .P Rsync copies files either to or from a remote host, or locally on the current host (it does not support copying files between two remote hosts). .P There are two different ways for rsync to contact a remote system: using a remote-shell program as the transport (such as ssh or rsh) or contacting an rsync daemon directly via TCP. The remote-shell transport is used whenever the source or destination path contains a single colon (:) separator after a host specification. Contacting an rsync daemon directly happens when the source or destination path contains a double colon (::) separator after a host specification, OR when an rsync:// URL is specified (see also the USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION section for an exception to this latter rule). .P As a special case, if a single source arg is specified without a destination, the files are listed in an output format similar to "\fBls\ \-l\fP". .P As expected, if neither the source or destination path specify a remote host, the copy occurs locally (see also the \fB\-\-list-only\fP option). .P Rsync refers to the local side as the client and the remote side as the server. Don't confuse server with an rsync daemon. A daemon is always a server, but a server can be either a daemon or a remote-shell spawned process. .P .SH "SETUP" .P See the file README.md for installation instructions. .P Once installed, you can use rsync to any machine that you can access via a remote shell (as well as some that you can access using the rsync daemon-mode protocol). For remote transfers, a modern rsync uses ssh for its communications, but it may have been configured to use a different remote shell by default, such as rsh or remsh. .P You can also specify any remote shell you like, either by using the \fB\-e\fP command line option, or by setting the \fBRSYNC_RSH\fP environment variable. .P Note that rsync must be installed on both the source and destination machines. .P .SH "USAGE" .P You use rsync in the same way you use rcp. You must specify a source and a destination, one of which may be remote. .P Perhaps the best way to explain the syntax is with some examples: .RS 4 .P .nf rsync -t *.c foo:src/ .fi .RE .P This would transfer all files matching the pattern \fB*.c\fP from the current directory to the directory src on the machine foo. If any of the files already exist on the remote system then the rsync remote-update protocol is used to update the file by sending only the differences in the data. Note that the expansion of wildcards on the command-line (\fB*.c\fP) into a list of files is handled by the shell before it runs rsync and not by rsync itself (exactly the same as all other Posix-style programs). .RS 4 .P .nf rsync -avz foo:src/bar /data/tmp .fi .RE .P This would recursively transfer all files from the directory src/bar on the machine foo into the /data/tmp/bar directory on the local machine. The files are transferred in archive mode, which ensures that symbolic links, devices, attributes, permissions, ownerships, etc. are preserved in the transfer. Additionally, compression will be used to reduce the size of data portions of the transfer. .RS 4 .P .nf rsync -avz foo:src/bar/ /data/tmp .fi .RE .P A trailing slash on the source changes this behavior to avoid creating an additional directory level at the destination. You can think of a trailing / on a source as meaning "copy the contents of this directory" as opposed to "copy the directory by name", but in both cases the attributes of the containing directory are transferred to the containing directory on the destination. In other words, each of the following commands copies the files in the same way, including their setting of the attributes of /dest/foo: .RS 4 .P .nf rsync -av /src/foo /dest rsync -av /src/foo/ /dest/foo .fi .RE .P Note also that host and module references don't require a trailing slash to copy the contents of the default directory. For example, both of these copy the remote directory's contents into "/dest": .RS 4 .P .nf rsync -av host: /dest rsync -av host::module /dest .fi .RE .P You can also use rsync in local-only mode, where both the source and destination don't have a ':' in the name. In this case it behaves like an improved copy command. .P Finally, you can list all the (listable) modules available from a particular rsync daemon by leaving off the module name: .RS 4 .P .nf rsync somehost.mydomain.com:: .fi .RE .P .SH "COPYING TO A DIFFERENT NAME" .P When you want to copy a directory to a different name, use a trailing slash on the source directory to put the contents of the directory into any destination directory you like: .RS 4 .P .nf rsync -ai foo/ bar/ .fi .RE .P Rsync also has the ability to customize a destination file's name when copying a single item. The rules for this are: .P .IP o The transfer list must consist of a single item (either a file or an empty directory) .IP o The final element of the destination path must not exist as a directory .IP o The destination path must not have been specified with a trailing slash .P Under those circumstances, rsync will set the name of the destination's single item to the last element of the destination path. Keep in mind that it is best to only use this idiom when copying a file and use the above trailing-slash idiom when copying a directory. .P The following example copies the \fBfoo.c\fP file as \fBbar.c\fP in the \fBsave\fP dir (assuming that \fBbar.c\fP isn't a directory): .RS 4 .P .nf rsync -ai src/foo.c save/bar.c .fi .RE .P The single-item copy rule might accidentally bite you if you unknowingly copy a single item and specify a destination dir that doesn't exist (without using a trailing slash). For example, if \fBsrc/*.c\fP matches one file and \fBsave/dir\fP doesn't exist, this will confuse you by naming the destination file \fBsave/dir\fP: .RS 4 .P .nf rsync -ai src/*.c save/dir .fi .RE .P To prevent such an accident, either make sure the destination dir exists or specify the destination path with a trailing slash: .RS 4 .P .nf rsync -ai src/*.c save/dir/ .fi .RE .P .SH "SORTED TRANSFER ORDER" .P Rsync always sorts the specified filenames into its internal transfer list. This handles the merging together of the contents of identically named directories, makes it easy to remove duplicate filenames. It can, however, confuse someone when the files are transferred in a different order than what was given on the command-line. .P If you need a particular file to be transferred prior to another, either separate the files into different rsync calls, or consider using \fB\-\-delay-updates\fP (which doesn't affect the sorted transfer order, but does make the final file-updating phase happen much more rapidly). .P .SH "MULTI-HOST SECURITY" .P Rsync takes steps to ensure that the file requests that are shared in a transfer are protected against various security issues. Most of the potential problems arise on the receiving side where rsync takes steps to ensure that the list of files being transferred remains within the bounds of what was requested. .P Toward this end, rsync 3.1.2 and later have aborted when a file list contains an absolute or relative path that tries to escape out of the top of the transfer. Also, beginning with version 3.2.5, rsync does two more safety checks of the file list to (1) ensure that no extra source arguments were added into the transfer other than those that the client requested and (2) ensure that the file list obeys the exclude rules that were sent to the sender. .P For those that don't yet have a 3.2.5 client rsync (or those that want to be extra careful), it is safest to do a copy into a dedicated destination directory for the remote files when you don't trust the remote host. For example, instead of doing an rsync copy into your home directory: .RS 4 .P .nf rsync -aiv host1:dir1 ~ .fi .RE .P Dedicate a "host1-files" dir to the remote content: .RS 4 .P .nf rsync -aiv host1:dir1 ~/host1-files .fi .RE .P See the \fB\-\-trust-sender\fP option for additional details. .P CAUTION: it is not particularly safe to use rsync to copy files from a case-preserving filesystem to a case-ignoring filesystem. If you must perform such a copy, you should either disable symlinks via \fB\-\-no-links\fP or enable the munging of symlinks via \fB\-\-munge-links\fP (and make sure you use the right local or remote option). This will prevent rsync from doing potentially dangerous things if a symlink name overlaps with a file or directory. It does not, however, ensure that you get a full copy of all the files (since that may not be possible when the names overlap). A potentially better solution is to list all the source files and create a safe list of filenames that you pass to the \fB\-\-files-from\fP option. Any files that conflict in name would need to be copied to different destination directories using more than one copy. .P While a copy of a case-ignoring filesystem to a case-ignoring filesystem can work out fairly well, if no \fB\-\-delete-during\fP or \fB\-\-delete-before\fP option is active, rsync can potentially update an existing file on the receiveing side without noticing that the upper-/lower-case of the filename should be changed to match the sender. .P .SH "ADVANCED USAGE" .P The syntax for requesting multiple files from a remote host is done by specifying additional remote-host args in the same style as the first, or with the hostname omitted. For instance, all these work: .RS 4 .P .nf rsync -aiv host:file1 :file2 host:file{3,4} /dest/ rsync -aiv host::modname/file{1,2} host::modname/extra /dest/ rsync -aiv host::modname/first ::extra-file{1,2} /dest/ .fi .RE .P Note that a daemon connection only supports accessing one module per copy command, so if the start of a follow-up path doesn't begin with the modname of the first path, it is assumed to be a path in the module (such as the extra-file1 & extra-file2 that are grabbed above). .P Really old versions of rsync (2.6.9 and before) only allowed specifying one remote-source arg, so some people have instead relied on the remote-shell performing space splitting to break up an arg into multiple paths. Such unintuitive behavior is no longer supported by default (though you can request it, as described below). .P Starting in 3.2.4, filenames are passed to a remote shell in such a way as to preserve the characters you give it. Thus, if you ask for a file with spaces in the name, that's what the remote rsync looks for: .RS 4 .P .nf rsync -aiv host:'a simple file.pdf' /dest/ .fi .RE .P If you use scripts that have been written to manually apply extra quoting to the remote rsync args (or to require remote arg splitting), you can ask rsync to let your script handle the extra escaping. This is done by either adding the \fB\-\-old-args\fP option to the rsync runs in the script (which requires a new rsync) or exporting RSYNC_OLD_ARGS=1 and RSYNC_PROTECT_ARGS=0 (which works with old or new rsync versions). .P .SH "CONNECTING TO AN RSYNC DAEMON" .P It is also possible to use rsync without a remote shell as the transport. In this case you will directly connect to a remote rsync daemon, typically using TCP port 873. (This obviously requires the daemon to be running on the remote system, so refer to the STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS section below for information on that.) .P Using rsync in this way is the same as using it with a remote shell except that: .P .IP o Use either double-colon syntax or rsync:// URL syntax instead of the single-colon (remote shell) syntax. .IP o The first element of the "path" is actually a module name. .IP o Additional remote source args can use an abbreviated syntax that omits the hostname and/or the module name, as discussed in ADVANCED USAGE. .IP o The remote daemon may print a "message of the day" when you connect. .IP o If you specify only the host (with no module or path) then a list of accessible modules on the daemon is output. .IP o If you specify a remote source path but no destination, a listing of the matching files on the remote daemon is output. .IP o The \fB\-\-rsh\fP (\fB\-e\fP) option must be omitted to avoid changing the connection style from using a socket connection to USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION. .P An example that copies all the files in a remote module named "src": .RS 4 .P .nf rsync -av host::src /dest .fi .RE .P Some modules on the remote daemon may require authentication. If so, you will receive a password prompt when you connect. You can avoid the password prompt by setting the environment variable \fBRSYNC_PASSWORD\fP to the password you want to use or using the \fB\-\-password-file\fP option. This may be useful when scripting rsync. .P WARNING: On some systems environment variables are visible to all users. On those systems using \fB\-\-password-file\fP is recommended. .P You may establish the connection via a web proxy by setting the environment variable \fBRSYNC_PROXY\fP to a hostname:port pair pointing to your web proxy. Note that your web proxy's configuration must support proxy connections to port 873. .P You may also establish a daemon connection using a program as a proxy by setting the environment variable \fBRSYNC_CONNECT_PROG\fP to the commands you wish to run in place of making a direct socket connection. The string may contain the escape "%H" to represent the hostname specified in the rsync command (so use "%%" if you need a single "%" in your string). For example: .RS 4 .P .nf export RSYNC_CONNECT_PROG='ssh proxyhost nc %H 873' rsync -av targethost1::module/src/ /dest/ rsync -av rsync://targethost2/module/src/ /dest/ .fi .RE .P The command specified above uses ssh to run nc (netcat) on a proxyhost, which forwards all data to port 873 (the rsync daemon) on the targethost (%H). .P Note also that if the \fBRSYNC_SHELL\fP environment variable is set, that program will be used to run the \fBRSYNC_CONNECT_PROG\fP command instead of using the default shell of the \fBsystem()\fP call. .P .SH "USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION" .P It is sometimes useful to use various features of an rsync daemon (such as named modules) without actually allowing any new socket connections into a system (other than what is already required to allow remote-shell access). Rsync supports connecting to a host using a remote shell and then spawning a single-use "daemon" server that expects to read its config file in the home dir of the remote user. This can be useful if you want to encrypt a daemon-style transfer's data, but since the daemon is started up fresh by the remote user, you may not be able to use features such as chroot or change the uid used by the daemon. (For another way to encrypt a daemon transfer, consider using ssh to tunnel a local port to a remote machine and configure a normal rsync daemon on that remote host to only allow connections from "localhost".) .P From the user's perspective, a daemon transfer via a remote-shell connection uses nearly the same command-line syntax as a normal rsync-daemon transfer, with the only exception being that you must explicitly set the remote shell program on the command-line with the \fB\-\-rsh=COMMAND\fP option. (Setting the RSYNC_RSH in the environment will not turn on this functionality.) For example: .RS 4 .P .nf rsync -av --rsh=ssh host::module /dest .fi .RE .P If you need to specify a different remote-shell user, keep in mind that the user@ prefix in front of the host is specifying the rsync-user value (for a module that requires user-based authentication). This means that you must give the '\-l user' option to ssh when specifying the remote-shell, as in this example that uses the short version of the \fB\-\-rsh\fP option: .RS 4 .P .nf rsync -av -e "ssh -l ssh-user" rsync-user@host::module /dest .fi .RE .P The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to log-in to the "module". .P In this setup, the daemon is started by the ssh command that is accessing the system (which can be forced via the \fB~/.ssh/authorized_keys\fP file, if desired). However, when accessing a daemon directly, it needs to be started beforehand. .P .SH "STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS" .P In order to connect to an rsync daemon, the remote system needs to have a daemon already running (or it needs to have configured something like inetd to spawn an rsync daemon for incoming connections on a particular port). For full information on how to start a daemon that will handling incoming socket connections, see the \fBrsyncd.conf\fP(5) manpage\ \-\- that is the config file for the daemon, and it contains the full details for how to run the daemon (including stand-alone and inetd configurations). .P If you're using one of the remote-shell transports for the transfer, there is no need to manually start an rsync daemon. .P .SH "EXAMPLES" .P Here are some examples of how rsync can be used. .P To backup a home directory, which consists of large MS Word files and mail folders, a per-user cron job can be used that runs this each day: .RS 4 .P .nf rsync -aiz . bkhost:backup/joe/ .fi .RE .P To move some files from a remote host to the local host, you could run: .RS 4 .P .nf rsync -aiv --remove-source-files rhost:/tmp/{file1,file2}.c ~/src/ .fi .RE .P .SH "OPTION SUMMARY" .P Here is a short summary of the options available in rsync. Each option also has its own detailed description later in this manpage. .P .nf --verbose, -v increase verbosity --info=FLAGS fine-grained informational verbosity --debug=FLAGS fine-grained debug verbosity --stderr=e|a|c change stderr output mode (default: errors) --quiet, -q suppress non-error messages --no-motd suppress daemon-mode MOTD --checksum, -c skip based on checksum, not mod-time & size --archive, -a archive mode is -rlptgoD (no -A,-X,-U,-N,-H) --no-OPTION turn off an implied OPTION (e.g. --no-D) --recursive, -r recurse into directories --relative, -R use relative path names --no-implied-dirs don't send implied dirs with --relative --backup, -b make backups (see --suffix & --backup-dir) --backup-dir=DIR make backups into hierarchy based in DIR --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) --update, -u skip files that are newer on the receiver --inplace update destination files in-place --append append data onto shorter files --append-verify --append w/old data in file checksum --dirs, -d transfer directories without recursing --old-dirs, --old-d works like --dirs when talking to old rsync --mkpath create destination's missing path components --links, -l copy symlinks as symlinks --copy-links, -L transform symlink into referent file/dir --copy-unsafe-links only "unsafe" symlinks are transformed --safe-links ignore symlinks that point outside the tree --munge-links munge symlinks to make them safe & unusable --copy-dirlinks, -k transform symlink to dir into referent dir --keep-dirlinks, -K treat symlinked dir on receiver as dir --hard-links, -H preserve hard links --perms, -p preserve permissions --executability, -E preserve executability --chmod=CHMOD affect file and/or directory permissions --acls, -A preserve ACLs (implies --perms) --xattrs, -X preserve extended attributes --owner, -o preserve owner (super-user only) --group, -g preserve group --devices preserve device files (super-user only) --copy-devices copy device contents as a regular file --write-devices write to devices as files (implies --inplace) --specials preserve special files -D same as --devices --specials --times, -t preserve modification times --atimes, -U preserve access (use) times --open-noatime avoid changing the atime on opened files --crtimes, -N preserve create times (newness) --omit-dir-times, -O omit directories from --times --omit-link-times, -J omit symlinks from --times --super receiver attempts super-user activities --fake-super store/recover privileged attrs using xattrs --sparse, -S turn sequences of nulls into sparse blocks --preallocate allocate dest files before writing them --dry-run, -n perform a trial run with no changes made --whole-file, -W copy files whole (w/o delta-xfer algorithm) --checksum-choice=STR choose the checksum algorithm (aka --cc) --one-file-system, -x don't cross filesystem boundaries --block-size=SIZE, -B force a fixed checksum block-size --rsh=COMMAND, -e specify the remote shell to use --rsync-path=PROGRAM specify the rsync to run on remote machine --existing skip creating new files on receiver --ignore-existing skip updating files that exist on receiver --remove-source-files sender removes synchronized files (non-dir) --del an alias for --delete-during --delete delete extraneous files from dest dirs --delete-before receiver deletes before xfer, not during --delete-during receiver deletes during the transfer --delete-delay find deletions during, delete after --delete-after receiver deletes after transfer, not during --delete-excluded also delete excluded files from dest dirs --ignore-missing-args ignore missing source args without error --delete-missing-args delete missing source args from destination --ignore-errors delete even if there are I/O errors --force force deletion of dirs even if not empty --max-delete=NUM don't delete more than NUM files --max-size=SIZE don't transfer any file larger than SIZE --min-size=SIZE don't transfer any file smaller than SIZE --max-alloc=SIZE change a limit relating to memory alloc --partial keep partially transferred files --partial-dir=DIR put a partially transferred file into DIR --delay-updates put all updated files into place at end --prune-empty-dirs, -m prune empty directory chains from file-list --numeric-ids don't map uid/gid values by user/group name --usermap=STRING custom username mapping --groupmap=STRING custom groupname mapping --chown=USER:GROUP simple username/groupname mapping --timeout=SECONDS set I/O timeout in seconds --contimeout=SECONDS set daemon connection timeout in seconds --ignore-times, -I don't skip files that match size and time --size-only skip files that match in size --modify-window=NUM, -@ set the accuracy for mod-time comparisons --temp-dir=DIR, -T create temporary files in directory DIR --fuzzy, -y find similar file for basis if no dest file --compare-dest=DIR also compare destination files relative to DIR --copy-dest=DIR ... and include copies of unchanged files --link-dest=DIR hardlink to files in DIR when unchanged --compress, -z compress file data during the transfer --compress-choice=STR choose the compression algorithm (aka --zc) --compress-level=NUM explicitly set compression level (aka --zl) --skip-compress=LIST skip compressing files with suffix in LIST --cvs-exclude, -C auto-ignore files in the same way CVS does --filter=RULE, -f add a file-filtering RULE -F same as --filter='dir-merge /.rsync-filter' repeated: --filter='- .rsync-filter' --exclude=PATTERN exclude files matching PATTERN --exclude-from=FILE read exclude patterns from FILE --include=PATTERN don't exclude files matching PATTERN --include-from=FILE read include patterns from FILE --files-from=FILE read list of source-file names from FILE --from0, -0 all *-from/filter files are delimited by 0s --old-args disable the modern arg-protection idiom --secluded-args, -s use the protocol to safely send the args --trust-sender trust the remote sender's file list --copy-as=USER[:GROUP] specify user & optional group for the copy --address=ADDRESS bind address for outgoing socket to daemon --port=PORT specify double-colon alternate port number --sockopts=OPTIONS specify custom TCP options --blocking-io use blocking I/O for the remote shell --outbuf=N|L|B set out buffering to None, Line, or Block --stats give some file-transfer stats --8-bit-output, -8 leave high-bit chars unescaped in output --human-readable, -h output numbers in a human-readable format --progress show progress during transfer -P same as --partial --progress --itemize-changes, -i output a change-summary for all updates --remote-option=OPT, -M send OPTION to the remote side only --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 --password-file=FILE read daemon-access password from FILE --early-input=FILE use FILE for daemon's early exec input --list-only list the files instead of copying them --bwlimit=RATE limit socket I/O bandwidth --stop-after=MINS Stop rsync after MINS minutes have elapsed --stop-at=y-m-dTh:m Stop rsync at the specified point in time --fsync fsync every written file --write-batch=FILE write a batched update to FILE --only-write-batch=FILE like --write-batch but w/o updating dest --read-batch=FILE read a batched update from FILE --protocol=NUM force an older protocol version to be used --iconv=CONVERT_SPEC request charset conversion of filenames --checksum-seed=NUM set block/file checksum seed (advanced) --ipv4, -4 prefer IPv4 --ipv6, -6 prefer IPv6 --version, -V print the version + other info and exit --help, -h (*) show this help (* -h is help only on its own) .fi .P Rsync can also be run as a daemon, in which case the following options are accepted: .P .nf --daemon run as an rsync daemon --address=ADDRESS bind to the specified address --bwlimit=RATE limit socket I/O bandwidth --config=FILE specify alternate rsyncd.conf file --dparam=OVERRIDE, -M override global daemon config parameter --no-detach do not detach from the parent --port=PORT listen on alternate port number --log-file=FILE override the "log file" setting --log-file-format=FMT override the "log format" setting --sockopts=OPTIONS specify custom TCP options --verbose, -v increase verbosity --ipv4, -4 prefer IPv4 --ipv6, -6 prefer IPv6 --help, -h show this help (when used with --daemon) .fi .P .SH "OPTIONS" .P Rsync accepts both long (double-dash + word) and short (single-dash + letter) options. The full list of the available options are described below. If an option can be specified in more than one way, the choices are comma-separated. Some options only have a long variant, not a short. .P If the option takes a parameter, the parameter is only listed after the long variant, even though it must also be specified for the short. When specifying a parameter, you can either use the form \fB\-\-option=param\fP, \fB\-\-option\ param\fP, \fB\-o=param\fP, \fB\-o\ param\fP, or \fB\-oparam\fP (the latter choices assume that your option has a short variant). .P The parameter may need to be quoted in some manner for it to survive the shell's command-line parsing. Also keep in mind that a leading tilde (\fB~\fP) in a pathname is substituted by your shell, so make sure that you separate the option name from the pathname using a space if you want the local shell to expand it. .P .IP "\fB\-\-help\fP" Print a short help page describing the options available in rsync and exit. You can also use \fB\-h\fP for \fB\-\-help\fP when it is used without any other options (since it normally means \fB\-\-human-readable\fP). .IP "\fB\-\-version\fP, \fB\-V\fP" Print the rsync version plus other info and exit. When repeated, the information is output is a JSON format that is still fairly readable (client side only). .IP The output includes a list of compiled-in capabilities, a list of optimizations, the default list of checksum algorithms, the default list of compression algorithms, the default list of daemon auth digests, a link to the rsync web site, and a few other items. .IP "\fB\-\-verbose\fP, \fB\-v\fP" This option increases the amount of information you are given during the transfer. By default, rsync works silently. A single \fB\-v\fP will give you information about what files are being transferred and a brief summary at the end. Two \fB\-v\fP options will give you information on what files are being skipped and slightly more information at the end. More than two \fB\-v\fP options should only be used if you are debugging rsync. .IP The end-of-run summary tells you the number of bytes sent to the remote rsync (which is the receiving side on a local copy), the number of bytes received from the remote host, and the average bytes per second of the transferred data computed over the entire length of the rsync run. The second line shows the total size (in bytes), which is the sum of all the file sizes that rsync considered transferring. It also shows a "speedup" value, which is a ratio of the total file size divided by the sum of the sent and received bytes (which is really just a feel-good bigger-is-better number). Note that these byte values can be made more (or less) human-readable by using the \fB\-\-human-readable\fP (or \fB\-\-no-human-readable\fP) options. .IP In a modern rsync, the \fB\-v\fP option is equivalent to the setting of groups of \fB\-\-info\fP and \fB\-\-debug\fP options. You can choose to use these newer options in addition to, or in place of using \fB\-\-verbose\fP, as any fine-grained settings override the implied settings of \fB\-v\fP. Both \fB\-\-info\fP and \fB\-\-debug\fP have a way to ask for help that tells you exactly what flags are set for each increase in verbosity. .IP However, do keep in mind that a daemon's "\fBmax\ verbosity\fP" setting will limit how high of a level the various individual flags can be set on the daemon side. For instance, if the max is 2, then any info and/or debug flag that is set to a higher value than what would be set by \fB\-vv\fP will be downgraded to the \fB\-vv\fP level in the daemon's logging. .IP "\fB\-\-info=FLAGS\fP" This option lets you have fine-grained control over the information output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use \fB\-\-info=help\fP to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples: .RS 4 .IP .nf rsync -a --info=progress2 src/ dest/ rsync -avv --info=stats2,misc1,flist0 src/ dest/ .fi .RE .IP Note that \fB\-\-info=name\fP's output is affected by the \fB\-\-out-format\fP and \fB\-\-itemize-changes\fP (\fB\-i\fP) options. See those options for more information on what is output and when. .IP This option was added to 3.1.0, so an older rsync on the server side might reject your attempts at fine-grained control (if one or more flags needed to be send to the server and the server was too old to understand them). See also the "\fBmax\ verbosity\fP" caveat above when dealing with a daemon. .IP "\fB\-\-debug=FLAGS\fP" This option lets you have fine-grained control over the debug output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use \fB\-\-debug=help\fP to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples: .RS 4 .IP .nf rsync -avvv --debug=none src/ dest/ rsync -avA --del --debug=del2,acl src/ dest/ .fi .RE .IP Note that some debug messages will only be output when the \fB\-\-stderr=all\fP option is specified, especially those pertaining to I/O and buffer debugging. .IP Beginning in 3.2.0, this option is no longer auto-forwarded to the server side in order to allow you to specify different debug values for each side of the transfer, as well as to specify a new debug option that is only present in one of the rsync versions. If you want to duplicate the same option on both sides, using brace expansion is an easy way to save you some typing. This works in zsh and bash: .RS 4 .IP .nf rsync -aiv {-M,}--debug=del2 src/ dest/ .fi .RE .IP "\fB\-\-stderr=errors|all|client\fP" This option controls which processes output to stderr and if info messages are also changed to stderr. The mode strings can be abbreviated, so feel free to use a single letter value. The 3 possible choices are: .IP .RS .IP o \fBerrors\fP \- (the default) causes all the rsync processes to send an error directly to stderr, even if the process is on the remote side of the transfer. Info messages are sent to the client side via the protocol stream. If stderr is not available (i.e. when directly connecting with a daemon via a socket) errors fall back to being sent via the protocol stream. .IP o \fBall\fP \- causes all rsync messages (info and error) to get written directly to stderr from all (possible) processes. This causes stderr to become line-buffered (instead of raw) and eliminates the ability to divide up the info and error messages by file handle. For those doing debugging or using several levels of verbosity, this option can help to avoid clogging up the transfer stream (which should prevent any chance of a deadlock bug hanging things up). It also allows \fB\-\-debug\fP to enable some extra I/O related messages. .IP o \fBclient\fP \- causes all rsync messages to be sent to the client side via the protocol stream. One client process outputs all messages, with errors on stderr and info messages on stdout. This \fBwas\fP the default in older rsync versions, but can cause error delays when a lot of transfer data is ahead of the messages. If you're pushing files to an older rsync, you may want to use \fB\-\-stderr=all\fP since that idiom has been around for several releases. .RE .IP This option was added in rsync 3.2.3. This version also began the forwarding of a non-default setting to the remote side, though rsync uses the backward-compatible options \fB\-\-msgs2stderr\fP and \fB\-\-no-msgs2stderr\fP to represent the \fBall\fP and \fBclient\fP settings, respectively. A newer rsync will continue to accept these older option names to maintain compatibility. .IP "\fB\-\-quiet\fP, \fB\-q\fP" This option decreases the amount of information you are given during the transfer, notably suppressing information messages from the remote server. This option is useful when invoking rsync from cron. .IP "\fB\-\-no-motd\fP" This option affects the information that is output by the client at the start of a daemon transfer. This suppresses the message-of-the-day (MOTD) text, but it also affects the list of modules that the daemon sends in response to the "rsync host::" request (due to a limitation in the rsync protocol), so omit this option if you want to request the list of modules from the daemon. .IP "\fB\-\-ignore-times\fP, \fB\-I\fP" Normally rsync will skip any files that are already the same size and have the same modification timestamp. This option turns off this "quick check" behavior, causing all files to be updated. .IP This option can be confusing compared to \fB\-\-ignore-existing\fP and \fB\-\-ignore-non-existing\fP in that that they cause rsync to transfer fewer files, while this option causes rsync to transfer more files. .IP "\fB\-\-size-only\fP" This modifies rsync's "quick check" algorithm for finding files that need to be transferred, changing it from the default of transferring files with either a changed size or a changed last-modified time to just looking for files that have changed in size. This is useful when starting to use rsync after using another mirroring system which may not preserve timestamps exactly. .IP "\fB\-\-modify-window=NUM\fP, \fB\-@\fP" When comparing two timestamps, rsync treats the timestamps as being equal if they differ by no more than the modify-window value. The default is 0, which matches just integer seconds. If you specify a negative value (and the receiver is at least version 3.1.3) then nanoseconds will also be taken into account. Specifying 1 is useful for copies to/from MS Windows FAT filesystems, because FAT represents times with a 2-second resolution (allowing times to differ from the original by up to 1 second). .IP If you want all your transfers to default to comparing nanoseconds, you can create a \fB~/.popt\fP file and put these lines in it: .RS 4 .IP .nf rsync alias -a -a@-1 rsync alias -t -t@-1 .fi .RE .IP With that as the default, you'd need to specify \fB\-\-modify-window=0\fP (aka \fB\-@0\fP) to override it and ignore nanoseconds, e.g. if you're copying between ext3 and ext4, or if the receiving rsync is older than 3.1.3. .IP "\fB\-\-checksum\fP, \fB\-c\fP" This changes the way rsync checks if the files have been changed and are in need of a transfer. Without this option, rsync uses a "quick check" that (by default) checks if each file's size and time of last modification match between the sender and receiver. This option changes this to compare a 128-bit checksum for each file that has a matching size. Generating the checksums means that both sides will expend a lot of disk I/O reading all the data in the files in the transfer, so this can slow things down significantly (and this is prior to any reading that will be done to transfer changed files) .IP The sending side generates its checksums while it is doing the file-system scan that builds the list of the available files. The receiver generates its checksums when it is scanning for changed files, and will checksum any file that has the same size as the corresponding sender's file: files with either a changed size or a changed checksum are selected for transfer. .IP Note that rsync always verifies that each \fItransferred\fP file was correctly reconstructed on the receiving side by checking a whole-file checksum that is generated as the file is transferred, but that automatic after-the-transfer verification has nothing to do with this option's before-the-transfer "Does this file need to be updated?" check. .IP The checksum used is auto-negotiated between the client and the server, but can be overridden using either the \fB\-\-checksum-choice\fP (\fB\-\-cc\fP) option or an environment variable that is discussed in that option's section. .IP "\fB\-\-archive\fP, \fB\-a\fP" This is equivalent to \fB\-rlptgoD\fP. It is a quick way of saying you want recursion and want to preserve almost everything. Be aware that it does \fBnot\fP include preserving ACLs (\fB\-A\fP), xattrs (\fB\-X\fP), atimes (\fB\-U\fP), crtimes (\fB\-N\fP), nor the finding and preserving of hardlinks (\fB\-H\fP). .IP The only exception to the above equivalence is when \fB\-\-files-from\fP is specified, in which case \fB\-r\fP is not implied. .IP "\fB\-\-no-OPTION\fP" You may turn off one or more implied options by prefixing the option name with "no-". Not all positive options have a negated opposite, but a lot do, including those that can be used to disable an implied option (e.g. \fB\-\-no-D\fP, \fB\-\-no-perms\fP) or have different defaults in various circumstances (e.g. \fB\-\-no-whole-file\fP, \fB\-\-no-blocking-io\fP, \fB\-\-no-dirs\fP). Every valid negated option accepts both the short and the long option name after the "no-" prefix (e.g. \fB\-\-no-R\fP is the same as \fB\-\-no-relative\fP). .IP As an example, if you want to use \fB\-\-archive\fP (\fB\-a\fP) but don't want \fB\-\-owner\fP (\fB\-o\fP), instead of converting \fB\-a\fP into \fB\-rlptgD\fP, you can specify \fB\-a\ \-\-no-o\fP (aka \fB\-\-archive\ \-\-no-owner\fP). .IP The order of the options is important: if you specify \fB\-\-no-r\ \-a\fP, the \fB\-r\fP option would end up being turned on, the opposite of \fB\-a\ \-\-no-r\fP. Note also that the side-effects of the \fB\-\-files-from\fP option are NOT positional, as it affects the default state of several options and slightly changes the meaning of \fB\-a\fP (see the \fB\-\-files-from\fP option for more details). .IP "\fB\-\-recursive\fP, \fB\-r\fP" This tells rsync to copy directories recursively. See also \fB\-\-dirs\fP (\fB\-d\fP) for an option that allows the scanning of a single directory. .IP See the \fB\-\-inc-recursive\fP option for a discussion of the incremental recursion for creating the list of files to transfer. .IP "\fB\-\-inc-recursive\fP, \fB\-\-i-r\fP" This option explicitly enables on incremental recursion when scanning for files, which is enabled by default when using the \fB\-\-recursive\fP option and both sides of the transfer are running rsync 3.0.0 or newer. .IP Incremental recursion uses much less memory than non-incremental, while also beginning the transfer more quickly (since it doesn't need to scan the entire transfer hierarchy before it starts transferring files). If no recursion is enabled in the source files, this option has no effect. .IP Some options require rsync to know the full file list, so these options disable the incremental recursion mode. These include: .IP .RS .IP o \fB\-\-delete-before\fP (the old default of \fB\-\-delete\fP) .IP o \fB\-\-delete-after\fP .IP o \fB\-\-prune-empty-dirs\fP .IP o \fB\-\-delay-updates\fP .RE .IP In order to make \fB\-\-delete\fP compatible with incremental recursion, rsync 3.0.0 made \fB\-\-delete-during\fP the default delete mode (which was first added in 2.6.4). .IP One side-effect of incremental recursion is that any missing sub-directories inside a recursively-scanned directory are (by default) created prior to recursing into the sub-dirs. This earlier creation point (compared to a non-incremental recursion) allows rsync to then set the modify time of the finished directory right away (without having to delay that until a bunch of recursive copying has finished). However, these early directories don't yet have their completed mode, mtime, or ownership set\ \-\- they have more restrictive rights until the subdirectory's copying actually begins. This early-creation idiom can be avoided by using the \fB\-\-omit-dir-times\fP option. .IP Incremental recursion can be disabled using the \fB\-\-no-inc-recursive\fP (\fB\-\-no-i-r\fP) option. .IP "\fB\-\-no-inc-recursive\fP, \fB\-\-no-i-r\fP" Disables the new incremental recursion algorithm of the \fB\-\-recursive\fP option. This makes rsync scan the full file list before it begins to transfer files. See \fB\-\-inc-recursive\fP for more info. .IP "\fB\-\-relative\fP, \fB\-R\fP" Use relative paths. This means that the full path names specified on the command line are sent to the server rather than just the last parts of the filenames. This is particularly useful when you want to send several different directories at the same time. For example, if you used this command: .RS 4 .IP .nf rsync -av /foo/bar/baz.c remote:/tmp/ .fi .RE .IP would create a file named baz.c in /tmp/ on the remote machine. If instead you used .RS 4 .IP .nf rsync -avR /foo/bar/baz.c remote:/tmp/ .fi .RE .IP then a file named /tmp/foo/bar/baz.c would be created on the remote machine, preserving its full path. These extra path elements are called "implied directories" (i.e. the "foo" and the "foo/bar" directories in the above example). .IP Beginning with rsync 3.0.0, rsync always sends these implied directories as real directories in the file list, even if a path element is really a symlink on the sending side. This prevents some really unexpected behaviors when copying the full path of a file that you didn't realize had a symlink in its path. If you want to duplicate a server-side symlink, include both the symlink via its path, and referent directory via its real path. If you're dealing with an older rsync on the sending side, you may need to use the \fB\-\-no-implied-dirs\fP option. .IP It is also possible to limit the amount of path information that is sent as implied directories for each path you specify. With a modern rsync on the sending side (beginning with 2.6.7), you can insert a dot and a slash into the source path, like this: .RS 4 .IP .nf rsync -avR /foo/./bar/baz.c remote:/tmp/ .fi .RE .IP That would create /tmp/bar/baz.c on the remote machine. (Note that the dot must be followed by a slash, so "/foo/." would not be abbreviated.) For older rsync versions, you would need to use a chdir to limit the source path. For example, when pushing files: .RS 4 .IP .nf (cd /foo; rsync -avR bar/baz.c remote:/tmp/) .fi .RE .IP (Note that the parens put the two commands into a sub-shell, so that the "cd" command doesn't remain in effect for future commands.) If you're pulling files from an older rsync, use this idiom (but only for a non-daemon transfer): .RS 4 .IP .nf rsync -avR --rsync-path="cd /foo; rsync" \\ remote:bar/baz.c /tmp/ .fi .RE .IP "\fB\-\-no-implied-dirs\fP" This option affects the default behavior of the \fB\-\-relative\fP option. When it is specified, the attributes of the implied directories from the source names are not included in the transfer. This means that the corresponding path elements on the destination system are left unchanged if they exist, and any missing implied directories are created with default attributes. This even allows these implied path elements to have big differences, such as being a symlink to a directory on the receiving side. .IP For instance, if a command-line arg or a files-from entry told rsync to transfer the file "path/foo/file", the directories "path" and "path/foo" are implied when \fB\-\-relative\fP is used. If "path/foo" is a symlink to "bar" on the destination system, the receiving rsync would ordinarily delete "path/foo", recreate it as a directory, and receive the file into the new directory. With \fB\-\-no-implied-dirs\fP, the receiving rsync updates "path/foo/file" using the existing path elements, which means that the file ends up being created in "path/bar". Another way to accomplish this link preservation is to use the \fB\-\-keep-dirlinks\fP option (which will also affect symlinks to directories in the rest of the transfer). .IP When pulling files from an rsync older than 3.0.0, you may need to use this option if the sending side has a symlink in the path you request and you wish the implied directories to be transferred as normal directories. .IP "\fB\-\-backup\fP, \fB\-b\fP" With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the \fB\-\-backup-dir\fP and \fB\-\-suffix\fP options. .IP If you don't specify \fB\-\-backup-dir\fP: .RS .IP .IP 1. the \fB\-\-omit-dir-times\fP option will be forced on .IP 2. the use of \fB\-\-delete\fP (without \fB\-\-delete-excluded\fP), causes rsync to add a "protect" filter-rule for the backup suffix to the end of all your existing filters that looks like this: \fB\-f\ "P\ *~"\fP. This rule prevents previously backed-up files from being deleted. .RE .IP Note that if you are supplying your own filter rules, you may need to manually insert your own exclude/protect rule somewhere higher up in the list so that it has a high enough priority to be effective (e.g. if your rules specify a trailing inclusion/exclusion of \fB*\fP, the auto-added rule would never be reached). .IP "\fB\-\-backup-dir=DIR\fP" This implies the \fB\-\-backup\fP option, and tells rsync to store all backups in the specified directory on the receiving side. This can be used for incremental backups. You can additionally specify a backup suffix using the \fB\-\-suffix\fP option (otherwise the files backed up in the specified directory will keep their original filenames). .IP Note that if you specify a relative path, the backup directory will be relative to the destination directory, so you probably want to specify either an absolute path or a path that starts with "../". If an rsync daemon is the receiver, the backup dir cannot go outside the module's path hierarchy, so take extra care not to delete it or copy into it. .IP "\fB\-\-suffix=SUFFIX\fP" This option allows you to override the default backup suffix used with the \fB\-\-backup\fP (\fB\-b\fP) option. The default suffix is a \fB~\fP if no \fB\-\-backup-dir\fP was specified, otherwise it is an empty string. .IP "\fB\-\-update\fP, \fB\-u\fP" This forces rsync to skip any files which exist on the destination and have a modified time that is newer than the source file. (If an existing destination file has a modification time equal to the source file's, it will be updated if the sizes are different.) .IP Note that this does not affect the copying of dirs, symlinks, or other special files. Also, a difference of file format between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects. In other words, if the source has a directory where the destination has a file, the transfer would occur regardless of the timestamps. .IP This option is a TRANSFER RULE, so don't expect any exclude side effects. .IP A caution for those that choose to combine \fB\-\-inplace\fP with \fB\-\-update\fP: an interrupted transfer will leave behind a partial file on the receiving side that has a very recent modified time, so re-running the transfer will probably \fBnot\fP continue the interrupted file. As such, it is usually best to avoid combining this with \fB\-\-inplace\fP unless you have implemented manual steps to handle any interrupted in-progress files. .IP "\fB\-\-inplace\fP" This option changes how rsync transfers a file when its data needs to be updated: instead of the default method of creating a new copy of the file and moving it into place when it is complete, rsync instead writes the updated data directly to the destination file. .IP This has several effects: .IP .RS .IP o Hard links are not broken. This means the new data will be visible through other hard links to the destination file. Moreover, attempts to copy differing source files onto a multiply-linked destination file will result in a "tug of war" with the destination data changing back and forth. .IP o In-use binaries cannot be updated (either the OS will prevent this from happening, or binaries that attempt to swap-in their data will misbehave or crash). .IP o The file's data will be in an inconsistent state during the transfer and will be left that way if the transfer is interrupted or if an update fails. .IP o A file that rsync cannot write to cannot be updated. While a super user can update any file, a normal user needs to be granted write permission for the open of the file for writing to be successful. .IP o The efficiency of rsync's delta-transfer algorithm may be reduced if some data in the destination file is overwritten before it can be copied to a position later in the file. This does not apply if you use \fB\-\-backup\fP, since rsync is smart enough to use the backup file as the basis file for the transfer. .RE .IP WARNING: you should not use this option to update files that are being accessed by others, so be careful when choosing to use this for a copy. .IP This option is useful for transferring large files with block-based changes or appended data, and also on systems that are disk bound, not network bound. It can also help keep a copy-on-write filesystem snapshot from diverging the entire contents of a file that only has minor changes. .IP The option implies \fB\-\-partial\fP (since an interrupted transfer does not delete the file), but conflicts with \fB\-\-partial-dir\fP and \fB\-\-delay-updates\fP. Prior to rsync 2.6.4 \fB\-\-inplace\fP was also incompatible with \fB\-\-compare-dest\fP and \fB\-\-link-dest\fP. .IP "\fB\-\-append\fP" This special copy mode only works to efficiently update files that are known to be growing larger where any existing content on the receiving side is also known to be the same as the content on the sender. The use of \fB\-\-append\fP \fBcan be dangerous\fP if you aren't 100% sure that all the files in the transfer are shared, growing files. You should thus use filter rules to ensure that you weed out any files that do not fit this criteria. .IP Rsync updates these growing file in-place without verifying any of the existing content in the file (it only verifies the content that it is appending). Rsync skips any files that exist on the receiving side that are not shorter than the associated file on the sending side (which means that new files are transferred). It also skips any files whose size on the sending side gets shorter during the send negotiations (rsync warns about a "diminished" file when this happens). .IP This does not interfere with the updating of a file's non-content attributes (e.g. permissions, ownership, etc.) when the file does not need to be transferred, nor does it affect the updating of any directories or non-regular files. .IP "\fB\-\-append-verify\fP" This special copy mode works like \fB\-\-append\fP except that all the data in the file is included in the checksum verification (making it less efficient but also potentially safer). This option \fBcan be dangerous\fP if you aren't 100% sure that all the files in the transfer are shared, growing files. See the \fB\-\-append\fP option for more details. .IP Note: prior to rsync 3.0.0, the \fB\-\-append\fP option worked like \fB\-\-append-verify\fP, so if you are interacting with an older rsync (or the transfer is using a protocol prior to 30), specifying either append option will initiate an \fB\-\-append-verify\fP transfer. .IP "\fB\-\-dirs\fP, \fB\-d\fP" Tell the sending side to include any directories that are encountered. Unlike \fB\-\-recursive\fP, a directory's contents are not copied unless the directory name specified is "." or ends with a trailing slash (e.g. ".", "dir/.", "dir/", etc.). Without this option or the \fB\-\-recursive\fP option, rsync will skip all directories it encounters (and output a message to that effect for each one). If you specify both \fB\-\-dirs\fP and \fB\-\-recursive\fP, \fB\-\-recursive\fP takes precedence. .IP The \fB\-\-dirs\fP option is implied by the \fB\-\-files-from\fP option or the \fB\-\-list-only\fP option (including an implied \fB\-\-list-only\fP usage) if \fB\-\-recursive\fP wasn't specified (so that directories are seen in the listing). Specify \fB\-\-no-dirs\fP (or \fB\-\-no-d\fP) if you want to turn this off. .IP There is also a backward-compatibility helper option, \fB\-\-old-dirs\fP (\fB\-\-old-d\fP) that tells rsync to use a hack of \fB\-r\ \-\-exclude='/*/*'\fP to get an older rsync to list a single directory without recursing. .IP "\fB\-\-mkpath\fP" Create all missing path components of the destination path. .IP By default, rsync allows only the final component of the destination path to not exist, which is an attempt to help you to validate your destination path. With this option, rsync creates all the missing destination-path components, just as if \fBmkdir\ \-p\ $DEST_PATH\fP had been run on the receiving side. .IP When specifying a destination path, including a trailing slash ensures that the whole path is treated as directory names to be created, even when the file list has a single item. See the COPYING TO A DIFFERENT NAME section for full details on how rsync decides if a final destination-path component should be created as a directory or not. .IP If you would like the newly-created destination dirs to match the dirs on the sending side, you should be using \fB\-\-relative\fP (\fB\-R\fP) instead of \fB\-\-mkpath\fP. For instance, the following two commands result in the same destination tree, but only the second command ensures that the "some/extra/path" components match the dirs on the sending side: .RS 4 .IP .nf rsync -ai --mkpath host:some/extra/path/*.c some/extra/path/ rsync -aiR host:some/extra/path/*.c ./ .fi .RE .IP "\fB\-\-links\fP, \fB\-l\fP" Add symlinks to the transferred files instead of noisily ignoring them with a "non-regular file" warning for each symlink encountered. You can alternately silence the warning by specifying \fB\-\-info=nonreg0\fP. .IP The default handling of symlinks is to recreate each symlink's unchanged value on the receiving side. .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-copy-links\fP, \fB\-L\fP" The sender transforms each symlink encountered in the transfer into the referent item, following the symlink chain to the file or directory that it references. If a symlink chain is broken, an error is output and the file is dropped from the transfer. .IP This option supersedes any other options that affect symlinks in the transfer, since there are no symlinks left in the transfer. .IP This option does not change the handling of existing symlinks on the receiving side, unlike versions of rsync prior to 2.6.3 which had the side-effect of telling the receiving side to also follow symlinks. A modern rsync won't forward this option to a remote receiver (since only the sender needs to know about it), so this caveat should only affect someone using an rsync client older than 2.6.7 (which is when \fB\-L\fP stopped being forwarded to the receiver). .IP See the \fB\-\-keep-dirlinks\fP (\fB\-K\fP) if you need a symlink to a directory to be treated as a real directory on the receiving side. .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-copy-unsafe-links\fP" This tells rsync to copy the referent of symbolic links that point outside the copied tree. Absolute symlinks are also treated like ordinary files, and so are any symlinks in the source path itself when \fB\-\-relative\fP is used. .IP Note that the cut-off point is the top of the transfer, which is the part of the path that rsync isn't mentioning in the verbose output. If you copy "/src/subdir" to "/dest/" then the "subdir" directory is a name inside the transfer tree, not the top of the transfer (which is /src) so it is legal for created relative symlinks to refer to other names inside the /src and /dest directories. If you instead copy "/src/subdir/" (with a trailing slash) to "/dest/subdir" that would not allow symlinks to any files outside of "subdir". .IP Note that safe symlinks are only copied if \fB\-\-links\fP was also specified or implied. The \fB\-\-copy-unsafe-links\fP option has no extra effect when combined with \fB\-\-copy-links\fP. .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-safe-links\fP" This tells the receiving rsync to ignore any symbolic links in the transfer which point outside the copied tree. All absolute symlinks are also ignored. .IP Since this ignoring is happening on the receiving side, it will still be effective even when the sending side has munged symlinks (when it is using \fB\-\-munge-links\fP). It also affects deletions, since the file being present in the transfer prevents any matching file on the receiver from being deleted when the symlink is deemed to be unsafe and is skipped. .IP This option must be combined with \fB\-\-links\fP (or \fB\-\-archive\fP) to have any symlinks in the transfer to conditionally ignore. Its effect is superseded by \fB\-\-copy-unsafe-links\fP. .IP Using this option in conjunction with \fB\-\-relative\fP may give unexpected results. .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-munge-links\fP" This option affects just one side of the transfer and tells rsync to munge symlink values when it is receiving files or unmunge symlink values when it is sending files. The munged values make the symlinks unusable on disk but allows the original contents of the symlinks to be recovered. .IP The server-side rsync often enables this option without the client's knowledge, such as in an rsync daemon's configuration file or by an option given to the rrsync (restricted rsync) script. When specified on the client side, specify the option normally if it is the client side that has/needs the munged symlinks, or use \fB\-M\-\-munge-links\fP to give the option to the server when it has/needs the munged symlinks. Note that on a local transfer, the client is the sender, so specifying the option directly unmunges symlinks while specifying it as a remote option munges symlinks. .IP This option has no effect when sent to a daemon via \fB\-\-remote-option\fP because the daemon configures whether it wants munged symlinks via its "\fBmunge\ symlinks\fP" parameter. .IP The symlink value is munged/unmunged once it is in the transfer, so any option that transforms symlinks into non-symlinks occurs prior to the munging/unmunging \fBexcept\fP for \fB\-\-safe-links\fP, which is a choice that the receiver makes, so it bases its decision on the munged/unmunged value. This does mean that if a receiver has munging enabled, that using \fB\-\-safe-links\fP will cause all symlinks to be ignored (since they are all absolute). .IP The method that rsync uses to munge the symlinks is to prefix each one's value with the string "/rsyncd-munged/". This prevents the links from being used as long as the directory does not exist. When this option is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory (though it only checks at startup). See also the "munge-symlinks" python script in the support directory of the source code for a way to munge/unmunge one or more symlinks in-place. .IP "\fB\-\-copy-dirlinks\fP, \fB\-k\fP" This option causes the sending side to treat a symlink to a directory as though it were a real directory. This is useful if you don't want symlinks to non-directories to be affected, as they would be using \fB\-\-copy-links\fP. .IP Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as \fB\-\-force\fP or \fB\-\-delete\fP is in effect). .IP See also \fB\-\-keep-dirlinks\fP for an analogous option for the receiving side. .IP \fB\-\-copy-dirlinks\fP applies to all symlinks to directories in the source. If you want to follow only a few specified symlinks, a trick you can use is to pass them as additional source args with a trailing slash, using \fB\-\-relative\fP to make the paths match up right. For example: .RS 4 .IP .nf rsync -r --relative src/./ src/./follow-me/ dest/ .fi .RE .IP This works because rsync calls \fBlstat\fP(2) on the source arg as given, and the trailing slash makes \fBlstat\fP(2) follow the symlink, giving rise to a directory in the file-list which overrides the symlink found during the scan of "src/./". .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-keep-dirlinks\fP, \fB\-K\fP" This option causes the receiving side to treat a symlink to a directory as though it were a real directory, but only if it matches a real directory from the sender. Without this option, the receiver's symlink would be deleted and replaced with a real directory. .IP For example, suppose you transfer a directory "foo" that contains a file "file", but "foo" is a symlink to directory "bar" on the receiver. Without \fB\-\-keep-dirlinks\fP, the receiver deletes symlink "foo", recreates it as a directory, and receives the file into the new directory. With \fB\-\-keep-dirlinks\fP, the receiver keeps the symlink and "file" ends up in "bar". .IP One note of caution: if you use \fB\-\-keep-dirlinks\fP, you must trust all the symlinks in the copy or enable the \fB\-\-munge-links\fP option on the receiving side! If it is possible for an untrusted user to create their own symlink to any real directory, the user could then (on a subsequent copy) replace the symlink with a real directory and affect the content of whatever directory the symlink references. For backup copies, you are better off using something like a bind mount instead of a symlink to modify your receiving hierarchy. .IP See also \fB\-\-copy-dirlinks\fP for an analogous option for the sending side. .IP See the SYMBOLIC LINKS section for multi-option info. .IP "\fB\-\-hard-links\fP, \fB\-H\fP" This tells rsync to look for hard-linked files in the source and link together the corresponding files on the destination. Without this option, hard-linked files in the source are treated as though they were separate files. .IP This option does NOT necessarily ensure that the pattern of hard links on the destination exactly matches that on the source. Cases in which the destination may end up with extra hard links include the following: .IP .RS .IP o If the destination contains extraneous hard-links (more linking than what is present in the source file list), the copying algorithm will not break them explicitly. However, if one or more of the paths have content differences, the normal file-update process will break those extra links (unless you are using the \fB\-\-inplace\fP option). .IP o If you specify a \fB\-\-link-dest\fP directory that contains hard links, the linking of the destination files against the \fB\-\-link-dest\fP files can cause some paths in the destination to become linked together due to the \fB\-\-link-dest\fP associations. .RE .IP Note that rsync can only detect hard links between files that are inside the transfer set. If rsync updates a file that has extra hard-link connections to files outside the transfer, that linkage will be broken. If you are tempted to use the \fB\-\-inplace\fP option to avoid this breakage, be very careful that you know how your files are being updated so that you are certain that no unintended changes happen due to lingering hard links (and see the \fB\-\-inplace\fP option for more caveats). .IP If incremental recursion is active (see \fB\-\-inc-recursive\fP), rsync may transfer a missing hard-linked file before it finds that another link for that contents exists elsewhere in the hierarchy. This does not affect the accuracy of the transfer (i.e. which files are hard-linked together), just its efficiency (i.e. copying the data for a new, early copy of a hard-linked file that could have been found later in the transfer in another member of the hard-linked set of files). One way to avoid this inefficiency is to disable incremental recursion using the \fB\-\-no-inc-recursive\fP option. .IP "\fB\-\-perms\fP, \fB\-p\fP" This option causes the receiving rsync to set the destination permissions to be the same as the source permissions. (See also the \fB\-\-chmod\fP option for a way to modify what rsync considers to be the source permissions.) .IP When this option is \fIoff\fP, permissions are set as follows: .IP .RS .IP o Existing files (including updated files) retain their existing permissions, though the \fB\-\-executability\fP option might change just the execute permission for the file. .IP o New files get their "normal" permission bits set to the source file's permissions masked with the receiving directory's default permissions (either the receiving process's umask, or the permissions specified via the destination directory's default ACL), and their special permission bits disabled except in the case where a new directory inherits a setgid bit from its parent directory. .RE .IP Thus, when \fB\-\-perms\fP and \fB\-\-executability\fP are both disabled, rsync's behavior is the same as that of other file-copy utilities, such as \fBcp\fP(1) and \fBtar\fP(1). .IP In summary: to give destination files (both old and new) the source permissions, use \fB\-\-perms\fP. To give new files the destination-default permissions (while leaving existing files unchanged), make sure that the \fB\-\-perms\fP option is off and use \fB\-\-chmod=ugo=rwX\fP (which ensures that all non-masked bits get enabled). If you'd care to make this latter behavior easier to type, you could define a popt alias for it, such as putting this line in the file \fB~/.popt\fP (the following defines the \fB\-Z\fP option, and includes \fB\-\-no-g\fP to use the default group of the destination dir): .RS 4 .IP .nf rsync alias -Z --no-p --no-g --chmod=ugo=rwX .fi .RE .IP You could then use this new option in a command such as this one: .RS 4 .IP .nf rsync -avZ src/ dest/ .fi .RE .IP (Caveat: make sure that \fB\-a\fP does not follow \fB\-Z\fP, or it will re-enable the two \fB\-\-no-*\fP options mentioned above.) .IP The preservation of the destination's setgid bit on newly-created directories when \fB\-\-perms\fP is off was added in rsync 2.6.7. Older rsync versions erroneously preserved the three special permission bits for newly-created files when \fB\-\-perms\fP was off, while overriding the destination's setgid bit setting on a newly-created directory. Default ACL observance was added to the ACL patch for rsync 2.6.7, so older (or non-ACL-enabled) rsyncs use the umask even if default ACLs are present. (Keep in mind that it is the version of the receiving rsync that affects these behaviors.) .IP "\fB\-\-executability\fP, \fB\-E\fP" This option causes rsync to preserve the executability (or non-executability) of regular files when \fB\-\-perms\fP is not enabled. A regular file is considered to be executable if at least one 'x' is turned on in its permissions. When an existing destination file's executability differs from that of the corresponding source file, rsync modifies the destination file's permissions as follows: .IP .RS .IP o To make a file non-executable, rsync turns off all its 'x' permissions. .IP o To make a file executable, rsync turns on each 'x' permission that has a corresponding 'r' permission enabled. .RE .IP If \fB\-\-perms\fP is enabled, this option is ignored. .IP "\fB\-\-acls\fP, \fB\-A\fP" This option causes rsync to update the destination ACLs to be the same as the source ACLs. The option also implies \fB\-\-perms\fP. .IP The source and destination systems must have compatible ACL entries for this option to work properly. See the \fB\-\-fake-super\fP option for a way to backup and restore ACLs that are not compatible. .IP "\fB\-\-xattrs\fP, \fB\-X\fP" This option causes rsync to update the destination extended attributes to be the same as the source ones. .IP For systems that support extended-attribute namespaces, a copy being done by a super-user copies all namespaces except system.*. A normal user only copies the user.* namespace. To be able to backup and restore non-user namespaces as a normal user, see the \fB\-\-fake-super\fP option. .IP The above name filtering can be overridden by using one or more filter options with the \fBx\fP modifier. When you specify an xattr-affecting filter rule, rsync requires that you do your own system/user filtering, as well as any additional filtering for what xattr names are copied and what names are allowed to be deleted. For example, to skip the system namespace, you could specify: .RS 4 .IP .nf --filter='-x system.*' .fi .RE .IP To skip all namespaces except the user namespace, you could specify a negated-user match: .RS 4 .IP .nf --filter='-x! user.*' .fi .RE .IP To prevent any attributes from being deleted, you could specify a receiver-only rule that excludes all names: .RS 4 .IP .nf --filter='-xr *' .fi .RE .IP Note that the \fB\-X\fP option does not copy rsync's special xattr values (e.g. those used by \fB\-\-fake-super\fP) unless you repeat the option (e.g. \fB\-XX\fP). This "copy all xattrs" mode cannot be used with \fB\-\-fake-super\fP. .IP "\fB\-\-chmod=CHMOD\fP" This option tells rsync to apply one or more comma-separated "chmod" modes to the permission of the files in the transfer. The resulting value is treated as though it were the permissions that the sending side supplied for the file, which means that this option can seem to have no effect on existing files if \fB\-\-perms\fP is not enabled. .IP In addition to the normal parsing rules specified in the \fBchmod\fP(1) manpage, you can specify an item that should only apply to a directory by prefixing it with a 'D', or specify an item that should only apply to a file by prefixing it with a 'F'. For example, the following will ensure that all directories get marked set-gid, that no files are other-writable, that both are user-writable and group-writable, and that both have consistent executability across all bits: .RS 4 .IP .nf --chmod=Dg+s,ug+w,Fo-w,+X .fi .RE .IP Using octal mode numbers is also allowed: .RS 4 .IP .nf --chmod=D2775,F664 .fi .RE .IP It is also legal to specify multiple \fB\-\-chmod\fP options, as each additional option is just appended to the list of changes to make. .IP See the \fB\-\-perms\fP and \fB\-\-executability\fP options for how the resulting permission value can be applied to the files in the transfer. .IP "\fB\-\-owner\fP, \fB\-o\fP" This option causes rsync to set the owner of the destination file to be the same as the source file, but only if the receiving rsync is being run as the super-user (see also the \fB\-\-super\fP and \fB\-\-fake-super\fP options). Without this option, the owner of new and/or transferred files are set to the invoking user on the receiving side. .IP The preservation of ownership will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the \fB\-\-numeric-ids\fP option for a full discussion). .IP "\fB\-\-group\fP, \fB\-g\fP" This option causes rsync to set the group of the destination file to be the same as the source file. If the receiving program is not running as the super-user (or if \fB\-\-no-super\fP was specified), only groups that the invoking user on the receiving side is a member of will be preserved. Without this option, the group is set to the default group of the invoking user on the receiving side. .IP The preservation of group information will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the \fB\-\-numeric-ids\fP option for a full discussion). .IP "\fB\-\-devices\fP" This option causes rsync to transfer character and block device files to the remote system to recreate these devices. If the receiving rsync is not being run as the super-user, rsync silently skips creating the device files (see also the \fB\-\-super\fP and \fB\-\-fake-super\fP options). .IP By default, rsync generates a "non-regular file" warning for each device file encountered when this option is not set. You can silence the warning by specifying \fB\-\-info=nonreg0\fP. .IP "\fB\-\-specials\fP" This option causes rsync to transfer special files, such as named sockets and fifos. If the receiving rsync is not being run as the super-user, rsync silently skips creating the special files (see also the \fB\-\-super\fP and \fB\-\-fake-super\fP options). .IP By default, rsync generates a "non-regular file" warning for each special file encountered when this option is not set. You can silence the warning by specifying \fB\-\-info=nonreg0\fP. .IP "\fB\-D\fP" The \fB\-D\fP option is equivalent to "\fB\-\-devices\fP \fB\-\-specials\fP". .IP "\fB\-\-copy-devices\fP" This tells rsync to treat a device on the sending side as a regular file, allowing it to be copied to a normal destination file (or another device if \fB\-\-write-devices\fP was also specified). .IP This option is refused by default by an rsync daemon. .IP "\fB\-\-write-devices\fP" This tells rsync to treat a device on the receiving side as a regular file, allowing the writing of file data into a device. .IP This option implies the \fB\-\-inplace\fP option. .IP Be careful using this, as you should know what devices are present on the receiving side of the transfer, especially when running rsync as root. .IP This option is refused by default by an rsync daemon. .IP "\fB\-\-times\fP, \fB\-t\fP" This tells rsync to transfer modification times along with the files and update them on the remote system. Note that if this option is not used, the optimization that excludes files that have not been modified cannot be effective; in other words, a missing \fB\-t\fP (or \fB\-a\fP) will cause the next transfer to behave as if it used \fB\-\-ignore-times\fP (\fB\-I\fP), causing all files to be updated (though rsync's delta-transfer algorithm will make the update fairly efficient if the files haven't actually changed, you're much better off using \fB\-t\fP). .IP A modern rsync that is using transfer protocol 30 or 31 conveys a modify time using up to 8-bytes. If rsync is forced to speak an older protocol (perhaps due to the remote rsync being older than 3.0.0) a modify time is conveyed using 4-bytes. Prior to 3.2.7, these shorter values could convey a date range of 13-Dec-1901 to 19-Jan-2038. Beginning with 3.2.7, these 4-byte values now convey a date range of 1-Jan-1970 to 7-Feb-2106. If you have files dated older than 1970, make sure your rsync executables are upgraded so that the full range of dates can be conveyed. .IP "\fB\-\-atimes\fP, \fB\-U\fP" This tells rsync to set the access (use) times of the destination files to the same value as the source files. .IP If repeated, it also sets the \fB\-\-open-noatime\fP option, which can help you to make the sending and receiving systems have the same access times on the transferred files without needing to run rsync an extra time after a file is transferred. .IP Note that some older rsync versions (prior to 3.2.0) may have been built with a pre-release \fB\-\-atimes\fP patch that does not imply \fB\-\-open-noatime\fP when this option is repeated. .IP "\fB\-\-open-noatime\fP" This tells rsync to open files with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred. If your OS does not support the O_NOATIME flag then rsync will silently ignore this option. Note also that some filesystems are mounted to avoid updating the atime on read access even without the O_NOATIME flag being set. .IP "\fB\-\-crtimes\fP, \fB\-N,\fP" This tells rsync to set the create times (newness) of the destination files to the same value as the source files. .IP "\fB\-\-omit-dir-times\fP, \fB\-O\fP" This tells rsync to omit directories when it is preserving modification, access, and create times. If NFS is sharing the directories on the receiving side, it is a good idea to use \fB\-O\fP. This option is inferred if you use \fB\-\-backup\fP without \fB\-\-backup-dir\fP. .IP This option also has the side-effect of avoiding early creation of missing sub-directories when incremental recursion is enabled, as discussed in the \fB\-\-inc-recursive\fP section. .IP "\fB\-\-omit-link-times\fP, \fB\-J\fP" This tells rsync to omit symlinks when it is preserving modification, access, and create times. .IP "\fB\-\-super\fP" This tells the receiving side to attempt super-user activities even if the receiving rsync wasn't run by the super-user. These activities include: preserving users via the \fB\-\-owner\fP option, preserving all groups (not just the current user's groups) via the \fB\-\-group\fP option, and copying devices via the \fB\-\-devices\fP option. This is useful for systems that allow such activities without being the super-user, and also for ensuring that you will get errors if the receiving side isn't being run as the super-user. To turn off super-user activities, the super-user can use \fB\-\-no-super\fP. .IP "\fB\-\-fake-super\fP" When this option is enabled, rsync simulates super-user activities by saving/restoring the privileged attributes via special extended attributes that are attached to each file (as needed). This includes the file's owner and group (if it is not the default), the file's device info (device & special files are created as empty text files), and any permission bits that we won't allow to be set on the real file (e.g. the real file gets u-s,g-s,o-t for safety) or that would limit the owner's access (since the real super-user can always access/change a file, the files we create can always be accessed/changed by the creating user). This option also handles ACLs (if \fB\-\-acls\fP was specified) and non-user extended attributes (if \fB\-\-xattrs\fP was specified). .IP This is a good way to backup data without using a super-user, and to store ACLs from incompatible systems. .IP The \fB\-\-fake-super\fP option only affects the side where the option is used. To affect the remote side of a remote-shell connection, use the \fB\-\-remote-option\fP (\fB\-M\fP) option: .RS 4 .IP .nf rsync -av -M--fake-super /src/ host:/dest/ .fi .RE .IP 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 \fB\-M\-\-fake-super\fP. If you wish a local copy to enable this option just for the source files, combine \fB\-\-fake-super\fP with \fB\-M\-\-super\fP. .IP This option is overridden by both \fB\-\-super\fP and \fB\-\-no-super\fP. .IP See also the \fBfake\ super\fP setting in the daemon's rsyncd.conf file. .IP "\fB\-\-sparse\fP, \fB\-S\fP" Try to handle sparse files efficiently so they take up less space on the destination. If combined with \fB\-\-inplace\fP the file created might not end up with sparse blocks with some combinations of kernel version and/or filesystem type. If \fB\-\-whole-file\fP is in effect (e.g. for a local copy) then it will always work because rsync truncates the file prior to writing out the updated version. .IP Note that versions of rsync older than 3.1.3 will reject the combination of \fB\-\-sparse\fP and \fB\-\-inplace\fP. .IP "\fB\-\-preallocate\fP" This tells the receiver to allocate each destination file to its eventual size before writing data to the file. Rsync will only use the real filesystem-level preallocation support provided by Linux's \fBfallocate\fP(2) system call or Cygwin's \fBposix_fallocate\fP(3), not the slow glibc implementation that writes a null byte into each block. .IP Without this option, larger files may not be entirely contiguous on the filesystem, but with this option rsync will probably copy more slowly. If the destination is not an extent-supporting filesystem (such as ext4, xfs, NTFS, etc.), this option may have no positive effect at all. .IP If combined with \fB\-\-sparse\fP, the file will only have sparse blocks (as opposed to allocated sequences of null bytes) if the kernel version and filesystem type support creating holes in the allocated data. .IP "\fB\-\-dry-run\fP, \fB\-n\fP" This makes rsync perform a trial run that doesn't make any changes (and produces mostly the same output as a real run). It is most commonly used in combination with the \fB\-\-verbose\fP (\fB\-v\fP) and/or \fB\-\-itemize-changes\fP (\fB\-i\fP) options to see what an rsync command is going to do before one actually runs it. .IP The output of \fB\-\-itemize-changes\fP is supposed to be exactly the same on a dry run and a subsequent real run (barring intentional trickery and system call failures); if it isn't, that's a bug. Other output should be mostly unchanged, but may differ in some areas. Notably, a dry run does not send the actual data for file transfers, so \fB\-\-progress\fP has no effect, the "bytes sent", "bytes received", "literal data", and "matched data" statistics are too small, and the "speedup" value is equivalent to a run where no file transfers were needed. .IP "\fB\-\-whole-file\fP, \fB\-W\fP" This option disables rsync's delta-transfer algorithm, which causes all transferred files to be sent whole. The transfer may be faster if this option is used when the bandwidth between the source and destination machines is higher than the bandwidth to disk (especially when the "disk" is actually a networked filesystem). This is the default when both the source and destination are specified as local paths, but only if no batch-writing option is in effect. .IP "\fB\-\-no-whole-file\fP, \fB\-\-no-W\fP" Disable whole-file updating when it is enabled by default for a local transfer. This usually slows rsync down, but it can be useful if you are trying to minimize the writes to the destination file (if combined with \fB\-\-inplace\fP) or for testing the checksum-based update algorithm. .IP See also the \fB\-\-whole-file\fP option. .IP "\fB\-\-checksum-choice=STR\fP, \fB\-\-cc=STR\fP" This option overrides the checksum algorithms. If one algorithm name is specified, it is used for both the transfer checksums and (assuming \fB\-\-checksum\fP is specified) the pre-transfer checksums. If two comma-separated names are supplied, the first name affects the transfer checksums, and the second name affects the pre-transfer checksums (\fB\-c\fP). .IP The checksum options that you may be able to use are: .IP .RS .IP o \fBauto\fP (the default automatic choice) .IP o \fBxxh128\fP .IP o \fBxxh3\fP .IP o \fBxxh64\fP (aka \fBxxhash\fP) .IP o \fBmd5\fP .IP o \fBmd4\fP .IP o \fBsha1\fP .IP o \fBnone\fP .RE .IP Run \fBrsync\ \-\-version\fP to see the default checksum list compiled into your version (which may differ from the list above). .IP If "none" is specified for the first (or only) name, the \fB\-\-whole-file\fP option is forced on and no checksum verification is performed on the transferred data. If "none" is specified for the second (or only) name, the \fB\-\-checksum\fP option cannot be used. .IP The "auto" option is the default, where rsync bases its algorithm choice on a negotiation between the client and the server as follows: .IP When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common checksum choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, a value is chosen based on the protocol version (which chooses between MD5 and various flavors of MD4 based on protocol age). .IP The default order can be customized by setting the environment variable \fBRSYNC_CHECKSUM_LIST\fP to a space-separated list of acceptable checksum names. If the string contains a "\fB&\fP" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default checksum list is used. This method does not allow you to specify the transfer checksum separately from the pre-transfer checksum, and it discards "auto" and all unknown checksum names. A list with only invalid names results in a failed negotiation. .IP The use of the \fB\-\-checksum-choice\fP option overrides this environment list. .IP "\fB\-\-one-file-system\fP, \fB\-x\fP" This tells rsync to avoid crossing a filesystem boundary when recursing. This does not limit the user's ability to specify items to copy from multiple filesystems, just rsync's recursion through the hierarchy of each directory that the user specified, and also the analogous recursion on the receiving side during deletion. Also keep in mind that rsync treats a "bind" mount to the same device as being on the same filesystem. .IP If this option is repeated, rsync omits all mount-point directories from the copy. Otherwise, it includes an empty directory at each mount-point it encounters (using the attributes of the mounted directory because those of the underlying mount-point directory are inaccessible). .IP If rsync has been told to collapse symlinks (via \fB\-\-copy-links\fP or \fB\-\-copy-unsafe-links\fP), a symlink to a directory on another device is treated like a mount-point. Symlinks to non-directories are unaffected by this option. .IP "\fB\-\-ignore-non-existing\fP, \fB\-\-existing\fP" This tells rsync to skip creating files (including directories) that do not exist yet on the destination. If this option is combined with the \fB\-\-ignore-existing\fP option, no files will be updated (which can be useful if all you want to do is delete extraneous files). .IP This option is a TRANSFER RULE, so don't expect any exclude side effects. .IP "\fB\-\-ignore-existing\fP" This tells rsync to skip updating files that already exist on the destination (this does \fInot\fP ignore existing directories, or nothing would get done). See also \fB\-\-ignore-non-existing\fP. .IP This option is a TRANSFER RULE, so don't expect any exclude side effects. .IP This option can be useful for those doing backups using the \fB\-\-link-dest\fP option when they need to continue a backup run that got interrupted. Since a \fB\-\-link-dest\fP run is copied into a new directory hierarchy (when it is used properly), using [\fB\-\-ignore-existing\fP will ensure that the already-handled files don't get tweaked (which avoids a change in permissions on the hard-linked files). This does mean that this option is only looking at the existing files in the destination hierarchy itself. .IP When \fB\-\-info=skip2\fP is used rsync will output "FILENAME exists (INFO)" messages where the INFO indicates one of "type change", "sum change" (requires \fB\-c\fP), "file change" (based on the quick check), "attr change", or "uptodate". Using \fB\-\-info=skip1\fP (which is also implied by 2 \fB\-v\fP options) outputs the exists message without the INFO suffix. .IP "\fB\-\-remove-source-files\fP" This tells rsync to remove from the sending side the files (meaning non-directories) that are a part of the transfer and have been successfully duplicated on the receiving side. .IP Note that you should only use this option on source files that are quiescent. If you are using this to move files that show up in a particular directory over to another host, make sure that the finished files get renamed into the source directory, not directly written into it, so that rsync can't possibly transfer a file that is not yet fully written. If you can't first write the files into a different directory, you should use a naming idiom that lets rsync avoid transferring files that are not yet finished (e.g. name the file "foo.new" when it is written, rename it to "foo" when it is done, and then use the option \fB\-\-exclude='*.new'\fP for the rsync transfer). .IP Starting with 3.1.0, rsync will skip the sender-side removal (and output an error) if the file's size or modify time has not stayed unchanged. .IP Starting with 3.2.6, a local rsync copy will ensure that the sender does not remove a file the receiver just verified, such as when the user accidentally makes the source and destination directory the same path. .IP "\fB\-\-delete\fP" This tells rsync to delete extraneous files from the receiving side (ones that aren't on the sending side), but only for the directories that are being synchronized. You must have asked rsync to send the whole directory (e.g. "\fBdir\fP" or "\fBdir/\fP") without using a wildcard for the directory's contents (e.g. "\fBdir/*\fP") since the wildcard is expanded by the shell and rsync thus gets a request to transfer individual files, not the files' parent directory. Files that are excluded from the transfer are also excluded from being deleted unless you use the \fB\-\-delete-excluded\fP option or mark the rules as only matching on the sending side (see the include/exclude modifiers in the FILTER RULES section). .IP Prior to rsync 2.6.7, this option would have no effect unless \fB\-\-recursive\fP was enabled. Beginning with 2.6.7, deletions will also occur when \fB\-\-dirs\fP (\fB\-d\fP) is enabled, but only for directories whose contents are being copied. .IP This option can be dangerous if used incorrectly! It is a very good idea to first try a run using the \fB\-\-dry-run\fP (\fB\-n\fP) option to see what files are going to be deleted. .IP If the sending side detects any I/O errors, then the deletion of any files at the destination will be automatically disabled. This is to prevent temporary filesystem failures (such as NFS errors) on the sending side from causing a massive deletion of files on the destination. You can override this with the \fB\-\-ignore-errors\fP option. .IP The \fB\-\-delete\fP option may be combined with one of the \-\-delete-WHEN options without conflict, as well as \fB\-\-delete-excluded\fP. However, if none of the \fB\-\-delete-WHEN\fP options are specified, rsync will choose the \fB\-\-delete-during\fP algorithm when talking to rsync 3.0.0 or newer, or the \fB\-\-delete-before\fP algorithm when talking to an older rsync. See also \fB\-\-delete-delay\fP and \fB\-\-delete-after\fP. .IP "\fB\-\-delete-before\fP" Request that the file-deletions on the receiving side be done before the transfer starts. See \fB\-\-delete\fP (which is implied) for more details on file-deletion. .IP Deleting before the transfer is helpful if the filesystem is tight for space and removing extraneous files would help to make the transfer possible. However, it does introduce a delay before the start of the transfer, and this delay might cause the transfer to timeout (if \fB\-\-timeout\fP was specified). It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see \fB\-\-recursive\fP). .IP "\fB\-\-delete-during\fP, \fB\-\-del\fP" Request that the file-deletions on the receiving side be done incrementally as the transfer happens. The per-directory delete scan is done right before each directory is checked for updates, so it behaves like a more efficient \fB\-\-delete-before\fP, including doing the deletions prior to any per-directory filter files being updated. This option was first added in rsync version 2.6.4. See \fB\-\-delete\fP (which is implied) for more details on file-deletion. .IP "\fB\-\-delete-delay\fP" Request that the file-deletions on the receiving side be computed during the transfer (like \fB\-\-delete-during\fP), and then removed after the transfer completes. This is useful when combined with \fB\-\-delay-updates\fP and/or \fB\-\-fuzzy\fP, and is more efficient than using \fB\-\-delete-after\fP (but can behave differently, since \fB\-\-delete-after\fP computes the deletions in a separate pass after all updates are done). If the number of removed files overflows an internal buffer, a temporary file will be created on the receiving side to hold the names (it is removed while open, so you shouldn't see it during the transfer). If the creation of the temporary file fails, rsync will try to fall back to using \fB\-\-delete-after\fP (which it cannot do if \fB\-\-recursive\fP is doing an incremental scan). See \fB\-\-delete\fP (which is implied) for more details on file-deletion. .IP "\fB\-\-delete-after\fP" Request that the file-deletions on the receiving side be done after the transfer has completed. This is useful if you are sending new per-directory merge files as a part of the transfer and you want their exclusions to take effect for the delete phase of the current transfer. It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see \fB\-\-recursive\fP). See \fB\-\-delete\fP (which is implied) for more details on file-deletion. .IP See also the \fB\-\-delete-delay\fP option that might be a faster choice for those that just want the deletions to occur at the end of the transfer. .IP "\fB\-\-delete-excluded\fP" This option turns any unqualified exclude/include rules into server-side rules that do not affect the receiver's deletions. .IP By default, an exclude or include has both a server-side effect (to "hide" and "show" files when building the server's file list) and a receiver-side effect (to "protect" and "risk" files when deletions are occurring). Any rule that has no modifier to specify what sides it is executed on will be instead treated as if it were a server-side rule only, avoiding any "protect" effects of the rules. .IP A rule can still apply to both sides even with this option specified if the rule is given both the sender & receiver modifier letters (e.g., \fB\-f'\-sr\ foo'\fP). Receiver-side protect/risk rules can also be explicitly specified to limit the deletions. This saves you from having to edit a bunch of \fB\-f'\-\ foo'\fP rules into \fB\-f'\-s\ foo'\fP (aka \fB\-f'H\ foo'\fP) rules (not to mention the corresponding includes). .IP See the FILTER RULES section for more information. See \fB\-\-delete\fP (which is implied) for more details on deletion. .IP "\fB\-\-ignore-missing-args\fP" When rsync is first processing the explicitly requested source files (e.g. command-line arguments or \fB\-\-files-from\fP entries), it is normally an error if the file cannot be found. This option suppresses that error, and does not try to transfer the file. This does not affect subsequent vanished-file errors if a file was initially found to be present and later is no longer there. .IP "\fB\-\-delete-missing-args\fP" This option takes the behavior of the (implied) \fB\-\-ignore-missing-args\fP option a step farther: each missing arg will become a deletion request of the corresponding destination file on the receiving side (should it exist). If the destination file is a non-empty directory, it will only be successfully deleted if \fB\-\-force\fP or \fB\-\-delete\fP are in effect. Other than that, this option is independent of any other type of delete processing. .IP The missing source files are represented by special file-list entries which display as a "\fB*missing\fP" entry in the \fB\-\-list-only\fP output. .IP "\fB\-\-ignore-errors\fP" Tells \fB\-\-delete\fP to go ahead and delete files even when there are I/O errors. .IP "\fB\-\-force\fP" This option tells rsync to delete a non-empty directory when it is to be replaced by a non-directory. This is only relevant if deletions are not active (see \fB\-\-delete\fP for details). .IP Note for older rsync versions: \fB\-\-force\fP used to still be required when using \fB\-\-delete-after\fP, and it used to be non-functional unless the \fB\-\-recursive\fP option was also enabled. .IP "\fB\-\-max-delete=NUM\fP" This tells rsync not to delete more than NUM files or directories. If that limit is exceeded, all further deletions are skipped through the end of the transfer. At the end, rsync outputs a warning (including a count of the skipped deletions) and exits with an error code of 25 (unless some more important error condition also occurred). .IP Beginning with version 3.0.0, you may specify \fB\-\-max-delete=0\fP to be warned about any extraneous files in the destination without removing any of them. Older clients interpreted this as "unlimited", so if you don't know what version the client is, you can use the less obvious \fB\-\-max-delete=\-1\fP as a backward-compatible way to specify that no deletions be allowed (though really old versions didn't warn when the limit was exceeded). .IP "\fB\-\-max-size=SIZE\fP" This tells rsync to avoid transferring any file that is larger than the specified SIZE. A numeric value can be suffixed with a string to indicate the numeric units or left unqualified to specify bytes. Feel free to use a fractional value along with the units, such as \fB\-\-max-size=1.5m\fP. .IP This option is a TRANSFER RULE, so don't expect any exclude side effects. .IP The first letter of a units string can be \fBB\fP (bytes), \fBK\fP (kilo), \fBM\fP (mega), \fBG\fP (giga), \fBT\fP (tera), or \fBP\fP (peta). If the string is a single char or has "ib" added to it (e.g. "G" or "GiB") then the units are multiples of 1024. If you use a two-letter suffix that ends with a "B" (e.g. "kb") then you get units that are multiples of 1000. The string's letters can be any mix of upper and lower-case that you want to use. .IP Finally, if the string ends with either "+1" or "\-1", it is offset by one byte in the indicated direction. The largest possible value is usually \fB8192P-1\fP. .IP Examples: \fB\-\-max-size=1.5mb-1\fP is 1499999 bytes, and \fB\-\-max-size=2g+1\fP is 2147483649 bytes. .IP Note that rsync versions prior to 3.1.0 did not allow \fB\-\-max-size=0\fP. .IP "\fB\-\-min-size=SIZE\fP" This tells rsync to avoid transferring any file that is smaller than the specified SIZE, which can help in not transferring small, junk files. See the \fB\-\-max-size\fP option for a description of SIZE and other info. .IP Note that rsync versions prior to 3.1.0 did not allow \fB\-\-min-size=0\fP. .IP "\fB\-\-max-alloc=SIZE\fP" By default rsync limits an individual malloc/realloc to about 1GB in size. For most people this limit works just fine and prevents a protocol error causing rsync to request massive amounts of memory. However, if you have many millions of files in a transfer, a large amount of server memory, and you don't want to split up your transfer into multiple parts, you can increase the per-allocation limit to something larger and rsync will consume more memory. .IP Keep in mind that this is not a limit on the total size of allocated memory. It is a sanity-check value for each individual allocation. .IP See the \fB\-\-max-size\fP option for a description of how SIZE can be specified. The default suffix if none is given is bytes. .IP Beginning in 3.2.3, a value of 0 specifies no limit. .IP You can set a default value using the environment variable \fBRSYNC_MAX_ALLOC\fP using the same SIZE values as supported by this option. If the remote rsync doesn't understand the \fB\-\-max-alloc\fP option, you can override an environmental value by specifying \fB\-\-max-alloc=1g\fP, which will make rsync avoid sending the option to the remote side (because "1G" is the default). .IP "\fB\-\-block-size=SIZE\fP, \fB\-B\fP" This forces the block size used in rsync's delta-transfer algorithm to a fixed value. It is normally selected based on the size of each file being updated. See the technical report for details. .IP Beginning in 3.2.3 the SIZE can be specified with a suffix as detailed in the \fB\-\-max-size\fP option. Older versions only accepted a byte count. .IP "\fB\-\-rsh=COMMAND\fP, \fB\-e\fP" This option allows you to choose an alternative remote shell program to use for communication between the local and remote copies of rsync. Typically, rsync is configured to use ssh by default, but you may prefer to use rsh on a local network. .IP If this option is used with \fB[user@]host::module/path\fP, then the remote shell \fICOMMAND\fP will be used to run an rsync daemon on the remote host, and all data will be transmitted through that remote shell connection, rather than through a direct socket connection to a running rsync daemon on the remote host. See the USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION section above. .IP Beginning with rsync 3.2.0, the \fBRSYNC_PORT\fP environment variable will be set when a daemon connection is being made via a remote-shell connection. It is set to 0 if the default daemon port is being assumed, or it is set to the value of the rsync port that was specified via either the \fB\-\-port\fP option or a non-empty port value in an \fBrsync://\fP URL. This allows the script to discern if a non-default port is being requested, allowing for things such as an SSL or stunnel helper script to connect to a default or alternate port. .IP Command-line arguments are permitted in COMMAND provided that COMMAND is presented to rsync as a single argument. You must use spaces (not tabs or other whitespace) to separate the command and args from each other, and you can use single- and/or double-quotes to preserve spaces in an argument (but not backslashes). Note that doubling a single-quote inside a single-quoted string gives you a single-quote; likewise for double-quotes (though you need to pay attention to which quotes your shell is parsing and which quotes rsync is parsing). Some examples: .RS 4 .IP .nf -e 'ssh -p 2234' -e 'ssh -o "ProxyCommand nohup ssh firewall nc -w1 %h %p"' .fi .RE .IP (Note that ssh users can alternately customize site-specific connect options in their .ssh/config file.) .IP You can also choose the remote shell program using the \fBRSYNC_RSH\fP environment variable, which accepts the same range of values as \fB\-e\fP. .IP See also the \fB\-\-blocking-io\fP option which is affected by this option. .IP "\fB\-\-rsync-path=PROGRAM\fP" Use this to specify what program is to be run on the remote machine to start-up rsync. Often used when rsync is not in the default remote-shell's path (e.g. \fB\-\-rsync-path=/usr/local/bin/rsync\fP). Note that PROGRAM is run with the help of a shell, so it can be any program, script, or command sequence you'd care to run, so long as it does not corrupt the standard-in & standard-out that rsync is using to communicate. .IP One tricky example is to set a different default directory on the remote machine for use with the \fB\-\-relative\fP option. For instance: .RS 4 .IP .nf rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/ .fi .RE .IP "\fB\-\-remote-option=OPTION\fP, \fB\-M\fP" This option is used for more advanced situations where you want certain effects to be limited to one side of the transfer only. For instance, if you want to pass \fB\-\-log-file=FILE\fP and \fB\-\-fake-super\fP to the remote system, specify it like this: .RS 4 .IP .nf rsync -av -M --log-file=foo -M--fake-super src/ dest/ .fi .RE .IP If you want to have an option affect only the local side of a transfer when it normally affects both sides, send its negation to the remote side. Like this: .RS 4 .IP .nf rsync -av -x -M--no-x src/ dest/ .fi .RE .IP Be cautious using this, as it is possible to toggle an option that will cause rsync to have a different idea about what data to expect next over the socket, and that will make it fail in a cryptic fashion. .IP Note that you should use a separate \fB\-M\fP option for each remote option you want to pass. On older rsync versions, the presence of any spaces in the remote-option arg could cause it to be split into separate remote args, but this requires the use of \fB\-\-old-args\fP in a modern rsync. .IP When performing a local transfer, the "local" side is the sender and the "remote" side is the receiver. .IP Note some versions of the popt option-parsing library have a bug in them that prevents you from using an adjacent arg with an equal in it next to a short option letter (e.g. \fB\-M\-\-log-file=/tmp/foo\fP). If this bug affects your version of popt, you can use the version of popt that is included with rsync. .IP "\fB\-\-cvs-exclude\fP, \fB\-C\fP" 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 a file should be ignored. .IP The exclude list is initialized to exclude the following items (these initial items are marked as perishable\ \-\- see the FILTER RULES section): .RS 4 .IP \fBRCS\fP \fBSCCS\fP \fBCVS\fP \fBCVS.adm\fP \fBRCSLOG\fP \fBcvslog.*\fP \fBtags\fP \fBTAGS\fP \fB.make.state\fP \fB.nse_depinfo\fP \fB*~\fP \fB#*\fP \fB.#*\fP \fB,*\fP \fB_$*\fP \fB*$\fP \fB*.old\fP \fB*.bak\fP \fB*.BAK\fP \fB*.orig\fP \fB*.rej\fP \fB.del-*\fP \fB*.a\fP \fB*.olb\fP \fB*.o\fP \fB*.obj\fP \fB*.so\fP \fB*.exe\fP \fB*.Z\fP \fB*.elc\fP \fB*.ln\fP \fBcore\fP \fB.svn/\fP \fB.git/\fP \fB.hg/\fP \fB.bzr/\fP .RE .IP then, files listed in a $HOME/.cvsignore are added to the list and any files listed in the CVSIGNORE environment variable (all cvsignore names are delimited by whitespace). .IP Finally, any file is ignored if it is in the same directory as a .cvsignore file and matches one of the patterns listed therein. Unlike rsync's filter/exclude files, these patterns are split on whitespace. See the \fBcvs\fP(1) manual for more information. .IP If you're combining \fB\-C\fP with your own \fB\-\-filter\fP rules, you should note that these CVS excludes are appended at the end of your own rules, regardless of where the \fB\-C\fP was placed on the command-line. This makes them a lower priority than any rules you specified explicitly. If you want to control where these CVS excludes get inserted into your filter rules, you should omit the \fB\-C\fP as a command-line option and use a combination of \fB\-\-filter=:C\fP and \fB\-\-filter=\-C\fP (either on your command-line or by putting the ":C" and "\-C" rules into a filter file with your other rules). The first option turns on the per-directory scanning for the .cvsignore file. The second option does a one-time import of the CVS excludes mentioned above. .IP "\fB\-\-filter=RULE\fP, \fB\-f\fP" This option allows you to add rules to selectively exclude certain files from the list of files to be transferred. This is most useful in combination with a recursive transfer. .IP You may use as many \fB\-\-filter\fP options on the command line as you like to build up the list of files to exclude. If the filter contains whitespace, be sure to quote it so that the shell gives the rule to rsync as a single argument. The text below also mentions that you can use an underscore to replace the space that separates a rule from its arg. .IP See the FILTER RULES section for detailed information on this option. .IP "\fB\-F\fP" The \fB\-F\fP option is a shorthand for adding two \fB\-\-filter\fP rules to your command. The first time it is used is a shorthand for this rule: .RS 4 .IP .nf --filter='dir-merge /.rsync-filter' .fi .RE .IP This tells rsync to look for per-directory .rsync-filter files that have been sprinkled through the hierarchy and use their rules to filter the files in the transfer. If \fB\-F\fP is repeated, it is a shorthand for this rule: .RS 4 .IP .nf --filter='exclude .rsync-filter' .fi .RE .IP This filters out the .rsync-filter files themselves from the transfer. .IP See the FILTER RULES section for detailed information on how these options work. .IP "\fB\-\-exclude=PATTERN\fP" This option is a simplified form of the \fB\-\-filter\fP option that specifies an exclude rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying \fB\-f'\-\ PATTERN'\fP. .IP See the FILTER RULES section for detailed information on this option. .IP "\fB\-\-exclude-from=FILE\fP" This option is related to the \fB\-\-exclude\fP option, but it specifies a FILE that contains exclude patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with '\fB;\fP' or '\fB#\fP' (filename rules that contain those characters are unaffected). .IP If a line begins with "\fB\-\ \fP" (dash, space) or "\fB+\ \fP" (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an exclude. .IP If a line consists of just "\fB!\fP", then the current filter rules are cleared before adding any further rules. .IP If \fIFILE\fP is '\fB\-\fP', the list will be read from standard input. .IP "\fB\-\-include=PATTERN\fP" This option is a simplified form of the \fB\-\-filter\fP option that specifies an include rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying \fB\-f'+\ PATTERN'\fP. .IP See the FILTER RULES section for detailed information on this option. .IP "\fB\-\-include-from=FILE\fP" This option is related to the \fB\-\-include\fP option, but it specifies a FILE that contains include patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with '\fB;\fP' or '\fB#\fP' (filename rules that contain those characters are unaffected). .IP If a line begins with "\fB\-\ \fP" (dash, space) or "\fB+\ \fP" (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an include. .IP If a line consists of just "\fB!\fP", then the current filter rules are cleared before adding any further rules. .IP If \fIFILE\fP is '\fB\-\fP', the list will be read from standard input. .IP "\fB\-\-files-from=FILE\fP" Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or '\fB\-\fP' for standard input). It also tweaks the default behavior of rsync to make transferring just the specified files and directories easier: .IP .RS .IP o The \fB\-\-relative\fP (\fB\-R\fP) option is implied, which preserves the path information that is specified for each item in the file (use \fB\-\-no-relative\fP or \fB\-\-no-R\fP if you want to turn that off). .IP o The \fB\-\-dirs\fP (\fB\-d\fP) option is implied, which will create directories specified in the list on the destination rather than noisily skipping them (use \fB\-\-no-dirs\fP or \fB\-\-no-d\fP if you want to turn that off). .IP o The \fB\-\-archive\fP (\fB\-a\fP) option's behavior does not imply \fB\-\-recursive\fP (\fB\-r\fP), so specify it explicitly, if you want it. .IP o These side-effects change the default state of rsync, so the position of the \fB\-\-files-from\fP option on the command-line has no bearing on how other options are parsed (e.g. \fB\-a\fP works the same before or after \fB\-\-files-from\fP, as does \fB\-\-no-R\fP and all other options). .RE .IP The filenames that are read from the FILE are all relative to the source dir\ \-\- any leading slashes are removed and no ".." references are allowed to go higher than the source dir. For example, take this command: .RS 4 .IP .nf rsync -a --files-from=/tmp/foo /usr remote:/backup .fi .RE .IP If /tmp/foo contains the string "bin" (or even "/bin"), the /usr/bin directory will be created as /backup/bin on the remote host. If it contains "bin/" (note the trailing slash), the immediate contents of the directory would also be sent (without needing to be explicitly mentioned in the file\ \-\- this began in version 2.6.4). In both cases, if the \fB\-r\fP option was enabled, that dir's entire hierarchy would also be transferred (keep in mind that \fB\-r\fP needs to be specified explicitly with \fB\-\-files-from\fP, since it is not implied by \fB\-a\fP. Also note that the effect of the (enabled by default) \fB\-r\fP option is to duplicate only the path info that is read from the file\ \-\- it does not force the duplication of the source-spec path (/usr in this case). .IP In addition, the \fB\-\-files-from\fP file can be read from the remote host instead of the local host if you specify a "host:" in front of the file (the host must match one end of the transfer). As a short-cut, you can specify just a prefix of ":" to mean "use the remote end of the transfer". For example: .RS 4 .IP .nf rsync -a --files-from=:/path/file-list src:/ /tmp/copy .fi .RE .IP This would copy all the files specified in the /path/file-list file that was located on the remote "src" host. .IP If the \fB\-\-iconv\fP and \fB\-\-secluded-args\fP options are specified and the \fB\-\-files-from\fP filenames are being sent from one host to another, the filenames will be translated from the sending host's charset to the receiving host's charset. .IP NOTE: sorting the list of files in the \fB\-\-files-from\fP input helps rsync to be more efficient, as it will avoid re-visiting the path elements that are shared between adjacent entries. If the input is not sorted, some path elements (implied directories) may end up being scanned multiple times, and rsync will eventually unduplicate them after they get turned into file-list elements. .IP "\fB\-\-from0\fP, \fB\-0\fP" This tells rsync that the rules/filenames it reads from a file are terminated by a null ('\\0') character, not a NL, CR, or CR+LF. This affects \fB\-\-exclude-from\fP, \fB\-\-include-from\fP, \fB\-\-files-from\fP, and any merged files specified in a \fB\-\-filter\fP rule. It does not affect \fB\-\-cvs-exclude\fP (since all names read from a .cvsignore file are split on whitespace). .IP "\fB\-\-old-args\fP" This option tells rsync to stop trying to protect the arg values on the remote side from unintended word-splitting or other misinterpretation. It also allows the client to treat an empty arg as a "." instead of generating an error. .IP The default in a modern rsync is for "shell-active" characters (including spaces) to be backslash-escaped in the args that are sent to the remote shell. The wildcard characters \fB*\fP, \fB?\fP, \fB[\fP, & \fB]\fP are not escaped in filename args (allowing them to expand into multiple filenames) while being protected in option args, such as \fB\-\-usermap\fP. .IP If you have a script that wants to use old-style arg splitting in its filenames, specify this option once. If the remote shell has a problem with any backslash escapes at all, specify this option twice. .IP You may also control this setting via the \fBRSYNC_OLD_ARGS\fP environment variable. If it has the value "1", rsync will default to a single-option setting. If it has the value "2" (or more), rsync will default to a repeated-option setting. If it is "0", you'll get the default escaping behavior. The environment is always overridden by manually specified positive or negative options (the negative is \fB\-\-no-old-args\fP). .IP Note that this option also disables the extra safety check added in 3.2.5 that ensures that a remote sender isn't including extra top-level items in the file-list that you didn't request. This side-effect is necessary because we can't know for sure what names to expect when the remote shell is interpreting the args. .IP This option conflicts with the \fB\-\-secluded-args\fP option. .IP "\fB\-\-secluded-args\fP, \fB\-s\fP" This option sends all filenames and most options to the remote rsync via the protocol (not the remote shell command line) which avoids letting the remote shell modify them. Wildcards are expanded on the remote host by rsync instead of a shell. .IP This is similar to the default backslash-escaping of args that was added in 3.2.4 (see \fB\-\-old-args\fP) in that it prevents things like space splitting and unwanted special-character side-effects. However, it has the drawbacks of being incompatible with older rsync versions (prior to 3.0.0) and of being refused by restricted shells that want to be able to inspect all the option values for safety. .IP This option is useful for those times that you need the argument's character set to be converted for the remote host, if the remote shell is incompatible with the default backslash-escpaing method, or there is some other reason that you want the majority of the options and arguments to bypass the command-line of the remote shell. .IP If you combine this option with \fB\-\-iconv\fP, the args related to the remote side will be translated from the local to the remote character-set. The translation happens before wild-cards are expanded. See also the \fB\-\-files-from\fP option. .IP You may also control this setting via the \fBRSYNC_PROTECT_ARGS\fP environment variable. If it has a non-zero value, this setting will be enabled by default, otherwise it will be disabled by default. Either state is overridden by a manually specified positive or negative version of this option (note that \fB\-\-no-s\fP and \fB\-\-no-secluded-args\fP are the negative versions). This environment variable is also superseded by a non-zero \fBRSYNC_OLD_ARGS\fP export. .IP This option conflicts with the \fB\-\-old-args\fP option. .IP This option used to be called \fB\-\-protect-args\fP (before 3.2.6) and that older name can still be used (though specifying it as \fB\-s\fP is always the easiest and most compatible choice). .IP "\fB\-\-trust-sender\fP" This option disables two extra validation checks that a local client performs on the file list generated by a remote sender. This option should only be used if you trust the sender to not put something malicious in the file list (something that could possibly be done via a modified rsync, a modified shell, or some other similar manipulation). .IP Normally, the rsync client (as of version 3.2.5) runs two extra validation checks when pulling files from a remote rsync: .IP .RS .IP o It verifies that additional arg items didn't get added at the top of the transfer. .IP o It verifies that none of the items in the file list are names that should have been excluded (if filter rules were specified). .RE .IP Note that various options can turn off one or both of these checks if the option interferes with the validation. For instance: .IP .RS .IP o Using a per-directory filter file reads filter rules that only the server knows about, so the filter checking is disabled. .IP o Using the \fB\-\-old-args\fP option allows the sender to manipulate the requested args, so the arg checking is disabled. .IP o Reading the files-from list from the server side means that the client doesn't know the arg list, so the arg checking is disabled. .IP o Using \fB\-\-read-batch\fP disables both checks since the batch file's contents will have been verified when it was created. .RE .IP This option may help an under-powered client server if the extra pattern matching is slowing things down on a huge transfer. It can also be used to work around a currently-unknown bug in the verification logic for a transfer from a trusted sender. .IP When using this option it is a good idea to specify a dedicated destination directory, as discussed in the MULTI-HOST SECURITY section. .IP "\fB\-\-copy-as=USER[:GROUP]\fP" This option instructs rsync to use the USER and (if specified after a colon) the GROUP for the copy operations. This only works if the user that is running rsync has the ability to change users. If the group is not specified then the user's default groups are used. .IP This option can help to reduce the risk of an rsync being run as root into or out of a directory that might have live changes happening to it and you want to make sure that root-level read or write actions of system files are not possible. While you could alternatively run all of rsync as the specified user, sometimes you need the root-level host-access credentials to be used, so this allows rsync to drop root for the copying part of the operation after the remote-shell or daemon connection is established. .IP The option only affects one side of the transfer unless the transfer is local, in which case it affects both sides. Use the \fB\-\-remote-option\fP to affect the remote side, such as \fB\-M\-\-copy-as=joe\fP. For a local transfer, the lsh (or lsh.sh) support file provides a local-shell helper script that can be used to allow a "localhost:" or "lh:" host-spec to be specified without needing to setup any remote shells, allowing you to specify remote options that affect the side of the transfer that is using the host-spec (and using hostname "lh" avoids the overriding of the remote directory to the user's home dir). .IP For example, the following rsync writes the local files as user "joe": .RS 4 .IP .nf sudo rsync -aiv --copy-as=joe host1:backups/joe/ /home/joe/ .fi .RE .IP This makes all files owned by user "joe", limits the groups to those that are available to that user, and makes it impossible for the joe user to do a timed exploit of the path to induce a change to a file that the joe user has no permissions to change. .IP The following command does a local copy into the "dest/" dir as user "joe" (assuming you've installed support/lsh into a dir on your $PATH): .RS 4 .IP .nf sudo rsync -aive lsh -M--copy-as=joe src/ lh:dest/ .fi .RE .IP "\fB\-\-temp-dir=DIR\fP, \fB\-T\fP" This option instructs rsync to use DIR as a scratch directory when creating temporary copies of the files transferred on the receiving side. The default behavior is to create each temporary file in the same directory as the associated destination file. Beginning with rsync 3.1.1, the temp-file names inside the specified DIR will not be prefixed with an extra dot (though they will still have a random suffix added). .IP This option is most often used when the receiving disk partition does not have enough free space to hold a copy of the largest file in the transfer. In this case (i.e. when the scratch directory is on a different disk partition), rsync will not be able to rename each received temporary file over the top of the associated destination file, but instead must copy it into place. Rsync does this by copying the file over the top of the destination file, which means that the destination file will contain truncated data during this copy. If this were not done this way (even if the destination file were first removed, the data locally copied to a temporary file in the destination directory, and then renamed into place) it would be possible for the old file to continue taking up disk space (if someone had it open), and thus there might not be enough room to fit the new version on the disk at the same time. .IP If you are using this option for reasons other than a shortage of disk space, you may wish to combine it with the \fB\-\-delay-updates\fP option, which will ensure that all copied files get put into subdirectories in the destination hierarchy, awaiting the end of the transfer. If you don't have enough room to duplicate all the arriving files on the destination partition, another way to tell rsync that you aren't overly concerned about disk space is to use the \fB\-\-partial-dir\fP option with a relative path; because this tells rsync that it is OK to stash off a copy of a single file in a subdir in the destination hierarchy, rsync will use the partial-dir as a staging area to bring over the copied file, and then rename it into place from there. (Specifying a \fB\-\-partial-dir\fP with an absolute path does not have this side-effect.) .IP "\fB\-\-fuzzy\fP, \fB\-y\fP" This option tells rsync that it should look for a basis file for any destination file that is missing. The current algorithm looks in the same directory as the destination file for either a file that has an identical size and modified-time, or a similarly-named file. If found, rsync uses the fuzzy basis file to try to speed up the transfer. .IP If the option is repeated, the fuzzy scan will also be done in any matching alternate destination directories that are specified via \fB\-\-compare-dest\fP, \fB\-\-copy-dest\fP, or \fB\-\-link-dest\fP. .IP Note that the use of the \fB\-\-delete\fP option might get rid of any potential fuzzy-match files, so either use \fB\-\-delete-after\fP or specify some filename exclusions if you need to prevent this. .IP "\fB\-\-compare-dest=DIR\fP" This option instructs rsync to use \fIDIR\fP on the destination machine as an additional hierarchy to compare destination files against doing transfers (if the files are missing in the destination directory). If a file is found in \fIDIR\fP that is identical to the sender's file, the file will NOT be transferred to the destination directory. This is useful for creating a sparse backup of just files that have changed from an earlier backup. This option is typically used to copy into an empty (or newly created) directory. .IP Beginning in version 2.6.4, multiple \fB\-\-compare-dest\fP directories may be provided, which will cause rsync to search the list in the order specified for an exact match. If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the \fIDIRs\fP will be selected to try to speed up the transfer. .IP If \fIDIR\fP is a relative path, it is relative to the destination directory. See also \fB\-\-copy-dest\fP and \fB\-\-link-dest\fP. .IP NOTE: beginning with version 3.1.0, rsync will remove a file from a non-empty destination hierarchy if an exact match is found in one of the compare-dest hierarchies (making the end result more closely match a fresh copy). .IP "\fB\-\-copy-dest=DIR\fP" This option behaves like \fB\-\-compare-dest\fP, but rsync will also copy unchanged files found in \fIDIR\fP to the destination directory using a local copy. This is useful for doing transfers to a new destination while leaving existing files intact, and then doing a flash-cutover when all files have been successfully transferred. .IP Multiple \fB\-\-copy-dest\fP directories may be provided, which will cause rsync to search the list in the order specified for an unchanged file. If a match is not found, a basis file from one of the \fIDIRs\fP will be selected to try to speed up the transfer. .IP If \fIDIR\fP is a relative path, it is relative to the destination directory. See also \fB\-\-compare-dest\fP and \fB\-\-link-dest\fP. .IP "\fB\-\-link-dest=DIR\fP" This option behaves like \fB\-\-copy-dest\fP, but unchanged files are hard linked from \fIDIR\fP to the destination directory. The files must be identical in all preserved attributes (e.g. permissions, possibly ownership) in order for the files to be linked together. An example: .RS 4 .IP .nf rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/ .fi .RE .IP If files aren't linking, double-check their attributes. Also check if some attributes are getting forced outside of rsync's control, such a mount option that squishes root to a single user, or mounts a removable drive with generic ownership (such as OS X's "Ignore ownership on this volume" option). .IP Beginning in version 2.6.4, multiple \fB\-\-link-dest\fP directories may be provided, which will cause rsync to search the list in the order specified for an exact match (there is a limit of 20 such directories). If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the \fIDIRs\fP will be selected to try to speed up the transfer. .IP This option works best when copying into an empty destination hierarchy, as existing files may get their attributes tweaked, and that can affect alternate destination files via hard-links. Also, itemizing of changes can get a bit muddled. Note that prior to version 3.1.0, an alternate-directory exact match would never be found (nor linked into the destination) when a destination file already exists. .IP Note that if you combine this option with \fB\-\-ignore-times\fP, rsync will not link any files together because it only links identical files together as a substitute for transferring the file, never as an additional check after the file is updated. .IP If \fIDIR\fP is a relative path, it is relative to the destination directory. See also \fB\-\-compare-dest\fP and \fB\-\-copy-dest\fP. .IP Note that rsync versions prior to 2.6.1 had a bug that could prevent \fB\-\-link-dest\fP from working properly for a non-super-user when \fB\-\-owner\fP (\fB\-o\fP) was specified (or implied). You can work-around this bug by avoiding the \fB\-o\fP option (or using \fB\-\-no-o\fP) when sending to an old rsync. .IP "\fB\-\-compress\fP, \fB\-z\fP" With this option, rsync compresses the file data as it is sent to the destination machine, which reduces the amount of data being transmitted\ \-\- something that is useful over a slow connection. .IP Rsync supports multiple compression methods and will choose one for you unless you force the choice using the \fB\-\-compress-choice\fP (\fB\-\-zc\fP) option. .IP Run \fBrsync\ \-\-version\fP to see the default compress list compiled into your version. .IP When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common compress choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, its list is assumed to be "zlib". .IP The default order can be customized by setting the environment variable \fBRSYNC_COMPRESS_LIST\fP to a space-separated list of acceptable compression names. If the string contains a "\fB&\fP" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default compress list is used. Any unknown compression names are discarded from the list, but a list with only invalid names results in a failed negotiation. .IP There are some older rsync versions that were configured to reject a \fB\-z\fP option and require the use of \fB\-zz\fP because their compression library was not compatible with the default zlib compression method. You can usually ignore this weirdness unless the rsync server complains and tells you to specify \fB\-zz\fP. .IP "\fB\-\-compress-choice=STR\fP, \fB\-\-zc=STR\fP" This option can be used to override the automatic negotiation of the compression algorithm that occurs when \fB\-\-compress\fP is used. The option implies \fB\-\-compress\fP unless "none" was specified, which instead implies \fB\-\-no-compress\fP. .IP The compression options that you may be able to use are: .IP .RS .IP o \fBzstd\fP .IP o \fBlz4\fP .IP o \fBzlibx\fP .IP o \fBzlib\fP .IP o \fBnone\fP .RE .IP Run \fBrsync\ \-\-version\fP to see the default compress list compiled into your version (which may differ from the list above). .IP Note that if you see an error about an option named \fB\-\-old-compress\fP or \fB\-\-new-compress\fP, this is rsync trying to send the \fB\-\-compress-choice=zlib\fP or \fB\-\-compress-choice=zlibx\fP option in a backward-compatible manner that more rsync versions understand. This error indicates that the older rsync version on the server will not allow you to force the compression type. .IP Note that the "zlibx" compression algorithm is just the "zlib" algorithm with matched data excluded from the compression stream (to try to make it more compatible with an external zlib implementation). .IP "\fB\-\-compress-level=NUM\fP, \fB\-\-zl=NUM\fP" Explicitly set the compression level to use (see \fB\-\-compress\fP, \fB\-z\fP) instead of letting it default. The \fB\-\-compress\fP option is implied as long as the level chosen is not a "don't compress" level for the compression algorithm that is in effect (e.g. zlib compression treats level 0 as "off"). .IP The level values vary depending on the checksum in effect. Because rsync will negotiate a checksum choice by default (when the remote rsync is new enough), it can be good to combine this option with a \fB\-\-compress-choice\fP (\fB\-\-zc\fP) option unless you're sure of the choice in effect. For example: .RS 4 .IP .nf rsync -aiv --zc=zstd --zl=22 host:src/ dest/ .fi .RE .IP For zlib & zlibx compression the valid values are from 1 to 9 with 6 being the default. Specifying \fB\-\-zl=0\fP turns compression off, and specifying \fB\-\-zl=\-1\fP chooses the default level of 6. .IP For zstd compression the valid values are from \-131072 to 22 with 3 being the default. Specifying 0 chooses the default of 3. .IP For lz4 compression there are no levels, so the value is always 0. .IP If you specify a too-large or too-small value, the number is silently limited to a valid value. This allows you to specify something like \fB\-\-zl=999999999\fP and be assured that you'll end up with the maximum compression level no matter what algorithm was chosen. .IP If you want to know the compression level that is in effect, specify \fB\-\-debug=nstr\fP to see the "negotiated string" results. This will report something like "\fBClient\ compress:\ zstd\ (level\ 3)\fP" (along with the checksum choice in effect). .IP "\fB\-\-skip-compress=LIST\fP" \fBNOTE:\fP no compression method currently supports per-file compression changes, so this option has no effect. .IP Override the list of file suffixes that will be compressed as little as possible. Rsync sets the compression level on a per-file basis based on the file's suffix. If the compression algorithm has an "off" level, then no compression occurs for those files. Other algorithms that support changing the streaming level on-the-fly will have the level minimized to reduces the CPU usage as much as possible for a matching file. .IP The \fBLIST\fP should be one or more file suffixes (without the dot) separated by slashes (\fB/\fP). You may specify an empty string to indicate that no files should be skipped. .IP Simple character-class matching is supported: each must consist of a list of letters inside the square brackets (e.g. no special classes, such as "[:alpha:]", are supported, and '\-' has no special meaning). .IP The characters asterisk (\fB*\fP) and question-mark (\fB?\fP) have no special meaning. .IP Here's an example that specifies 6 suffixes to skip (since 1 of the 5 rules matches 2 suffixes): .RS 4 .IP .nf --skip-compress=gz/jpg/mp[34]/7z/bz2 .fi .RE .IP The default file suffixes in the skip-compress list in this version of rsync are: .RS 4 .IP 3g2 3gp 7z aac ace apk avi bz2 deb dmg ear f4v flac flv gpg gz iso jar jpeg jpg lrz lz lz4 lzma lzo m1a m1v m2a m2ts m2v m4a m4b m4p m4r m4v mka mkv mov mp1 mp2 mp3 mp4 mpa mpeg mpg mpv mts odb odf odg odi odm odp ods odt oga ogg ogm ogv ogx opus otg oth otp ots ott oxt png qt rar rpm rz rzip spx squashfs sxc sxd sxg sxm sxw sz tbz tbz2 tgz tlz ts txz tzo vob war webm webp xz z zip zst .RE .IP This list will be replaced by your \fB\-\-skip-compress\fP list in all but one situation: a copy from a daemon rsync will add your skipped suffixes to its list of non-compressing files (and its list may be configured to a different default). .IP "\fB\-\-numeric-ids\fP" With this option rsync will transfer numeric group and user IDs rather than using user and group names and mapping them at both ends. .IP By default rsync will use the username and groupname to determine what ownership to give files. The special uid 0 and the special group 0 are never mapped via user/group names even if the \fB\-\-numeric-ids\fP option is not specified. .IP If a user or group has no name on the source system or it has no match on the destination system, then the numeric ID from the source system is used instead. See also the \fBuse\ chroot\fP setting in the rsyncd.conf manpage for some comments on how the chroot setting affects rsync's ability to look up the names of the users and groups and what you can do about it. .IP "\fB\-\-usermap=STRING\fP, \fB\-\-groupmap=STRING\fP" These options allow you to specify users and groups that should be mapped to other values by the receiving side. The \fBSTRING\fP is one or more \fBFROM\fP:\fBTO\fP pairs of values separated by commas. Any matching \fBFROM\fP value from the sender is replaced with a \fBTO\fP value from the receiver. You may specify usernames or user IDs for the \fBFROM\fP and \fBTO\fP values, and the \fBFROM\fP value may also be a wild-card string, which will be matched against the sender's names (wild-cards do NOT match against ID numbers, though see below for why a '\fB*\fP' matches everything). You may instead specify a range of ID numbers via an inclusive range: LOW-HIGH. For example: .RS 4 .IP .nf --usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr .fi .RE .IP The first match in the list is the one that is used. You should specify all your user mappings using a single \fB\-\-usermap\fP option, and/or all your group mappings using a single \fB\-\-groupmap\fP option. .IP Note that the sender's name for the 0 user and group are not transmitted to the receiver, so you should either match these values using a 0, or use the names in effect on the receiving side (typically "root"). All other \fBFROM\fP names match those in use on the sending side. All \fBTO\fP names match those in use on the receiving side. .IP Any IDs that do not have a name on the sending side are treated as having an empty name for the purpose of matching. This allows them to be matched via a "\fB*\fP" or using an empty name. For instance: .RS 4 .IP .nf --usermap=:nobody --groupmap=*:nobody .fi .RE .IP When the \fB\-\-numeric-ids\fP option is used, the sender does not send any names, so all the IDs are treated as having an empty name. This means that you will need to specify numeric \fBFROM\fP values if you want to map these nameless IDs to different values. .IP For the \fB\-\-usermap\fP option to work, the receiver will need to be running as a super-user (see also the \fB\-\-super\fP and \fB\-\-fake-super\fP options). For the \fB\-\-groupmap\fP option to work, the receiver will need to have permissions to set that group. .IP Starting with rsync 3.2.4, the \fB\-\-usermap\fP option implies the \fB\-\-owner\fP (\fB\-o\fP) option while the \fB\-\-groupmap\fP option implies the \fB\-\-group\fP (\fB\-g\fP) option (since rsync needs to have those options enabled for the mapping options to work). .IP An older rsync client may need to use \fB\-s\fP to avoid a complaint about wildcard characters, but a modern rsync handles this automatically. .IP "\fB\-\-chown=USER:GROUP\fP" This option forces all files to be owned by USER with group GROUP. This is a simpler interface than using \fB\-\-usermap\fP & \fB\-\-groupmap\fP directly, but it is implemented using those options internally so they cannot be mixed. If either the USER or GROUP is empty, no mapping for the omitted user/group will occur. If GROUP is empty, the trailing colon may be omitted, but if USER is empty, a leading colon must be supplied. .IP If you specify "\fB\-\-chown=foo:bar\fP", this is exactly the same as specifying "\fB\-\-usermap=*:foo\ \-\-groupmap=*:bar\fP", only easier (and with the same implied \fB\-\-owner\fP and/or \fB\-\-group\fP options). .IP An older rsync client may need to use \fB\-s\fP to avoid a complaint about wildcard characters, but a modern rsync handles this automatically. .IP "\fB\-\-timeout=SECONDS\fP" This option allows you to set a maximum I/O timeout in seconds. If no data is transferred for the specified time then rsync will exit. The default is 0, which means no timeout. .IP "\fB\-\-contimeout=SECONDS\fP" This option allows you to set the amount of time that rsync will wait for its connection to an rsync daemon to succeed. If the timeout is reached, rsync exits with an error. .IP "\fB\-\-address=ADDRESS\fP" By default rsync will bind to the wildcard address when connecting to an rsync daemon. The \fB\-\-address\fP option allows you to specify a specific IP address (or hostname) to bind to. .IP See also the daemon version of the \fB\-\-address\fP option. .IP "\fB\-\-port=PORT\fP" This specifies an alternate TCP port number to use rather than the default of 873. This is only needed if you are using the double-colon (::) syntax to connect with an rsync daemon (since the URL syntax has a way to specify the port as a part of the URL). .IP See also the daemon version of the \fB\-\-port\fP option. .IP "\fB\-\-sockopts=OPTIONS\fP" This option can provide endless fun for people who like to tune their systems to the utmost degree. You can set all sorts of socket options which may make transfers faster (or slower!). Read the manpage for the \fBsetsockopt()\fP system call for details on some of the options you may be able to set. By default no special socket options are set. This only affects direct socket connections to a remote rsync daemon. .IP See also the daemon version of the \fB\-\-sockopts\fP option. .IP "\fB\-\-blocking-io\fP" This tells rsync to use blocking I/O when launching a remote shell transport. If the remote shell is either rsh or remsh, rsync defaults to using blocking I/O, otherwise it defaults to using non-blocking I/O. (Note that ssh prefers non-blocking I/O.) .IP "\fB\-\-outbuf=MODE\fP" This sets the output buffering mode. The mode can be None (aka Unbuffered), Line, or Block (aka Full). You may specify as little as a single letter for the mode, and use upper or lower case. .IP The main use of this option is to change Full buffering to Line buffering when rsync's output is going to a file or pipe. .IP "\fB\-\-itemize-changes\fP, \fB\-i\fP" Requests a simple itemized list of the changes that are being made to each file, including attribute changes. This is exactly the same as specifying \fB\-\-out-format='%i\ %n%L'\fP. If you repeat the option, unchanged files will also be output, but only if the receiving rsync is at least version 2.6.7 (you can use \fB\-vv\fP with older versions of rsync, but that also turns on the output of other verbose messages). .IP The "%i" escape has a cryptic output that is 11 letters long. The general format is like the string \fBYXcstpoguax\fP, where \fBY\fP is replaced by the type of update being done, \fBX\fP is replaced by the file-type, and the other letters represent attributes that may be output if they are being modified. .IP The update types that replace the \fBY\fP are as follows: .IP .RS .IP o A \fB<\fP means that a file is being transferred to the remote host (sent). .IP o A \fB>\fP means that a file is being transferred to the local host (received). .IP o A \fBc\fP means that a local change/creation is occurring for the item (such as the creation of a directory or the changing of a symlink, etc.). .IP o A \fBh\fP means that the item is a hard link to another item (requires \fB\-\-hard-links\fP). .IP o A \fB.\fP means that the item is not being updated (though it might have attributes that are being modified). .IP o A \fB*\fP means that the rest of the itemized-output area contains a message (e.g. "deleting"). .RE .IP The file-types that replace the \fBX\fP are: \fBf\fP for a file, a \fBd\fP for a directory, an \fBL\fP for a symlink, a \fBD\fP for a device, and a \fBS\fP for a special file (e.g. named sockets and fifos). .IP The other letters in the string indicate if some attributes of the file have changed, as follows: .IP .RS .IP o "\fB.\fP" \- the attribute is unchanged. .IP o "\fB+\fP" \- the file is newly created. .IP o "\fB\ \fP" \- all the attributes are unchanged (all dots turn to spaces). .IP o "\fB?\fP" \- the change is unknown (when the remote rsync is old). .IP o A letter indicates an attribute is being updated. .RE .IP The attribute that is associated with each letter is as follows: .IP .RS .IP o A \fBc\fP means either that a regular file has a different checksum (requires \fB\-\-checksum\fP) or that a symlink, device, or special file has a changed value. Note that if you are sending files to an rsync prior to 3.0.1, this change flag will be present only for checksum-differing regular files. .IP o A \fBs\fP means the size of a regular file is different and will be updated by the file transfer. .IP o A \fBt\fP means the modification time is different and is being updated to the sender's value (requires \fB\-\-times\fP). An alternate value of \fBT\fP means that the modification time will be set to the transfer time, which happens when a file/symlink/device is updated without \fB\-\-times\fP and when a symlink is changed and the receiver can't set its time. (Note: when using an rsync 3.0.0 client, you might see the \fBs\fP flag combined with \fBt\fP instead of the proper \fBT\fP flag for this time-setting failure.) .IP o A \fBp\fP means the permissions are different and are being updated to the sender's value (requires \fB\-\-perms\fP). .IP o An \fBo\fP means the owner is different and is being updated to the sender's value (requires \fB\-\-owner\fP and super-user privileges). .IP o A \fBg\fP means the group is different and is being updated to the sender's value (requires \fB\-\-group\fP and the authority to set the group). .IP o .IP .RS .IP o A \fBu\fP|\fBn\fP|\fBb\fP indicates the following information: \fBu\fP means the access (use) time is different and is being updated to the sender's value (requires \fB\-\-atimes\fP) .IP o \fBn\fP means the create time (newness) is different and is being updated to the sender's value (requires \fB\-\-crtimes\fP) .IP o \fBb\fP means that both the access and create times are being updated .RE .IP o The \fBa\fP means that the ACL information is being changed. .IP o The \fBx\fP means that the extended attribute information is being changed. .RE .IP One other output is possible: when deleting files, the "%i" will output the string "\fB*deleting\fP" for each item that is being removed (assuming that you are talking to a recent enough rsync that it logs deletions instead of outputting them as a verbose message). .IP "\fB\-\-out-format=FORMAT\fP" This allows you to specify exactly what the rsync client outputs to the user on a per-update basis. The format is a text string containing embedded single-character escape sequences prefixed with a percent (%) character. A default format of "%n%L" is assumed if either \fB\-\-info=name\fP or \fB\-v\fP is specified (this tells you just the name of the file and, if the item is a link, where it points). For a full list of the possible escape characters, see the \fBlog\ format\fP setting in the rsyncd.conf manpage. .IP Specifying the \fB\-\-out-format\fP option implies the \fB\-\-info=name\fP option, which will mention each file, dir, etc. that gets updated in a significant way (a transferred file, a recreated symlink/device, or a touched directory). In addition, if the itemize-changes escape (%i) is included in the string (e.g. if the \fB\-\-itemize-changes\fP option was used), the logging of names increases to mention any item that is changed in any way (as long as the receiving side is at least 2.6.4). See the \fB\-\-itemize-changes\fP option for a description of the output of "%i". .IP Rsync will output the out-format string prior to a file's transfer unless one of the transfer-statistic escapes is requested, in which case the logging is done at the end of the file's transfer. When this late logging is in effect and \fB\-\-progress\fP is also specified, rsync will also output the name of the file being transferred prior to its progress information (followed, of course, by the out-format output). .IP "\fB\-\-log-file=FILE\fP" This option causes rsync to log what it is doing to a file. This is similar to the logging that a daemon does, but can be requested for the client side and/or the server side of a non-daemon transfer. If specified as a client option, transfer logging will be enabled with a default format of "%i %n%L". See the \fB\-\-log-file-format\fP option if you wish to override this. .IP Here's an example command that requests the remote side to log what is happening: .RS 4 .IP .nf rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/ .fi .RE .IP This is very useful if you need to debug why a connection is closing unexpectedly. .IP See also the daemon version of the \fB\-\-log-file\fP option. .IP "\fB\-\-log-file-format=FORMAT\fP" This allows you to specify exactly what per-update logging is put into the file specified by the \fB\-\-log-file\fP option (which must also be specified for this option to have any effect). If you specify an empty string, updated files will not be mentioned in the log file. For a list of the possible escape characters, see the \fBlog\ format\fP setting in the rsyncd.conf manpage. .IP The default FORMAT used if \fB\-\-log-file\fP is specified and this option is not is '%i %n%L'. .IP See also the daemon version of the \fB\-\-log-file-format\fP option. .IP "\fB\-\-stats\fP" This tells rsync to print a verbose set of statistics on the file transfer, allowing you to tell how effective rsync's delta-transfer algorithm is for your data. This option is equivalent to \fB\-\-info=stats2\fP if combined with 0 or 1 \fB\-v\fP options, or \fB\-\-info=stats3\fP if combined with 2 or more \fB\-v\fP options. .IP The current statistics are as follows: .IP .RS .IP o \fBNumber\ of\ files\fP is the count of all "files" (in the generic sense), which includes directories, symlinks, etc. The total count will be followed by a list of counts by filetype (if the total is non-zero). For example: "(reg: 5, dir: 3, link: 2, dev: 1, special: 1)" lists the totals for regular files, directories, symlinks, devices, and special files. If any of value is 0, it is completely omitted from the list. .IP o \fBNumber\ of\ created\ files\fP is the count of how many "files" (generic sense) were created (as opposed to updated). The total count will be followed by a list of counts by filetype (if the total is non-zero). .IP o \fBNumber\ of\ deleted\ files\fP is the count of how many "files" (generic sense) were deleted. The total count will be followed by a list of counts by filetype (if the total is non-zero). Note that this line is only output if deletions are in effect, and only if protocol 31 is being used (the default for rsync 3.1.x). .IP o \fBNumber\ of\ regular\ files\ transferred\fP is the count of normal files that were updated via rsync's delta-transfer algorithm, which does not include dirs, symlinks, etc. Note that rsync 3.1.0 added the word "regular" into this heading. .IP o \fBTotal\ file\ size\fP is the total sum of all file sizes in the transfer. This does not count any size for directories or special files, but does include the size of symlinks. .IP o \fBTotal\ transferred\ file\ size\fP is the total sum of all files sizes for just the transferred files. .IP o \fBLiteral\ data\fP is how much unmatched file-update data we had to send to the receiver for it to recreate the updated files. .IP o \fBMatched\ data\fP is how much data the receiver got locally when recreating the updated files. .IP o \fBFile\ list\ size\fP is how big the file-list data was when the sender sent it to the receiver. This is smaller than the in-memory size for the file list due to some compressing of duplicated data when rsync sends the list. .IP o \fBFile\ list\ generation\ time\fP is the number of seconds that the sender spent creating the file list. This requires a modern rsync on the sending side for this to be present. .IP o \fBFile\ list\ transfer\ time\fP is the number of seconds that the sender spent sending the file list to the receiver. .IP o \fBTotal\ bytes\ sent\fP is the count of all the bytes that rsync sent from the client side to the server side. .IP o \fBTotal\ bytes\ received\fP is the count of all non-message bytes that rsync received by the client side from the server side. "Non-message" bytes means that we don't count the bytes for a verbose message that the server sent to us, which makes the stats more consistent. .RE .IP "\fB\-\-8-bit-output\fP, \fB\-8\fP" This tells rsync to leave all high-bit characters unescaped in the output instead of trying to test them to see if they're valid in the current locale and escaping the invalid ones. All control characters (but never tabs) are always escaped, regardless of this option's setting. .IP The escape idiom that started in 2.6.7 is to output a literal backslash (\fB\\\fP) and a hash (\fB#\fP), followed by exactly 3 octal digits. For example, a newline would output as "\fB\\#012\fP". A literal backslash that is in a filename is not escaped unless it is followed by a hash and 3 digits (0-9). .IP "\fB\-\-human-readable\fP, \fB\-h\fP" Output numbers in a more human-readable format. There are 3 possible levels: .RS .IP .IP 1. output numbers with a separator between each set of 3 digits (either a comma or a period, depending on if the decimal point is represented by a period or a comma). .IP 2. output numbers in units of 1000 (with a character suffix for larger units\ \-\- see below). .IP 3. output numbers in units of 1024. .RE .IP The default is human-readable level 1. Each \fB\-h\fP option increases the level by one. You can take the level down to 0 (to output numbers as pure digits) by specifying the \fB\-\-no-human-readable\fP (\fB\-\-no-h\fP) option. .IP The unit letters that are appended in levels 2 and 3 are: \fBK\fP (kilo), \fBM\fP (mega), \fBG\fP (giga), \fBT\fP (tera), or \fBP\fP (peta). For example, a 1234567-byte file would output as 1.23M in level-2 (assuming that a period is your local decimal point). .IP Backward compatibility note: versions of rsync prior to 3.1.0 do not support human-readable level 1, and they default to level 0. Thus, specifying one or two \fB\-h\fP options will behave in a comparable manner in old and new versions as long as you didn't specify a \fB\-\-no-h\fP option prior to one or more \fB\-h\fP options. See the \fB\-\-list-only\fP option for one difference. .IP "\fB\-\-partial\fP" By default, rsync will delete any partially transferred file if the transfer is interrupted. In some circumstances it is more desirable to keep partially transferred files. Using the \fB\-\-partial\fP option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster. .IP "\fB\-\-partial-dir=DIR\fP" This option modifies the behavior of the \fB\-\-partial\fP option while also implying that it be enabled. This enhanced partial-file method puts any partially transferred files into the specified \fIDIR\fP instead of writing the partial file out to the destination file. On the next transfer, rsync will use a file found in this dir as data to speed up the resumption of the transfer and then delete it after it has served its purpose. .IP Note that if \fB\-\-whole-file\fP is specified (or implied), any partial-dir files that are found for a file that is being updated will simply be removed (since rsync is sending files without using rsync's delta-transfer algorithm). .IP Rsync will create the \fIDIR\fP if it is missing, but just the last dir\ \-\- not the whole path. This makes it easy to use a relative path (such as "\fB\-\-partial-dir=.rsync-partial\fP") to have rsync create the partial-directory in the destination file's directory when it is needed, and then remove it again when the partial file is deleted. Note that this directory removal is only done for a relative pathname, as it is expected that an absolute path is to a directory that is reserved for partial-dir work. .IP If the partial-dir value is not an absolute path, rsync will add an exclude rule at the end of all your existing excludes. This will prevent the sending of any partial-dir files that may exist on the sending side, and will also prevent the untimely deletion of partial-dir items on the receiving side. An example: the above \fB\-\-partial-dir\fP option would add the equivalent of this "perishable" exclude at the end of any other filter rules: \fB\-f\ '\-p\ .rsync-partial/'\fP .IP If you are supplying your own exclude rules, you may need to add your own exclude/hide/protect rule for the partial-dir because: .RS .IP .IP 1. the auto-added rule may be ineffective at the end of your other rules, or .IP 2. you may wish to override rsync's exclude choice. .RE .IP For instance, if you want to make rsync clean-up any left-over partial-dirs that may be lying around, you should specify \fB\-\-delete-after\fP and add a "risk" filter rule, e.g. \fB\-f\ 'R\ .rsync-partial/'\fP. Avoid using \fB\-\-delete-before\fP or \fB\-\-delete-during\fP unless you don't need rsync to use any of the left-over partial-dir data during the current run. .IP IMPORTANT: the \fB\-\-partial-dir\fP should not be writable by other users or it is a security risk! E.g. AVOID "/tmp"! .IP You can also set the partial-dir value the \fBRSYNC_PARTIAL_DIR\fP environment variable. Setting this in the environment does not force \fB\-\-partial\fP to be enabled, but rather it affects where partial files go when \fB\-\-partial\fP is specified. For instance, instead of using \fB\-\-partial-dir=.rsync-tmp\fP along with \fB\-\-progress\fP, you could set \fBRSYNC_PARTIAL_DIR=.rsync-tmp\fP in your environment and then use the \fB\-P\fP option to turn on the use of the .rsync-tmp dir for partial transfers. The only times that the \fB\-\-partial\fP option does not look for this environment value are: .RS .IP .IP 1. when \fB\-\-inplace\fP was specified (since \fB\-\-inplace\fP conflicts with \fB\-\-partial-dir\fP), and .IP 2. when \fB\-\-delay-updates\fP was specified (see below). .RE .IP When a modern rsync resumes the transfer of a file in the partial-dir, that partial file is now updated in-place instead of creating yet another tmp-file copy (so it maxes out at dest + tmp instead of dest + partial + tmp). This requires both ends of the transfer to be at least version 3.2.0. .IP For the purposes of the daemon-config's "\fBrefuse\ options\fP" setting, \fB\-\-partial-dir\fP does \fInot\fP imply \fB\-\-partial\fP. This is so that a refusal of the \fB\-\-partial\fP option can be used to disallow the overwriting of destination files with a partial transfer, while still allowing the safer idiom provided by \fB\-\-partial-dir\fP. .IP "\fB\-\-delay-updates\fP" This option puts the temporary file from each updated file into a holding directory until the end of the transfer, at which time all the files are renamed into place in rapid succession. This attempts to make the updating of the files a little more atomic. By default the files are placed into a directory named \fB.~tmp~\fP in each file's destination directory, but if you've specified the \fB\-\-partial-dir\fP option, that directory will be used instead. See the comments in the \fB\-\-partial-dir\fP section for a discussion of how this \fB.~tmp~\fP dir will be excluded from the transfer, and what you can do if you want rsync to cleanup old \fB.~tmp~\fP dirs that might be lying around. Conflicts with \fB\-\-inplace\fP and \fB\-\-append\fP. .IP This option implies \fB\-\-no-inc-recursive\fP since it needs the full file list in memory in order to be able to iterate over it at the end. .IP This option uses more memory on the receiving side (one bit per file transferred) and also requires enough free disk space on the receiving side to hold an additional copy of all the updated files. Note also that you should not use an absolute path to \fB\-\-partial-dir\fP unless: .RS .IP .IP 1. there is no chance of any of the files in the transfer having the same name (since all the updated files will be put into a single directory if the path is absolute), and .IP 2. there are no mount points in the hierarchy (since the delayed updates will fail if they can't be renamed into place). .RE .IP See also the "atomic-rsync" python script in the "support" subdir for an update algorithm that is even more atomic (it uses \fB\-\-link-dest\fP and a parallel hierarchy of files). .IP "\fB\-\-prune-empty-dirs\fP, \fB\-m\fP" This option tells the receiving rsync to get rid of empty directories from the file-list, including nested directories that have no non-directory children. This is useful for avoiding the creation of a bunch of useless directories when the sending rsync is recursively scanning a hierarchy of files using include/exclude/filter rules. .IP This option can still leave empty directories on the receiving side if you make use of TRANSFER_RULES. .IP Because the file-list is actually being pruned, this option also affects what directories get deleted when a delete is active. However, keep in mind that excluded files and directories can prevent existing items from being deleted due to an exclude both hiding source files and protecting destination files. See the perishable filter-rule option for how to avoid this. .IP You can prevent the pruning of certain empty directories from the file-list by using a global "protect" filter. For instance, this option would ensure that the directory "emptydir" was kept in the file-list: .RS 4 .IP .nf --filter 'protect emptydir/' .fi .RE .IP Here's an example that copies all .pdf files in a hierarchy, only creating the necessary destination directories to hold the .pdf files, and ensures that any superfluous files and directories in the destination are removed (note the hide filter of non-directories being used instead of an exclude): .RS 4 .IP .nf rsync -avm --del --include='*.pdf' -f 'hide,! */' src/ dest .fi .RE .IP If you didn't want to remove superfluous destination files, the more time-honored options of \fB\-\-include='*/'\ \-\-exclude='*'\fP would work fine in place of the hide-filter (if that is more natural to you). .IP "\fB\-\-progress\fP" This option tells rsync to print information showing the progress of the transfer. This gives a bored user something to watch. With a modern rsync this is the same as specifying \fB\-\-info=flist2,name,progress\fP, but any user-supplied settings for those info flags takes precedence (e.g. \fB\-\-info=flist0\ \-\-progress\fP). .IP While rsync is transferring a regular file, it updates a progress line that looks like this: .RS 4 .IP .nf 782448 63% 110.64kB/s 0:00:04 .fi .RE .IP In this example, the receiver has reconstructed 782448 bytes or 63% of the sender's file, which is being reconstructed at a rate of 110.64 kilobytes per second, and the transfer will finish in 4 seconds if the current rate is maintained until the end. .IP These statistics can be misleading if rsync's delta-transfer algorithm is in use. For example, if the sender's file consists of the basis file followed by additional data, the reported rate will probably drop dramatically when the receiver gets to the literal data, and the transfer will probably take much longer to finish than the receiver estimated as it was finishing the matched part of the file. .IP When the file transfer finishes, rsync replaces the progress line with a summary line that looks like this: .RS 4 .IP .nf 1,238,099 100% 146.38kB/s 0:00:08 (xfr#5, to-chk=169/396) .fi .RE .IP In this example, the file was 1,238,099 bytes long in total, the average rate of transfer for the whole file was 146.38 kilobytes per second over the 8 seconds that it took to complete, it was the 5th transfer of a regular file during the current rsync session, and there are 169 more files for the receiver to check (to see if they are up-to-date or not) remaining out of the 396 total files in the file-list. .IP In an incremental recursion scan, rsync won't know the total number of files in the file-list until it reaches the ends of the scan, but since it starts to transfer files during the scan, it will display a line with the text "ir-chk" (for incremental recursion check) instead of "to-chk" until the point that it knows the full size of the list, at which point it will switch to using "to-chk". Thus, seeing "ir-chk" lets you know that the total count of files in the file list is still going to increase (and each time it does, the count of files left to check will increase by the number of the files added to the list). .IP "\fB\-P\fP" The \fB\-P\fP option is equivalent to "\fB\-\-partial\fP \fB\-\-progress\fP". Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted. .IP There is also a \fB\-\-info=progress2\fP option that outputs statistics based on the whole transfer, rather than individual files. Use this flag without outputting a filename (e.g. avoid \fB\-v\fP or specify \fB\-\-info=name0\fP) if you want to see how the transfer is doing without scrolling the screen with a lot of names. (You don't need to specify the \fB\-\-progress\fP option in order to use \fB\-\-info=progress2\fP.) .IP Finally, you can get an instant progress report by sending rsync a signal of either SIGINFO or SIGVTALRM. On BSD systems, a SIGINFO is generated by typing a Ctrl+T (Linux doesn't currently support a SIGINFO signal). When the client-side process receives one of those signals, it sets a flag to output a single progress report which is output when the current file transfer finishes (so it may take a little time if a big file is being handled when the signal arrives). A filename is output (if needed) followed by the \fB\-\-info=progress2\fP format of progress info. If you don't know which of the 3 rsync processes is the client process, it's OK to signal all of them (since the non-client processes ignore the signal). .IP CAUTION: sending SIGVTALRM to an older rsync (pre-3.2.0) will kill it. .IP "\fB\-\-password-file=FILE\fP" This option allows you to provide a password for accessing an rsync daemon via a file or via standard input if \fBFILE\fP is \fB\-\fP. The file should contain just the password on the first line (all other lines are ignored). Rsync will exit with an error if \fBFILE\fP is world readable or if a root-run rsync command finds a non-root-owned file. .IP This option does not supply a password to a remote shell transport such as ssh; to learn how to do that, consult the remote shell's documentation. When accessing an rsync daemon using a remote shell as the transport, this option only comes into effect after the remote shell finishes its authentication (i.e. if you have also specified a password in the daemon's config file). .IP "\fB\-\-early-input=FILE\fP" This option allows rsync to send up to 5K of data to the "early exec" script on its stdin. One possible use of this data is to give the script a secret that can be used to mount an encrypted filesystem (which you should unmount in the the "post-xfer exec" script). .IP The daemon must be at least version 3.2.1. .IP "\fB\-\-list-only\fP" This option will cause the source files to be listed instead of transferred. This option is inferred if there is a single source arg and no destination specified, so its main uses are: .RS .IP .IP 1. to turn a copy command that includes a destination arg into a file-listing command, or .IP 2. to be able to specify more than one source arg. Note: be sure to include the destination. .RE .IP CAUTION: keep in mind that a source arg with a wild-card is expanded by the shell into multiple args, so it is never safe to try to specify a single wild-card arg to try to infer this option. A safe example is: .RS 4 .IP .nf rsync -av --list-only foo* dest/ .fi .RE .IP This option always uses an output format that looks similar to this: .RS 4 .IP .nf drwxrwxr-x 4,096 2022/09/30 12:53:11 support -rw-rw-r-- 80 2005/01/11 10:37:37 support/Makefile .fi .RE .IP The only option that affects this output style is (as of 3.1.0) the \fB\-\-human-readable\fP (\fB\-h\fP) option. The default is to output sizes as byte counts with digit separators (in a 14-character-width column). Specifying at least one \fB\-h\fP option makes the sizes output with unit suffixes. If you want old-style bytecount sizes without digit separators (and an 11-character-width column) use \fB\-\-no-h\fP. .IP Compatibility note: when requesting a remote listing of files from an rsync that is version 2.6.3 or older, you may encounter an error if you ask for a non-recursive listing. This is because a file listing implies the \fB\-\-dirs\fP option w/o \fB\-\-recursive\fP, and older rsyncs don't have that option. To avoid this problem, either specify the \fB\-\-no-dirs\fP option (if you don't need to expand a directory's content), or turn on recursion and exclude the content of subdirectories: \fB\-r\ \-\-exclude='/*/*'\fP. .IP "\fB\-\-bwlimit=RATE\fP" This option allows you to specify the maximum transfer rate for the data sent over the socket, specified in units per second. The RATE value can be suffixed with a string to indicate a size multiplier, and may be a fractional value (e.g. \fB\-\-bwlimit=1.5m\fP). If no suffix is specified, the value will be assumed to be in units of 1024 bytes (as if "K" or "KiB" had been appended). See the \fB\-\-max-size\fP option for a description of all the available suffixes. A value of 0 specifies no limit. .IP For backward-compatibility reasons, the rate limit will be rounded to the nearest KiB unit, so no rate smaller than 1024 bytes per second is possible. .IP Rsync writes data over the socket in blocks, and this option both limits the size of the blocks that rsync writes, and tries to keep the average transfer rate at the requested limit. Some burstiness may be seen where rsync writes out a block of data and then sleeps to bring the average rate into compliance. .IP Due to the internal buffering of data, the \fB\-\-progress\fP option may not be an accurate reflection on how fast the data is being sent. This is because some files can show up as being rapidly sent when the data is quickly buffered, while other can show up as very slow when the flushing of the output buffer occurs. This may be fixed in a future version. .IP See also the daemon version of the \fB\-\-bwlimit\fP option. .IP "\fB\-\-stop-after=MINS\fP, (\fB\-\-time-limit=MINS\fP)" This option tells rsync to stop copying when the specified number of minutes has elapsed. .IP For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using \fB\-\-remote-option\fP (\fB\-M\fP), should the need arise. .IP The \fB\-\-time-limit\fP version of this option is deprecated. .IP "\fB\-\-stop-at=y-m-dTh:m\fP" This option tells rsync to stop copying when the specified point in time has been reached. The date & time can be fully specified in a numeric format of year-month-dayThour:minute (e.g. 2000-12-31T23:59) in the local timezone. You may choose to separate the date numbers using slashes instead of dashes. .IP The value can also be abbreviated in a variety of ways, such as specifying a 2-digit year and/or leaving off various values. In all cases, the value will be taken to be the next possible point in time where the supplied information matches. If the value specifies the current time or a past time, rsync exits with an error. .IP For example, "1-30" specifies the next January 30th (at midnight local time), "14:00" specifies the next 2 P.M., "1" specifies the next 1st of the month at midnight, "31" specifies the next month where we can stop on its 31st day, and ":59" specifies the next 59th minute after the hour. .IP For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using \fB\-\-remote-option\fP (\fB\-M\fP), should the need arise. Do keep in mind that the remote host may have a different default timezone than your local host. .IP "\fB\-\-fsync\fP" Cause the receiving side to fsync each finished file. This may slow down the transfer, but can help to provide peace of mind when updating critical files. .IP "\fB\-\-write-batch=FILE\fP" Record a file that can later be applied to another identical destination with \fB\-\-read-batch\fP. See the "BATCH MODE" section for details, and also the \fB\-\-only-write-batch\fP option. .IP This option overrides the negotiated checksum & compress lists and always negotiates a choice based on old-school md5/md4/zlib choices. If you want a more modern choice, use the \fB\-\-checksum-choice\fP (\fB\-\-cc\fP) and/or \fB\-\-compress-choice\fP (\fB\-\-zc\fP) options. .IP "\fB\-\-only-write-batch=FILE\fP" Works like \fB\-\-write-batch\fP, except that no updates are made on the destination system when creating the batch. This lets you transport the changes to the destination system via some other means and then apply the changes via \fB\-\-read-batch\fP. .IP Note that you can feel free to write the batch directly to some portable media: if this media fills to capacity before the end of the transfer, you can just apply that partial transfer to the destination and repeat the whole process to get the rest of the changes (as long as you don't mind a partially updated destination system while the multi-update cycle is happening). .IP Also note that you only save bandwidth when pushing changes to a remote system because this allows the batched data to be diverted from the sender into the batch file without having to flow over the wire to the receiver (when pulling, the sender is remote, and thus can't write the batch). .IP "\fB\-\-read-batch=FILE\fP" Apply all of the changes stored in FILE, a file previously generated by \fB\-\-write-batch\fP. If \fIFILE\fP is \fB\-\fP, the batch data will be read from standard input. See the "BATCH MODE" section for details. .IP "\fB\-\-protocol=NUM\fP" Force an older protocol version to be used. This is useful for creating a batch file that is compatible with an older version of rsync. For instance, if rsync 2.6.4 is being used with the \fB\-\-write-batch\fP option, but rsync 2.6.3 is what will be used to run the \fB\-\-read-batch\fP option, you should use "\-\-protocol=28" when creating the batch file to force the older protocol version to be used in the batch file (assuming you can't upgrade the rsync on the reading system). .IP "\fB\-\-iconv=CONVERT_SPEC\fP" Rsync can convert filenames between character sets using this option. Using a CONVERT_SPEC of "." tells rsync to look up the default character-set via the locale setting. Alternately, you can fully specify what conversion to do by giving a local and a remote charset separated by a comma in the order \fB\-\-iconv=LOCAL,REMOTE\fP, e.g. \fB\-\-iconv=utf8,iso88591\fP. This order ensures that the option will stay the same whether you're pushing or pulling files. Finally, you can specify either \fB\-\-no-iconv\fP or a CONVERT_SPEC of "\-" to turn off any conversion. The default setting of this option is site-specific, and can also be affected via the \fBRSYNC_ICONV\fP environment variable. .IP For a list of what charset names your local iconv library supports, you can run "\fBiconv\ \-\-list\fP". .IP If you specify the \fB\-\-secluded-args\fP (\fB\-s\fP) option, rsync will translate the filenames you specify on the command-line that are being sent to the remote host. See also the \fB\-\-files-from\fP option. .IP Note that rsync does not do any conversion of names in filter files (including include/exclude files). It is up to you to ensure that you're specifying matching rules that can match on both sides of the transfer. For instance, you can specify extra include/exclude rules if there are filename differences on the two sides that need to be accounted for. .IP When you pass an \fB\-\-iconv\fP option to an rsync daemon that allows it, the daemon uses the charset specified in its "charset" configuration parameter regardless of the remote charset you actually pass. Thus, you may feel free to specify just the local charset for a daemon transfer (e.g. \fB\-\-iconv=utf8\fP). .IP "\fB\-\-ipv4\fP, \fB\-4\fP or \fB\-\-ipv6\fP, \fB\-6\fP" Tells rsync to prefer IPv4/IPv6 when creating sockets or running ssh. This affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an rsync daemon, as well as the forwarding of the \fB\-4\fP or \fB\-6\fP option to ssh when rsync can deduce that ssh is being used as the remote shell. For other remote shells you'll need to specify the "\fB\-\-rsh\ SHELL\ \-4\fP" option directly (or whatever IPv4/IPv6 hint options it uses). .IP See also the daemon version of these options. .IP If rsync was compiled without support for IPv6, the \fB\-\-ipv6\fP option will have no effect. The \fBrsync\ \-\-version\fP output will contain "\fBno\ IPv6\fP" if is the case. .IP "\fB\-\-checksum-seed=NUM\fP" Set the checksum seed to the integer NUM. This 4 byte checksum seed is included in each block and MD4 file checksum calculation (the more modern MD5 file checksums don't use a seed). By default the checksum seed is generated by the server and defaults to the current \fBtime\fP(). This option is used to set a specific checksum seed, which is useful for applications that want repeatable block checksums, or in the case where the user wants a more random checksum seed. Setting NUM to 0 causes rsync to use the default of \fBtime\fP() for checksum seed. .P .SH "DAEMON OPTIONS" .P The options allowed when starting an rsync daemon are as follows: .P .IP "\fB\-\-daemon\fP" This tells rsync that it is to run as a daemon. The daemon you start running may be accessed using an rsync client using the \fBhost::module\fP or \fBrsync://host/module/\fP syntax. .IP If standard input is a socket then rsync will assume that it is being run via inetd, otherwise it will detach from the current terminal and become a background daemon. The daemon will read the config file (rsyncd.conf) on each connect made by a client and respond to requests accordingly. .IP See the \fBrsyncd.conf\fP(5) manpage for more details. .IP "\fB\-\-address=ADDRESS\fP" By default rsync will bind to the wildcard address when run as a daemon with the \fB\-\-daemon\fP option. The \fB\-\-address\fP option allows you to specify a specific IP address (or hostname) to bind to. This makes virtual hosting possible in conjunction with the \fB\-\-config\fP option. .IP See also the address global option in the rsyncd.conf manpage and the client version of the \fB\-\-address\fP option. .IP "\fB\-\-bwlimit=RATE\fP" This option allows you to specify the maximum transfer rate for the data the daemon sends over the socket. The client can still specify a smaller \fB\-\-bwlimit\fP value, but no larger value will be allowed. .IP See the client version of the \fB\-\-bwlimit\fP option for some extra details. .IP "\fB\-\-config=FILE\fP" This specifies an alternate config file than the default. This is only relevant when \fB\-\-daemon\fP is specified. The default is /etc/rsyncd.conf unless the daemon is running over a remote shell program and the remote user is not the super-user; in that case the default is rsyncd.conf in the current directory (typically $HOME). .IP "\fB\-\-dparam=OVERRIDE\fP, \fB\-M\fP" This option can be used to set a daemon-config parameter when starting up rsync in daemon mode. It is equivalent to adding the parameter at the end of the global settings prior to the first module's definition. The parameter names can be specified without spaces, if you so desire. For instance: .RS 4 .IP .nf rsync --daemon -M pidfile=/path/rsync.pid .fi .RE .IP "\fB\-\-no-detach\fP" When running as a daemon, this option instructs rsync to not detach itself and become a background process. This option is required when running as a service on Cygwin, and may also be useful when rsync is supervised by a program such as \fBdaemontools\fP or AIX's \fBSystem\ Resource\ Controller\fP. \fB\-\-no-detach\fP is also recommended when rsync is run under a debugger. This option has no effect if rsync is run from inetd or sshd. .IP "\fB\-\-port=PORT\fP" This specifies an alternate TCP port number for the daemon to listen on rather than the default of 873. .IP See also the client version of the \fB\-\-port\fP option and the port global setting in the rsyncd.conf manpage. .IP "\fB\-\-log-file=FILE\fP" This option tells the rsync daemon to use the given log-file name instead of using the "\fBlog\ file\fP" setting in the config file. .IP See also the client version of the \fB\-\-log-file\fP option. .IP "\fB\-\-log-file-format=FORMAT\fP" This option tells the rsync daemon to use the given FORMAT string instead of using the "\fBlog\ format\fP" setting in the config file. It also enables "\fBtransfer\ logging\fP" unless the string is empty, in which case transfer logging is turned off. .IP See also the client version of the \fB\-\-log-file-format\fP option. .IP "\fB\-\-sockopts\fP" This overrides the \fBsocket\ options\fP setting in the rsyncd.conf file and has the same syntax. .IP See also the client version of the \fB\-\-sockopts\fP option. .IP "\fB\-\-verbose\fP, \fB\-v\fP" This option increases the amount of information the daemon logs during its startup phase. After the client connects, the daemon's verbosity level will be controlled by the options that the client used and the "\fBmax\ verbosity\fP" setting in the module's config section. .IP See also the client version of the \fB\-\-verbose\fP option. .IP "\fB\-\-ipv4\fP, \fB\-4\fP or \fB\-\-ipv6\fP, \fB\-6\fP" Tells rsync to prefer IPv4/IPv6 when creating the incoming sockets that the rsync daemon will use to listen for connections. One of these options may be required in older versions of Linux to work around an IPv6 bug in the kernel (if you see an "address already in use" error when nothing else is using the port, try specifying \fB\-\-ipv6\fP or \fB\-\-ipv4\fP when starting the daemon). .IP See also the client version of these options. .IP If rsync was compiled without support for IPv6, the \fB\-\-ipv6\fP option will have no effect. The \fBrsync\ \-\-version\fP output will contain "\fBno\ IPv6\fP" if is the case. .IP "\fB\-\-help\fP, \fB\-h\fP" When specified after \fB\-\-daemon\fP, print a short help page describing the options available for starting an rsync daemon. .P .SH "FILTER RULES" .P The filter rules allow for custom control of several aspects of how files are handled: .P .IP o Control which files the sending side puts into the file list that describes the transfer hierarchy .IP o Control which files the receiving side protects from deletion when the file is not in the sender's file list .IP o Control which extended attribute names are skipped when copying xattrs .P The rules are either directly specified via option arguments or they can be read in from one or more files. The filter-rule files can even be a part of the hierarchy of files being copied, affecting different parts of the tree in different ways. .P .SS "SIMPLE INCLUDE/EXCLUDE RULES" .P We will first cover the basics of how include & exclude rules affect what files are transferred, ignoring any deletion side-effects. Filter rules mainly affect the contents of directories that rsync is "recursing" into, but they can also affect a top-level item in the transfer that was specified as a argument. .P The default for any unmatched file/dir is for it to be included in the transfer, which puts the file/dir into the sender's file list. The use of an exclude rule causes one or more matching files/dirs to be left out of the sender's file list. An include rule can be used to limit the effect of an exclude rule that is matching too many files. .P The order of the rules is important because the first rule that matches is the one that takes effect. Thus, if an early rule excludes a file, no include rule that comes after it can have any effect. This means that you must place any include overrides somewhere prior to the exclude that it is intended to limit. .P When a directory is excluded, all its contents and sub-contents are also excluded. The sender doesn't scan through any of it at all, which can save a lot of time when skipping large unneeded sub-trees. .P It is also important to understand that the include/exclude rules are applied to every file and directory that the sender is recursing into. Thus, if you want a particular deep file to be included, you have to make sure that none of the directories that must be traversed on the way down to that file are excluded or else the file will never be discovered to be included. As an example, if the directory "\fBa/path\fP" was given as a transfer argument and you want to ensure that the file "\fBa/path/down/deep/wanted.txt\fP" is a part of the transfer, then the sender must not exclude the directories "\fBa/path\fP", "\fBa/path/down\fP", or "\fBa/path/down/deep\fP" as it makes it way scanning through the file tree. .P When you are working on the rules, it can be helpful to ask rsync to tell you what is being excluded/included and why. Specifying \fB\-\-debug=FILTER\fP or (when pulling files) \fB\-M\-\-debug=FILTER\fP turns on level 1 of the FILTER debug information that will output a message any time that a file or directory is included or excluded and which rule it matched. Beginning in 3.2.4 it will also warn if a filter rule has trailing whitespace, since an exclude of "foo\ " (with a trailing space) will not exclude a file named "foo". .P Exclude and include rules can specify wildcard PATTERN MATCHING RULES (similar to shell wildcards) that allow you to match things like a file suffix or a portion of a filename. .P A rule can be limited to only affecting a directory by putting a trailing slash onto the filename. .P .SS "SIMPLE INCLUDE/EXCLUDE EXAMPLE" .P With the following file tree created on the sending side: .RS 4 .P .nf mkdir x/ touch x/file.txt mkdir x/y/ touch x/y/file.txt touch x/y/zzz.txt mkdir x/z/ touch x/z/file.txt .fi .RE .P Then the following rsync command will transfer the file "\fBx/y/file.txt\fP" and the directories needed to hold it, resulting in the path "\fB/tmp/x/y/file.txt\fP" existing on the remote host: .RS 4 .P .nf rsync -ai -f'+ x/' -f'+ x/y/' -f'+ x/y/file.txt' -f'- *' x host:/tmp/ .fi .RE .P Aside: this copy could also have been accomplished using the \fB\-R\fP option (though the 2 commands behave differently if deletions are enabled): .RS 4 .P .nf rsync -aiR x/y/file.txt host:/tmp/ .fi .RE .P The following command does not need an include of the "x" directory because it is not a part of the transfer (note the traililng slash). Running this command would copy just "\fB/tmp/x/file.txt\fP" because the "y" and "z" dirs get excluded: .RS 4 .P .nf rsync -ai -f'+ file.txt' -f'- *' x/ host:/tmp/x/ .fi .RE .P This command would omit the zzz.txt file while copying "x" and everything else it contains: .RS 4 .P .nf rsync -ai -f'- zzz.txt' x host:/tmp/ .fi .RE .P .SS "FILTER RULES WHEN DELETING" .P By default the include & exclude filter rules affect both the sender (as it creates its file list) and the receiver (as it creates its file lists for calculating deletions). If no delete option is in effect, the receiver skips creating the delete-related file lists. This two-sided default can be manually overridden so that you are only specifying sender rules or receiver rules, as described in the FILTER RULES IN DEPTH section. .P When deleting, an exclude protects a file from being removed on the receiving side while an include overrides that protection (putting the file at risk of deletion). The default is for a file to be at risk\ \-\- its safety depends on it matching a corresponding file from the sender. .P An example of the two-sided exclude effect can be illustrated by the copying of a C development directory between 2 systems. When doing a touch-up copy, you might want to skip copying the built executable and the \fB.o\fP files (sender hide) so that the receiving side can build their own and not lose any object files that are already correct (receiver protect). For instance: .RS 4 .P .nf rsync -ai --del -f'- *.o' -f'- cmd' src host:/dest/ .fi .RE .P Note that using \fB\-f'\-p\ *.o'\fP is even better than \fB\-f'\-\ *.o'\fP if there is a chance that the directory structure may have changed. The "p" modifier is discussed in FILTER RULE MODIFIERS. .P One final note, if your shell doesn't mind unexpanded wildcards, you could simplify the typing of the filter options by using an underscore in place of the space and leaving off the quotes. For instance, \fB\-f\ \-_*.o\ \-f\ \-_cmd\fP (and similar) could be used instead of the filter options above. .P .SS "FILTER RULES IN DEPTH" .P Rsync supports old-style include/exclude rules and new-style filter rules. The older rules are specified using \fB\-\-include\fP and \fB\-\-exclude\fP as well as the \fB\-\-include-from\fP and \fB\-\-exclude-from\fP. These are limited in behavior but they don't require a "\-" or "+" prefix. An old-style exclude rule is turned into a "\fB\-\ name\fP" filter rule (with no modifiers) and an old-style include rule is turned into a "\fB+\ name\fP" filter rule (with no modifiers). .P Rsync builds an ordered list of filter rules as specified on the command-line and/or read-in from files. New style filter rules have the following syntax: .RS 4 .P .nf RULE [PATTERN_OR_FILENAME] RULE,MODIFIERS [PATTERN_OR_FILENAME] .fi .RE .P You have your choice of using either short or long RULE names, as described below. If you use a short-named rule, the ',' separating the RULE from the MODIFIERS is optional. The PATTERN or FILENAME that follows (when present) must come after either a single space or an underscore (_). Any additional spaces and/or underscores are considered to be a part of the pattern name. Here are the available rule prefixes: .P .IP "\fBexclude,\ '\-'\fP" specifies an exclude pattern that (by default) is both a \fBhide\fP and a \fBprotect\fP. .IP "\fBinclude,\ '+'\fP" specifies an include pattern that (by default) is both a \fBshow\fP and a \fBrisk\fP. .IP "\fBmerge,\ '.'\fP" specifies a merge-file on the client side to read for more rules. .IP "\fBdir-merge,\ ':'\fP" specifies a per-directory merge-file. Using this kind of filter rule requires that you trust the sending side's filter checking, so it has the side-effect mentioned under the \fB\-\-trust-sender\fP option. .IP "\fBhide,\ 'H'\fP" specifies a pattern for hiding files from the transfer. Equivalent to a sender-only exclude, so \fB\-f'H\ foo'\fP could also be specified as \fB\-f'\-s\ foo'\fP. .IP "\fBshow,\ 'S'\fP" files that match the pattern are not hidden. Equivalent to a sender-only include, so \fB\-f'S\ foo'\fP could also be specified as \fB\-f'+s\ foo'\fP. .IP "\fBprotect,\ 'P'\fP" specifies a pattern for protecting files from deletion. Equivalent to a receiver-only exclude, so \fB\-f'P\ foo'\fP could also be specified as \fB\-f'\-r\ foo'\fP. .IP "\fBrisk,\ 'R'\fP" files that match the pattern are not protected. Equivalent to a receiver-only include, so \fB\-f'R\ foo'\fP could also be specified as \fB\-f'+r\ foo'\fP. .IP "\fBclear,\ '!'\fP" clears the current include/exclude list (takes no arg) .P When rules are being read from a file (using merge or dir-merge), empty lines are ignored, as are whole-line comments that start with a '\fB#\fP' (filename rules that contain a hash character are unaffected). .P Note also that the \fB\-\-filter\fP, \fB\-\-include\fP, and \fB\-\-exclude\fP options take one rule/pattern each. To add multiple ones, you can repeat the options on the command-line, use the merge-file syntax of the \fB\-\-filter\fP option, or the \fB\-\-include-from\fP / \fB\-\-exclude-from\fP options. .P .SS "PATTERN MATCHING RULES" .P Most of the rules mentioned above take an argument that specifies what the rule should match. If rsync is recursing through a directory hierarchy, keep in mind that each pattern is matched against the name of every directory in the descent path as rsync finds the filenames to send. .P The matching rules for the pattern argument take several forms: .P .IP o If a pattern contains a \fB/\fP (not counting a trailing slash) or a "\fB**\fP" (which can match a slash), then the pattern is matched against the full pathname, including any leading directories within the transfer. If the pattern doesn't contain a (non-trailing) \fB/\fP or a "\fB**\fP", then it is matched only against the final component of the filename or pathname. For example, \fBfoo\fP means that the final path component must be "foo" while \fBfoo/bar\fP would match the last 2 elements of the path (as long as both elements are within the transfer). .IP o A pattern that ends with a \fB/\fP only matches a directory, not a regular file, symlink, or device. .IP o A pattern that starts with a \fB/\fP is anchored to the start of the transfer path instead of the end. For example, \fB/foo/**\fP or \fB/foo/bar/**\fP match only leading elements in the path. If the rule is read from a per-directory filter file, the transfer path being matched will begin at the level of the filter file instead of the top of the transfer. See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for a full discussion of how to specify a pattern that matches at the root of the transfer. .P Rsync chooses between doing a simple string match and wildcard matching by checking if the pattern contains one of these three wildcard characters: '\fB*\fP', \&'\fB?\fP', and '\fB[\fP' : .P .IP o a '\fB?\fP' matches any single character except a slash (\fB/\fP). .IP o a '\fB*\fP' matches zero or more non-slash characters. .IP o a '\fB**\fP' matches zero or more characters, including slashes. .IP o a '\fB[\fP' introduces a character class, such as \fB[a-z]\fP or \fB[[:alpha:]]\fP, that must match one character. .IP o a trailing \fB***\fP in the pattern is a shorthand that allows you to match a directory and all its contents using a single rule. For example, specifying "\fBdir_name/***\fP" will match both the "dir_name" directory (as if "\fBdir_name/\fP" had been specified) and everything in the directory (as if "\fBdir_name/**\fP" had been specified). .IP o a backslash can be used to escape a wildcard character, but it is only interpreted as an escape character if at least one wildcard character is present in the match pattern. For instance, the pattern "\fBfoo\\bar\fP" matches that single backslash literally, while the pattern "\fBfoo\\bar*\fP" would need to be changed to "\fBfoo\\\\bar*\fP" to avoid the "\fB\\b\fP" becoming just "b". .P Here are some examples of exclude/include matching: .P .IP o Option \fB\-f'\-\ *.o'\fP would exclude all filenames ending with \fB.o\fP .IP o Option \fB\-f'\-\ /foo'\fP would exclude a file (or directory) named foo in the transfer-root directory .IP o Option \fB\-f'\-\ foo/'\fP would exclude any directory named foo .IP o Option \fB\-f'\-\ foo/*/bar'\fP would exclude any file/dir named bar which is at two levels below a directory named foo (if foo is in the transfer) .IP o Option \fB\-f'\-\ /foo/**/bar'\fP would exclude any file/dir named bar that was two or more levels below a top-level directory named foo (note that /foo/bar is \fBnot\fP excluded by this) .IP o Options \fB\-f'+\ */'\ \-f'+\ *.c'\ \-f'\-\ *'\fP would include all directories and .c source files but nothing else .IP o Options \fB\-f'+\ foo/'\ \-f'+\ foo/bar.c'\ \-f'\-\ *'\fP would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "\fB\-\ *\fP") .P .SS "FILTER RULE MODIFIERS" .P The following modifiers are accepted after an include (+) or exclude (\-) rule: .P .IP o A \fB/\fP specifies that the include/exclude rule should be matched against the absolute pathname of the current item. For example, \fB\-f'\-/\ /etc/passwd'\fP would exclude the passwd file any time the transfer was sending files from the "/etc" directory, and "\-/ subdir/foo" would always exclude "foo" when it is in a dir named "subdir", even if "foo" is at the root of the current transfer. .IP o A \fB!\fP specifies that the include/exclude should take effect if the pattern fails to match. For instance, \fB\-f'\-!\ */'\fP would exclude all non-directories. .IP o A \fBC\fP is used to indicate that all the global CVS-exclude rules should be inserted as excludes in place of the "\-C". No arg should follow. .IP o An \fBs\fP is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it affects what files are put into the sender's file list. The default is for a rule to affect both sides unless \fB\-\-delete-excluded\fP was specified, in which case default rules become sender-side only. See also the hide (H) and show (S) rules, which are an alternate way to specify sending-side includes/excludes. .IP o An \fBr\fP is used to indicate that the rule applies to the receiving side. When a rule affects the receiving side, it prevents files from being deleted. See the \fBs\fP modifier for more info. See also the protect (P) and risk (R) rules, which are an alternate way to specify receiver-side includes/excludes. .IP o A \fBp\fP indicates that a rule is perishable, meaning that it is ignored in directories that are being deleted. For instance, the \fB\-\-cvs-exclude\fP (\fB\-C\fP) option's default rules that exclude things like "CVS" and "\fB*.o\fP" are marked as perishable, and will not prevent a directory that was removed on the source from being deleted on the destination. .IP o An \fBx\fP indicates that a rule affects xattr names in xattr copy/delete operations (and is thus ignored when matching file/dir names). If no xattr-matching rules are specified, a default xattr filtering rule is used (see the \fB\-\-xattrs\fP option). .P .SS "MERGE-FILE FILTER RULES" .P You can merge whole files into your filter rules by specifying either a merge (.) or a dir-merge (:) filter rule (as introduced in the FILTER RULES section above). .P There are two kinds of merged files\ \-\- single-instance ('.') and per-directory (':'). A single-instance merge file is read one time, and its rules are incorporated into the filter list in the place of the "." rule. For per-directory merge files, rsync will scan every directory that it traverses for the named file, merging its contents when the file exists into the current list of inherited rules. These per-directory rule files must be created on the sending side because it is the sending side that is being scanned for the available files to transfer. These rule files may also need to be transferred to the receiving side if you want them to affect what files don't get deleted (see PER-DIRECTORY RULES AND DELETE below). .P Some examples: .RS 4 .P .nf merge /etc/rsync/default.rules \&. /etc/rsync/default.rules dir-merge .per-dir-filter dir-merge,n- .non-inherited-per-dir-excludes :n- .non-inherited-per-dir-excludes .fi .RE .P The following modifiers are accepted after a merge or dir-merge rule: .P .IP o A \fB\-\fP specifies that the file should consist of only exclude patterns, with no other rule-parsing except for in-file comments. .IP o A \fB+\fP specifies that the file should consist of only include patterns, with no other rule-parsing except for in-file comments. .IP o A \fBC\fP is a way to specify that the file should be read in a CVS-compatible manner. This turns on 'n', 'w', and '\-', but also allows the list-clearing token (!) to be specified. If no filename is provided, ".cvsignore" is assumed. .IP o A \fBe\fP will exclude the merge-file name from the transfer; e.g. "dir-merge,e \&.rules" is like "dir-merge .rules" and "\- .rules". .IP o An \fBn\fP specifies that the rules are not inherited by subdirectories. .IP o A \fBw\fP specifies that the rules are word-split on whitespace instead of the normal line-splitting. This also turns off comments. Note: the space that separates the prefix from the rule is treated specially, so "\- foo + bar" is parsed as two rules (assuming that prefix-parsing wasn't also disabled). .IP o You may also specify any of the modifiers for the "+" or "\-" rules (above) in order to have the rules that are read in from the file default to having that modifier set (except for the \fB!\fP modifier, which would not be useful). For instance, "merge,\-/ .excl" would treat the contents of .excl as absolute-path excludes, while "dir-merge,s .filt" and ":sC" would each make all their per-directory rules apply only on the sending side. If the merge rule specifies sides to affect (via the \fBs\fP or \fBr\fP modifier or both), then the rules in the file must not specify sides (via a modifier or a rule prefix such as \fBhide\fP). .P Per-directory rules are inherited in all subdirectories of the directory where the merge-file was found unless the 'n' modifier was used. Each subdirectory's rules are prefixed to the inherited per-directory rules from its parents, which gives the newest rules a higher priority than the inherited rules. The entire set of dir-merge rules are grouped together in the spot where the merge-file was specified, so it is possible to override dir-merge rules via a rule that got specified earlier in the list of global rules. When the list-clearing rule ("!") is read from a per-directory file, it only clears the inherited rules for the current merge file. .P Another way to prevent a single rule from a dir-merge file from being inherited is to anchor it with a leading slash. Anchored rules in a per-directory merge-file are relative to the merge-file's directory, so a pattern "/foo" would only match the file "foo" in the directory where the dir-merge filter file was found. .P Here's an example filter file which you'd specify via \fB\-\-filter=".\ file":\fP .RS 4 .P .nf merge /home/user/.global-filter - *.gz dir-merge .rules + *.[ch] - *.o - foo* .fi .RE .P This will merge the contents of the /home/user/.global-filter file at the start of the list and also turns the ".rules" filename into a per-directory filter file. All rules read in prior to the start of the directory scan follow the global anchoring rules (i.e. a leading slash matches at the root of the transfer). .P If a per-directory merge-file is specified with a path that is a parent directory of the first transfer directory, rsync will scan all the parent dirs from that starting point to the transfer directory for the indicated per-directory file. For instance, here is a common filter (see \fB\-F\fP): .RS 4 .P .nf --filter=': /.rsync-filter' .fi .RE .P That rule tells rsync to scan for the file .rsync-filter in all directories from the root down through the parent directory of the transfer prior to the start of the normal directory scan of the file in the directories that are sent as a part of the transfer. (Note: for an rsync daemon, the root is always the same as the module's "path".) .P Some examples of this pre-scanning for per-directory files: .RS 4 .P .nf rsync -avF /src/path/ /dest/dir rsync -av --filter=': ../../.rsync-filter' /src/path/ /dest/dir rsync -av --filter=': .rsync-filter' /src/path/ /dest/dir .fi .RE .P The first two commands above will look for ".rsync-filter" in "/" and "/src" before the normal scan begins looking for the file in "/src/path" and its subdirectories. The last command avoids the parent-dir scan and only looks for the ".rsync-filter" files in each directory that is a part of the transfer. .P If you want to include the contents of a ".cvsignore" in your patterns, you should use the rule ":C", which creates a dir-merge of the .cvsignore file, but parsed in a CVS-compatible manner. You can use this to affect where the \fB\-\-cvs-exclude\fP (\fB\-C\fP) option's inclusion of the per-directory \&.cvsignore file gets placed into your rules by putting the ":C" wherever you like in your filter rules. Without this, rsync would add the dir-merge rule for the .cvsignore file at the end of all your other rules (giving it a lower priority than your command-line rules). For example: .RS 4 .P .nf cat < out.dat .fi .RE .P then look at out.dat. If everything is working correctly then out.dat should be a zero length file. If you are getting the above error from rsync then you will probably find that out.dat contains some text or data. Look at the contents and try to work out what is producing it. The most common cause is incorrectly configured shell startup scripts (such as .cshrc or .profile) that contain output statements for non-interactive logins. .P If you are having trouble debugging filter patterns, then try specifying the \fB\-vv\fP option. At this level of verbosity rsync will show why each individual file is included or excluded. .P .SH "EXIT VALUES" .P .IP o \fB0\fP \- Success .IP o \fB1\fP \- Syntax or usage error .IP o \fB2\fP \- Protocol incompatibility .IP o \fB3\fP \- Errors selecting input/output files, dirs .IP o .P .RS .IP o \fB4\fP \- Requested action not supported. Either: an attempt was made to manipulate 64-bit files on a platform that cannot support them .IP o an option was specified that is supported by the client and not by the server .RE .IP o \fB5\fP \- Error starting client-server protocol .IP o \fB6\fP \- Daemon unable to append to log-file .IP o \fB10\fP \- Error in socket I/O .IP o \fB11\fP \- Error in file I/O .IP o \fB12\fP \- Error in rsync protocol data stream .IP o \fB13\fP \- Errors with program diagnostics .IP o \fB14\fP \- Error in IPC code .IP o \fB20\fP \- Received SIGUSR1 or SIGINT .IP o \fB21\fP \- Some error returned by \fBwaitpid()\fP .IP o \fB22\fP \- Error allocating core memory buffers .IP o \fB23\fP \- Partial transfer due to error .IP o \fB24\fP \- Partial transfer due to vanished source files .IP o \fB25\fP \- The \-\-max-delete limit stopped deletions .IP o \fB30\fP \- Timeout in data send/receive .IP o \fB35\fP \- Timeout waiting for daemon connection .P .SH "ENVIRONMENT VARIABLES" .P .IP "\fBCVSIGNORE\fP" The CVSIGNORE environment variable supplements any ignore patterns in \&.cvsignore files. See the \fB\-\-cvs-exclude\fP option for more details. .IP "\fBRSYNC_ICONV\fP" Specify a default \fB\-\-iconv\fP setting using this environment variable. First supported in 3.0.0. .IP "\fBRSYNC_OLD_ARGS\fP" Specify a "1" if you want the \fB\-\-old-args\fP option to be enabled by default, a "2" (or more) if you want it to be enabled in the repeated-option state, or a "0" to make sure that it is disabled by default. When this environment variable is set to a non-zero value, it supersedes the \fBRSYNC_PROTECT_ARGS\fP variable. .IP This variable is ignored if \fB\-\-old-args\fP, \fB\-\-no-old-args\fP, or \fB\-\-secluded-args\fP is specified on the command line. .IP First supported in 3.2.4. .IP "\fBRSYNC_PROTECT_ARGS\fP" Specify a non-zero numeric value if you want the \fB\-\-secluded-args\fP option to be enabled by default, or a zero value to make sure that it is disabled by default. .IP This variable is ignored if \fB\-\-secluded-args\fP, \fB\-\-no-secluded-args\fP, or \fB\-\-old-args\fP is specified on the command line. .IP First supported in 3.1.0. Starting in 3.2.4, this variable is ignored if \fBRSYNC_OLD_ARGS\fP is set to a non-zero value. .IP "\fBRSYNC_RSH\fP" This environment variable allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name, just as in the \fB\-\-rsh\fP (\fB\-e\fP) option. .IP "\fBRSYNC_PROXY\fP" This environment variable allows you to redirect your rsync client to use a web proxy when connecting to an rsync daemon. You should set \fBRSYNC_PROXY\fP to a hostname:port pair. .IP "\fBRSYNC_PASSWORD\fP" This environment variable allows you to set the password for an rsync \fBdaemon\fP connection, which avoids the password prompt. Note that this does \fBnot\fP supply a password to a remote shell transport such as ssh (consult its documentation for how to do that). .IP "\fBUSER\fP or \fBLOGNAME\fP" The USER or LOGNAME environment variables are used to determine the default username sent to an rsync daemon. If neither is set, the username defaults to "nobody". If both are set, \fBUSER\fP takes precedence. .IP "\fBRSYNC_PARTIAL_DIR\fP" This environment variable specifies the directory to use for a \fB\-\-partial\fP transfer without implying that partial transfers be enabled. See the \fB\-\-partial-dir\fP option for full details. .IP "\fBRSYNC_COMPRESS_LIST\fP" This environment variable allows you to customize the negotiation of the compression algorithm by specifying an alternate order or a reduced list of names. Use the command \fBrsync\ \-\-version\fP to see the available compression names. See the \fB\-\-compress\fP option for full details. .IP "\fBRSYNC_CHECKSUM_LIST\fP" This environment variable allows you to customize the negotiation of the checksum algorithm by specifying an alternate order or a reduced list of names. Use the command \fBrsync\ \-\-version\fP to see the available checksum names. See the \fB\-\-checksum-choice\fP option for full details. .IP "\fBRSYNC_MAX_ALLOC\fP" This environment variable sets an allocation maximum as if you had used the \fB\-\-max-alloc\fP option. .IP "\fBRSYNC_PORT\fP" This environment variable is not read by rsync, but is instead set in its sub-environment when rsync is running the remote shell in combination with a daemon connection. This allows a script such as \fBrsync-ssl\fP to be able to know the port number that the user specified on the command line. .IP "\fBHOME\fP" This environment variable is used to find the user's default .cvsignore file. .IP "\fBRSYNC_CONNECT_PROG\fP" This environment variable is mainly used in debug setups to set the program to use when making a daemon connection. See CONNECTING TO AN RSYNC DAEMON for full details. .IP "\fBRSYNC_SHELL\fP" This environment variable is mainly used in debug setups to set the program to use to run the program specified by \fBRSYNC_CONNECT_PROG\fP. See CONNECTING TO AN RSYNC DAEMON for full details. .P .SH "FILES" .P /etc/rsyncd.conf or rsyncd.conf .P .SH "SEE ALSO" .P \fBrsync-ssl\fP(1), \fBrsyncd.conf\fP(5), \fBrrsync\fP(1) .P .SH "BUGS" .P .IP o Times are transferred as *nix time_t values. .IP o When transferring to FAT filesystems rsync may re-sync unmodified files. See the comments on the \fB\-\-modify-window\fP option. .IP o File permissions, devices, etc. are transferred as native numerical values. .IP o See also the comments on the \fB\-\-delete\fP option. .P Please report bugs! See the web site at https://rsync.samba.org/. .P .SH "VERSION" .P This manpage is current for version 3.2.7 of rsync. .P .SH "INTERNAL OPTIONS" .P The options \fB\-\-server\fP and \fB\-\-sender\fP are used internally by rsync, and should never be typed by a user under normal circumstances. Some awareness of these options may be needed in certain scenarios, such as when setting up a login that can only run an rsync command. For instance, the support directory of the rsync distribution has an example script named rrsync (for restricted rsync) that can be used with a restricted ssh login. .P .SH "CREDITS" .P Rsync is distributed under the GNU General Public License. See the file COPYING for details. .P An rsync web site is available at https://rsync.samba.org/. The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page. .P The rsync github project is https://github.com/WayneD/rsync. .P We would be delighted to hear from you if you like this program. Please contact the mailing-list at rsync@lists.samba.org. .P This program uses the excellent zlib compression library written by Jean-loup Gailly and Mark Adler. .P .SH "THANKS" .P Special thanks go out to: John Van Essen, Matt McCutchen, Wesley W. Terpstra, David Dykstra, Jos Backus, Sebastian Krahmer, Martin Pool, and our gone-but-not-forgotten compadre, J.W. Schultz. .P Thanks also to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell and David Bell. I've probably missed some people, my apologies if I have. .P .SH "AUTHOR" .P Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. It is currently maintained by Wayne Davison. .P Mailing lists for support and development are available at https://lists.samba.org/. rsync-3.2.7/runtests.sh0000775000000000000000000002607014170671375013627 0ustar rootroot#! /bin/sh # Copyright (C) 2001, 2002 by Martin Pool # Copyright (C) 2003-2022 Wayne Davison # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version # 2 as published by the Free Software Foundation. # # 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ------------------------------------------------------------------------- # rsync top-level test script -- this invokes all the other more # detailed tests in order. This script can either be called by `make # check' or `make installcheck'. `check' runs against the copies of # the program and other files in the build directory, and # `installcheck' against the installed copy of the program. # It can also be called on a single test file using a run like this: # # preserve_scratch=yes whichtests=itemize.test ./runtests.sh # In either case we need to also be able to find the source directory, # since we read test scripts and possibly other information from # there. # Whenever possible, informational messages are written to stdout and # error messages to stderr. They're separated out by the build farm # display scripts. # According to the GNU autoconf manual, the only valid place to set up # directory locations is through Make, since users are allowed to (try # to) change their mind on the Make command line. So, Make has to # pass in all the values we need. # For other configured settings we read ./config.sh, which tells us # about shell commands on this machine and similar things. # rsync_bin gives the location of the rsync binary. This is either # builddir/rsync if we're testing an uninstalled copy, or # install_prefix/bin/rsync if we're testing an installed copy. On the # build farm rsync will be installed, but into a scratch /usr. # srcdir gives the location of the source tree, which lets us find the # build scripts. At the moment we assume we are invoked from the # source directory. # This script must be invoked from the build directory. # A scratch directory, 'testtmp', is used in the build directory to # hold per-test subdirectories. # This script also uses the $loglevel environment variable. 1 is the # default value, and 10 the most verbose. You can set this from the # Make command line. It's also set by the build farm to give more # detail for failing builds. # ------------------------------------------------------------------------- # NOTES FOR TEST CASES: # Each test case runs in its own shell. # Exit codes from tests: # 1 tests failed # 2 error in starting tests # 77 this test skipped (random value unlikely to happen by chance, same as # automake) # HOWEVER, the overall exit code to the farm is different: we return # the *number of tests that failed*, so that it will show up nicely in # the overall summary. # rsync.fns contains some general setup functions and definitions. # ------------------------------------------------------------------------- # NOTES ON PORTABILITY: # Both this script and the Makefile have to be pretty conservative # about which Unix features they use. # We cannot count on Make exporting variables to commands, unless # they're explicitly given on the command line. # Also, we can't count on 'cp -a' or 'mkdir -p', although they're # pretty handy (see function makepath for the latter). # I think some of the GNU documentation suggests that we shouldn't # rely on shell functions. However, the Bash manual seems to say that # they're in POSIX 1003.2, and since the build farm relies on them # they're probably working on most machines we really care about. # You cannot use "function foo {" syntax, but must instead say "foo() # {", or it breaks on FreeBSD. # BSD machines tend not to have "head" or "seq". # You cannot do "export VAR=VALUE" all on one line; the export must be # separate from the assignment. (SCO SysV) # Don't rely on grep -q, as that doesn't work everywhere -- just redirect # stdout to /dev/null to keep it quiet. # ------------------------------------------------------------------------- # STILL TO DO: # We need a good protection against tests that hang indefinitely. # Perhaps some combination of starting them in the background, wait, # and kill? # Perhaps we need a common way to cleanup tests. At the moment just # clobbering the directory when we're done should be enough. # If any of the targets fail, then (GNU?) Make returns 2, instead of # the return code from the failing command. This is fine, but it # means that the build farm just shows "2" for failed tests, not the # number of tests that actually failed. For more details we might # need to grovel through the log files to find a line saying how many # failed. set -e . "./shconfig" RUNSHFLAGS='-e' export RUNSHFLAGS # for Solaris if [ -d /usr/xpg4/bin ]; then PATH="/usr/xpg4/bin/:$PATH" export PATH fi if [ "x$loglevel" != x ] && [ "$loglevel" -gt 8 ]; then if set -x; then # If it doesn't work the first time, don't keep trying. RUNSHFLAGS="$RUNSHFLAGS -x" fi fi POSIXLY_CORRECT=1 if test x"$TOOLDIR" = x; then TOOLDIR=`pwd` fi srcdir=`dirname $0` if test x"$srcdir" = x || test x"$srcdir" = x.; then srcdir="$TOOLDIR" fi if test x"$rsync_bin" = x; then rsync_bin="$TOOLDIR/rsync" fi # This allows the user to specify extra rsync options -- use carefully! RSYNC="$rsync_bin $*" #RSYNC="valgrind $rsync_bin $*" TLS_ARGS='' if grep -E '^#define HAVE_LUTIMES 1' config.h >/dev/null; then TLS_ARGS="$TLS_ARGS -l" fi if grep -E '#undef CHOWN_MODIFIES_SYMLINK' config.h >/dev/null; then TLS_ARGS="$TLS_ARGS -L" fi export POSIXLY_CORRECT TOOLDIR srcdir RSYNC TLS_ARGS echo "============================================================" echo "$0 running in $TOOLDIR" echo " rsync_bin=$RSYNC" echo " srcdir=$srcdir" echo " TLS_ARGS=$TLS_ARGS" if [ -f /usr/bin/whoami ]; then testuser=`/usr/bin/whoami` elif [ -f /usr/ucb/whoami ]; then testuser=`/usr/ucb/whoami` elif [ -f /bin/whoami ]; then testuser=`/bin/whoami` else testuser=`id -un 2>/dev/null || echo ${LOGNAME:-${USERNAME:-${USER:-'UNKNOWN'}}}` fi echo " testuser=$testuser" echo " os=`uname -a`" # It must be "yes", not just nonnull if [ "x$preserve_scratch" = xyes ]; then echo " preserve_scratch=yes" else echo " preserve_scratch=no" fi # Check if setacl/setfacl is around and if it supports the -k or -s option. if setacl -k u::7,g::5,o:5 testsuite 2>/dev/null; then setfacl_nodef='setacl -k' elif setfacl --help 2>&1 | grep ' -k,\|\[-[a-z]*k' >/dev/null; then setfacl_nodef='setfacl -k' elif setfacl -s u::7,g::5,o:5 testsuite 2>/dev/null; then setfacl_nodef='setfacl -s u::7,g::5,o:5' else # The "true" command runs successfully, but does nothing. setfacl_nodef=true fi export setfacl_nodef if [ ! -f "$rsync_bin" ]; then echo "rsync_bin $rsync_bin is not a file" >&2 exit 2 fi if [ ! -d "$srcdir" ]; then echo "srcdir $srcdir is not a directory" >&2 exit 2 fi expect_skipped="${RSYNC_EXPECT_SKIPPED-IGNORE}" skipped_list='' skipped=0 missing=0 passed=0 failed=0 # Directory that holds the other test subdirs. We create separate dirs # inside for each test case, so that they can be left behind in case of # failure to aid investigation. We don't remove the testtmp subdir at # the end so that it can be configured as a symlink to a filesystem that # has ACLs and xattr support enabled (if desired). scratchbase="${scratchbase:-$TOOLDIR}"/testtmp echo " scratchbase=$scratchbase" [ -d "$scratchbase" ] || mkdir "$scratchbase" suitedir="$srcdir/testsuite" TESTRUN_TIMEOUT=300 export scratchdir suitedir TESTRUN_TIMEOUT prep_scratch() { [ -d "$scratchdir" ] && chmod -R u+rwX "$scratchdir" && rm -rf "$scratchdir" mkdir "$scratchdir" # Get rid of default ACLs and dir-setgid to avoid confusing some tests. $setfacl_nodef "$scratchdir" 2>/dev/null || true chmod g-s "$scratchdir" case "$srcdir" in /*) ln -s "$srcdir" "$scratchdir/src" ;; *) ln -s "$TOOLDIR/$srcdir" "$scratchdir/src" ;; esac return 0 } maybe_discard_scratch() { [ x"$preserve_scratch" != xyes ] && [ -d "$scratchdir" ] && rm -rf "$scratchdir" return 0 } if [ "x$whichtests" = x ]; then whichtests="*.test" full_run=yes else full_run=no fi for testscript in $suitedir/$whichtests; do testbase=`echo $testscript | sed -e 's!.*/!!' -e 's/.test\$//'` scratchdir="$scratchbase/$testbase" prep_scratch case "$testscript" in *hardlinks*) TESTRUN_TIMEOUT=600 ;; *) TESTRUN_TIMEOUT=300 ;; esac set +e "$TOOLDIR/"testrun $RUNSHFLAGS "$testscript" >"$scratchdir/test.log" 2>&1 result=$? set -e if [ "x$always_log" = xyes ] || ( [ $result != 0 ] && [ $result != 77 ] && [ $result != 78 ] ) then echo "----- $testbase log follows" cat "$scratchdir/test.log" echo "----- $testbase log ends" if [ -f "$scratchdir/rsyncd.log" ]; then echo "----- $testbase rsyncd.log follows" cat "$scratchdir/rsyncd.log" echo "----- $testbase rsyncd.log ends" fi fi case $result in 0) echo "PASS $testbase" passed=`expr $passed + 1` maybe_discard_scratch ;; 77) # backticks will fill the whole file onto one line, which is a feature whyskipped=`cat "$scratchdir/whyskipped"` echo "SKIP $testbase ($whyskipped)" skipped_list="$skipped_list,$testbase" skipped=`expr $skipped + 1` maybe_discard_scratch ;; 78) # It failed, but we expected that. don't dump out error logs, # because most users won't want to see them. But do leave # the working directory around. echo "XFAIL $testbase" failed=`expr $failed + 1` ;; *) echo "FAIL $testbase" failed=`expr $failed + 1` if [ "x$nopersist" = xyes ]; then exit 1 fi esac done echo '------------------------------------------------------------' echo "----- overall results:" echo " $passed passed" [ "$failed" -gt 0 ] && echo " $failed failed" [ "$skipped" -gt 0 ] && echo " $skipped skipped" [ "$missing" -gt 0 ] && echo " $missing missing" if [ "$full_run" = yes ] && [ "$expect_skipped" != IGNORE ]; then skipped_list=`echo "$skipped_list" | sed 's/^,//'` echo "----- skipped results:" echo " expected: $expect_skipped" echo " got: $skipped_list" else skipped_list='' expect_skipped='' fi echo '------------------------------------------------------------' # OK, so expr exits with 0 if the result is neither null nor zero; and # 1 if the expression is null or zero. This is the opposite of what # we want, and if we just call expr then this script will always fail, # because -e is set. result=`expr $failed + $missing || true` if [ "$result" = 0 ] && [ "$skipped_list" != "$expect_skipped" ]; then result=1 fi echo "overall result is $result" exit $result rsync-3.2.7/stunnel-rsyncd.conf.in0000664000000000000000000000177013647135761015647 0ustar rootroot# This config for stunnel will start up rsync for an incoming ssl connection. foreground = no #output = /var/log/stunnel-rsyncd.log pid = /var/run/stunnel-rsyncd.pid socket = l:TCP_NODELAY=1 socket = r:TCP_NODELAY=1 #compression = rle # This must be root for rsync to use chroot -- rsync will drop permissions: setuid = root setgid = root [rsync] accept = 874 # You can set the cert to a combo *.pem file and omit the key, if you like. cert = /etc/rsync-ssl/certs/server.crt key = /etc/rsync-ssl/certs/server.key client = no # To allow anyone to try an ssl connection, use this: verify = 0 CAfile = /etc/ssl/certs/ca-certificates.crt # To allow only cert-authorized clients, use something like this instead of the above: #verify = 3 #CAfile = /etc/rsync-ssl/certs/allowed-clients.cert.pem exec = @bindir@/rsync # You can either share the same config as a normal daemon, or specify a separate config: execargs = rsync --server --daemon . #execargs = rsync --server --daemon --config=/etc/rsync-ssl/rsyncd.conf . rsync-3.2.7/inums.h0000664000000000000000000000271613443220465012676 0ustar rootroot/* Inline functions for rsync. * * Copyright (C) 2008-2019 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. */ static inline char * big_num(int64 num) { return do_big_num(num, 0, NULL); } static inline char * comma_num(int64 num) { extern int human_readable; return do_big_num(num, human_readable != 0, NULL); } static inline char * human_num(int64 num) { extern int human_readable; return do_big_num(num, human_readable, NULL); } static inline char * big_dnum(double dnum, int decimal_digits) { return do_big_dnum(dnum, 0, decimal_digits); } static inline char * comma_dnum(double dnum, int decimal_digits) { extern int human_readable; return do_big_dnum(dnum, human_readable != 0, decimal_digits); } static inline char * human_dnum(double dnum, int decimal_digits) { extern int human_readable; return do_big_dnum(dnum, human_readable, decimal_digits); } rsync-3.2.7/tech_report.tex0000664000000000000000000003452306626126243014437 0ustar rootroot\documentclass[a4paper]{article} \begin{document} \title{The rsync algorithm} \author{Andrew Tridgell \quad\quad Paul Mackerras\\ Department of Computer Science \\ Australian National University \\ Canberra, ACT 0200, Australia} \maketitle \begin{abstract} This report presents an algorithm for updating a file on one machine to be identical to a file on another machine. We assume that the two machines are connected by a low-bandwidth high-latency bi-directional communications link. The algorithm identifies parts of the source file which are identical to some part of the destination file, and only sends those parts which cannot be matched in this way. Effectively, the algorithm computes a set of differences without having both files on the same machine. The algorithm works best when the files are similar, but will also function correctly and reasonably efficiently when the files are quite different. \end{abstract} \section{The problem} Imagine you have two files, $A$ and $B$, and you wish to update $B$ to be the same as $A$. The obvious method is to copy $A$ onto $B$. Now imagine that the two files are on machines connected by a slow communications link, for example a dialup IP link. If $A$ is large, copying $A$ onto $B$ will be slow. To make it faster you could compress $A$ before sending it, but that will usually only gain a factor of 2 to 4. Now assume that $A$ and $B$ are quite similar, perhaps both derived from the same original file. To really speed things up you would need to take advantage of this similarity. A common method is to send just the differences between $A$ and $B$ down the link and then use this list of differences to reconstruct the file. The problem is that the normal methods for creating a set of differences between two files rely on being able to read both files. Thus they require that both files are available beforehand at one end of the link. If they are not both available on the same machine, these algorithms cannot be used (once you had copied the file over, you wouldn't need the differences). This is the problem that rsync addresses. The rsync algorithm efficiently computes which parts of a source file match some part of an existing destination file. These parts need not be sent across the link; all that is needed is a reference to the part of the destination file. Only parts of the source file which are not matched in this way need to be sent verbatim. The receiver can then construct a copy of the source file using the references to parts of the existing destination file and the verbatim material. Trivially, the data sent to the receiver can be compressed using any of a range of common compression algorithms, for further speed improvements. \section{The rsync algorithm} Suppose we have two general purpose computers $\alpha$ and $\beta$. Computer $\alpha$ has access to a file $A$ and $\beta$ has access to file $B$, where $A$ and $B$ are ``similar''. There is a slow communications link between $\alpha$ and $\beta$. The rsync algorithm consists of the following steps: \begin{enumerate} \item $\beta$ splits the file $B$ into a series of non-overlapping fixed-sized blocks of size S bytes\footnote{We have found that values of S between 500 and 1000 are quite good for most purposes}. The last block may be shorter than $S$ bytes. \item For each of these blocks $\beta$ calculates two checksums: a weak ``rolling'' 32-bit checksum (described below) and a strong 128-bit MD4 checksum. \item $\beta$ sends these checksums to $\alpha$. \item $\alpha$ searches through $A$ to find all blocks of length $S$ bytes (at any offset, not just multiples of $S$) that have the same weak and strong checksum as one of the blocks of $B$. This can be done in a single pass very quickly using a special property of the rolling checksum described below. \item $\alpha$ sends $\beta$ a sequence of instructions for constructing a copy of $A$. Each instruction is either a reference to a block of $B$, or literal data. Literal data is sent only for those sections of $A$ which did not match any of the blocks of $B$. \end{enumerate} The end result is that $\beta$ gets a copy of $A$, but only the pieces of $A$ that are not found in $B$ (plus a small amount of data for checksums and block indexes) are sent over the link. The algorithm also only requires one round trip, which minimises the impact of the link latency. The most important details of the algorithm are the rolling checksum and the associated multi-alternate search mechanism which allows the all-offsets checksum search to proceed very quickly. These will be discussed in greater detail below. \section{Rolling checksum} The weak rolling checksum used in the rsync algorithm needs to have the property that it is very cheap to calculate the checksum of a buffer $X_2 .. X_{n+1}$ given the checksum of buffer $X_1 .. X_n$ and the values of the bytes $X_1$ and $X_{n+1}$. The weak checksum algorithm we used in our implementation was inspired by Mark Adler's adler-32 checksum. Our checksum is defined by $$ a(k,l) = (\sum_{i=k}^l X_i) \bmod M $$ $$ b(k,l) = (\sum_{i=k}^l (l-i+1)X_i) \bmod M $$ $$ s(k,l) = a(k,l) + 2^{16} b(k,l) $$ where $s(k,l)$ is the rolling checksum of the bytes $X_k \ldots X_l$. For simplicity and speed, we use $M = 2^{16}$. The important property of this checksum is that successive values can be computed very efficiently using the recurrence relations $$ a(k+1,l+1) = (a(k,l) - X_k + X_{l+1}) \bmod M $$ $$ b(k+1,l+1) = (b(k,l) - (l-k+1) X_k + a(k+1,l+1)) \bmod M $$ Thus the checksum can be calculated for blocks of length S at all possible offsets within a file in a ``rolling'' fashion, with very little computation at each point. Despite its simplicity, this checksum was found to be quite adequate as a first-level check for a match of two file blocks. We have found in practice that the probability of this checksum matching when the blocks are not equal is quite low. This is important because the much more expensive strong checksum must be calculated for each block where the weak checksum matches. \section{Checksum searching} Once $\alpha$ has received the list of checksums of the blocks of $B$, it must search $A$ for any blocks at any offset that match the checksum of some block of $B$. The basic strategy is to compute the 32-bit rolling checksum for a block of length $S$ starting at each byte of $A$ in turn, and for each checksum, search the list for a match. To do this our implementation uses a simple 3 level searching scheme. The first level uses a 16-bit hash of the 32-bit rolling checksum and a $2^{16}$ entry hash table. The list of checksum values (i.e., the checksums from the blocks of $B$) is sorted according to the 16-bit hash of the 32-bit rolling checksum. Each entry in the hash table points to the first element of the list for that hash value, or contains a null value if no element of the list has that hash value. At each offset in the file the 32-bit rolling checksum and its 16-bit hash are calculated. If the hash table entry for that hash value is not a null value, the second-level check is invoked. The second-level check involves scanning the sorted checksum list starting with the entry pointed to by the hash table entry, looking for an entry whose 32-bit rolling checksum matches the current value. The scan terminates when it reaches an entry whose 16-bit hash differs. If this search finds a match, the third-level check is invoked. The third-level check involves calculating the strong checksum for the current offset in the file and comparing it with the strong checksum value in the current list entry. If the two strong checksums match, we assume that we have found a block of $A$ which matches a block of $B$. In fact the blocks could be different, but the probability of this is microscopic, and in practice this is a reasonable assumption. When a match is found, $\alpha$ sends $\beta$ the data in $A$ between the current file offset and the end of the previous match, followed by the index of the block in $B$ that matched. This data is sent immediately a match is found, which allows us to overlap the communication with further computation. If no match is found at a given offset in the file, the rolling checksum is updated to the next offset and the search proceeds. If a match is found, the search is restarted at the end of the matched block. This strategy saves a considerable amount of computation for the common case where the two files are nearly identical. In addition, it would be a simple matter to encode the block indexes as runs, for the common case where a portion of $A$ matches a series of blocks of $B$ in order. \section{Pipelining} The above sections describe the process for constructing a copy of one file on a remote system. If we have a several files to copy, we can gain a considerable latency advantage by pipelining the process. This involves $\beta$ initiating two independent processes. One of the processes generates and sends the checksums to $\alpha$ while the other receives the difference information from $\alpha$ and reconstructs the files. If the communications link is buffered then these two processes can proceed independently and the link should be kept fully utilised in both directions for most of the time. \section{Results} To test the algorithm, tar files were created of the Linux kernel sources for two versions of the kernel. The two kernel versions were 1.99.10 and 2.0.0. These tar files are approximately 24MB in size and are separated by 5 released patch levels. Out of the 2441 files in the 1.99.10 release, 291 files had changed in the 2.0.0 release, 19 files had been removed and 25 files had been added. A ``diff'' of the two tar files using the standard GNU diff utility produced over 32 thousand lines of output totalling 2.1 MB. The following table shows the results for rsync between the two files with a varying block size.\footnote{All the tests in this section were carried out using rsync version 0.5} \vspace*{5mm} \begin{tabular}{|l|l|l|l|l|l|l|} \hline {\bf block} & {\bf matches} & {\bf tag} & {\bf false} & {\bf data} & {\bf written} & {\bf read} \\ {\bf size} & & {\bf hits} & {\bf alarms} & & & \\ \hline \hline 300 & 64247 & 3817434 & 948 & 5312200 & 5629158 & 1632284 \\ \hline 500 & 46989 & 620013 & 64 & 1091900 & 1283906 & 979384 \\ \hline 700 & 33255 & 571970 & 22 & 1307800 & 1444346 & 699564 \\ \hline 900 & 25686 & 525058 & 24 & 1469500 & 1575438 & 544124 \\ \hline 1100 & 20848 & 496844 & 21 & 1654500 & 1740838 & 445204 \\ \hline \end{tabular} \vspace*{5mm} In each case, the CPU time taken was less than the time it takes to run ``diff'' on the two files.\footnote{The wall clock time was approximately 2 minutes per run on a 50 MHz SPARC 10 running SunOS, using rsh over loopback for communication. GNU diff took about 4 minutes.} The columns in the table are as follows: \begin{description} \item [block size] The size in bytes of the checksummed blocks. \item [matches] The number of times a block of $B$ was found in $A$. \item [tag hits] The number of times the 16-bit hash of the rolling checksum matched a hash of one of the checksums from $B$. \item [false alarms] The number of times the 32-bit rolling checksum matched but the strong checksum didn't. \item [data] The amount of file data transferred verbatim, in bytes. \item [written] The total number of bytes written by $\alpha$, including protocol overheads. This is almost all file data. \item [read] The total number of bytes read by $\alpha$, including protocol overheads. This is almost all checksum information. \end{description} The results demonstrate that for block sizes above 300 bytes, only a small fraction (around 5\%) of the file was transferred. The amount transferred was also considerably less than the size of the diff file that would have been transferred if the diff/patch method of updating a remote file was used. The checksums themselves took up a considerable amount of space, although much less than the size of the data transferred in each case. Each pair of checksums consumes 20 bytes: 4 bytes for the rolling checksum plus 16 bytes for the 128-bit MD4 checksum. The number of false alarms was less than $1/1000$ of the number of true matches, indicating that the 32-bit rolling checksum is quite good at screening out false matches. The number of tag hits indicates that the second level of the checksum search algorithm was invoked about once every 50 characters. This is quite high because the total number of blocks in the file is a large fraction of the size of the tag hash table. For smaller files we would expect the tag hit rate to be much closer to the number of matches. For extremely large files, we should probably increase the size of the hash table. The next table shows similar results for a much smaller set of files. In this case the files were not packed into a tar file first. Rather, rsync was invoked with an option to recursively descend the directory tree. The files used were from two source releases of another software package called Samba. The total source code size is 1.7 MB and the diff between the two releases is 4155 lines long totalling 120 kB. \vspace*{5mm} \begin{tabular}{|l|l|l|l|l|l|l|} \hline {\bf block} & {\bf matches} & {\bf tag} & {\bf false} & {\bf data} & {\bf written} & {\bf read} \\ {\bf size} & & {\bf hits} & {\bf alarms} & & & \\ \hline \hline 300 & 3727 & 3899 & 0 & 129775 & 153999 & 83948 \\ \hline 500 & 2158 & 2325 & 0 & 171574 & 189330 & 50908 \\ \hline 700 & 1517 & 1649 & 0 & 195024 & 210144 & 36828 \\ \hline 900 & 1156 & 1281 & 0 & 222847 & 236471 & 29048 \\ \hline 1100 & 921 & 1049 & 0 & 250073 & 262725 & 23988 \\ \hline \end{tabular} \vspace*{5mm} \section{Availability} An implementation of rsync which provides a convenient interface similar to the common UNIX command rcp has been written and is available for download from http://rsync.samba.org/ \end{document} rsync-3.2.7/t_unsafe.c0000664000000000000000000000244013671304046013335 0ustar rootroot/* * Test harness for unsafe_symlink(). Not linked into rsync itself. * * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2020 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. */ /* Prints either "safe" or "unsafe" depending on the two arguments. * Always returns 0 unless something extraordinary happens. */ #include "rsync.h" int dry_run = 0; int am_root = 0; int am_sender = 1; int read_only = 0; int list_only = 0; short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: t_unsafe LINKDEST SRCDIR\n"); return 1; } printf("%s\n", unsafe_symlink(argv[1], argv[2]) ? "unsafe" : "safe"); return 0; } rsync-3.2.7/.gitignore0000664000000000000000000000136414213426645013364 0ustar rootroot*.[oa] *~ dummy ID Makefile Makefile.old configure.sh configure.sh.old config.cache config.h config.h.in config.h.in.old config.log config.status aclocal.m4 /proto.h /proto.h-tstamp /rsync*.[15] /rrsync /rrsync*.1 /rsync*.html /rrsync*.html /help-rsync*.h /default-cvsignore.h /default-dont-compress.h /daemon-parm.h /.md2man-works /autom4te*.cache /confdefs.h /conftest* /dox /getgroups /gists /gmon.out /rsync /stunnel-rsyncd.conf /shconfig /git-version.h /testdir /tests-dont-exist /testtmp /tls /testrun /trimslash /t_unsafe /wildtest /getfsdev /rounding.h /doc/rsync.pdf /doc/rsync.ps /support/savetransfer /testsuite/chown-fake.test /testsuite/devices-fake.test /testsuite/xattrs-hlink.test /patches /patches.gen /build /auto-build-save .deps /*.exe rsync-3.2.7/uidlist.c0000664000000000000000000003374314272101413013207 0ustar rootroot/* * Handle the mapping of uid/gid and user/group names between systems. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2004-2022 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. */ /* If the source username/group does not exist on the target then use * the numeric IDs. Never do any mapping for uid=0 or gid=0 as these * are special. */ #include "rsync.h" #include "ifuncs.h" #include "itypes.h" #include "io.h" extern int am_root; extern int preserve_uid; extern int preserve_gid; extern int preserve_acls; extern int numeric_ids; extern int xmit_id0_names; extern pid_t namecvt_pid; extern gid_t our_gid; extern char *usermap; extern char *groupmap; #ifdef HAVE_GETGROUPS # ifndef GETGROUPS_T # define GETGROUPS_T gid_t # endif #endif #define NFLAGS_WILD_NAME_MATCH (1<<0) #define NFLAGS_NAME_MATCH (1<<1) union name_or_id { const char *name; id_t max_id; }; struct idlist { struct idlist *next; union name_or_id u; id_t id, id2; uint16 flags; }; static struct idlist *uidlist, *uidmap; static struct idlist *gidlist, *gidmap; static inline int id_eq_uid(id_t id, uid_t uid) { return id == (id_t)uid; } static inline int id_eq_gid(id_t id, gid_t gid) { return id == (id_t)gid; } static id_t id_parse(const char *num_str) { id_t tmp, num = 0; const char *cp = num_str; while (*cp) { if (!isDigit(cp)) { invalid_num: rprintf(FERROR, "Invalid ID number: %s\n", num_str); exit_cleanup(RERR_SYNTAX); } tmp = num * 10 + *cp++ - '0'; if (tmp < num) goto invalid_num; num = tmp; } return num; } static struct idlist *add_to_list(struct idlist **root, id_t id, union name_or_id noiu, id_t id2, uint16 flags) { struct idlist *node = new(struct idlist); node->next = *root; node->u = noiu; node->id = id; node->id2 = id2; node->flags = flags; *root = node; return node; } /* turn a uid into a user name */ const char *uid_to_user(uid_t uid) { const char *name = NULL; if (namecvt_pid) { id_t id = uid; namecvt_call("uid", &name, &id); } else { struct passwd *pass = getpwuid(uid); if (pass) name = strdup(pass->pw_name); } return name; } /* turn a gid into a group name */ const char *gid_to_group(gid_t gid) { const char *name = NULL; if (namecvt_pid) { id_t id = gid; namecvt_call("gid", &name, &id); } else { struct group *grp = getgrgid(gid); if (grp) name = strdup(grp->gr_name); } return name; } /* Parse a user name or (optionally) a number into a uid */ int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok) { if (!name || !*name) return 0; if (num_ok && name[strspn(name, "0123456789")] == '\0') { *uid_p = id_parse(name); return 1; } if (namecvt_pid) { id_t id; if (!namecvt_call("usr", &name, &id)) return 0; *uid_p = id; } else { struct passwd *pass = getpwnam(name); if (!pass) return 0; *uid_p = pass->pw_uid; } return 1; } /* Parse a group name or (optionally) a number into a gid */ int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok) { if (!name || !*name) return 0; if (num_ok && name[strspn(name, "0123456789")] == '\0') { *gid_p = id_parse(name); return 1; } if (namecvt_pid) { id_t id; if (!namecvt_call("grp", &name, &id)) return 0; *gid_p = id; } else { struct group *grp = getgrnam(name); if (!grp) return 0; *gid_p = grp->gr_gid; } return 1; } static int is_in_group(gid_t gid) { #ifdef HAVE_GETGROUPS static gid_t last_in; static int ngroups = -2, last_out = -1; static GETGROUPS_T *gidset; int n; if (gid == last_in && last_out >= 0) return last_out; if (ngroups < -1) { if ((ngroups = getgroups(0, NULL)) < 0) ngroups = 0; gidset = new_array(GETGROUPS_T, ngroups+1); if (ngroups > 0) ngroups = getgroups(ngroups, gidset); /* The default gid might not be in the list on some systems. */ for (n = 0; n < ngroups; n++) { if ((gid_t)gidset[n] == our_gid) break; } if (n == ngroups) gidset[ngroups++] = our_gid; if (DEBUG_GTE(OWN, 2)) { int pos; char *gidbuf = new_array(char, ngroups*21+32); pos = snprintf(gidbuf, 32, "process has %d gid%s: ", ngroups, ngroups == 1? "" : "s"); for (n = 0; n < ngroups; n++) { pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]); } rprintf(FINFO, "%s\n", gidbuf); free(gidbuf); } } last_in = gid; for (n = 0; n < ngroups; n++) { if ((gid_t)gidset[n] == gid) return last_out = 1; } return last_out = 0; #else return gid == our_gid; #endif } /* Add a uid/gid to its list of ids. Only called on receiving side. */ static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap, id_t id, const char *name) { struct idlist *node; union name_or_id noiu; int flag; id_t id2; noiu.name = name; /* ensure that add_to_list() gets the raw value. */ if (!name) name = ""; for (node = idmap; node; node = node->next) { if (node->flags & NFLAGS_WILD_NAME_MATCH) { if (!wildmatch(node->u.name, name)) continue; } else if (node->flags & NFLAGS_NAME_MATCH) { if (strcmp(node->u.name, name) != 0) continue; } else if (node->u.max_id) { if (id < node->id || id > node->u.max_id) continue; } else { if (node->id != id) continue; } break; } if (node) id2 = node->id2; else if (*name && id) { if (idlist_ptr == &uidlist) { uid_t uid; id2 = user_to_uid(name, &uid, False) ? (id_t)uid : id; } else { gid_t gid; id2 = group_to_gid(name, &gid, False) ? (id_t)gid : id; } } else id2 = id; flag = idlist_ptr == &gidlist && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0; node = add_to_list(idlist_ptr, id, noiu, id2, flag); if (DEBUG_GTE(OWN, 2)) { rprintf(FINFO, "%sid %u(%s) maps to %u\n", idlist_ptr == &uidlist ? "u" : "g", (unsigned)id, name, (unsigned)id2); } return node; } /* this function is a definite candidate for a faster algorithm */ uid_t match_uid(uid_t uid) { static struct idlist *last = NULL; struct idlist *list; if (last && id_eq_uid(last->id, uid)) return last->id2; for (list = uidlist; list; list = list->next) { if (id_eq_uid(list->id, uid)) break; } if (!list) list = recv_add_id(&uidlist, uidmap, uid, NULL); last = list; return list->id2; } gid_t match_gid(gid_t gid, uint16 *flags_ptr) { static struct idlist *last = NULL; struct idlist *list; if (last && id_eq_gid(last->id, gid)) list = last; else { for (list = gidlist; list; list = list->next) { if (id_eq_gid(list->id, gid)) break; } if (!list) list = recv_add_id(&gidlist, gidmap, gid, NULL); last = list; } if (flags_ptr && list->flags & FLAG_SKIP_GROUP) *flags_ptr |= FLAG_SKIP_GROUP; return list->id2; } /* Add a uid to the list of uids. Only called on sending side. */ const char *add_uid(uid_t uid) { struct idlist *list; struct idlist *node; union name_or_id noiu; for (list = uidlist; list; list = list->next) { if (id_eq_uid(list->id, uid)) return NULL; } noiu.name = uid_to_user(uid); node = add_to_list(&uidlist, uid, noiu, 0, 0); return node->u.name; } /* Add a gid to the list of gids. Only called on sending side. */ const char *add_gid(gid_t gid) { struct idlist *list; struct idlist *node; union name_or_id noiu; for (list = gidlist; list; list = list->next) { if (id_eq_gid(list->id, gid)) return NULL; } noiu.name = gid_to_group(gid); node = add_to_list(&gidlist, gid, noiu, 0, 0); return node->u.name; } static void send_one_name(int f, id_t id, const char *name) { int len; if (!name) name = ""; if ((len = strlen(name)) > 255) /* Impossible? */ len = 255; write_varint30(f, id); write_byte(f, len); if (len) write_buf(f, name, len); } static void send_one_list(int f, struct idlist *idlist, int usernames) { struct idlist *list; /* we send sequences of id/byte-len/name */ for (list = idlist; list; list = list->next) { if (list->id && list->u.name) send_one_name(f, list->id, list->u.name); } /* Terminate the uid list with 0 (which was excluded above). * A modern rsync also sends the name of id 0. */ if (xmit_id0_names) send_one_name(f, 0, usernames ? uid_to_user(0) : gid_to_group(0)); else write_varint30(f, 0); } /* send a complete uid/gid mapping to the peer */ void send_id_lists(int f) { if (preserve_uid || preserve_acls) send_one_list(f, uidlist, 1); if (preserve_gid || preserve_acls) send_one_list(f, gidlist, 0); } uid_t recv_user_name(int f, uid_t uid) { struct idlist *node; int len = read_byte(f); char *name; if (len) { name = new_array(char, len+1); read_sbuf(f, name, len); if (numeric_ids < 0) { free(name); name = NULL; } } else name = NULL; node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */ return node->id2; } gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr) { struct idlist *node; int len = read_byte(f); char *name; if (len) { name = new_array(char, len+1); read_sbuf(f, name, len); if (numeric_ids < 0) { free(name); name = NULL; } } else name = NULL; node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */ if (flags_ptr && node->flags & FLAG_SKIP_GROUP) *flags_ptr |= FLAG_SKIP_GROUP; return node->id2; } /* recv a complete uid/gid mapping from the peer and map the uid/gid * in the file list to local names */ void recv_id_list(int f, struct file_list *flist) { id_t id; int i; if ((preserve_uid || preserve_acls) && numeric_ids <= 0) { /* read the uid list */ while ((id = read_varint30(f)) != 0) recv_user_name(f, id); if (xmit_id0_names) recv_user_name(f, 0); } if ((preserve_gid || preserve_acls) && numeric_ids <= 0) { /* read the gid list */ while ((id = read_varint30(f)) != 0) recv_group_name(f, id, NULL); if (xmit_id0_names) recv_group_name(f, 0, NULL); } /* Now convert all the uids/gids from sender values to our values. */ #ifdef SUPPORT_ACLS if (preserve_acls && (!numeric_ids || usermap || groupmap)) match_acl_ids(); #endif if (am_root && preserve_uid && (!numeric_ids || usermap)) { for (i = 0; i < flist->used; i++) F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i])); } if (preserve_gid && (!am_root || !numeric_ids || groupmap)) { for (i = 0; i < flist->used; i++) { F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), &flist->files[i]->flags); } } } void parse_name_map(char *map, BOOL usernames) { struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap; struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist; char *colon, *cp = map + strlen(map); union name_or_id noiu; id_t id1; uint16 flags; /* Parse the list in reverse, so the order in the struct is right. */ while (1) { while (cp > map && cp[-1] != ',') cp--; if (!(colon = strchr(cp, ':'))) { rprintf(FERROR, "No colon found in --%smap: %s\n", usernames ? "user" : "group", cp); exit_cleanup(RERR_SYNTAX); } if (!colon[1]) { rprintf(FERROR, "No name found after colon --%smap: %s\n", usernames ? "user" : "group", cp); exit_cleanup(RERR_SYNTAX); } *colon = '\0'; if (isDigit(cp)) { char *dash = strchr(cp, '-'); if (strspn(cp, "0123456789-") != (size_t)(colon - cp) || (dash && (!dash[1] || strchr(dash+1, '-')))) { rprintf(FERROR, "Invalid number in --%smap: %s\n", usernames ? "user" : "group", cp); exit_cleanup(RERR_SYNTAX); } if (dash) { *dash = '\0'; noiu.max_id = id_parse(dash+1); } else noiu.max_id = 0; flags = 0; id1 = id_parse(cp); if (dash) *dash = '-'; } else if (strpbrk(cp, "*[?")) { flags = NFLAGS_WILD_NAME_MATCH; noiu.name = cp; id1 = 0; } else { flags = NFLAGS_NAME_MATCH; noiu.name = cp; id1 = 0; } if (usernames) { uid_t uid; if (user_to_uid(colon+1, &uid, True)) add_to_list(idmap_ptr, id1, noiu, uid, flags); else { rprintf(FERROR, "Unknown --usermap name on receiver: %s\n", colon+1); } } else { gid_t gid; if (group_to_gid(colon+1, &gid, True)) add_to_list(idmap_ptr, id1, noiu, gid, flags); else { rprintf(FERROR, "Unknown --groupmap name on receiver: %s\n", colon+1); } } if (cp == map) break; *--cp = '\0'; /* replace comma */ } /* If the sender isn't going to xmit the id0 name, we assume it's "root". */ if (!xmit_id0_names) recv_add_id(idlist_ptr, *idmap_ptr, 0, numeric_ids ? NULL : "root"); } #ifdef HAVE_GETGROUPLIST const char *getallgroups(uid_t uid, item_list *gid_list) { struct passwd *pw; gid_t *gid_array; int size; if ((pw = getpwuid(uid)) == NULL) return "getpwuid failed"; gid_list->count = 0; /* We're overwriting any items in the list */ (void)EXPAND_ITEM_LIST(gid_list, gid_t, 32); size = gid_list->malloced; /* Get all the process's groups, with the pw_gid group first. */ if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) { if (size > (int)gid_list->malloced) { gid_list->count = gid_list->malloced; (void)EXPAND_ITEM_LIST(gid_list, gid_t, size); if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) size = -1; } else size = -1; if (size < 0) return "getgrouplist failed"; } gid_list->count = size; gid_array = gid_list->items; /* Paranoia: is the default group not first in the list? */ if (gid_array[0] != pw->pw_gid) { int j; for (j = 1; j < size; j++) { if (gid_array[j] == pw->pw_gid) break; } if (j == size) { /* The default group wasn't found! */ (void)EXPAND_ITEM_LIST(gid_list, gid_t, size+1); gid_array = gid_list->items; } gid_array[j] = gid_array[0]; gid_array[0] = pw->pw_gid; } return NULL; } #endif rsync-3.2.7/token.c0000664000000000000000000006434114170671375012670 0ustar rootroot/* * Routines used by the file-transfer code. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2022 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 "itypes.h" #include #ifdef SUPPORT_ZSTD #include #endif #ifdef SUPPORT_LZ4 #include #endif extern int do_compression; extern int protocol_version; extern int module_id; extern int do_compression_level; extern char *skip_compress; #ifndef Z_INSERT_ONLY #define Z_INSERT_ONLY Z_SYNC_FLUSH #endif static int skip_compression_level; /* The least possible compressing for handling skip-compress files. */ static int per_file_default_level; /* The default level that each new file gets prior to checking its suffix. */ struct suffix_tree { struct suffix_tree *sibling; struct suffix_tree *child; char letter, word_end; }; static char *match_list; static struct suffix_tree *suftree; void init_compression_level(void) { int min_level, max_level, def_level, off_level; switch (do_compression) { case CPRES_NONE: return; case CPRES_ZLIB: case CPRES_ZLIBX: min_level = 1; max_level = Z_BEST_COMPRESSION; def_level = 6; /* Z_DEFAULT_COMPRESSION is -1, so set it to the real default */ off_level = skip_compression_level = Z_NO_COMPRESSION; if (do_compression_level == Z_DEFAULT_COMPRESSION) do_compression_level = def_level; break; #ifdef SUPPORT_ZSTD case CPRES_ZSTD: min_level = skip_compression_level = ZSTD_minCLevel(); max_level = ZSTD_maxCLevel(); def_level = ZSTD_CLEVEL_DEFAULT; off_level = CLVL_NOT_SPECIFIED; if (do_compression_level == 0) do_compression_level = def_level; break; #endif #ifdef SUPPORT_LZ4 case CPRES_LZ4: min_level = skip_compression_level = 0; max_level = 0; def_level = 0; off_level = CLVL_NOT_SPECIFIED; break; #endif default: /* paranoia to prevent missing case values */ NOISY_DEATH("Unknown do_compression value"); } if (do_compression_level == CLVL_NOT_SPECIFIED) do_compression_level = def_level; else if (do_compression_level == off_level) { do_compression = CPRES_NONE; return; } /* We don't bother with any errors or warnings -- just make sure that the values are valid. */ if (do_compression_level < min_level) do_compression_level = min_level; else if (do_compression_level > max_level) do_compression_level = max_level; } static void add_suffix(struct suffix_tree **prior, char ltr, const char *str) { struct suffix_tree *node, *newnode; if (ltr == '[') { const char *after = strchr(str, ']'); /* Treat "[foo" and "[]" as having a literal '['. */ if (after && after++ != str+1) { while ((ltr = *str++) != ']') add_suffix(prior, ltr, after); return; } } for (node = *prior; node; prior = &node->sibling, node = node->sibling) { if (node->letter == ltr) { if (*str) add_suffix(&node->child, *str, str+1); else node->word_end = 1; return; } if (node->letter > ltr) break; } newnode = new(struct suffix_tree); newnode->sibling = node; newnode->child = NULL; newnode->letter = ltr; *prior = newnode; if (*str) { add_suffix(&newnode->child, *str, str+1); newnode->word_end = 0; } else newnode->word_end = 1; } static void add_nocompress_suffixes(const char *str) { char *buf, *t; const char *f = str; buf = new_array(char, strlen(f) + 1); while (*f) { if (*f == '/') { f++; continue; } t = buf; do { if (isUpper(f)) *t++ = toLower(f); else *t++ = *f; } while (*++f != '/' && *f); *t++ = '\0'; add_suffix(&suftree, *buf, buf+1); } free(buf); } static void init_set_compression(void) { const char *f; char *t, *start; if (skip_compress) add_nocompress_suffixes(skip_compress); /* A non-daemon transfer skips the default suffix list if the * user specified --skip-compress. */ if (skip_compress && module_id < 0) f = ""; else f = lp_dont_compress(module_id); match_list = t = new_array(char, strlen(f) + 2); per_file_default_level = do_compression_level; while (*f) { if (*f == ' ') { f++; continue; } start = t; do { if (isUpper(f)) *t++ = toLower(f); else *t++ = *f; } while (*++f != ' ' && *f); *t++ = '\0'; if (t - start == 1+1 && *start == '*') { /* Optimize a match-string of "*". */ *match_list = '\0'; suftree = NULL; per_file_default_level = skip_compression_level; break; } /* Move *.foo items into the stuffix tree. */ if (*start == '*' && start[1] == '.' && start[2] && !strpbrk(start+2, ".?*")) { add_suffix(&suftree, start[2], start+3); t = start; } } *t++ = '\0'; } /* determine the compression level based on a wildcard filename list */ void set_compression(const char *fname) { #if 0 /* No compression algorithms currently allow mid-stream changing of the level. */ const struct suffix_tree *node; const char *s; char ltr; #endif if (!do_compression) return; if (!match_list) init_set_compression(); #if 0 compression_level = per_file_default_level; if (!*match_list && !suftree) return; if ((s = strrchr(fname, '/')) != NULL) fname = s + 1; for (s = match_list; *s; s += strlen(s) + 1) { if (iwildmatch(s, fname)) { compression_level = skip_compression_level; return; } } if (!(node = suftree) || !(s = strrchr(fname, '.')) || s == fname || !(ltr = *++s)) return; while (1) { if (isUpper(<r)) ltr = toLower(<r); while (node->letter != ltr) { if (node->letter > ltr) return; if (!(node = node->sibling)) return; } if ((ltr = *++s) == '\0') { if (node->word_end) compression_level = skip_compression_level; return; } if (!(node = node->child)) return; } #else (void)fname; #endif } /* non-compressing recv token */ static int32 simple_recv_token(int f, char **data) { static int32 residue; static char *buf; int32 n; if (!buf) buf = new_array(char, CHUNK_SIZE); if (residue == 0) { int32 i = read_int(f); if (i <= 0) return i; residue = i; } *data = buf; n = MIN(CHUNK_SIZE,residue); residue -= n; read_buf(f,buf,n); return n; } /* non-compressing send token */ static void simple_send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 n) { if (n > 0) { int32 len = 0; while (len < n) { int32 n1 = MIN(CHUNK_SIZE, n-len); write_int(f, n1); write_buf(f, map_ptr(buf, offset+len, n1), n1); len += n1; } } /* a -2 token means to send data only and no token */ if (token != -2) write_int(f, -(token+1)); } /* Flag bytes in compressed stream are encoded as follows: */ #define END_FLAG 0 /* that's all folks */ #define TOKEN_LONG 0x20 /* followed by 32-bit token number */ #define TOKENRUN_LONG 0x21 /* ditto with 16-bit run count */ #define DEFLATED_DATA 0x40 /* + 6-bit high len, then low len byte */ #define TOKEN_REL 0x80 /* + 6-bit relative token number */ #define TOKENRUN_REL 0xc0 /* ditto with 16-bit run count */ #define MAX_DATA_COUNT 16383 /* fit 14 bit count into 2 bytes with flags */ /* zlib.h says that if we want to be able to compress something in a single * call, avail_out must be at least 0.1% larger than avail_in plus 12 bytes. * We'll add in 0.1%+16, just to be safe (and we'll avoid floating point, * to ensure that this is a compile-time value). */ #define AVAIL_OUT_SIZE(avail_in_size) ((avail_in_size)*1001/1000+16) /* For coding runs of tokens */ static int32 last_token = -1; static int32 run_start; static int32 last_run_end; /* Deflation state */ static z_stream tx_strm; /* Output buffer */ static char *obuf; /* We want obuf to be able to hold both MAX_DATA_COUNT+2 bytes as well as * AVAIL_OUT_SIZE(CHUNK_SIZE) bytes, so make sure that it's large enough. */ #if MAX_DATA_COUNT+2 > AVAIL_OUT_SIZE(CHUNK_SIZE) #define OBUF_SIZE (MAX_DATA_COUNT+2) #else #define OBUF_SIZE AVAIL_OUT_SIZE(CHUNK_SIZE) #endif /* Send a deflated token */ static void send_deflated_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 nb, int32 toklen) { static int init_done, flush_pending; int32 n, r; if (last_token == -1) { /* initialization */ if (!init_done) { tx_strm.next_in = NULL; tx_strm.zalloc = NULL; tx_strm.zfree = NULL; if (deflateInit2(&tx_strm, per_file_default_level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { rprintf(FERROR, "compression init failed\n"); exit_cleanup(RERR_PROTOCOL); } obuf = new_array(char, OBUF_SIZE); init_done = 1; } else deflateReset(&tx_strm); last_run_end = 0; run_start = token; flush_pending = 0; } else if (last_token == -2) { run_start = token; } else if (nb != 0 || token != last_token + 1 || token >= run_start + 65536) { /* output previous run */ r = run_start - last_run_end; n = last_token - run_start; if (r >= 0 && r <= 63) { write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r); } else { write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG)); write_int(f, run_start); } if (n != 0) { write_byte(f, n); write_byte(f, n >> 8); } last_run_end = last_token; run_start = token; } last_token = token; if (nb != 0 || flush_pending) { /* deflate the data starting at offset */ int flush = Z_NO_FLUSH; tx_strm.avail_in = 0; tx_strm.avail_out = 0; do { if (tx_strm.avail_in == 0 && nb != 0) { /* give it some more input */ n = MIN(nb, CHUNK_SIZE); tx_strm.next_in = (Bytef *) map_ptr(buf, offset, n); tx_strm.avail_in = n; nb -= n; offset += n; } if (tx_strm.avail_out == 0) { tx_strm.next_out = (Bytef *)(obuf + 2); tx_strm.avail_out = MAX_DATA_COUNT; if (flush != Z_NO_FLUSH) { /* * We left the last 4 bytes in the * buffer, in case they are the * last 4. Move them to the front. */ memcpy(tx_strm.next_out, obuf+MAX_DATA_COUNT-2, 4); tx_strm.next_out += 4; tx_strm.avail_out -= 4; } } if (nb == 0 && token != -2) flush = Z_SYNC_FLUSH; r = deflate(&tx_strm, flush); if (r != Z_OK) { rprintf(FERROR, "deflate returned %d\n", r); exit_cleanup(RERR_STREAMIO); } if (nb == 0 || tx_strm.avail_out == 0) { n = MAX_DATA_COUNT - tx_strm.avail_out; if (flush != Z_NO_FLUSH) { /* * We have to trim off the last 4 * bytes of output when flushing * (they are just 0, 0, ff, ff). */ n -= 4; } if (n > 0) { obuf[0] = DEFLATED_DATA + (n >> 8); obuf[1] = n; write_buf(f, obuf, n+2); } } } while (nb != 0 || tx_strm.avail_out == 0); flush_pending = token == -2; } if (token == -1) { /* end of file - clean up */ write_byte(f, END_FLAG); } else if (token != -2 && do_compression == CPRES_ZLIB) { /* Add the data in the current block to the compressor's * history and hash table. */ do { /* Break up long sections in the same way that * see_deflate_token() does. */ int32 n1 = toklen > 0xffff ? 0xffff : toklen; toklen -= n1; tx_strm.next_in = (Bytef *)map_ptr(buf, offset, n1); tx_strm.avail_in = n1; if (protocol_version >= 31) /* Newer protocols avoid a data-duplicating bug */ offset += n1; tx_strm.next_out = (Bytef *) obuf; tx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); r = deflate(&tx_strm, Z_INSERT_ONLY); if (r != Z_OK || tx_strm.avail_in != 0) { rprintf(FERROR, "deflate on token returned %d (%d bytes left)\n", r, tx_strm.avail_in); exit_cleanup(RERR_STREAMIO); } } while (toklen > 0); } } /* tells us what the receiver is in the middle of doing */ static enum { r_init, r_idle, r_running, r_inflating, r_inflated } recv_state; /* for inflating stuff */ static z_stream rx_strm; static char *cbuf; static char *dbuf; /* for decoding runs of tokens */ static int32 rx_token; static int32 rx_run; /* Receive a deflated token and inflate it */ static int32 recv_deflated_token(int f, char **data) { static int init_done; static int32 saved_flag; int32 n, flag; int r; for (;;) { switch (recv_state) { case r_init: if (!init_done) { rx_strm.next_out = NULL; rx_strm.zalloc = NULL; rx_strm.zfree = NULL; if (inflateInit2(&rx_strm, -15) != Z_OK) { rprintf(FERROR, "inflate init failed\n"); exit_cleanup(RERR_PROTOCOL); } cbuf = new_array(char, MAX_DATA_COUNT); dbuf = new_array(char, AVAIL_OUT_SIZE(CHUNK_SIZE)); init_done = 1; } else { inflateReset(&rx_strm); } recv_state = r_idle; rx_token = 0; break; case r_idle: case r_inflated: if (saved_flag) { flag = saved_flag & 0xff; saved_flag = 0; } else flag = read_byte(f); if ((flag & 0xC0) == DEFLATED_DATA) { n = ((flag & 0x3f) << 8) + read_byte(f); read_buf(f, cbuf, n); rx_strm.next_in = (Bytef *)cbuf; rx_strm.avail_in = n; recv_state = r_inflating; break; } if (recv_state == r_inflated) { /* check previous inflated stuff ended correctly */ rx_strm.avail_in = 0; rx_strm.next_out = (Bytef *)dbuf; rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); r = inflate(&rx_strm, Z_SYNC_FLUSH); n = AVAIL_OUT_SIZE(CHUNK_SIZE) - rx_strm.avail_out; /* * Z_BUF_ERROR just means no progress was * made, i.e. the decompressor didn't have * any pending output for us. */ if (r != Z_OK && r != Z_BUF_ERROR) { rprintf(FERROR, "inflate flush returned %d (%d bytes)\n", r, n); exit_cleanup(RERR_STREAMIO); } if (n != 0 && r != Z_BUF_ERROR) { /* have to return some more data and save the flag for later. */ saved_flag = flag + 0x10000; *data = dbuf; return n; } /* * At this point the decompressor should * be expecting to see the 0, 0, ff, ff bytes. */ if (!inflateSyncPoint(&rx_strm)) { rprintf(FERROR, "decompressor lost sync!\n"); exit_cleanup(RERR_STREAMIO); } rx_strm.avail_in = 4; rx_strm.next_in = (Bytef *)cbuf; cbuf[0] = cbuf[1] = 0; cbuf[2] = cbuf[3] = (char)0xff; inflate(&rx_strm, Z_SYNC_FLUSH); recv_state = r_idle; } if (flag == END_FLAG) { /* that's all folks */ recv_state = r_init; return 0; } /* here we have a token of some kind */ if (flag & TOKEN_REL) { rx_token += flag & 0x3f; flag >>= 6; } else rx_token = read_int(f); if (flag & 1) { rx_run = read_byte(f); rx_run += read_byte(f) << 8; recv_state = r_running; } return -1 - rx_token; case r_inflating: rx_strm.next_out = (Bytef *)dbuf; rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); r = inflate(&rx_strm, Z_NO_FLUSH); n = AVAIL_OUT_SIZE(CHUNK_SIZE) - rx_strm.avail_out; if (r != Z_OK) { rprintf(FERROR, "inflate returned %d (%d bytes)\n", r, n); exit_cleanup(RERR_STREAMIO); } if (rx_strm.avail_in == 0) recv_state = r_inflated; if (n != 0) { *data = dbuf; return n; } break; case r_running: ++rx_token; if (--rx_run == 0) recv_state = r_idle; return -1 - rx_token; } } } /* * put the data corresponding to a token that we've just returned * from recv_deflated_token into the decompressor's history buffer. */ static void see_deflate_token(char *buf, int32 len) { int r; int32 blklen; unsigned char hdr[5]; rx_strm.avail_in = 0; blklen = 0; hdr[0] = 0; do { if (rx_strm.avail_in == 0 && len != 0) { if (blklen == 0) { /* Give it a fake stored-block header. */ rx_strm.next_in = (Bytef *)hdr; rx_strm.avail_in = 5; blklen = len; if (blklen > 0xffff) blklen = 0xffff; hdr[1] = blklen; hdr[2] = blklen >> 8; hdr[3] = ~hdr[1]; hdr[4] = ~hdr[2]; } else { rx_strm.next_in = (Bytef *)buf; rx_strm.avail_in = blklen; if (protocol_version >= 31) /* Newer protocols avoid a data-duplicating bug */ buf += blklen; len -= blklen; blklen = 0; } } rx_strm.next_out = (Bytef *)dbuf; rx_strm.avail_out = AVAIL_OUT_SIZE(CHUNK_SIZE); r = inflate(&rx_strm, Z_SYNC_FLUSH); if (r != Z_OK && r != Z_BUF_ERROR) { rprintf(FERROR, "inflate (token) returned %d\n", r); exit_cleanup(RERR_STREAMIO); } } while (len || rx_strm.avail_out == 0); } #ifdef SUPPORT_ZSTD static ZSTD_inBuffer zstd_in_buff; static ZSTD_outBuffer zstd_out_buff; static ZSTD_CCtx *zstd_cctx; static void send_zstd_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 nb) { static int comp_init_done, flush_pending; ZSTD_EndDirective flush = ZSTD_e_continue; int32 n, r; /* initialization */ if (!comp_init_done) { zstd_cctx = ZSTD_createCCtx(); if (!zstd_cctx) { rprintf(FERROR, "compression init failed\n"); exit_cleanup(RERR_PROTOCOL); } obuf = new_array(char, OBUF_SIZE); ZSTD_CCtx_setParameter(zstd_cctx, ZSTD_c_compressionLevel, do_compression_level); zstd_out_buff.dst = obuf + 2; comp_init_done = 1; } if (last_token == -1) { last_run_end = 0; run_start = token; flush_pending = 0; } else if (last_token == -2) { run_start = token; } else if (nb != 0 || token != last_token + 1 || token >= run_start + 65536) { /* output previous run */ r = run_start - last_run_end; n = last_token - run_start; if (r >= 0 && r <= 63) { write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r); } else { write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG)); write_int(f, run_start); } if (n != 0) { write_byte(f, n); write_byte(f, n >> 8); } last_run_end = last_token; run_start = token; } last_token = token; if (nb || flush_pending) { zstd_in_buff.src = map_ptr(buf, offset, nb); zstd_in_buff.size = nb; zstd_in_buff.pos = 0; do { if (zstd_out_buff.size == 0) { zstd_out_buff.size = MAX_DATA_COUNT; zstd_out_buff.pos = 0; } /* File ended, flush */ if (token != -2) flush = ZSTD_e_flush; r = ZSTD_compressStream2(zstd_cctx, &zstd_out_buff, &zstd_in_buff, flush); if (ZSTD_isError(r)) { rprintf(FERROR, "ZSTD_compressStream returned %d\n", r); exit_cleanup(RERR_STREAMIO); } /* * Nothing is sent if the buffer isn't full so avoid smaller * transfers. If a file is finished then we flush the internal * state and send a smaller buffer so that the remote side can * finish the file. */ if (zstd_out_buff.pos == zstd_out_buff.size || flush == ZSTD_e_flush) { n = zstd_out_buff.pos; obuf[0] = DEFLATED_DATA + (n >> 8); obuf[1] = n; write_buf(f, obuf, n+2); zstd_out_buff.size = 0; } /* * Loop while the input buffer isn't full consumed or the * internal state isn't fully flushed. */ } while (zstd_in_buff.pos < zstd_in_buff.size || r > 0); flush_pending = token == -2; } if (token == -1) { /* end of file - clean up */ write_byte(f, END_FLAG); } } static ZSTD_DCtx *zstd_dctx; static int32 recv_zstd_token(int f, char **data) { static int decomp_init_done; static int out_buffer_size; int32 n, flag; int r; if (!decomp_init_done) { zstd_dctx = ZSTD_createDCtx(); if (!zstd_dctx) { rprintf(FERROR, "ZSTD_createDStream failed\n"); exit_cleanup(RERR_PROTOCOL); } /* Output buffer fits two decompressed blocks */ out_buffer_size = ZSTD_DStreamOutSize() * 2; cbuf = new_array(char, MAX_DATA_COUNT); dbuf = new_array(char, out_buffer_size); zstd_in_buff.src = cbuf; zstd_out_buff.dst = dbuf; decomp_init_done = 1; } for (;;) { switch (recv_state) { case r_init: recv_state = r_idle; rx_token = 0; break; case r_idle: flag = read_byte(f); if ((flag & 0xC0) == DEFLATED_DATA) { n = ((flag & 0x3f) << 8) + read_byte(f); read_buf(f, cbuf, n); zstd_in_buff.size = n; zstd_in_buff.pos = 0; recv_state = r_inflating; break; } if (flag == END_FLAG) { /* that's all folks */ recv_state = r_init; return 0; } /* here we have a token of some kind */ if (flag & TOKEN_REL) { rx_token += flag & 0x3f; flag >>= 6; } else rx_token = read_int(f); if (flag & 1) { rx_run = read_byte(f); rx_run += read_byte(f) << 8; recv_state = r_running; } return -1 - rx_token; case r_inflated: /* zstd doesn't get into this state */ break; case r_inflating: zstd_out_buff.size = out_buffer_size; zstd_out_buff.pos = 0; r = ZSTD_decompressStream(zstd_dctx, &zstd_out_buff, &zstd_in_buff); n = zstd_out_buff.pos; if (ZSTD_isError(r)) { rprintf(FERROR, "ZSTD decomp returned %d (%d bytes)\n", r, n); exit_cleanup(RERR_STREAMIO); } /* * If the input buffer is fully consumed and the output * buffer is not full then next step is to read more * data. */ if (zstd_in_buff.size == zstd_in_buff.pos && n < out_buffer_size) recv_state = r_idle; if (n != 0) { *data = dbuf; return n; } break; case r_running: ++rx_token; if (--rx_run == 0) recv_state = r_idle; return -1 - rx_token; } } } #endif /* SUPPORT_ZSTD */ #ifdef SUPPORT_LZ4 static void send_compressed_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 nb) { static int init_done, flush_pending; int size = MAX(LZ4_compressBound(CHUNK_SIZE), MAX_DATA_COUNT+2); int32 n, r; if (last_token == -1) { if (!init_done) { obuf = new_array(char, size); init_done = 1; } last_run_end = 0; run_start = token; flush_pending = 0; } else if (last_token == -2) { run_start = token; } else if (nb != 0 || token != last_token + 1 || token >= run_start + 65536) { /* output previous run */ r = run_start - last_run_end; n = last_token - run_start; if (r >= 0 && r <= 63) { write_byte(f, (n==0? TOKEN_REL: TOKENRUN_REL) + r); } else { write_byte(f, (n==0? TOKEN_LONG: TOKENRUN_LONG)); write_int(f, run_start); } if (n != 0) { write_byte(f, n); write_byte(f, n >> 8); } last_run_end = last_token; run_start = token; } last_token = token; if (nb != 0 || flush_pending) { int available_in, available_out = 0; const char *next_in; do { char *next_out = obuf + 2; if (available_out == 0) { available_in = MIN(nb, MAX_DATA_COUNT); next_in = map_ptr(buf, offset, available_in); } else available_in /= 2; available_out = LZ4_compress_default(next_in, next_out, available_in, size - 2); if (!available_out) { rprintf(FERROR, "compress returned %d\n", available_out); exit_cleanup(RERR_STREAMIO); } if (available_out <= MAX_DATA_COUNT) { obuf[0] = DEFLATED_DATA + (available_out >> 8); obuf[1] = available_out; write_buf(f, obuf, available_out + 2); available_out = 0; nb -= available_in; offset += available_in; } } while (nb != 0); flush_pending = token == -2; } if (token == -1) { /* end of file - clean up */ write_byte(f, END_FLAG); } } static int32 recv_compressed_token(int f, char **data) { static int init_done; int32 n, flag; int size = MAX(LZ4_compressBound(CHUNK_SIZE), MAX_DATA_COUNT+2); static const char *next_in; static int avail_in; int avail_out; for (;;) { switch (recv_state) { case r_init: if (!init_done) { cbuf = new_array(char, MAX_DATA_COUNT); dbuf = new_array(char, size); init_done = 1; } recv_state = r_idle; rx_token = 0; break; case r_idle: flag = read_byte(f); if ((flag & 0xC0) == DEFLATED_DATA) { n = ((flag & 0x3f) << 8) + read_byte(f); read_buf(f, cbuf, n); next_in = (char *)cbuf; avail_in = n; recv_state = r_inflating; break; } if (flag == END_FLAG) { /* that's all folks */ recv_state = r_init; return 0; } /* here we have a token of some kind */ if (flag & TOKEN_REL) { rx_token += flag & 0x3f; flag >>= 6; } else rx_token = read_int(f); if (flag & 1) { rx_run = read_byte(f); rx_run += read_byte(f) << 8; recv_state = r_running; } return -1 - rx_token; case r_inflating: avail_out = LZ4_decompress_safe(next_in, dbuf, avail_in, size); if (avail_out < 0) { rprintf(FERROR, "uncompress failed: %d\n", avail_out); exit_cleanup(RERR_STREAMIO); } recv_state = r_idle; *data = dbuf; return avail_out; case r_inflated: /* lz4 doesn't get into this state */ break; case r_running: ++rx_token; if (--rx_run == 0) recv_state = r_idle; return -1 - rx_token; } } } #endif /* SUPPORT_LZ4 */ /** * Transmit a verbatim buffer of length @p n followed by a token. * If token == -1 then we have reached EOF * If n == 0 then don't send a buffer */ void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 n, int32 toklen) { switch (do_compression) { case CPRES_NONE: simple_send_token(f, token, buf, offset, n); break; case CPRES_ZLIB: case CPRES_ZLIBX: send_deflated_token(f, token, buf, offset, n, toklen); break; #ifdef SUPPORT_ZSTD case CPRES_ZSTD: send_zstd_token(f, token, buf, offset, n); break; #endif #ifdef SUPPORT_LZ4 case CPRES_LZ4: send_compressed_token(f, token, buf, offset, n); break; #endif default: NOISY_DEATH("Unknown do_compression value"); } } /* * receive a token or buffer from the other end. If the return value is >0 then * it is a data buffer of that length, and *data will point at the data. * if the return value is -i then it represents token i-1 * if the return value is 0 then the end has been reached */ int32 recv_token(int f, char **data) { switch (do_compression) { case CPRES_NONE: return simple_recv_token(f,data); case CPRES_ZLIB: case CPRES_ZLIBX: return recv_deflated_token(f, data); #ifdef SUPPORT_ZSTD case CPRES_ZSTD: return recv_zstd_token(f, data); #endif #ifdef SUPPORT_LZ4 case CPRES_LZ4: return recv_compressed_token(f, data); #endif default: NOISY_DEATH("Unknown do_compression value"); } } /* * look at the data corresponding to a token, if necessary */ void see_token(char *data, int32 toklen) { switch (do_compression) { case CPRES_NONE: break; case CPRES_ZLIB: see_deflate_token(data, toklen); break; case CPRES_ZLIBX: break; #ifdef SUPPORT_ZSTD case CPRES_ZSTD: break; #endif #ifdef SUPPORT_LZ4 case CPRES_LZ4: /*see_uncompressed_token(data, toklen);*/ break; #endif default: NOISY_DEATH("Unknown do_compression value"); } } rsync-3.2.7/mkproto.awk0000664000000000000000000000160513712072252013563 0ustar rootroot#!/usr/bin/awk -f BEGIN { while ((getline i < "proto.h") > 0) old_protos = old_protos ? old_protos "\n" i : i close("proto.h") protos = "/* This file is automatically generated with \"make proto\". DO NOT EDIT */\n" } inheader { protos = protos "\n" ((inheader = /\)[ \t]*$/ ? 0 : 1) ? $0 : $0 ";") next } /^FN_(LOCAL|GLOBAL)_[^(]+\([^,()]+/ { local = /^FN_LOCAL/ gsub(/^FN_(LOC|GLOB)AL_|,.*$/, "") sub(/^BOOL\(/, "BOOL ") sub(/^CHAR\(/, "char ") sub(/^INTEGER\(/, "int ") sub(/^STRING\(/, "char *") protos = protos "\n" $0 (local ? "(int module_id);" : "(void);") next } /^static|^extern|;/||!/^[A-Za-z][A-Za-z0-9_]* / { next } /\(.*\)[ \t]*$/ { protos = protos "\n" $0 ";" next } /\(/ { inheader = 1 protos = protos "\n" $0 } END { if (old_protos != protos) print protos > "proto.h" system("touch proto.h-tstamp") } rsync-3.2.7/rrsync.10000664000000000000000000001317714324367163013005 0ustar rootroot.TH "rrsync" "1" "20 Oct 2022" "rrsync from rsync 3.2.7" "User Commands" .\" prefix=/usr .P .SH "NAME" .P rrsync \- a script to setup restricted rsync users via ssh logins .P .SH "SYNOPSIS" .P .nf rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR .fi .P The single non-option argument specifies the restricted \fIDIR\fP to use. It can be relative to the user's home directory or an absolute path. .P The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rrsync.1. .P .SH "DESCRIPTION" .P A user's ssh login can be restricted to only allow the running of an rsync transfer in one of two easy ways: .P .IP o forcing the running of the rrsync script .IP o forcing the running of an rsync daemon-over-ssh command. .P Both of these setups use a feature of ssh that allows a command to be forced to run instead of an interactive shell. However, if the user's home shell is bash, please see BASH SECURITY ISSUE for a potential issue. .P To use the rrsync script, edit the user's \fB~/.ssh/authorized_keys\fP file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted: .RS 4 .P .nf command="rrsync DIR" command="rrsync -ro DIR" command="rrsync -munge -no-del DIR" .fi .RE .P Then, ensure that the rrsync script has your desired option restrictions. You may want to copy the script to a local bin dir with a unique name if you want to have multiple configurations. One or more rrsync options can be specified prior to the \fIDIR\fP if you want to further restrict the transfer. .P To use an rsync daemon setup, edit the user's \fB~/.ssh/authorized_keys\fP file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted: .RS 4 .P .nf command="rsync --server --daemon ." command="rsync --server --daemon --config=/PATH/TO/rsyncd.conf ." .fi .RE .P Then, ensure that the rsyncd.conf file is created with one or more module names with the appropriate path and option restrictions. If rsync's \fB\-\-config\fP option is omitted, it defaults to \fB~/rsyncd.conf\fP. See the \fBrsyncd.conf\fP(5) manpage for details of how to configure an rsync daemon. .P When using rrsync, there can be just one restricted dir per authorized key. A daemon setup, on the other hand, allows multiple module names inside the config file, each one with its own path setting. .P The remainder of this manpage is dedicated to using the rrsync script. .P .SH "OPTIONS" .P .IP "\fB\-ro\fP" Allow only reading from the DIR. Implies \fB\-no-del\fP and \fB\-no-lock\fP. .IP "\fB\-wo\fP" Allow only writing to the DIR. .IP "\fB\-munge\fP" Enable rsync's \fB\-\-munge-links\fP on the server side. .IP "\fB\-no-del\fP" Disable rsync's \fB\-\-delete*\fP and \fB\-\-remove*\fP options. .IP "\fB\-no-lock\fP" Avoid the single-run (per-user) lock check. Useful with \fB\-munge\fP. .IP "\fB\-help\fP, \fB\-h\fP" Output this help message and exit. .P .SH "SECURITY RESTRICTIONS" .P The rrsync script validates the path arguments it is sent to try to restrict them to staying within the specified DIR. .P The rrsync script rejects rsync's \fB\-\-copy-links\fP option (by default) so that a copy cannot dereference a symlink within the DIR to get to a file outside the DIR. .P The rrsync script rejects rsync's \fB\-\-protect-args\fP (\fB\-s\fP) option because it would allow options to be sent to the server-side that the script cannot check. If you want to support \fB\-\-protect-args\fP, use a daemon-over-ssh setup. .P The rrsync script accepts just a subset of rsync's options that the real rsync uses when running the server command. A few extra convenience options are also included to help it to interact with BackupPC and accept some convenient user overrides. .P The script (or a copy of it) can be manually edited if you want it to customize the option handling. .P .SH "BASH SECURITY ISSUE" .P If your users have bash set as their home shell, bash may try to be overly helpful and ensure that the user's login bashrc files are run prior to executing the forced command. This can be a problem if the user can somehow update their home bashrc files, perhaps via the restricted copy, a shared home directory, or something similar. .P One simple way to avoid the issue is to switch the user to a simpler shell, such as dash. When choosing the new home shell, make sure that you're not choosing bash in disguise, as it is unclear if it avoids the security issue. .P Another potential fix is to ensure that the user's home directory is not a shared mount and that they have no means of copying files outside of their restricted directories. This may require you to force the enabling of symlink munging on the server side. .P A future version of openssh may have a change to the handling of forced commands that allows it to avoid using the user's home shell. .P .SH "EXAMPLES" .P The \fB~/.ssh/authorized_keys\fP file might have lines in it like this: .RS 4 .P .nf command="rrsync client/logs" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzG... command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmk... .fi .RE .P .SH "FILES" .P ~/.ssh/authorized_keys .P .SH "SEE ALSO" .P \fBrsync\fP(1), \fBrsyncd.conf\fP(5) .P .SH "VERSION" .P This manpage is current for version 3.2.7 of rsync. .P .SH "CREDITS" .P rsync is distributed under the GNU General Public License. See the file COPYING for details. .P An rsync web site is available at https://rsync.samba.org/ and its github project is https://github.com/WayneD/rsync. .P .SH "AUTHOR" .P The original rrsync perl script was written by Joe Smith. Many people have later contributed to it. The python version was created by Wayne Davison. rsync-3.2.7/rsync-ssl0000775000000000000000000001202014124202700013227 0ustar rootroot#!/usr/bin/env bash # This script uses openssl, gnutls, or stunnel to secure an rsync daemon connection. # By default this script takes rsync args and hands them off to the actual # rsync command with an --rsh option that makes it open an SSL connection to an # rsync daemon. See the rsync-ssl manpage for usage details and env variables. # When the first arg is --HELPER, we are being used by rsync as an --rsh helper # script, and the args are (note the trailing dot): # # rsync-ssl --HELPER HOSTNAME rsync --server --daemon . # # --HELPER is not a user-facing option, so it is not documented in the manpage. # The first SSL setup was based on: http://dozzie.jarowit.net/trac/wiki/RsyncSSL # Note that an stunnel connection requires at least version 4.x of stunnel. function rsync_ssl_run { case "$*" in *rsync://*) ;; *::*) ;; *) echo "You must use rsync-ssl with a daemon-style hostname." 1>&2 exit 1 ;; esac exec rsync --rsh="$0 --HELPER" "${@}" } function rsync_ssl_helper { if [[ -z "$RSYNC_SSL_TYPE" ]]; then found=`path_search openssl stunnel4 stunnel` || exit 1 if [[ "$found" == */openssl ]]; then RSYNC_SSL_TYPE=openssl RSYNC_SSL_OPENSSL="$found" elif [[ "$found" == */gnutls-cli ]]; then RSYNC_SSL_TYPE=gnutls RSYNC_SSL_GNUTLS="$found" else RSYNC_SSL_TYPE=stunnel RSYNC_SSL_STUNNEL="$found" fi fi case "$RSYNC_SSL_TYPE" in openssl) if [[ -z "$RSYNC_SSL_OPENSSL" ]]; then RSYNC_SSL_OPENSSL=`path_search openssl` || exit 1 fi optsep=' ' ;; gnutls) if [[ -z "$RSYNC_SSL_GNUTLS" ]]; then RSYNC_SSL_GNUTLS=`path_search gnutls-cli` || exit 1 fi optsep=' ' ;; stunnel) if [[ -z "$RSYNC_SSL_STUNNEL" ]]; then RSYNC_SSL_STUNNEL=`path_search stunnel4 stunnel` || exit 1 fi optsep=' = ' ;; *) echo "The RSYNC_SSL_TYPE specifies an unknown type: $RSYNC_SSL_TYPE" 1>&2 exit 1 ;; esac if [[ -z "$RSYNC_SSL_CERT" ]]; then certopt="" gnutls_cert_opt="" else certopt="-cert$optsep$RSYNC_SSL_CERT" gnutls_cert_opt="--x509certfile=$RSYNC_SSL_CERT" fi if [[ -z "$RSYNC_SSL_KEY" ]]; then keyopt="" gnutls_key_opt="" else keyopt="-key$optsep$RSYNC_SSL_KEY" gnutls_key_opt="--x509keyfile=$RSYNC_SSL_KEY" fi if [[ -z ${RSYNC_SSL_CA_CERT+x} ]]; then # RSYNC_SSL_CA_CERT unset - default CA set AND verify: # openssl: caopt="-verify_return_error -verify 4" # gnutls: gnutls_opts="" # stunnel: # Since there is no way of using the default CA certificate collection, # we cannot do any verification. Thus, stunnel should really only be # used if nothing else is available. cafile="" verify="" elif [[ "$RSYNC_SSL_CA_CERT" == "" ]]; then # RSYNC_SSL_CA_CERT set but empty -do NO verifications: # openssl: caopt="-verify 1" # gnutls: gnutls_opts="--insecure" # stunnel: cafile="" verify="verifyChain = no" else # RSYNC_SSL_CA_CERT set - use CA AND verify: # openssl: caopt="-CAfile $RSYNC_SSL_CA_CERT -verify_return_error -verify 4" # gnutls: gnutls_opts="--x509cafile=$RSYNC_SSL_CA_CERT" # stunnel: cafile="CAfile = $RSYNC_SSL_CA_CERT" verify="verifyChain = yes" fi port="${RSYNC_PORT:-0}" if [[ "$port" == 0 ]]; then port="${RSYNC_SSL_PORT:-874}" fi # If the user specified USER@HOSTNAME::module, then rsync passes us # the -l USER option too, so we must be prepared to ignore it. if [[ "$1" == "-l" ]]; then shift 2 fi hostname="$1" shift if [[ -z "$hostname" || "$1" != rsync || "$2" != --server || "$3" != --daemon ]]; then echo "Usage: rsync-ssl --HELPER HOSTNAME rsync --server --daemon ." 1>&2 exit 1 fi if [[ $RSYNC_SSL_TYPE == openssl ]]; then exec $RSYNC_SSL_OPENSSL s_client $caopt $certopt $keyopt -quiet -verify_quiet -servername $hostname -verify_hostname $hostname -connect $hostname:$port elif [[ $RSYNC_SSL_TYPE == gnutls ]]; then exec $RSYNC_SSL_GNUTLS --logfile=/dev/null $gnutls_cert_opt $gnutls_key_opt $gnutls_opts $hostname:$port else # devzero@web.de came up with this no-tmpfile calling syntax: exec $RSYNC_SSL_STUNNEL -fd 10 11<&0 <&2 echo "See the rsync-ssl manpage for configuration assistance." 1>&2 return 1 } if [[ "$#" == 0 ]]; then echo "Usage: rsync-ssl [--type=SSL_TYPE] RSYNC_ARG [...]" 1>&2 echo "The SSL_TYPE can be openssl or stunnel" exit 1 fi if [[ "$1" = --help || "$1" = -h ]]; then exec rsync --help fi if [[ "$1" == --HELPER ]]; then shift rsync_ssl_helper "${@}" fi if [[ "$1" == --type=* ]]; then export RSYNC_SSL_TYPE="${1/--type=/}" shift fi rsync_ssl_run "${@}" rsync-3.2.7/t_stub.c0000664000000000000000000000507714277731224013047 0ustar rootroot/* * This file contains really simple implementations for rsync global * functions, so that module test harnesses can run standalone. * * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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" int do_fsync = 0; int inplace = 0; int modify_window = 0; int preallocate_files = 0; int protect_args = 0; int module_id = -1; int relative_paths = 0; int module_dirlen = 0; int preserve_xattrs = 0; int preserve_perms = 0; int preserve_executability = 0; int omit_link_times = 0; int open_noatime = 0; size_t max_alloc = 0; /* max_alloc is needed when combined with util2.o */ char *partial_dir; char *module_dir; filter_rule_list daemon_filter_list; void rprintf(UNUSED(enum logcode code), const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } void rsyserr(UNUSED(enum logcode code), int errcode, const char *format, ...) { va_list ap; fputs(RSYNC_NAME ": ", stderr); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); fprintf(stderr, ": %s (%d)\n", strerror(errcode), errcode); } void _exit_cleanup(int code, const char *file, int line) { fprintf(stderr, "exit(%d): %s(%d)\n", code, file, line); exit(code); } int check_filter(UNUSED(filter_rule_list *listp), UNUSED(enum logcode code), UNUSED(const char *name), UNUSED(int name_is_dir)) { /* This function doesn't really get called in this test context, so * just return 0. */ return 0; } int copy_xattrs(UNUSED(const char *source), UNUSED(const char *dest)) { return -1; } void free_xattr(UNUSED(stat_x *sxp)) { return; } void free_acl(UNUSED(stat_x *sxp)) { return; } char *lp_name(UNUSED(int mod)) { return NULL; } BOOL lp_use_chroot(UNUSED(int mod)) { return 0; } const char *who_am_i(void) { return "tester"; } int csum_len_for_type(int cst, int flg) { return cst || !flg ? 16 : 1; } int canonical_checksum(int cst) { return cst ? 0 : 0; } rsync-3.2.7/rsync-ssl.1.html0000664000000000000000000001724414324367163014364 0ustar rootroot rsync-ssl(1) manpage

NAME

rsync-ssl -⁠ a helper script for connecting to an ssl rsync daemon

SYNOPSIS

rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS

The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rsync-ssl.1.

DESCRIPTION

The rsync-ssl script helps you to run an rsync copy to/from an rsync daemon that requires ssl connections.

The script requires that you specify an rsync-daemon arg in the style of either hostname:: (with 2 colons) or rsync://hostname/. The default port used for connecting is 874 (one higher than the normal 873) unless overridden in the environment. You can specify an overriding port via --port or by including it in the normal spot in the URL format, though both of those require your rsync version to be at least 3.2.0.

OPTIONS

If the first arg is a --type=SSL_TYPE option, the script will only use that particular program to open an ssl connection instead of trying to find an openssl or stunnel executable via a simple heuristic (assuming that the RSYNC_SSL_TYPE environment variable is not set as well -⁠-⁠ see below). This option must specify one of openssl or stunnel. The equal sign is required for this particular option.

All the other options are passed through to the rsync command, so consult the rsync(1) manpage for more information on how it works.

ENVIRONMENT VARIABLES

The ssl helper scripts are affected by the following environment variables:

RSYNC_SSL_TYPE

Specifies the program type that should be used to open the ssl connection. It must be one of openssl or stunnel. The --type=SSL_TYPE option overrides this, when specified.

RSYNC_SSL_PORT

If specified, the value is the port number that is used as the default when the user does not specify a port in their rsync command. When not specified, the default port number is 874. (Note that older rsync versions (prior to 3.2.0) did not communicate an overriding port number value to the helper script.)

RSYNC_SSL_CERT

If specified, the value is a filename that contains a certificate to use for the connection.

RSYNC_SSL_KEY

If specified, the value is a filename that contains a key for the provided certificate to use for the connection.

RSYNC_SSL_CA_CERT

If specified, the value is a filename that contains a certificate authority certificate that is used to validate the connection.

RSYNC_SSL_OPENSSL

Specifies the openssl executable to run when the connection type is set to openssl. If unspecified, the $PATH is searched for "openssl".

RSYNC_SSL_GNUTLS

Specifies the gnutls-cli executable to run when the connection type is set to gnutls. If unspecified, the $PATH is searched for "gnutls-cli".

RSYNC_SSL_STUNNEL

Specifies the stunnel executable to run when the connection type is set to stunnel. If unspecified, the $PATH is searched first for "stunnel4" and then for "stunnel".

EXAMPLES

rsync-ssl -aiv example.com::mod/ dest
rsync-ssl --type=openssl -aiv example.com::mod/ dest
rsync-ssl -aiv --port 9874 example.com::mod/ dest
rsync-ssl -aiv rsync://example.com:9874/mod/ dest

THE SERVER SIDE

For help setting up an SSL/TLS supporting rsync, see the instructions in rsyncd.conf.

SEE ALSO

rsync(1), rsyncd.conf(5)

CAVEATS

Note that using an stunnel connection requires at least version 4 of stunnel, which should be the case on modern systems. Also, it does not verify a connection against the CA certificate collection, so it only encrypts the connection without any cert validation unless you have specified the certificate environment options.

This script also supports a --type=gnutls option, but at the time of this release the gnutls-cli command was dropping output, making it unusable. If that bug has been fixed in your version, feel free to put gnutls into an exported RSYNC_SSL_TYPE environment variable to make its use the default.

BUGS

Please report bugs! See the web site at https://rsync.samba.org/.

VERSION

This manpage is current for version 3.2.7 of rsync.

CREDITS

Rsync is distributed under the GNU General Public License. See the file COPYING for details.

A web site is available at https://rsync.samba.org/. The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page.

AUTHOR

This manpage was written by Wayne Davison.

Mailing lists for support and development are available at https://lists.samba.org/.

20 Oct 2022

rsync-3.2.7/doc/0000775000000000000000000000000014324367162012136 5ustar rootrootrsync-3.2.7/doc/README-SGML0000664000000000000000000000124007442774776013573 0ustar rootrootHandling the rsync SGML documentation rsync documentation is now primarily in Docbook format. Docbook is an SGML/XML documentation format that is becoming standard on free operating systems. It's also used for Samba documentation. The SGML files are source code that can be translated into various useful output formats, primarily PDF, HTML, Postscript and plain text. To do this transformation on Debian, you should install the docbook-utils package. Having done that, you can say docbook2pdf rsync.sgml and so on. On other systems you probably need James Clark's "sp" and "JadeTeX" packages. Work it out for yourself and send a note to the mailing list. rsync-3.2.7/doc/profile.txt0000664000000000000000000000361707436476451014356 0ustar rootrootNotes on rsync profiling strlcpy is hot: 0.00 0.00 1/7735635 push_dir [68] 0.00 0.00 1/7735635 pop_dir [71] 0.00 0.00 1/7735635 send_file_list [15] 0.01 0.00 18857/7735635 send_files [4] 0.04 0.00 129260/7735635 send_file_entry [18] 0.04 0.00 129260/7735635 make_file [20] 0.04 0.00 141666/7735635 send_directory [36] 2.29 0.00 7316589/7735635 f_name [13] [14] 11.7 2.42 0.00 7735635 strlcpy [14] Here's the top few functions: 46.23 9.57 9.57 13160929 0.00 0.00 mdfour64 14.78 12.63 3.06 13160929 0.00 0.00 copy64 11.69 15.05 2.42 7735635 0.00 0.00 strlcpy 10.05 17.13 2.08 41438 0.05 0.38 sum_update 4.11 17.98 0.85 13159996 0.00 0.00 mdfour_update 1.50 18.29 0.31 file_compare 1.45 18.59 0.30 129261 0.00 0.01 send_file_entry 1.23 18.84 0.26 2557585 0.00 0.00 f_name 1.11 19.07 0.23 1483750 0.00 0.00 u_strcmp 1.11 19.30 0.23 118129 0.00 0.00 writefd_unbuffered 0.92 19.50 0.19 1085011 0.00 0.00 writefd 0.43 19.59 0.09 156987 0.00 0.00 read_timeout 0.43 19.68 0.09 129261 0.00 0.00 clean_fname 0.39 19.75 0.08 32887 0.00 0.38 matched 0.34 19.82 0.07 1 70.00 16293.92 send_files 0.29 19.89 0.06 129260 0.00 0.00 make_file 0.29 19.95 0.06 75430 0.00 0.00 read_unbuffered mdfour could perhaps be made faster: /* NOTE: This code makes no attempt to be fast! */ There might be an optimized version somewhere that we can borrow. rsync-3.2.7/doc/rsync.sgml0000664000000000000000000002710313645724757014177 0ustar rootroot rsync 1996 -- 2002 Martin Pool Andrew Tridgell Martin Pool Introduction rsync is a flexible program for efficiently copying files or directory trees. rsync has many options to select which files will be copied and how they are to be transferred. It may be used as an alternative to ftp, http, scp or rcp. The rsync remote-update protocol allows rsync to transfer just the differences between two sets of files across the network link, using an efficient checksum-search algorithm described in the technical report that accompanies this package. Some of the additional features of rsync are: support for copying links, devices, owners, groups and permissions exclude and exclude-from options similar to GNU tar a CVS exclude mode for ignoring the same files that CVS would ignore can use any transparent remote shell, including rsh or ssh does not require root privileges pipelining of file transfers to minimize latency costs support for anonymous or authenticated rsync servers (ideal for mirroring) Using rsync
Introductory example Probably the most common case of rsync usage is to copy files to or from a remote machine using ssh as a network transport. In this situation rsync is a good alternative to scp. The most commonly used arguments for rsync are Be verbose. Primarily, display the name of each file as it is copied. Reproduce the structure and attributes of the origin files as exactly as possible: this includes copying subdirectories, symlinks, special files, ownership and permissions. (@xref{Attributes to copy}.) Compress network traffic, using a modified version of the @command{zlib} library. Display a progress indicator while files are transferred. This should normally be omitted if rsync is not run on a terminal.
Local and remote There are six different ways of using rsync. They are: for copying local files. This is invoked when neither source nor destination path contains a @code{:} separator for copying from the local machine to a remote machine using a remote shell program as the transport (such as rsh or ssh). This is invoked when the destination path contains a single @code{:} separator. for copying from a remote machine to the local machine using a remote shell program. This is invoked when the source contains a @code{:} separator. for copying from a remote rsync server to the local machine. This is invoked when the source path contains a @code{::} separator or a @code{rsync://} URL. for copying from the local machine to a remote rsync server. This is invoked when the destination path contains a @code{::} separator. for listing files on a remote machine. This is done the same way as rsync transfers except that you leave off the local destination. Note that in all cases (other than listing) at least one of the source and destination paths must be local. Any one invocation of rsync makes a copy in a single direction. rsync currently has no equivalent of @command{ftp}'s interactive mode. @cindex @sc{nfs} @cindex network filesystems @cindex remote filesystems rsync's network protocol is generally faster at copying files than network filesystems such as @sc{nfs} or @sc{cifs}. It is better to run rsync on the file server either as a daemon or over ssh than running rsync giving the network directory.
Frequently asked questions Are there mailing lists for rsync? Yes, and you can subscribe and unsubscribe through a web interface at http://lists.samba.org/ If you are having trouble with the mailing list, please send mail to the administrator rsync-admin@lists.samba.org not to the list itself. The mailing list archives are searchable. Use Google and prepend the search with site:lists.samba.org rsync, plus relevant keywords. Why is rsync so much bigger when I build it with gcc? On gcc, rsync builds by default with debug symbols included. If you strip both executables, they should end up about the same size. (Use make install-strip.) Is rsync useful for a single large file like an ISO image? Yes, but note the following: Background: A common use of rsync is to update a file (or set of files) in one location from a more correct or up-to-date copy in another location, taking advantage of portions of the files that are identical to speed up the process. (Note that rsync will transfer a file in its entirety if no copy exists at the destination.) (This discussion is written in terms of updating a local copy of a file from a correct file in a remote location, although rsync can work in either direction.) The file to be updated (the local file) must be in a destination directory that has enough space for two copies of the file. (In addition, keep an extra copy of the file to be updated in a different location for safety -- see the discussion (below) about rsync's behavior when the rsync process is interrupted before completion.) The local file must have the same name as the remote file being sync'd to (I think?). If you are trying to upgrade an iso from, for example, beta1 to beta2, rename the local file to the same name as the beta2 file. *(This is a useful thing to do -- only the changed portions will be transmitted.)* The extra copy of the local file kept in a different location is because of rsync's behavior if interrupted before completion: * If you specify the --partial option and rsync is interrupted, rsync will save the partially rsync'd file and throw away the original local copy. (The partially rsync'd file is correct but truncated.) If rsync is restarted, it will not have a local copy of the file to check for duplicate blocks beyond the section of the file that has already been rsync'd, thus the remainder of the rsync process will be a "pure transfer" of the file rather than taking advantage of the rsync algorithm. * If you don't specify the --partial option and rsync is interrupted, rsync will throw away the partially rsync'd file, and, when rsync is restarted starts the rsync process over from the beginning. Which of these is most desirable depends on the degree of commonality between the local and remote copies of the file *and how much progress was made before the interruption*. The ideal approach after an interruption would be to create a new file by taking the original file and deleting a portion equal in size to the portion already rsync'd and then appending *the remaining* portion to the portion of the file that has already been rsync'd. (There has been some discussion about creating an option to do this automatically.) The --compare-dest option is useful when transferring multiple files, but is of no benefit in transferring a single file. (AFAIK) *Other potentially useful information can be found at: -[3]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFile This answer, formatted with "real" bullets, can be found at: -[4]http://twiki.org/cgi-bin/view/Wikilearn/RsyncingALargeFileFAQ* Other Resources
rsync-3.2.7/case_N.h0000664000000000000000000000442113646104106012724 0ustar rootroot/* * Allow an arbitrary sequence of case labels. * * Copyright (C) 2006-2020 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. */ /* This is included multiple times, once for every segment in a switch statement. * This produces the next "case N:" statement in sequence. */ #if !defined CASE_N_STATE_0 #define CASE_N_STATE_0 case 0: #elif !defined CASE_N_STATE_1 #define CASE_N_STATE_1 /* FALLTHROUGH */ case 1: #elif !defined CASE_N_STATE_2 #define CASE_N_STATE_2 /* FALLTHROUGH */ case 2: #elif !defined CASE_N_STATE_3 #define CASE_N_STATE_3 /* FALLTHROUGH */ case 3: #elif !defined CASE_N_STATE_4 #define CASE_N_STATE_4 /* FALLTHROUGH */ case 4: #elif !defined CASE_N_STATE_5 #define CASE_N_STATE_5 /* FALLTHROUGH */ case 5: #elif !defined CASE_N_STATE_6 #define CASE_N_STATE_6 /* FALLTHROUGH */ case 6: #elif !defined CASE_N_STATE_7 #define CASE_N_STATE_7 /* FALLTHROUGH */ case 7: #elif !defined CASE_N_STATE_8 #define CASE_N_STATE_8 /* FALLTHROUGH */ case 8: #elif !defined CASE_N_STATE_9 #define CASE_N_STATE_9 /* FALLTHROUGH */ case 9: #elif !defined CASE_N_STATE_10 #define CASE_N_STATE_10 /* FALLTHROUGH */ case 10: #elif !defined CASE_N_STATE_11 #define CASE_N_STATE_11 /* FALLTHROUGH */ case 11: #elif !defined CASE_N_STATE_12 #define CASE_N_STATE_12 /* FALLTHROUGH */ case 12: #elif !defined CASE_N_STATE_13 #define CASE_N_STATE_13 /* FALLTHROUGH */ case 13: #elif !defined CASE_N_STATE_14 #define CASE_N_STATE_14 /* FALLTHROUGH */ case 14: #elif !defined CASE_N_STATE_15 #define CASE_N_STATE_15 /* FALLTHROUGH */ case 15: #elif !defined CASE_N_STATE_16 #define CASE_N_STATE_16 /* FALLTHROUGH */ case 16: #else #error Need to add more case statements! #endif rsync-3.2.7/connection.c0000664000000000000000000000252713643716631013704 0ustar rootroot/* * Support the max connections option. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2006-2020 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" /* A simple routine to do connection counting. This returns 1 on success * and 0 on failure, with errno also being set if the open() failed (errno * will be 0 if the lock request failed). */ int claim_connection(char *fname, int max_connections) { int fd, i; if (max_connections == 0) return 1; if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0) return 0; /* Find a free spot. */ for (i = 0; i < max_connections; i++) { if (lock_range(fd, i*4, 4)) return 1; } close(fd); /* A lock failure needs to return an errno of 0. */ errno = 0; return 0; } rsync-3.2.7/options.c0000664000000000000000000027400014307170062013223 0ustar rootroot/* * Command-line (and received via daemon-socket) option parsing. * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000, 2001, 2002 Martin Pool * Copyright (C) 2002-2022 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 "itypes.h" #include "ifuncs.h" #include extern int module_id; extern int local_server; extern int sanitize_paths; extern int trust_sender_args; extern int trust_sender_filter; extern unsigned int module_dirlen; extern filter_rule_list filter_list; extern filter_rule_list daemon_filter_list; int make_backups = 0; /** * If 1, send the whole file as literal data rather than trying to * create an incremental diff. * * If -1, then look at whether we're local or remote and go by that. * * @sa disable_deltas_p() **/ int whole_file = -1; int append_mode = 0; int keep_dirlinks = 0; int copy_dirlinks = 0; int copy_links = 0; int copy_devices = 0; int write_devices = 0; int preserve_links = 0; int preserve_hard_links = 0; int preserve_acls = 0; int preserve_xattrs = 0; int preserve_perms = 0; int preserve_executability = 0; int preserve_devices = 0; int preserve_specials = 0; int preserve_uid = 0; int preserve_gid = 0; int preserve_mtimes = 0; int preserve_atimes = 0; int preserve_crtimes = 0; int omit_dir_times = 0; int omit_link_times = 0; int trust_sender = 0; int update_only = 0; int open_noatime = 0; int cvs_exclude = 0; int dry_run = 0; int do_xfers = 1; int do_fsync = 0; int ignore_times = 0; int delete_mode = 0; int delete_during = 0; int delete_before = 0; int delete_after = 0; int delete_excluded = 0; int remove_source_files = 0; int one_file_system = 0; int protocol_version = PROTOCOL_VERSION; int sparse_files = 0; int preallocate_files = 0; int do_compression = 0; int do_compression_level = CLVL_NOT_SPECIFIED; int am_root = 0; /* 0 = normal, 1 = root, 2 = --super, -1 = --fake-super */ int am_server = 0; int am_sender = 0; int am_starting_up = 1; int relative_paths = -1; int implied_dirs = 1; int missing_args = 0; /* 0 = FERROR_XFER, 1 = ignore, 2 = delete */ int numeric_ids = 0; int msgs2stderr = 2; /* Default: send errors to stderr for local & remote-shell transfers */ int saw_stderr_opt = 0; int allow_8bit_chars = 0; int force_delete = 0; int io_timeout = 0; int prune_empty_dirs = 0; int use_qsort = 0; char *files_from = NULL; int filesfrom_fd = -1; char *filesfrom_host = NULL; int eol_nulls = 0; int protect_args = -1; int old_style_args = -1; int human_readable = 1; int recurse = 0; int mkpath_dest_arg = 0; int allow_inc_recurse = 1; int xfer_dirs = -1; int am_daemon = 0; int connect_timeout = 0; int keep_partial = 0; int safe_symlinks = 0; int copy_unsafe_links = 0; int munge_symlinks = 0; int size_only = 0; int daemon_bwlimit = 0; int bwlimit = 0; int fuzzy_basis = 0; size_t bwlimit_writemax = 0; int ignore_existing = 0; int ignore_non_existing = 0; int need_messages_from_generator = 0; int max_delete = INT_MIN; OFF_T max_size = -1; OFF_T min_size = -1; int ignore_errors = 0; int modify_window = 0; int blocking_io = -1; int checksum_seed = 0; int inplace = 0; int delay_updates = 0; int32 block_size = 0; time_t stop_at_utime = 0; char *skip_compress = NULL; char *copy_as = NULL; item_list dparam_list = EMPTY_ITEM_LIST; /** Network address family. **/ int default_af_hint #ifdef INET6 = 0; /* Any protocol */ #else = AF_INET; /* Must use IPv4 */ # ifdef AF_INET6 # undef AF_INET6 # endif # define AF_INET6 AF_INET /* make -6 option a no-op */ #endif /** Do not go into the background when run as --daemon. Good * for debugging and required for running as a service on W32, * or under Unix process-monitors. **/ int no_detach #if defined _WIN32 || defined __WIN32__ = 1; #else = 0; #endif int write_batch = 0; int read_batch = 0; int backup_dir_len = 0; int backup_suffix_len; unsigned int backup_dir_remainder; char *backup_suffix = NULL; char *tmpdir = NULL; char *partial_dir = NULL; char *basis_dir[MAX_BASIS_DIRS+1]; char *config_file = NULL; char *shell_cmd = NULL; char *logfile_name = NULL; char *logfile_format = NULL; char *stdout_format = NULL; char *password_file = NULL; char *early_input_file = NULL; char *rsync_path = RSYNC_PATH; char *backup_dir = NULL; char backup_dir_buf[MAXPATHLEN]; char *sockopts = NULL; char *usermap = NULL; char *groupmap = NULL; int rsync_port = 0; int alt_dest_type = 0; int basis_dir_cnt = 0; #define DEFAULT_MAX_ALLOC (1024L * 1024 * 1024) size_t max_alloc = DEFAULT_MAX_ALLOC; char *max_alloc_arg; static int version_opt_cnt = 0; static int remote_option_alloc = 0; int remote_option_cnt = 0; const char **remote_options = NULL; const char *checksum_choice = NULL; const char *compress_choice = NULL; int quiet = 0; int output_motd = 1; int log_before_transfer = 0; int stdout_format_has_i = 0; int stdout_format_has_o_or_i = 0; int logfile_format_has_i = 0; int logfile_format_has_o_or_i = 0; int always_checksum = 0; int list_only = 0; #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */ char *batch_name = NULL; int need_unsorted_flist = 0; char *iconv_opt = #ifdef ICONV_OPTION ICONV_OPTION; #else NULL; #endif struct chmod_mode_struct *chmod_modes = NULL; static const char *debug_verbosity[] = { /*0*/ NULL, /*1*/ NULL, /*2*/ "BIND,CMD,CONNECT,DEL,DELTASUM,DUP,FILTER,FLIST,ICONV", /*3*/ "ACL,BACKUP,CONNECT2,DELTASUM2,DEL2,EXIT,FILTER2,FLIST2,FUZZY,GENR,OWN,RECV,SEND,TIME", /*4*/ "CMD2,DELTASUM3,DEL3,EXIT2,FLIST3,ICONV2,OWN2,PROTO,TIME2", /*5*/ "CHDIR,DELTASUM4,FLIST4,FUZZY2,HASH,HLINK", }; #define MAX_VERBOSITY ((int)(sizeof debug_verbosity / sizeof debug_verbosity[0]) - 1) static const char *info_verbosity[1+MAX_VERBOSITY] = { /*0*/ "NONREG", /*1*/ "COPY,DEL,FLIST,MISC,NAME,STATS,SYMSAFE", /*2*/ "BACKUP,MISC2,MOUNT,NAME2,REMOVE,SKIP", }; #define MAX_OUT_LEVEL 4 /* The largest N allowed for any flagN word. */ short info_levels[COUNT_INFO], debug_levels[COUNT_DEBUG]; #define DEFAULT_PRIORITY 0 /* Default/implied/--verbose set values. */ #define HELP_PRIORITY 1 /* The help output uses this level. */ #define USER_PRIORITY 2 /* User-specified via --info or --debug */ #define LIMIT_PRIORITY 3 /* Overriding priority when limiting values. */ #define W_CLI (1<<0) /* client side */ #define W_SRV (1<<1) /* server side */ #define W_SND (1<<2) /* sending side */ #define W_REC (1<<3) /* receiving side */ struct output_struct { char *name; /* The name of the info/debug flag. */ char *help; /* The description of the info/debug flag. */ uchar namelen; /* The length of the name string. */ uchar flag; /* The flag's value, for consistency check. */ uchar where; /* Bits indicating where the flag is used. */ uchar priority; /* See *_PRIORITY defines. */ }; #define INFO_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, INFO_##flag, where, 0 } static struct output_struct info_words[COUNT_INFO+1] = { INFO_WORD(BACKUP, W_REC, "Mention files backed up"), INFO_WORD(COPY, W_REC, "Mention files copied locally on the receiving side"), INFO_WORD(DEL, W_REC, "Mention deletions on the receiving side"), INFO_WORD(FLIST, W_CLI, "Mention file-list receiving/sending (levels 1-2)"), INFO_WORD(MISC, W_SND|W_REC, "Mention miscellaneous information (levels 1-2)"), INFO_WORD(MOUNT, W_SND|W_REC, "Mention mounts that were found or skipped"), INFO_WORD(NAME, W_SND|W_REC, "Mention 1) updated file/dir names, 2) unchanged names"), INFO_WORD(NONREG, W_REC, "Mention skipped non-regular files (default 1, 0 disables)"), INFO_WORD(PROGRESS, W_CLI, "Mention 1) per-file progress or 2) total transfer progress"), INFO_WORD(REMOVE, W_SND, "Mention files removed on the sending side"), INFO_WORD(SKIP, W_REC, "Mention files skipped due to transfer overrides (levels 1-2)"), INFO_WORD(STATS, W_CLI|W_SRV, "Mention statistics at end of run (levels 1-3)"), INFO_WORD(SYMSAFE, W_SND|W_REC, "Mention symlinks that are unsafe"), { NULL, "--info", 0, 0, 0, 0 } }; #define DEBUG_WORD(flag, where, help) { #flag, help, sizeof #flag - 1, DEBUG_##flag, where, 0 } static struct output_struct debug_words[COUNT_DEBUG+1] = { DEBUG_WORD(ACL, W_SND|W_REC, "Debug extra ACL info"), DEBUG_WORD(BACKUP, W_REC, "Debug backup actions (levels 1-2)"), DEBUG_WORD(BIND, W_CLI, "Debug socket bind actions"), DEBUG_WORD(CHDIR, W_CLI|W_SRV, "Debug when the current directory changes"), DEBUG_WORD(CONNECT, W_CLI, "Debug connection events (levels 1-2)"), DEBUG_WORD(CMD, W_CLI, "Debug commands+options that are issued (levels 1-2)"), DEBUG_WORD(DEL, W_REC, "Debug delete actions (levels 1-3)"), DEBUG_WORD(DELTASUM, W_SND|W_REC, "Debug delta-transfer checksumming (levels 1-4)"), DEBUG_WORD(DUP, W_REC, "Debug weeding of duplicate names"), DEBUG_WORD(EXIT, W_CLI|W_SRV, "Debug exit events (levels 1-3)"), DEBUG_WORD(FILTER, W_SND|W_REC, "Debug filter actions (levels 1-3)"), DEBUG_WORD(FLIST, W_SND|W_REC, "Debug file-list operations (levels 1-4)"), DEBUG_WORD(FUZZY, W_REC, "Debug fuzzy scoring (levels 1-2)"), DEBUG_WORD(GENR, W_REC, "Debug generator functions"), DEBUG_WORD(HASH, W_SND|W_REC, "Debug hashtable code"), DEBUG_WORD(HLINK, W_SND|W_REC, "Debug hard-link actions (levels 1-3)"), DEBUG_WORD(ICONV, W_CLI|W_SRV, "Debug iconv character conversions (levels 1-2)"), DEBUG_WORD(IO, W_CLI|W_SRV, "Debug I/O routines (levels 1-4)"), DEBUG_WORD(NSTR, W_CLI|W_SRV, "Debug negotiation strings"), DEBUG_WORD(OWN, W_REC, "Debug ownership changes in users & groups (levels 1-2)"), DEBUG_WORD(PROTO, W_CLI|W_SRV, "Debug protocol information"), DEBUG_WORD(RECV, W_REC, "Debug receiver functions"), DEBUG_WORD(SEND, W_SND, "Debug sender functions"), DEBUG_WORD(TIME, W_REC, "Debug setting of modified times (levels 1-2)"), { NULL, "--debug", 0, 0, 0, 0 } }; static int verbose = 0; static int do_stats = 0; static int do_progress = 0; static int daemon_opt; /* sets am_daemon after option error-reporting */ static int F_option_cnt = 0; static int modify_window_set; static int itemize_changes = 0; static int refused_delete, refused_archive_part, refused_compress; static int refused_partial, refused_progress, refused_delete_before; static int refused_delete_during; static int refused_inplace, refused_no_iconv; static BOOL usermap_via_chown, groupmap_via_chown; static char *outbuf_mode; static char *bwlimit_arg, *max_size_arg, *min_size_arg; static char tmp_partialdir[] = ".~tmp~"; /** Local address to bind. As a character string because it's * interpreted by the IPv6 layer: should be a numeric IP4 or IP6 * address, or a hostname. **/ char *bind_address; static void output_item_help(struct output_struct *words); /* This constructs a string that represents all the options set for either * the --info or --debug setting, skipping any implied options (by -v, etc.). * This is used both when conveying the user's options to the server, and * when the help output wants to tell the user what options are implied. */ static char *make_output_option(struct output_struct *words, short *levels, uchar where) { char *str = words == info_words ? "--info=" : "--debug="; int j, counts[MAX_OUT_LEVEL+1], pos, skipped = 0, len = 0, max = 0, lev = 0; int word_count = words == info_words ? COUNT_INFO : COUNT_DEBUG; char *buf; memset(counts, 0, sizeof counts); for (j = 0; words[j].name; j++) { if (words[j].flag != j) { rprintf(FERROR, "rsync: internal error on %s%s: %d != %d\n", words == info_words ? "INFO_" : "DEBUG_", words[j].name, words[j].flag, j); exit_cleanup(RERR_UNSUPPORTED); } if (!(words[j].where & where)) continue; if (words[j].priority == DEFAULT_PRIORITY) { /* Implied items don't need to be mentioned. */ skipped++; continue; } len += len ? 1 : strlen(str); len += strlen(words[j].name); len += levels[j] == 1 ? 0 : 1; if (words[j].priority == HELP_PRIORITY) continue; /* no abbreviating for help */ assert(levels[j] <= MAX_OUT_LEVEL); if (++counts[levels[j]] > max) { /* Determine which level has the most items. */ lev = levels[j]; max = counts[lev]; } } /* Sanity check the COUNT_* define against the length of the table. */ if (j != word_count) { rprintf(FERROR, "rsync: internal error: %s is wrong! (%d != %d)\n", words == info_words ? "COUNT_INFO" : "COUNT_DEBUG", j, word_count); exit_cleanup(RERR_UNSUPPORTED); } if (!len) return NULL; len++; buf = new_array(char, len); pos = 0; if (skipped || max < 5) lev = -1; else { if (lev == 0) pos += snprintf(buf, len, "%sNONE", str); else if (lev == 1) pos += snprintf(buf, len, "%sALL", str); else pos += snprintf(buf, len, "%sALL%d", str, lev); } for (j = 0; words[j].name && pos < len; j++) { if (words[j].priority == DEFAULT_PRIORITY || levels[j] == lev || !(words[j].where & where)) continue; if (pos) buf[pos++] = ','; else pos += strlcpy(buf+pos, str, len-pos); if (pos < len) pos += strlcpy(buf+pos, words[j].name, len-pos); /* Level 1 is implied by the name alone. */ if (levels[j] != 1 && pos < len) buf[pos++] = '0' + levels[j]; } buf[pos] = '\0'; return buf; } static void parse_output_words(struct output_struct *words, short *levels, const char *str, uchar priority) { const char *s; int j, len, lev; for ( ; str; str = s) { if ((s = strchr(str, ',')) != NULL) len = s++ - str; else len = strlen(str); if (!len) continue; if (!isDigit(str)) { while (len && isDigit(str+len-1)) len--; } lev = isDigit(str+len) ? atoi(str+len) : 1; if (lev > MAX_OUT_LEVEL) lev = MAX_OUT_LEVEL; if (len == 4 && strncasecmp(str, "help", 4) == 0) { output_item_help(words); exit_cleanup(0); } if (len == 4 && strncasecmp(str, "none", 4) == 0) len = lev = 0; else if (len == 3 && strncasecmp(str, "all", 3) == 0) len = 0; for (j = 0; words[j].name; j++) { if (!len || (len == words[j].namelen && strncasecmp(str, words[j].name, len) == 0)) { if (priority >= words[j].priority) { words[j].priority = priority; levels[j] = lev; } if (len) break; } } if (len && !words[j].name && !am_server) { rprintf(FERROR, "Unknown %s item: \"%.*s\"\n", words[j].help, len, str); exit_cleanup(RERR_SYNTAX); } } } /* Tell the user what all the info or debug flags mean. */ static void output_item_help(struct output_struct *words) { short *levels = words == info_words ? info_levels : debug_levels; const char **verbosity = words == info_words ? info_verbosity : debug_verbosity; char buf[128], *opt, *fmt = "%-10s %s\n"; int j; reset_output_levels(); rprintf(FINFO, "Use OPT or OPT1 for level 1 output, OPT2 for level 2, etc.; OPT0 silences.\n"); rprintf(FINFO, "\n"); for (j = 0; words[j].name; j++) rprintf(FINFO, fmt, words[j].name, words[j].help); rprintf(FINFO, "\n"); snprintf(buf, sizeof buf, "Set all %s options (e.g. all%d)", words[j].help, MAX_OUT_LEVEL); rprintf(FINFO, fmt, "ALL", buf); snprintf(buf, sizeof buf, "Silence all %s options (same as all0)", words[j].help); rprintf(FINFO, fmt, "NONE", buf); rprintf(FINFO, fmt, "HELP", "Output this help message"); rprintf(FINFO, "\n"); rprintf(FINFO, "Options added at each level of verbosity:\n"); for (j = 0; j <= MAX_VERBOSITY; j++) { parse_output_words(words, levels, verbosity[j], HELP_PRIORITY); opt = make_output_option(words, levels, W_CLI|W_SRV|W_SND|W_REC); if (opt) { rprintf(FINFO, "%d) %s\n", j, strchr(opt, '=')+1); free(opt); } reset_output_levels(); } } /* The --verbose option now sets info+debug flags. */ static void set_output_verbosity(int level, uchar priority) { int j; if (level > MAX_VERBOSITY) level = MAX_VERBOSITY; for (j = 0; j <= level; j++) { parse_output_words(info_words, info_levels, info_verbosity[j], priority); parse_output_words(debug_words, debug_levels, debug_verbosity[j], priority); } } /* Limit the info+debug flag levels given a verbose-option level limit. */ void limit_output_verbosity(int level) { short info_limits[COUNT_INFO], debug_limits[COUNT_DEBUG]; int j; if (level > MAX_VERBOSITY) return; memset(info_limits, 0, sizeof info_limits); memset(debug_limits, 0, sizeof debug_limits); /* Compute the level limits in the above arrays. */ for (j = 0; j <= level; j++) { parse_output_words(info_words, info_limits, info_verbosity[j], LIMIT_PRIORITY); parse_output_words(debug_words, debug_limits, debug_verbosity[j], LIMIT_PRIORITY); } for (j = 0; j < COUNT_INFO; j++) { if (info_levels[j] > info_limits[j]) info_levels[j] = info_limits[j]; } for (j = 0; j < COUNT_DEBUG; j++) { if (debug_levels[j] > debug_limits[j]) debug_levels[j] = debug_limits[j]; } } void reset_output_levels(void) { int j; memset(info_levels, 0, sizeof info_levels); memset(debug_levels, 0, sizeof debug_levels); for (j = 0; j < COUNT_INFO; j++) info_words[j].priority = DEFAULT_PRIORITY; for (j = 0; j < COUNT_DEBUG; j++) debug_words[j].priority = DEFAULT_PRIORITY; } void negate_output_levels(void) { int j; for (j = 0; j < COUNT_INFO; j++) info_levels[j] *= -1; for (j = 0; j < COUNT_DEBUG; j++) debug_levels[j] *= -1; } enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP, OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD, OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE, OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE, OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR, OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS, OPT_OLD_ARGS, OPT_STOP_AFTER, OPT_STOP_AT, OPT_REFUSED_BASE = 9000}; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"help", 0, POPT_ARG_NONE, 0, OPT_HELP, 0, 0 }, {"version", 'V', POPT_ARG_NONE, 0, 'V', 0, 0}, {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, {"no-verbose", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 }, {"no-v", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 }, {"info", 0, POPT_ARG_STRING, 0, OPT_INFO, 0, 0 }, {"debug", 0, POPT_ARG_STRING, 0, OPT_DEBUG, 0, 0 }, {"stderr", 0, POPT_ARG_STRING, 0, OPT_STDERR, 0, 0 }, {"msgs2stderr", 0, POPT_ARG_VAL, &msgs2stderr, 1, 0, 0 }, {"no-msgs2stderr", 0, POPT_ARG_VAL, &msgs2stderr, 0, 0, 0 }, {"quiet", 'q', POPT_ARG_NONE, 0, 'q', 0, 0 }, {"motd", 0, POPT_ARG_VAL, &output_motd, 1, 0, 0 }, {"no-motd", 0, POPT_ARG_VAL, &output_motd, 0, 0, 0 }, {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 }, {"human-readable", 'h', POPT_ARG_NONE, 0, 'h', 0, 0}, {"no-human-readable",0, POPT_ARG_VAL, &human_readable, 0, 0, 0}, {"no-h", 0, POPT_ARG_VAL, &human_readable, 0, 0, 0}, {"dry-run", 'n', POPT_ARG_NONE, &dry_run, 0, 0, 0 }, {"archive", 'a', POPT_ARG_NONE, 0, 'a', 0, 0 }, {"recursive", 'r', POPT_ARG_VAL, &recurse, 2, 0, 0 }, {"no-recursive", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 }, {"no-r", 0, POPT_ARG_VAL, &recurse, 0, 0, 0 }, {"inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 }, {"no-inc-recursive", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 }, {"i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 1, 0, 0 }, {"no-i-r", 0, POPT_ARG_VAL, &allow_inc_recurse, 0, 0, 0 }, {"dirs", 'd', POPT_ARG_VAL, &xfer_dirs, 2, 0, 0 }, {"no-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 }, {"no-d", 0, POPT_ARG_VAL, &xfer_dirs, 0, 0, 0 }, {"old-dirs", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 }, {"old-d", 0, POPT_ARG_VAL, &xfer_dirs, 4, 0, 0 }, {"perms", 'p', POPT_ARG_VAL, &preserve_perms, 1, 0, 0 }, {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 }, {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 }, {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 }, {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 }, {"xattrs", 'X', POPT_ARG_NONE, 0, 'X', 0, 0 }, {"no-xattrs", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, {"no-X", 0, POPT_ARG_VAL, &preserve_xattrs, 0, 0, 0 }, {"times", 't', POPT_ARG_VAL, &preserve_mtimes, 1, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_mtimes, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_mtimes, 0, 0, 0 }, {"atimes", 'U', POPT_ARG_NONE, 0, 'U', 0, 0 }, {"no-atimes", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 }, {"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 }, {"open-noatime", 0, POPT_ARG_VAL, &open_noatime, 1, 0, 0 }, {"no-open-noatime", 0, POPT_ARG_VAL, &open_noatime, 0, 0, 0 }, {"crtimes", 'N', POPT_ARG_VAL, &preserve_crtimes, 1, 0, 0 }, {"no-crtimes", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 }, {"no-N", 0, POPT_ARG_VAL, &preserve_crtimes, 0, 0, 0 }, {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"omit-link-times", 'J', POPT_ARG_VAL, &omit_link_times, 1, 0, 0 }, {"no-omit-link-times",0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, {"no-J", 0, POPT_ARG_VAL, &omit_link_times, 0, 0, 0 }, {"modify-window", '@', POPT_ARG_INT, &modify_window, OPT_MODIFY_WINDOW, 0, 0 }, {"super", 0, POPT_ARG_VAL, &am_root, 2, 0, 0 }, {"no-super", 0, POPT_ARG_VAL, &am_root, 0, 0, 0 }, {"fake-super", 0, POPT_ARG_VAL, &am_root, -1, 0, 0 }, {"owner", 'o', POPT_ARG_VAL, &preserve_uid, 1, 0, 0 }, {"no-owner", 0, POPT_ARG_VAL, &preserve_uid, 0, 0, 0 }, {"no-o", 0, POPT_ARG_VAL, &preserve_uid, 0, 0, 0 }, {"group", 'g', POPT_ARG_VAL, &preserve_gid, 1, 0, 0 }, {"no-group", 0, POPT_ARG_VAL, &preserve_gid, 0, 0, 0 }, {"no-g", 0, POPT_ARG_VAL, &preserve_gid, 0, 0, 0 }, {0, 'D', POPT_ARG_NONE, 0, 'D', 0, 0 }, {"no-D", 0, POPT_ARG_NONE, 0, OPT_NO_D, 0, 0 }, {"devices", 0, POPT_ARG_VAL, &preserve_devices, 1, 0, 0 }, {"no-devices", 0, POPT_ARG_VAL, &preserve_devices, 0, 0, 0 }, {"copy-devices", 0, POPT_ARG_NONE, ©_devices, 0, 0, 0 }, {"write-devices", 0, POPT_ARG_VAL, &write_devices, 1, 0, 0 }, {"no-write-devices", 0, POPT_ARG_VAL, &write_devices, 0, 0, 0 }, {"specials", 0, POPT_ARG_VAL, &preserve_specials, 1, 0, 0 }, {"no-specials", 0, POPT_ARG_VAL, &preserve_specials, 0, 0, 0 }, {"links", 'l', POPT_ARG_VAL, &preserve_links, 1, 0, 0 }, {"no-links", 0, POPT_ARG_VAL, &preserve_links, 0, 0, 0 }, {"no-l", 0, POPT_ARG_VAL, &preserve_links, 0, 0, 0 }, {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, {"copy-unsafe-links",0, POPT_ARG_NONE, ©_unsafe_links, 0, 0, 0 }, {"safe-links", 0, POPT_ARG_NONE, &safe_symlinks, 0, 0, 0 }, {"munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 1, 0, 0 }, {"no-munge-links", 0, POPT_ARG_VAL, &munge_symlinks, 0, 0, 0 }, {"copy-dirlinks", 'k', POPT_ARG_NONE, ©_dirlinks, 0, 0, 0 }, {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, {"hard-links", 'H', POPT_ARG_NONE, 0, 'H', 0, 0 }, {"no-hard-links", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 }, {"no-H", 0, POPT_ARG_VAL, &preserve_hard_links, 0, 0, 0 }, {"relative", 'R', POPT_ARG_VAL, &relative_paths, 1, 0, 0 }, {"no-relative", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, {"no-R", 0, POPT_ARG_VAL, &relative_paths, 0, 0, 0 }, {"implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 }, {"no-implied-dirs", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, {"i-d", 0, POPT_ARG_VAL, &implied_dirs, 1, 0, 0 }, {"no-i-d", 0, POPT_ARG_VAL, &implied_dirs, 0, 0, 0 }, {"chmod", 0, POPT_ARG_STRING, 0, OPT_CHMOD, 0, 0 }, {"ignore-times", 'I', POPT_ARG_NONE, &ignore_times, 0, 0, 0 }, {"size-only", 0, POPT_ARG_NONE, &size_only, 0, 0, 0 }, {"one-file-system", 'x', POPT_ARG_NONE, 0, 'x', 0, 0 }, {"no-one-file-system",0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, {"no-x", 0, POPT_ARG_VAL, &one_file_system, 0, 0, 0 }, {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 }, {"existing", 0, POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-non-existing",0,POPT_ARG_NONE, &ignore_non_existing, 0, 0, 0 }, {"ignore-existing", 0, POPT_ARG_NONE, &ignore_existing, 0, 0, 0 }, {"max-size", 0, POPT_ARG_STRING, &max_size_arg, OPT_MAX_SIZE, 0, 0 }, {"min-size", 0, POPT_ARG_STRING, &min_size_arg, OPT_MIN_SIZE, 0, 0 }, {"max-alloc", 0, POPT_ARG_STRING, &max_alloc_arg, 0, 0, 0 }, {"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 }, {"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, {"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 }, {"preallocate", 0, POPT_ARG_NONE, &preallocate_files, 0, 0, 0}, {"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 }, {"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 }, {"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 }, {"append-verify", 0, POPT_ARG_VAL, &append_mode, 2, 0, 0 }, {"no-append", 0, POPT_ARG_VAL, &append_mode, 0, 0, 0 }, {"del", 0, POPT_ARG_NONE, &delete_during, 0, 0, 0 }, {"delete", 0, POPT_ARG_NONE, &delete_mode, 0, 0, 0 }, {"delete-before", 0, POPT_ARG_NONE, &delete_before, 0, 0, 0 }, {"delete-during", 0, POPT_ARG_VAL, &delete_during, 1, 0, 0 }, {"delete-delay", 0, POPT_ARG_VAL, &delete_during, 2, 0, 0 }, {"delete-after", 0, POPT_ARG_NONE, &delete_after, 0, 0, 0 }, {"delete-excluded", 0, POPT_ARG_NONE, &delete_excluded, 0, 0, 0 }, {"delete-missing-args",0,POPT_BIT_SET, &missing_args, 2, 0, 0 }, {"ignore-missing-args",0,POPT_BIT_SET, &missing_args, 1, 0, 0 }, {"remove-sent-files",0, POPT_ARG_VAL, &remove_source_files, 2, 0, 0 }, /* deprecated */ {"remove-source-files",0,POPT_ARG_VAL, &remove_source_files, 1, 0, 0 }, {"force", 0, POPT_ARG_VAL, &force_delete, 1, 0, 0 }, {"no-force", 0, POPT_ARG_VAL, &force_delete, 0, 0, 0 }, {"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 }, {0, 'F', POPT_ARG_NONE, 0, 'F', 0, 0 }, {"filter", 'f', POPT_ARG_STRING, 0, OPT_FILTER, 0, 0 }, {"exclude", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE, 0, 0 }, {"include", 0, POPT_ARG_STRING, 0, OPT_INCLUDE, 0, 0 }, {"exclude-from", 0, POPT_ARG_STRING, 0, OPT_EXCLUDE_FROM, 0, 0 }, {"include-from", 0, POPT_ARG_STRING, 0, OPT_INCLUDE_FROM, 0, 0 }, {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 }, {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 }, {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, {"no-W", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 }, {"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 }, {"checksum-choice", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 }, {"cc", 0, POPT_ARG_STRING, &checksum_choice, 0, 0, 0 }, {"block-size", 'B', POPT_ARG_STRING, 0, OPT_BLOCK_SIZE, 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 }, {"link-dest", 0, POPT_ARG_STRING, 0, OPT_LINK_DEST, 0, 0 }, {"fuzzy", 'y', POPT_ARG_NONE, 0, 'y', 0, 0 }, {"no-fuzzy", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 }, {"no-y", 0, POPT_ARG_VAL, &fuzzy_basis, 0, 0, 0 }, {"compress", 'z', POPT_ARG_NONE, 0, 'z', 0, 0 }, {"old-compress", 0, POPT_ARG_NONE, 0, OPT_OLD_COMPRESS, 0, 0 }, {"new-compress", 0, POPT_ARG_NONE, 0, OPT_NEW_COMPRESS, 0, 0 }, {"no-compress", 0, POPT_ARG_NONE, 0, OPT_NO_COMPRESS, 0, 0 }, {"no-z", 0, POPT_ARG_NONE, 0, OPT_NO_COMPRESS, 0, 0 }, {"compress-choice", 0, POPT_ARG_STRING, &compress_choice, 0, 0, 0 }, {"zc", 0, POPT_ARG_STRING, &compress_choice, 0, 0, 0 }, {"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 }, {"compress-level", 0, POPT_ARG_INT, &do_compression_level, 0, 0, 0 }, {"zl", 0, POPT_ARG_INT, &do_compression_level, 0, 0, 0 }, {0, 'P', POPT_ARG_NONE, 0, 'P', 0, 0 }, {"progress", 0, POPT_ARG_VAL, &do_progress, 1, 0, 0 }, {"no-progress", 0, POPT_ARG_VAL, &do_progress, 0, 0, 0 }, {"partial", 0, POPT_ARG_VAL, &keep_partial, 1, 0, 0 }, {"no-partial", 0, POPT_ARG_VAL, &keep_partial, 0, 0, 0 }, {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, {"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 }, {"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 }, {"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 }, {"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, {"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 }, {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 }, {"out-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, {"log-format", 0, POPT_ARG_STRING, &stdout_format, 0, 0, 0 }, /* DEPRECATED */ {"itemize-changes", 'i', POPT_ARG_NONE, 0, 'i', 0, 0 }, {"no-itemize-changes",0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"no-i", 0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"bwlimit", 0, POPT_ARG_STRING, &bwlimit_arg, OPT_BWLIMIT, 0, 0 }, {"no-bwlimit", 0, POPT_ARG_VAL, &bwlimit, 0, 0, 0 }, {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 }, {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 }, {"backup-dir", 0, POPT_ARG_STRING, &backup_dir, 0, 0, 0 }, {"suffix", 0, POPT_ARG_STRING, &backup_suffix, 0, 0, 0 }, {"list-only", 0, POPT_ARG_VAL, &list_only, 2, 0, 0 }, {"read-batch", 0, POPT_ARG_STRING, &batch_name, OPT_READ_BATCH, 0, 0 }, {"write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_WRITE_BATCH, 0, 0 }, {"only-write-batch", 0, POPT_ARG_STRING, &batch_name, OPT_ONLY_WRITE_BATCH, 0, 0 }, {"files-from", 0, POPT_ARG_STRING, &files_from, 0, 0, 0 }, {"from0", '0', POPT_ARG_VAL, &eol_nulls, 1, 0, 0}, {"no-from0", 0, POPT_ARG_VAL, &eol_nulls, 0, 0, 0}, {"old-args", 0, POPT_ARG_NONE, 0, OPT_OLD_ARGS, 0, 0}, {"no-old-args", 0, POPT_ARG_VAL, &old_style_args, 0, 0, 0}, {"secluded-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0}, {"no-secluded-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, {"protect-args", 0, POPT_ARG_VAL, &protect_args, 1, 0, 0}, {"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, {"trust-sender", 0, POPT_ARG_VAL, &trust_sender, 1, 0, 0}, {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 }, {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 }, {"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 }, {"groupmap", 0, POPT_ARG_STRING, 0, OPT_GROUPMAP, 0, 0 }, {"chown", 0, POPT_ARG_STRING, 0, OPT_CHOWN, 0, 0 }, {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 }, {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 }, {"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 }, {"no-contimeout", 0, POPT_ARG_VAL, &connect_timeout, 0, 0, 0 }, {"fsync", 0, POPT_ARG_NONE, &do_fsync, 0, 0, 0 }, {"stop-after", 0, POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 }, {"time-limit", 0, POPT_ARG_STRING, 0, OPT_STOP_AFTER, 0, 0 }, /* earlier stop-after name */ {"stop-at", 0, POPT_ARG_STRING, 0, OPT_STOP_AT, 0, 0 }, {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 }, {"rsync-path", 0, POPT_ARG_STRING, &rsync_path, 0, 0, 0 }, {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 }, {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 }, {"no-iconv", 0, POPT_ARG_NONE, 0, OPT_NO_ICONV, 0, 0 }, {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 }, {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 }, {"8-bit-output", '8', POPT_ARG_VAL, &allow_8bit_chars, 1, 0, 0 }, {"no-8-bit-output", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 }, {"no-8", 0, POPT_ARG_VAL, &allow_8bit_chars, 0, 0, 0 }, {"mkpath", 0, POPT_ARG_VAL, &mkpath_dest_arg, 1, 0, 0 }, {"no-mkpath", 0, POPT_ARG_VAL, &mkpath_dest_arg, 0, 0, 0 }, {"qsort", 0, POPT_ARG_NONE, &use_qsort, 0, 0, 0 }, {"copy-as", 0, POPT_ARG_STRING, ©_as, 0, 0, 0 }, {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, {"sockopts", 0, POPT_ARG_STRING, &sockopts, 0, 0, 0 }, {"password-file", 0, POPT_ARG_STRING, &password_file, 0, 0, 0 }, {"early-input", 0, POPT_ARG_STRING, &early_input_file, 0, 0, 0 }, {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, {"outbuf", 0, POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 }, {"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 }, {"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 }, {"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 }, /* All the following options switch us into daemon-mode option-parsing. */ {"config", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 }, {"daemon", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, {"dparam", 0, POPT_ARG_STRING, 0, OPT_DAEMON, 0, 0 }, {"detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, {"no-detach", 0, POPT_ARG_NONE, 0, OPT_DAEMON, 0, 0 }, {0,0,0,0, 0, 0, 0} }; static struct poptOption long_daemon_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"address", 0, POPT_ARG_STRING, &bind_address, 0, 0, 0 }, {"bwlimit", 0, POPT_ARG_INT, &daemon_bwlimit, 0, 0, 0 }, {"config", 0, POPT_ARG_STRING, &config_file, 0, 0, 0 }, {"daemon", 0, POPT_ARG_NONE, &daemon_opt, 0, 0, 0 }, {"dparam", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 }, {"ipv4", '4', POPT_ARG_VAL, &default_af_hint, AF_INET, 0, 0 }, {"ipv6", '6', POPT_ARG_VAL, &default_af_hint, AF_INET6, 0, 0 }, {"detach", 0, POPT_ARG_VAL, &no_detach, 0, 0, 0 }, {"no-detach", 0, POPT_ARG_VAL, &no_detach, 1, 0, 0 }, {"log-file", 0, POPT_ARG_STRING, &logfile_name, 0, 0, 0 }, {"log-file-format", 0, POPT_ARG_STRING, &logfile_format, 0, 0, 0 }, {"port", 0, POPT_ARG_INT, &rsync_port, 0, 0, 0 }, {"sockopts", 0, POPT_ARG_STRING, &sockopts, 0, 0, 0 }, {"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 }, {"server", 0, POPT_ARG_NONE, &am_server, 0, 0, 0 }, {"temp-dir", 'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 }, {"verbose", 'v', POPT_ARG_NONE, 0, 'v', 0, 0 }, {"no-verbose", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 }, {"no-v", 0, POPT_ARG_VAL, &verbose, 0, 0, 0 }, {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 }, {0,0,0,0, 0, 0, 0} }; static char err_buf[200]; /** * Store the option error message, if any, so that we can log the * connection attempt (which requires parsing the options), and then * show the error later on. **/ void option_error(void) { if (!err_buf[0]) { strlcpy(err_buf, "Error parsing options: option may " "be supported on client but not on server?\n", sizeof err_buf); } rprintf(FERROR, RSYNC_NAME ": %s", err_buf); io_flush(MSG_FLUSH); msleep(20); } static void parse_one_refuse_match(int negated, const char *ref, const struct poptOption *list_end) { struct poptOption *op; char shortName[2]; int is_wild = strpbrk(ref, "*?[") != NULL; int found_match = 0; shortName[1] = '\0'; if (strcmp("a", ref) == 0 || strcmp("archive", ref) == 0) { ref = "[ardlptgoD]"; is_wild = 1; } for (op = long_options; op != list_end; op++) { *shortName = op->shortName; if ((op->longName && wildmatch(ref, op->longName)) || (*shortName && wildmatch(ref, shortName))) { if (op->descrip[1] == '*') op->descrip = negated ? "a*" : "r*"; else if (!is_wild) op->descrip = negated ? "a=" : "r="; found_match = 1; if (!is_wild) break; } } if (!found_match) rprintf(FLOG, "No match for refuse-options string \"%s\"\n", ref); } /** * Tweak the option table to disable all options that the rsyncd.conf * file has told us to refuse. **/ static void set_refuse_options(void) { struct poptOption *op, *list_end = NULL; char *cp, *ref = lp_refuse_options(module_id); int negated; if (!ref) ref = ""; if (!am_daemon) ref = ""; /* We abuse the descrip field in poptOption to make it easy to flag which options * are refused (since we don't use it otherwise). Start by marking all options * as "a"ccepted with a few options also marked as non-wild. */ for (op = long_options; ; op++) { const char *longName = op->longName ? op->longName : ""; if (!op->longName && !op->shortName) { list_end = op; break; } if (!am_daemon || op->shortName == 'e' /* Required for compatibility flags */ || op->shortName == '0' /* --from0 just modifies --files-from, so refuse that instead (or not) */ || op->shortName == 's' /* --secluded-args is always OK */ || op->shortName == 'n' /* --dry-run is always OK */ || strcmp("iconv", longName) == 0 || strcmp("no-iconv", longName) == 0 || strcmp("checksum-seed", longName) == 0 || strcmp("copy-devices", longName) == 0 /* disable wild-match (it gets refused below) */ || strcmp("write-devices", longName) == 0 /* disable wild-match (it gets refused below) */ || strcmp("log-format", longName) == 0 /* aka out-format (NOT log-file-format) */ || strcmp("sender", longName) == 0 || strcmp("server", longName) == 0) op->descrip = "a="; /* exact-match only */ else op->descrip = "a*"; /* wild-card-able */ } assert(list_end != NULL); if (am_daemon) { /* Refused by default, but can be accepted via a negated exact match. */ parse_one_refuse_match(0, "copy-devices", list_end); parse_one_refuse_match(0, "write-devices", list_end); } while (1) { while (*ref == ' ') ref++; if (!*ref) break; if ((cp = strchr(ref, ' ')) != NULL) *cp = '\0'; negated = *ref == '!'; if (negated && ref[1]) ref++; parse_one_refuse_match(negated, ref, list_end); if (!cp) break; *cp = ' '; ref = cp + 1; } if (am_daemon) { #ifdef ICONV_OPTION if (!*lp_charset(module_id)) parse_one_refuse_match(0, "iconv", list_end); #endif parse_one_refuse_match(0, "log-file*", list_end); } #ifndef SUPPORT_ATIMES parse_one_refuse_match(0, "atimes", list_end); #endif #ifndef SUPPORT_HARD_LINKS parse_one_refuse_match(0, "link-dest", list_end); #endif #ifndef HAVE_MKTIME parse_one_refuse_match(0, "stop-at", list_end); #endif #ifndef ICONV_OPTION parse_one_refuse_match(0, "iconv", list_end); #endif #ifndef HAVE_SETVBUF parse_one_refuse_match(0, "outbuf", list_end); #endif #ifndef SUPPORT_CRTIMES parse_one_refuse_match(0, "crtimes", list_end); #endif /* Now we use the descrip values to actually mark the options for refusal. */ for (op = long_options; op != list_end; op++) { int refused = op->descrip[0] == 'r'; op->descrip = NULL; if (!refused) continue; if (op->argInfo == POPT_ARG_VAL) op->argInfo = POPT_ARG_NONE; op->val = (op - long_options) + OPT_REFUSED_BASE; /* The following flags are set to let us easily check an implied option later in the code. */ switch (op->shortName) { case 'r': case 'd': case 'l': case 'p': case 't': case 'g': case 'o': case 'D': refused_archive_part = op->val; break; case 'z': refused_compress = op->val; break; case '\0': if (strcmp("delete", op->longName) == 0) refused_delete = op->val; else if (strcmp("delete-before", op->longName) == 0) refused_delete_before = op->val; else if (strcmp("delete-during", op->longName) == 0) refused_delete_during = op->val; else if (strcmp("partial", op->longName) == 0) refused_partial = op->val; else if (strcmp("progress", op->longName) == 0) refused_progress = op->val; else if (strcmp("inplace", op->longName) == 0) refused_inplace = op->val; else if (strcmp("no-iconv", op->longName) == 0) refused_no_iconv = op->val; break; } } } static int count_args(const char **argv) { int i = 0; if (argv) { while (argv[i] != NULL) i++; } return i; } /* If the size_arg is an invalid string or the value is < min_value, an error * is put into err_buf & the return is -1. Note that this parser does NOT * support negative numbers, so a min_value < 0 doesn't make any sense. */ static ssize_t parse_size_arg(const char *size_arg, char def_suf, const char *opt_name, ssize_t min_value, ssize_t max_value, BOOL unlimited_0) { int reps, mult, len; const char *arg, *err = "invalid", *min_max = NULL; ssize_t limit = -1, size = 1; for (arg = size_arg; isDigit(arg); arg++) {} if (*arg == '.' || *arg == get_decimal_point()) /* backward compatibility: always allow '.' */ for (arg++; isDigit(arg); arg++) {} switch (*arg && *arg != '+' && *arg != '-' ? *arg++ : def_suf) { case 'b': case 'B': reps = 0; break; case 'k': case 'K': reps = 1; break; case 'm': case 'M': reps = 2; break; case 'g': case 'G': reps = 3; break; case 't': case 'T': reps = 4; break; case 'p': case 'P': reps = 5; break; default: goto failure; } if (*arg == 'b' || *arg == 'B') mult = 1000, arg++; else if (!*arg || *arg == '+' || *arg == '-') mult = 1024; else if (strncasecmp(arg, "ib", 2) == 0) mult = 1024, arg += 2; else goto failure; while (reps--) size *= mult; size *= atof(size_arg); if ((*arg == '+' || *arg == '-') && arg[1] == '1' && arg != size_arg) size += atoi(arg), arg += 2; if (*arg) goto failure; if (size < 0 || (max_value >= 0 && size > max_value)) { err = "too large"; min_max = "max"; limit = max_value; goto failure; } if (size < min_value && (!unlimited_0 || size != 0)) { err = "too small"; min_max = "min"; limit = min_value; goto failure; } return size; failure: len = snprintf(err_buf, sizeof err_buf - 1, "--%s=%s is %s", opt_name, size_arg, err); if (min_max && limit >= 0 && len < (int)sizeof err_buf - 10) { len += snprintf(err_buf + len, sizeof err_buf - len - 1, " (%s: %s%s)", min_max, do_big_num(limit, 3, NULL), unlimited_0 && min_max[1] == 'i' ? " or 0 for unlimited" : ""); } err_buf[len] = '\n'; err_buf[len+1] = '\0'; return -1; } #ifdef HAVE_MKTIME /* Allow the user to specify a time in the format yyyy-mm-ddThh:mm while * also allowing abbreviated data. For instance, if the time is omitted, * it defaults to midnight. If the date is omitted, it defaults to the * next possible date in the future with the specified time. Even the * year or year-month can be omitted, again defaulting to the next date * in the future that matches the specified information. A 2-digit year * is also OK, as is using '/' instead of '-'. */ static time_t parse_time(const char *arg) { const char *cp; time_t val, now = time(NULL); struct tm t, *today = localtime(&now); int in_date, old_mday, n; memset(&t, 0, sizeof t); t.tm_year = t.tm_mon = t.tm_mday = -1; t.tm_hour = t.tm_min = t.tm_isdst = -1; cp = arg; if (*cp == 'T' || *cp == 't' || *cp == ':') { in_date = *cp == ':' ? 0 : -1; cp++; } else in_date = 1; for ( ; ; cp++) { if (!isDigit(cp)) return (time_t)-1; n = 0; do { n = n * 10 + *cp++ - '0'; } while (isDigit(cp)); if (*cp == ':') in_date = 0; if (in_date > 0) { if (t.tm_year != -1) return (time_t)-1; t.tm_year = t.tm_mon; t.tm_mon = t.tm_mday; t.tm_mday = n; if (!*cp) break; if (*cp == 'T' || *cp == 't') { if (!cp[1]) break; in_date = -1; } else if (*cp != '-' && *cp != '/') return (time_t)-1; continue; } if (t.tm_hour != -1) return (time_t)-1; t.tm_hour = t.tm_min; t.tm_min = n; if (!*cp) { if (in_date < 0) return (time_t)-1; break; } if (*cp != ':') return (time_t)-1; in_date = 0; } in_date = 0; if (t.tm_year < 0) { t.tm_year = today->tm_year; in_date = 1; } else if (t.tm_year < 100) { while (t.tm_year < today->tm_year) t.tm_year += 100; } else t.tm_year -= 1900; if (t.tm_mon < 0) { t.tm_mon = today->tm_mon; in_date = 2; } else t.tm_mon--; if (t.tm_mday < 0) { t.tm_mday = today->tm_mday; in_date = 3; } n = 0; if (t.tm_min < 0) { t.tm_hour = t.tm_min = 0; } else if (t.tm_hour < 0) { if (in_date != 3) return (time_t)-1; in_date = 0; t.tm_hour = today->tm_hour; n = 60*60; } /* Note that mktime() might change a too-large tm_mday into the start of * the following month which we need to undo in the following code! */ old_mday = t.tm_mday; if (t.tm_hour > 23 || t.tm_min > 59 || t.tm_mon < 0 || t.tm_mon >= 12 || t.tm_mday < 1 || t.tm_mday > 31 || (val = mktime(&t)) == (time_t)-1) return (time_t)-1; while (in_date && (val <= now || t.tm_mday < old_mday)) { switch (in_date) { case 3: old_mday = ++t.tm_mday; break; case 2: if (t.tm_mday < old_mday) t.tm_mday = old_mday; /* The month already got bumped forward */ else if (++t.tm_mon == 12) { t.tm_mon = 0; t.tm_year++; } break; case 1: if (t.tm_mday < old_mday) { /* mon==1 mday==29 got bumped to mon==2 */ if (t.tm_mon != 2 || old_mday != 29) return (time_t)-1; t.tm_mon = 1; t.tm_mday = 29; } t.tm_year++; break; } if ((val = mktime(&t)) == (time_t)-1) { /* This code shouldn't be needed, as mktime() should auto-round to the next month. */ if (in_date != 3 || t.tm_mday <= 28) return (time_t)-1; t.tm_mday = old_mday = 1; in_date = 2; } } if (n) { while (val <= now) val += n; } return val; } #endif static void create_refuse_error(int which) { const char *msg; if (am_daemon) msg = "The server is configured to refuse"; else if (am_server) msg = "The server does not support"; else msg = "This rsync does not support"; /* The "which" value is the index + OPT_REFUSED_BASE. */ struct poptOption *op = &long_options[which - OPT_REFUSED_BASE]; int n = snprintf(err_buf, sizeof err_buf, "%s --%s\n", msg, op->longName) - 1; if (op->shortName) snprintf(err_buf + n, sizeof err_buf - n, " (-%c)\n", op->shortName); } /* This is used to make sure that --daemon & --server cannot be aliased to * something else. These options have always disabled popt aliases for the * parsing of a daemon or server command-line, but we have to make sure that * these options cannot vanish so that the alias disabling can take effect. */ static void popt_unalias(poptContext con, const char *opt) { struct poptAlias unalias; memset(&unalias, 0, sizeof unalias); unalias.longName = opt + 2; /* point past the leading "--" */ unalias.argc = 1; unalias.argv = new_array0(const char*, 2); unalias.argv[0] = strdup(opt); poptAddAlias(con, unalias, 0); } char *alt_dest_opt(int type) { if (!type) type = alt_dest_type; switch (type) { case COMPARE_DEST: return "--compare-dest"; case COPY_DEST: return "--copy-dest"; case LINK_DEST: return "--link-dest"; default: NOISY_DEATH("Unknown alt_dest_opt type"); } } /** * Process command line arguments. Called on both local and remote. * * @retval 1 if all options are OK; with globals set to appropriate * values * * @retval 0 on error, with err_buf containing an explanation **/ int parse_arguments(int *argc_p, const char ***argv_p) { static poptContext pc; const char *arg, **argv = *argv_p; int argc = *argc_p; int opt, want_dest_type; int orig_protect_args = protect_args; if (argc == 0) { strlcpy(err_buf, "argc is zero!\n", sizeof err_buf); return 0; } set_refuse_options(); #ifdef ICONV_OPTION if (!am_daemon && protect_args <= 0 && (arg = getenv("RSYNC_ICONV")) != NULL && *arg) iconv_opt = strdup(arg); #endif /* TODO: Call poptReadDefaultConfig; handle errors. */ /* The context leaks in case of an error, but if there's a * problem we always exit anyhow. */ if (pc) poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); if (!am_server) { poptReadDefaultConfig(pc, 0); popt_unalias(pc, "--daemon"); popt_unalias(pc, "--server"); } while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; * only special cases are returned and listed here. */ switch (opt) { case 'V': version_opt_cnt++; break; case OPT_SERVER: if (!am_server) { /* Disable popt aliases on the server side and * then start parsing the options again. */ poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); am_server = 1; } #ifdef ICONV_OPTION iconv_opt = NULL; #endif break; case OPT_SENDER: if (!am_server) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } am_sender = 1; break; case OPT_DAEMON: if (am_daemon) { strlcpy(err_buf, "Attempt to hack rsync thwarted!\n", sizeof err_buf); return 0; } #ifdef ICONV_OPTION iconv_opt = NULL; #endif protect_args = 0; poptFreeContext(pc); pc = poptGetContext(RSYNC_NAME, argc, argv, long_daemon_options, 0); while ((opt = poptGetNextOpt(pc)) != -1) { char **cpp; switch (opt) { case 'h': daemon_usage(FINFO); exit_cleanup(0); case 'M': arg = poptGetOptArg(pc); if (!strchr(arg, '=')) { rprintf(FERROR, "--dparam value is missing an '=': %s\n", arg); goto daemon_error; } cpp = EXPAND_ITEM_LIST(&dparam_list, char *, 4); *cpp = strdup(arg); break; case 'v': verbose++; break; default: rprintf(FERROR, "rsync: %s: %s (in daemon mode)\n", poptBadOption(pc, POPT_BADOPTION_NOALIAS), poptStrerror(opt)); goto daemon_error; } } if (dparam_list.count && !set_dparams(1)) exit_cleanup(RERR_SYNTAX); if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) { snprintf(err_buf, sizeof err_buf, "the --temp-dir path is WAY too long.\n"); return 0; } if (!daemon_opt) { rprintf(FERROR, "Daemon option(s) used without --daemon.\n"); daemon_error: rprintf(FERROR, "(Type \"rsync --daemon --help\" for assistance with daemon mode.)\n"); exit_cleanup(RERR_SYNTAX); } *argv_p = argv = poptGetArgs(pc); *argc_p = argc = count_args(argv); am_starting_up = 0; daemon_opt = 0; am_daemon = 1; return 1; case OPT_MODIFY_WINDOW: /* The value has already been set by popt, but * we need to remember that we're using a * non-default setting. */ modify_window_set = 1; break; case OPT_FILTER: parse_filter_str(&filter_list, poptGetOptArg(pc), rule_template(0), 0); break; case OPT_EXCLUDE: parse_filter_str(&filter_list, poptGetOptArg(pc), rule_template(0), XFLG_OLD_PREFIXES); break; case OPT_INCLUDE: parse_filter_str(&filter_list, poptGetOptArg(pc), rule_template(FILTRULE_INCLUDE), XFLG_OLD_PREFIXES); break; case OPT_EXCLUDE_FROM: case OPT_INCLUDE_FROM: arg = poptGetOptArg(pc); if (sanitize_paths) arg = sanitize_path(NULL, arg, NULL, 0, SP_DEFAULT); if (daemon_filter_list.head) { int rej; char *cp = strdup(arg); if (!*cp) rej = 1; else { char *dir = cp + (*cp == '/' ? module_dirlen : 0); clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); rej = check_filter(&daemon_filter_list, FLOG, dir, 0) < 0; } free(cp); if (rej) goto options_rejected; } parse_filter_file(&filter_list, arg, rule_template(opt == OPT_INCLUDE_FROM ? FILTRULE_INCLUDE : 0), XFLG_FATAL_ERRORS | XFLG_OLD_PREFIXES); break; case 'a': if (refused_archive_part) { create_refuse_error(refused_archive_part); return 0; } if (!recurse) /* preserve recurse == 2 */ recurse = 1; #ifdef SUPPORT_LINKS preserve_links = 1; #endif preserve_perms = 1; preserve_mtimes = 1; preserve_gid = 1; preserve_uid = 1; preserve_devices = 1; preserve_specials = 1; break; case 'D': preserve_devices = preserve_specials = 1; break; case OPT_NO_D: preserve_devices = preserve_specials = 0; break; case 'h': human_readable++; break; case 'H': preserve_hard_links++; break; case 'i': itemize_changes++; break; case 'U': if (++preserve_atimes > 1) open_noatime = 1; break; case 'v': verbose++; break; case 'y': fuzzy_basis++; break; case 'q': quiet++; break; case 'x': one_file_system++; break; case 'F': switch (++F_option_cnt) { case 1: parse_filter_str(&filter_list,": /.rsync-filter",rule_template(0),0); break; case 2: parse_filter_str(&filter_list,"- .rsync-filter",rule_template(0),0); break; } break; case 'P': if (refused_partial || refused_progress) { create_refuse_error(refused_partial ? refused_partial : refused_progress); return 0; } do_progress = 1; keep_partial = 1; break; case 'z': do_compression++; break; case OPT_OLD_COMPRESS: compress_choice = "zlib"; break; case OPT_NEW_COMPRESS: compress_choice = "zlibx"; break; case OPT_NO_COMPRESS: do_compression = 0; compress_choice = NULL; break; case OPT_OLD_ARGS: if (old_style_args <= 0) old_style_args = 1; else old_style_args++; break; case 'M': arg = poptGetOptArg(pc); if (*arg != '-') { snprintf(err_buf, sizeof err_buf, "Remote option must start with a dash: %s\n", arg); return 0; } if (remote_option_cnt+2 >= remote_option_alloc) { remote_option_alloc += 16; remote_options = realloc_array(remote_options, const char *, remote_option_alloc); 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; break; case OPT_ONLY_WRITE_BATCH: /* batch_name is already set */ write_batch = -1; break; case OPT_READ_BATCH: /* batch_name is already set */ read_batch = 1; break; case OPT_NO_ICONV: #ifdef ICONV_OPTION iconv_opt = NULL; #endif break; case OPT_BLOCK_SIZE: { /* We may not know the real protocol_version at this point if this is the client * option parsing, but we still want to check it so that the client can specify * a --protocol=29 option with a larger block size. */ int max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE; ssize_t size; arg = poptGetOptArg(pc); if ((size = parse_size_arg(arg, 'b', "block-size", 0, max_blength, False)) < 0) return 0; block_size = (int32)size; break; } case OPT_MAX_SIZE: if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0) return 0; max_size_arg = strdup(do_big_num(max_size, 0, NULL)); break; case OPT_MIN_SIZE: if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0) return 0; min_size_arg = strdup(do_big_num(min_size, 0, NULL)); break; case OPT_BWLIMIT: { ssize_t size = parse_size_arg(bwlimit_arg, 'K', "bwlimit", 512, -1, True); if (size < 0) return 0; bwlimit_arg = strdup(do_big_num(size, 0, NULL)); bwlimit = (size + 512) / 1024; break; } case OPT_APPEND: if (am_server) append_mode++; else append_mode = 1; break; case OPT_LINK_DEST: want_dest_type = LINK_DEST; goto set_dest_dir; case OPT_COPY_DEST: want_dest_type = COPY_DEST; goto set_dest_dir; case OPT_COMPARE_DEST: want_dest_type = COMPARE_DEST; set_dest_dir: if (alt_dest_type && alt_dest_type != want_dest_type) { snprintf(err_buf, sizeof err_buf, "ERROR: the %s option conflicts with the %s option\n", alt_dest_opt(want_dest_type), alt_dest_opt(0)); return 0; } alt_dest_type = want_dest_type; if (basis_dir_cnt >= MAX_BASIS_DIRS) { snprintf(err_buf, sizeof err_buf, "ERROR: at most %d %s args may be specified\n", MAX_BASIS_DIRS, alt_dest_opt(0)); return 0; } /* We defer sanitizing this arg until we know what * our destination directory is going to be. */ basis_dir[basis_dir_cnt++] = (char *)poptGetOptArg(pc); break; case OPT_CHMOD: arg = poptGetOptArg(pc); if (!parse_chmod(arg, &chmod_modes)) { snprintf(err_buf, sizeof err_buf, "Invalid argument passed to --chmod (%s)\n", arg); return 0; } break; case OPT_INFO: arg = poptGetOptArg(pc); parse_output_words(info_words, info_levels, arg, USER_PRIORITY); break; case OPT_DEBUG: arg = poptGetOptArg(pc); parse_output_words(debug_words, debug_levels, arg, USER_PRIORITY); break; case OPT_USERMAP: if (usermap) { if (usermap_via_chown) { snprintf(err_buf, sizeof err_buf, "--usermap conflicts with prior --chown.\n"); return 0; } snprintf(err_buf, sizeof err_buf, "You can only specify --usermap once.\n"); return 0; } usermap = (char *)poptGetOptArg(pc); usermap_via_chown = False; preserve_uid = 1; break; case OPT_GROUPMAP: if (groupmap) { if (groupmap_via_chown) { snprintf(err_buf, sizeof err_buf, "--groupmap conflicts with prior --chown.\n"); return 0; } snprintf(err_buf, sizeof err_buf, "You can only specify --groupmap once.\n"); return 0; } groupmap = (char *)poptGetOptArg(pc); groupmap_via_chown = False; preserve_gid = 1; break; case OPT_CHOWN: { const char *chown = poptGetOptArg(pc); int len; if ((arg = strchr(chown, ':')) != NULL) len = arg++ - chown; else len = strlen(chown); if (len) { if (usermap) { if (!usermap_via_chown) { snprintf(err_buf, sizeof err_buf, "--chown conflicts with prior --usermap.\n"); return 0; } snprintf(err_buf, sizeof err_buf, "You can only specify a user-affecting --chown once.\n"); return 0; } if (asprintf(&usermap, "*:%.*s", len, chown) < 0) out_of_memory("parse_arguments"); usermap_via_chown = True; preserve_uid = 1; } if (arg && *arg) { if (groupmap) { if (!groupmap_via_chown) { snprintf(err_buf, sizeof err_buf, "--chown conflicts with prior --groupmap.\n"); return 0; } snprintf(err_buf, sizeof err_buf, "You can only specify a group-affecting --chown once.\n"); return 0; } if (asprintf(&groupmap, "*:%s", arg) < 0) out_of_memory("parse_arguments"); groupmap_via_chown = True; preserve_gid = 1; } break; } case OPT_HELP: usage(FINFO); exit_cleanup(0); case 'A': #ifdef SUPPORT_ACLS preserve_acls = 1; preserve_perms = 1; break; #else /* FIXME: this should probably be ignored with a * warning and then countermeasures taken to * restrict group and other access in the presence * of any more restrictive ACLs, but this is safe * for now */ snprintf(err_buf,sizeof(err_buf), "ACLs are not supported on this %s\n", am_server ? "server" : "client"); return 0; #endif case 'X': #ifdef SUPPORT_XATTRS preserve_xattrs++; break; #else snprintf(err_buf,sizeof(err_buf), "extended attributes are not supported on this %s\n", am_server ? "server" : "client"); return 0; #endif case OPT_STOP_AFTER: { long val; arg = poptGetOptArg(pc); stop_at_utime = time(NULL); if ((val = atol(arg) * 60) <= 0 || LONG_MAX - val < stop_at_utime || (long)(time_t)val != val) { snprintf(err_buf, sizeof err_buf, "invalid --stop-after value: %s\n", arg); return 0; } stop_at_utime += val; break; } #ifdef HAVE_MKTIME case OPT_STOP_AT: arg = poptGetOptArg(pc); if ((stop_at_utime = parse_time(arg)) == (time_t)-1) { snprintf(err_buf, sizeof err_buf, "invalid --stop-at format: %s\n", arg); return 0; } if (stop_at_utime <= time(NULL)) { snprintf(err_buf, sizeof err_buf, "--stop-at time is not in the future: %s\n", arg); return 0; } break; #endif case OPT_STDERR: { int len; arg = poptGetOptArg(pc); len = strlen(arg); if (len && strncmp("errors", arg, len) == 0) msgs2stderr = 2; else if (len && strncmp("all", arg, len) == 0) msgs2stderr = 1; else if (len && strncmp("client", arg, len) == 0) msgs2stderr = 0; else { snprintf(err_buf, sizeof err_buf, "--stderr mode \"%s\" is not one of errors, all, or client\n", arg); return 0; } saw_stderr_opt = 1; break; } default: /* A large opt value means that set_refuse_options() * turned this option off. */ if (opt >= OPT_REFUSED_BASE) { create_refuse_error(opt); return 0; } snprintf(err_buf, sizeof err_buf, "%s%s: %s\n", am_server ? "on remote machine: " : "", poptBadOption(pc, POPT_BADOPTION_NOALIAS), poptStrerror(opt)); return 0; } } if (msgs2stderr != 2) saw_stderr_opt = 1; if (version_opt_cnt) { print_rsync_version(version_opt_cnt > 1 && !am_server ? FNONE : FINFO); exit_cleanup(0); } if (!max_alloc_arg) { max_alloc_arg = getenv("RSYNC_MAX_ALLOC"); if (max_alloc_arg && !*max_alloc_arg) max_alloc_arg = NULL; } if (max_alloc_arg) { ssize_t size = parse_size_arg(max_alloc_arg, 'B', "max-alloc", 1024*1024, -1, True); if (size < 0) return 0; max_alloc = size; } if (old_style_args < 0) { if (!am_server && protect_args <= 0 && (arg = getenv("RSYNC_OLD_ARGS")) != NULL && *arg) { protect_args = 0; old_style_args = atoi(arg); } else old_style_args = 0; } else if (old_style_args) { if (protect_args > 0) { snprintf(err_buf, sizeof err_buf, "--secluded-args conflicts with --old-args.\n"); return 0; } protect_args = 0; } if (protect_args < 0) { if (am_server) protect_args = 0; else if ((arg = getenv("RSYNC_PROTECT_ARGS")) != NULL && *arg) protect_args = atoi(arg) ? 1 : 0; else { #ifdef RSYNC_USE_SECLUDED_ARGS protect_args = 1; #else protect_args = 0; #endif } } if (checksum_choice && strcasecmp(checksum_choice, "auto") != 0 && strcasecmp(checksum_choice, "auto,auto") != 0) { /* Call this early to verify the args and figure out if we need to force * --whole-file. Note that the parse function will get called again later, * just in case an "auto" choice needs to know the protocol_version. */ parse_checksum_choice(0); } else checksum_choice = NULL; if (human_readable > 1 && argc == 2 && !am_server) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); exit_cleanup(0); } if (!compress_choice && do_compression > 1) compress_choice = "zlibx"; if (compress_choice && strcasecmp(compress_choice, "auto") != 0) parse_compress_choice(0); /* Twiddles do_compression and can possibly NULL-out compress_choice. */ else compress_choice = NULL; if (do_compression || do_compression_level != CLVL_NOT_SPECIFIED) { if (!do_compression) do_compression = CPRES_AUTO; if (do_compression && refused_compress) { create_refuse_error(refused_compress); return 0; } } #ifdef HAVE_SETVBUF if (outbuf_mode && !am_server) { int mode = *(uchar *)outbuf_mode; if (islower(mode)) mode = toupper(mode); fflush(stdout); /* Just in case... */ switch (mode) { case 'N': /* None */ case 'U': /* Unbuffered */ mode = _IONBF; break; case 'L': /* Line */ mode = _IOLBF; break; case 'B': /* Block */ case 'F': /* Full */ mode = _IOFBF; break; default: snprintf(err_buf, sizeof err_buf, "Invalid --outbuf setting -- specify N, L, or B.\n"); return 0; } setvbuf(stdout, (char *)NULL, mode, 0); } if (msgs2stderr == 1) { /* Are all messages going to stderr? */ /* Make stderr line buffered for better sharing of the stream. */ fflush(stderr); /* Just in case... */ setvbuf(stderr, (char *)NULL, _IOLBF, 0); } #endif set_output_verbosity(verbose, DEFAULT_PRIORITY); if (do_stats) { parse_output_words(info_words, info_levels, verbose > 1 ? "stats3" : "stats2", DEFAULT_PRIORITY); } #ifdef ICONV_OPTION if (iconv_opt && protect_args != 2) { if (!am_server && strcmp(iconv_opt, "-") == 0) iconv_opt = NULL; else need_unsorted_flist = 1; } if (refused_no_iconv && !iconv_opt) { create_refuse_error(refused_no_iconv); return 0; } #endif if (fuzzy_basis > 1) fuzzy_basis = basis_dir_cnt + 1; /* Don't let the client reset protect_args if it was already processed */ if (orig_protect_args == 2 && am_server) protect_args = orig_protect_args; if (protect_args == 1 && am_server) return 1; *argv_p = argv = poptGetArgs(pc); *argc_p = argc = count_args(argv); #ifndef SUPPORT_LINKS if (preserve_links && !am_sender) { snprintf(err_buf, sizeof err_buf, "symlinks are not supported on this %s\n", am_server ? "server" : "client"); return 0; } #endif #ifndef SUPPORT_HARD_LINKS if (preserve_hard_links) { snprintf(err_buf, sizeof err_buf, "hard links are not supported on this %s\n", am_server ? "server" : "client"); return 0; } #endif #ifdef SUPPORT_XATTRS if (am_root < 0 && preserve_xattrs > 1) { snprintf(err_buf, sizeof err_buf, "--fake-super conflicts with -XX\n"); return 0; } #else if (am_root < 0) { snprintf(err_buf, sizeof err_buf, "--fake-super requires an rsync with extended attributes enabled\n"); return 0; } #endif if (write_batch && read_batch) { snprintf(err_buf, sizeof err_buf, "--write-batch and --read-batch can not be used together\n"); return 0; } if (write_batch > 0 || read_batch) { if (am_server) { rprintf(FINFO, "ignoring --%s-batch option sent to server\n", write_batch ? "write" : "read"); /* We don't actually exit_cleanup(), so that we can * still service older version clients that still send * batch args to server. */ read_batch = write_batch = 0; batch_name = NULL; } else if (dry_run) write_batch = 0; } else if (write_batch < 0 && dry_run) write_batch = 0; if (read_batch && files_from) { snprintf(err_buf, sizeof err_buf, "--read-batch cannot be used with --files-from\n"); return 0; } if (read_batch && remove_source_files) { snprintf(err_buf, sizeof err_buf, "--read-batch cannot be used with --remove-%s-files\n", remove_source_files == 1 ? "source" : "sent"); return 0; } if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) { snprintf(err_buf, sizeof err_buf, "the batch-file name must be %d characters or less.\n", MAX_BATCH_NAME_LEN); return 0; } if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) { snprintf(err_buf, sizeof err_buf, "the --temp-dir path is WAY too long.\n"); return 0; } if (max_delete < 0 && max_delete != INT_MIN) { /* Negative numbers are treated as "no deletions". */ max_delete = 0; } if (files_from) { if (recurse == 1) /* preserve recurse == 2 */ recurse = 0; if (xfer_dirs < 0) xfer_dirs = 1; } if (argc < 2 && !read_batch && !am_server) list_only |= 1; if (xfer_dirs >= 4) { parse_filter_str(&filter_list, "- /*/*", rule_template(0), 0); recurse = xfer_dirs = 1; } else if (recurse) xfer_dirs = 1; else if (xfer_dirs < 0) xfer_dirs = list_only ? 1 : 0; if (relative_paths < 0) relative_paths = files_from? 1 : 0; if (!relative_paths) implied_dirs = 0; if (delete_before + !!delete_during + delete_after > 1) { snprintf(err_buf, sizeof err_buf, "You may not combine multiple --delete-WHEN options.\n"); return 0; } if (delete_before || delete_during || delete_after) delete_mode = 1; else if (delete_mode || delete_excluded) { /* Only choose now between before & during if one is refused. */ if (refused_delete_before) { if (!refused_delete_during) delete_during = 1; else { create_refuse_error(refused_delete_before); return 0; } } else if (refused_delete_during) delete_before = 1; delete_mode = 1; } if (!xfer_dirs && delete_mode) { snprintf(err_buf, sizeof err_buf, "--delete does not work without --recursive (-r) or --dirs (-d).\n"); return 0; } if (missing_args == 3) /* simplify if both options were specified */ missing_args = 2; if (refused_delete && (delete_mode || missing_args == 2)) { create_refuse_error(refused_delete); return 0; } if (remove_source_files) { /* We only want to infer this refusal of --remove-source-files * via the refusal of "delete", not any of the "delete-FOO" * options. */ if (refused_delete && am_sender) { create_refuse_error(refused_delete); return 0; } need_messages_from_generator = 1; } if (munge_symlinks && !am_daemon) { STRUCT_STAT st; char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */ strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */ if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) { rprintf(FERROR, "Symlink munging is unsafe when a %s directory exists.\n", prefix); exit_cleanup(RERR_UNSUPPORTED); } } if (sanitize_paths) { int i; for (i = argc; i-- > 0; ) argv[i] = sanitize_path(NULL, argv[i], "", 0, SP_KEEP_DOT_DIRS); if (tmpdir) tmpdir = sanitize_path(NULL, tmpdir, NULL, 0, SP_DEFAULT); if (backup_dir) backup_dir = sanitize_path(NULL, backup_dir, NULL, 0, SP_DEFAULT); } if (daemon_filter_list.head && !am_sender) { filter_rule_list *elp = &daemon_filter_list; if (tmpdir) { char *dir; if (!*tmpdir) goto options_rejected; dir = tmpdir + (*tmpdir == '/' ? module_dirlen : 0); clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(elp, FLOG, dir, 1) < 0) goto options_rejected; } if (backup_dir) { char *dir; if (!*backup_dir) goto options_rejected; dir = backup_dir + (*backup_dir == '/' ? module_dirlen : 0); clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(elp, FLOG, dir, 1) < 0) goto options_rejected; } } if (!backup_suffix) backup_suffix = backup_dir ? "" : BACKUP_SUFFIX; backup_suffix_len = strlen(backup_suffix); if (strchr(backup_suffix, '/') != NULL) { snprintf(err_buf, sizeof err_buf, "--suffix cannot contain slashes: %s\n", backup_suffix); return 0; } if (backup_dir) { size_t len; make_backups = 1; /* --backup-dir implies --backup */ while (*backup_dir == '.' && backup_dir[1] == '/') backup_dir += 2; if (*backup_dir == '.' && backup_dir[1] == '\0') backup_dir++; len = strlcpy(backup_dir_buf, backup_dir, sizeof backup_dir_buf); if (len > sizeof backup_dir_buf - 128) { snprintf(err_buf, sizeof err_buf, "the --backup-dir path is WAY too long.\n"); return 0; } backup_dir_len = (int)len; if (!backup_dir_len) { backup_dir_len = -1; backup_dir = NULL; } else if (backup_dir_buf[backup_dir_len - 1] != '/') { backup_dir_buf[backup_dir_len++] = '/'; backup_dir_buf[backup_dir_len] = '\0'; } backup_dir_remainder = sizeof backup_dir_buf - backup_dir_len; } if (backup_dir) { /* No need for a suffix or a protect rule. */ } else if (!backup_suffix_len && (!am_server || !am_sender)) { snprintf(err_buf, sizeof err_buf, "--suffix cannot be empty %s\n", backup_dir_len < 0 ? "when --backup-dir is the same as the dest dir" : "without a --backup-dir"); return 0; } else if (make_backups && delete_mode && !delete_excluded && !am_server) { snprintf(backup_dir_buf, sizeof backup_dir_buf, "P *%s", backup_suffix); parse_filter_str(&filter_list, backup_dir_buf, rule_template(0), 0); } if (make_backups && !backup_dir) omit_dir_times = -1; /* Implied, so avoid -O to sender. */ if (stdout_format) { if (am_server && log_format_has(stdout_format, 'I')) stdout_format_has_i = 2; else if (log_format_has(stdout_format, 'i')) stdout_format_has_i = itemize_changes | 1; if (!log_format_has(stdout_format, 'b') && !log_format_has(stdout_format, 'c') && !log_format_has(stdout_format, 'C')) log_before_transfer = !am_server; } else if (itemize_changes) { stdout_format = "%i %n%L"; stdout_format_has_i = itemize_changes; log_before_transfer = !am_server; } if (do_progress && !am_server) { if (!log_before_transfer && INFO_EQ(NAME, 0)) parse_output_words(info_words, info_levels, "name", DEFAULT_PRIORITY); parse_output_words(info_words, info_levels, "flist2,progress", DEFAULT_PRIORITY); } if (dry_run) do_xfers = 0; set_io_timeout(io_timeout); if (INFO_GTE(NAME, 1) && !stdout_format) { stdout_format = "%n%L"; log_before_transfer = !am_server; } if (stdout_format_has_i || log_format_has(stdout_format, 'o')) stdout_format_has_o_or_i = 1; if (logfile_name && !am_daemon) { if (!logfile_format) { logfile_format = "%i %n%L"; logfile_format_has_i = logfile_format_has_o_or_i = 1; } else { if (log_format_has(logfile_format, 'i')) logfile_format_has_i = 1; if (logfile_format_has_i || log_format_has(logfile_format, 'o')) logfile_format_has_o_or_i = 1; } log_init(0); } else if (!am_daemon) logfile_format = NULL; if (daemon_bwlimit && (!bwlimit || bwlimit > daemon_bwlimit)) bwlimit = daemon_bwlimit; if (bwlimit) { bwlimit_writemax = (size_t)bwlimit * 128; if (bwlimit_writemax < 512) bwlimit_writemax = 512; } if (append_mode) { if (whole_file > 0) { snprintf(err_buf, sizeof err_buf, "--append cannot be used with --whole-file\n"); return 0; } if (refused_inplace) { create_refuse_error(refused_inplace); return 0; } inplace = 1; } if (write_devices) { if (refused_inplace) { create_refuse_error(refused_inplace); return 0; } inplace = 1; } if (delay_updates && !partial_dir) partial_dir = tmp_partialdir; if (inplace) { #ifdef HAVE_FTRUNCATE if (partial_dir) { snprintf(err_buf, sizeof err_buf, "--%s cannot be used with --%s\n", append_mode ? "append" : "inplace", delay_updates ? "delay-updates" : "partial-dir"); return 0; } /* --inplace implies --partial for refusal purposes, but we * clear the keep_partial flag for internal logic purposes. */ if (refused_partial) { create_refuse_error(refused_partial); return 0; } keep_partial = 0; #else snprintf(err_buf, sizeof err_buf, "--%s is not supported on this %s\n", append_mode ? "append" : "inplace", am_server ? "server" : "client"); return 0; #endif } else { if (keep_partial && !partial_dir && !am_server) { if ((arg = getenv("RSYNC_PARTIAL_DIR")) != NULL && *arg) partial_dir = strdup(arg); } if (partial_dir) { if (*partial_dir) clean_fname(partial_dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (!*partial_dir || strcmp(partial_dir, ".") == 0) partial_dir = NULL; if (!partial_dir && refused_partial) { create_refuse_error(refused_partial); return 0; } keep_partial = 1; } } if (files_from) { char *h, *p; int q; if (argc > 2 || (!am_daemon && !am_server && argc == 1)) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } if (strcmp(files_from, "-") == 0) { filesfrom_fd = 0; if (am_server) filesfrom_host = ""; /* reading from socket */ } else if ((p = check_for_hostspec(files_from, &h, &q)) != 0) { if (am_server) { snprintf(err_buf, sizeof err_buf, "The --files-from sent to the server cannot specify a host.\n"); return 0; } files_from = p; filesfrom_host = h; if (strcmp(files_from, "-") == 0) { snprintf(err_buf, sizeof err_buf, "Invalid --files-from remote filename\n"); return 0; } } else { if (sanitize_paths) files_from = sanitize_path(NULL, files_from, NULL, 0, SP_DEFAULT); if (daemon_filter_list.head) { char *dir; if (!*files_from) goto options_rejected; dir = files_from + (*files_from == '/' ? module_dirlen : 0); clean_fname(dir, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(&daemon_filter_list, FLOG, dir, 0) < 0) goto options_rejected; } filesfrom_fd = open(files_from, O_RDONLY|O_BINARY); if (filesfrom_fd < 0) { snprintf(err_buf, sizeof err_buf, "failed to open files-from file %s: %s\n", files_from, strerror(errno)); return 0; } } } if (trust_sender || am_server || read_batch) trust_sender_args = trust_sender_filter = 1; else if (old_style_args || filesfrom_host != NULL) trust_sender_args = 1; am_starting_up = 0; return 1; options_rejected: snprintf(err_buf, sizeof err_buf, "Your options have been rejected by the server.\n"); return 0; } static char SPLIT_ARG_WHEN_OLD[1]; /** * Do backslash quoting of any weird chars in "arg", append the resulting * string to the end of the "opt" (which gets a "=" appended if it is not * an empty or NULL string), and return the (perhaps malloced) result. * If opt is NULL, arg is considered a filename arg that allows wildcards. * If it is "" or any other value, it is considered an option. **/ char *safe_arg(const char *opt, const char *arg) { #define SHELL_CHARS "!#$&;|<>(){}\"' \t\\" #define WILD_CHARS "*?[]" /* We don't allow remote brace expansion */ BOOL is_filename_arg = !opt; char *escapes = is_filename_arg ? SHELL_CHARS : WILD_CHARS SHELL_CHARS; BOOL escape_leading_dash = is_filename_arg && *arg == '-'; BOOL escape_leading_tilde = 0; int len1 = opt && *opt ? strlen(opt) + 1 : 0; int len2 = strlen(arg); int extras = escape_leading_dash ? 2 : 0; char *ret; if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) { const char *f; if (!trust_sender_args && *arg == '~' && ((relative_paths && !strstr(arg, "/./")) || !strchr(arg, '/'))) { extras++; escape_leading_tilde = 1; } for (f = arg; *f; f++) { if (strchr(escapes, *f)) extras++; } } if (!len1 && !extras) return (char*)arg; ret = new_array(char, len1 + len2 + extras + 1); if (len1) { memcpy(ret, opt, len1-1); ret[len1-1] = '='; } if (escape_leading_dash) { ret[len1++] = '.'; ret[len1++] = '/'; extras -= 2; } if (!extras) memcpy(ret + len1, arg, len2); else { const char *f = arg; char *t = ret + len1; if (escape_leading_tilde) *t++ = '\\'; while (*f) { if (*f == '\\') { if (!is_filename_arg || !strchr(WILD_CHARS, f[1])) *t++ = '\\'; } else if (strchr(escapes, *f)) *t++ = '\\'; *t++ = *f++; } } ret[len1+len2+extras] = '\0'; return ret; } /** * Construct a filtered list of options to pass through from the * client to the server. * * This involves setting options that will tell the server how to * behave, and also filtering out options that are processed only * locally. **/ void server_options(char **args, int *argc_p) { static char argstr[64]; int ac = *argc_p; uchar where; char *arg; int i, x; /* This should always remain first on the server's command-line. */ args[ac++] = "--server"; if (!am_sender) args[ac++] = "--sender"; x = 1; argstr[0] = '-'; if (protect_args) argstr[x++] = 's'; for (i = 0; i < verbose; i++) argstr[x++] = 'v'; if (quiet && msgs2stderr) argstr[x++] = 'q'; if (make_backups) argstr[x++] = 'b'; if (update_only) argstr[x++] = 'u'; if (!do_xfers) /* Note: NOT "dry_run"! */ argstr[x++] = 'n'; if (preserve_links) argstr[x++] = 'l'; if ((xfer_dirs >= 2 && xfer_dirs < 4) || (xfer_dirs && !recurse && (list_only || (delete_mode && am_sender)))) argstr[x++] = 'd'; if (am_sender) { if (keep_dirlinks) argstr[x++] = 'K'; if (prune_empty_dirs) argstr[x++] = 'm'; if (omit_dir_times > 0) argstr[x++] = 'O'; if (omit_link_times) argstr[x++] = 'J'; if (fuzzy_basis) { argstr[x++] = 'y'; if (fuzzy_basis > 1) argstr[x++] = 'y'; } } else { if (copy_links) argstr[x++] = 'L'; if (copy_dirlinks) argstr[x++] = 'k'; } if (whole_file > 0) argstr[x++] = 'W'; /* We don't need to send --no-whole-file, because it's the * default for remote transfers, and in any case old versions * of rsync will not understand it. */ if (preserve_hard_links) { argstr[x++] = 'H'; if (preserve_hard_links > 1) argstr[x++] = 'H'; } if (preserve_uid) argstr[x++] = 'o'; if (preserve_gid) argstr[x++] = 'g'; if (preserve_devices) /* ignore preserve_specials here */ argstr[x++] = 'D'; if (preserve_mtimes) argstr[x++] = 't'; if (preserve_atimes) { argstr[x++] = 'U'; if (preserve_atimes > 1) argstr[x++] = 'U'; } #ifdef SUPPORT_CRTIMES if (preserve_crtimes) argstr[x++] = 'N'; #endif if (preserve_perms) argstr[x++] = 'p'; else if (preserve_executability && am_sender) argstr[x++] = 'E'; #ifdef SUPPORT_ACLS if (preserve_acls) argstr[x++] = 'A'; #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { argstr[x++] = 'X'; if (preserve_xattrs > 1) argstr[x++] = 'X'; } #endif if (recurse) argstr[x++] = 'r'; if (always_checksum) argstr[x++] = 'c'; if (cvs_exclude) argstr[x++] = 'C'; if (ignore_times) argstr[x++] = 'I'; if (relative_paths) argstr[x++] = 'R'; if (one_file_system) { argstr[x++] = 'x'; if (one_file_system > 1) argstr[x++] = 'x'; } if (sparse_files) argstr[x++] = 'S'; if (do_compression == CPRES_ZLIB) argstr[x++] = 'z'; set_allow_inc_recurse(); /* This '\0'-terminates argstr and makes sure it didn't overflow. */ x += maybe_add_e_option(argstr + x, (int)sizeof argstr - x); if (x > 1) args[ac++] = argstr; #ifdef ICONV_OPTION if (iconv_opt) { char *set = strchr(iconv_opt, ','); if (set) set++; else set = iconv_opt; args[ac++] = safe_arg("--iconv", set); } #endif if (protect_args && !local_server) /* unprotected args stop here */ args[ac++] = NULL; if (list_only > 1) args[ac++] = "--list-only"; /* This makes sure that the remote rsync can handle deleting with -d * sans -r because the --no-r option was added at the same time. */ if (xfer_dirs && !recurse && delete_mode && am_sender) args[ac++] = "--no-r"; if (do_compression && do_compression_level != CLVL_NOT_SPECIFIED) { if (asprintf(&arg, "--compress-level=%d", do_compression_level) < 0) goto oom; args[ac++] = arg; } if (preserve_devices) { /* Note: sending "--devices" would not be backward-compatible. */ if (!preserve_specials) args[ac++] = "--no-specials"; /* -D is already set. */ } else if (preserve_specials) args[ac++] = "--specials"; /* The server side doesn't use our log-format, but in certain * circumstances they need to know a little about the option. */ if (stdout_format && am_sender) { /* Use --log-format, not --out-format, for compatibility. */ if (stdout_format_has_i > 1) args[ac++] = "--log-format=%i%I"; else if (stdout_format_has_i) args[ac++] = "--log-format=%i"; else if (stdout_format_has_o_or_i) args[ac++] = "--log-format=%o"; else if (!verbose) args[ac++] = "--log-format=X"; } if (msgs2stderr == 1) args[ac++] = "--msgs2stderr"; else if (msgs2stderr == 0) args[ac++] = "--no-msgs2stderr"; if (block_size) { if (asprintf(&arg, "-B%u", (int)block_size) < 0) goto oom; args[ac++] = arg; } if (io_timeout) { if (asprintf(&arg, "--timeout=%d", io_timeout) < 0) goto oom; args[ac++] = arg; } if (bwlimit) { if (asprintf(&arg, "--bwlimit=%d", bwlimit) < 0) goto oom; args[ac++] = arg; } if (backup_dir) { /* This split idiom allows for ~/path expansion via the shell. */ args[ac++] = "--backup-dir"; args[ac++] = safe_arg("", backup_dir); } /* Only send --suffix if it specifies a non-default value. */ if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) args[ac++] = safe_arg("--suffix", backup_suffix); if (checksum_choice) args[ac++] = safe_arg("--checksum-choice", checksum_choice); if (do_compression == CPRES_ZLIBX) args[ac++] = "--new-compress"; else if (compress_choice && do_compression == CPRES_ZLIB) args[ac++] = "--old-compress"; else if (compress_choice) args[ac++] = safe_arg("--compress-choice", compress_choice); if (am_sender) { if (max_delete > 0) { if (asprintf(&arg, "--max-delete=%d", max_delete) < 0) goto oom; args[ac++] = arg; } else if (max_delete == 0) args[ac++] = "--max-delete=-1"; if (min_size >= 0) args[ac++] = safe_arg("--min-size", min_size_arg); if (max_size >= 0) args[ac++] = safe_arg("--max-size", max_size_arg); if (delete_before) args[ac++] = "--delete-before"; else if (delete_during == 2) args[ac++] = "--delete-delay"; else if (delete_during) args[ac++] = "--delete-during"; else if (delete_after) args[ac++] = "--delete-after"; else if (delete_mode && !delete_excluded) args[ac++] = "--delete"; if (delete_excluded) args[ac++] = "--delete-excluded"; if (force_delete) args[ac++] = "--force"; if (write_batch < 0) args[ac++] = "--only-write-batch=X"; if (am_root > 1) args[ac++] = "--super"; if (size_only) args[ac++] = "--size-only"; if (do_stats) args[ac++] = "--stats"; } else { if (skip_compress) args[ac++] = safe_arg("--skip-compress", skip_compress); } if (max_alloc_arg && max_alloc != DEFAULT_MAX_ALLOC) args[ac++] = safe_arg("--max-alloc", max_alloc_arg); /* --delete-missing-args needs the cooperation of both sides, but * the sender can handle --ignore-missing-args by itself. */ if (missing_args == 2) args[ac++] = "--delete-missing-args"; else if (missing_args == 1 && !am_sender) args[ac++] = "--ignore-missing-args"; if (modify_window_set && am_sender) { char *fmt = modify_window < 0 ? "-@%d" : "--modify-window=%d"; if (asprintf(&arg, fmt, modify_window) < 0) goto oom; args[ac++] = arg; } if (checksum_seed) { if (asprintf(&arg, "--checksum-seed=%d", checksum_seed) < 0) goto oom; args[ac++] = arg; } if (partial_dir && am_sender) { if (partial_dir != tmp_partialdir) { args[ac++] = "--partial-dir"; args[ac++] = safe_arg("", partial_dir); } if (delay_updates) args[ac++] = "--delay-updates"; } else if (keep_partial && am_sender) args[ac++] = "--partial"; if (ignore_errors) args[ac++] = "--ignore-errors"; if (copy_unsafe_links) args[ac++] = "--copy-unsafe-links"; if (safe_symlinks) args[ac++] = "--safe-links"; if (numeric_ids) args[ac++] = "--numeric-ids"; if (use_qsort) args[ac++] = "--use-qsort"; if (am_sender) { if (usermap) args[ac++] = safe_arg("--usermap", usermap); if (groupmap) args[ac++] = safe_arg("--groupmap", groupmap); if (ignore_existing) args[ac++] = "--ignore-existing"; /* Backward compatibility: send --existing, not --ignore-non-existing. */ if (ignore_non_existing) args[ac++] = "--existing"; if (tmpdir) { args[ac++] = "--temp-dir"; args[ac++] = safe_arg("", tmpdir); } if (do_fsync) args[ac++] = "--fsync"; if (basis_dir[0]) { /* the server only needs this option if it is not the sender, * and it may be an older version that doesn't know this * option, so don't send it if client is the sender. */ for (i = 0; i < basis_dir_cnt; i++) { args[ac++] = alt_dest_opt(0); args[ac++] = safe_arg("", basis_dir[i]); } } } /* What flags do we need to send to the other side? */ where = (am_server ? W_CLI : W_SRV) | (am_sender ? W_REC : W_SND); arg = make_output_option(info_words, info_levels, where); if (arg) args[ac++] = arg; if (append_mode) { if (append_mode > 1) args[ac++] = "--append"; args[ac++] = "--append"; } else if (inplace) { args[ac++] = "--inplace"; /* Work around a bug in older rsync versions (on the remote side) for --inplace --sparse */ if (sparse_files && !whole_file && am_sender) args[ac++] = "--no-W"; } if (files_from && (!am_sender || filesfrom_host)) { if (filesfrom_host) { args[ac++] = "--files-from"; args[ac++] = safe_arg("", files_from); if (eol_nulls) args[ac++] = "--from0"; } else { args[ac++] = "--files-from=-"; args[ac++] = "--from0"; } if (!relative_paths) args[ac++] = "--no-relative"; } /* It's OK that this checks the upper-bound of the protocol_version. */ if (relative_paths && !implied_dirs && (!am_sender || protocol_version >= 30)) args[ac++] = "--no-implied-dirs"; if (write_devices && am_sender) args[ac++] = "--write-devices"; if (remove_source_files == 1) args[ac++] = "--remove-source-files"; else if (remove_source_files) args[ac++] = "--remove-sent-files"; if (copy_devices && !am_sender) args[ac++] = "--copy-devices"; if (preallocate_files && am_sender) args[ac++] = "--preallocate"; if (open_noatime && preserve_atimes <= 1) args[ac++] = "--open-noatime"; if (mkpath_dest_arg && am_sender) args[ac++] = "--mkpath"; if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); exit_cleanup(RERR_MALLOC); } if (remote_option_cnt) { int j; if (ac + remote_option_cnt > MAX_SERVER_ARGS) { rprintf(FERROR, "too many remote options specified.\n"); exit_cleanup(RERR_SYNTAX); } for (j = 1; j <= remote_option_cnt; j++) args[ac++] = safe_arg(SPLIT_ARG_WHEN_OLD, remote_options[j]); } *argc_p = ac; return; oom: out_of_memory("server_options"); } int maybe_add_e_option(char *buf, int buf_len) { int x = 0; /* We don't really know the actual protocol_version at this point, * but checking the pre-negotiated value allows the user to use a * --protocol=29 override to avoid the use of this -eFLAGS opt. */ if (protocol_version >= 30 && buf_len > 0) { /* We make use of the -e option to let the server know about * any pre-release protocol version && some behavior flags. */ buf[x++] = 'e'; #if SUBPROTOCOL_VERSION != 0 if (protocol_version == PROTOCOL_VERSION) x += snprintf(buf + x, buf_len - x, "%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION); else #endif buf[x++] = '.'; if (allow_inc_recurse) buf[x++] = 'i'; #ifdef CAN_SET_SYMLINK_TIMES buf[x++] = 'L'; /* symlink time-setting support */ #endif #ifdef ICONV_OPTION buf[x++] = 's'; /* symlink iconv translation support */ #endif buf[x++] = 'f'; /* flist I/O-error safety support */ buf[x++] = 'x'; /* xattr hardlink optimization not desired */ buf[x++] = 'C'; /* support checksum seed order fix */ buf[x++] = 'I'; /* support inplace_partial behavior */ buf[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */ buf[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */ /* NOTE: Avoid using 'V' -- it was represented with the high bit of a write_byte() that became a write_varint(). */ } if (x >= buf_len) { /* Not possible... */ rprintf(FERROR, "overflow in add_e_flags().\n"); exit_cleanup(RERR_MALLOC); } buf[x] = '\0'; return x; } /* If str points to a valid hostspec, return allocated memory containing the * [USER@]HOST part of the string, and set the path_start_ptr to the part of * the string after the host part. Otherwise, return NULL. If port_ptr is * non-NULL, we must be parsing an rsync:// URL hostname, and we will set * *port_ptr if a port number is found. Note that IPv6 IPs will have their * (required for parsing) [ and ] chars elided from the returned string. */ static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr) { char *s, *host_start = str; int hostlen = 0, userlen = 0; char *ret; for (s = str; ; s++) { if (!*s) { /* It is only OK if we run out of string with rsync:// */ if (!port_ptr) return NULL; if (!hostlen) hostlen = s - host_start; break; } if (*s == ':' || *s == '/') { if (!hostlen) hostlen = s - host_start; if (*s++ == '/') { if (!port_ptr) return NULL; } else if (port_ptr) { *port_ptr = atoi(s); while (isDigit(s)) s++; if (*s && *s++ != '/') return NULL; } break; } if (*s == '@') { userlen = s - str + 1; host_start = s + 1; } else if (*s == '[') { if (s != host_start++) return NULL; while (*s && *s != ']' && *s != '/') s++; /*SHARED ITERATOR*/ hostlen = s - host_start; if (*s != ']' || (s[1] && s[1] != '/' && s[1] != ':') || !hostlen) return NULL; } } *path_start_ptr = s; ret = new_array(char, userlen + hostlen + 1); if (userlen) strlcpy(ret, str, userlen + 1); strlcpy(ret + userlen, host_start, hostlen + 1); return ret; } /* Look for a HOST specification of the form "HOST:PATH", "HOST::PATH", or * "rsync://HOST:PORT/PATH". If found, *host_ptr will be set to some allocated * memory with the HOST. If a daemon-accessing spec was specified, the value * of *port_ptr will contain a non-0 port number, otherwise it will be set to * 0. The return value is a pointer to the PATH. Note that the HOST spec can * be an IPv6 literal address enclosed in '[' and ']' (such as "[::1]" or * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */ char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr) { char *path; if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) { *host_ptr = parse_hostspec(s + strlen(URL_PREFIX), &path, port_ptr); if (*host_ptr) { if (!*port_ptr) *port_ptr = -1; /* -1 indicates they want the default */ return path; } } *host_ptr = parse_hostspec(s, &path, NULL); if (!*host_ptr) return NULL; if (*path == ':') { if (port_ptr && !*port_ptr) *port_ptr = -1; return path + 1; } if (port_ptr) *port_ptr = 0; return path; } rsync-3.2.7/README.md0000664000000000000000000001065614217634073012657 0ustar rootrootWHAT IS RSYNC? -------------- Rsync is a fast and extraordinarily versatile file copying tool for both remote and local files. Rsync uses a delta-transfer algorithm which provides a very fast method for bringing remote files into sync. It does this by sending just the differences in the files across the link, without requiring that both sets of files are present at one of the ends of the link beforehand. At first glance this may seem impossible because the calculation of diffs between two files normally requires local access to both files. A technical report describing the rsync algorithm is included with this package. USAGE ----- Basically you use rsync just like scp, but rsync has many additional options. To get a complete list of supported options type: rsync --help See the [manpage][0] for more detailed information. [0]: https://download.samba.org/pub/rsync/rsync.1 BUILDING AND INSTALLING ----------------------- If you need to build rsync yourself, check out the [INSTALL][1] page for information on what libraries and packages you can use to get the maximum features in your build. [1]: https://github.com/WayneD/rsync/blob/master/INSTALL.md SETUP ----- Rsync normally uses ssh or rsh for communication with remote systems. It does not need to be setuid and requires no special privileges for installation. You must, however, have a working ssh or rsh system. Using ssh is recommended for its security features. Alternatively, rsync can run in `daemon' mode, listening on a socket. This is generally used for public file distribution, although authentication and access control are available. To install rsync, first run the "configure" script. This will create a Makefile and config.h appropriate for your system. Then type "make". Note that on some systems you will have to force configure not to use gcc because gcc may not support some features (such as 64 bit file offsets) that your system may support. Set the environment variable CC to the name of your native compiler before running configure in this case. Once built put a copy of rsync in your search path on the local and remote systems (or use "make install"). That's it! RSYNC DAEMONS ------------- Rsync can also talk to "rsync daemons" which can provide anonymous or authenticated rsync. See the rsyncd.conf(5) manpage for details on how to setup an rsync daemon. See the rsync(1) manpage for info on how to connect to an rsync daemon. WEB SITE -------- For more information, visit the [main rsync web site][2]. [2]: https://rsync.samba.org/ You'll find a FAQ list, downloads, resources, HTML versions of the manpages, etc. MAILING LISTS ------------- There is a mailing list for the discussion of rsync and its applications that is open to anyone to join. New releases are announced on this list, and there is also an announcement-only mailing list for those that want official announcements. See the [mailing-list page][3] for full details. [3]: https://rsync.samba.org/lists.html BUG REPORTS ----------- The [bug-tracking web page][4] has full details on bug reporting. [4]: https://rsync.samba.org/bug-tracking.html That page contains links to the current bug list, and information on how to do a good job when reporting a bug. You might also like to try searching the Internet for the error message you've received, or looking in the [mailing list archives][5]. [5]: https://mail-archive.com/rsync@lists.samba.org/ To send a bug report, follow the instructions on the bug-tracking page of the web site. Alternately, email your bug report to . GIT REPOSITORY -------------- If you want to get the very latest version of rsync direct from the source code repository, then you will need to use git. The git repo is hosted [on GitHub][6] and [on Samba's site][7]. [6]: https://github.com/WayneD/rsync [7]: https://git.samba.org/?p=rsync.git;a=summary See [the download page][8] for full details on all the ways to grab the source. [8]: https://rsync.samba.org/download.html COPYRIGHT --------- Rsync was originally written by Andrew Tridgell and is currently maintained by Wayne Davison. It has been improved by many developers from around the world. Rsync may be used, modified and redistributed only under the terms of the GNU General Public License, found in the file [COPYING][9] in this distribution, or at [the Free Software Foundation][10]. [9]: https://github.com/WayneD/rsync/blob/master/COPYING [10]: https://www.fsf.org/licenses/gpl.html rsync-3.2.7/NEWS.md0000664000000000000000000062624314324367162012504 0ustar rootroot# NEWS for rsync 3.2.7 (20 Oct 2022) ## Changes in this version: ### BUG FIXES: - Fixed the client-side validating of the remote sender's filtering behavior. - More fixes for the "unrequested file-list name" name, including a copy of "/" with `--relative` enabled and a copy with a lot of related paths with `--relative` enabled (often derived from a `--files-from` list). - When rsync gets an unpack error on an ACL, mention the filename. - Avoid over-setting sanitize_paths when a daemon is serving "/" (even if "use chroot" is false). ### ENHANCEMENTS: - Added negotiated daemon-auth support that allows a stronger checksum digest to be used to validate a user's login to the daemon. Added SHA512, SHA256, and SHA1 digests to MD5 & MD4. These new digests are at the highest priority in the new daemon-auth negotiation list. - Added support for the SHA1 digest in file checksums. While this tends to be overkill, it is available if someone really needs it. This overly-long checksum is at the lowest priority in the normal checksum negotiation list. See [`--checksum-choice`](rsync.1#opt) (`--cc`) and the `RSYNC_CHECKSUM_LIST` environment var for how to customize this. - Improved the xattr hash table to use a 64-bit key without slowing down the key's computation. This should make extra sure that a hash collision doesn't happen. - If the `--version` option is repeated (e.g. `-VV`) then the information is output in a (still readable) JSON format. Client side only. - The script `support/json-rsync-version` is available to get the JSON style version output from any rsync. The script accepts either text on stdin **or** an arg that specifies an rsync executable to run with a doubled `--version` option. If the text we get isn't already in JSON format, it is converted. Newer rsync versions will provide more complete json info than older rsync versions. Various tweaks are made to keep the flag names consistent across versions. - The [`use chroot`](rsyncd.conf.5#) daemon parameter now defaults to "unset" so that rsync can use chroot when it works and a sanitized copy when chroot is not supported (e.g., for a non-root daemon). Explicitly setting the parameter to true or false (on or off) behaves the same way as before. - The `--fuzzy` option was optimized a bit to try to cut down on the amount of computations when considering a big pool of files. The simple heuristic from Kenneth Finnegan resuled in about a 2x speedup. - If rsync is forced to use protocol 29 or before (perhaps due to talking to an rsync before 3.0.0), the modify time of a file is limited to 4-bytes. Rsync now interprets this value as an unsigned integer so that a current year past 2038 can continue to be represented. This does mean that years prior to 1970 cannot be represented in an older protocol, but this trade-off seems like the right choice given that (1) 2038 is very rapidly approaching, and (2) newer protocols support a much wider range of old and new dates. - The rsync client now treats an empty destination arg as an error, just like it does for an empty source arg. This doesn't affect a `host:` arg (which is treated the same as `host:.`) since the arg is not completely empty. The use of [`--old-args`](rsync.1#opt) (including via `RSYNC_OLD_ARGS`) allows the prior behavior of treating an empty destination arg as a ".". ### PACKAGING RELATED: - The checksum code now uses openssl's EVP methods, which gets rid of various deprecation warnings and makes it easy to support more digest methods. On newer systems, the MD4 digest is marked as legacy in the openssl code, which makes openssl refuse to support it via EVP. You can choose to ignore this and allow rsync's MD4 code to be used for older rsync connections (when talking to an rsync prior to 3.0.0) or you can choose to configure rsync to tell openssl to enable legacy algorithms (see below). - A simple openssl config file is supplied that can be installed for rsync to use. If you install packaging/openssl-rsync.cnf to a public spot (such as `/etc/ssl/openssl-rsync.cnf`) and then run configure with the option `--with-openssl-conf=/path/name.cnf`, this will cause rsync to export the configured path in the OPENSSL_CONF environment variable (when the variable is not already set). This will enable openssl's MD4 code for rsync to use. - The packager may wish to include an explicit "use chroot = true" in the top section of their supplied /etc/rsyncd.conf file if the daemon is being installed to run as the root user (though rsync should behave the same even with the value unset, a little extra paranoia doesn't hurt). - I've noticed that some packagers haven't installed support/nameconvert for users to use in their chrooted rsync configs. Even if it is not installed as an executable script (to avoid a python3 dependency) it would be good to install it with the other rsync-related support scripts. - It would be good to add support/json-rsync-version to the list of installed support scripts. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.6 (9 Sep 2022) ## Changes in this version: ### BUG FIXES: - More path-cleaning improvements in the file-list validation code to avoid rejecting of valid args. - A file-list validation fix for a [`--files-from`](rsync.1#opt) file that ends without a line-terminating character. - Added a safety check that prevents the sender from removing destination files when a local copy using [`--remove-source-files`](rsync.1#opt) has some files that are shared between the sending & receiving hierarchies, including the case where the source dir & destination dir are identical. - Fixed a bug in the internal MD4 checksum code that could cause the digest to be sporadically incorrect (the openssl version was/is fine). - A minor tweak to rrsync added "copy-devices" to the list of known args, but left it disabled by default. ### ENHANCEMENTS: - Rename `--protect-args` to [`--secluded-args`](rsync.1#opt) to make it clearer how it differs from the default backslash-escaped arg-protecting behavior of rsync. The old option names are still accepted. The environment-variable override did not change its name. ### PACKAGING RELATED: - The configure option `--with-protected-args` was renamed to `--with-secluded-args`. This option makes `--secluded-args` the default rsync behavior instead of using backslash escaping for protecting args. - The mkgitver script now makes sure that a `.git` dir/file is in the top-level source dir before calling `git describe`. It also runs a basic check on the version value. This should avoid using an unrelated git description for rsync's version. ### DEVELOPER RELATED: - The configure script no longer sets the -pedantic-errors CFLAG (which it used to try to do only for gcc). - The name_num_obj struct was modified to allow its dynamic name_num_item list to be initialized in a better way. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.5 (14 Aug 2022) ## Changes in this version: ### SECURITY FIXES: - Added some file-list safety checking that helps to ensure that a rogue sending rsync can't add unrequested top-level names and/or include recursive names that should have been excluded by the sender. These extra safety checks only require the receiver rsync to be updated. When dealing with an untrusted sending host, it is safest to copy into a dedicated destination directory for the remote content (i.e. don't copy into a destination directory that contains files that aren't from the remote host unless you trust the remote host). Fixes CVE-2022-29154. - A fix for CVE-2022-37434 in the bundled zlib (buffer overflow issue). ### BUG FIXES: - Fixed the handling of filenames specified with backslash-quoted wildcards when the default remote-arg-escaping is enabled. - Fixed the configure check for signed char that was causing a host that defaults to unsigned characters to generate bogus rolling checksums. This made rsync send mostly literal data for a copy instead of finding matching data in the receiver's basis file (for a file that contains high-bit characters). - Lots of manpage improvements, including an attempt to better describe how include/exclude filters work. - If rsync is compiled with an xxhash 0.8 library and then moved to a system with a dynamically linked xxhash 0.7 library, we now detect this and disable the XX3 hashes (since these routines didn't stabilize until 0.8). ### ENHANCEMENTS: - The [`--trust-sender`](rsync.1#opt) option was added as a way to bypass the extra file-list safety checking (should that be required). ### PACKAGING RELATED: - A note to those wanting to patch older rsync versions: the changes in this release requires the quoted argument change from 3.2.4. Then, you'll want every single code change from 3.2.5 since there is no fluff in this release. - The build date that goes into the manpages is now based on the developer's release date, not on the build's local-timezone interpretation of the date. ### DEVELOPER RELATED: - Configure now defaults GETGROUPS_T to gid_t when cross compiling. - Configure now looks for the bsd/string.h include file in order to fix the build on a host that has strlcpy() in the main libc but not defined in the main string.h file. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.4 (15 Apr 2022) ## Changes in this version: ### BEHAVIOR CHANGES: - A new form of arg protection was added that works similarly to the older `--protect-args` ([`-s`](rsync.1#opt)) option but in a way that avoids breaking things like rrsync (the restricted rsync script): rsync now uses backslash escaping for sending "shell-active" characters to the remote shell. This includes spaces, so fetching a remote file via a simple quoted filename value now works by default without any extra quoting: ```shell rsync -aiv host:'a simple file.pdf' . ``` Wildcards are not escaped in filename args, but they are escaped in options like the [`--suffix`](rsync.1#opt) and [`--usermap`](rsync.1#opt) values. If your rsync script depends on the old arg-splitting behavior, either run it with the [`--old-args`](rsync.1#opt) option or `export RSYNC_OLD_ARGS=1` in the script's environment. See also the [ADVANCED USAGE](rsync.1#) section of rsync's manpage for how to use a more modern arg style. - A long-standing bug was preventing rsync from figuring out the current locale's decimal point character, which made rsync always output numbers using the "C" locale. Since this is now fixed in 3.2.4, a script that parses rsync's decimal numbers (e.g. from the verbose footer) may want to setup the environment in a way that the output continues to be in the C locale. For instance, one of the following should work fine: ```shell export LC_ALL=C.UTF-8 ``` or if iconv translations are needed: ```shell if [ "${LC_ALL:-}" ]; then export LANG="$LC_ALL" export LC_CTYPE="$LC_ALL" unset LC_ALL fi export LC_NUMERIC=C.UTF-8 ``` ### SECURITY FIXES: - A fix for CVE-2018-25032 in the bundled zlib (memory corruption issue). ### BUG FIXES: - Fixed a bug with [`--inplace`](rsync.1#opt) + [`--sparse`](rsync.1#opt) (and a lack of [`--whole-file`](rsync.1#opt)) where the destination file could get reconstructed with bogus data. Since the bug can also be avoided by using (the seemingly redundant) [`--no-W`](rsync.1#opt) on the receiving side, the latest rsync will now send `--no-W` to a remote receiver when this option combination occurs. If your client rsync is not new enough to do this for you (or if you're just paranoid), you can manually specify `--no-W -M--no-W` (when not using [`--whole-file`](rsync.1#opt)) to make sure the bug is avoided. - Fixed a bug with [`--mkpath`](rsync.1#opt) if a single-file copy specifies an existing destination dir with a non-existing destination filename. - Fixed `--update -vv` to output "is uptodate" instead of "is newer" messages for files that are being skipped due to an identical modify time. (This was a new output quirk in 3.2.3.) - When doing an append transfer, the sending side's file must not get shorter or it is skipped. Fixes a crash that could occur when the size changes to 0 in the middle of the send negotiations. - When dealing with special files (see [`--specials`](rsync.1#opt)) in an alt-dest hierarchy, rsync now checks the non-permission mode bits to ensure that the 2 special files are really the same before hard-linking them together. - Fixed a bug where [`--delay-updates`](rsync.1#opt) with stale partial data could cause a file to fail to update. - Fixed a few places that would output an INFO message with [`--info=NAME`](rsync.1#opt) that should only have been output given [`--verbose`](rsync.1#opt) or [`--itemize-changes`](rsync.1#opt). - Avoid a weird failure if you run a local copy with a (useless) [`--rsh`](rsync.1#opt) option that contains a `V` in the command. - Fixed a long-standing compression bug where the compression level of the first file transferred affected the level for all future files. Also, the per-file compression skipping has apparently never worked, so it is now documented as being ineffective. - Fixed a truncate error when a `--write-devices` copy wrote a file onto a device that was shorter than the device. - Made `--write-devices` support both `--checksum` and `--no-whole-file` when copying to a device. - Improved how the [`--stop-at`](rsync.1#opt), [`--stop-after`](rsync.1#opt), and (the deprecated) [`--time-limit`](rsync.1#opt) options check to see if the allowed time is over, which should make rsync exit more consistently. - Tweak --progress to display "`??:??:??`" when the time-remaining value is so large as to be meaningless. - Silence some chmod warnings about symlinks when it looks like we have a function to set their permissions but they can't really be set. - Fixed a potential issue in git-set-file-times when handling commits with high-bit characters in the description & when handling a description that might mimic the git raw-commit deliniators. (See the support dir.) - The bundled systemd/rsync.service file now includes `Restart=on-failure`. ### ENHANCEMENTS: - Use openssl's `-verify_hostname` option in the rsync-ssl script. - Added extra info to the "FILENAME exists" output of [`--ignore-existing`](rsync.1#opt) when [`--info=skip2`](rsync.1#opt) is used. The skip message becomes "FILENAME exists (INFO)" where the INFO is one of "type change", "sum change" (requires [`--checksum`](rsync.1#opt)), "file change" (based on the quick check), "attr change", or "uptodate". Prior versions only supported `--info=skip1`. - Added the [`--fsync`](rsync.1#opt) option (promoted from the patches repo). - Added the [`--copy-devices`](rsync.1#opt) option. Compared to the historical version from the rsync-patches repo, this version: properly handles `--checksum`; fixes a truncation bug when doing an `--inplace` copy onto a longer file; fixes several bugs in the `--itemize` output; and only the sending side needs the enhanced rsync for the copy to work. - Reduced memory usage for an incremental transfer that has a bunch of small directories. - The rsync daemon can now handle a client address with an implied "%scope" suffix. - Added support for [`--atimes`](rsync.1#opt) on macOS and fixed a bug where it wouldn't work without [`--times`](rsync.1#opt). - Rsync can now update the xattrs on a read-only file when your user can temporarily add user-write permission to the file. (It always worked for a root transfer.) - Rsync can now work around an [`--inplace`](rsync.1#opt) update of a file that is being refused due to the Linux fs.protected_regular sysctl setting. - When [`--chown`](rsync.1#opt), [`--usermap`](rsync.1#opt), or [`--groupmap`](rsync.1#opt) is specified, rsync now makes sure that the appropriate [`--owner`](rsync.1#opt) and/or [`--group`](rsync.1#opt) options are enabled. - Added the [`--info=NONREG`](rsync.1#opt) setting to control if rsync should warn about non-regular files in the transfer. This is enabled by default (keeping the behavior the same as before), so specifying `--info=nonreg0` can be used to turn the warnings off. - An optional asm optimization for the rolling checksum from Shark64. Enable it with `./configure --enable-roll-asm`. - Using `--debug=FILTER` now outputs a caution message if a filter rule has trailing whitespace. - Transformed rrsync into a python script with improvements: - Security has been beefed up. - The known rsync options were updated to include recent additions. - Make rrsync reject [`--copy-links`](rsync.1#opt) (`-L`), [`--copy-dirlinks`](rsync.1#opt) (`-k`), & [`--keep-dirlinks`](rsync.1#opt) (`-K`) by default to make it harder to exploit any out-of-subdir symlinks. - A new rrsync option of [`-munge`](rrsync.1#opt) tells rrsync to always enable rsync's [`--munge-links`](rsync.1#opt) option on the server side. - A new rrsync option of [`-no-lock`](rrsync.1#opt) disables a new single-use locking idiom that is the default when [`-ro`](rrsync.1#opt) is not used (useful with [`-munge`](rrsync.1#opt)). - A new rrsync option of [`-no-del`](rrsync.1#opt) disables all `--remove*` and `--delete*` rsync options on the server side. - The log format has been tweaked slightly to add seconds to the timestamp and to output the command executed as a tuple (making the args clearer). - An rrsync.1 manpage was added (in the support dir with rrsync). - Added options to the lsh script to facilitate rrsync testing. (See the support dir.) - Transformed the atomic-rsync script into a python script and added the ability to ignore one or more non-zero exit codes. By default, it now ignores code 24, the file-vanished exit code. (See the support dir.) - Transformed the munge-symlinks script into python. (See the support dir.) - Improved the rsync-no-vanished script to not join stdout & stderr together. (See the support dir.) - Work around a glibc bug where lchmod() breaks in a chroot w/o /proc mounted. - Try to support a client that sent a remote rsync a wacko stderr file handle (such as an older File::RsyncP perl library used by BackupPC). - Lots of manpage improvements, including better HTML versions. ### PACKAGING RELATED: - Give configure the `--with-rrsync` option if you want `make install` to install the (now python3) rrsync script and its new manpage. - If the rrsync script is installed, its package should be changed to depend on python3 and the (suggested but not mandatory) python3 braceexpand lib. - When creating a package from a non-release version (w/o a git checkout), the packager can elect to create git-version.h and define RSYNC_GITVER to the string they want `--version` to output. (The file is still auto-generated using the output of `git describe` when building inside a non-shallow git checkout, though.) - Renamed configure's `--enable-simd` option to `--enable-roll-simd` and added the option `--enable-roll-asm` to use the new asm version of the code. Both are x86_64/amd64 only. - Renamed configure's `--enable-asm` option to `--enable-md5-asm` to avoid confusion with the asm option for the rolling checksum. It is also honored even when openssl crypto is in use. This allows: normal MD4 & MD5, normal MD4 + asm MD5, openssl MD4 & MD5, or openssl MD4 + asm MD5 depending on the configure options selected. - Made SIMD & asm configure checks default to "no" on non-Linux hosts due to various reports of problems on NetBSD & macOS hosts. These were also tweaked to allow enabling the feature on a host_cpu of amd64 (was only allowed on x86_64 before). - Fixed configure to not fail at the SIMD check when cross-compiling. - Improved the IPv6 determination in configure. - Compile the C files with `-pedantic-errors` (when possible) so that we will get warned if a static initialization overflows in the future (among other things). - When linking with an external zlib, rsync renames its `read_buf()` function to `read_buf_()` to avoid a symbol clash on an unpatched zlib. - Added a SECURITY.md file. ### DEVELOPER RELATED: - Made it easier to write rsync tests that diff the output while also checking the status code, and used the idiom to improve the existing tests. (See the `checkdiff` and `checkdiff2` idioms in the `testsuite/*.test` files. - The packaging scripts & related python lib got some minor enhancements. ### INTERNAL - Use setenv() instead of putenv() when it is available. - Improve the logic in compat.c so that we don't need to try to remember to sprinkle `!local_server` exceptions throughout the protocol logic. - One more C99 Flexible Array improvement (started in the last release) and make use of the C99 `%zd` format string when printing size_t values (when possible). - Use mallinfo2() instead of mallinfo(), when available. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.3 (6 Aug 2020) ## Changes in this version: ### BUG FIXES: - Fixed a bug in the xattr code that was freeing the wrong object when trying to cleanup the xattr list. - Fixed a bug in the xattr code that was not leaving room for the "rsync." prefix in some instances where it needed to be added. - Restored the ability to use [`--bwlimit=0`](rsync.1#opt) to specify no bandwidth limit. (It was accidentally broken in 3.2.2.) - Fixed a bug when combining [`--delete-missing-args`](rsync.1#opt) with [`--no-implied-dirs`](rsync.1#opt) & [`-R`](rsync.1#opt) where rsync might create the destination path of a missing arg. The code also avoids some superfluous warnings for nested paths of removed args. - Fixed an issue where hard-linked devices could cause the rdev_major value to get out of sync between the sender and the receiver, which could cause a device to get created with the wrong major value in its major,minor pair. - Rsync now complains about a missing [`--temp-dir`](rsync.1#opt) before starting any file transfers. - A completely empty source arg is now a fatal error. This doesn't change the handling of implied dot-dir args such as "localhost:" and such. ### ENHANCEMENTS: - Allow [`--max-alloc=0`](rsync.1#opt) to specify no limit to the alloc sanity check. - Allow [`--block-size=SIZE`](rsync.1#opt) to specify the size using units (e.g. "100K"). - The name of the id-0 user & group are now sent to the receiver along with the other user/group names in the transfer (instead of assuming that both sides have the same id-0 names). - Added the [`--stop-after`](rsync.1#opt) and [`--stop-at`](rsync.1#opt) options (with a [`--time-limit`](rsync.1#opt) alias for `--stop-after`). This is an enhanced version of the time-limit patch from the patches repo. - Added the [`name converter`](rsyncd.conf.5#opt) daemon parameter to make it easier to convert user & group names inside a chrooted daemon module. This is based on the nameconverter patch with some improvements, including a tweak to the request protocol (so if you used this patch in the past, be sure to update your converter script to use newlines instead of null chars). - Added [`--crtimes`](rsync.1#opt) (`-N`) option for preserving the file's create time (I believe that this is macOS only at the moment). - Added [`--mkpath`](rsync.1#opt) option to tell rsync that it should create a non-existing path component of the destination arg. - Added [`--stderr=errors|all|client`](rsync.1#opt) to replace the `--msgs2stderr` and `--no-msgs2stderr` options (which are still accepted). The default use of stderr was changed to be `--stderr=errors` where all the processes that have stderr available output directly to stderr, which should help error messages get to the user more quickly, especially when doing a push (which includes local copying). This also allows rsync to exit quickly when a receiver failure occurs, since rsync doesn't need to try to keep the connection alive long enough for the fatal error to go from the receiver to the generator to the sender. The old default can be requested via `--stderr=client`. Also changed is that a non-default stderr mode is conveyed to the remote rsync (using the older option names) instead of requiring the user to use [`--remote-option`](rsync.1#opt) (`-M`) to tell the remote rsync what to do. - Added the ability to specify "@netgroup" names to the [`hosts allow`](rsyncd.conf.5#opt) and [`hosts deny`](rsyncd.conf.5#opt) daemon parameters. This is a finalized version of the netgroup-auth patch from the patches repo. - Rsync can now hard-link symlinks on FreeBSD due to it making use of the linkat() function when it is available. - Output file+line info on out-of-memory & overflow errors while also avoiding the output of alternate build-dir path info that is not useful to the user. - Change configure to know that Cygwin supports Linux xattrs. - Improved the testsuite on FreeBSD & Cygwin. - Added some compatibility code for HPE NonStop platforms. - Improved the INSTALL.md info. - Added a few more suffixes to the default skip-compress list. - Improved configure's error handling to notify about several issues at once instead of one by one (for the newest optional features). ### INTERNAL: - Use a simpler overflow check idiom in a few spots. - Use a C99 Flexible Array for a trailing variable-size filename in a struct (with a fallback to the old 1-char string kluge for older compilers). ------------------------------------------------------------------------------ # NEWS for rsync 3.2.2 (4 Jul 2020) ## Changes in this version: ### BUG FIXES: - Avoid a crash when a daemon module enables `transfer logging` without setting a `log format` value. - Fixed installing rsync-ssl script from an alternate build dir. - Fixed the updating of configure.sh from an alternate build dir. - Apple requires the asm function name to begin with an underscore. - Avoid a test failure in the daemon test when `--atimes` is disabled. ### ENHANCEMENTS: - Allow the server side to restrict checksum & compression choices via the same environment variables the client uses. The env vars can be divided into "client list & server list" by the "`&`" char or the same list can apply to both. - Simplify how the negotiation environment variables apply when interacting with an older rsync and also when a list contains only invalid names. - Do not allow a negotiated checksum or compression choice of "none" unless the user authorized it via an environment variable or command-line option. - Added the `--max-alloc=SIZE` option to be able to override the memory allocator's sanity-check limit. It defaults to 1G (as before) but the error message when exceeding it specifically mentions the new option so that you can differentiate an out-of-memory error from a failure of this limit. It also allows you to specify the value via the RSYNC_MAX_ALLOC environment variable. - Add the "open atime" daemon parameter to allow a daemon to always enable or disable the use of O_NOATIME (the default is to let the user control it). - The default systemd config was changed to remove the `ProtectHome=on` setting since rsync is often used to serve files in /home and /root and this seemed a bit too strict. Feel free to use `systemctl edit rsync` to add that restriction (or maybe `ProtectHome=read-only`), if you like. See the 3.2.0 NEWS for the other restrictions that were added compared to 3.1.3. - The memory allocation functions now automatically check for a failure and die when out of memory. This eliminated some caller-side check-and-die code and added some missing sanity-checking of allocations. - Put optimizations into their own list in the `--version` output. - Improved the manpage a bit more. ### PACKAGING RELATED: - Prepared the checksum code for an upcoming xxHash release that provides new XXH3 (64-bit) & XXH128 (128-bit) checksum routines. These will not be compiled into rsync until the xxhash v0.8.0 include files are installed on the build host, and that release is a few weeks away at the time this was written. So, if it's now the future and you have packaged and installed xxhash-0.8.0-devel, a fresh rebuild of rsync 3.2.2 will give you the new checksum routines. Just make sure that the new rsync package depends on xxhash >= 0.8.0. ### DEVELOPER RELATED: - Moved the version number out of configure.ac into its own version.h file so that we don't need to reconfigure just because the version number changes. - Moved the daemon parameter list into daemon-parm.txt so that an awk script can create the interrelated structs and accessors that loadparm.c needs. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.1 (22 Jun 2020) ## Changes in this version: ### BUG FIXES: - Fixed a potential build issue with the MD5 assembly-language code by removing some non-portable directives. - Use the preprocessor with the asm file to ensure that if the code is unneeded, it doesn't get built. - Avoid the stack getting set to executable when including the asm code. - Some improvements in the SIMD configure testing to try to avoid build issues, such as avoiding a clang++ core dump when `-g` is combined with `-O2`. Note that clang++ is quite buggy in this area, and it does still crash for some folks, so just use `--disable-simd` if you need to avoid their buggy compiler (since the configure test is apparently not finding all the compilers that will to crash and burn). - Fixed an issue in the md2man script when building from an alternate dir. - Disable `--atimes` on macOS (it apparently just ignores the atime change). ### ENHANCEMENTS: - The use of `--backup-dir=STR` now implies `--backup`. - Added `--zl=NUM` as a short-hand for `--compress-level=NUM`. - Added `--early-input=FILE` option that allows the client to send some data to a daemon's (optional) "early exec" script on its stdin. - Mention atimes in the capabilities list that `--version` outputs. - Mention either "default protect-args" or "optional protect-args" in the `--version` capabilities depending on how rsync was configured. - Some info on optimizations is now elided from the `--version` capabilities since they aren't really user-facing capabilities. You can still see the info (plus the status of a couple extra optimizations) by repeating the `--version` option (e.g. `-VV`). - Updated various URLs to be https instead of http. - Some documentation improvements. ### PACKAGING RELATED: - If you had to use `--disable-simd` for 3.2.0, you might want to try removing that and see if it will succeed or auto-disable. Some buggy clang++ compilers are still not auto disabled, though. - The MD5 asm code is now under its own configure flag (not shared with the SIMD setting), so if you have any issues compiling it, re-run configure with `--disable-asm`. - Merged the OLDNEWS.md file into NEWS.md. ------------------------------------------------------------------------------ # NEWS for rsync 3.2.0 (19 Jun 2020) ## Changes in this version: ### BUG FIXES: - Avoid a potential out-of-bounds read in daemon mode if argc can be made to become 0. - Fix the default list of skip-compress files for non-daemon transfers. - Fix xattr filter rules losing an 'x' attribute in a non-local transfer. - Avoid an error when a check for a potential fuzzy file happens to reference a directory. - Make the atomic-rsync helper script have a more consistent error-exit. - Make sure that a signal handler's use of exit_cleanup() calls `_exit()` instead of exit(). - Various zlib fixes, including security fixes for CVE-2016-9843, CVE-2016-9842, CVE-2016-9841, and CVE-2016-9840. - Fixed an issue with `--remove-source-files` not removing a source symlink when combined with `--copy-links`. - Fixed a bug where the daemon would fail to write early fatal error messages to the client, such as refused or unknown command-line options. - Fixed the block-size validation logic when dealing with older protocols. - Some rrsync fixes and enhancements to handle the latest options. - Fixed a problem with the `--link-dest`|`--copy-dest` code when `--xattrs` was specified along with multiple alternate-destination directories (it could possibly choose a bad file match while trying to find a better xattr match). - Fixed a couple bugs in the handling of files with the `--sparse` option. - Fixed a bug in the writing of the batch.sh file (w/`--write-batch`) when the source & destination args were not last on the command-line. - Avoid a hang when an overabundance of messages clogs up all the I/O buffers. - Fixed a mismatch in the RSYNC_PID values put into the environment of `pre-xfer exec` and a `post-xfer exec`. - Fixed a crash in the `--iconv` code. - Fixed a rare crash in the popt_unalias() code. ### ENHANCEMENTS: - The default systemd config was made stricter by default. For instance, `ProtectHome=on` (which hides content in /root and /home/USER dirs), `ProtectSystem=full` (which makes /usr, /boot, & /etc dirs read-only), and `PrivateDevices=on` (which hides devices). You can override any of these using the standard `systemctl edit rsync` and add one or more directives under a `[Service]` heading (and restart the rsync service). - Various checksum enhancements, including the optional use of openssl's MD4 & MD5 checksum algorithms, some x86-64 optimizations for the rolling checksum, some x86-64 optimizations for the (non-openssl) MD5 checksum, the addition of xxHash checksum support, and a negotiation heuristic that ensures that it is easier to add new checksum algorithms in the future. The environment variable `RSYNC_CHECKSUM_LIST` can be used to customize the preference order of the negotiation, or use `--checksum-choice` (`--cc`) to force a choice. - Various compression enhancements, including the addition of zstd and lz4 compression algorithms and a negotiation heuristic that picks the best compression option supported by both sides. The environment variable `RSYNC_COMPRESS_LIST` can be used to customize the preference order of the negotiation, or use `--compress-choice` (`--zc`) to force a choice. - Added a `--debug=NSTR` option that outputs details of the new negotiation strings (for checksums and compression). The first level just outputs the result of each negotiation on the client, level 2 outputs the values of the strings that were sent to and received from the server, and level 3 outputs all those values on the server side too (when the server was given the debug option). - The `--debug=OPTS` command-line option is no longer auto-forwarded to the remote rsync which allows for the client and server to have different levels of debug specified. This also allows for newer debug options to be specified, such as using `--debug=NSTR` to see the negotiated hash result, without having the command fail if the server version is too old to handle that debug item. Use `-M--debug=OPTS` to send the options to the remote side. - Added the `--atimes` option based on the long-standing patch (just with some fixes that the patch has been needing). - Added `--open-noatime` option to open files using `O_NOATIME`. - Added the `--write-devices` option based on the long-standing patch. - Added openssl & preliminary gnutls support to the rsync-ssl script, which is now installed by default. This was unified with the old stunnel-rsync helper script to simplify packaging. Note that the script accepts the use of `--type=gnutls` for gnutls testing, but does not look for gnutls-cli on the path yet. The use of `--type=gnutls` will not work right until gnutls-cli no longer drops data. - Rsync was enhanced to set the `RSYNC_PORT` environment variable when running a daemon-over-rsh script. Its value is the user-specified port number (set via `--port` or an rsync:// URL) or 0 if the user didn't override the port. - Added the `proxy protocol` daemon parameter that allows your rsyncd to know the real remote IP when it is setup behind a proxy. - Added negated matching to the daemon's `refuse options` setting by using match strings that start with a `!` (such as `!compress*`). This lets you refuse all options except for a particular approved list, for example. It also lets rsync refuse certain options by default (such as `write-devices`) while allowing the config to override that, as desired. - Added the `early exec` daemon parameter that runs a script before the transfer parameters are known, allowing some early setup based on module name. - Added status output in response to a signal (via both SIGINFO & SIGVTALRM). - Added `--copy-as=USER` option to give some extra security to root-run rsync commands into/from untrusted directories (such as backups and restores). - When resuming the transfer of a file in the `--partial-dir`, rsync will now update that partial file in-place instead of creating yet another tmp file copy. This requires both sender & receiver to be at least v3.2.0. - Added support for `RSYNC_SHELL` & `RSYNC_NO_XFER_EXEC` environment variables that affect the early, pre-xfer, and post-xfer exec rsync daemon parameters. - Optimize the `--fuzzy --fuzzy` heuristic to avoid the fuzzy directory scan until all other basis-file options are exhausted (such as `--link-dest`). - Have the daemon log include the normal-exit sent/received stats when the transfer exited with an error when possible (i.e. if it is the sender). - The daemon now locks its pid file (when configured to use one) so that it will not fail to start when the file exists but no daemon is running. - Various manpage improvements, including some html representations (that aren't installed by default). - Made `-V` the short option for `--version` and improved its information. - Pass the `-4` or `-6` option to the ssh command, making it easier to type than `--rsh='ssh -4'` (or the `-6` equivalent). - Added example config for rsyncd SSL proxy configs to rsyncd.conf. - More errors messages now mention if the error is coming from the sender or the receiver. ### PACKAGING RELATED: - Add installed bash script: /usr/bin/rsync-ssl - Add installed manpage: /usr/man/man1/rsync-ssl.1 - Tweak auxiliary doc file names, such as: README.md, INSTALL.md, & NEWS.md. - The rsync-ssl script wants to run openssl or stunnel4, so consider adding a dependency for one of those options (though it's probably fine to just let it complain about being unable to find the program and let the user decide if they want to install one or the other). - If you packaged rsync + rsync-ssl + rsync-ssl-daemon as separate packages, the rsync-ssl package is now gone (rsync-ssl should be considered to be mainstream now that Samba requires SSL for its rsync daemon). - Add _build_ dependency for liblz4-dev, libxxhash-dev, libzstd-dev, and libssl-dev. These development libraries will give rsync extra compression algorithms, extra checksum algorithms, and allow use of openssl's crypto lib for (potentially) faster MD4/MD5 checksums. - Add _build_ dependency for g++ or clang++ on x86_64 systems to enable the SIMD checksum optimizations. - Add _build_ dependency for _either_ python3-cmarkcfm or python3-commonmark to allow for patching of manpages or building a git release. This is not required for a release-tar build, since it comes with pre-built manpages. Note that cmarkcfm is faster than commonmark, but they generate the same data. The commonmark dependency is easiest to install since it's native python, and can even be installed via `pip3 install --user commonmark` if you want to just install it for the build user. - Remove yodl _build_ dependency (if it was even listed before). ### DEVELOPER RELATED: - Silenced some annoying warnings about major() & minor() by improving an autoconf include-file check. - Converted the manpages from yodl to markdown. They are now processed via a simple python3 script using the cmarkgfm **or** commonmark library. This should make it easier to package rsync, since yodl is rather obscure. - Improved some configure checks to work better with strict C99 compilers. - Some perl building/packaging scripts were recoded into awk and python3. - Some defines in byteorder.h were changed into static inline functions that will help to ensure that the args don't get evaluated multiple times on "careful alignment" hosts. - Some code typos were fixed (as pointed out by a Fossies run). ------------------------------------------------------------------------------ # NEWS for rsync 3.1.3 (28 Jan 2018) ## Changes in this version: ### SECURITY FIXES: - Fixed a buffer overrun in the protocol's handling of xattr names and ensure that the received name is null terminated. - Fix an issue with `--protect-args` where the user could specify the arg in the protected-arg list and short-circuit some of the arg-sanitizing code. ### BUG FIXES: - Don't output about a new backup dir without appropriate info verbosity. - Fixed some issues with the sort functions in the rsyncstats script (in the support dir). - Added a way to specify daemon config lists (e.g. users, groups, etc) that contain spaces (see `auth users` in the latest rsyncd.conf manpage). - If a backup fails (e.g. full disk) rsync exits with an error. - Fixed a problem with a doubled `--fuzzy` option combined with `--link-dest`. - Avoid invalid output in the summary if either the start or end time had an error. - We don't allow a popt alias to affect the `--daemon` or `--server` options. - Fix daemon exclude code to disallow attribute changes in addition to disallowing transfers. - Don't force nanoseconds to match if a non-transferred, non-checksummed file only passed the quick-check w/o comparing nanoseconds. ### ENHANCEMENTS: - Added the ability for rsync to compare nanosecond times in its file-check comparisons, and added support nanosecond times on Mac OS X. - Added a short-option (`-@`) for `--modify-window`. - Added the `--checksum-choice=NAME[,NAME]` option to choose the checksum algorithms. - Added hashing of xattr names (with using `-X`) to improve the handling of files with large numbers of xattrs. - Added a way to filter xattr names using include/exclude/filter rules (see the `--xattrs` option in the manpage for details). - Added `daemon chroot|uid|gid` to the daemon config (in addition to the old chroot|uid|gid settings that affect the daemon's transfer process). - Added `syslog tag` to the daemon configuration. - Some manpage improvements. ### DEVELOPER RELATED: - Tweak the `make` output when yodl isn't around to create the manpages. - Changed an obsolete autoconf compile macro. - Support newer yodl versions when converting manpages. ------------------------------------------------------------------------------ # NEWS for rsync 3.1.2 (21 Dec 2015) ## Changes in this version: ### SECURITY FIXES: - Make sure that all transferred files use only path names from inside the transfer. This makes it impossible for a malicious sender to try to make the receiver use an unsafe destination path for a transferred file, such as a just-sent symlink. ### BUG FIXES: - Change the checksum seed order in the per-block checksums. This prevents someone from trying to create checksum blocks that match in sum but not content. - Fixed a with the per-dir filter files (using `-FF`) that could trigger an assert failure. - Only skip `set_modtime()` on a transferred file if the time is exactly right. - Don't create an empty backup dir for a transferred file that doesn't exist yet. - Fixed a bug where `--link-dest` and `--xattrs` could cause rsync to exit if a filename had a matching dir of the same name in the alt-dest area. - Allow more than 32 group IDs per user in the daemon's gid=LIST config. - Fix the logging of %b & %c via `--log-file` (daemon logging was already correct, as was `--out-format='%b/%c'`). - Fix erroneous acceptance of `--info=5` & `--debug=5` (an empty flag name is not valid). ### ENHANCEMENTS: - Added `(DRY RUN)` info to the `--debug=exit` output line. - Use usleep() for our msleep() function if it is available. - Added a few extra long-option names to rrsync script, which will make BackupPC happier. - Made configure choose to use Linux xattrs on NetBSD (rather than not supporting xattrs). - Added `-wo` (write-only) option to rrsync support script. - Misc. manpage tweaks. ### DEVELOPER RELATED: - Fixed a bug with the Makefile's use of `INSTALL_STRIP`. - Improve a test in the suite that could get an erroneous timestamp error. - Tweaks for newer versions of git in the packaging tools. - Improved the m4 generation rules and some autoconf idioms. ------------------------------------------------------------------------------ # NEWS for rsync 3.1.1 (22 Jun 2014) ## Changes in this version: ### BUG FIXES: - If the receiver gets bogus filenames from the sender (an unexpected leading slash or a `..` infix dir), exit with an error. This prevents a malicious sender from trying to inject filenames that would affect an area outside the destination directories. - Fixed a failure to remove the partial-transfer temp file when interrupted (and rsync is not saving the partial files). - Changed the chown/group/xattr-set order to avoid losing some security- related xattr info (that would get cleared by a chown). - Fixed a bug in the xattr-finding code that could make a non-root-run receiver not able to find some xattr numbers. - Fixed a bug in the early daemon protocol where a timeout failed to be honored (e.g. if the remote side fails to send us the initial protocol greeting). - Fixed unintended inclusion of commas in file numbers in the daemon log. - We once again send the 'f' sub-flag (of `-e`) to the server side so it knows that we can handle incremental-recursion directory errors properly in older protocols. - Fixed an issue with too-aggressive keep-alive messages causing a problem for older rsync versions early in the transfer. - Fixed an incorrect message about backup-directory-creation when using `--dry-run` and the backup dir is not an absolute path. - Fixed a bug where a failed deletion and/or a failed sender-side removal would not affect the exit code. - Fixed a bug that caused a failure when combining `--delete-missing-args` with `--xattrs` and/or `--acls`. - Fixed a strange `dir_depth` assertion error that was caused by empty-dir removals and/or duplicate files in the transfer. - Fixed a problem with `--info=progress2`'s output stats where rsync would only update the stats at the end of each file's transfer. It now uses the data that is flowing for the current file, making the stats more accurate and less jumpy. - Fixed an itemize bug that affected the combo of `--link-dest`, `-X`, and `-n`. - Fixed a problem with delete messages not appearing in the log file when the user didn't use `--verbose`. - Improve chunked xattr reading for OS X. - Removed an attempted hard-link xattr optimization that was causing a transfer failure. This removal is flagged in the compatibility code, so if a better fix can be discovered, we have a way to flip it on again. - Fixed a bug when the receiver is not configured to be able to hard link symlimks/devices/special-file items but the sender sent some of these items flagged as hard-linked. - We now generate a better error if the buffer overflows in `do_mknod()`. - Fixed a problem reading more than 16 ACLs on some OSes. - Fixed the reading of the secrets file to avoid an infinite wait when the username is missing. - Fixed a parsing problem in the `--usermap`/`--groupmap` options when using MIN-MAX numbers. - Switched Cygwin back to using socketpair `pipes` to try to speed it up. - Added knowledge of a few new options to rrsync. ### ENHANCEMENTS: - Tweaked the temp-file naming when `--temp-dir=DIR` is used: the temp-file names will not get a '.' prepended. - Added support for a new-compression idiom that does not compress all the matching data in a transfer. This can help rsync to use less cpu when a transfer has a lot of matching data, and also makes rsync compatible with a non-bundled zlib. See the `--new-compress` and `--old-compress` options in the manpage. - Added the rsync-no-vanished shell script. (See the support dir.) - Made configure more prominently mention when we failed to find yodl (in case the user wants to be able to generate manpages from `*.yo` files). - Have manpage mention how a daemon's max-verbosity setting affects info and debug options. Also added more clarification on backslash removals for excludes that contain wildcards. - Have configure check if for the attr lib (for getxattr) for those systems that need to link against it explicitly. - Change the early dir-creation logic to only use that idiom in an inc-recursive copy that is preserving directory times. e.g. using `--omit-dir-times` will avoid these early directories being created. - Fix a bug in `cmp_time()` that would return a wrong result if the 2 times differed by an amount greater than what a `time_t` can hold. ### DEVELOPER RELATED: - We now include an example systemd file (in packaging/systemd). - Tweaked configure to make sure that any intended use of the included popt and/or zlib code is put early in the CFLAGS. ------------------------------------------------------------------------------ # NEWS for rsync 3.1.0 (28 Sep 2013) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 31. ### OUTPUT CHANGES: - Output numbers in 3-digit groups by default (e.g. 1,234,567). See the `--human-readable` option for a way to turn it off. See also the daemon's `log format` parameter and related command-line options (including `--out-format`) for a modifier that can be used to request digit-grouping or human-readable output in log escapes. (Note that log output is unchanged by default.) - The `--list-only` option is now affected by the `--human-readable` setting. It will display digit groupings by default, and unit suffixes if higher levels of readability are requested. Also, the column width for the size output has increased from 11 to 14 characters when human readability is enabled. Use `--no-h` to get the old-style output and column size. - The output of the `--progress` option has changed: the string `xfer` was shortened to `xfr`, and the string `to-check` was shortened to `to-chk`, both designed to make room for the (by default) wider display of file size numbers without making the total line-length longer. Also, when incremental recursion is enabled, the string `ir-chk` will be used instead of `to-chk` up until the incremental-recursion scan is done, letting you know that the value to check and the total value will still be increasing as new files are found. - Enhanced the `--stats` output: 1) to mention how many files were created (protocol >= 28), 2) to mention how many files were deleted (a new line for protocol 31, but only output when `--delete` is in effect), and 3) to follow the file-count, created-count, and deleted-count with a subcount list that shows the counts by type. The wording of the transferred count has also changed so that it is clearer that it is only a count of regular files. ### BUG FIXES: - Fixed a bug in the iconv code when EINVAL or EILSEQ is returned with a full output buffer. - Fixed some rare bugs in `--iconv` processing that might cause a multi-byte character to get translated incorrectly. - Fixed a bogus `vanished file` error if some files were specified with `./` prefixes and others were not. - Fixed a bug in `--sparse` where an extra gap could get inserted after a partial write. - Changed the way `--progress` overwrites its prior output in order to make it nearly impossible for the progress to get overwritten by an error. - Improved the propagation of abnormal-exit error messages. This should help the client side to receive errors from the server when it is exiting abnormally, and should also avoid dying with an `connection unexpectedly closed` exit when the closed connection is really expected. - The sender now checks each file it plans to remove to ensure that it hasn't changed from the first stat's info. This helps to avoid losing file data when the user is not using the option in a safe manner. - Fixed a data-duplication bug in the compress option that made compression less efficient. This improves protocol 31 onward, while behaving in a compatible (buggy) manner with older rsync protocols. - When creating a temp-file, rsync is now a bit smarter about it dot-char choices, which can fix a problem on OS X with names that start with `..`. - Rsync now sets a cleanup flag for `--inplace` and `--append` transfers that will flush the write buffer if the transfer aborts. This ensures that more received data gets written out to the disk on an aborted transfer (which is quite helpful on a slow, flaky connection). - The reads that `map_ptr()` now does are aligned on 1K boundaries. This helps some filesystems and/or files that don't like unaligned reads. - Fix an issue in the msleep() function if time jumps backwards. - Fix daemon-server module-name splitting bug where an arg would get split even if `--protect-args` was used. ### ENHANCEMENTS: - Added the `--remote-option=OPT` (`-M OPT`) command-line option that is useful for things like sending a remote `--log-file=FILE` or `--fake-super` option. - Added the `--info=FLAGS` and `--debug=FLAGS` options to allow finer-grained control over what is output. Added an extra type of `--progress` output using `--info=progress2`. - The `--msgs2stderr` option can help with debugging rsync by allowing the debug messages to get output to stderr rather than travel via the socket protocol. - Added the `--delete-missing-args` and `--ignore-missing-args` options to either delete or ignore user-specified files on the receiver that are missing on the sender (normally the absence of user-specified files generates an error). - Added a `T` (terabyte) category to the `--human-readable` size suffixes. - Added the `--usermap`/`--groupmap`/`--chown` options for manipulating file ownership during the copy. - Added the `%C` escape to the log-output handling, which will output the MD5 checksum of any transferred file, or all files if `--checksum` was specified (when protocol 30 or above is in effect). - Added the `reverse lookup` parameter to the rsync daemon config file to allow reverse-DNS lookups to be disabled. - Added a forward-DNS lookup for the daemon's hosts allow/deny config. Can be disabled via `forward lookup` parameter (defaults to enabled). - Added a way for more than one group to be specified in the daemon's config file, including a way to specify that you want all of the specified user's groups without having to name them. Also changed the daemon to complain about an inability to set explicitly-specified uid/gid values, even when not run by a super-user. - The daemon now tries to send the user the error messages from the pre-xfer exec script when it fails. - Improved the use of alt-dest options into an existing hierarchy of files: If a match is found in an alt-dir, it takes precedence over an existing file. (We'll need to wait for a future version before attribute-changes on otherwise unchanged files are safe when using an existing hierarchy.) - Added per-user authorization options and group-authorization support to the daemon's `auth users` parameter. - Added a way to reference environment variables in a daemon's config file (using %VAR% references). - When replacing a non-dir with a symlink/hard-link/device/special-file, the update should now be done in an atomic manner. - Avoid re-sending xattr info for hard-linked files w/the same xattrs (protocol 31). - The backup code was improved to use better logic maintaining the backup directory hierarchy. Also, when a file is being backed up, rsync tries to hard-link it into place so that the upcoming replacement of the destination file will be atomic (for the normal, non-inplace logic). - Added the ability to synchronize nanosecond modified times. - Added a few more default suffixes for the `dont compress` settings. - Added the checking of the `RSYNC_PROTECT_ARGS` environment variable to allow the default for the `--protect-args` command-line option to be overridden. - Added the `--preallocate` command-line option. - Allow `--password-file=-` to read the password from stdin (filename `-`). - Rsync now comes packaged with an rsync-ssl helper script that can be used to contact a remote rsync daemon using a piped-stunnel command. It also includes an stunnel config file to run the server side to support ssl daemon connections. See the packaging/lsb/rsync.spec file for one way to package the resulting files. (Suggestions for how to make this even easier to install & use are welcomed.) - Improved the speed of some `--inplace` updates when there are lots of identical checksum blocks that end up being unusable. - Added the `--outbuf=N|L|B` option for choosing the output buffering. - Repeating the `--fuzzy` option now causes the code to look for fuzzy matches inside alt-dest directories too. - The `--chmod` option now supports numeric modes, e.g. `--chmod=644,D755` - Added some Solaris xattr code. - Made an rsync daemon (the listening process) exit with a 0 status when it was signaled to die. This helps launchd. - Improved the `RSYNC_*` environment variables for the pre-xfer exec script: when a daemon is sent multiple request args, they are now joined into a single return value (separated by spaces) so that the `RSYNC_REQUEST` environment variable is accurate for any `pre-xfer exec`. The values in `RSYNC_ARG#` vars are no longer truncated at the `.` arg (prior to the request dirs/files), so that all the requested values are also listed (separately) in `RSYNC_ARG#` variables. ### EXTRAS: - Added an `instant-rsyncd` script to the support directory, which makes it easy to configure a simple rsync daemon in the current directory. - Added the `mapfrom` and `mapto` scripts to the support directory, which makes it easier to do user/group mapping in a local transfer based on passwd/group files from another machine. - There's a new, improved version of the lsh script in the support dir: it's written in perl and supports `-u` without resorting to using sudo (when run as root). The old shell version is now named lsh.sh. - There is a helper script named rsync-slash-strip in the support directory for anyone that wants to change the way rsync handles args with trailing slashes. (e.g. arg/ would get stripped to arg while arg/. would turn into arg/). ### INTERNAL: - The I/O code was rewritten to be simpler and do bigger buffered reads over the socket. The I/O between the receiver and the generator was changed to be standard multiplexed-I/O (like that over the socket). - The sender tries to use any dead time while the generator is looking for files to transfer in order to do sender-side directory scanning in a more parallel manner. - A daemon can now inform a client about a daemon-configured timeout value so that the client can assist in the keep-alive activity (protocol 31). - The filter code received some refactoring to make it more extendable, to read better, and do better sanity checking. - Really big numbers are now output using our own big-num routine rather than casting them to a double and using a %.0f conversion. - The `pool_alloc` library has received some minor improvements in alignment handling. - Added `init_stat_x()` function to avoid duplication of acl/xattr init code. - The included zlib was upgraded from 1.2.3 to 1.2.8. - Rsync can now be compiled to use an unmodified zlib library instead of the tweaked one that is included with rsync. This will eventually become the default, at which point we'll start the countdown to removing the included zlib. Until then, feel free to configure using: ./configure `--with-included-zlib=no` ### DEVELOPER RELATED: - Added more conditional debug output. - Fixed some build issues for Android and Minix. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.9 (23 Sep 2011) ## Changes in this version: ### BUG FIXES: - Fix a crash bug in checksum scanning when `--inplace` is used. - Fix a hang if a hard-linked file cannot be opened by the sender (e.g. if it has no read permission). - Fix preservation of a symlink's system xattrs (e.g. selinux) on Linux. - Fix a memory leak in the xattr code. - Fixed a bug with `--delete-excluded` when a filter merge file has a rule that specifies a receiver-only side restriction. - Fix a bug with the modifying of unwritable directories. - Fix `--fake-super`'s interaction with `--link-dest` same-file comparisons. - Fix the updating of the `curr_dir` buffer to avoid a duplicate slash. - Fix the directory permissions on an implied dot-dir when using `--relative` (e.g. /outside/path/././send/path). - Fixed some too-long sleeping instances when using `--bwlimit`. - Fixed when symlink ownership difference-checking gets compiled into `unchanged_attrs()`. - Improved the socket-error reporting when multiple protocols fail. - Fixed a case where a socket error could reference just-freed memory. - Failing to use a password file that was specified on the command-line is now a fatal error. - Fix the non-root updating of directories that don't have the read and/or execute permission. - Make daemon-excluded file errors more error-like. - Fix a compilation issue on older C compilers (due to a misplaced var declaration). - Make configure avoid finding socketpair on Cygwin. - Avoid trying to reference `SO_BROADCAST` if the OS doesn't support it. - Fix some issues with the post-processing of the manpages. - Fixed the user home-dir handling in the lsh script. (See the support dir.) - Some minor manpage improvements. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.8 (26 Mar 2011) ## Changes in this version: ### BUG FIXES: - Fixed two buffer-overflow issues: one where a directory path that is exactly MAXPATHLEN was not handled correctly, and one handling a `--backup-dir` that is extra extra large. - Fixed a data-corruption issue when preserving hard-links without preserving file ownership, and doing deletions either before or during the transfer (CVE-2011-1097). This fixes some assert errors in the hard-linking code, and some potential failed checksums (via `-c`) that should have matched. - Fixed a potential crash when an rsync daemon has a filter/exclude list and the transfer is using ACLs or xattrs. - Fixed a hang if a really large file is being processed by an rsync that can't handle 64-bit numbers. Rsync will now complain about the file being too big and skip it. - For devices and special files, we now avoid gathering useless ACL and/or xattr information for files that aren't being copied. (The un-copied files are still put into the file list, but there's no need to gather data that is not going to be used.) This ensures that if the user uses `--no-D`, that rsync can't possibly complain about being unable to gather extended information from special files that are in the file list (but not in the transfer). - Properly handle requesting remote filenames that start with a dash. This avoids a potential error where a filename could be interpreted as a (usually invalid) option. - Fixed a bug in the comparing of upper-case letters in file suffixes for `--skip-compress`. - If an rsync daemon has a module configured without a path setting, rsync will now disallow access to that module. - If the destination arg is an empty string, it will be treated as a reference to the current directory (as 2.x used to do). - If rsync was compiled with a newer time-setting function (such as lutimes), rsync will fall-back to an older function (such as utimes) on a system where the newer function is not around. This helps to make the rsync binary more portable in mixed-OS-release situations. - Fixed a batch-file writing bug that would not write out the full set of compatibility flags that the transfer was using. This fixes a potential protocol problem for a batch file that contains a sender-side I/O error: it would have been sent in a way that the batch-reader wasn't expecting. - Some improvements to the hard-linking code to ensure that device-number hashing is working right, and to supply more information if the hard-link code fails. - The `--inplace` code was improved to not search for an impossible checksum position. The quadruple-verbose chunk[N] message will now mention when an inplace chunk was handled by a seek rather than a read+write. - Improved ACL mask handling, e.g. for Solaris. - Fixed a bug that prevented `--numeric-ids` from disabling the translation of user/group IDs for ACLs. - Fixed an issue where an xattr and/or ACL transfer that used an alt-dest option (e.g. `--link-dest`) could output an error trying to itemize the changes against the alt-dest directory's xattr/ACL info but was instead trying to access the not-yet-existing new destination directory. - Improved xattr system-error messages to mention the full path to the file. - The `--link-dest` checking for identical symlinks now avoids considering attribute differences that cannot be changed on the receiver. - Avoid trying to read/write xattrs on certain file types for certain OSes. Improved configure to set `NO_SYMLINK_XATTRS`, `NO_DEVICE_XATTRS`, and/or `NO_SPECIAL_XATTRS` defines in config.h. - Improved the unsafe-symlink errors messages. - Fixed a bug setting xattrs on new files that aren't user writable. - Avoid re-setting xattrs on a hard-linked file w/the same xattrs. - Fixed a bug with `--fake-super` when copying files and dirs that aren't user writable. - Fixed a bug where a sparse file could have its last sparse block turned into a real block when rsync sets the file size (requires ftruncate). - If a temp-file name is too long, rsync now avoids truncating the name in the middle of adjacent high-bit characters. This prevents a potential filename error if the filesystem doesn't allow a name to contain an invalid multi-byte sequence. - If a muli-protocol socket connection fails (i.e., when contacting a daemon), we now report all the failures, not just the last one. This avoids losing a relevant error (e.g. an IPv4 connection-refused error) that happened before the final error (e.g. an IPv6 protocol-not-supported error). - Generate a transfer error if we try to call chown with a `-1` for a uid or a gid (which is not settable). - Fixed the working of `--force` when used with `--one-file-system`. - Fix the popt arg parsing so that an option that doesn't take an arg will reject an attempt to supply one (can configure `--with-included-popt` if your system's popt library doesn't yet have this fix). - A couple minor option tweaks to the rrsync script, and also some regex changes that make vim highlighting happier. (See the support dir.) - Fixed some issues in the mnt-excl script. (See the support dir.) - Various manpage improvements. ### ENHANCEMENTS: - Added `.hg/` to the default cvs excludes (see `-C` & `--cvs-exclude`). ### DEVELOPER RELATED: - Use lchmod() whenever it is available (not just on symlinks). - A couple fixes to the `socketpair_tcp()` routine. - Updated the helper scripts in the packaging subdirectory. - Renamed configure.in to configure.ac. - Fixed configure's checking for iconv routines for newer OS X versions. - Fixed the testsuite/xattrs.test script on OS X. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.7 (31 Dec 2009) ## Changes in this version: ### BUG FIXES: - Fixed a bogus free when using `--xattrs` with `--backup`. - Avoid an error when `--dry-run` was trying to stat a prior hard-link file that hasn't really been created. - Fixed a problem with `--compress` (`-z`) where the receiving side could return the error "`inflate (token) returned -5`". - Fixed a bug where `--delete-during` could delete in a directory before it noticed that the sending side sent an I/O error for that directory (both sides of the transfer must be at least 3.0.7). - Improved `--skip-compress`'s error handling of bad character-sets and got rid of a lingering debug fprintf(). - Fixed the daemon's conveyance of `io_error` value from the sender. - An rsync daemon use seteuid() (when available) if it used setuid(). - Get the permissions right on a `--fake-super` transferred directory that needs more owner permissions to emulate root behavior. - An absolute-path filter rule (i.e. with a '/' modifier) no longer loses its modifier when sending the filter rules to the remote rsync. - Improved the "`--delete does not work without -r or -d`" message. - Improved rsync's handling of `--timeout` to avoid a weird timeout case where the sender could timeout even though it has recently written data to the socket (but hasn't read data recently, due to the writing). - Some misc manpage improvements. - Fixed the chmod-temp-dir testsuite on a system without /var/tmp. - Make sure that a timeout specified in the daemon's config is used as a maximum timeout value when the user also specifies a timeout. - Improved the error-exit reporting when rsync gets an error trying to cleanup after an error: the initial error is reported. - Improved configure's detection of IPv6 for Solaris and Cygwin. - The AIX sysacls routines will now return ENOSYS if ENOTSUP is missing. - Made our (only used if missing) getaddrinfo() routine use `inet_pton()` (which we also provide) instead of `inet_aton()`. - The exit-related debug messages now mention the program's role so it is clear who output what message. ### DEVELOPER RELATED: - Got rid of type-punned compiler warnings output by newer gcc versions. - The Makefile now ensures that proto.h will be rebuilt if config.h changes. - The testsuite no longer uses `id -u`, so it works better on Solaris. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.6 (8 May 2009) ## Changes in this version: ### BUG FIXES: - Fixed a `--read-batch` hang when rsync is reading a batch file that was created from an incremental-recursion transfer. - Fixed the daemon's socket code to handle the simultaneous arrival of multiple connections. - Fix `--safe-links`/`--copy-unsafe-links` to properly handle symlinks that have consecutive slashes in the value. - Fixed the parsing of an `[IPv6_LITERAL_ADDR]` when a USER@ is prefixed. - The sender now skips a (bogus) symlink that has a 0-length value, which avoids a transfer error in the receiver. - Fixed a case where the sender could die with a tag-0 error if there was an I/O during the sending of the file list. - Fixed the rrsync script to avoid a server-side problem when `-e` is at the start of the short options. - Fixed a problem where a vanished directory could turn into an exit code 23 instead of the proper exit code 24. - Fixed the `--iconv` conversion of symlinks when doing a local copy. - Fixed a problem where `--one-file-system` was not stopping deletions on the receiving side when a mount-point directory did not match a directory in the transfer. - Fixed the dropping of an ACL mask when no named ACL values were present. - Fixed an ACL/xattr corruption issue where the `--backup` option could cause rsync to associate the wrong ACL/xattr information with received files. - Fixed the use of `--xattrs` with `--only-write-batch`. - Fixed the use of `--dry-run` with `--read-batch`. - Fixed configure's erroneous use of target. - Fixed configure's `--disable-debug` option. - Fixed a run-time issue for systems that can't find `iconv_open()` by adding the `--disable-iconv-open` configure option. - Complain and die if the user tries to combine `--remove-source-files` (or the deprecated `--remove-sent-files`) with `--read-batch`. - Fixed an failure transferring special files from Solaris to Linux. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.5 (28 Dec 2008) ## Changes in this version: ### BUG FIXES: - Initialize xattr data in a couple spots in the hlink code, which avoids a crash when the xattr pointer's memory happens to start out non-zero. Also fixed the itemizing of an alt-dest file's xattrs when hard-linking. - Don't send a bogus `-` option to an older server if there were no short options specified. - Fixed skipping of unneeded updates in a batch file when incremental recursion is active. Added a test for this. Made batch-mode handle `redo` files properly (and without hanging). - Fix the %P logfile escape when the daemon logs from inside a chroot. - Fixed the use of `-s` (`--protect-args`) when used with a remote source or destination that had an empty path (e.g. `host:`). Also fixed a problem when `-s` was used when accessing a daemon via a remote-shell. - Fixed the use of a dot-dir path (e.g. foo/./bar) inside a `--files-from` file when the root of the transfer isn't the current directory. - Fixed a bug with `-K --delete` removing symlinks to directories when incremental recursion is active. - Fixed a hard to trigger hang when using `--remove-source-files`. - Got rid of an annoying delay when accessing a daemon via a remote-shell. - Properly ignore (superfluous) source args on a `--read-batch` command. - Improved the manpage's description of the `*` wildcard to remove the confusing `non-empty` qualifier. - Fixed reverse lookups in the compatibility-library version of getnameinfo(). - Fixed a bug when using `--sparse` on a sparse file that has over 2GB of consecutive sparse data. - Avoid a hang when using at least 3 `--verbose` options on a transfer with a client sender (which includes local copying). - Fixed a problem with `--delete-delay` reporting an error when it was ready to remove a directory that was now gone. - Got rid of a bunch of `warn_unused_result` compiler warnings. - If an ftruncate() on a received file fails, it now causes a partial- transfer warning. - Allow a path with a leading `//` to be preserved (CYGWIN only). ### ENHANCEMENTS: - Made the atomic-rsync script able to perform a fully atomic update of the copied hierarchy when the destination is setup using a particular symlink idiom. (See the support dir.) ------------------------------------------------------------------------------ # NEWS for rsync 3.0.4 (6 Sep 2008) ## Changes in this version: ### BUG FIXES: - Fixed a bug in the hard-linking code where it would sometimes try to allocate 0 bytes of memory (which fails on some OSes, such as AIX). - Fixed the hard-linking of files from a device that has a device number of 0 (which seems to be a common device number on NetBSD). - Fixed the handling of a `--partial-dir` that cannot be created. This particularly impacts the `--delay-updates` option (since the files cannot be delayed without a partial-dir), and was potentially destructive if the `--remove-source-files` was also specified. - Fixed a couple issues in the `--fake-super` handling of xattrs when the destination files have root-level attributes (e.g. selinux values) that a non-root copy can't affect. - Improved the keep-alive check in the generator to fire consistently in incremental-recursion mode when `--timeout` is enabled. - The `--iconv` option now converts the content of a symlink too, instead of leaving it in the wrong character-set (requires 3.0.4 on both sides of the transfer). - When using `--iconv`, if a filename fails to convert on the receiving side, this no longer makes deletions in the root-dir of the transfer fail silently (the user now gets a warning about deletions being disabled due to IO error as long as `--ignore-errors` was not specified). - When using `--iconv`, if a server-side receiver can't convert a filename, the error message sent back to the client no longer mangles the name with the wrong charset conversion. - Fixed a potential alignment issue in the IRIX ACL code when allocating the initial `struct acl` object. Also, cast mallocs to avoid warnings. - Changed some errors that were going to stdout to go to stderr. - Made `human_num()` and `human_dnum()` able to output a negative number (rather than outputting a cryptic string of punctuation). ### ENHANCEMENTS: - Rsync will avoid sending an `-e` option to the server if an older protocol is requested (and thus the option would not be useful). This lets the user specify the `--protocol=29` option to access an overly-restrictive server that is rejecting the protocol-30 use of `-e` to the server. - Improved the message output for an `RERR_PARTIAL` exit. ### DEVELOPER RELATED: - The Makefile will not halt for just a timestamp change on the Makefile or the configure files, only for actual changes in content. - Changed some commands in the testsuite's xattrs.test that called `rsync` instead of `$RSYNC`. - Enhanced the release scripts to be able to handle a branch release and to do even more consistency checks on the files. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.3 (29 Jun 2008) ## Changes in this version: ### BUG FIXES: - Fixed a wildcard matching problem in the daemon when a module has `use chroot` enabled. - Fixed a crash bug in the hard-link code. - Fixed the sending of xattr directory information when the code finds a `--link-dest` or `--copy-dest` directory with unchanged xattrs -- the destination directory now gets these unchanged xattrs properly applied. - Fixed an xattr-sending glitch that could cause an `Internal abbrev` error. - Fixed the combination of `--xattrs` and `--backup`. - The generator no longer allows a '.' dir to be excluded by a daemon-exclude rule. - Fixed deletion handling when copying a single, empty directory (with no files) to a differently named, non-existent directory. - Fixed the conversion of spaces into dashes in the %M log escape. - Fixed several places in the code that were not returning the right errno when a function failed. - Fixed the backing up of a device or special file into a backup dir. - Moved the setting of the socket options prior to the connect(). - If rsync exits in the middle of a `--progress` output, it now outputs a newline to help prevent the progress line from being overwritten. - Fixed a problem with how a destination path with a trailing slash or a trailing dot-dir was compared against the daemon excludes. - Fixed the sending of large (size > 16GB) files when talking to an older rsync (protocols < 30): we now use a compatible block size limit. - If a file's length is so huge that we overflow a checksum buffer count (i.e. several hundred TB), warn the user and avoid sending an invalid checksum struct over the wire. - If a source arg is excluded, `--relative` no longer adds the excluded arg's implied dirs to the transfer. This fix also made the exclude check happen in the better place in the sending code. - Use the `overflow_exit()` function for overflows, not `out_of_memory()`. - Improved the code to better handle a system that has only 32-bit file offsets. ### ENHANCEMENTS: - The rsyncd.conf manpage now consistently refers to the parameters in the daemon config file as `parameters`. - The description of the `--inplace` option was improved. ### EXTRAS: - Added a new script in the support directory, deny-rsync, which allows an admin to (temporarily) replace the rsync command with a script that sends an error message to the remote client via the rsync protocol. ### DEVELOPER RELATED: - Fixed a testcase failure if the tests are run as root and made some compatibility improvements. - Improved the daemon tests, including checking module comments, the listing of files, and the ensuring that daemon excludes can't affect a dot-dir arg. - Improved some build rules for those that build in a separate directory from the source, including better install rules for the manpages, and the fixing of a proto.h-tstamp rule that could make the binaries get rebuild without cause. - Improved the testsuite to work around a problem with some utilities (e.g. `cp -p` & `touch -r`) rounding sub-second timestamps. - Ensure that the early patches don't cause any generated-file hunks to bleed-over into patches that follow. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.2 (8 Apr 2008) ## Changes in this version: ### BUG FIXES: - Fixed a potential buffer overflow in the xattr code. ### ENHANCEMENTS: - None. ### DEVELOPER RELATED: - The RPM spec file was improved to install more useful files. - A few developer-oriented scripts were moved from the support dir to the packaging dir. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.1 (3 Apr 2008) ## Changes in this version: ### NOTABLE CHANGES IN BEHAVIOR: - Added the 'c'-flag to the itemizing of non-regular files so that the itemized output doesn't get hidden if there were no attribute changes, and also so that the itemizing of a `--copy-links` run will distinguish between copying an identical non-regular file and the creation of a revised version with a new value (e.g. a changed symlink referent, a new device number, etc.). ### BUG FIXES: - Fixed a crash bug when a single-use rsync daemon (via remote shell) was run without specifying a `--config=FILE` option. - Fixed a crash when backing up a directory that has a default ACL. - Fixed a bug in the handling of xattr values that could cause rsync to not think that a file's extended attributes are up-to-date. - Fixed the working of `--fake-super` with `--link-dest` and `--xattrs`. - Fixed a hang when combining `--dry-run` with `--remove-source-files`. - Fixed a bug with `--iconv`'s handling of files that cannot be converted: a failed name can no longer cause a transfer failure. - Fixed the building of the rounding.h file on systems that need custom CPPFLAGS to be used. Also improved the error reporting if the building of rounding.h fails. - Fixed the use of the `--protect-args` (`-s`) option when talking to a daemon. - Fixed the `--ignore-existing` option's protection of files on the receiver that are non-regular files on the sender (e.g. if a symlink or a dir on the sender is trying to replace a file on the receiver). The reverse protection (protecting a dir/symlink/device from being replaced by a file) was already working. - Fixed an assert failure if `--hard-links` is combined with an option that can skip a file in a set of hard-linked files (i.e. `--ignore-existing`, `--append`, etc.), without skipping all the files in the set. - Avoid setting the modify time on a directory that already has the right modify time set. This avoids tweaking the dir's ctime. - Improved the daemon-exclude handling to do a better job of applying the exclude rules to path entries. It also sends the user an error just as if the files were actually missing (instead of silently ignoring the user's args), and avoids sending the user the filter-action messages for these non-user-initiated rules. - Fixed some glitches with the dry-run code's missing-directory handling, including a problem when combined with `--fuzzy`. - Fixed some glitches with the skipped-directory handling. - Fixed the 'T'-flag itemizing of symlinks when `--time` isn't preserved. - Fixed a glitch in the itemizing of permissions with the `-E` option. - The `--append` option's restricting of transfers to those that add data no longer prevents the updating of non-content changes to otherwise up-to-date files (i.e. those with the same content but differing permissions, ownership, xattrs, etc.). - Don't allow `--fake-super` to be specified with `-XX` (double `--xattrs`) because the options conflict. If a daemon has `fake super` enabled, it automatically downgrades a `-XX` request to `-X`. - Fixed a couple bugs in the parsing of daemon-config excludes that could make a floating exclude rule get treated as matching an absolute path. - A daemon doesn't try to auto-refuse the `iconv` option if iconv-support wasn't compiled in to the daemon (avoiding a warning in the logs). - Fixed the inclusion of per-dir merge files from implied dirs. - Fixed the rrsync script to work with the latest options that rsync sends, including its flag-specifying use of `-e` to the server. (See the support dir.) ### ENHANCEMENTS: - Added the `--old-dirs` (`--old-d`) option to make it easier for a user to ask for file-listings with older rsync versions (this is easier than having to type `-r --exclude='/*/*'` manually). - When getting an error while asking an older rsync daemon for a file listing, rsync will try to notice if the error is a rejection of the `--dirs` (`-d`) option and let the user know how to work around the issue. - Added a few more `--no-OPTION` overrides. - Improved the documentation of the `--append` option. - Improved the documentation of the filter/exclude/include daemon parameters. ### INTERNAL: - Fixed a couple minor bugs in the included popt library (ones which I sent to the official popt project for inclusion in the 1.14 release). - Fixed a stat() call that should have been `do_stat()` so that the proper normal/64-bit stat() function gets called. (Was in an area that should not have caused problems, though.) - Changed the file-glob code to do a directory scan without using the `glob` and `glob.h`. This lets us do the globbing with less memory churn, and also avoid adding daemon-excluded items to the returned args. ### DEVELOPER RELATED: - The configure script tries to get the user's compiler to not warn about unused function parameters if the build is not including one or more of the ACL/xattrs/iconv features. - The configure script now has better checks for figuring out if the included popt code should be used or not. - Fixed two testsuite glitches: avoid a failure if someone's `cd` command outputs the current directory when cd-ing to a relative path, and made the itemized test query how rsync was built to determine if it should expect hard-linked symlinks or not. - Updated the testsuite to verify that various bug fixes remain fixed. - The RPM spec file was updated to have: (1) comments for how to use the rsync-patch tar file, and (2) an /etc/xinetd.d/rsync file. - Updated the build scripts to work with a revised FTP directory structure. ------------------------------------------------------------------------------ # NEWS for rsync 3.0.0 (1 Mar 2008) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 30. ### NOTABLE CHANGES IN BEHAVIOR: - The handling of implied directories when using `--relative` has changed to send them as directories (e.g. no implied dir is ever sent as a symlink). This avoids unexpected behavior and should not adversely affect most people. If you're one of those rare individuals who relied upon having an implied dir be duplicated as a symlink, you should specify the transfer of the symlink and the transfer of the referent directory as separate args. (See also `--keep-dirlinks` and `--no-implied-dirs`.) Also, exclude rules no longer have a partial effect on implied dirs. - Requesting a remote file-listing without specifying `-r` (`--recursive`) now sends the `-d` (`--dirs`) option to the remote rsync rather than sending `-r` along with an extra exclude of `/*/*`. If the remote rsync does not understand the `-d` option (i.e. it is 2.6.3 or older), you will need to either turn off `-d` (`--no-d`), or specify `-r --exclude='/*/*'` manually. - In `--dry-run` mode, the last line of the verbose summary text is output with a "(DRY RUN)" suffix to help remind you that no updates were made. Similarly, `--only-write-batch` outputs `(BATCH ONLY)`. - A writable rsync daemon with `use chroot` disabled now defaults to a symlink-munging behavior designed to make symlinks safer while also allowing absolute symlinks to be stored and retrieved. This also has the effect of making symlinks unusable while they're in the daemon's hierarchy. See the daemon's `munge symlinks` parameter for details. - Starting up an extra copy of an rsync daemon will not clobber the pidfile for the running daemon -- if the pidfile exists, the new daemon will exit with an error. This means that your wrapper script that starts the rsync daemon should be made to handle lock-breaking (if you want any automatic breaking of locks to be done). ### BUG FIXES: - A daemon with `use chroot = no` and excluded items listed in the daemon config file now properly checks an absolute-path arg specified for these options: `--compare-dest`, `--link-dest`, `--copy-dest`, `--partial-dir`, `--backup-dir`, `--temp-dir`, and `--files-from`. - A daemon can now be told to disable all user- and group-name translation on a per-module basis. This avoids a potential problem with a writable daemon module that has `use chroot` enabled -- if precautions weren't taken, a user could try to add a missing library and get rsync to use it. This makes rsync safer by default, and more configurable when id-translation is not desired. See the daemon's `numeric ids` parameter for full details. - A chroot daemon can now indicate which part of its path should affect the chroot call, and which part should become an inside-chroot path for the module. This allows you to have outside-the-transfer paths (such as for libraries) even when you enable chroot protection. The idiom used in the rsyncd.conf file is: `path = /chroot/dirs/./dirs/inside` - If a file's data arrived successfully on the receiving side but the rename of the temporary file to the destination file failed AND the `--remove-source-files` (or the deprecated `--remove-sent-files`) option was specified, rsync no longer erroneously removes the associated source file. - Fixed the output of `-ii` when combined with one of the `--*-dest` options: it now itemizes all the items, not just the changed ones. - Made the output of all file types consistent when using a `--*-dest` option. Prior versions would output too many creation events for matching items. - The code that waits for a child pid now handles being interrupted by a signal. This fixes a problem with the pre-xfer exec function not being able to get the exit status from the script. - A negated filter rule (i.e. with a '!' modifier) no longer loses the negation when sending the filter rules to the remote rsync. - Fixed a problem with the `--out-format` (aka `--log-format`) option %f: it no longer outputs superfluous directory info for a non-daemon rsync. - Fixed a problem with `-vv` (double `--verbose`) and `--stats` when `pushing` files (which includes local copies). Version 2.6.9 would complete the copy, but exit with an error when the receiver output its memory stats. - If `--password-file` is used on a non-daemon transfer, rsync now complains and exits. This should help users figure out that they can't use this option to control a remote shell's password prompt. - Make sure that directory permissions of a newly-created destination directory are handled right when `--perms` is left off. - The itemized output of a newly-created destination directory is now output as a creation event, not a change event. - Improved `--hard-link` so that more corner cases are handled correctly when combined with options such as `--link-dest` and/or `--ignore-existing`. - The `--append` option no longer updates a file that has the same size. - Fixed a bug when combining `--backup` and `--backup-dir` with `--inplace`: any missing backup directories are now created. - Fixed a bug when using `--backup` and `--inplace` with `--whole-file` or `--read-batch`: backup files are actually created now. - The daemon pidfile is checked and created sooner in the startup sequence. - If a daemon module's `path` value is not an absolute pathname, the code now makes it absolute internally (making it work properly). - Ensure that a temporary file always has owner-write permission while we are writing to it. This avoids problems with some network filesystems when transferring read-only files. - Any errors output about password-file reading no longer cause an error at the end of the run about a partial transfer. - The `--read-batch` option for protocol 30 now ensures that several more options are set correctly for the current batch file: `--iconv`, `--acls`, `--xattrs`, `--inplace`, `--append`, and `--append-verify`. - Using `--only-write-batch` to a daemon receiver now works properly (older versions would update some files while writing the batch). - Avoid outputting a "file has vanished" message when the file is a broken symlink and `--copy-unsafe-links` or `--copy-dirlinks` is used (the code already handled this for `--copy-links`). - Fixed the combination of `--only-write-batch` and `--dry-run`. - Fixed rsync's ability to remove files that are not writable by the file's owner when rsync is running as the same user. - When transferring large files, the sender's hashtable of checksums is kept at a more reasonable state of fullness (no more than 80% full) so that the scanning of the hashtable will not bog down as the number of blocks increases. ### ENHANCEMENTS: - A new incremental-recursion algorithm is now used when rsync is talking to another 3.x version. This starts the transfer going more quickly (before all the files have been found), and requires much less memory. See the `--recursive` option in the manpage for some restrictions. - Lowered memory use in the non-incremental-recursion algorithm for typical option values (usually saving from 21-29 bytes per file). - The default `--delete` algorithm is now `--delete-during` when talking to a 3.x rsync. This is a faster scan than using `--delete-before` (which is the default when talking to older rsync versions), and is compatible with the new incremental recursion mode. - Rsync now allows multiple remote-source args to be specified rather than having to rely on a special space-splitting side-effect of the remote- shell. Additional remote args must specify the same host or an empty one (e.g. empty: `:file1` or `::module/file2`). For example, this means that local use of brace expansion now works: `rsync -av host:dir/{f1,f2} .` - Added the `--protect-args` (`-s`) option, that tells rsync to send most of the command-line args at the start of the transfer rather than as args to the remote-shell command. This protects them from space-splitting, and only interprets basic wildcard special shell characters (`*?[`). - Added the `--delete-delay` option, which is a more efficient way to delete files at the end of the transfer without needing a separate delete pass. - Added the `--acls` (`-A`) option to preserve Access Control Lists. This is an improved version of the prior patch that was available, and it even supports OS X ACLs. If you need to have backward compatibility with old, ACL-patched versions of rsync, apply the acls.diff file from the patches dir. - Added the `--xattrs` (`-X`) option to preserve extended attributes. This is an improved version of the prior patch that was available, and it even supports OS X xattrs (which includes their resource fork data). If you need to have backward compatibility with old, xattr-patched versions of rsync, apply the xattrs.diff file from the patches dir. - Added the `--fake-super` option that allows a non-super user to preserve all attributes of a file by using a special extended-attribute idiom. It even supports the storing of foreign ACL data on your backup server. There is also an analogous `fake super` parameter for an rsync daemon. - Added the `--iconv` option, which allows rsync to convert filenames from one character-set to another during the transfer. The default is to make this feature available as long as your system has `iconv_open()`. If compilation fails, specify `--disable-iconv` to configure, and then rebuild. If you want rsync to perform character-set conversions by default, you can specify `--enable-iconv=CONVERT_STRING` with the default value for the `--iconv` option that you wish to use. For example, `--enable-iconv=.` is a good choice. See the rsync manpage for an explanation of the `--iconv` option's settings. - A new daemon config parameter, `charset`, lets you control the character- set that is used during an `--iconv` transfer to/from a daemon module. You can also set your daemon to refuse `no-iconv` if you want to force the client to use an `--iconv` transfer (requiring an rsync 3.x client). - Added the `--skip-compress=LIST` option to override the default list of file suffixes that will not be compressed when using `--compress` (`-z`). - The daemon's default for `dont compress` was extended to include: `*.7z` `*.mp[34]` `*.mov` `*.avi` `*.ogg` `*.jpg` `*.jpeg` and the name-matching routine was also optimized to run more quickly. - The `--max-delete` option now outputs a warning if it skipped any file deletions, including a count of how many deletions were skipped. (Older versions just silently stopped deleting things.) - You may specify `--max-delete=0` to a 3.0.0 client to request that it warn about extraneous files without deleting anything. If you're not sure what version the client is, you can use the less-obvious `--max-delete=-1`, as both old and new versions will treat that as the same request (though older versions don't warn). - The `--hard-link` option now uses less memory on both the sending and receiving side for all protocol versions. For protocol 30, the use of a hashtable on the sending side allows us to more efficiently convey to the receiver what files are linked together. This reduces the amount of data sent over the socket by a considerable margin (rather than adding more data), and limits the in-memory storage of the device+inode information to just the sending side for the new protocol 30, or to the receiving side when speaking an older protocol (note that older rsync versions kept the device+inode information on both sides). - The filter rules now support a perishable (`p`) modifier that marks rules that should not have an effect in a directory that is being deleted. e.g. `-f '-p .svn/'` would only affect `live` .svn directories. - Rsync checks all the alternate-destination args for validity (e.g. `--link-dest`). This lets the user know when they specified a directory that does not exist. - If we get an ENOSYS error setting the time on a symlink, we don't complain about it anymore (for those systems that even support the setting of the modify-time on a symlink). - Protocol 30 now uses MD5 checksums instead of MD4. - Changed the `--append` option to not checksum the existing data in the destination file, which speeds up file appending. - Added the `--append-verify` option, which works like the older `--append` option (verifying the existing data in the destination file). For compatibility with older rsync versions, any use of `--append` that is talking protocol 29 or older will revert to the `--append-verify` method. - Added the `--contimeout=SECONDS` option that lets the user specify a connection timeout for rsync daemon access. - Documented and extended the support for the `RSYNC_CONNECT_PROG` variable that can be used to enhance the client side of a daemon connection. - Improved the dashes and double-quotes in the nroff manpage output. - Rsync now supports a lot more `--no-OPTION` override options. ### INTERNAL: - The file-list sorting algorithm now uses a sort that keeps any same-named items in the same order as they were specified. This allows rsync to always ensure that the first of the duplicates is the one that will be included in the copy. The new sort is also faster than the glibc version of qsort() and mergesort(). - Rsync now supports the transfer of 64-bit timestamps (`time_t` values). - Made the file-deletion code use a little less stack when recursing through a directory hierarchy of extraneous files. - Fixed a build problem with older (2.x) versions of gcc. - Added some isType() functions that make dealing with signed characters easier without forcing variables via casts. - Changed strcat/strcpy/sprintf function calls to use safer versions. - Upgraded the included popt version to 1.10.2 and improved its use of string-handling functions. - Added missing prototypes for compatibility functions from the lib dir. - Configure determines if iconv() has a const arg, allowing us to avoid a compiler warning. - Made the sending of some numbers more efficient for protocol 30. - Make sure that a daemon process doesn't mind if the client was weird and omitted the `--server` option. - There are more internal logging categories available in protocol 30 than the age-old FINFO and FERROR, including `FERROR_XFER` and FWARN. These new categories allow some errors and warnings to go to stderr without causing an erroneous end-of-run warning about some files not being able to be transferred. - Improved the use of `const` on pointers. - Improved J.W.'s `pool_alloc` routines to add a way of incrementally freeing older sections of a pool's memory. - The getaddrinfo.c compatibility code in the `lib` dir was replaced with some new code (derived from samba, derived from PostgreSQL) that has a better license than the old code. ### DEVELOPER RELATED: - Rsync is now licensed under the GPLv3 or later. - Rsync is now being maintained in a `git` repository instead of CVS (though the old CVS repository still exists for historical access). Several maintenance scripts were updated to work with git. - Generated files are no longer committed into the source repository. The autoconf and autoheader commands are now automatically run during the normal use of `configure` and `make`. The latest dev versions of all generated files can also be copied from the samba.org web site (see the prepare-source script's fetch option). - The `patches` directory of diff files is now built from branches in the rsync git repository (branch patch/FOO creates file patches/FOO.diff). This directory is now distributed in a separate separate tar file named rsync-patches-VERSION.tar.gz instead of the main rsync-VERSION.tar.gz. - The proto.h file is now built using a simple perl script rather than a complex awk script, which proved to be more widely compatible. - When running the tests, we now put our per-test temp dirs into a sub- directory named testtmp (which is created, if missing). This allows someone to symlink the testtmp directory to another filesystem (which is useful if the build dir's filesystem does not support ACLs and xattrs, but another filesystem does). - Rsync now has a way of handling protocol-version changes during the development of a new protocol version. This causes any out-of-sync versions to speak an older protocol rather than fail in a cryptic manner. This addition makes it safer to deploy a pre-release version that may interact with the public. This new exchange of sub-version info does not interfere with the `{MIN,MAX}_PROTOCOL_VERSION` checking algorithm (which does not have enough range to allow the main protocol number to be incremented for every minor tweak in that happens during development). - The csprotocol.txt file was updated to mention the daemon protocol change in the 3.0.0 release. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.9 (6 Nov 2006) ## Changes in this version: ### BUG FIXES: - If rsync is interrupted via a handled signal (such as SIGINT), it will once again clean-up its temp file from the destination dir. - Fixed an overzealous sanitizing bug in the handling of the `--link-dest`, `--copy-dest`, and `--compare-dest` options to a daemon without chroot: if the copy's destination dir is deeper than the top of the module's path, these options now accept a safe number of parent-dir (../) references (since these options are relative to the destination dir). The old code incorrectly chopped off all `../` prefixes for these options, no matter how deep the destination directory was in the module's hierarchy. - Fixed a bug where a deferred info/error/log message could get sent directly to the sender instead of being handled by rwrite() in the generator. This fixes an `unexpected tag 3` fatal error, and should also fix a potential problem where a deferred info/error message from the receiver might bypass the log file and get sent only to the client process. (These problems could only affect an rsync daemon that was receiving files.) - Fixed a bug when `--inplace` was combined with a `--*-dest` option and we update a file's data using an alternate basis file. The code now notices that it needs to copy the matching data from the basis file instead of (wrongly) assuming that it was already present in the file. - Fixed a bug where using `--dry-run` with a `--*-dest` option with a path relative to a directory that does not yet exist: the affected option gets its proper path value so that the output of the dry-run is right. - Fixed a bug in the %f logfile escape when receiving files: the destination path is now included in the output (e.g. you can now tell when a user specifies a subdir inside a module). - If the receiving side fails to create a directory, it will now skip trying to update everything that is inside that directory. - If `--link-dest` is specified with `--checksum` but without `--times`, rsync will now allow a hard-link to be created to a matching link-dest file even when the file's modify-time doesn't match the server's file. - The daemon now calls more timezone-using functions prior to doing a chroot. This should help some C libraries to generate proper timestamps from inside a chrooted daemon (and to not try to access /etc/timezone over and over again). - Fixed a bug in the handling of an absolute `--partial-dir=ABS_PATH` option: it now deletes an alternate basis file from the partial-dir that was used to successfully update a destination file. - Fixed a bug in the handling of `--delete-excluded` when using a per-dir merge file: the merge file is now honored on the receiving side, and only its unqualified include/exclude commands are ignored (just as is done for global include/excludes). - Fixed a recent bug where `--delete` was not working when transferring from the root (/) of the filesystem with `--relative` enabled. - Fixed a recent bug where an `--exclude='*'` could affect the root (/) of the filesystem with `--relative` enabled. - When `--inplace` creates a file, it is now created with owner read/write permissions (0600) instead of no permissions at all. This avoids a problem continuing a transfer that was interrupted (since `--inplace` will not update a file that has no write permissions). - If either `--remove-source-files` or `--remove-sent-files` is enabled and we are unable to remove the source file, rsync now outputs an error. - Fixed a bug in the daemon's `incoming chmod` rule: newly-created directories no longer get the 'F' (file) rules applied to them. - Fixed an infinite loop bug when a filter rule was rejected due to being overly long. - When the server receives a `--partial-dir` option from the client, it no longer runs the client-side code that adds an assumed filter rule (since the client will be sending us the rules in the usual manner, and they may have chosen to override the auto-added rule). ### ENHANCEMENTS: - Added the `--log-file=FILE` and `--log-file-format=FORMAT` options. These can be used to tell any rsync to output what it is doing to a log file. They work with a client rsync, a non-daemon server rsync (see the manpage for instructions), and also allows the overriding of rsyncd.conf settings when starting a daemon. - The `--log-format` option was renamed to be `--out-format` to avoid confusing it with affecting the log-file output. (The old option remains as an alias for the new to preserve backward compatibility.) - Made `log file` and `syslog facility` settable on a per-module basis in the daemon's config file. - Added the `--remove-source-files` option as a replacement for the (now deprecated) `--remove-sent-files` option. This new option removes all non-dirs from the source directories, even if the file was already up-to-date. This fixes a problem where interrupting an rsync that was using `--remove-sent-files` and restarting it could leave behind a file that the earlier rsync synchronized, but didn't get to remove. (The deprecated `--remove-sent-files` is still understood for now, and still behaves in the same way as before.) - Added the option `--no-motd` to suppress the message-of-the-day output from a daemon when doing a copy. (See the manpage for a caveat.) - Added a new environment variable to the pre-/post-xfer exec commands (in the daemon's config file): `RSYNC_PID`. This value will be the same in both the pre- and post-xfer commands, so it can be used as a unique ID if the pre-xfer command wants to cache some arg/request info for the post-xfer command. ### INTERNAL: - Did a code audit using IBM's code-checker program and made several changes, including: replacing most of the strcpy() and sprintf() calls with strlcpy(), snprintf(), and memcpy(), adding a 0-value to an enum that had been intermingling a literal 0 with the defined enum values, silencing some uninitialized memory checks, marking some functions with a `noreturn` attribute, and changing an `if` that could never succeed on some platforms into a pre-processor directive that conditionally compiles the code. - Fixed a potential bug in `f_name_cmp()` when both the args are a top-level `.` dir (which doesn't happen in normal operations). - Changed `exit_cleanup()` so that it can never return instead of exit. The old code might return if it found the `exit_cleanup()` function was being called recursively. The new code is segmented so that any recursive calls move on to the next step of the exit-processing. - The macro WIFEXITED(stat) will now be defined if the OS didn't already define it. ### DEVELOPER RELATED: - The acls.diff and xattrs.diff patches have received a bunch of work to make them much closer to being acceptable in the main distribution. The xattrs patch also has some preliminary Mac OS X and FreeBSD compatibility code that various system types to exchange extended file-attributes. - A new diff in the patches dir, fake-root.diff, allows rsync to maintain a backup hierarchy with full owner, group, and device info without actually running as root. It does this using a special extended attribute, so it depends on xattrs.diff (which depends on acls.diff). - The rsync.yo and rsyncd.conf.yo files have been updated to work better with the latest yodl 2.x releases. - Updated config.guess and config.sub to their 2006-07-02 versions. - Updated various files to include the latest FSF address and to have consistent opening comments. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.8 (22 Apr 2006) ## Changes in this version: ### BUG FIXES: - Fixed a bug in the exclude code where an anchored exclude without any wildcards fails to match an absolute source arg, but only when `--relative` is in effect. - Improved the I/O code for the generator to fix a potential hang when the receiver gets an EOF on the socket but the generator's select() call never indicates that the socket is writable for it to be notified about the EOF. (This can happen when using stunnel). - Fixed a problem with the file-reading code where a failed read (such as that caused by a bad sector) would not advance the file's read-position beyond the failed read's data. - Fixed a logging bug where the `log file` directive was not being honored in a single-use daemon (one spawned by a remote-shell connection or by init). - If rsync cannot honor the `--delete` option, we output an error and exit instead of silently ignoring the option. - Fixed a bug in the `--link-dest` code that prevented special files (such as fifos) from being linked. - The ability to hard-link symlinks and special files is now determined at configure time instead of at runtime. This fixes a bug with `--link-dest` creating a hard-link to a symlink's referent on a BSD system. ### ENHANCEMENTS: - In daemon mode, if rsync fails to bind to the requested port, the error(s) returned by socket() and/or bind() are now logged. - When we output a fatal error, we now output the version of rsync in the message. - Improved the documentation for the `--owner` and `--group` options. - The rsyncstats script in `support` has an improved line-parsing regex that is easier to read and also makes it to parse syslog-generated lines. - A new script in `support`: file-attr-restore, can be used to restore the attributes of a file-set (the permissions, ownership, and group info) taken from the cached output of a `find ARG... -ls` command. ### DEVELOPER RELATED: - Removed the unused function `write_int_named()`, the unused variable `io_read_phase`, and the rarely used variable `io_write_phase`. This also elides the confusing 'phase "unknown"' part of one error message. - Removed two unused configure checks and two related (also unused) compatibility functions. - The xattrs.diff patch received a security fix that prevents a potential buffer overflow in the `receive_xattr()` code. - The acls.diff patch has been improved quite a bit, with more to come. - A new patch was added: log-file.diff. This contains an early version of a future option, `--log-file=FILE`, that will allow any rsync to log its actions to a file (something that only a daemon supports at present). ------------------------------------------------------------------------------ # NEWS for rsync 2.6.7 (11 Mar 2006) ## Changes in this version: ### OUTPUT CHANGES: - The letter 'D' in the itemized output was being used for both devices (character or block) as well as other special files (such as fifos and named sockets). This has changed to separate non-device special files under the 'S' designation (e.g. `cS+++++++ path/fifo`). See also the `--specials` option, below. - The way rsync escapes unreadable characters has changed. First, rsync now has support for recognizing valid multi-byte character sequences in your current locale, allowing it to escape fewer characters than before for a locale such as UTF-8. Second, it now uses an escape idiom of `\#123`, which is the literal string `\#` followed by exactly 3 octal digits. Rsync no longer doubles a backslash character in a filename (e.g. it used to output `foo\\bar` when copying `foo\bar`) -- now it only escapes a backslash that is followed by a hash-sign and 3 digits (0-9) (e.g. it will output `foo\#134#789` when copying `foo\#789`). See also the `--8-bit-output` (`-8`) option, mentioned below. Script writers: the local rsync is the one that outputs escaped names, so if you need to support unescaping of filenames for older rsyncs, I'd suggest that you parse the output of `rsync --version` and only use the old unescaping rules for 2.6.5 and 2.6.6. ### BUG FIXES: - Fixed a really old bug that caused `--checksum` (`-c`) to checksum all the files encountered during the delete scan (ouch). - Fixed a potential hang in a remote generator: when the receiver gets a read-error on the socket, it now signals the generator about this so that the generator does not try to send any of the terminating error messages to the client (avoiding a potential hang in some setups). - Made hard-links work with symlinks and devices again. - If the sender gets an early EOF reading a source file, we propagate this error to the receiver so that it can discard the file and try requesting it again (which is the existing behavior for other kinds of read errors). - If a device-file/special-file changes permissions, rsync now updates the permissions without recreating the file. - If the user specifies a remote-host for both the source and destination, we now output a syntax error rather than trying to open the destination hostspec as a filename. - When `--inplace` creates a new destination file, rsync now creates it with permissions 0600 instead of 0000 -- this makes restarting possible when the transfer gets interrupted in the middle of sending a new file. - Reject the combination of `--inplace` and `--sparse` since the sparse-output algorithm doesn't work when overwriting existing data. - Fixed the directory name in the error that is output when `pop_dir()` fails. - Really fixed the parsing of a `!` entry in .cvsignore files this time. - If the generator gets a stat() error on a file, output it (this used to require at least `-vv` for the error to be seen). - If waitpid() fails or the child rsync didn't exit cleanly, we now handle the exit status properly and generate a better error. - Fixed some glitches in the double-verbose output when using `--copy-dest`, `--link-dest`, or `--compare-dest`. Also improved how the verbose output handles hard-links (within the transfer) that had an up-to-date alternate `dest` file, and copied files (via `--copy-dest`). - Fixed the matching of the dont-compress items (e.g. `*.gz`) against files that have a path component containing a slash. - If the code reading a filter/exclude file gets an EINTR error, rsync now clears the error flag on the file handle so it can keep on reading. - If `--relative` is active, the sending side cleans up trailing `/` or `/.` suffixes to avoid triggering a bug in older rsync versions. Also, we now reject a `..` dir if it would be sent as a relative dir. - If a non-directory is in the way of a directory and rsync is run with `--dry-run` and `--delete`, rsync no longer complains about not being able to opendir() the not-yet present directory. - When `--list-only` is used and a non-existent local destination dir was also specified as a destination, rsync no longer generates a warning about being unable to create the missing directory. - Fixed some problems with `--relative --no-implied-dirs` when the destination directory did not yet exist: we can now create a symlink or device when it is the first thing in the missing dir, and `--fuzzy` no longer complains about being unable to open the missing dir. - Fixed a bug where the `--copy-links` option would not affect implied directories without `--copy-unsafe-links` (see `--relative`). - Got rid of the need for `--force` to be used in some circumstances with `--delete-after` (making it consistent with `--delete-before`/`--delete-during`). - Rsync now ignores the SIGXFSZ signal, just in case your OS sends this when a file is too large (rsync handles the write error). - Fixed a bug in the Proxy-Authorization header's base64-encoded value: it was not properly padded with trailing '=' chars. This only affects a user that need to use a password-authenticated proxy for an outgoing daemon-rsync connection. - If we're transferring an empty directory to a new name, rsync no longer forces `S_IWUSR` if it wasn't already set, nor does it accidentally leave it set. - Fixed a bug in the debug output (`-vvvvv`) that could mention the wrong checksum for the current file offset. - Rsync no longer allows a single directory to be copied over a non-directory destination arg. ### ENHANCEMENTS: - Added the `--append` option that makes rsync append data onto files that are longer on the source than the destination (this includes new files). - Added the `--min-size=SIZE` option to exclude small files from the transfer. - Added the `--compress-level` option to allow you to set how aggressive rsync's compression should be (this option implies `--compress`). - Enhanced the parsing of the SIZE value for `--min-size` and `--max-size` to allow easy entry of multiples of 1000 (instead of just multiples of 1024) and off-by-one values too (e.g. `--max-size=8mb-1`). - Added the `--8-bit-output` (`-8`) option, which tells rsync to avoid escaping high-bit characters that it thinks are unreadable in the current locale. - The new option `--human-readable` (`-h`) changes the output of `--progress`, `--stats`, and the end-of-run summary to be easier to read. If repeated, the units become powers of 1024 instead of powers of 1000. (The old meaning of `-h`, as a shorthand for `--help`, still works as long as you just use it on its own, as in `rsync -h`.) - If lutimes() and/or lchmod() are around, use them to allow the preservation of attributes on symlinks. - The `--link-dest` option now affects symlinks and devices (when possible). - Added two config items to the rsyncd.conf parsing: `pre-xfer exec` and `post-xfer exec`. These allow a command to be specified on a per-module basis that will be run before and/or after a daemon-mode transfer. (See the manpage for a list of the environment variables that are set with information about the transfer.) - When using the `--relative` option, you can now insert a dot dir in the source path to indicate where the replication of the source dirs should start. For example, if you specify a source path of rsync://host/module/foo/bar/./baz/dir with `-R`, rsync will now only replicate the `baz/dir` part of the source path (note: a trailing dot dir is unaffected unless it also has a trailing slash). - Added some new `--no-FOO` options that make it easier to override unwanted implied or default options. For example, `-a --no-o` (aka `--archive --no-owner`) can be used to turn off the preservation of file ownership that is implied by `-a`. - Added the `--chmod=MODE` option that allows the destination permissions to be changed from the source permissions. E.g. `--chmod=g+w,o-rwx` - Added the `incoming chmod` and `outgoing chmod` daemon options that allow a module to specify what permissions changes should be applied to all files copied to and from the daemon. - Allow the `--temp-dir` option to be specified when starting a daemon, which sets the default temporary directory for incoming files. - If `--delete` is combined with `--dirs` without `--recursive`, rsync will now delete in any directory whose content is being synchronized. - If `--backup` is combined with `--delete` without `--backup-dir` (and without `--delete-excluded`), we add a `protect` filter-rule to ensure that files with the backup suffix are not deleted. - The file-count stats that are output by `--progress` were improved to better indicate what the numbers mean. For instance, the output: `(xfer#5, to-check=8383/9999)` indicates that this was the fifth file to be transferred, and we still need to check 8383 more files out of a total of 9999. - The include/exclude code now allows a `dir/***` directive (with 3 trailing stars) to match both the dir itself as well as all the content below the dir (`dir/**` would not match the dir). - Added the `--prune-empty-dirs` (`-m`) option that makes the receiving rsync discard empty chains of directories from the file-list. This makes it easier to selectively copy files from a source hierarchy and end up with just the directories needed to hold the resulting files. - If the `--itemize-changes` (`-i`) option is repeated, rsync now includes unchanged files in the itemized output (similar to `-vv`, but without all the other verbose messages that can get in the way). Of course, the client must be version 2.6.7 for this to work, but the remote rsync only needs to be 2.6.7 if you're pushing files. - Added the `--specials` option to tell rsync to copy non-device special files (which rsync now attempts even as a normal user). The `--devices` option now requests the copying of just devices (character and block). The `-D` option still requests both (e.g. `--devices` and `--specials`), `-a` still implies `-D`, and non-root users still get a silent downgrade that omits device copying. - Added the `--super` option to make the receiver always attempt super-user activities. This is useful for systems that allow things such as devices to be created or ownership to be set without being UID 0, and is also useful for someone who wants to ensure that errors will be output if the receiving rsync isn't being run as root. - Added the `--sockopts` option for those few who want to customize the TCP options used to contact a daemon rsync. - Added a way for the `--temp-dir` option to be combined with a partial-dir setting that lets rsync avoid non-atomic updates (for those times when `--temp-dir` is not being used because space is tight). - A new support script, files-to-excludes, will transform a list of files into a set of include/exclude directives that will copy those files. - A new option, `--executability` (`-E`) can be used to preserve just the execute bit on files, for those times when using the `--perms` option is not desired. - The daemon now logs each connection and also each module-list request that it receives. - New log-format options: %M (modtime), %U (uid), %G (gid), and %B (permission bits, e.g. `rwxr-xrwt`). - The `--dry-run` option no longer forces the enabling of `--verbose`. - The `--remove-sent-files` option now does a better job of incrementally removing the sent files on the sending side (older versions tended to clump up all the removals at the end). - A daemon now supersedes its minimal SIGCHLD handler with the standard PID-remembering version after forking. This ensures that the generator can get the child-exit status from the receiver. - Use of the `--bwlimit` option no longer interferes with the remote rsync sending error messages about invalid/refused options. - Rsync no longer returns a usage error when used with one local source arg and no destination: this now implies the `--list-only` option, just like the comparable situation with a remote source arg. - Added the `--copy-dirlinks` option, a more limited version of `--copy-links`. - Various documentation improvements, including: a better synopsis, some improved examples, a better discussion of the presence and absence of `--perms` (including how it interacts with the new `--executability` and `--chmod` options), an extended discussion of `--temp-dir`, an improved discussion of `--partial-dir`, a better description of rsync's pattern matching characters, an improved `--no-implied-dirs` section, and the documenting of what the `--stats` option outputs. - Various new and updated diffs in the patches dir, including: acls.diff, xattrs.diff, atimes.diff, detect-renamed.diff, and slp.diff. ### INTERNAL: - We now use sigaction() and sigprocmask() if possible, and fall back on signal() if not. Using sigprocmask() ensures that rsync enables all the signals that it needs, just in case it was started in a masked state. - Some buffer sizes were expanded a bit, particularly on systems where MAXPATHLEN is overly small (e.g. Cygwin). - If `io_printf()` tries to format more data than fits in the buffer, exit with an error instead of transmitting a truncated buffer. - If a `va_copy` macro is defined, lib/snprintf.c will use it when defining the `VA_COPY` macro. - Reduced the amount of stack memory needed for each level of directory recursion by nearly MAXPATHLEN bytes. - The wildmatch function was extended to allow an array of strings to be supplied as the string to match. This allows the exclude code to do less string copying. - Got rid of the `safe_fname()` function (and all the myriad calls) and replaced it with a new function in the log.c code that filters all the output going to the terminal. - Unified the `f_name()` and the `f_name_to()` functions. - Improved the hash-table code the sender uses to handle checksums to make it use slightly less memory and run just a little faster. ### DEVELOPER RELATED: - The diffs in the patches dir now require `patch -p1 high` in `clean_flist()` was wrong for an empty list. This could cause `flist_find()` to crash in certain rare circumstances (e.g. if just the right directory setup was around when `--fuzzy` was combined with `--link-dest`). - The outputting of hard-linked files when verbosity was > 1 was not right: (1) Without `-i` it would output the name of each hard-linked file as though it had been changed; it now outputs a `is hard linked` message for the file. (2) With `-i` it would output all dots for the unchanged attributes of a hard-link; it now changes those dots to spaces, as is done for other totally unchanged items. - When backing up a changed symlink or device, get rid of any old backup item so that we don't get an `already exists` error. - A couple places that were comparing a local and a remote modification-time were not honoring the `--modify-window` option. - Fixed a bug where the 'p' (permissions) itemized-changes flag might get set too often (if some non-significant mode bits differed). - Fixed a really old, minor bug that could cause rsync to warn about being unable to mkdir() a path that ends in `/.` because it just created the directory (required `--relative`, `--no-implied-dirs`, a source path that ended in either a trailing slash or a trailing `/.`, and a non-existing destination dir to tickle the bug in a recent version). ### ENHANCEMENTS: - Made the `max verbosity` setting in the rsyncd.conf file settable on a per-module basis (which now matches the documentation). - The rrsync script has been upgraded to verify the args of options that take args (instead of rejecting any such options). It was also changed to try to be more secure and to fix a problem in the parsing of a pull operation that has multiple source args. (See the support dir.) - Improved the documentation that explains the difference between a normal daemon transfer and a daemon-over remote-shell transfer. - Some of the diffs supplied in the patches dir were fixed and/or improved. ### BUILD CHANGES: - Made configure define `NOBODY_USER` (currently hard-wired to `nobody`) and `NOBODY_GROUP` (set to either `nobody` or `nogroup` depending on what we find in the /etc/group file). - Added a test to the test suite, itemized.test, that tests the output of `-i` (log-format w/%i) and some double-verbose messages. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.5 (1 Jun 2005) ## Changes in this version: ### OUTPUT CHANGES: - Non-printable chars in filenames are now output using backslash-escaped characters rather than '?'s. Any non-printable character is output using 3 digits of octal (e.g. `\n` -> `\012`), and a backslash is now output as `\\`. Rsync also uses your locale setting, which can make it treat fewer high-bit characters as non-printable. - If rsync received an empty file-list when pulling files, it would output a `nothing to do` message and exit with a 0 (success) exit status, even if the remote rsync returned an error (it did not do this under the same conditions when pushing files). This was changed to make the pulling behavior the same as the pushing behavior: we now do the normal end-of-run outputting (depending on options) and exit with the appropriate exit status. ### BUG FIXES: - A crash bug was fixed when a daemon had its `path` set to `/`, did not have chroot enabled, and used some anchored excludes in the rsyncd.conf file. - Fixed a bug in the transfer of a single file when `-H` is specified (rsync would either infinite loop or perhaps crash). - Fixed a case where the generator might try (and fail) to tweak the write-permissions of a read-only directory in list-only mode (this only caused an annoying warning message). - If `--compare-dest` or `--link-dest` uses a locally-copied file as the basis for an updated version, log this better when `--verbose` or `-i` is in effect. - Fixed the accidental disabling of `--backup` during the `--delete-after` processing. - Restored the ability to use the `--address` option in client mode (in addition to its use in daemon mode). - Make sure that some temporary progress information from the delete processing does not get left on the screen when it is followed by a newline. - When `--existing` skips a directory with extra verbosity, refer to it as a `directory`, not a `file`. - When transferring a single file to a different-named file, any generator messages that are source-file related no longer refer to the file by the destination filename. - Fixed a bug where hard-linking a group of files might fail if the generator hasn't created a needed destination directory yet. - Fixed a bug where a hard-linked group of files that is newly-linked to a file in a `--link-dest` dir doesn't link the files from the rest of the cluster. - When deleting files with the `--one-file-system` (`-x`) option set, rsync no longer tries to remove files from inside a mount-point on the receiving side. Also, we don't complain about being unable to remove the mount-point dir. - Fixed a compatibility problem when using `--cvs-ignore` (`-C`) and sending files to an older rsync without using `--delete`. - Make sure that a `- !` or `+ !` include/exclude pattern does not trigger the list-clearing action that is reserved for `!`. - Avoid a timeout in the generator when the sender/receiver aren't handling the generator's checksum output quickly enough. - Fixed the omission of some directories in the delete processing when `--relative` (`-R`) was combined with a source path that had a trailing slash. - Fixed a case where rsync would erroneously delete some files and then re-transfer them when the options `--relative` (`-R`) and `--recursive` (`-r`) were both enabled (along with `--delete`) and a source path had a trailing slash. - Make sure that `--max-size` doesn't affect a device or a symlink. - Make sure that a system with a really small MAXPATHLEN does not cause the buffers in `readfd_unbuffered()` to be too small to receive normal messages. (This mainly affected Cygwin.) - If a source pathname ends with a filename of `..`, treat it as if `../` had been specified (so that we don't copy files to the parent dir of the destination). - If `--delete` is combined with a file-listing rsync command (i.e. no transfer is happening), avoid outputting a warning that we couldn't delete anything. - If `--stats` is specified with `--delete-after`, ensure that all the `deleting` messages are output before the statistics. - Improved one `if` in the deletion code that was only checking errno for ENOTEMPTY when it should have also been checking for EEXIST (for compatibility with OS variations). ### ENHANCEMENTS: - Added the `--only-write-batch=FILE` option that may be used (instead of `--write-batch=FILE`) to create a batch file without doing any actual updating of the destination. This allows you to divert all the file-updating data away from a slow data link (as long as you are pushing the data to the remote server when creating the batch). - When the generator is taking a long time to fill up its output buffer (e.g. if the transferred files are few, small, or missing), it now periodically flushes the output buffer so that the sender/receiver can get started on the files sooner rather than later. - Improved the keep-alive code to handle a long silence between the sender and the receiver that can occur when the sender is receiving the checksum data for a large file. - Improved the auth-errors that are logged by the daemon to include some information on why the authorization failed: wrong user, password mismatch, etc. (The client-visible message is unchanged!) - Improved the client's handling of an `@ERROR` from a daemon so that it does not complain about an unexpectedly closed socket (since we really did expect the socket to close). - If the daemon can't open the log-file specified in rsyncd.conf, fall back to using syslog and log an appropriate warning. This is better than what was typically a totally silent (and fatal) failure (since a daemon is not usually run with the `--no-detach` option that was necessary to see the error on stderr). - The manpages now consistently refer to an rsync daemon as a `daemon` instead of a `server` (to distinguish it from the server process in a non-daemon transfer). - Made a small change to the rrsync script (restricted rsync -- in the support dir) to make a read-only server reject all `--remove-*` options when sending files (to future-proof it against the possibility of other similar options being added at some point). ### INTERNAL: - Rsync now calls `setlocale(LC_CTYPE, "")`. This enables isprint() to better discern which filename characters need to be escaped in messages (which should result in fewer escaped characters in some locales). - Improved the naming of the log-file open/reopen/close functions. - Removed some protocol-compatibility code that was only needed to help someone running a pre-release of 2.6.4. ### BUILD CHANGES: - Added configure option `--disable-locale` to disable any use of setlocale() in the binary. - Fixed a bug in the `SUPPORT{,_HARD}_LINKS` #defines which prevented rsync from being built without symlink or hard-link support. - Only #define `HAVE_REMSH` if it is going to be set to 1. - Configure now disables the use of mkstemp() under HP-UX (since they refuse to fix its broken handling of large files). - Configure now explicitly checks for the lseek64() function so that the code can use `HAVE_LSEEK64` instead of inferring lseek64()'s presence based on the presence of the `off64_t` type. - Configure no longer mentions the change in the default remote-shell (from rsh to ssh) that occurred for the 2.6.0 release. - Some minor enhancements to the test scripts. - Added a few new `*.diff` files to the patches dir, including a patch that enables the optional copying of extended attributes. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.4 (30 March 2005) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 29. ### OUTPUT CHANGES: - When rsync deletes a directory and outputs a verbose message about it, it now appends a trailing slash to the name instead of (only sometimes) outputting a preceding "directory " string. - The `--stats` output will contain file-list time-statistics if both sides are 2.6.4, or if the local side is 2.6.4 and the files are being pushed (since the stats come from the sending side). (Requires protocol 29 for a pull.) - The `%o` (operation) log-format escape now has a third value (besides `send` and `recv`): `del.` (with trailing dot to make it 4 chars). This changes the way deletions are logged in the daemon's log file. - When the `--log-format` option is combined with `--verbose`, rsync now avoids outputting the name of the file twice in most circumstances. As long as the `--log-format` item does not refer to any post-transfer items (such as %b or %c), the `--log-format` message is output prior to the transfer, so `--verbose` is now the equivalent of a `--log-format` of '%n%L' (which outputs the name and any link info). If the log output must occur after the transfer to be complete, the only time the name is also output prior to the transfer is when `--progress` was specified (so that the name will precede the progress stats, and the full `--log-format` output will come after). - Non-printable characters in filenames are replaced with a '?' to avoid corrupting the screen or generating empty lines in the output. ### BUG FIXES: - Restore the list-clearing behavior of `!` in a .cvsignore file (2.6.3 was only treating it as a special token in an rsync include/exclude file). - The combination of `--verbose` and `--dry-run` now mentions the full list of changes that would be output without `--dry-run`. - Avoid a mkdir warning when removing a directory in the destination that already exists in the `--backup-dir`. - An OS that has a binary mode for its files (such as Cygwin) needed `setmode(fd, O_BINARY)` called on the temp-file we opened with mkstemp(). (Fix derived from Cygwin's 2.6.3 rsync package.) - Fixed a potential hang when verbosity is high, the client side is the sender, and the file-list is large. - Fixed a potential protocol-corrupting bug where the generator could merge a message from the receiver into the middle of a multiplexed packet of data if only part of that data had been written out to the socket when the message from the generator arrived. - We now check if the OS doesn't support using mknod() for creating FIFOs and sockets, and compile-in some compatibility code using mkfifo() and socket() when necessary. - Fixed an off-by-one error in the handling of `--max-delete=N`. Also, if the `--max-delete` limit is exceeded during a run, we now output a warning about this at the end of the run and exit with a new error code (25). - One place in the code wasn't checking if fork() failed. - The `ignore nonreadable` daemon parameter used to erroneously affect readable symlinks that pointed to a non-existent file. - If the OS does not have lchown() and a chown() of a symlink will affect the referent of a symlink (as it should), we no longer try to set the user and group of a symlink. - The generator now properly runs the hard-link loop and the dir-time rewriting loop after we're sure that the redo phase is complete. - When `--backup` was specified with `--partial-dir=DIR`, where DIR is a relative path, the backup code was erroneously trying to backup a file that was put into the partial-dir. - If a file gets resent in a single transfer and the `--backup` option is enabled along with `--inplace`, rsync no longer performs a duplicate backup (it used to overwrite the first backup with the failed file). - One call to `flush_write_file()` was not being checked for an error. - The `--no-relative` option was not being sent from the client to a server sender. - If an rsync daemon specified `dont compress = ...` for a file and the client tried to specify `--compress`, the libz code was not handling a compression level of 0 properly. This could cause a transfer failure if the block-size for a file was large enough (e.g. rsync might have exited with an error for large files). - Fixed a bug that would sometimes surface when using `--compress` and sending a file with a block-size larger than 64K (either manually specified, or computed due to the file being really large). Prior versions of rsync would sometimes fail to decompress the data properly, and thus the transferred file would fail its verification. - If a daemon can't open the specified log file (i.e. syslog is not being used), die without crashing. We also output an error about the failure on stderr (which will only be seen if `--no-detach` was specified) and exit with a new error code (6). - A local transfer no longer duplicates all its include/exclude options (since the forked process already has a copy of the exclude list, there's no need to send them a set of duplicates). - The output of the items that are being updated by the generator (dirs, symlinks, devices) is now intermingled in the proper order with the output from the items that the receiver is updating (regular files) when pulling. This misordering was particularly bad when `--progress` was specified. (Requires protocol 29.) - When `--timeout` is specified, lulls that occur in the transfer while the generator is doing work that does not generate socket traffic (looking for changed files, deleting files, doing directory-time touch-ups, etc.) will cause a new keep-alive packet to be sent that should keep the transfer going as long as the generator continues to make progress. (Requires protocol 29.) - The stat size of a device is not added to the total file size of the items in the transfer (the size might be undefined on some OSes). - Fixed a problem with refused-option messages sometimes not making it back to the client side when a remote `--files-from` was in effect and the daemon was the receiver. - The `--compare-dest` option was not updating a file that differed in (the preserved) attributes from the version in the compare-dest DIR. - When rsync is copying files into a write-protected directory, fixed the change-report output for the directory so that we don't report an identical directory as changed. ### ENHANCEMENTS: - Rsync now supports popt's option aliases, which means that you can use /etc/popt and/or ~/.popt to create your own option aliases. - Added the `--delete-during` (`--del`) option which will delete files from the receiving side incrementally as each directory in the transfer is being processed. This makes it more efficient than the default, before-the-transfer behavior, which is now also available as `--delete-before` (and is still the default `--delete-WHEN` option that will be chosen if `--delete` or `--delete-excluded` is specified without a `--delete-WHEN` choice). All the `--del*` options infer `--delete`, so an rsync daemon that refuses `delete` will still refuse to allow any file-deleting options (including the new `--remove-sent-files` option). - All the `--delete-WHEN` options are now more memory efficient: Previously an duplicate set of file-list objects was created on the receiving side for the entire destination hierarchy. The new algorithm only creates one directory of objects at a time (for files inside the transfer). - Added the `--copy-dest` option, which works like `--link-dest` except that it locally copies identical files instead of hard-linking them. - Added support for specifying multiple `--compare-dest`, `--copy-dest`, or `--link-dest` options, but only of a single type. (Promoted from the patches dir and enhanced.) (Requires protocol 29.) - Added the `--max-size` option. (Promoted from the patches dir.) - The daemon-mode options are now separated from the normal rsync options so that they can't be mixed together. This makes it impossible to start a daemon that has improper default option values (which could cause problems when a client connects, such as hanging or crashing). - The `--bwlimit` option may now be used in combination with `--daemon` to specify both a default value for the daemon side and a value that cannot be exceeded by a user-specified `--bwlimit` option. - Added the `port` parameter to the rsyncd.conf file. (Promoted from the patches dir.) Also added `address`. The command-line options take precedence over a config-file option, as expected. - In `_exit_cleanup()`: when we are exiting with a partially-received file, we now flush any data in the write-cache before closing the partial file. - The `--inplace` support was enhanced to work with `--compare-dest`, `--link-dest`, and (the new) `--copy-dest` options. (Requires protocol 29.) - Added the `--dirs` (`-d`) option for an easier way to copy directories without recursion. Any directories that are encountered are created on the destination. Specifying a directory with a trailing slash copies its immediate contents to the destination. - The `--files-from` option now implies `--dirs` (`-d`). - Added the `--list-only` option, which is mainly a way for the client to put the server into listing mode without needing to resort to any internal option kluges (e.g. the age-old use of `-r --exclude='/*/*'` for a non-recursive listing). This option is used automatically (behind the scenes) when a modern rsync speaks to a modern daemon, but may also be specified manually if you want to force the use of the `--list-only` option over a remote-shell connection. - Added the `--omit-dir-times` (`-O`) option, which will avoid updating the modified time for directories when `--times` was specified. This option will avoid an extra pass through the file-list at the end of the transfer (to tweak all the directory times), which may provide an appreciable speedup for a really large transfer. (Promoted from the patches dir.) - Added the `--filter` (`-f`) option and its helper option, `-F`. Filter rules are an extension to the existing include/exclude handling that also supports nested filter files as well as per-directory filter files (like .cvsignore, but with full filter-rule parsing). This new option was chosen in order to ensure that all existing include/exclude processing remained 100% compatible with older versions. Protocol 29 is needed for full filter-rule support, but backward-compatible rules work with earlier protocol versions. (Promoted from the patches dir and enhanced.) - Added the `--delay-updates` option that puts all updated files into a temporary directory (by default `.~tmp~`, but settable via the `--partial-dir=DIR` option) until the end of the transfer. This makes the updates a little more atomic for a large transfer. - If rsync is put into the background, any output from `--progress` is reduced. - Documented the `max verbosity` setting for rsyncd.conf. (This setting was added a couple releases ago, but left undocumented.) - The sender and the generator now double-check the file-list index they are given, and refuse to try to do a file transfer on a non-file index (since that would indicate that something had gone very wrong). - Added the `--itemize-changes` (`-i`) option, which is a way to output a more detailed list of what files changed and in what way. The effect is the same as specifying a `--log-format` of `%i %n%L` (see both the rsync and rsyncd.conf manpages). Works with `--dry-run` too. - Added the `--fuzzy` (`-y`) option, which attempts to find a basis file for a file that is being created from scratch. The current algorithm only looks in the destination directory for the created file, but it does attempt to find a match based on size/mod-time (in case the file was renamed with no other changes) as well as based on a fuzzy name-matching algorithm. This option requires protocol 29 because it needs the new file-sorting order. (Promoted from patches dir and enhanced.) (Requires protocol 29.) - Added the `--remove-sent-files` option, which lets you move files between systems. - The hostname in HOST:PATH or HOST::PATH may now be an IPv6 literal enclosed in '[' and ']' (e.g. `[::1]`). (We already allowed IPv6 literals in the rsync://HOST:PORT/PATH format.) - When rsync recurses to build the file list, it no longer keeps open one or more directory handles from the dir's parent dirs. - When building under windows, the default for `--daemon` is now to avoid detaching, requiring the new `--detach` option to force rsync to detach. - The `--dry-run` option can now be combined with either `--write-batch` or `--read-batch`, allowing you to run a do-nothing test command to see what would happen without `--dry-run`. - The daemon's `read only` config item now sets an internal `read_only` variable that makes extra sure that no write/delete calls on the read-only side can succeed. - The log-format % escapes can now have a numeric field width in between the % and the escape letter (e.g. `%-40n %08p`). - Improved the option descriptions in the `--help` text. ### SUPPORT FILES: - Added atomic-rsync to the support dir: a perl script that will transfer some files using rsync, and then move the updated files into place all at once at the end of the transfer. Only works when pulling, and uses `--link-dest` and a parallel hierarchy of files to effect its update. - Added mnt-excl to the support dir: a perl script that takes the /proc/mounts file and translates it into a set of excludes that will exclude all mount points (even mapped mounts to the same disk). The excludes are made relative to the specified source dir and properly anchored. - Added savetransfer.c to the support dir: a C program that can make a copy of all the data that flows over the wire. This lets you test for data corruption (by saving the data on both the sending side and the receiving side) and provides one way to debug a protocol error. - Added rrsync to the support dir: this is an updated version of Joe Smith's restricted rsync perl script. This helps to ensure that only certain rsync commands can be run by an ssh invocation. ### INTERNAL: - Added better checking of the checksum-header values that come over the socket. - Merged a variety of file-deleting functions into a single function so that it is easier to maintain. - Improved the type of some variables (particularly blocksize vars) for consistency and proper size. - Got rid of the uint64 type (which we didn't need). - Use a slightly more compatible set of core #include directives. - Defined int32 in a way that ensures that the build dies if we can't find a variable with at least 32 bits. ### PROTOCOL DIFFERENCES FOR VERSION 29: - A 16-bit flag-word is transmitted after every file-list index. This indicates what is changing between the sender and the receiver. The generator now transmits an index and a flag-word to indicate when dirs and symlinks have changed (instead of producing a message), which makes the outputting of the information more consistent and less prone to screen corruption (because the local receiver/sender is now outputting all the file-change info messages). - If a file is being hard-linked, the `ITEM_XNAME_FOLLOWS` bit is enabled in the flag-word and the name of the file that was linked immediately follows in vstring format (see below). - If a file is being transferred with an alternate-basis file, the `ITEM_BASIS_TYPE_FOLLOWS` bit is enabled in the flag-word and a single byte follows, indicating what type of basis file was chosen. If that indicates that a fuzzy-match was selected, the `ITEM_XNAME_FOLLOWS` bit is set in the flag-word and the name of the match in vstring format follows the basis byte. A vstring is a variable length string that has its size written prior to the string, and no terminating null. If the string is from 1-127 bytes, the length is a single byte. If it is from 128-32767 bytes, the length is written as ((len >> 8) | 0x80) followed by (len % 0x100). - The sending of exclude names is done using filter-rule syntax. This means that all names have a prefixed rule indicator, even excludes (which used to be sent as a bare pattern, when possible). The `-C` option will include the per-dir .cvsignore merge file in the list of filter rules so it is positioned correctly (unlike in some older transfer scenarios). - Rsync sorts the filename list in a different way: it sorts the subdir names after the non-subdir names for each dir's contents, and it always puts a dir's contents immediately after the dir's name in the list. (Previously an item named `foo.txt` would sort in between directory `foo/` and `foo/bar`.) - When talking to a protocol 29 rsync daemon, a list-only request is able to note this before the options are sent over the wire and the new `--list-only` option is included in the options. - When the `--stats` bytes are sent over the wire (or stored in a batch), they now include two elapsed-time values: one for how long it took to build the file-list, and one for how long it took to send it over the wire (each expressed in thousandths of a second). - When `--delete-excluded` is specified with some filter rules (AKA excludes), a client sender will now initiate a send of the rules to the receiver (older protocols used to omit the sending of excludes in this situation since there were no receiver-specific rules that survived `--delete-excluded` back then). Note that, as with all the filter-list sending, only items that are significant to the other side will actually be sent over the wire, so the filter-rule list that is sent in this scenario is often empty. - An index equal to the file-list count is sent as a keep-alive packet from the generator to the sender, which then forwards it on to the receiver. This normally invalid index is only a valid keep-alive packet if the 16-bit flag-word that follows it contains a single bit (`ITEM_IS_NEW`, which is normally an illegal flag to appear alone). - A protocol-29 batch file includes a bit for the setting of the `--dirs` option and for the setting of the `--compress` option. Also, the shell script created by `--write-batch` will use the `--filter` option instead of `--exclude-from` to capture any filter rules. ### BUILD CHANGES: - Handle an operating system that use mkdev() in place of makedev(). - Improved configure to better handle cross-compiling. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.3 (30 Sep 2004) ## Changes in this version: ### SECURITY FIXES: - A bug in the `sanitize_path` routine (which affects a non-chrooted rsync daemon) could allow a user to craft a pathname that would get transformed into an absolute path for certain options (but not for file-transfer names). If you're running an rsync daemon with chroot disabled, **please upgrade**, ESPECIALLY if the user privs you run rsync under is anything above `nobody`. OUTPUT CHANGES (ATTN: those using a script to parse the verbose output): - Please note that the 2-line footer (output when verbose) now uses the term `sent` instead of `wrote` and `received` instead of `read`. If you are not parsing the numeric values out of this footer, a script would be better off using the empty line prior to the footer as the indicator that the verbose output is over. - The output from the `--stats` option was similarly affected to change `written` to `sent` and `read` to `received`. - Rsync ensures that a filename that contains a newline gets mentioned with each newline transformed into a question mark (which prevents a filename from causing an empty line to be output). - The `backed up ...` message that is output when at least 2 `--verbose` options are specified is now the same both with and without the `--backup-dir` option. ### BUG FIXES: - Fixed a crash bug that might appear when `--delete` was used and multiple source directories were specified. - Fixed a 32-bit truncation of the file length when generating the checksums. - The `--backup` code no longer attempts to create some directories over and over again (generating warnings along the way). - Fixed a bug in the reading of the secrets file (by the daemon) and the password file (by the client): the files no longer need to be terminated by a newline for their content to be read in. - If a file has a read error on the sending side or the reconstructed data doesn't match the expected checksum (perhaps due to the basis file changing during the transfer), the receiver will no longer retain the resulting file unless the `--partial` option was specified. (Note: for the read-error detection to work, neither side can be older than 2.6.3 -- older receivers will always retain the file, and older senders don't tell the receiver that the file had a read error.) - If a file gets resent in a single transfer and the `--backup` option is enabled, rsync no longer performs a duplicate backup (it used to overwrite the original file in the backup area). - Files specified in the daemon's `exclude` or `exclude from` config items are now excluded from being uploaded (assuming that the module allows uploading at all) in addition to the old download exclusion. - Got rid of a potential hang in the receiver when near the end of a phase. - When using `--backup` without a `--backup-dir`, rsync no longer preserves the modify time on directories. This avoids confusing NFS. - When `--copy-links` (`-L`) is specified, we now output a separate error for a symlink that has no referent instead of claiming that a file `vanished`. - The `--copy-links` (`-L`) option no longer has the side-effect of telling the receiving side to follow symlinks. See the `--keep-dirlinks` option (mentioned below) for a way to specify that behavior. - Error messages from the daemon server's option-parsing (such as refused options) are now successfully transferred back to the client (the server used to fail to send the message because the socket wasn't in the right state for the message to get through). - Most transfer errors that occur during a daemon transfer are now returned to the user in addition to being logged (some messages are intended to be daemon-only and are not affected by this). - Fixed a bug in the daemon authentication code when using one of the batch-processing options. - We try to work around some buggy IPv6 implementations that fail to implement `IPV6_V6ONLY`. This should fix the `address in use` error that some daemons get when running on an OS with a buggy IPv6 implementation. Also, if the new code gets this error, we might suggest that the user specify `--ipv4` or `--ipv6` (if we think it will help). - When the remote rsync dies, make a better effort to recover any error messages it may have sent before dying (the local rsync used to just die with a socket-write error). - When using `--delete` and a `--backup-dir` that contains files that are hard-linked to their destination equivalents, rsync now makes sure that removed files really get removed (avoids a really weird rename() behavior). - Avoid a bogus run-time complaint about a lack of 64-bit integers when the int64 type is defined as an `off_t` and it actually has 64-bits. - Added a configure check for open64() without mkstemp64() so that we can avoid using mkstemp() when such a combination is encountered. This bypasses a problem writing out large temp files on OSes such as AIX and HP-UX. - Fixed an age-old crash problem with `--read-batch` on a local copy (rsync was improperly assuming `--whole-file` for the local copy). - When `--dry-run` (`-n`) is used and the destination directory does not exist, rsync now produces a correct report of files that would be sent instead of dying with a chdir() error. - Fixed a bug that could cause a slow-to-connect rsync daemon to die with an error instead of waiting for the connection to finish. - Fixed an ssh interaction that could cause output to be lost when the user chose to combine the output of rsync's stdout and stderr (e.g. using the `2>&1`). - Fixed an option-parsing bug when `--files-from` got passed to a daemon. ### ENHANCEMENTS: - Added the `--partial-dir=DIR` option that lets you specify where to (temporarily) put a partially transferred file (instead of overwriting the destination file). E.g. `--partial-dir=.rsync-partial` Also added support for the `RSYNC_PARTIAL_DIR` environment variable that, when found, transforms a regular `--partial` option (such as the convenient `-P` option) into one that also specifies a directory. - Added `--keep-dirlinks` (`-K`), which allows you to symlink a directory onto another partition on the receiving side and have rsync treat it as matching a normal directory from the sender. - Added the `--inplace` option that tells rsync to write each destination file without using a temporary file. The matching of existing data in the destination file can be severely limited by this, but there are also cases where this is more efficient (such as appending data). Use only when needed (see the manpage for more details). - Added the `write only` option for the daemon's config file. - Added long-option names for `-4` and `-6` (namely `--ipv4` and `--ipv6`) and documented all these options in the manpage. - Improved the handling of the `--bwlimit` option so that it's less bursty, more accurate, and works properly over a larger range of values. - The rsync daemon-over-ssh code now looks for `SSH_CONNECTION` and `SSH2_CLIENT` in addition to `SSH_CLIENT` to figure out the IP address. - Added the `--checksum-seed=N` option for advanced users. - Batch writing/reading has a brand-new implementation that is simpler, fixes a few weird problems with the old code (such as no longer sprinkling the batch files into different dirs or even onto different systems), and is much less intrusive into the code (making it easier to maintain for the future). The new code generates just one data file instead of three, which makes it possible to read the batch on stdin via a remote shell. Also, the old requirement of forcing the same fixed checksum-seed for all batch processing has been removed. - If an rsync daemon has a module set with `list = no` (which hides its presence in the list of available modules), a user that fails to authenticate gets the same `unknown module` error that they would get if the module were actually unknown (while still logging the real error to the daemon's log file). This prevents fishing for module names. - The daemon's `refuse options` config item now allows you to match option names using wildcards and/or the single-letter option names. - Each transferred file now gets its permissions and modified-time updated before the temp-file gets moved into place. Previously, the finished file would have a very brief window where its permissions disallowed all group and world access. - Added the ability to parse a literal IPv6 address in an `rsync:` URL (e.g. rsync://[2001:638:500:101::21]:873/module/dir). - The daemon's wildcard expanding code can now handle more than 1000 filenames (it's now limited by memory instead of having a hard-wired limit). ### INTERNAL: - Some cleanup in the exclude code has saved some per-exclude memory and made the code easier to maintain. - Improved the argv-overflow checking for a remote command that has a lot of args. - Use rsyserr() in the various places that were still calling rprintf() with strerror() as an arg. - If an rsync daemon is listening on multiple sockets (to handle both IPv4 and IPv6 to a single port), we now close all the unneeded file handles after we accept a connection (we used to close just one of them). - Optimized the handling of larger block sizes (rsync used to slow to a crawl if the block size got too large). - Optimized away a loop in `hash_search()`. - Some improvements to the `sanitize_path()` and `clean_fname()` functions makes them more efficient and produce better results (while still being compatible with the file-name cleaning that gets done on both sides when sending the file-list). - Got rid of `alloc_sanitize_path()` after adding a destination-buffer arg to `sanitize_path()` made it possible to put all the former's functionality into the latter. - The file-list that is output when at least 4 verbose options are specified reports the uid value on the sender even when rsync is not running as root (since we might be sending to a root receiver). ### BUILD CHANGES: - Added a `gen` target to rebuild most of the generated files, including configure, config.h.in, the manpages, and proto.h. - If `make proto` doesn't find some changes in the prototypes, the proto.h file is left untouched (its time-stamp used to always be updated). - The variable `$STRIP` (that is optionally set by the install-strip target's rule) was changed to `$INSTALL_STRIP` because some systems have `$STRIP` already set in the environment. - Fixed a build problem when `SUPPORT_HARD_LINKS` isn't defined. - When cross-compiling, the gettimeofday() function is now assumed to be a modern version that takes two-args (since we can't test it). ### DEVELOPER RELATED: - The scripts in the testsuite dir were cleaned up a bit and a few new tests added. - Some new diffs were added to the patches dir, and some accepted ones were removed. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.2 (30 Apr 2004) ## Changes in this version: ### BUG FIXES: - Fixed a major bug in the sorting of the filenames when `--relative` is used for some sources (just sources such as `/` and `/*` were affected). This fix ensures that we ask for the right file-list item when requesting changes from the sender. - Rsync now checks the return value of the close() function to better report disk-full problems on an NFS file system. - Restored the old daemon-server behavior of logging error messages rather than returning them to the user. (A better long-term fix will be sought in the future.) - An obscure uninitialized-variable bug was fixed in the uid/gid code. (This bug probably had no ill effects.) ### BUILD CHANGES: - Got rid of the configure check for sys/sysctl.h (it wasn't used and was causing a problem on some systems). Also improved the broken-largefile-locking test to try to avoid failure due to an NFS build-dir. - Fixed a compile problem on systems that don't define `AI_NUMERICHOST`. - Fixed a compile problem in the popt source for compilers that don't support `__attribute__`. ### DEVELOPER RELATED: - Improved the testsuite's `merge` test to work on OSF1. - Two new diffs were added to the patches dir. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.1 (26 Apr 2004) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 28. ### SECURITY FIXES: - Paths sent to an rsync daemon are more thoroughly sanitized when chroot is not used. If you're running a non-read-only rsync daemon with chroot disabled, **please upgrade**, ESPECIALLY if the user privs you run rsync under is anything above `nobody`. ### ENHANCEMENTS: - Lower memory use, more optimal transfer of data over the socket, and lower CPU usage (see the INTERNAL section for details). - The `RSYNC_PROXY` environment variable can now contain a `USER:PASS@` prefix before the `HOST:PORT` information. (Bardur Arantsson) - The `--progress` output now mentions how far along in the transfer we are, including both a count of files transferred and a percentage of the total file-count that we've processed. It also shows better current-rate-of-transfer and remaining-transfer-time values. - Documentation changes now attempt to describe some often misunderstood features more clearly. ### BUG FIXES: - When `-x` (`--one-file-system`) is combined with `-L` (`--copy-links`) or `--copy-unsafe-links,` no symlinked files are skipped, even if the referent file is on a different filesystem. - The `--link-dest` code now works properly for a non-root user when (1) the UIDs of the source and destination differ and `-o` was specified, or (2) when the group of the source can't be used on the destination and `-g` was specified. - Fixed a bug in the handling of `-H` (hard-links) that might cause the expanded PATH/NAME value of the current item to get overwritten (due to an expanded-name caching bug). - We now reset the `new data has been sent` flag at the start of each file we send. This makes sure that an interrupted transfer with the `--partial` option set doesn't keep a shorter temp file than the current basis file when no new data has been transferred over the wire for that file. - Fixed a byte-order problem in `--batch-mode` on big-endian machines. (Jay Fenlason) - When using `--cvs-exclude`, the exclude items we get from a per-directory's .cvsignore file once again only affect that one directory (not all following directories too). The items are also now properly word-split and parsed without any +/- prefix parsing. - When specifying the USER@HOST: prefix for a file, the USER part can now contain an '@', if needed (i.e. the last '@' is used to find the HOST, not the first). - Fixed some bugs in the handling of group IDs for non-root users: (1) It properly handles a group that the sender didn't have a name for (it would previously skip changing the group on any files in that group). (2) If `--numeric-ids` is used, rsync no longer attempts to set groups that the user doesn't have the permission to set. - Fixed the `refuse options` setting in the rsyncd.conf file. - Improved the `-x` (`--one-file-system`) flag's handling of any mount-point directories we encounter. It is both more optimal (in that it no longer does a useless scan of the contents of the mount-point dirs) and also fixes a bug where a remapped mount of the original filesystem could get discovered in a subdir we should be ignoring. - Rsync no longer discards a double-slash at the start of a filename when trying to open the file. It also no longer constructs names that start with a double slash (unless the user supplied them). - Path-specifying options to a daemon should now work the same with or without chroot turned on. Previously, such a option (such as `--link-dest`) would get its absolute path munged into a relative one if chroot was not on, making that setting fairly useless. Rsync now transforms the path into one that is based on the module's base dir when chroot is not enabled. - Fixed a compatibility problem interacting with older rsync versions that might send us an empty `--suffix` value without telling us that `--backup-dir` was specified. - The `hosts allow` option for a daemon-over-remote-shell process now has improved support for IPv6 addresses and a fix for systems that have a length field in their socket structs. - Fixed the ability to request an empty backup `--suffix` when sending files to an rsync daemon. - Fixed an option-parsing bug when `--files-from` was sent to a server sender. ### INTERNAL: - Most of the I/O is now buffered, which results in a pretty large speedup when running under MS Windows. (Craig Barratt) - Optimizations to the name-handling/comparing code have made some significant reductions in user-CPU time for large file sets. - Some cleanup of the variable types make the code more consistent. - Reduced memory requirements of hard link preservation. (J.W. Schultz) - Implemented a new algorithm for hard-link handling that speeds up the code significantly. (J.W. Schultz and Wayne Davison) - The `--hard-link` option now uses the first existing file in the group of linked files as the basis for the transfer. This prevents the sub-optimal transfer of a file's data when a new hardlink is added on the sending side and it sorts alphabetically earlier in the list than the files that are already present on the receiving side. - Dropped support for protocol versions less than 20 (2.3.0 released 15 Mar 1999) and activated warnings for protocols less than 25 (2.5.0 released 23 Aug 2001). (Wayne Davison and J.W. Schultz, severally) - More optimal data transmission for `--hard-links` (protocol 28). - More optimal data transmission for `--checksum` (protocol 28). - Less memory is used when `--checksum` is specified. - Less memory is used in the file list (a per-file savings). - The generator is now better about not modifying the file list during the transfer in order to avoid a copy-on-write memory bifurcation (on systems where fork() uses shared memory). Previously, rsync's shared memory would slowly become unshared, resulting in real memory usage nearly doubling on the receiving side by the end of the transfer. Now, as long as permissions are being preserved, the shared memory should remain that way for the entire transfer. - Changed hardlink info and `file_struct` + strings to use allocation pools. This reduces memory use for large file-sets and permits freeing memory to the OS. (J.W. Schultz) - The 2 pipes used between the receiver and generator processes (which are forked on the same machine) were reduced to 1 pipe and the protocol improved so that (1) it is now impossible to have the `redo` pipe fill up and hang rsync, and (2) trailing messages from the receiver don't get lost on their way through the generator over to the sender (which mainly affected hard-link messages and verbose `--stats` output). - Improved the internal uid/gid code to be more portable and a little more optimized. - The device numbers sent when using `--devices` are now sent as separate major/minor values with 32-bit accuracy (protocol 28). Previously, the copied devices were sent as a single 32-bit number. This will make inter-operation of 64-bit binaries more compatible with their 32-bit brethren (with both ends of the connection are using protocol 28). Note that optimizations in the binary protocol for sending the device numbers often results in fewer bytes being used than before, even though more precision is now available. - Some cleanup of the exclude/include structures and its code made things clearer (internally), simpler, and more efficient. - The reading & writing of the file-list in batch-mode is now handled by the same code that sends & receives the list over the wire. This makes it much easier to maintain. (Note that the batch code is still considered to be experimental.) ### BUILD CHANGES: - The configure script now accepts `--with-rsyncd-conf=PATH` to override the default value of the /etc/rsyncd.conf file. - Fixed configure bug when running `./configure --disable-ipv6`. - Fixed compilation problem on Tru64 Unix (having to do with `sockaddr.sa_len` and `sockaddr.sin_len`). ### DEVELOPER RELATED: - Fixed `make test` bug when build dir is not the source dir. - Added a couple extra diffs in the `patches` dir, removed the ones that got applied, and rebuilt the rest. ------------------------------------------------------------------------------ # NEWS for rsync 2.6.0 (1 Jan 2004) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 27. The maximum accepted protocol number was increased from 30 to 40. ### ENHANCEMENTS: - `ssh` is now the default remote shell for rsync. If you want to change this, configure like this: `./configure --with-rsh=rsh`. - Added `--files-from`, `--no-relative`, `--no-implied-dirs`, and `--from0`. Note that `--from0` affects the line-ending character for all the files read by the `--*-from` options. (Wayne Davison) - Length of csum2 is now per-file starting with protocol version 27. (J.W. Schultz) - Per-file dynamic block size is now sqrt(file length). The per-file checksum size is determined according to an algorithm provided by Donovan Baarda which reduces the probability of rsync algorithm corrupting data and falling back using the whole md4 checksums. (J.W. Schultz, Donovan Baarda) - The `--stats` option no longer includes the (debug) malloc summary unless the verbose option was specified at least twice. - Added a new error/warning code for when files vanish from the sending side. Made vanished source files not interfere with the file-deletion pass when `--delete-after` was specified. - Various trailing-info sections are now preceded by a newline. ### BUG FIXES: - Fixed several exclude/include matching bugs when using wild-cards. This has a several user-visible effects, all of which make the matching more consistent and intuitive. This should hopefully not cause anyone problems since it makes the matching work more like what people are expecting. (Wayne Davison) - A pattern with a `**` no longer causes a `*` to match slashes. For example, with `/*/foo/**`, `foo` must be 2 levels deep. [If your string has BOTH `*` and `**` wildcards, changing the `*` wildcards to `**` will provide the old behavior in all versions.] - `**/foo` now matches at the base of the transfer (like /foo does). [Use `/**/foo` to get the old behavior in all versions.] - A non-anchored wildcard term floats to match beyond the base of the transfer. E.g. `CVS/R*` matches at the end of the path, just like the non-wildcard term `CVS/Root` does. [Use `/CVS/R*` to get the old behavior in all versions.] - Including a `**` in the match term causes it to be matched against the entire path, not just the name portion, even if there aren't any interior slashes in the term. E.g. `foo**bar` would exclude `/path/foo-bar` (just like before) as well as `/foo-path/baz-bar` (unlike before). [Use `foo*bar` to get the old behavior in all versions.] - The exclude list specified in the daemon's config file is now properly applied to the pulled items no matter how deep the user's file-args are in the source tree. (Wayne Davison) - For protocol version >= 27, `mdfour_tail()` is called when the block size (including `checksum_seed`) is a multiple of 64. Previously it was not called, giving the wrong MD4 checksum. (Craig Barratt) - For protocol version >= 27, a 64 bit bit counter is used in mdfour.c as required by the RFC. Previously only a 32 bit bit counter was used, causing incorrect MD4 file checksums for file sizes >= 512MB - 4. (Craig Barratt) - Fixed a crash bug when interacting with older rsync versions and multiple files of the same name are destined for the same dir. (Wayne Davison) - Keep tmp names from overflowing MAXPATHLEN. - Make `--link-dest` honor the absence of `-p`, `-o`, and `-g`. - Made rsync treat a trailing slash in the destination in a more consistent manner. - Fixed file I/O error detection. (John Van Essen) - Fixed bogus `malformed address {hostname}` message in rsyncd log when checking IP address against hostnames from `hosts allow` and `hosts deny` parameters in config file. - Print heap statistics when verbose >= 2 instead of when >= 1. - Fixed a compression (`-z`) bug when syncing a mostly-matching file that contains already-compressed data. (Yasuoka Masahiko and Wayne Davison) - Fixed a bug in the `--backup` code that could cause deleted files to not get backed up. - When the backup code makes new directories, create them with mode 0700 instead of 0755 (since the directory permissions in the backup tree are not yet copied from the main tree). - Call setgroups() in a more portable manner. - Improved file-related error messages to better indicate exactly what pathname failed. (Wayne Davison) - Fixed some bugs in the handling of `--delete` and `--exclude` when using the `--relative` (`-R`) option. (Wayne Davison) - Fixed bug that prevented regular files from replacing special files and caused a directory in `--link-dest` or `--compare-dest` to block the creation of a file with the same path. A directory still cannot be replaced by a regular file unless `--delete` specified. (J.W. Schultz) - Detect and report when open or opendir succeed but read and readdir fail caused by network filesystem issues and truncated files. (David Norwood, Michael Brown, J.W. Schultz) - Added a fix that should give ssh time to restore the tty settings if the user presses Ctrl-C at an ssh password prompt. ### INTERNAL: - Eliminated vestigial support for old versions that we stopped supporting. (J.W. Schultz) - Simplified some of the option-parsing code. (Wayne Davison) - Some cleanup made to the exclude code, as well as some new defines added to enhance readability. (Wayne Davison) - Changed the protocol-version code so that it can interact at a lower protocol level than the maximum supported by both sides. Added an undocumented option, `--protocol=N`, to force the value we advertise to the other side (primarily for testing purposes). (Wayne Davison) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.7 (4 Dec 2003) ## Changes in this version: ### SECURITY FIXES: - Fix buffer handling bugs. (Andrew Tridgell, Martin Pool, Paul Russell, Andrea Barisani) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.6, aka "the dwd-between-jobs release" (26 Jan 2003) ## Changes in this version: ### ENHANCEMENTS: - The `--delete-after` option now implies `--delete`. (Wayne Davison) - The `--suffix` option can now be used with `--backup-dir`. (Michael Zimmerman) - Combining `::` syntax with the `--rsh`/`-e` option now uses the specified remote-shell as a transport to talk to a (newly-spawned) server-daemon. This allows someone to use daemon features, such as modules, over a secure protocol, such as ssh. (JD Paul) - The rsync:// syntax for daemon connections is now accepted in the destination field. - If the file name given to `--include-from` or `--exclude-from` is `-`, rsync will read from standard input. (J.W. Schultz) - New option `--link-dest` which is like `--compare-dest` except that unchanged files are hard-linked in to the destination directory. (J.W. Schultz) - Don't report an error if an excluded file disappears during an rsync run. (Eugene Chupriyanov and Bo Kersey) - Added .svn to `--cvs-exclude` list to support subversion. (Jon Middleton) - Properly support IPv6 addresses in the rsyncd.conf `hosts allow` and `hosts deny` fields. (Hideaki Yoshifuji) - Changed exclude file handling to permit DOS or MAC style line terminations. (J.W. Schultz) - Ignore errors from chmod when `-p`/`-a`/`--preserve-perms` is not set. (Dave Dykstra) ### BUG FIXES: - Fix `forward name lookup failed` errors on AIX 4.3.3. (John L. Allen, Martin Pool) - Generate each file's rolling-checksum data as we send it, not in a separate (memory-eating) pass before hand. This prevents timeout errors on really large files. (Stefan Nehlsen) - Fix compilation on Tru64. (Albert Chin, Zoong Pham) - Better handling of some client-server errors. (Martin Pool) - Fixed a crash that would occur when sending a list of files that contains a duplicate name (if it sorts to the end of the file list) and using `--delete`. (Wayne Davison) - Fixed the file-name duplicate-removal code when dealing with multiple dups in a row. (Wayne Davison) - Fixed a bug that caused rsync to lose the exit status of its child processes and sometimes return an exit code of 0 instead of showing an error. (David R. Staples, Dave Dykstra) - Fixed bug in `--copy-unsafe-links` that caused it to be completely broken. (Dave Dykstra) - Prevent infinite recursion in cleanup code under certain circumstances. (Sviatoslav Sviridov and Marc Espie) - Fixed a bug that prevented rsync from creating intervening directories when `--relative-paths`/`-R` is set. (Craig Barratt) - Prevent `Connection reset by peer` messages from Cygwin. (Randy O'Meara) ### INTERNAL: - Many code cleanups and improved internal documentation. (Martin Pool, Nelson Beebe) - Portability fixes. (Dave Dykstra and Wayne Davison) - More test cases. (Martin Pool) - Some test-case fixes. (Brian Poole, Wayne Davison) - Updated included popt to the latest vendor drop, version 1.6.4. (Jos Backus) - Updated config.guess and config.sub to latest versions; this means rsync should build on more platforms. (Paul Green) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.5, aka Snowy River (2 Apr 2002) ## Changes in this version: ### ENHANCEMENTS: - With `--progress`, when a transfer is complete show the time taken; otherwise show expected time to complete. (Cameron Simpson) - Make `make install-strip` works properly, and `make install` accepts a DESTDIR variable for help in building binary packages. (Peter Breitenlohner, Greg Louis) - If configured with `--enable-maintainer-mode`, then on receipt of a fatal signal rsync will try to open an xterm running gdb, similarly to Samba's `panic action` or GNOME's bug-buddy. (Martin Pool) ### BUG FIXES: - Fix situation where failure to fork (e.g. because out of process slots) would cause rsync to kill all processes owned by the current user. Yes, really! (Paul Haas, Martin Pool) - Fix test suite on Solaris. (Jos Backus, Martin Pool) - Fix minor memory leak in socket code. (Dave Dykstra, Martin Pool.) - Fix `--whole-file` problem that caused it to be the default even for remote connections. (Martin Pool, Frank Schulz) - Work around bug in Mac OS X mkdir(2), which cannot handle trailing slashes. (Martin Pool) - Improved network error handling. (Greg A. Woods) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.4, aka "Imitation lizard skin" (13 Mar 2002) ## Changes in this version: ### BUG FIXES: - Additional fix for zlib double-free bug. (Martin Pool, Andrew Tridgell) (CVE CAN-2002-0059) ### ENHANCEMENTS: - Merge in changes from zlib 1.1.3 to zlib 1.1.4. (Jos Backus) (Note that rsync still uses a custom version of zlib; you can not just link against a system library. See zlib/README.rsync) - Additional test cases for `--compress`. (Martin Pool) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.3, aka "Happy 26" (11 Mar 2002) ## Changes in this version: ### SECURITY FIXES: - Make sure that supplementary groups are removed from a server process after changing uid and gid. (Ethan Benson) (Debian bug #132272, CVE CAN-2002-0080) ### BUG FIXES: - Fix zlib double-free bug. (Owen Taylor, Mark J Cox) (CVE CAN-2002-0059) - Fixed problem that in many cases caused the error message unexpected read size of 0 in `map_ptr` and resulted in the wrong data being copied. - Fixed compilation errors on some systems caused by the use of `unsigned int64` in rsync.h. - Fixed problem on systems such as Sunos4 that do not support realloc on a NULL pointer; error was 'out of memory in "flist_expand"'. - Fix for rsync server processes hanging around after the client unexpectedly disconnects. (Colin Walters) (Debian bug #128632) - Cope with BSD systems on which mkdir() will not accept a trailing slash. ### ENHANCEMENTS: - Merge in changes from zlib 1.1.2 to zlib 1.1.3. (Note that rsync still uses a custom version of zlib; you can not just link against a system library. See zlib/README.rsync) - Command to initiate connections is only shown with `-vv`, rather than `-v` as in 2.5.2. Output from plain `-v` is more similar to what was historically used so as not to break scripts that try to parse the output. - Added `--no-whole-file` and `--no-blocking-io` options (Dave Dykstra) - Made the `--write-batch` and `--read-batch` options actually work and added documentation in the manpage (Jos Backus) - If the daemon is unable to fork a child to accept a connection, print an error message. (Colin Walters) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.2 (26 Jan 2002) ## Changes in this version: ### SECURITY FIXES: - Signedness security patch from Sebastian Krahmer -- in some cases we were not sufficiently careful about reading integers from the network. ### PROTOCOL NUMBER: - The protocol number was changed to 26. ### BUG FIXES: - Fix possible string mangling in log files. - Fix for setting local address of outgoing sockets. - Better handling of hardlinks and devices on platforms with 64-bit `dev_t` or `ino_t`. - Name resolution on machines supporting IPv6 is improved. - Fix for device nodes. (dann frazier) (Debian #129135) ### ENHANCEMENTS: - With `-v`, rsync now shows the command used to initiate an ssh/rsh connection. - `--statistics` now shows memory heap usage on platforms that support mallinfo(). - "The Ted T'so school of program optimization": make progress visible and people will think it's faster. (With `--progress`, rsync will show you how many files it has seen as it builds the `file_list`, giving some indication that it has not hung.) - Improvements to batch mode support. This is still experimental but testing would be welcome. (Jos Backus) - New `--ignore-existing` option, patch previously distributed with Vipul's Razor. (Debian #124286) ------------------------------------------------------------------------------ # NEWS for rsync 2.5.1 (3 Jan 2002) ## Changes in this version: ### BUG FIXES: - Fix for segfault in `--daemon` mode configuration parser. (Paul Mackerras) - Correct `string<->address` parsing for both IPv4 and 6. (YOSHIFUJI Hideaki, SUMIKAWA Munechika and Jun-ichiro `itojun` Hagino) - Various fixes for IPv6 support. (Dave Dykstra) - rsync.1 typo fix. (Matt Kraai) - Test suite typo fixes. (Tom Schmidt) - rsync.1 grammar and clarity improvements. (Edward Welbourne) - Correction to ./configure tests for `inet_ntop`. (Jeff Garzik) ### ENHANCEMENTS: - `--progress` and `-P` now show estimated data transfer rate (in a multiple of bytes/s) and estimated time to completion. (Rik Faith) - `--no-detach` option, required to run as a W32 service and also useful when running on Unix under daemontools, AIX's SRC, or a debugger. (Max Bowsher, Jos Backus) - Clearer error messages for some conditions. ------------------------------------------------------------------------------ # NEWS for rsync 2.5.0 (30 Nov 2001) ## Changes in this version: ### PROTOCOL NUMBER: - The protocol number was changed to 25. ### ANNOUNCEMENTS: - Martin Pool is now a co-maintainer. ### NEW FEATURES: - Support for LSB-compliant packaging - Shell wildcards are allowed in `auth users` lines. - Merged UNC rsync+ patch to support creation of standalone patch sets. By Bert J. Dempsey and Debra Weiss, updated by Jos Backus. - IPv6 support based on a patch from KAME.net, on systems including modern versions of Linux, Solaris, and HP-UX. Also includes IPv6 compatibility functions for old OSs by the Internet Software Consortium, Paul Vixie, the OpenSSH portability project, and OpenBSD. ### ENHANCEMENTS: - Include/exclude cluestick: with `-vv`, print out whether files are included or excluded and why. - Many error messages have more friendly explanations and more details. - Manual page improvements plus scanty protocol documentation. - When running as `--daemon` in the background and using a `log file` rsyncd.conf directive, close the log file every time it is open when going to sleep on the socket. This allows the log file to get cleaned out by another process. - Change to using libpopt rather than getopt for processing options. This makes the code cleaner and the behaviour more consistent across platforms. popt is included and built if not installed on the platform. - More details in `--version`, including note about whether 64-bit files, symlinks and hardlinks are supported. - MD4 code may use less CPU cycles. - Use mkstemp on systems where it is secure. If we use mktemp, explain that we do it in a secure way. - `--whole-file` is the default when source and target are on the local machine. ### BUG FIXES: - Fix for various bugs causing rsync to hang. - Attempt to fix Large File Summit support on AIX. - Attempt to fix error handling lockup bug. - Give a non-0 exit code if **any** of the files we have been asked to transfer fail to transfer. - For log messages containing ridiculously long strings that might overflow a buffer rsync no longer aborts, but rather prints an ellipsis at the end of the string. (Patch from Ed Santiago.) ### PLATFORMS: - Improved support for UNICOS (tested on Cray T3E and Cray SV1) - autoconf2.52 (or later) is now required to rebuild the autoconf scripts. It is not required to simply build rsync. - Platforms thought to work in this release: - Cray SV1 UNICOS 10.0.0.8 cc - Debian Linux 2.2 UltraSparc gcc - Debian Linux testing/unstable ARM gcc - FreeBSD 3.3-RELEASE i386 cc - FreeBSD 4.1.1-RELEASE i386 cc - FreeBSD 4.3-STABLE i386 cc - HP PA-RISC HP-UX 10.20 gcc - HP PA-RISC HP-UX 11.11 cc - IRIX 6.5 MIPS cc - IRIX 6.5 MIPS gcc - Mac OS X PPC (`--disable-ipv6`) cc - NetBSD 1.5 i386 gcc - NetBSD Current i386 cc - OpenBSD 2.5 Sparc gcc - OpenBSD 2.9 i386 cc - OpenBSD Current i386 cc - RedHat 6.2 i386 gcc - RedHat 6.2 i386 insure++ - RedHat 7.0 i386 gcc - RedHat 7.1 i386 (Kernel 2.4.10) gcc - Slackware 8.0 i686 (Kernel 2.4.10) - Solaris 8 UltraSparc cc - Solaris 8 UltraSparc gcc - Solaris 8 i386 gcc - SuSE 7.1 i386 gcc2.95.2 - SuSE 7.1 ppc gcc2.95.2 - i386-pc-sco3.2v5.0.5 cc - i386-pc-sco3.2v5.0.5 gcc - powerpc-ibm-aix4.3.3.0 cc - i686-unknown-sysv5UnixWare7.1.0 gcc - i686-unknown-sysv5UnixWare7.1.0 cc ### TESTING: - The existing test.sh script by Phil Hands has been merged into a test framework that works from both `make check` and the Samba build farm. ------------------------------------------------------------------------------ ## Partial Protocol History | RELEASE DATE | VER. | DATE OF COMMIT\* | PROTOCOL | |--------------|--------|------------------|-------------| | 20 Oct 2022 | 3.2.7 | | 31 | | 09 Sep 2022 | 3.2.6 | | 31 | | 14 Aug 2022 | 3.2.5 | | 31 | | 15 Apr 2022 | 3.2.4 | | 31 | | 06 Aug 2020 | 3.2.3 | | 31 | | 04 Jul 2020 | 3.2.2 | | 31 | | 22 Jun 2020 | 3.2.1 | | 31 | | 19 Jun 2020 | 3.2.0 | | 31 | | 28 Jan 2018 | 3.1.3 | | 31 | | 21 Dec 2015 | 3.1.2 | | 31 | | 22 Jun 2014 | 3.1.1 | | 31 | | 28 Sep 2013 | 3.1.0 | 31 Aug 2008 | 31 | | 23 Sep 2011 | 3.0.9 | | 30 | | 26 Mar 2011 | 3.0.8 | | 30 | | 31 Dec 2009 | 3.0.7 | | 30 | | 08 May 2009 | 3.0.6 | | 30 | | 28 Dec 2008 | 3.0.5 | | 30 | | 06 Sep 2008 | 3.0.4 | | 30 | | 29 Jun 2008 | 3.0.3 | | 30 | | 08 Apr 2008 | 3.0.2 | | 30 | | 03 Apr 2008 | 3.0.1 | | 30 | | 01 Mar 2008 | 3.0.0 | 11 Nov 2006 | 30 | | 06 Nov 2006 | 2.6.9 | | 29 | | 22 Apr 2006 | 2.6.8 | | 29 | | 11 Mar 2006 | 2.6.7 | | 29 | | 28 Jul 2005 | 2.6.6 | | 29 | | 01 Jun 2005 | 2.6.5 | | 29 | | 30 Mar 2005 | 2.6.4 | 17 Jan 2005 | 29 | | 30 Sep 2004 | 2.6.3 | | 28 | | 30 Apr 2004 | 2.6.2 | | 28 | | 26 Apr 2004 | 2.6.1 | 08 Jan 2004 | 28 | | 01 Jan 2004 | 2.6.0 | 10 Apr 2003 | 27 (MAX=40) | | 04 Dec 2003 | 2.5.7 | | 26 | | 26 Jan 2003 | 2.5.6 | | 26 | | 02 Apr 2002 | 2.5.5 | | 26 | | 13 Mar 2002 | 2.5.4 | | 26 | | 11 Mar 2002 | 2.5.3 | | 26 | | 26 Jan 2002 | 2.5.2 | 11 Jan 2002 | 26 | | 03 Jan 2002 | 2.5.1 | | 25 | | 30 Nov 2001 | 2.5.0 | 23 Aug 2001 | 25 | | 06 Sep 2000 | 2.4.6 | | 24 | | 19 Aug 2000 | 2.4.5 | | 24 | | 29 Jul 2000 | 2.4.4 | | 24 | | 09 Apr 2000 | 2.4.3 | | 24 | | 30 Mar 2000 | 2.4.2 | | 24 | | 30 Jan 2000 | 2.4.1 | 29 Jan 2000 | 24 | | 29 Jan 2000 | 2.4.0 | 28 Jan 2000 | 23 | | 25 Jan 2000 | 2.3.3 | 23 Jan 2000 | 22 | | 08 Nov 1999 | 2.3.2 | 26 Jun 1999 | 21 | | 06 Apr 1999 | 2.3.1 | | 20 | | 15 Mar 1999 | 2.3.0 | 15 Mar 1999 | 20 | | 25 Nov 1998 | 2.2.1 | | 19 | | 03 Nov 1998 | 2.2.0 | | 19 | | 09 Sep 1998 | 2.1.1 | | 19 | | 20 Jul 1998 | 2.1.0 | | 19 | | 17 Jul 1998 | 2.0.19 | | 19 | | 18 Jun 1998 | 2.0.17 | | 19 | | 01 Jun 1998 | 2.0.16 | | 19 | | 27 May 1998 | 2.0.13 | 27 May 1998 | 19 | | 26 May 1998 | 2.0.12 | | 18 | | 22 May 1998 | 2.0.11 | | 18 | | 18 May 1998 | 2.0.9 | 18 May 1998 | 18 | | 17 May 1998 | 2.0.8 | | 17 | | 15 May 1998 | 2.0.1 | | 17 | | 14 May 1998 | 2.0.0 | | 17 | | 17 Apr 1998 | 1.7.4 | | 17 | | 13 Apr 1998 | 1.7.3 | | 17 | | 05 Apr 1998 | 1.7.2 | | 17 | | 26 Mar 1998 | 1.7.1 | | 17 | | 26 Mar 1998 | 1.7.0 | 26 Mar 1998 | 17 (MAX=30) | | 13 Jan 1998 | 1.6.9 | 13 Jan 1998 | 15 (MAX=20) | \* DATE OF COMMIT is the date the protocol change was committed to version control. @USE_GFM_PARSER@ rsync-3.2.7/.gitattributes0000664000000000000000000000002313703635364014261 0ustar rootroot* text=auto eol=lf rsync-3.2.7/config.sub0000664000000000000000000007560413672315367013372 0ustar rootroot#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-05-04' # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) basic_machine=$field1 os=$maybe_os ;; android-linux) basic_machine=$field1-unknown os=linux-android ;; *) basic_machine=$field1-$field2 os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 os= ;; *) basic_machine=$field1 os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc os=bsd ;; a29khif) basic_machine=a29k-amd os=udi ;; adobe68k) basic_machine=m68010-adobe os=scout ;; alliant) basic_machine=fx80-alliant os= ;; altos | altos3068) basic_machine=m68k-altos os= ;; am29k) basic_machine=a29k-none os=bsd ;; amdahl) basic_machine=580-amdahl os=sysv ;; amiga) basic_machine=m68k-unknown os= ;; amigaos | amigados) basic_machine=m68k-unknown os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=sysv4 ;; apollo68) basic_machine=m68k-apollo os=sysv ;; apollo68bsd) basic_machine=m68k-apollo os=bsd ;; aros) basic_machine=i386-pc os=aros ;; aux) basic_machine=m68k-apple os=aux ;; balance) basic_machine=ns32k-sequent os=dynix ;; blackfin) basic_machine=bfin-unknown os=linux ;; cegcc) basic_machine=arm-unknown os=cegcc ;; convex-c1) basic_machine=c1-convex os=bsd ;; convex-c2) basic_machine=c2-convex os=bsd ;; convex-c32) basic_machine=c32-convex os=bsd ;; convex-c34) basic_machine=c34-convex os=bsd ;; convex-c38) basic_machine=c38-convex os=bsd ;; cray) basic_machine=j90-cray os=unicos ;; crds | unos) basic_machine=m68k-crds os= ;; da30) basic_machine=m68k-da30 os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec os= ;; delta88) basic_machine=m88k-motorola os=sysv3 ;; dicos) basic_machine=i686-pc os=dicos ;; djgpp) basic_machine=i586-pc os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=ose ;; gmicro) basic_machine=tron-gmicro os=sysv ;; go32) basic_machine=i386-pc os=go32 ;; h8300hms) basic_machine=h8300-hitachi os=hms ;; h8300xray) basic_machine=h8300-hitachi os=xray ;; h8500hms) basic_machine=h8500-hitachi os=hms ;; harris) basic_machine=m88k-harris os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp os=hpux ;; hp300bsd) basic_machine=m68k-hp os=bsd ;; hppaosf) basic_machine=hppa1.1-hp os=osf ;; hppro) basic_machine=hppa1.1-hp os=proelf ;; i386mach) basic_machine=i386-mach os=mach ;; isi68 | isi) basic_machine=m68k-isi os=sysv ;; m68knommu) basic_machine=m68k-unknown os=linux ;; magnum | m3230) basic_machine=mips-mips os=sysv ;; merlin) basic_machine=ns32k-utek os=sysv ;; mingw64) basic_machine=x86_64-pc os=mingw64 ;; mingw32) basic_machine=i686-pc os=mingw32 ;; mingw32ce) basic_machine=arm-unknown os=mingw32ce ;; monitor) basic_machine=m68k-rom68k os=coff ;; morphos) basic_machine=powerpc-unknown os=morphos ;; moxiebox) basic_machine=moxie-unknown os=moxiebox ;; msdos) basic_machine=i386-pc os=msdos ;; msys) basic_machine=i686-pc os=msys ;; mvs) basic_machine=i370-ibm os=mvs ;; nacl) basic_machine=le32-unknown os=nacl ;; ncr3000) basic_machine=i486-ncr os=sysv4 ;; netbsd386) basic_machine=i386-pc os=netbsd ;; netwinder) basic_machine=armv4l-rebel os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=newsos ;; news1000) basic_machine=m68030-sony os=newsos ;; necv70) basic_machine=v70-nec os=sysv ;; nh3000) basic_machine=m68k-harris os=cxux ;; nh[45]000) basic_machine=m88k-harris os=cxux ;; nindy960) basic_machine=i960-intel os=nindy ;; mon960) basic_machine=i960-intel os=mon960 ;; nonstopux) basic_machine=mips-compaq os=nonstopux ;; os400) basic_machine=powerpc-ibm os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=ose ;; os68k) basic_machine=m68k-none os=os68k ;; paragon) basic_machine=i860-intel os=osf ;; parisc) basic_machine=hppa-unknown os=linux ;; pw32) basic_machine=i586-unknown os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=rdos ;; rdos32) basic_machine=i386-pc os=rdos ;; rom68k) basic_machine=m68k-rom68k os=coff ;; sa29200) basic_machine=a29k-amd os=udi ;; sei) basic_machine=mips-sei os=seiux ;; sequent) basic_machine=i386-sequent os= ;; sps7) basic_machine=m68k-bull os=sysv2 ;; st2000) basic_machine=m68k-tandem os= ;; stratus) basic_machine=i860-stratus os=sysv4 ;; sun2) basic_machine=m68000-sun os= ;; sun2os3) basic_machine=m68000-sun os=sunos3 ;; sun2os4) basic_machine=m68000-sun os=sunos4 ;; sun3) basic_machine=m68k-sun os= ;; sun3os3) basic_machine=m68k-sun os=sunos3 ;; sun3os4) basic_machine=m68k-sun os=sunos4 ;; sun4) basic_machine=sparc-sun os= ;; sun4os3) basic_machine=sparc-sun os=sunos3 ;; sun4os4) basic_machine=sparc-sun os=sunos4 ;; sun4sol2) basic_machine=sparc-sun os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun os= ;; sv1) basic_machine=sv1-cray os=unicos ;; symmetry) basic_machine=i386-sequent os=dynix ;; t3e) basic_machine=alphaev5-cray os=unicos ;; t90) basic_machine=t90-cray os=unicos ;; toad1) basic_machine=pdp10-xkl os=tops20 ;; tpf) basic_machine=s390x-ibm os=tpf ;; udi29k) basic_machine=a29k-amd os=udi ;; ultra3) basic_machine=a29k-nyu os=sym1 ;; v810 | necv810) basic_machine=v810-nec os=none ;; vaxv) basic_machine=vax-dec os=sysv ;; vms) basic_machine=vax-dec os=vms ;; vsta) basic_machine=i386-pc os=vsta ;; vxworks960) basic_machine=i960-wrs os=vxworks ;; vxworks68) basic_machine=m68k-wrs os=vxworks ;; vxworks29k) basic_machine=a29k-wrs os=vxworks ;; xbox) basic_machine=i686-pc os=mingw32 ;; ymp) basic_machine=ymp-cray os=unicos ;; *) basic_machine=$1 os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi os=${os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray os=${os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $os in irix*) ;; *) os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony os=newsos ;; next | m*-next) cpu=m68k vendor=next case $os in openstep*) ;; nextstep*) ;; ns2*) os=nextstep2 ;; *) os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde os=${os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x$os != x ] then case $os in # First match some system type aliases that might get confused # with valid system types. # solaris* is a basic system type, with this one exception. auroraux) os=auroraux ;; bluegene*) os=cnk ;; solaris1 | solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; solaris) os=solaris2 ;; unixware*) os=sysv4.2uw ;; gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) es1800*) os=ose ;; # Some version numbers need modification chorusos*) os=chorusos ;; isc) os=isc2.2 ;; sco6) os=sco5v6 ;; sco5) os=sco3.2v5 ;; sco4) os=sco3.2v4 ;; sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` ;; sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; scout) # Don't match below ;; sco*) os=sco3.2v2 ;; psos*) os=psos ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # sysv* is not here because it comes later, after sysvr4. gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | sym* | kopensolaris* | plan9* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ | knetbsd* | mirbsd* | netbsd* \ | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* \ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ | linux-newlib* | linux-musl* | linux-uclibc* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ | openstep* | oskit* | conix* | pw32* | nonstopux* \ | storm-chaos* | tops10* | tenex* | tops20* | its* \ | os2* | vos* | palmos* | uclinux* | nucleus* \ | morphos* | superux* | rtmk* | windiss* \ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ | skyos* | haiku* | rdos* | toppers* | drops* | es* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | nsk* | powerunix* | genode*) # Remember, each alternative MUST END IN *, to match a version number. ;; qnx*) case $cpu in x86 | i*86) ;; *) os=nto-$os ;; esac ;; hiux*) os=hiuxwe2 ;; nto-qnx*) ;; nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; sim | xray | os68k* | v88r* \ | windows* | osx | abug | netware* | os9* \ | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) ;; linux-dietlibc) os=linux-dietlibc ;; linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; lynx*178) os=lynxos178 ;; lynx*5) os=lynxos5 ;; lynx*) os=lynxos ;; mac*) os=`echo "$os" | sed -e 's|mac|macos|'` ;; opened*) os=openedition ;; os400*) os=os400 ;; sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; wince*) os=wince ;; utek*) os=bsd ;; dynix*) os=bsd ;; acis*) os=aos ;; atheos*) os=atheos ;; syllable*) os=syllable ;; 386bsd) os=bsd ;; ctix* | uts*) os=sysv ;; nova*) os=rtmk-nova ;; ns2) os=nextstep2 ;; # Preserve the version number of sinix5. sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; sinix*) os=sysv4 ;; tpf*) os=tpf ;; triton*) os=sysv3 ;; oss*) os=sysv3 ;; svr4*) os=sysv4 ;; svr3) os=sysv3 ;; sysvr4) os=sysv4 ;; # This must come after sysvr4. sysv*) ;; ose*) os=ose ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) os=mint ;; zvmoe) os=zvmoe ;; dicos*) os=dicos ;; pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $cpu in arm*) os=eabi ;; *) os=elf ;; esac ;; nacl*) ;; ios) ;; none) ;; *-eabi) ;; *) echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $cpu-$vendor in score-*) os=elf ;; spu-*) os=elf ;; *-acorn) os=riscix1.2 ;; arm*-rebel) os=linux ;; arm*-semi) os=aout ;; c4x-* | tic4x-*) os=coff ;; c8051-*) os=elf ;; clipper-intergraph) os=clix ;; hexagon-*) os=elf ;; tic54x-*) os=coff ;; tic55x-*) os=coff ;; tic6x-*) os=coff ;; # This must come before the *-dec entry. pdp10-*) os=tops20 ;; pdp11-*) os=none ;; *-dec | vax-*) os=ultrix4.2 ;; m68*-apollo) os=domain ;; i386-sun) os=sunos4.0.2 ;; m68000-sun) os=sunos3 ;; m68*-cisco) os=aout ;; mep-*) os=elf ;; mips*-cisco) os=elf ;; mips*-*) os=elf ;; or32-*) os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 ;; sparc-* | *-sun) os=sunos4.1.1 ;; pru-*) os=elf ;; *-be) os=beos ;; *-ibm) os=aix ;; *-knuth) os=mmixware ;; *-wec) os=proelf ;; *-winbond) os=proelf ;; *-oki) os=proelf ;; *-hp) os=hpux ;; *-hitachi) os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=sysv ;; *-cbm) os=amigaos ;; *-dg) os=dgux ;; *-dolphin) os=sysv3 ;; m68k-ccur) os=rtu ;; m88k-omron*) os=luna ;; *-next) os=nextstep ;; *-sequent) os=ptx ;; *-crds) os=unos ;; *-ns) os=genix ;; i370-*) os=mvs ;; *-gould) os=sysv ;; *-highlevel) os=bsd ;; *-encore) os=bsd ;; *-sgi) os=irix ;; *-siemens) os=sysv4 ;; *-masscomp) os=rtu ;; f30[01]-fujitsu | f700-fujitsu) os=uxpv ;; *-rom68k) os=coff ;; *-*bug) os=coff ;; *-apple) os=macos ;; *-atari*) os=mint ;; *-wrs) os=vxworks ;; *) os=none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $os in riscix*) vendor=acorn ;; sunos*) vendor=sun ;; cnk*|-aix*) vendor=ibm ;; beos*) vendor=be ;; hpux*) vendor=hp ;; mpeix*) vendor=hp ;; hiux*) vendor=hitachi ;; unos*) vendor=crds ;; dgux*) vendor=dg ;; luna*) vendor=omron ;; genix*) vendor=ns ;; clix*) vendor=intergraph ;; mvs* | opened*) vendor=ibm ;; os400*) vendor=ibm ;; ptx*) vendor=sequent ;; tpf*) vendor=ibm ;; vxsim* | vxworks* | windiss*) vendor=wrs ;; aux*) vendor=apple ;; hms*) vendor=hitachi ;; mpw* | macos*) vendor=apple ;; *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) vendor=atari ;; vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsync-3.2.7/fileio.c0000664000000000000000000002012513675270555013013 0ustar rootroot/* * File IO utilities used in rsync. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2020 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 "inums.h" #ifndef ENODATA #define ENODATA EAGAIN #endif /* We want all reads to be aligned on 1K boundaries. */ #define ALIGN_BOUNDARY 1024 /* How far past the boundary is an offset? */ #define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDARY-1)) /* Round up a length to the next boundary */ #define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDARY-1)) + 1) extern int sparse_files; OFF_T preallocated_len = 0; static OFF_T sparse_seek = 0; static OFF_T sparse_past_write = 0; int sparse_end(int f, OFF_T size) { int ret; sparse_past_write = 0; if (!sparse_seek) return 0; #ifdef HAVE_FTRUNCATE ret = do_ftruncate(f, size); #else if (do_lseek(f, sparse_seek-1, SEEK_CUR) != size-1) ret = -1; else { do { ret = write(f, "", 1); } while (ret < 0 && errno == EINTR); ret = ret <= 0 ? -1 : 0; } #endif sparse_seek = 0; return ret; } /* Note that the offset is just the caller letting us know where * the current file position is in the file. The use_seek arg tells * us that we should seek over matching data instead of writing it. */ static int write_sparse(int f, int use_seek, OFF_T offset, const char *buf, int len) { int l1 = 0, l2 = 0; int ret; for (l1 = 0; l1 < len && buf[l1] == 0; l1++) {} for (l2 = 0; l2 < len-l1 && buf[len-(l2+1)] == 0; l2++) {} sparse_seek += l1; if (l1 == len) return len; if (sparse_seek) { if (sparse_past_write >= preallocated_len) { if (do_lseek(f, sparse_seek, SEEK_CUR) < 0) return -1; } else if (do_punch_hole(f, sparse_past_write, sparse_seek) < 0) { sparse_seek = 0; return -1; } } sparse_seek = l2; sparse_past_write = offset + len - l2; if (use_seek) { /* The in-place data already matches. */ if (do_lseek(f, len - (l1+l2), SEEK_CUR) < 0) return -1; return len; } while ((ret = write(f, buf + l1, len - (l1+l2))) <= 0) { if (ret < 0 && errno == EINTR) continue; sparse_seek = 0; return ret; } if (ret != (int)(len - (l1+l2))) { sparse_seek = 0; return l1+ret; } return len; } static char *wf_writeBuf; static size_t wf_writeBufSize; static size_t wf_writeBufCnt; int flush_write_file(int f) { int ret = 0; char *bp = wf_writeBuf; while (wf_writeBufCnt > 0) { if ((ret = write(f, bp, wf_writeBufCnt)) < 0) { if (errno == EINTR) continue; return ret; } wf_writeBufCnt -= ret; bp += ret; } return ret; } /* write_file does not allow incomplete writes. It loops internally * until len bytes are written or errno is set. Note that use_seek and * offset are only used in sparse processing (see write_sparse()). */ int write_file(int f, int use_seek, OFF_T offset, const char *buf, int len) { int ret = 0; while (len > 0) { int r1; if (sparse_files > 0) { int len1 = MIN(len, SPARSE_WRITE_SIZE); r1 = write_sparse(f, use_seek, offset, buf, len1); offset += r1; } else { if (!wf_writeBuf) { wf_writeBufSize = WRITE_SIZE * 8; wf_writeBufCnt = 0; wf_writeBuf = new_array(char, wf_writeBufSize); } r1 = (int)MIN((size_t)len, wf_writeBufSize - wf_writeBufCnt); if (r1) { memcpy(wf_writeBuf + wf_writeBufCnt, buf, r1); wf_writeBufCnt += r1; } if (wf_writeBufCnt == wf_writeBufSize) { if (flush_write_file(f) < 0) return -1; if (!r1 && len) continue; } } if (r1 <= 0) { if (ret > 0) return ret; return r1; } len -= r1; buf += r1; ret += r1; } return ret; } /* An in-place update found identical data at an identical location. We either * just seek past it, or (for an in-place sparse update), we give the data to * the sparse processor with the use_seek flag set. */ int skip_matched(int fd, OFF_T offset, const char *buf, int len) { OFF_T pos; if (sparse_files > 0) { if (write_file(fd, 1, offset, buf, len) != len) return -1; return 0; } if (flush_write_file(fd) < 0) return -1; if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset + len) { rsyserr(FERROR_XFER, errno, "lseek returned %s, not %s", big_num(pos), big_num(offset)); return -1; } return 0; } /* This provides functionality somewhat similar to mmap() but using read(). * It gives sliding window access to a file. mmap() is not used because of * the possibility of another program (such as a mailer) truncating the * file thus giving us a SIGBUS. */ struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size) { struct map_struct *map; map = new0(struct map_struct); if (blk_size && (read_size % blk_size)) read_size += blk_size - (read_size % blk_size); map->fd = fd; map->file_size = len; map->def_window_size = ALIGNED_LENGTH(read_size); return map; } /* slide the read window in the file */ char *map_ptr(struct map_struct *map, OFF_T offset, int32 len) { OFF_T window_start, read_start; int32 window_size, read_size, read_offset, align_fudge; if (len == 0) return NULL; if (len < 0) { rprintf(FERROR, "invalid len passed to map_ptr: %ld\n", (long)len); exit_cleanup(RERR_FILEIO); } /* in most cases the region will already be available */ if (offset >= map->p_offset && offset+len <= map->p_offset+map->p_len) return map->p + (offset - map->p_offset); /* nope, we are going to have to do a read. Work out our desired window */ align_fudge = (int32)ALIGNED_OVERSHOOT(offset); window_start = offset - align_fudge; window_size = map->def_window_size; if (window_start + window_size > map->file_size) window_size = (int32)(map->file_size - window_start); if (window_size < len + align_fudge) window_size = ALIGNED_LENGTH(len + align_fudge); /* make sure we have allocated enough memory for the window */ if (window_size > map->p_size) { map->p = realloc_array(map->p, char, window_size); map->p_size = window_size; } /* Now try to avoid re-reading any bytes by reusing any bytes from the previous buffer. */ if (window_start >= map->p_offset && window_start < map->p_offset + map->p_len && window_start + window_size >= map->p_offset + map->p_len) { read_start = map->p_offset + map->p_len; read_offset = (int32)(read_start - window_start); read_size = window_size - read_offset; memmove(map->p, map->p + (map->p_len - read_offset), read_offset); } else { read_start = window_start; read_size = window_size; read_offset = 0; } if (read_size <= 0) { rprintf(FERROR, "invalid read_size of %ld in map_ptr\n", (long)read_size); exit_cleanup(RERR_FILEIO); } if (map->p_fd_offset != read_start) { OFF_T ret = do_lseek(map->fd, read_start, SEEK_SET); if (ret != read_start) { rsyserr(FERROR, errno, "lseek returned %s, not %s", big_num(ret), big_num(read_start)); exit_cleanup(RERR_FILEIO); } map->p_fd_offset = read_start; } map->p_offset = window_start; map->p_len = window_size; while (read_size > 0) { int32 nread = read(map->fd, map->p + read_offset, read_size); if (nread <= 0) { if (!map->status) map->status = nread ? errno : ENODATA; /* The best we can do is zero the buffer -- the file * has changed mid transfer! */ memset(map->p + read_offset, 0, read_size); break; } map->p_fd_offset += nread; read_offset += nread; read_size -= nread; } return map->p + align_fudge; } int unmap_file(struct map_struct *map) { int ret; if (map->p) { free(map->p); map->p = NULL; } ret = map->status; #if 0 /* I don't think we really need this. */ force_memzero(map, sizeof map[0]); #endif free(map); return ret; } rsync-3.2.7/tls.c0000664000000000000000000001773214170671375012354 0ustar rootroot/* * Trivial ls for comparing two directories after running an rsync. * * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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, write to the Free Software Foundation, Inc., * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* The problem with using the system's own ls is that some features * have little quirks that make directories look different when for * our purposes they're the same -- for example, the BSD braindamage * about setting the mode on symlinks based on your current umask. * * All the filenames must be given on the command line -- tls does not * even read directories, let alone recurse. The typical usage is * "find|sort|xargs tls". * * The format is not exactly the same as any particular Unix ls(1). * * A key requirement for this program is that the output be "very * reproducible." So we mask away information that can accidentally * change. */ #include "rsync.h" #include #include "lib/sysxattrs.h" #define PROGRAM "tls" /* These are to make syscall.o shut up. */ int dry_run = 0; int am_root = 0; int am_sender = 1; int read_only = 1; int list_only = 0; int link_times = 0; int link_owner = 0; int nsec_times = 0; #ifdef SUPPORT_XATTRS #ifdef HAVE_LINUX_XATTRS #define XSTAT_ATTR "user.rsync.%stat" #else #define XSTAT_ATTR "rsync.%stat" #endif static int stat_xattr(const char *fname, STRUCT_STAT *fst) { unsigned int mode; int rdev_major, rdev_minor, uid, gid, len; char buf[256]; if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode)) return -1; len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1); if (len >= (int)sizeof buf) { len = -1; errno = ERANGE; } if (len < 0) { if (errno == ENOTSUP || errno == ENOATTR) return -1; if (errno == EPERM && S_ISLNK(fst->st_mode)) { fst->st_uid = 0; fst->st_gid = 0; return 0; } fprintf(stderr, "failed to read xattr %s for %s: %s\n", XSTAT_ATTR, fname, strerror(errno)); return -1; } buf[len] = '\0'; if (sscanf(buf, "%o %d,%d %d:%d", &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) { fprintf(stderr, "Corrupt %s xattr attached to %s: \"%s\"\n", XSTAT_ATTR, fname, buf); exit(1); } #if _S_IFLNK != 0120000 if ((mode & (_S_IFMT)) == 0120000) mode = (mode & ~(_S_IFMT)) | _S_IFLNK; #endif fst->st_mode = mode; fst->st_rdev = MAKEDEV(rdev_major, rdev_minor); fst->st_uid = uid; fst->st_gid = gid; return 0; } #endif static int display_atimes = 0; #ifdef SUPPORT_CRTIMES static int display_crtimes = 0; #endif static void failed(char const *what, char const *where) { fprintf(stderr, PROGRAM ": %s %s: %s\n", what, where, strerror(errno)); exit(1); } static void storetime(char *dest, size_t destsize, time_t t, int nsecs) { if (t) { int len; struct tm *mt = gmtime(&t); len = snprintf(dest, destsize, " %04d-%02d-%02d %02d:%02d:%02d", (int)mt->tm_year + 1900, (int)mt->tm_mon + 1, (int)mt->tm_mday, (int)mt->tm_hour, (int)mt->tm_min, (int)mt->tm_sec); if (nsecs >= 0 && len >= 0) snprintf(dest + len, destsize - len, ".%09d", nsecs); } else { int has_nsecs = nsecs >= 0 ? 1 : 0; int len = MIN(20 + 10*has_nsecs, (int)destsize - 1); memset(dest, ' ', len); dest[len] = '\0'; } } static void list_file(const char *fname) { STRUCT_STAT buf; #ifdef SUPPORT_CRTIMES time_t crtime = 0; #endif char permbuf[PERMSTRING_SIZE]; char mtimebuf[50]; char atimebuf[50]; char crtimebuf[50]; char linkbuf[4096]; int nsecs; if (do_lstat(fname, &buf) < 0) failed("stat", fname); #ifdef SUPPORT_CRTIMES if (display_crtimes && (crtime = get_create_time(fname, &buf)) == 0) failed("get_create_time", fname); #endif #ifdef SUPPORT_XATTRS if (am_root < 0) stat_xattr(fname, &buf); #endif /* The size of anything but a regular file is probably not * worth thinking about. */ if (!S_ISREG(buf.st_mode)) buf.st_size = 0; /* On some BSD platforms the mode bits of a symlink are * undefined. Also it tends not to be possible to reset a * symlink's mtime, so we default to ignoring it too. */ if (S_ISLNK(buf.st_mode)) { int len; buf.st_mode &= ~0777; if (!link_times) buf.st_mtime = (time_t)0; if (!link_owner) buf.st_uid = buf.st_gid = 0; strlcpy(linkbuf, " -> ", sizeof linkbuf); /* const-cast required for silly UNICOS headers */ len = do_readlink((char*)fname, linkbuf+4, sizeof linkbuf - 4); if (len == -1) failed("do_readlink", fname); else /* it's not nul-terminated */ linkbuf[4+len] = 0; } else { linkbuf[0] = '\0'; } permstring(permbuf, buf.st_mode); #ifdef ST_MTIME_NSEC if (nsec_times) nsecs = (int)buf.ST_MTIME_NSEC; else #endif nsecs = -1; storetime(mtimebuf, sizeof mtimebuf, buf.st_mtime, nsecs); if (display_atimes) storetime(atimebuf, sizeof atimebuf, S_ISDIR(buf.st_mode) ? 0 : buf.st_atime, -1); else atimebuf[0] = '\0'; #ifdef SUPPORT_CRTIMES if (display_crtimes) storetime(crtimebuf, sizeof crtimebuf, crtime, -1); else #endif crtimebuf[0] = '\0'; /* TODO: Perhaps escape special characters in fname? */ printf("%s ", permbuf); if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) { printf("%5ld,%6ld", (long)major(buf.st_rdev), (long)minor(buf.st_rdev)); } else printf("%15s", do_big_num(buf.st_size, 1, NULL)); printf(" %6ld.%-6ld %6ld%s%s%s %s%s\n", (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink, mtimebuf, atimebuf, crtimebuf, fname, linkbuf); } static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"atimes", 'U', POPT_ARG_NONE, &display_atimes, 0, 0, 0}, #ifdef SUPPORT_CRTIMES {"crtimes", 'N', POPT_ARG_NONE, &display_crtimes, 0, 0, 0}, #endif {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 }, {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 }, #ifdef SUPPORT_XATTRS {"fake-super", 'f', POPT_ARG_VAL, &am_root, -1, 0, 0 }, #endif #ifdef ST_MTIME_NSEC {"nsec", 's', POPT_ARG_NONE, &nsec_times, 0, 0, 0 }, #endif {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 }, {0,0,0,0,0,0,0} }; static void NORETURN tls_usage(int ret) { FILE *F = ret ? stderr : stdout; fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n"); fprintf(F,"Trivial file listing program for portably checking rsync\n"); fprintf(F,"\nOptions:\n"); fprintf(F," -U, --atimes display access (last-used) times\n"); #ifdef SUPPORT_CRTIMES fprintf(F," -N, --crtimes display create times (newness)\n"); #endif fprintf(F," -l, --link-times display the time on a symlink\n"); fprintf(F," -L, --link-owner display the owner+group on a symlink\n"); #ifdef SUPPORT_XATTRS fprintf(F," -f, --fake-super display attributes including fake-super xattrs\n"); #endif fprintf(F," -h, --help show this help\n"); exit(ret); } int main(int argc, char *argv[]) { poptContext pc; const char **extra_args; int opt; pc = poptGetContext(PROGRAM, argc, (const char **)argv, long_options, 0); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case 'h': tls_usage(0); default: fprintf(stderr, "%s: %s\n", poptBadOption(pc, POPT_BADOPTION_NOALIAS), poptStrerror(opt)); tls_usage(1); } } extra_args = poptGetArgs(pc); if (!extra_args || *extra_args == NULL) tls_usage(1); for (; *extra_args; extra_args++) list_file(*extra_args); poptFreeContext(pc); return 0; } rsync-3.2.7/configure.ac0000664000000000000000000013426614323037532013665 0ustar rootrootdnl Process this file with autoconf to produce a configure script. AC_INIT([rsync],[ ],[https://rsync.samba.org/bug-tracking.html]) AC_C_BIGENDIAN AC_HEADER_DIRENT AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \ unistd.h utime.h compat.h sys/param.h ctype.h sys/wait.h sys/stat.h \ sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h grp.h \ sys/un.h sys/attr.h arpa/inet.h arpa/nameser.h locale.h sys/types.h \ netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h mcheck.h \ sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h dl.h \ popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netgroup.h \ zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h \ bsd/string.h) AC_CHECK_HEADERS([netinet/ip.h], [], [], [[#include ]]) AC_HEADER_MAJOR_FIXED AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([byteorder.h]) AC_CONFIG_HEADERS([config.h]) AC_PREREQ([2.69]) PACKAGE_VERSION=`sed -n 's/.*RSYNC_VERSION.*"\(.*\)".*/\1/p' <$srcdir/version.h` AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION]) LDFLAGS=${LDFLAGS-""} AC_CANONICAL_HOST dnl define the directory for replacement function since AC_LIBOBJ does not dnl officially support subdirs and fails with automake AC_CONFIG_LIBOBJ_DIR([lib]) # We must decide this before testing the compiler. # Please allow this to default to yes, so that your users have more # chance of getting a useful stack trace if problems occur. AC_MSG_CHECKING([whether to include debugging symbols]) AC_ARG_ENABLE(debug, AS_HELP_STRING([--disable-debug],[disable to omit debugging symbols and features])) if test x"$enable_debug" = x"no"; then AC_MSG_RESULT(no) ac_cv_prog_cc_g=no else AC_MSG_RESULT([yes]) dnl AC_DEFINE(DEBUG, 1, [Define to turn on debugging code that may slow normal operation]) # leave ac_cv_prog_cc_g alone; AC_PROG_CC will try to include -g if it can fi dnl Checks for programs. AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_AWK AC_PROG_EGREP AC_PROG_INSTALL AC_PROG_MKDIR_P AC_SUBST(SHELL) AC_PATH_PROG([PERL], [perl]) AC_PATH_PROG([PYTHON3], [python3]) AC_DEFINE([_GNU_SOURCE], 1, [Define _GNU_SOURCE so that we get all necessary prototypes]) if test x"$ac_cv_prog_cc_stdc" = x"no"; then AC_MSG_WARN([rsync requires an ANSI C compiler and you do not seem to have one]) fi no_lib='' err_msg='' nl=' ' AC_ARG_ENABLE(profile, AS_HELP_STRING([--enable-profile],[enable to turn on CPU profiling])) if test x"$enable_profile" = x"yes"; then CFLAGS="$CFLAGS -pg" fi AC_MSG_CHECKING([if md2man can create manpages]) if test x"$ac_cv_path_PYTHON3" = x; then AC_MSG_RESULT(no - python3 not found) md2man_works=no else md2man_out=`"$srcdir/md2man" --test "$srcdir/rsync-ssl.1.md" 2>&1` if test $? = 0; then AC_MSG_RESULT(yes) md2man_works=yes else AC_MSG_RESULT(no) md2man_works=no echo "$md2man_out" fi fi AC_MSG_CHECKING([if we require man-page building]) AC_ARG_ENABLE([md2man], AS_HELP_STRING([--disable-md2man],[disable to omit manpage creation])) if test x"$enable_md2man" != x"no"; then if test -f "$srcdir/rsync.1"; then AC_MSG_RESULT(optional) else AC_MSG_RESULT(required) if test x"$md2man_works" = x"no"; then err_msg="$err_msg$nl- You need python3 and either the cmarkgfm OR commonmark python3 lib in order" err_msg="$err_msg$nl to build manpages based on the git source (manpages are included in the" err_msg="$err_msg$nl official release tar files)." no_lib="$no_lib md2man" fi fi MAKE_MAN=man else AC_MSG_RESULT(no) fi # Specifically, this turns on panic_action handling. AC_ARG_ENABLE(maintainer-mode, AS_HELP_STRING([--enable-maintainer-mode],[enable to turn on extra debug features])) if test x"$enable_maintainer_mode" = x"yes"; then CFLAGS="$CFLAGS -DMAINTAINER_MODE" fi # This is needed for our included version of popt. Kind of silly, but # I don't want our version too far out of sync. CFLAGS="$CFLAGS -DHAVE_CONFIG_H" # If GCC, turn on warnings. if test x"$GCC" = x"yes"; then CFLAGS="$CFLAGS -Wall -W" fi AC_ARG_WITH(openssl-conf, AS_HELP_STRING([--with-openssl-conf=PATH],[set default OPENSSL_CONF path for rsync])) case "$with_openssl_conf" in *[^-/a-zA-Z0-9.,=@+_]*) AC_MSG_ERROR([Invalid path given to --with-openssl-conf]) ;; /*) CFLAGS="$CFLAGS -DSET_OPENSSL_CONF=$with_openssl_conf" ;; no|'') ;; yes) AC_MSG_ERROR([No path given to --with-openssl-conf]) ;; *) AC_MSG_ERROR([Non absolute path given to --with-openssl-conf]) ;; esac AC_ARG_WITH(rrsync, AS_HELP_STRING([--with-rrsync],[also install the rrsync script and its manpage])) if test x"$with_rrsync" != x"yes"; then with_rrsync=no else MAKE_RRSYNC='rrsync' MAKE_RRSYNC_1='rrsync.1' GEN_RRSYNC='rrsync.1 rrsync.1.html' fi AC_SUBST(with_rrsync) AC_ARG_WITH(included-popt, AS_HELP_STRING([--with-included-popt],[use bundled popt library, not from system])) AC_ARG_WITH(included-zlib, AS_HELP_STRING([--with-included-zlib],[use bundled zlib library, not from system])) AC_ARG_WITH(secluded-args, AS_HELP_STRING([--with-secluded-args],[make --secluded-args option the default])) if test x"$with_secluded_args" = x"yes"; then AC_DEFINE_UNQUOTED(RSYNC_USE_SECLUDED_ARGS, 1, [Define to 1 if --secluded-args should be the default]) fi AC_ARG_WITH(rsync-path, AS_HELP_STRING([--with-rsync-path=PATH],[set default --rsync-path to PATH (default: rsync)]), [ RSYNC_PATH="$with_rsync_path" ], [ RSYNC_PATH="rsync" ]) AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [location of rsync on remote machine]) AC_ARG_WITH(rsyncd-conf, AS_HELP_STRING([--with-rsyncd-conf=PATH],[set configuration file for rsync server to PATH (default: /etc/rsyncd.conf)]), [ if test ! -z "$with_rsyncd_conf" ; then case $with_rsyncd_conf in yes|no) RSYNCD_SYSCONF="/etc/rsyncd.conf" ;; /*) RSYNCD_SYSCONF="$with_rsyncd_conf" ;; *) AC_MSG_ERROR(You must specify an absolute path to --with-rsyncd-conf=PATH) ;; esac else RSYNCD_SYSCONF="/etc/rsyncd.conf" fi ], [ RSYNCD_SYSCONF="/etc/rsyncd.conf" ]) AC_DEFINE_UNQUOTED(RSYNCD_SYSCONF, "$RSYNCD_SYSCONF", [location of configuration file for rsync server]) AC_ARG_WITH(rsh, AS_HELP_STRING([--with-rsh=CMD],[set remote shell command to CMD (default: ssh)])) AC_CHECK_PROG(HAVE_REMSH, remsh, 1, 0) if test x$HAVE_REMSH = x1; then AC_DEFINE(HAVE_REMSH, 1, [Define to 1 if remote shell is remsh, not rsh]) fi if test x"$with_rsh" != x; then RSYNC_RSH="$with_rsh" else RSYNC_RSH="ssh" fi AC_DEFINE_UNQUOTED(RSYNC_RSH, "$RSYNC_RSH", [default -e command]) # Some programs on solaris are only found in /usr/xpg4/bin (or work better than others versions). AC_PATH_PROG(SHELL_PATH, sh, /bin/sh, [/usr/xpg4/bin$PATH_SEPARATOR$PATH]) AC_PATH_PROG(FAKEROOT_PATH, fakeroot, /usr/bin/fakeroot, [/usr/xpg4/bin$PATH_SEPARATOR$PATH]) AC_ARG_WITH(nobody-user, AS_HELP_STRING([--with-nobody-user=USER],[set the default unprivileged user (default nobody)]), [ NOBODY_USER="$with_nobody_user" ], [ NOBODY_USER="nobody" ]) AC_ARG_WITH(nobody-group, AS_HELP_STRING([--with-nobody-group=GROUP],[set the default unprivileged group (default nobody or nogroup)]), [ NOBODY_GROUP="$with_nobody_group" ]) if test x"$with_nobody_group" = x; then AC_MSG_CHECKING([the group for user "nobody"]) if grep '^nobody:' /etc/group >/dev/null 2>&1; then NOBODY_GROUP=nobody elif grep '^nogroup:' /etc/group >/dev/null 2>&1; then NOBODY_GROUP=nogroup else NOBODY_GROUP=nobody # test for others? fi AC_MSG_RESULT($NOBODY_GROUP) fi AC_DEFINE_UNQUOTED(NOBODY_USER, "$NOBODY_USER", [unprivileged user--e.g. nobody]) AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user]) # rolling-checksum SIMD optimizations ROLL_SIMD= AC_MSG_CHECKING([whether to enable rolling-checksum SIMD optimizations]) AC_ARG_ENABLE(roll-simd, AS_HELP_STRING([--enable-roll-simd],[enable/disable to control rolling-checksum SIMD optimizations (requires c++)])) # Clag is crashing with -g -O2, so we'll get rid of -g for now. CXXFLAGS=`echo "$CXXFLAGS" | sed 's/-g //'` m4_define(SIMD_X86_64_TEST, [[#include #if HAVE_STDLIB_H #include #endif #include __attribute__ ((target("default"))) int test_ssse3(int x) { return x; } __attribute__ ((target("default"))) int test_sse2(int x) { return x; } __attribute__ ((target("default"))) int test_avx2(int x) { return x; } __attribute__ ((target("ssse3"))) int test_ssse3(int x) { return x; } __attribute__ ((target("sse2"))) int test_sse2(int x) { return x; } __attribute__ ((target("avx2"))) int test_avx2(int x) { return x; } typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(1))); __attribute__ ((target("default"))) void more_testing(char* buf, int len) { } __attribute__ ((target("ssse3"))) void more_testing(char* buf, int len) { int i; for (i = 0; i < (len-32); i+=32) { __m128i in8_1, in8_2; in8_1 = _mm_lddqu_si128((__m128i_u*)&buf[i]); in8_2 = _mm_lddqu_si128((__m128i_u*)&buf[i + 16]); } } ]]) if test x"$enable_roll_simd" = x""; then case "$host_os" in *linux*) ;; *) enable_roll_simd=no ;; esac fi if test x"$enable_roll_simd" != x"no"; then # For x86-64 SIMD, g++ >=5 or clang++ >=7 is required if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then AC_LANG(C++) if test x"$host" = x"$build"; then AC_RUN_IFELSE([AC_LANG_PROGRAM([SIMD_X86_64_TEST],[[if (test_ssse3(42) != 42 || test_sse2(42) != 42 || test_avx2(42) != 42) exit(1);]])], [CXX_OK=yes],[CXX_OK=no]) else AC_COMPILE_IFELSE([AC_LANG_PROGRAM([SIMD_X86_64_TEST])],[CXX_OK=yes],[CXX_OK=no]) fi AC_LANG(C) if test x"$CXX_OK" = x"yes"; then # AC_MSG_RESULT() is called below. ROLL_SIMD="$host_cpu" elif test x"$enable_roll_simd" = x"yes"; then AC_MSG_RESULT(error) AC_MSG_ERROR(The rolling-checksum SIMD compilation test failed. Omit --enable-roll-simd to continue without it.) fi elif test x"$enable_roll_simd" = x"yes"; then AC_MSG_RESULT(unavailable) AC_MSG_ERROR(The rolling-checksum SIMD optimizations are currently x86_64|amd64 only. Omit --enable-roll-simd to continue without it.) fi fi if test x"$ROLL_SIMD" != x""; then AC_MSG_RESULT([yes ($ROLL_SIMD)]) AC_DEFINE(USE_ROLL_SIMD, 1, [Define to 1 to enable rolling-checksum SIMD optimizations]) ROLL_SIMD='$(ROLL_SIMD_'"$ROLL_SIMD)" # We only use c++ for its target attribute dispatching, disable unneeded bulky features CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" # Apple often has "g++" as a symlink for clang. Try to find out the truth. CXX_VERSION=`$CXX --version 2>/dev/null | head -n 2` case "$CXX_VERSION" in *clang*) CXXFLAGS="$CXXFLAGS -fno-slp-vectorize" ;; # avoid a performance hit esac else AC_MSG_RESULT(no) fi AC_SUBST(ROLL_SIMD) AC_MSG_CHECKING([if assembler accepts noexecstack]) OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wa,--noexecstack" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[return 0;]])], [ NOEXECSTACK='-Wa,--noexecstack' ; AC_MSG_RESULT(yes) ], [ NOEXECSTACK='' ; AC_MSG_RESULT(no) ]) CFLAGS="$OLD_CFLAGS" AC_SUBST(NOEXECSTACK) # arrgh. libc in some old debian version screwed up the largefile # stuff, getting byte range locking wrong AC_CACHE_CHECK([for broken largefile support],rsync_cv_HAVE_BROKEN_LARGEFILE,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #define _FILE_OFFSET_BITS 64 $ac_includes_default #ifdef HAVE_FCNTL_H # include #elif defined HAVE_SYS_FCNTL_H # include #endif #ifdef HAVE_SYS_WAIT_H #include #endif int main(void) { struct flock lock; int status; char tpl[32] = "/tmp/locktest.XXXXXX"; int fd = mkstemp(tpl); if (fd < 0) { strcpy(tpl, "conftest.dat"); fd = open(tpl, O_CREAT|O_RDWR, 0600); } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; lock.l_pid = 0; fcntl(fd,F_SETLK,&lock); if (fork() == 0) { lock.l_start = 1; _exit(fcntl(fd,F_SETLK,&lock) == 0); } wait(&status); unlink(tpl); return WEXITSTATUS(status); } ]])],[rsync_cv_HAVE_BROKEN_LARGEFILE=yes],[rsync_cv_HAVE_BROKEN_LARGEFILE=no],[rsync_cv_HAVE_BROKEN_LARGEFILE=cross])]) if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then AC_SYS_LARGEFILE fi AC_MSG_CHECKING([whether to enable ipv6]) AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--disable-ipv6],[disable to omit ipv6 support]), [ case "$enableval" in no) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(yes) AC_DEFINE(INET6, 1, [true if you have IPv6]) ;; esac ], AC_RUN_IFELSE([AC_LANG_SOURCE([[ /* AF_INET6 availability check */ #include #include #include main() { if (socket(AF_INET6, SOCK_STREAM, 0) < 0) exit(1); else exit(0); } ]])], [AC_MSG_RESULT(yes) AC_DEFINE(INET6, 1, true if you have IPv6)], [AC_MSG_RESULT(no)], [AC_MSG_RESULT(no)] )) dnl Do you want to disable use of locale functions AC_ARG_ENABLE([locale], AS_HELP_STRING([--disable-locale],[disable to omit locale features])) AH_TEMPLATE([CONFIG_LOCALE], [Undefine if you do not want locale features. By default this is defined.]) if test x"$enable_locale" != x"no"; then AC_DEFINE(CONFIG_LOCALE) fi AC_MSG_CHECKING([whether to call shutdown on all sockets]) case $host_os in *cygwin* ) AC_MSG_RESULT(yes) AC_DEFINE(SHUTDOWN_ALL_SOCKETS, 1, [Define to 1 if sockets need to be shutdown]) ;; * ) AC_MSG_RESULT(no);; esac AC_MSG_CHECKING([whether to enable use of openssl crypto library]) AC_ARG_ENABLE([openssl], AS_HELP_STRING([--disable-openssl],[disable to omit openssl crypto library])) AH_TEMPLATE([USE_OPENSSL], [Undefine if you do not want to use openssl crypto library. By default this is defined.]) if test x"$enable_openssl" != x"no"; then if test x"$ac_cv_header_openssl_md4_h" = x"yes" && test x"$ac_cv_header_openssl_md5_h" = x"yes"; then AC_MSG_RESULT(yes) AC_SEARCH_LIBS(MD5_Init, crypto, [AC_DEFINE(USE_OPENSSL) enable_openssl=yes], [err_msg="$err_msg$nl- Failed to find MD5_Init function in openssl crypto lib."; no_lib="$no_lib openssl"]) else AC_MSG_RESULT(no) err_msg="$err_msg$nl- Failed to find openssl/md4.h and openssl/md5.h for openssl crypto lib support." no_lib="$no_lib openssl" fi if test x"$enable_md5_asm" != x"yes"; then enable_md5_asm=no fi else AC_MSG_RESULT(no) fi MD5_ASM= AC_MSG_CHECKING([whether to enable MD5 ASM optimizations]) AC_ARG_ENABLE(md5-asm, AS_HELP_STRING([--enable-md5-asm],[enable/disable to control MD5 ASM optimizations])) if test x"$enable_md5_asm" = x""; then case "$host_os" in *linux*) ;; *) enable_md5_asm=no ;; esac fi if test x"$enable_md5_asm" != x"no"; then if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then MD5_ASM="$host_cpu" elif test x"$enable_md5_asm" = x"yes"; then AC_MSG_RESULT(unavailable) AC_MSG_ERROR(The ASM optimizations are currently x86_64|amd64 only. Omit --enable-md5-asm to continue without it.) fi fi if test x"$MD5_ASM" != x""; then AC_MSG_RESULT([yes ($MD5_ASM)]) AC_DEFINE(USE_MD5_ASM, 1, [Define to 1 to enable MD5 ASM optimizations]) MD5_ASM='$(MD5_ASM_'"$MD5_ASM)" else AC_MSG_RESULT(no) fi AC_SUBST(MD5_ASM) ROLL_ASM= AC_MSG_CHECKING([whether to enable rolling-checksum ASM optimizations]) AC_ARG_ENABLE(roll-asm, AS_HELP_STRING([--enable-roll-asm],[enable/disable to control rolling-checksum ASM optimizations (requires --enable-roll-simd)])) if test x"$ROLL_SIMD" = x""; then enable_roll_asm=no fi if test x"$enable_roll_asm" = x"yes"; then ROLL_ASM="$host_cpu" AC_MSG_RESULT([yes ($ROLL_ASM)]) AC_DEFINE(USE_ROLL_ASM, 1, [Define to 1 to enable rolling-checksum ASM optimizations (requires --enable-roll-simd)]) ROLL_ASM='$(ROLL_ASM_'"$ROLL_ASM)" else AC_MSG_RESULT(no) fi AC_SUBST(ROLL_ASM) AC_MSG_CHECKING([whether to enable xxhash checksum support]) AC_ARG_ENABLE([xxhash], AS_HELP_STRING([--disable-xxhash],[disable to omit xxhash checksums])) AH_TEMPLATE([SUPPORT_XXHASH], [Undefine if you do not want xxhash checksums. By default this is defined.]) if test x"$enable_xxhash" != x"no"; then if test x"$ac_cv_header_xxhash_h" = x"yes"; then AC_MSG_RESULT(yes) AC_SEARCH_LIBS(XXH64_createState, xxhash, [AC_DEFINE(SUPPORT_XXHASH)], [err_msg="$err_msg$nl- Failed to find XXH64_createState function in xxhash lib."; no_lib="$no_lib xxhash"]) else AC_MSG_RESULT(no) err_msg="$err_msg$nl- Failed to find xxhash.h for xxhash checksum support."; no_lib="$no_lib xxhash" fi else AC_MSG_RESULT(no) fi AC_MSG_CHECKING([whether to enable zstd compression]) AC_ARG_ENABLE([zstd], AS_HELP_STRING([--disable-zstd], [disable to omit zstd compression])) AH_TEMPLATE([SUPPORT_ZSTD], [Undefine if you do not want zstd compression. By default this is defined.]) if test x"$enable_zstd" != x"no"; then if test x"$ac_cv_header_zstd_h" = x"yes"; then AC_MSG_RESULT(yes) AC_SEARCH_LIBS(ZSTD_minCLevel, zstd, [AC_DEFINE(SUPPORT_ZSTD)], [err_msg="$err_msg$nl- Failed to find ZSTD_minCLevel function in zstd lib."; no_lib="$no_lib zstd"]) else AC_MSG_RESULT(no) err_msg="$err_msg$nl- Failed to find zstd.h for zstd compression support."; no_lib="$no_lib zstd" fi else AC_MSG_RESULT(no) fi AC_MSG_CHECKING([whether to enable LZ4 compression]) AC_ARG_ENABLE([lz4], AS_HELP_STRING([--disable-lz4], [disable to omit LZ4 compression])) AH_TEMPLATE([SUPPORT_LZ4], [Undefine if you do not want LZ4 compression. By default this is defined.]) if test x"$enable_lz4" != x"no"; then if test x"$ac_cv_header_lz4_h" = x"yes"; then AC_MSG_RESULT(yes) AC_SEARCH_LIBS(LZ4_compress_default, lz4, [AC_DEFINE(SUPPORT_LZ4)], [err_msg="$err_msg$nl- Failed to find LZ4_compress_default function in lz4 lib."; no_lib="$no_lib lz4"]) else AC_MSG_RESULT(no) err_msg="$err_msg$nl- Failed to find lz4.h for lz4 compression support." no_lib="$no_lib lz4" fi else AC_MSG_RESULT(no) fi if test x"$no_lib" != x; then echo "" echo "Configure found the following issues:" echo "$err_msg" echo "" echo "See the INSTALL file for hints on how to install the missing libraries and/or" echo "how to generate (or fetch) manpages:" echo " https://github.com/WayneD/rsync/blob/master/INSTALL.md" echo "" echo "To disable one or more features, the relevant configure options are:" for lib in $no_lib; do echo " --disable-$lib" done echo "" AC_MSG_ERROR(Aborting configure run) fi AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef MAJOR_IN_MKDEV #include # if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__) # define makedev mkdev # endif #elif defined MAJOR_IN_SYSMACROS #include #endif int main(void) { dev_t dev = makedev(0, 5, 7); if (major(dev) != 5 || minor(dev) != 7) return 1; return 0; } ]])],[rsync_cv_MAKEDEV_TAKES_3_ARGS=yes],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no],[rsync_cv_MAKEDEV_TAKES_3_ARGS=no])]) if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then AC_DEFINE(MAKEDEV_TAKES_3_ARGS, 1, [Define to 1 if makedev() takes 3 args]) fi AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int16_t) AC_CHECK_SIZEOF(uint16_t) AC_CHECK_SIZEOF(int32_t) AC_CHECK_SIZEOF(uint32_t) AC_CHECK_SIZEOF(int64_t) AC_CHECK_SIZEOF(off_t) AC_CHECK_SIZEOF(off64_t) AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(char*) AC_C_INLINE AC_TYPE_LONG_DOUBLE_WIDER ac_cv_c_long_double=$ac_cv_type_long_double_wider if test $ac_cv_c_long_double = yes; then AC_DEFINE([HAVE_LONG_DOUBLE],[1],[Define to 1 if the type `long double' works and has more range or precision than `double'.]) fi AC_TYPE_UID_T AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t]) if test "$cross_compiling" = no; then AC_TYPE_GETGROUPS else AC_DEFINE([GETGROUPS_T],[gid_t],[Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'.]) fi AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_mtimensec, struct stat.st_mtimespec.tv_nsec, struct stat.st_mtim.tv_nsec],,,[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif]) TYPE_SOCKLEN_T AC_CACHE_CHECK([for errno in errno.h],rsync_cv_errno, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = errno]])],[rsync_cv_errno=yes],[rsync_cv_have_errno_decl=no])]) if test x"$rsync_cv_errno" = x"yes"; then AC_DEFINE(HAVE_ERRNO_DECL, 1, [Define to 1 if errno is declared in errno.h]) fi # The following test taken from the cvs sources # If we can't find connect, try looking in -lsocket, -lnsl, and -linet. # These need checks to be before checks for any other functions that # might be in the same libraries. # The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has # libsocket.so which has a bad implementation of gethostbyname (it # only looks in /etc/hosts), so we only look for -lsocket if we need # it. AC_CHECK_FUNCS(connect) if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl_s, printf) ;; esac case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl, printf) ;; esac case "$LIBS" in *-lsocket*) ;; *) AC_CHECK_LIB(socket, connect) ;; esac case "$LIBS" in *-linet*) ;; *) AC_CHECK_LIB(inet, connect) ;; esac dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value dnl has been cached. if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run AC_DEFINE(HAVE_CONNECT, 1, [Define to 1 if you have the "connect" function]) fi fi AC_SEARCH_LIBS(inet_ntop, resolv) # For OS X, Solaris, HP-UX, etc.: figure out if -liconv is needed. We'll # accept either iconv_open or libiconv_open, since some include files map # the former to the latter. AC_SEARCH_LIBS(iconv_open, iconv) AC_SEARCH_LIBS(libiconv_open, iconv) AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #if HAVE_STDLIB_H #include #endif #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ]], [[]])],[am_cv_proto_iconv_arg1=""],[am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) dnl AC_MSG_NOTICE([Looking in libraries: $LIBS]) AC_REPLACE_FUNCS([inet_ntop inet_pton]) AC_HAVE_TYPE([struct addrinfo], [#include ]) AC_HAVE_TYPE([struct sockaddr_storage], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif]) # Irix 6.5 has getaddrinfo but not the corresponding defines, so use # builtin getaddrinfo if one of the defines don't exist AC_CACHE_CHECK([whether defines needed by getaddrinfo exist], rsync_cv_HAVE_GETADDR_DEFINES,[ AC_EGREP_CPP(yes, [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef AI_PASSIVE yes #endif], rsync_cv_HAVE_GETADDR_DEFINES=yes, rsync_cv_HAVE_GETADDR_DEFINES=no)]) AS_IF([test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" && test x"$ac_cv_type_struct_addrinfo" = x"yes"],[ # Tru64 UNIX has getaddrinfo() but has it renamed in libc as # something else so we must include to get the # redefinition. AC_CHECK_FUNCS(getaddrinfo, , [AC_MSG_CHECKING([for getaddrinfo by including ]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include ]], [[getaddrinfo(NULL, NULL, NULL, NULL);]])],[AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_GETADDRINFO, 1, [Define to 1 if you have the "getaddrinfo" function and required types.])],[AC_MSG_RESULT([no]) AC_LIBOBJ([getaddrinfo])])]) ],[AC_LIBOBJ([getaddrinfo])]) AC_CHECK_MEMBER([struct sockaddr.sa_len], [ AC_DEFINE(HAVE_SOCKADDR_LEN, 1, [Do we have sockaddr.sa_len?]) ], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif ]) AC_CHECK_MEMBER([struct sockaddr_in.sin_len], [ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include ]) AC_CHECK_MEMBER([struct sockaddr_un.sun_len], [ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_len?]) ], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include ]) AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id], [ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID, 1, [Do we have sockaddr_in6.sin6_scope_id?]) ], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include ]) AC_HAVE_TYPE([struct stat64], [#include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif ]) # if we can't find strcasecmp, look in -lresolv (for Unixware at least) # AC_CHECK_FUNCS(strcasecmp) if test x"$ac_cv_func_strcasecmp" = x"no"; then AC_CHECK_LIB(resolv, strcasecmp) fi AC_CHECK_FUNCS(aclsort) if test x"$ac_cv_func_aclsort" = x"no"; then AC_CHECK_LIB(sec, aclsort) fi dnl At the moment we don't test for a broken memcmp(), because all we dnl need to do is test for equality, not comparison, and it seems that dnl every platform has a memcmp that can do at least that. dnl AC_FUNC_MEMCMP AC_FUNC_UTIME_NULL AC_FUNC_ALLOCA AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ chflags getattrlist mktime innetgr linkat \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ strlcat strlcpy strtol mallinfo mallinfo2 getgroups setgroups geteuid getegid \ 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 \ initgroups utimensat posix_fallocate attropen setvbuf nanosleep usleep \ setenv unsetenv) dnl cygwin iconv.h defines iconv_open as libiconv_open if test x"$ac_cv_func_iconv_open" != x"yes"; then AC_CHECK_FUNC(libiconv_open, [ac_cv_func_iconv_open=yes; AC_DEFINE(HAVE_ICONV_OPEN, 1)]) fi dnl Preallocation stuff (also fallocate, posix_fallocate function tests above): AC_CACHE_CHECK([for useable fallocate],rsync_cv_have_fallocate,[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #ifdef HAVE_SYS_TYPES_H #include #endif]], [[fallocate(0, 0, 0, 0);]])],[rsync_cv_have_fallocate=yes],[rsync_cv_have_fallocate=no])]) if test x"$rsync_cv_have_fallocate" = x"yes"; then AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if you have the fallocate function and it compiles and links without error]) fi AC_MSG_CHECKING([for FALLOC_FL_PUNCH_HOLE]) AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ #define _GNU_SOURCE 1 #include #ifndef FALLOC_FL_PUNCH_HOLE #error FALLOC_FL_PUNCH_HOLE is missing #endif ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_FALLOC_FL_PUNCH_HOLE], [1], [Define if FALLOC_FL_PUNCH_HOLE is available.]) ], [ AC_MSG_RESULT([no]) ] ) AC_MSG_CHECKING([for FALLOC_FL_ZERO_RANGE]) AC_PREPROC_IFELSE([AC_LANG_SOURCE([[ #define _GNU_SOURCE 1 #include #ifndef FALLOC_FL_ZERO_RANGE #error FALLOC_FL_ZERO_RANGE is missing #endif ]])], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_FALLOC_FL_ZERO_RANGE], [1], [Define if FALLOC_FL_ZERO_RANGE is available.]) ], [ AC_MSG_RESULT([no]) ] ) AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif]], [[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);]])],[rsync_cv_have_sys_fallocate=yes],[rsync_cv_have_sys_fallocate=no])]) if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then AC_DEFINE(HAVE_SYS_FALLOCATE, 1, [Define to 1 if you have the SYS_fallocate syscall number]) fi if test x"$ac_cv_func_posix_fallocate" = x"yes"; then AC_MSG_CHECKING([whether posix_fallocate is efficient]) case $host_os in *cygwin*) AC_MSG_RESULT(yes) AC_DEFINE(HAVE_EFFICIENT_POSIX_FALLOCATE, 1, [Define if posix_fallocate is efficient (Cygwin)]) ;; *) AC_MSG_RESULT(no) ;; esac fi dnl End of preallocation stuff AC_CHECK_FUNCS(getpgrp tcgetpgrp) if test $ac_cv_func_getpgrp = yes; then AC_FUNC_GETPGRP fi AC_ARG_ENABLE(iconv-open, AS_HELP_STRING([--disable-iconv-open],[disable to avoid all use of iconv_open()]), [], [enable_iconv_open=$ac_cv_func_iconv_open]) if test x"$enable_iconv_open" != x"no"; then AC_DEFINE(USE_ICONV_OPEN, 1, [Define to 1 if you want rsync to make use of iconv_open()]) fi AC_ARG_ENABLE(iconv, AS_HELP_STRING([--disable-iconv],[disable to omit the --iconv option]), [], [enable_iconv=$enable_iconv_open]) AH_TEMPLATE([ICONV_OPTION], [Define if you want the --iconv option. Specifying a value will set the default iconv setting (a NULL means no --iconv processing by default).]) if test x"$enable_iconv" != x"no"; then if test x"$enable_iconv" = x"yes"; then AC_DEFINE(ICONV_OPTION, NULL) else AC_DEFINE_UNQUOTED(ICONV_OPTION, "$enable_iconv") fi AC_DEFINE(UTF8_CHARSET, "UTF-8", [String to pass to iconv() for the UTF-8 charset.]) fi AC_CACHE_CHECK([whether chown() modifies symlinks],rsync_cv_chown_modifies_symlink,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #if HAVE_UNISTD_H # include #endif #include #include int main(void) { char const *dangling_symlink = "conftest.dangle"; unlink(dangling_symlink); if (symlink("conftest.no-such", dangling_symlink) < 0) abort(); if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) return 1; return 0; }]])],[rsync_cv_chown_modifies_symlink=yes],[rsync_cv_chown_modifies_symlink=no],[rsync_cv_chown_modifies_symlink=no])]) if test $rsync_cv_chown_modifies_symlink = yes; then AC_DEFINE(CHOWN_MODIFIES_SYMLINK, 1, [Define to 1 if chown modifies symlinks.]) fi AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_FCNTL_H # include #elif defined HAVE_SYS_FCNTL_H # include #endif #if HAVE_UNISTD_H # include #endif #include #include #define FILENAME "conftest.dangle" int main(void) { unlink(FILENAME); if (symlink("conftest.no-such", FILENAME) < 0) abort(); unlink(FILENAME "2"); #ifdef HAVE_LINKAT if (linkat(AT_FDCWD, FILENAME, AT_FDCWD, FILENAME "2", 0) < 0) return 1; #else if (link(FILENAME, FILENAME "2") < 0) return 1; #endif return 0; }]])],[rsync_cv_can_hardlink_symlink=yes],[rsync_cv_can_hardlink_symlink=no],[rsync_cv_can_hardlink_symlink=no])]) if test $rsync_cv_can_hardlink_symlink = yes; then AC_DEFINE(CAN_HARDLINK_SYMLINK, 1, [Define to 1 if link() can hard-link symlinks.]) fi AC_CACHE_CHECK([whether link() can hard-link special files],rsync_cv_can_hardlink_special,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #if HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include #include #define FILENAME "conftest.fifi" int main(void) { unlink(FILENAME); if (mkfifo(FILENAME, 0777) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) return 1; return 0; }]])],[rsync_cv_can_hardlink_special=yes],[rsync_cv_can_hardlink_special=no],[rsync_cv_can_hardlink_special=no])]) if test $rsync_cv_can_hardlink_special = yes; then AC_DEFINE(CAN_HARDLINK_SPECIAL, 1, [Define to 1 if link() can hard-link special files.]) fi AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif int main(void) { int fd[2]; return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1; }]])],[rsync_cv_HAVE_SOCKETPAIR=yes],[rsync_cv_HAVE_SOCKETPAIR=no],[rsync_cv_HAVE_SOCKETPAIR=cross])]) if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then AC_DEFINE(HAVE_SOCKETPAIR, 1, [Define to 1 if you have the "socketpair" function]) fi AC_REPLACE_FUNCS([getpass]) if test x"$with_included_popt" != x"yes"; then AC_CHECK_LIB(popt, poptGetContext, , [with_included_popt=yes]) fi if test x"$ac_cv_header_popt_popt_h" = x"yes"; then # If the system has /usr/include/popt/popt.h, we enable the # included popt because an attempt to "#include " # would use our included header file anyway (due to -I.), and # might conflict with the system popt. with_included_popt=yes elif test x"$ac_cv_header_popt_h" != x"yes"; then with_included_popt=yes fi AC_MSG_CHECKING([whether to use included libpopt]) if test x"$with_included_popt" = x"yes"; then AC_MSG_RESULT($srcdir/popt) BUILD_POPT='$(popt_OBJS)' CFLAGS="-I$srcdir/popt $CFLAGS" if test x"$ALLOCA" != x then # this can be removed when/if we add an included alloca.c; # see autoconf documentation on AC_FUNC_ALLOCA AC_MSG_WARN([included libpopt will use malloc, not alloca (which wastes a small amount of memory)]) fi else AC_MSG_RESULT(no) fi # We default to using our zlib unless --with-included-zlib=no is given. if test x"$with_included_zlib" != x"no"; then with_included_zlib=yes elif test x"$ac_cv_header_zlib_h" != x"yes"; then with_included_zlib=yes fi if test x"$with_included_zlib" != x"yes"; then AC_CHECK_LIB(z, deflateParams, , [with_included_zlib=yes]) fi AC_MSG_CHECKING([whether to use included zlib]) if test x"$with_included_zlib" = x"yes"; then AC_MSG_RESULT($srcdir/zlib) BUILD_ZLIB='$(zlib_OBJS)' CFLAGS="-I$srcdir/zlib $CFLAGS" else AC_DEFINE(EXTERNAL_ZLIB, 1, [Define to 1 if using external zlib]) AC_MSG_RESULT(no) fi AC_CACHE_CHECK([for unsigned char],rsync_cv_SIGNED_CHAR_OK,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[signed char *s = (signed char *)""]])],[rsync_cv_SIGNED_CHAR_OK=yes],[rsync_cv_SIGNED_CHAR_OK=no])]) if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then AC_DEFINE(SIGNED_CHAR_OK, 1, [Define to 1 if "signed char" is a valid type]) fi AC_CACHE_CHECK([for broken readdir],rsync_cv_HAVE_BROKEN_READDIR,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_SYS_TYPES_H #include #endif #include int main(void) { struct dirent *di; DIR *d = opendir("."); di = readdir(d); if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 && di->d_name[0] == 0) return 0; return 1;} ]])],[rsync_cv_HAVE_BROKEN_READDIR=yes],[rsync_cv_HAVE_BROKEN_READDIR=no],[rsync_cv_HAVE_BROKEN_READDIR=cross])]) if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then AC_DEFINE(HAVE_BROKEN_READDIR, 1, [Define to 1 if readdir() is broken]) fi AC_CACHE_CHECK([for utimbuf],rsync_cv_HAVE_STRUCT_UTIMBUF,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_TYPES_H #include #endif #include ]], [[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);]])],[rsync_cv_HAVE_STRUCT_UTIMBUF=yes],[rsync_cv_HAVE_STRUCT_UTIMBUF=no])]) if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then AC_DEFINE(HAVE_STRUCT_UTIMBUF, 1, [Define to 1 if you have the "struct utimbuf" type]) fi AC_CACHE_CHECK([if gettimeofday takes tz argument],rsync_cv_HAVE_GETTIMEOFDAY_TZ,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #ifdef HAVE_UNISTD_H #include #endif]], [[struct timeval tv; return gettimeofday(&tv, NULL);]])],[rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes],[rsync_cv_HAVE_GETTIMEOFDAY_TZ=no])]) if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then AC_DEFINE(HAVE_GETTIMEOFDAY_TZ, 1, [Define to 1 if gettimeofday() takes a time-zone arg]) fi AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #ifdef HAVE_SYS_TYPES_H #include #endif #include #include #if HAVE_STDLIB_H #include #endif #include void foo(const char *format, ...) { va_list ap; int len; static char buf[] = "12345678901234567890"; va_start(ap, format); len = vsnprintf(0, 0, format, ap); va_end(ap); if (len != 5) exit(1); if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1); } int main(void) { foo("hello"); return 0; } ]])],[rsync_cv_HAVE_C99_VSNPRINTF=yes],[rsync_cv_HAVE_C99_VSNPRINTF=no],[rsync_cv_HAVE_C99_VSNPRINTF=cross])]) if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [Define to 1 if vsprintf has a C99-compatible return value]) fi AC_CACHE_CHECK([for secure mkstemp],rsync_cv_HAVE_SECURE_MKSTEMP,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[#include #ifdef HAVE_SYS_TYPES_H #include #endif #include #ifdef HAVE_UNISTD_H #include #endif int main(void) { struct stat st; char tpl[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); if (fd == -1) return 1; unlink(tpl); if (fstat(fd, &st) != 0) return 1; if ((st.st_mode & 0777) != 0600) return 1; return 0; }]])],[rsync_cv_HAVE_SECURE_MKSTEMP=yes],[rsync_cv_HAVE_SECURE_MKSTEMP=no],[rsync_cv_HAVE_SECURE_MKSTEMP=cross])]) if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then case $host_os in hpux*) dnl HP-UX has a broken mkstemp() implementation they refuse to fix, dnl so we noisily skip using it. See HP change request JAGaf34426 dnl for details. (sbonds) AC_MSG_WARN(Skipping broken HP-UX mkstemp() -- using mktemp() instead) ;; *) AC_DEFINE(HAVE_SECURE_MKSTEMP, 1, [Define to 1 if mkstemp() is available and works right]) ;; esac fi AC_CACHE_CHECK([if mknod creates FIFOs],rsync_cv_MKNOD_CREATES_FIFOS,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include #if HAVE_UNISTD_H # include #endif int main(void) { int rc, ec; char *fn = "fifo-test"; unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn); if (rc) {printf("(%d %d) ",rc,ec); return ec;} return 0;}]])],[rsync_cv_MKNOD_CREATES_FIFOS=yes],[rsync_cv_MKNOD_CREATES_FIFOS=no],[rsync_cv_MKNOD_CREATES_FIFOS=cross])]) if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then AC_DEFINE(MKNOD_CREATES_FIFOS, 1, [Define to 1 if mknod() can create FIFOs.]) fi AC_CACHE_CHECK([if mknod creates sockets],rsync_cv_MKNOD_CREATES_SOCKETS,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include #if HAVE_UNISTD_H # include #endif int main(void) { int rc, ec; char *fn = "sock-test"; unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn); if (rc) {printf("(%d %d) ",rc,ec); return ec;} return 0;}]])],[rsync_cv_MKNOD_CREATES_SOCKETS=yes],[rsync_cv_MKNOD_CREATES_SOCKETS=no],[rsync_cv_MKNOD_CREATES_SOCKETS=cross])]) if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then AC_DEFINE(MKNOD_CREATES_SOCKETS, 1, [Define to 1 if mknod() can create sockets.]) fi # # The following test was mostly taken from the tcl/tk plus patches # AC_CACHE_CHECK([whether -c -o works],rsync_cv_DASHC_WORKS_WITH_DASHO,[ rm -rf conftest* cat > conftest.$ac_ext < #endif #ifdef HAVE_SYS_ACL_H #include #endif]], [[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);]])],[samba_cv_HAVE_POSIX_ACLS=yes],[samba_cv_HAVE_POSIX_ACLS=no])]) AC_MSG_CHECKING(ACL test results) if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then AC_MSG_RESULT(Using posix ACLs) AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs]) AC_DEFINE(SUPPORT_ACLS, 1) AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_ACL_H #include #endif]], [[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);]])],[samba_cv_HAVE_ACL_GET_PERM_NP=yes],[samba_cv_HAVE_ACL_GET_PERM_NP=no])]) if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np]) fi else if test x"$enable_acl_support" = x"yes"; then AC_MSG_ERROR(Failed to find ACL support) else AC_MSG_RESULT(No ACL support found) fi fi ;; esac fi ################################################# # check for extended attribute support AC_MSG_CHECKING(whether to support extended attributes) AC_ARG_ENABLE(xattr-support, AS_HELP_STRING([--disable-xattr-support],[disable to omit extended attributes]), [], [case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link$ac_cv_func_attropen" in *yes*) enable_xattr_support=maybe ;; *) enable_xattr_support=no ;; esac]) AH_TEMPLATE([SUPPORT_XATTRS], [Define to 1 to add support for extended attributes]) if test x"$enable_xattr_support" = x"no"; then AC_MSG_RESULT(no) else case "$host_os" in *linux*|*netbsd*|*cygwin*) AC_MSG_RESULT(Using Linux xattrs) AC_DEFINE(HAVE_LINUX_XATTRS, 1, [True if you have Linux xattrs (or equivalent)]) AC_DEFINE(SUPPORT_XATTRS, 1) AC_DEFINE(NO_SYMLINK_USER_XATTRS, 1, [True if symlinks do not support user xattrs]) AC_CHECK_LIB(attr,getxattr) ;; darwin*) AC_MSG_RESULT(Using OS X xattrs) AC_DEFINE(HAVE_OSX_XATTRS, 1, [True if you have Mac OS X xattrs]) AC_DEFINE(SUPPORT_XATTRS, 1) AC_DEFINE(NO_DEVICE_XATTRS, 1, [True if device files do not support xattrs]) AC_DEFINE(NO_SPECIAL_XATTRS, 1, [True if special files do not support xattrs]) ;; freebsd*) AC_MSG_RESULT(Using FreeBSD extattrs) AC_DEFINE(HAVE_FREEBSD_XATTRS, 1, [True if you have FreeBSD xattrs]) AC_DEFINE(SUPPORT_XATTRS, 1) ;; solaris*) AC_MSG_RESULT(Using Solaris xattrs) AC_DEFINE(HAVE_SOLARIS_XATTRS, 1, [True if you have Solaris xattrs]) AC_DEFINE(SUPPORT_XATTRS, 1) AC_DEFINE(NO_SYMLINK_XATTRS, 1, [True if symlinks do not support xattrs]) ;; *) if test x"$enable_xattr_support" = x"yes"; then AC_MSG_ERROR(Failed to find extended attribute support) else AC_MSG_RESULT(No extended attribute support found) fi ;; esac fi if test x"$enable_acl_support" = x"no" || test x"$enable_xattr_support" = x"no" || test x"$enable_iconv" = x"no"; then AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter]) OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-parameter" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("hello\n");]])],[rsync_warn_flag=yes],[rsync_warn_flag=no]) AC_MSG_RESULT([$rsync_warn_flag]) if test x"$rsync_warn_flag" = x"no"; then CFLAGS="$OLD_CFLAGS" fi fi case "$CC" in ' checker'*|checker*) AC_DEFINE(FORCE_FD_ZERO_MEMSET, 1, [Used to make "checker" understand that FD_ZERO() clears memory.]) ;; esac AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig]) AC_OUTPUT AC_MSG_RESULT() AC_MSG_RESULT([ rsync $PACKAGE_VERSION configuration successful]) AC_MSG_RESULT() rsync-3.2.7/csprotocol.txt0000664000000000000000000001021114315642342014310 0ustar rootrootThis is kind of informal and may be wrong, but it helped me. It's basically a summary of clientserver.c and authenticate.c. -- Martin Pool This is the protocol used for rsync --daemon; i.e. connections to port 873 rather than invocations over a remote shell. When the server accepts a connection, it prints a newline-terminated greeting line: @RSYNCD: . The is the numeric version (see PROTOCOL_VERSION in rsync.h) The is the numeric subprotocol version (which is 0 for a final protocol version, as the SUBPROTOCOL_VERSION define discusses). The names are the authentication digest algorithms that the daemon supports, listed in order of preference. An rsync prior to 3.2.7 omits the digest names. An rsync prior to 3.0.0 also omits the period and the value. Since a final protocol has a subprotocol value of 0, a missing subprotocol value is assumed to be 0 for any protocol prior to 30. It is considered a fatal error for protocol 30 and above to omit it. It is considered a fatal error for protocol 32 and above to omit the digest name list (currently 31 is the newest protocol). The daemon expects to see a similar greeting line back from the client. Once received, the daemon follows the opening line with a free-format text message-of-the-day (if any is defined). The server is now in the connected state. The client can either send the command: #list (to get a listing of modules) or the name of a module. After this, the connection is now bound to a particular module. Access per host for this module is now checked, as is per-module connection limits. If authentication is required to use this module, the server will say: @RSYNCD: AUTHREQD where is a random string of base64 characters. The client must respond with: The is the username they claim to be. The is the base64 form of the digest hash of the challenge+password string. The chosen digest method is the most preferred client method that is also in the server's list. If no digest list was explicitly provided, the side expecting a list assumes the other side provided either the single name "md5" (for a negotiated protocol 30 or 31), or the single name "md4" (for an older protocol). At this point the server applies all remaining constraints before handing control to the client, including switching uid/gid, setting up include and exclude lists, moving to the root of the module, and doing chroot. If the login is acceptable, then the server will respond with @RSYNCD: OK The client now writes some rsync options, as if it were remotely executing the command. The server parses these arguments as if it had just been invoked with them, but they're added to the existing state. So if the client specifies a list of files to be included or excluded, they'll defer to existing limits specified in the server configuration. At this point the client and server both switch to using a multiplexing layer across the socket. The main point of this is to allow the server to asynchronously pass errors back, while still allowing streamed and pipelined data. Unfortunately, the multiplex protocol is not used at every stage. We start up in plain socket mode and then change over by calling io_start_buffering. Of course both the client and the server have to do this at the same point. The server then talks to the client as normal across the socket, passing checksums, file lists and so on. For documentation of that, stay tuned (or write it yourself!). ------------ Protocol version changes 31 (2013-09-28, 3.1.0) Initial release of protocol 31 had no changes. Rsync 3.2.7 introduced the suffixed list of digest names on the greeting line. The presence of the list is allowed even if the greeting indicates an older protocol version number. 30 (2007-10-04, 3.0.0pre1) The use of a "." number was added to @RSYNCD: . 25 (2001-08-20, 2.4.7pre2) Send an explicit "@RSYNC EXIT" command at the end of the module listing. We never intentionally end the transmission by just closing the socket anymore. rsync-3.2.7/support/0000775000000000000000000000000014324367162013105 5ustar rootrootrsync-3.2.7/support/rsync-no-vanished0000775000000000000000000000112114144003115016356 0ustar rootroot#!/usr/bin/env bash REAL_RSYNC=/usr/bin/rsync IGNOREEXIT=24 IGNOREOUT='^(file has vanished: |rsync warning: some files vanished before they could be transferred)' # If someone installs this as "rsync", make sure we don't affect a server run. for arg in "${@}"; do if [[ "$arg" == --server ]]; then exec $REAL_RSYNC "${@}" exit $? # Not reached fi done set -o pipefail # This filters stderr without merging it with stdout: { $REAL_RSYNC "${@}" 2>&1 1>&3 3>&- | grep -E -v "$IGNOREOUT"; ret=${PIPESTATUS[0]}; } 3>&1 1>&2 if [[ $ret == $IGNOREEXIT ]]; then ret=0 fi exit $ret rsync-3.2.7/support/git-set-file-times0000775000000000000000000000747614225047737016464 0ustar rootroot#!/usr/bin/env python3 import os, re, argparse, subprocess from datetime import datetime NULL_COMMIT_RE = re.compile(r'\0\0commit [a-f0-9]{40}$|\0$') def main(): if not args.git_dir: cmd = 'git rev-parse --show-toplevel 2>/dev/null || echo .' top_dir = subprocess.check_output(cmd, shell=True, encoding='utf-8').strip() args.git_dir = os.path.join(top_dir, '.git') if not args.prefix: os.chdir(top_dir) git = [ 'git', '--git-dir=' + args.git_dir ] if args.tree: cmd = git + 'ls-tree -z -r --name-only'.split() + [ args.tree ] else: cmd = git + 'ls-files -z'.split() proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, encoding='utf-8') out = proc.communicate()[0] ls = set(out.split('\0')) ls.discard('') if not args.tree: # All modified files keep their current mtime. proc = subprocess.Popen(git + 'status -z --no-renames'.split(), stdout=subprocess.PIPE, encoding='utf-8') out = proc.communicate()[0] for fn in out.split('\0'): if fn == '' or (fn[0] != 'M' and fn[1] != 'M'): continue fn = fn[3:] if args.list: mtime = os.lstat(fn).st_mtime print_line(fn, mtime, mtime) ls.discard(fn) cmd = git + 'log -r --name-only --format=%x00commit%x20%H%n%x00commit_time%x20%ct%n --no-renames -z'.split() if args.tree: cmd.append(args.tree) cmd += ['--'] + args.files proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, encoding='utf-8') for line in proc.stdout: line = line.strip() m = re.match(r'^\0commit_time (\d+)$', line) if m: commit_time = int(m[1]) elif NULL_COMMIT_RE.search(line): line = NULL_COMMIT_RE.sub('', line) files = set(fn for fn in line.split('\0') if fn in ls) if not files: continue for fn in files: if args.prefix: fn = args.prefix + fn mtime = os.lstat(fn).st_mtime if args.list: print_line(fn, mtime, commit_time) elif mtime != commit_time: if not args.quiet: print(f"Setting {fn}") os.utime(fn, (commit_time, commit_time), follow_symlinks = False) ls -= files if not ls: break proc.communicate() def print_line(fn, mtime, commit_time): if args.list > 1: ts = str(commit_time).rjust(10) else: ts = datetime.utcfromtimestamp(commit_time).strftime("%Y-%m-%d %H:%M:%S") chg = '.' if mtime == commit_time else '*' print(chg, ts, fn) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Set the times of the files in the current git checkout to their last-changed time.", add_help=False) parser.add_argument('--git-dir', metavar='GIT_DIR', help="The git dir to query (defaults to affecting the current git checkout).") parser.add_argument('--tree', metavar='TREE-ISH', help="The tree-ish to query (defaults to the current branch).") parser.add_argument('--prefix', metavar='PREFIX_STR', help="Prepend the PREFIX_STR to each filename we tweak (defaults to the top of current checkout).") parser.add_argument('--quiet', '-q', action='store_true', help="Don't output the changed-file information.") parser.add_argument('--list', '-l', action='count', help="List files & times instead of changing them. Repeat for Unix timestamp instead of human readable.") parser.add_argument('files', metavar='FILE', nargs='*', help="Specify a subset of checked-out files to tweak.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et rsync-3.2.7/support/munge-symlinks0000775000000000000000000000507114160221254016005 0ustar rootroot#!/usr/bin/env python3 # This script will either prefix all symlink values with the string # "/rsyncd-munged/" or remove that prefix. import os, sys, argparse SYMLINK_PREFIX = '/rsyncd-munged/' PREFIX_LEN = len(SYMLINK_PREFIX) def main(): for arg in args.names: if os.path.islink(arg): process_one_arg(arg) elif os.path.isdir(arg): for fn in find_symlinks(arg): process_one_arg(fn) else: print("Arg is not a symlink or a dir:", arg, file=sys.stderr) def find_symlinks(path): for entry in os.scandir(path): if entry.is_symlink(): yield entry.path elif entry.is_dir(follow_symlinks=False): yield from find_symlinks(entry.path) def process_one_arg(fn): lnk = os.readlink(fn) if args.unmunge: if not lnk.startswith(SYMLINK_PREFIX): return lnk = lnk[PREFIX_LEN:] while args.all and lnk.startswith(SYMLINK_PREFIX): lnk = lnk[PREFIX_LEN:] else: if not args.all and lnk.startswith(SYMLINK_PREFIX): return lnk = SYMLINK_PREFIX + lnk try: os.unlink(fn) except OSError as e: print("Unable to unlink symlink:", str(e), file=sys.stderr) return try: os.symlink(lnk, fn) except OSError as e: print("Unable to recreate symlink", fn, '->', lnk + ':', str(e), file=sys.stderr) return print(fn, '->', lnk) if __name__ == '__main__': our_desc = """\ Adds or removes the %s prefix to/from the start of each symlink's value. When given the name of a directory, affects all the symlinks in that directory hierarchy. """ % SYMLINK_PREFIX epilog = 'See the "munge symlinks" option in the rsyncd.conf manpage for more details.' parser = argparse.ArgumentParser(description=our_desc, epilog=epilog, add_help=False) uniq_group = parser.add_mutually_exclusive_group() uniq_group.add_argument('--munge', action='store_true', help="Add the prefix to symlinks (the default).") uniq_group.add_argument('--unmunge', action='store_true', help="Remove the prefix from symlinks.") parser.add_argument('--all', action='store_true', help="Always adds the prefix when munging (even if already munged) or removes multiple instances of the prefix when unmunging.") parser.add_argument('--help', '-h', action='help', help="Output this help message and exit.") parser.add_argument('names', metavar='NAME', nargs='+', help="One or more directories and/or symlinks to process.") args = parser.parse_args() main() # vim: sw=4 et rsync-3.2.7/support/cvs2includes0000775000000000000000000000230013672270624015433 0ustar rootroot#!/usr/bin/env perl # # This script finds all CVS/Entries files in the current directory and below # and creates a local .cvsinclude file with non-inherited rules including each # checked-in file. Then, use this option whenever using --cvs-exclude (-C): # # -f ': .cvsinclude' # # That ensures that all checked-in files/dirs are included in the transfer. # (You could alternately put ": .cvsinclude" into an .rsync-filter file and # use the -F option, which is easier to type.) # # The downside is that you need to remember to re-run cvs2includes whenever # you add a new file to the project. use strict; open(FIND, 'find . -name CVS -type d |') or die $!; while () { chomp; s#^\./##; my $entries = "$_/Entries"; s/CVS$/.cvsinclude/; my $filter = $_; open(ENTRIES, $entries) or die "Unable to open $entries: $!\n"; my @includes; while () { push(@includes, $1) if m#/(.+?)/#; } close ENTRIES; if (@includes) { open(FILTER, ">$filter") or die "Unable to write $filter: $!\n"; print FILTER map "+ /$_\n", @includes; close FILTER; print "Updated $filter\n"; } elsif (-f $filter) { unlink($filter); print "Removed $filter\n"; } } close FIND; rsync-3.2.7/support/nameconvert0000775000000000000000000000276713712703754015371 0ustar rootroot#!/usr/bin/env python3 # This implements a simple protocol to do user & group conversions between # names & ids. All input and output consists of simple strings with a # terminating newline. # # The requests can be: # # uid ID_NUM\n -> NAME\n # gid ID_NUM\n -> NAME\n # usr NAME\n -> ID_NUM\n # grp NAME\n -> ID_NUM\n # # An unknown ID_NUM or NAME results in an empty return value. # # This is used by an rsync daemon when configured with the "name converter" and # (often) "use chroot = true". While this converter uses real user & group # lookups you could change it to use any mapping idiom you'd like. import sys, argparse, pwd, grp def main(): for line in sys.stdin: try: req, arg = line.rstrip().split(' ', 1) except: req = None try: if req == 'uid': ans = pwd.getpwuid(int(arg)).pw_name elif req == 'gid': ans = grp.getgrgid(int(arg)).gr_name elif req == 'usr': ans = pwd.getpwnam(arg).pw_uid elif req == 'grp': ans = grp.getgrnam(arg).gr_gid else: print("Invalid request", file=sys.stderr) sys.exit(1) except KeyError: ans = '' print(ans, flush=True) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Convert users & groups between names & numbers for an rsync daemon.") args = parser.parse_args() main() # vim: sw=4 et rsync-3.2.7/support/mnt-excl0000775000000000000000000000347013672270624014567 0ustar rootroot#!/usr/bin/env perl # This script takes a command-line arg of a source directory # that will be passed to rsync, and generates a set of excludes # that will exclude all mount points from the list. This is # useful if you have "bind" mounts since the --one-file-system # option won't notice the transition to a different spot on # the same disk. For example: # # mnt-excl /dir | rsync --exclude-from=- ... /dir /dest/ # mnt-excl /dir/ | rsync --exclude-from=- ... /dir/ /dest/ # ssh host mnt-excl /dir | rsync --exclude-from=- ... host:/dir /dest/ # # Imagine that /dir/foo is a mount point: the first invocation of # mnt-excl would have output /dir/foo, while the second would have # output /foo (which are the properly anchored excludes). # # NOTE: This script expects /proc/mounts to exist, but could be # easily adapted to read /etc/mtab or similar. # # ADDENDUM: The addition of the --filter option (which has support for # absolute-anchored excludes) can make this script unneeded in some # scenarios. If you don't need delete protection on the receiving side # (or if the destination path is identical to the source path), then you # can exclude some absolute paths from the transfer based on the mount # dirs. For instance: # # awk '{print $2}' /proc/mounts | grep -v '^/$' | \ # rsync -avf 'merge,/- -' /dir host:/dest/ use strict; use warnings; use Cwd 'abs_path'; my $file = '/proc/mounts'; my $dir = shift || '/'; my $trailing_slash = $dir =~ m{./$} ? '/' : ''; $dir = abs_path($dir) . $trailing_slash; $dir =~ s{([^/]*)$}{}; my $trailing = $1; $trailing = '' if $trailing eq '.' || !-d "$dir$trailing"; $trailing .= '/' if $trailing ne ''; open(IN, $file) or die "Unable to open $file: $!\n"; while () { $_ = (split)[1]; next unless s{^\Q$dir$trailing\E}{}o && $_ ne ''; print "- /$trailing$_\n"; } close IN; rsync-3.2.7/support/mapfrom0000775000000000000000000000117113672270624014475 0ustar rootroot#!/usr/bin/env perl # This helper script makes it easy to use a passwd or group file to map # values in a LOCAL transfer. For instance, if you mount a backup that # does not have the same passwd setup as the local machine, you can do # a copy FROM the backup area as follows and get the differing ID values # mapped just like a remote transfer FROM the backed-up machine would do: # # rsync -av --usermap=`mapfrom /mnt/backup/etc/passwd` \ # --groupmap=`mapfrom /mnt/backup/etc/group` \ # /mnt/backup/some/src/ /some/dest/ while (<>) { push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/; } print join(',', @_), "\n"; rsync-3.2.7/support/rrsync0000775000000000000000000003053714277731301014360 0ustar rootroot#!/usr/bin/env python3 # Restricts rsync to subdirectory declared in .ssh/authorized_keys. See # the rrsync man page for details of how to make use of this script. # NOTE: install python3 braceexpand to support brace expansion in the args! # Originally a perl script by: Joe Smith 30-Sep-2004 # Python version by: Wayne Davison # You may configure these 2 values to your liking. See also the section of # short & long options if you want to disable any options that rsync accepts. RSYNC = '/usr/bin/rsync' LOGFILE = 'rrsync.log' # NOTE: the file must exist for a line to be appended! # The following options are mainly the options that a client rsync can send # to the server, and usually just in the one option format that the stock # rsync produces. However, there are some additional convenience options # added as well, and thus a few options are present in both the short and # long lists (such as --group, --owner, and --perms). # NOTE when disabling: check for both a short & long version of the option! ### START of options data produced by the cull-options script. ### # To disable a short-named option, add its letter to this string: short_disabled = 's' # These are also disabled when the restricted dir is not "/": short_disabled_subdir = 'KLk' # These are all possible short options that we will accept (when not disabled above): short_no_arg = 'ACDEHIJKLNORSUWXbcdgklmnopqrstuvxyz' # DO NOT REMOVE ANY short_with_num = '@B' # DO NOT REMOVE ANY # To disable a long-named option, change its value to a -1. The values mean: # 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only # check the arg when receiving; and 3 = always check the arg. long_opts = { 'append': 0, 'backup-dir': 2, 'block-size': 1, 'bwlimit': 1, 'checksum-choice': 1, 'checksum-seed': 1, 'compare-dest': 2, 'compress-choice': 1, 'compress-level': 1, 'copy-dest': 2, 'copy-devices': -1, 'copy-unsafe-links': 0, 'daemon': -1, 'debug': 1, 'delay-updates': 0, 'delete': 0, 'delete-after': 0, 'delete-before': 0, 'delete-delay': 0, 'delete-during': 0, 'delete-excluded': 0, 'delete-missing-args': 0, 'existing': 0, 'fake-super': 0, 'files-from': 3, 'force': 0, 'from0': 0, 'fsync': 0, 'fuzzy': 0, 'group': 0, 'groupmap': 1, 'hard-links': 0, 'iconv': 1, 'ignore-errors': 0, 'ignore-existing': 0, 'ignore-missing-args': 0, 'ignore-times': 0, 'info': 1, 'inplace': 0, 'link-dest': 2, 'links': 0, 'list-only': 0, 'log-file': 3, 'log-format': 1, 'max-alloc': 1, 'max-delete': 1, 'max-size': 1, 'min-size': 1, 'mkpath': 0, 'modify-window': 1, 'msgs2stderr': 0, 'munge-links': 0, 'new-compress': 0, 'no-W': 0, 'no-implied-dirs': 0, 'no-msgs2stderr': 0, 'no-munge-links': -1, 'no-r': 0, 'no-relative': 0, 'no-specials': 0, 'numeric-ids': 0, 'old-compress': 0, 'one-file-system': 0, 'only-write-batch': 1, 'open-noatime': 0, 'owner': 0, 'partial': 0, 'partial-dir': 2, 'perms': 0, 'preallocate': 0, 'recursive': 0, 'remove-sent-files': 0, 'remove-source-files': 0, 'safe-links': 0, 'sender': 0, 'server': 0, 'size-only': 0, 'skip-compress': 1, 'specials': 0, 'stats': 0, 'stderr': 1, 'suffix': 1, 'super': 0, 'temp-dir': 2, 'timeout': 1, 'times': 0, 'use-qsort': 0, 'usermap': 1, 'write-devices': -1, } ### END of options data produced by the cull-options script. ### import os, sys, re, argparse, glob, socket, time, subprocess from argparse import RawTextHelpFormatter try: from braceexpand import braceexpand except: braceexpand = lambda x: [ DE_BACKSLASH_RE.sub(r'\1', x) ] HAS_DOT_DOT_RE = re.compile(r'(^|/)\.\.(/|$)') LONG_OPT_RE = re.compile(r'^--([^=]+)(?:=(.*))?$') DE_BACKSLASH_RE = re.compile(r'\\(.)') def main(): if not os.path.isdir(args.dir): die("Restricted directory does not exist!") # The format of the environment variables set by sshd: # SSH_ORIGINAL_COMMAND: # rsync --server -vlogDtpre.iLsfxCIvu --etc . ARG # push # rsync --server --sender -vlogDtpre.iLsfxCIvu --etc . ARGS # pull # SSH_CONNECTION (client_ip client_port server_ip server_port): # 192.168.1.100 64106 192.168.1.2 22 command = os.environ.get('SSH_ORIGINAL_COMMAND', None) if not command: die("Not invoked via sshd") command = command.split(' ', 2) if command[0:1] != ['rsync']: die("SSH_ORIGINAL_COMMAND does not run rsync") if command[1:2] != ['--server']: die("--server option is not the first arg") command = '' if len(command) < 3 else command[2] global am_sender am_sender = command.startswith("--sender ") # Restrictive on purpose! if args.ro and not am_sender: die("sending to read-only server is not allowed") if args.wo and am_sender: die("reading from write-only server is not allowed") if args.wo or not am_sender: long_opts['sender'] = -1 if args.no_del: for opt in long_opts: if opt.startswith(('remove', 'delete')): long_opts[opt] = -1 if args.ro: long_opts['log-file'] = -1 if args.dir != '/': global short_disabled short_disabled += short_disabled_subdir short_no_arg_re = short_no_arg short_with_num_re = short_with_num if short_disabled: for ltr in short_disabled: short_no_arg_re = short_no_arg_re.replace(ltr, '') short_with_num_re = short_with_num_re.replace(ltr, '') short_disabled_re = re.compile(r'^-[%s]*([%s])' % (short_no_arg_re, short_disabled)) short_no_arg_re = re.compile(r'^-(?=.)[%s]*(e\d*\.\w*)?$' % short_no_arg_re) short_with_num_re = re.compile(r'^-[%s]\d+$' % short_with_num_re) log_fh = open(LOGFILE, 'a') if os.path.isfile(LOGFILE) else None try: os.chdir(args.dir) except OSError as e: die('unable to chdir to restricted dir:', str(e)) rsync_opts = [ '--server' ] rsync_args = [ ] saw_the_dot_arg = False last_opt = check_type = None for arg in re.findall(r'(?:[^\s\\]+|\\.[^\s\\]*)+', command): if check_type: rsync_opts.append(validated_arg(last_opt, arg, check_type)) check_type = None elif saw_the_dot_arg: # NOTE: an arg that starts with a '-' is safe due to our use of "--" in the cmd tuple. try: b_e = braceexpand(arg) # Also removes backslashes except: # Handle errors such as unbalanced braces by just de-backslashing the arg: b_e = [ DE_BACKSLASH_RE.sub(r'\1', arg) ] for xarg in b_e: rsync_args += validated_arg('arg', xarg, wild=True) else: # parsing the option args if arg == '.': saw_the_dot_arg = True continue rsync_opts.append(arg) if short_no_arg_re.match(arg) or short_with_num_re.match(arg): continue disabled = False m = LONG_OPT_RE.match(arg) if m: opt = m.group(1) opt_arg = m.group(2) ct = long_opts.get(opt, None) if ct is None: break # Generate generic failure due to unfinished arg parsing if ct == 0: continue opt = '--' + opt if ct > 0: if opt_arg is not None: rsync_opts[-1] = opt + '=' + validated_arg(opt, opt_arg, ct) else: check_type = ct last_opt = opt continue disabled = True elif short_disabled: m = short_disabled_re.match(arg) if m: disabled = True opt = '-' + m.group(1) if disabled: die("option", opt, "has been disabled on this server.") break # Generate a generic failure if not saw_the_dot_arg: die("invalid rsync-command syntax or options") if args.munge: rsync_opts.append('--munge-links') if not rsync_args: rsync_args = [ '.' ] cmd = (RSYNC, *rsync_opts, '--', '.', *rsync_args) if log_fh: now = time.localtime() host = os.environ.get('SSH_CONNECTION', 'unknown').split()[0] # Drop everything after the IP addr if host.startswith('::ffff:'): host = host[7:] try: host = socket.gethostbyaddr(socket.inet_aton(host)) except: pass log_fh.write("%02d:%02d:%02d %-16s %s\n" % (now.tm_hour, now.tm_min, now.tm_sec, host, str(cmd))) log_fh.close() # NOTE: This assumes that the rsync protocol will not be maliciously hijacked. if args.no_lock: os.execlp(RSYNC, *cmd) die("execlp(", RSYNC, *cmd, ') failed') child = subprocess.run(cmd) if child.returncode != 0: sys.exit(child.returncode) def validated_arg(opt, arg, typ=3, wild=False): if opt != 'arg': # arg values already have their backslashes removed. arg = DE_BACKSLASH_RE.sub(r'\1', arg) orig_arg = arg if arg.startswith('./'): arg = arg[1:] arg = arg.replace('//', '/') if args.dir != '/': if HAS_DOT_DOT_RE.search(arg): die("do not use .. in", opt, "(anchor the path at the root of your restricted dir)") if arg.startswith('/'): arg = args.dir + arg if wild: got = glob.glob(arg) if not got: got = [ arg ] else: got = [ arg ] ret = [ ] for arg in got: if args.dir != '/' and arg != '.' and (typ == 3 or (typ == 2 and not am_sender)): arg_has_trailing_slash = arg.endswith('/') if arg_has_trailing_slash: arg = arg[:-1] else: arg_has_trailing_slash_dot = arg.endswith('/.') if arg_has_trailing_slash_dot: arg = arg[:-2] real_arg = os.path.realpath(arg) if arg != real_arg and not real_arg.startswith(args.dir_slash): die('unsafe arg:', orig_arg, [arg, real_arg]) if arg_has_trailing_slash: arg += '/' elif arg_has_trailing_slash_dot: arg += '/.' if opt == 'arg' and arg.startswith(args.dir_slash): arg = arg[args.dir_slash_len:] if arg == '': arg = '.' ret.append(arg) return ret if wild else ret[0] def lock_or_die(dirname): import fcntl global lock_handle lock_handle = os.open(dirname, os.O_RDONLY) try: fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB) except: die('Another instance of rrsync is already accessing this directory.') def die(*msg): print(sys.argv[0], 'error:', *msg, file=sys.stderr) if sys.stdin.isatty(): arg_parser.print_help(sys.stderr) sys.exit(1) # This class displays the --help to the user on argparse error IFF they're running it interactively. class OurArgParser(argparse.ArgumentParser): def error(self, msg): die(msg) if __name__ == '__main__': our_desc = """Use "man rrsync" to learn how to restrict ssh users to using a restricted rsync command.""" arg_parser = OurArgParser(description=our_desc, add_help=False) only_group = arg_parser.add_mutually_exclusive_group() only_group.add_argument('-ro', action='store_true', help="Allow only reading from the DIR. Implies -no-del and -no-lock.") only_group.add_argument('-wo', action='store_true', help="Allow only writing to the DIR.") arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.") arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.") arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.") arg_parser.add_argument('-help', '-h', action='help', help="Output this help message and exit.") arg_parser.add_argument('dir', metavar='DIR', help="The restricted directory to use.") args = arg_parser.parse_args() args.dir = os.path.realpath(args.dir) args.dir_slash = args.dir + '/' args.dir_slash_len = len(args.dir_slash) if args.ro: args.no_del = True elif not args.no_lock: lock_or_die(args.dir) main() # vim: sw=4 et rsync-3.2.7/support/json-rsync-version0000775000000000000000000000666414324366276016644 0ustar rootroot#!/usr/bin/python3 import sys, argparse, subprocess, json TWEAK_NAME = { 'asm': 'asm_roll', 'ASM': 'asm_roll', 'hardlink_special': 'hardlink_specials', 'protect_args': 'secluded_args', 'protected_args': 'secluded_args', 'SIMD': 'SIMD_roll', } MOVE_OPTIM = set('asm_roll SIMD_roll'.split()) def main(): if not args.rsync or args.rsync == '-': ver_out = sys.stdin.read().strip() else: ver_out = subprocess.check_output([args.rsync, '--version', '--version'], encoding='utf-8').strip() if ver_out.startswith('{'): print(ver_out) return info = { } misplaced_optims = { } for line in ver_out.splitlines(): if line.startswith('rsync '): prog, vstr, ver, pstr, vstr2, proto = line.split() info['program'] = prog if ver.startswith('v'): ver = ver[1:] info[vstr] = ver if '.' not in proto: proto += '.0' else: proto = proto.replace('.PR', '.') info[pstr] = proto elif line.startswith('Copyright '): info['copyright'] = line[10:] elif line.startswith('Web site: '): info['url'] = line[10:] elif line.startswith(' '): if not saw_comma and ',' in line: saw_comma = True info[sect_name] = { } if saw_comma: for x in line.strip(' ,').split(', '): if ' ' in x: val, var = x.split(' ', 1) if val == 'no': val = False elif val.endswith('-bit'): var = var[:-1] + '_bits' val = int(val.split('-')[0]) else: var = x val = True var = var.replace(' ', '_').replace('-', '_') if var in TWEAK_NAME: var = TWEAK_NAME[var] if sect_name[0] != 'o' and var in MOVE_OPTIM: misplaced_optims[var] = val else: info[sect_name][var] = val else: info[sect_name] += [ x for x in line.split() if not x.startswith('(') ] elif line == '': break else: sect_name = line.strip(' :').replace(' ', '_').lower() info[sect_name] = [ ] saw_comma = False for chk in 'capabilities optimizations'.split(): if chk not in info: info[chk] = { } if misplaced_optims: info['optimizations'].update(misplaced_optims) for chk in 'checksum_list compress_list daemon_auth_list'.split(): if chk not in info: info[chk] = [ ] info['license'] = 'GPLv3' if ver[0] == '3' else 'GPLv2' info['caveat'] = 'rsync comes with ABSOLUTELY NO WARRANTY' print(json.dumps(info)) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Output rsync's version data in JSON format, even if the rsync doesn't support a native json-output method.", add_help=False) parser.add_argument('rsync', nargs='?', help="Specify an rsync command to run. Otherwise stdin is consumed.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et rsync-3.2.7/support/lsh0000775000000000000000000000603614162467441013627 0ustar rootroot#!/usr/bin/env perl # This is a "local shell" command that works like a remote shell but only for # the local host. See the usage message for more details. use strict; use warnings; use Getopt::Long; use English '-no_match_vars'; &Getopt::Long::Configure('bundling'); &Getopt::Long::Configure('require_order'); GetOptions( 'l=s' => \( my $login_name ), '1|2|4|6|A|a|C|f|g|k|M|N|n|q|s|T|t|V|v|X|x|Y' => sub { }, # Ignore 'b|c|D|e|F|i|L|m|O|o|p|R|S|w=s' => sub { }, # Ignore 'no-cd' => \( my $no_chdir ), 'sudo' => \( my $use_sudo ), 'rrsync=s' => \( my $rrsync_dir ), 'rropts=s' => \( my $rrsync_opts ), ) or &usage; &usage unless @ARGV > 1; my $host = shift; if ($host =~ s/^([^@]+)\@//) { $login_name = $1; } if ($host eq 'lh') { $no_chdir = 1; } elsif ($host ne 'localhost') { die "lsh: unable to connect to host $host\n"; } my ($home_dir, @cmd); if ($login_name) { my ($uid, $gid); if ($login_name =~ /\D/) { $uid = getpwnam($login_name); die "Unknown user: $login_name\n" unless defined $uid; } else { $uid = $login_name; } ($login_name, $gid, $home_dir) = (getpwuid($uid))[0,3,7]; if ($use_sudo) { unshift @ARGV, "cd '$home_dir' &&" unless $no_chdir; unshift @cmd, qw( sudo -H -u ), $login_name; $no_chdir = 1; } else { my $groups = "$gid $gid"; while (my ($grgid, $grmembers) = (getgrent)[2,3]) { if ($grgid != $gid && $grmembers =~ /(^|\s)\Q$login_name\E(\s|$)/o) { $groups .= " $grgid"; } } my ($ruid, $euid) = ($UID, $EUID); $GID = $EGID = $groups; $UID = $EUID = $uid; die "Cannot set ruid: $! (use --sudo?)\n" if $UID == $ruid && $ruid != $uid; die "Cannot set euid: $! (use --sudo?)\n" if $EUID == $euid && $euid != $uid; $ENV{USER} = $ENV{USERNAME} = $login_name; $ENV{HOME} = $home_dir; } } else { $home_dir = (getpwuid($UID))[7]; } unless ($no_chdir) { chdir $home_dir or die "Unable to chdir to $home_dir: $!\n"; } if ($rrsync_dir) { $ENV{SSH_ORIGINAL_COMMAND} = join(' ', @ARGV); push @cmd, 'rrsync'; if ($rrsync_opts) { foreach my $opt (split(/[ ,]+/, $rrsync_opts)) { $opt = "-$opt" unless $opt =~ /^-/; push @cmd, $opt; } } push @cmd, $rrsync_dir; } else { push @cmd, '/bin/sh', '-c', "@ARGV"; } exec @cmd; die "Failed to exec: $!\n"; sub usage { die <) { my($pid,$msg) = /^(?:$syslog_prefix|$rsyncd_prefix)\[(\d+)\]:? (.*)/o; next unless defined $pid; my($mod_spec) = $msg =~ /^rsync (?:on|to) (\S+) from /; if (defined $mod_spec) { if ($mod_spec =~ /^$match(\/\S*)?$/o) { $pids{$pid} = 1; } else { delete $pids{$pid}; } } next unless $pids{$pid}; print $_; } rsync-3.2.7/support/rrsync.1.md0000664000000000000000000001272214306676204015112 0ustar rootroot## NAME rrsync - a script to setup restricted rsync users via ssh logins ## SYNOPSIS ``` rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR ``` The single non-option argument specifies the restricted _DIR_ to use. It can be relative to the user's home directory or an absolute path. The online version of this manpage (that includes cross-linking of topics) is available at . ## DESCRIPTION A user's ssh login can be restricted to only allow the running of an rsync transfer in one of two easy ways: * forcing the running of the rrsync script * forcing the running of an rsync daemon-over-ssh command. Both of these setups use a feature of ssh that allows a command to be forced to run instead of an interactive shell. However, if the user's home shell is bash, please see [BASH SECURITY ISSUE](#) for a potential issue. To use the rrsync script, edit the user's `~/.ssh/authorized_keys` file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted: > ``` > command="rrsync DIR" > command="rrsync -ro DIR" > command="rrsync -munge -no-del DIR" > ``` Then, ensure that the rrsync script has your desired option restrictions. You may want to copy the script to a local bin dir with a unique name if you want to have multiple configurations. One or more rrsync options can be specified prior to the _DIR_ if you want to further restrict the transfer. To use an rsync daemon setup, edit the user's `~/.ssh/authorized_keys` file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted: > ``` > command="rsync --server --daemon ." > command="rsync --server --daemon --config=/PATH/TO/rsyncd.conf ." > ``` Then, ensure that the rsyncd.conf file is created with one or more module names with the appropriate path and option restrictions. If rsync's [`--config`](rsync.1#dopt) option is omitted, it defaults to `~/rsyncd.conf`. See the [**rsyncd.conf**(5)](rsyncd.conf.5) manpage for details of how to configure an rsync daemon. When using rrsync, there can be just one restricted dir per authorized key. A daemon setup, on the other hand, allows multiple module names inside the config file, each one with its own path setting. The remainder of this manpage is dedicated to using the rrsync script. ## OPTIONS 0. `-ro` Allow only reading from the DIR. Implies [`-no-del`](#opt) and [`-no-lock`](#opt). 0. `-wo` Allow only writing to the DIR. 0. `-munge` Enable rsync's [`--munge-links`](rsync.1#opt) on the server side. 0. `-no-del` Disable rsync's `--delete*` and `--remove*` options. 0. `-no-lock` Avoid the single-run (per-user) lock check. Useful with [`-munge`](#opt). 0. `-help`, `-h` Output this help message and exit. ## SECURITY RESTRICTIONS The rrsync script validates the path arguments it is sent to try to restrict them to staying within the specified DIR. The rrsync script rejects rsync's [`--copy-links`](rsync.1#opt) option (by default) so that a copy cannot dereference a symlink within the DIR to get to a file outside the DIR. The rrsync script rejects rsync's [`--protect-args`](rsync.1#opt) (`-s`) option because it would allow options to be sent to the server-side that the script cannot check. If you want to support `--protect-args`, use a daemon-over-ssh setup. The rrsync script accepts just a subset of rsync's options that the real rsync uses when running the server command. A few extra convenience options are also included to help it to interact with BackupPC and accept some convenient user overrides. The script (or a copy of it) can be manually edited if you want it to customize the option handling. ## BASH SECURITY ISSUE If your users have bash set as their home shell, bash may try to be overly helpful and ensure that the user's login bashrc files are run prior to executing the forced command. This can be a problem if the user can somehow update their home bashrc files, perhaps via the restricted copy, a shared home directory, or something similar. One simple way to avoid the issue is to switch the user to a simpler shell, such as dash. When choosing the new home shell, make sure that you're not choosing bash in disguise, as it is unclear if it avoids the security issue. Another potential fix is to ensure that the user's home directory is not a shared mount and that they have no means of copying files outside of their restricted directories. This may require you to force the enabling of symlink munging on the server side. A future version of openssh may have a change to the handling of forced commands that allows it to avoid using the user's home shell. ## EXAMPLES The `~/.ssh/authorized_keys` file might have lines in it like this: > ``` > command="rrsync client/logs" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzG... > command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmk... > ``` ## FILES ~/.ssh/authorized_keys ## SEE ALSO [**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5) ## VERSION This manpage is current for version @VERSION@ of rsync. ## CREDITS rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. An rsync web site is available at and its github project is . ## AUTHOR The original rrsync perl script was written by Joe Smith. Many people have later contributed to it. The python version was created by Wayne Davison. rsync-3.2.7/support/lsh.sh0000775000000000000000000000212414166655663014243 0ustar rootroot#!/bin/sh # This script can be used as a "remote shell" command that is only # capable of pretending to connect to "localhost". This is useful # for testing or for running a local copy where the sender and the # receiver needs to use different options (e.g. --fake-super). If # we get a -l USER option, we try to use "sudo -u USER" to run the # command. Supports only the hostnames "localhost" and "lh", with # the latter implying the --no-cd option. user='' do_cd=y # Default path is user's home dir (just like ssh) unless host is "lh". while : ; do case "$1" in -l) user="$2"; shift; shift ;; -l*) user=`echo "$1" | sed 's/^-l//'`; shift ;; --no-cd) do_cd=n; shift ;; -*) shift ;; localhost) shift; break ;; lh) do_cd=n; shift; break ;; *) echo "lsh: unable to connect to host $1" 1>&2; exit 1 ;; esac done if [ "$user" ]; then prefix='' if [ $do_cd = y ]; then home=`perl -e "print((getpwnam('$user'))[7])"` prefix="cd '$home' &&" fi sudo -H -u "$user" sh -c "$prefix $*" else if [ $do_cd = y ]; then cd || exit 1 fi eval "${@}" fi rsync-3.2.7/support/file-attr-restore0000775000000000000000000001151013672270624016402 0ustar rootroot#!/usr/bin/env perl # This script will parse the output of "find ARG [ARG...] -ls" and # apply (at your discretion) the permissions, owner, and group info # it reads onto any existing files and dirs (it doesn't try to affect # symlinks). Run this with --help (-h) for a usage summary. use strict; use Getopt::Long; our($p_opt, $o_opt, $g_opt, $map_file, $dry_run, $verbosity, $help_opt); &Getopt::Long::Configure('bundling'); &usage if !&GetOptions( 'all|a' => sub { $p_opt = $o_opt = $g_opt = 1 }, 'perms|p' => \$p_opt, 'owner|o' => \$o_opt, 'groups|g' => \$g_opt, 'map|m=s' => \$map_file, 'dry-run|n' => \$dry_run, 'help|h' => \$help_opt, 'verbose|v+' => \$verbosity, ) || $help_opt; our(%uid_hash, %gid_hash); $" = ', '; # How to join arrays referenced in double-quotes. &parse_map_file($map_file) if defined $map_file; my $detail_line = qr{ ^ \s* \d+ \s+ # ignore inode \d+ \s+ # ignore size ([-bcdlps]) # 1. File type ( [-r][-w][-xsS] # 2. user-permissions [-r][-w][-xsS] # group-permissions [-r][-w][-xtT] ) \s+ # other-permissions \d+ \s+ # ignore number of links (\S+) \s+ # 3. owner (\S+) \s+ # 4. group (?: \d+ \s+ )? # ignore size (when present) \w+ \s+ \d+ \s+ # ignore month and date \d+ (?: : \d+ )? \s+ # ignore time or year ([^\r\n]+) $ # 5. name }x; while (<>) { my($type, $perms, $owner, $group, $name) = /$detail_line/; die "Invalid input line $.:\n$_" unless defined $name; die "A filename is not properly escaped:\n$_" unless $name =~ /^[^"\\]*(\\(\d\d\d|\D)[^"\\]*)*$/; my $fn = $name; $fn =~ s/\\(\d+|.)/ eval "\"\\$1\"" /eg; if ($type eq '-') { undef $type unless -f $fn; } elsif ($type eq 'd') { undef $type unless -d $fn; } elsif ($type eq 'b') { undef $type unless -b $fn; } elsif ($type eq 'c') { undef $type unless -c $fn; } elsif ($type eq 'p') { undef $type unless -p $fn; } elsif ($type eq 's') { undef $type unless -S $fn; } else { if ($verbosity) { if ($type eq 'l') { $name =~ s/ -> .*//; $type = 'symlink'; } else { $type = "type '$type'"; } print "Skipping $name ($type ignored)\n"; } next; } if (!defined $type) { my $reason = -e _ ? "types don't match" : 'missing'; print "Skipping $name ($reason)\n"; next; } my($cur_mode, $cur_uid, $cur_gid) = (stat(_))[2,4,5]; $cur_mode &= 07777; my $highs = join('', $perms =~ /..(.)..(.)..(.)/); $highs =~ tr/-rwxSTst/00001111/; $perms =~ tr/-STrwxst/00011111/; my $mode = $p_opt ? oct('0b' . $highs . $perms) : $cur_mode; my $uid = $o_opt ? $uid_hash{$owner} : $cur_uid; if (!defined $uid) { if ($owner =~ /^\d+$/) { $uid = $owner; } else { $uid = getpwnam($owner); } $uid_hash{$owner} = $uid; } my $gid = $g_opt ? $gid_hash{$group} : $cur_gid; if (!defined $gid) { if ($group =~ /^\d+$/) { $gid = $group; } else { $gid = getgrnam($group); } $gid_hash{$group} = $gid; } my @changes; if ($mode != $cur_mode) { push(@changes, 'permissions'); if (!$dry_run && !chmod($mode, $fn)) { warn "chmod($mode, \"$name\") failed: $!\n"; } } if ($uid != $cur_uid || $gid != $cur_gid) { push(@changes, 'owner') if $uid != $cur_uid; push(@changes, 'group') if $gid != $cur_gid; if (!$dry_run) { if (!chown($uid, $gid, $fn)) { warn "chown($uid, $gid, \"$name\") failed: $!\n"; } if (($mode & 06000) && !chmod($mode, $fn)) { warn "post-chown chmod($mode, \"$name\") failed: $!\n"; } } } if (@changes) { print "$name: changed @changes\n"; } elsif ($verbosity) { print "$name: OK\n"; } } exit; sub parse_map_file { my($fn) = @_; open(IN, $fn) or die "Unable to open $fn: $!\n"; while () { if (/^user\s+(\S+)\s+(\S+)/) { $uid_hash{$1} = $2; } elsif (/^group\s+(\S+)\s+(\S+)/) { $gid_hash{$1} = $2; } else { die "Invalid line #$. in mapfile `$fn':\n$_"; } } close IN; } sub usage { die < set -e dir="$(pwd)" echo echo "This will setup an rsync daemon in $dir" if [ $# = 0 ]; then IFS='' read -p 'Module name to create (or return to exit): ' module [ ! "$module" ] && exit else module="$1" shift fi if [ $# = 0 ]; then IFS='' read -p 'Port number the daemon should listen on [873]: ' port else port="$1" shift fi [ "$port" ] || port=873 if [ $# = 0 ]; then IFS='' read -p 'User name for authentication (empty for none): ' user else user="$1" shift fi if [ "$user" ]; then IFS='' read -s -p 'Desired password: ' password echo fi rsync="$1" [ "$rsync" ] || rsync=rsync moduledir="${dir%/}/$module" mkdir "$module" cat >rsyncd.conf <>rsyncd.conf <<-EOF auth users = $user secrets file = $module.secrets EOF touch "$module".secrets chmod go-rwx "$module".secrets echo "$user:$password" >"$module".secrets user="$user@" fi cat >start <stop <<"EOF" #!/bin/bash set -e cd `dirname $0` ! [ -e rsyncd.pid ] || kill -s SIGTERM $(< rsyncd.pid) EOF chmod +x stop path="rsync://$user$(hostname):$port/$module/" if ./start; then sleep .2 echo echo "I ran the start command for the daemon. The log file rsyncd.log says:" echo cat rsyncd.log echo echo "You can start and stop it with ./start and ./stop respectively." echo "You can customize the configuration file rsyncd.conf." echo echo "Give rsync the following path to access the module:" echo " $path" echo if [ "$user" ]; then echo "Let's test the daemon now. Enter the password you chose at the prompt." else echo "Let's test the daemon now." fi echo echo '$' $rsync --list-only "$path" $rsync --list-only "$path" echo echo "You should see an empty folder; it's $moduledir." else echo "Something went wrong. Do you see an error message?" fi rsync-3.2.7/support/deny-rsync0000775000000000000000000000175513672270624015137 0ustar rootroot#!/usr/bin/env bash # Send an error message via the rsync-protocol to a non-daemon client rsync. # # Usage: deny-rsync "message" protocol_version=29 exit_code=4 # same as a daemon that refuses an option # e.g. byte_escape 29 => \035 function byte_escape { echo -ne "\\0$(printf "%o" $1)" } msg="$1" if [ "${#msg}" -gt 254 ]; then # truncate a message that is too long for this naive script to handle msg="${msg:0:251}..." fi msglen=$(( ${#msg} + 1 )) # add 1 for the newline we append below # Send protocol version. All numbers are LSB-first 4-byte ints. echo -ne "$(byte_escape $protocol_version)\\000\\000\\000" # Send a zero checksum seed. echo -ne "\\000\\000\\000\\000" # The following is equivalent to rprintf(FERROR_XFER, "%s\n", $msg). # 1. Message header: ((MPLEX_BASE + FERROR_XFER) << 24) + $msglen. echo -ne "$(byte_escape $msglen)\\000\\000\\010" # 2. The actual data. echo -E "$msg" # Make sure the client gets our message, not a write failure. sleep 1 exit $exit_code rsync-3.2.7/support/rsync-slash-strip0000775000000000000000000000140114144003115016415 0ustar rootroot#!/usr/bin/env bash # This script can be used as an rsync command-line filter that strips a single # trailing slash from each arg. That treats "src/" the same as "src", thus # you need to use "src/." or "src//" for just the contents of the "src" dir. # (Note that command-line dir-excludes would need to use "excl//" too.) # # To use this, name it something like "rs", put it somewhere in your path, and # then use "rs" in place of "rsync" when you are typing your copy commands. REAL_RSYNC=/usr/bin/rsync args=() for arg in "${@}"; do if [[ "$arg" == --server ]]; then exec $REAL_RSYNC "${@}" exit $? # Not reached fi if [[ "$arg" == / ]]; then args=("${args[@]}" /) else args=("${args[@]}" "${arg%/}") fi done exec $REAL_RSYNC "${args[@]}" rsync-3.2.7/support/rsyncstats0000775000000000000000000002076313672270624015261 0ustar rootroot#!/usr/bin/env perl # # This script parses the default logfile format produced by rsync when running # as a daemon with transfer logging enabled. It also parses a slightly tweaked # version of the default format where %o has been replaced with %i. # # This script is derived from the xferstats script that comes with wuftpd. See # the usage message at the bottom for the options it takes. # # Andrew Tridgell, October 1998 use Getopt::Long; # You may wish to edit the next line to customize for your default log file. $usage_file = "/var/log/rsyncd.log"; # Edit the following lines for default report settings. # Entries defined here will be over-ridden by the command line. $hourly_report = 0; $domain_report = 0; $total_report = 0; $depth_limit = 9999; $only_section = ''; &Getopt::Long::Configure('bundling'); &usage if !&GetOptions( 'hourly-report|h' => \$hourly_report, 'domain-report|d' => \$domain_report, 'domain|D:s' => \$only_domain, 'total-report|t' => \$total_report, 'depth-limit|l:i' => \$depth_limit, 'real|r' => \$real, 'anon|a' => \$anon, 'section|s:s' => \$only_section, 'file|f:s' => \$usage_file, ); $anon = 1 if !$real && !$anon; open(LOG, $usage_file) || die "Error opening usage log file: $usage_file\n"; if ($only_domain) { print "Transfer Totals include the '$only_domain' domain only.\n"; print "All other domains are filtered out for this report.\n\n"; } if ($only_section) { print "Transfer Totals include the '$only_section' section only.\n"; print "All other sections are filtered out for this report.\n\n"; } line: while () { my $syslog_prefix = '\w\w\w +\d+ \d\d:\d\d:\d\d \S+ rsyncd'; my $rsyncd_prefix = '\d\d\d\d/\d\d/\d\d \d\d:\d\d:\d\d '; next unless ($day,$time,$op,$host,$module,$file,$bytes) = m{^ ( \w\w\w\s+\d+ | \d+/\d\d/\d\d ) \s+ # day (\d\d:\d\d:\d\d) \s+ # time [^[]* \[\d+\]:? \s+ # pid (ignored) (send|recv|[<>]f\S+) \s+ # op (%o or %i) (\S+) \s+ # host \[\d+\.\d+\.\d+\.\d+\] \s+ # IP (ignored) (\S+) \s+ # module \(\S*\) \s+ # user (ignored) (.*) \s+ # file name (\d+) # file length in bytes $ }x; # TODO actually divide the data by into send/recv categories if ($op =~ /^>/) { $op = 'send'; } elsif ($op =~ /^ 0 || $#address < 2 ) { $domain = "unresolved"; } if ($only_domain ne '') { next unless (substr($domain,0,length($only_domain)) eq $only_domain); } # printf("c=%d day=%s bytes=%d file=%s path=%s\n", # $#line, $daytime, $bytes, $file, $pathkey); $xferfiles++; # total files sent $xfertfiles++; # total files sent $xferfiles{$daytime}++; # files per day $groupfiles{$pathkey}++; # per-group accesses $domainfiles{$domain}++; $xferbytes{$daytime} += $bytes; # bytes per day $domainbytes{$domain} += $bytes; # xmit bytes to domain $xferbytes += $bytes; # total bytes sent $groupbytes{$pathkey} += $bytes; # per-group bytes sent $xfertfiles{$hour}++; # files per hour $xfertbytes{$hour} += $bytes; # bytes per hour $xfertbytes += $bytes; # total bytes sent } close LOG; #@syslist = keys %systemfiles; @dates = sort datecompare keys %xferbytes; if ($xferfiles == 0) {die "There was no data to process.\n";} print "TOTALS FOR SUMMARY PERIOD ", $dates[0], " TO ", $dates[$#dates], "\n\n"; printf("Files Transmitted During Summary Period %12.0f\n", $xferfiles); printf("Bytes Transmitted During Summary Period %12.0f\n", $xferbytes); #printf("Systems Using Archives %12.0f\n\n", $#syslist+1); printf("Average Files Transmitted Daily %12.0f\n", $xferfiles / ($#dates + 1)); printf("Average Bytes Transmitted Daily %12.0f\n", $xferbytes / ($#dates + 1)); format top1 = Daily Transmission Statistics Number Of Number of Percent Of Percent Of Date Files Sent MB Sent Files Sent Bytes Sent --------------- ---------- ----------- ---------- ---------- . format line1 = @<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>> $date, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes . $^ = top1; $~ = line1; foreach $date (sort datecompare keys %xferbytes) { $nfiles = $xferfiles{$date}; $nbytes = $xferbytes{$date}; $pctfiles = sprintf("%8.2f", 100*$xferfiles{$date} / $xferfiles); $pctbytes = sprintf("%8.2f", 100*$xferbytes{$date} / $xferbytes); write; } if ($total_report) { format top2 = Total Transfers from each Archive Section (By bytes) - Percent - Archive Section NFiles MB Files Bytes ------------------------------------- ------- ----------- ----- ------- . format line2 = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>> @>>>>>>>>>> @>>>> @>>>> $section, $files, $bytes/(1024*1024), $pctfiles, $pctbytes . $| = 1; $- = 0; $^ = top2; $~ = line2; foreach $section (sort bytecompare keys %groupfiles) { $files = $groupfiles{$section}; $bytes = $groupbytes{$section}; $pctbytes = sprintf("%8.2f", 100 * $groupbytes{$section} / $xferbytes); $pctfiles = sprintf("%8.2f", 100 * $groupfiles{$section} / $xferfiles); write; } if ( $xferfiles < 1 ) { $xferfiles = 1; } if ( $xferbytes < 1 ) { $xferbytes = 1; } } if ($domain_report) { format top3 = Total Transfer Amount By Domain Number Of Number of Percent Of Percent Of Domain Name Files Sent MB Sent Files Sent Bytes Sent ----------- ---------- ------------ ---------- ---------- . format line3 = @<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>>> @>>>>>>> @>>>>>>> $domain, $files, $bytes/(1024*1024), $pctfiles, $pctbytes . $- = 0; $^ = top3; $~ = line3; foreach $domain (sort domnamcompare keys %domainfiles) { if ( $domainsecs{$domain} < 1 ) { $domainsecs{$domain} = 1; } $files = $domainfiles{$domain}; $bytes = $domainbytes{$domain}; $pctfiles = sprintf("%8.2f", 100 * $domainfiles{$domain} / $xferfiles); $pctbytes = sprintf("%8.2f", 100 * $domainbytes{$domain} / $xferbytes); write; } } if ($hourly_report) { format top8 = Hourly Transmission Statistics Number Of Number of Percent Of Percent Of Time Files Sent MB Sent Files Sent Bytes Sent --------------- ---------- ----------- ---------- ---------- . format line8 = @<<<<<<<<<<<<<< @>>>>>>>>> @>>>>>>>>>> @>>>>>>> @>>>>>>> $hour, $nfiles, $nbytes/(1024*1024), $pctfiles, $pctbytes . $| = 1; $- = 0; $^ = top8; $~ = line8; foreach $hour (sort keys %xfertbytes) { $nfiles = $xfertfiles{$hour}; $nbytes = $xfertbytes{$hour}; $pctfiles = sprintf("%8.2f", 100*$xfertfiles{$hour} / $xferfiles); $pctbytes = sprintf("%8.2f", 100*$xfertbytes{$hour} / $xferbytes); write; } } exit(0); sub datecompare { $a cmp $b; } sub domnamcompare { $sdiff = length($a) - length($b); ($sdiff < 0) ? -1 : ($sdiff > 0) ? 1 : $a cmp $b; } sub bytecompare { $bdiff = $groupbytes{$b} - $groupbytes{$a}; ($bdiff < 0) ? -1 : ($bdiff > 0) ? 1 : $a cmp $b; } sub faccompare { $fdiff = $fac{$b} - $fac{$a}; ($fdiff < 0) ? -1 : ($fdiff > 0) ? 1 : $a cmp $b; } sub usage { die <) { push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/; } print join(',', @_), "\n"; rsync-3.2.7/support/files-to-excludes0000775000000000000000000000103213672270624016364 0ustar rootroot#!/usr/bin/env perl # This script takes an input of filenames and outputs a set of # include/exclude directives that can be used by rsync to copy # just the indicated files using an --exclude-from=FILE option. use strict; my %hash; while (<>) { chomp; s#^/+##; my $path = '/'; while (m#([^/]+/)/*#g) { $path .= $1; print "+ $path\n" unless $hash{$path}++; } if (m#([^/]+)$#) { print "+ $path$1\n"; } else { delete $hash{$path}; } } foreach (sort keys %hash) { print "- $_*\n"; } print "- /*\n"; rsync-3.2.7/support/Makefile0000664000000000000000000000012010171016361014522 0ustar rootrootall: savetransfer savetransfer: savetransfer.o clean: rm -f *.o savetransfer rsync-3.2.7/support/atomic-rsync0000775000000000000000000001210614163413232015432 0ustar rootroot#!/usr/bin/env python3 # This script lets you update a hierarchy of files in an atomic way by # first creating a new hierarchy using rsync's --link-dest option, and # then swapping the hierarchy into place. **See the usage message for # more details and some important caveats!** import os, sys, re, subprocess, shutil ALT_DEST_ARG_RE = re.compile('^--[a-z][^ =]+-dest(=|$)') RSYNC_PROG = '/usr/bin/rsync' def main(): cmd_args = sys.argv[1:] if '--help' in cmd_args: usage_and_exit() if len(cmd_args) < 2: usage_and_exit(True) dest_dir = cmd_args[-1].rstrip('/') if dest_dir == '' or dest_dir.startswith('-'): usage_and_exit(True) if not os.path.isdir(dest_dir): die(dest_dir, "is not a directory or a symlink to a dir.\nUse --help for help.") bad_args = [ arg for arg in cmd_args if ALT_DEST_ARG_RE.match(arg) ] if bad_args: die("You cannot use the", ' or '.join(bad_args), "option with atomic-rsync.\nUse --help for help.") # We ignore exit-code 24 (file vanished) by default. allowed_exit_codes = '0 ' + os.environ.get('ATOMIC_RSYNC_OK_CODES', '24') try: allowed_exit_codes = set(int(num) for num in re.split(r'[, ]+', allowed_exit_codes) if num != '') except ValueError: die('Invalid integer in ATOMIC_RSYNC_OK_CODES:', allowed_exit_codes[2:]) symlink_content = os.readlink(dest_dir) if os.path.islink(dest_dir) else None dest_arg = dest_dir dest_dir = os.path.realpath(dest_dir) # The real destination dir with all symlinks dereferenced if dest_dir == '/': die('You must not use "/" as the destination directory.\nUse --help for help.') old_dir = new_dir = None if symlink_content is not None and dest_dir.endswith(('-1','-2')): if not symlink_content.endswith(dest_dir[-2:]): die("Symlink suffix out of sync with dest_dir name:", symlink_content, 'vs', dest_dir) num = 3 - int(dest_dir[-1]); old_dir = None new_dir = dest_dir[:-1] + str(num) symlink_content = symlink_content[:-1] + str(num) else: old_dir = dest_dir + '~old~' new_dir = dest_dir + '~new~' cmd_args[-1] = new_dir + '/' if old_dir is not None and os.path.isdir(old_dir): shutil.rmtree(old_dir) if os.path.isdir(new_dir): shutil.rmtree(new_dir) child = subprocess.run([RSYNC_PROG, '--link-dest=' + dest_dir, *cmd_args]) if child.returncode not in allowed_exit_codes: die('The rsync copy failed with code', child.returncode, exitcode=child.returncode) if not os.path.isdir(new_dir): die('The rsync copy failed to create:', new_dir) if old_dir is None: atomic_symlink(symlink_content, dest_arg) else: os.rename(dest_dir, old_dir) os.rename(new_dir, dest_dir) def atomic_symlink(target, link): newlink = link + "~new~" try: os.unlink(newlink); # Just in case except OSError: pass os.symlink(target, newlink) os.rename(newlink, link) def usage_and_exit(use_stderr=False): usage_msg = """\ Usage: atomic-rsync [RSYNC-OPTIONS] [HOST:]/SOURCE/DIR/ /DEST/DIR/ atomic-rsync [RSYNC-OPTIONS] HOST::MOD/DIR/ /DEST/DIR/ This script lets you update a hierarchy of files in an atomic way by first creating a new hierarchy (using hard-links to leverage the existing files), and then swapping the new hierarchy into place. You must be pulling files to a local directory, and that directory must already exist. For example: mkdir /local/files-1 ln -s files-1 /local/files atomic-rsync -aiv host:/remote/files/ /local/files/ If /local/files is a symlink to a directory that ends in -1 or -2, the copy will go to the alternate suffix and the symlink will be changed to point to the new dir. This is a fully atomic update. If the destination is not a symlink (or not a symlink to a *-1 or a *-2 directory), this will instead create a directory with "~new~" suffixed, move the current directory to a name with "~old~" suffixed, and then move the ~new~ directory to the original destination name (this double rename is not fully atomic, but is rapid). In both cases, the prior destintaion directory will be preserved until the next update, at which point it will be deleted. By default, rsync exit-code 24 (file vanished) is allowed without halting the atomic update. If you want to change that, specify the environment variable ATOMIC_RSYNC_OK_CODES with numeric values separated by spaces and/or commas. Specify an empty string to only allow a successful copy. An override example: ATOMIC_RSYNC_OK_CODES='23 24' atomic-rsync -aiv host:src/ dest/ See the errcode.h file for a list of all the exit codes. See the "rsync" command for its list of options. You may not use the --link-dest, --compare-dest, or --copy-dest options (since this script uses --link-dest to make the transfer efficient). """ print(usage_msg, file=sys.stderr if use_stderr else sys.stdout) sys.exit(1 if use_stderr else 0) def die(*args, exitcode=1): print(*args, file=sys.stderr) sys.exit(exitcode) if __name__ == '__main__': main() # vim: sw=4 et rsync-3.2.7/support/savetransfer.c0000664000000000000000000001072010541441050015736 0ustar rootroot/* This program can record the stream of data flowing to or from a program. * This allows it to be used to check that rsync's data that is flowing * through a remote shell is not being corrupted (for example). * * Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...] * -i Save the input going to PROGRAM to the OUTPUT_FILE * -o Save the output coming from PROGRAM to the OUTPUT_FILE * * If you want to capture the flow of data for an rsync command, use one of * the following commands (the resulting files should be identical): * * rsync -av --rsh="savetransfer -i /tmp/to.server ssh" * --rsync-path="savetransfer -i /tmp/from.client rsync" SOURCE DEST * * rsync -av --rsh="savetransfer -o /tmp/from.server ssh" * --rsync-path="savetransfer -o /tmp/to.client rsync" SOURCE DEST * * Note that this program aborts after 30 seconds of inactivity, so you'll need * to change it if that is not enough dead time for your transfer. Also, some * of the above commands will not notice that the transfer is done (if we're * saving the input to a PROGRAM and the PROGRAM goes away: we won't notice * that it's gone unless more data comes in) -- when this happens it will delay * at the end of the transfer until the timeout period expires. */ #include "../rsync.h" #define TIMEOUT_SECONDS 30 #ifdef HAVE_SIGACTION static struct sigaction sigact; #endif void run_program(char **command); char buf[4096]; int save_data_from_program = 0; int main(int argc, char *argv[]) { int fd_file, len; struct timeval tv; fd_set fds; argv++; if (--argc && argv[0][0] == '-') { if (argv[0][1] == 'o') save_data_from_program = 1; else if (argv[0][1] == 'i') save_data_from_program = 0; else { fprintf(stderr, "Unknown option: %s\n", argv[0]); exit(1); } argv++; argc--; } if (argc < 2) { fprintf(stderr, "Usage: savetransfer [-i|-o] OUTPUT_FILE PROGRAM [ARGS...]\n"); fprintf(stderr, "-i Save the input going to PROGRAM to the OUTPUT_FILE\n"); fprintf(stderr, "-o Save the output coming from PROGRAM to the OUTPUT_FILE\n"); exit(1); } if ((fd_file = open(*argv, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0644)) < 0) { fprintf(stderr, "Unable to write to `%s': %s\n", *argv, strerror(errno)); exit(1); } set_blocking(fd_file); SIGACTION(SIGPIPE, SIG_IGN); run_program(argv + 1); #if defined HAVE_SETMODE && O_BINARY setmode(STDIN_FILENO, O_BINARY); setmode(STDOUT_FILENO, O_BINARY); #endif set_nonblocking(STDIN_FILENO); set_blocking(STDOUT_FILENO); while (1) { FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); tv.tv_sec = TIMEOUT_SECONDS; tv.tv_usec = 0; if (!select(STDIN_FILENO+1, &fds, NULL, NULL, &tv)) break; if (!FD_ISSET(STDIN_FILENO, &fds)) break; if ((len = read(STDIN_FILENO, buf, sizeof buf)) <= 0) break; if (write(STDOUT_FILENO, buf, len) != len) { fprintf(stderr, "Failed to write data to stdout: %s\n", strerror(errno)); exit(1); } if (write(fd_file, buf, len) != len) { fprintf(stderr, "Failed to write data to fd_file: %s\n", strerror(errno)); exit(1); } } return 0; } void run_program(char **command) { int pipe_fds[2], ret; pid_t pid; if (pipe(pipe_fds) < 0) { fprintf(stderr, "pipe failed: %s\n", strerror(errno)); exit(1); } if ((pid = fork()) < 0) { fprintf(stderr, "fork failed: %s\n", strerror(errno)); exit(1); } if (pid == 0) { if (save_data_from_program) ret = dup2(pipe_fds[1], STDOUT_FILENO); else ret = dup2(pipe_fds[0], STDIN_FILENO); if (ret < 0) { fprintf(stderr, "Failed to dup (in child): %s\n", strerror(errno)); exit(1); } close(pipe_fds[0]); close(pipe_fds[1]); set_blocking(STDIN_FILENO); set_blocking(STDOUT_FILENO); execvp(command[0], command); fprintf(stderr, "Failed to exec %s: %s\n", command[0], strerror(errno)); exit(1); } if (save_data_from_program) ret = dup2(pipe_fds[0], STDIN_FILENO); else ret = dup2(pipe_fds[1], STDOUT_FILENO); if (ret < 0) { fprintf(stderr, "Failed to dup (in parent): %s\n", strerror(errno)); exit(1); } close(pipe_fds[0]); close(pipe_fds[1]); } void set_nonblocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL, 0)) == -1) return; if (!(val & NONBLOCK_FLAG)) { val |= NONBLOCK_FLAG; fcntl(fd, F_SETFL, val); } } void set_blocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL, 0)) < 0) return; if (val & NONBLOCK_FLAG) { val &= ~NONBLOCK_FLAG; fcntl(fd, F_SETFL, val); } } rsync-3.2.7/Doxyfile0000664000000000000000000001575607454212730013111 0ustar rootroot# Doxyfile 1.2.15 #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- PROJECT_NAME = rsync PROJECT_NUMBER = HEAD OUTPUT_DIRECTORY = dox OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = *source INTERNAL_DOCS = YES STRIP_CODE_COMMENTS = NO CASE_SENSE_NAMES = YES SHORT_NAMES = NO HIDE_SCOPE_NAMES = YES VERBATIM_HEADERS = YES SHOW_INCLUDE_FILES = YES JAVADOC_AUTOBRIEF = YES INHERIT_DOCS = YES INLINE_INFO = YES SORT_MEMBER_DOCS = NO DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 8 GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES ALIASES = ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = NO WARN_IF_UNDOCUMENTED = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . FILE_PATTERNS = *.c \ *.h RECURSIVE = YES EXCLUDE = proto.h \ zlib \ popt EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 3 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 3 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = YES #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = NO MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = YES TEMPLATE_RELATIONS = YES HIDE_UNDOC_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO CGI_NAME = search.cgi CGI_URL = DOC_URL = DOC_ABSPATH = BIN_ABSPATH = /usr/local/bin/ EXT_DOC_PATHS = rsync-3.2.7/pipe.c0000664000000000000000000001212213671304046012464 0ustar rootroot/* * Routines used to setup various kinds of inter-process pipes. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2004-2020 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" extern int am_sender; extern int am_server; extern int blocking_io; extern int filesfrom_fd; extern int munge_symlinks; extern char *logfile_name; extern int remote_option_cnt; extern const char **remote_options; extern struct chmod_mode_struct *chmod_modes; /** * Create a child connected to us via its stdin/stdout. * * This is derived from CVS code * * Note that in the child STDIN is set to blocking and STDOUT * is set to non-blocking. This is necessary as rsh relies on stdin being blocking * and ssh relies on stdout being non-blocking * * If blocking_io is set then use blocking io on both fds. That can be * used to cope with badly broken rsh implementations like the one on * Solaris. **/ pid_t piped_child(char **command, int *f_in, int *f_out) { pid_t pid; int to_child_pipe[2]; int from_child_pipe[2]; if (DEBUG_GTE(CMD, 1)) print_child_argv("opening connection using:", command); if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) { rsyserr(FERROR, errno, "pipe"); exit_cleanup(RERR_IPC); } pid = do_fork(); if (pid == -1) { rsyserr(FERROR, errno, "fork"); exit_cleanup(RERR_IPC); } if (pid == 0) { if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || close(to_child_pipe[1]) < 0 || close(from_child_pipe[0]) < 0 || dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { rsyserr(FERROR, errno, "Failed to dup/close"); exit_cleanup(RERR_IPC); } if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); set_blocking(STDIN_FILENO); if (blocking_io > 0) set_blocking(STDOUT_FILENO); execvp(command[0], command); rsyserr(FERROR, errno, "Failed to exec %s", command[0]); exit_cleanup(RERR_IPC); } if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { rsyserr(FERROR, errno, "Failed to close"); exit_cleanup(RERR_IPC); } *f_in = from_child_pipe[0]; *f_out = to_child_pipe[1]; return pid; } /* This function forks a child which calls child_main(). First, * however, it has to establish communication paths to and from the * newborn child. It creates two socket pairs -- one for writing to * the child (from the parent) and one for reading from the child * (writing to the parent). Since that's four socket ends, each * process has to close the two ends it doesn't need. The remaining * two socket ends are retained for reading and writing. In the * child, the STDIN and STDOUT file descriptors refer to these * sockets. In the parent, the function arguments f_in and f_out are * set to refer to these sockets. */ pid_t local_child(int argc, char **argv, int *f_in, int *f_out, int (*child_main)(int, char*[])) { pid_t pid; int to_child_pipe[2]; int from_child_pipe[2]; /* The parent process is always the sender for a local rsync. */ assert(am_sender); if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) { rsyserr(FERROR, errno, "pipe"); exit_cleanup(RERR_IPC); } pid = do_fork(); if (pid == -1) { rsyserr(FERROR, errno, "fork"); exit_cleanup(RERR_IPC); } if (pid == 0) { am_sender = 0; am_server = 1; filesfrom_fd = -1; munge_symlinks = 0; /* Each side needs its own option. */ chmod_modes = NULL; /* Let the sending side handle this. */ /* Let the client side handle this. */ if (logfile_name) { logfile_name = NULL; logfile_close(); } if (remote_option_cnt) { int rc = remote_option_cnt + 1; const char **rv = remote_options; if (!parse_arguments(&rc, &rv)) { option_error(); exit_cleanup(RERR_SYNTAX); } } if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || close(to_child_pipe[1]) < 0 || close(from_child_pipe[0]) < 0 || dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { rsyserr(FERROR, errno, "Failed to dup/close"); exit_cleanup(RERR_IPC); } if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); #ifdef ICONV_CONST setup_iconv(); #endif child_main(argc, argv); } if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { rsyserr(FERROR, errno, "Failed to close"); exit_cleanup(RERR_IPC); } *f_in = from_child_pipe[0]; *f_out = to_child_pipe[1]; return pid; } rsync-3.2.7/trimslash.c0000664000000000000000000000226513651401443013541 0ustar rootroot/* * Simple utility used only by the test harness. * * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2020 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" /* These are to make syscall.o shut up. */ int dry_run = 0; int am_root = 0; int am_sender = 1; int read_only = 1; int list_only = 0; int main(int argc, char **argv) { int i; if (argc <= 1) { fprintf(stderr, "trimslash: needs at least one argument\n"); return 1; } for (i = 1; i < argc; i++) { trim_trailing_slashes(argv[i]); /* modify in place */ printf("%s\n", argv[i]); } return 0; } rsync-3.2.7/itypes.h0000664000000000000000000000276114170671375013070 0ustar rootroot/* Inline functions for rsync. * * Copyright (C) 2007-2022 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. */ static inline int isDigit(const char *ptr) { return isdigit(*(unsigned char *)ptr); } static inline int isHexDigit(const char *ptr) { return isxdigit(*(unsigned char *)ptr); } static inline int isPrint(const char *ptr) { return isprint(*(unsigned char *)ptr); } static inline int isSpace(const char *ptr) { return isspace(*(unsigned char *)ptr); } static inline int isAlNum(const char *ptr) { return isalnum(*(unsigned char *)ptr); } static inline int isLower(const char *ptr) { return islower(*(unsigned char *)ptr); } static inline int isUpper(const char *ptr) { return isupper(*(unsigned char *)ptr); } static inline int toLower(const char *ptr) { return tolower(*(unsigned char *)ptr); } static inline int toUpper(const char *ptr) { return toupper(*(unsigned char *)ptr); } rsync-3.2.7/rsync.1.html0000664000000000000000000105577214324367163013576 0ustar rootroot rsync(1) manpage

NAME

rsync -⁠ a fast, versatile, remote (and local) file-copying tool

SYNOPSIS

Local:
    rsync [OPTION...] SRC... [DEST]

Access via remote shell:
    Pull:
        rsync [OPTION...] [USER@]HOST:SRC... [DEST]
    Push:
        rsync [OPTION...] SRC... [USER@]HOST:DEST

Access via rsync daemon:
    Pull:
        rsync [OPTION...] [USER@]HOST::SRC... [DEST]
        rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]
    Push:
        rsync [OPTION...] SRC... [USER@]HOST::DEST
        rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST)

Usages with just one SRC arg and no DEST arg will list the source files instead of copying.

The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rsync.1.

DESCRIPTION

Rsync is a fast and extraordinarily versatile file copying tool. It can copy locally, to/from another host over any remote shell, or to/from a remote rsync daemon. It offers a large number of options that control every aspect of its behavior and permit very flexible specification of the set of files to be copied. It is famous for its delta-transfer algorithm, which reduces the amount of data sent over the network by sending only the differences between the source files and the existing files in the destination. Rsync is widely used for backups and mirroring and as an improved copy command for everyday use.

Rsync finds files that need to be transferred using a "quick check" algorithm (by default) that looks for files that have changed in size or in last-modified time. Any changes in the other preserved attributes (as requested by options) are made on the destination file directly when the quick check indicates that the file's data does not need to be updated.

Some of the additional features of rsync are:

  • support for copying links, devices, owners, groups, and permissions
  • exclude and exclude-from options similar to GNU tar
  • a CVS exclude mode for ignoring the same files that CVS would ignore
  • can use any transparent remote shell, including ssh or rsh
  • does not require super-user privileges
  • pipelining of file transfers to minimize latency costs
  • support for anonymous or authenticated rsync daemons (ideal for mirroring)

GENERAL

Rsync copies files either to or from a remote host, or locally on the current host (it does not support copying files between two remote hosts).

There are two different ways for rsync to contact a remote system: using a remote-shell program as the transport (such as ssh or rsh) or contacting an rsync daemon directly via TCP. The remote-shell transport is used whenever the source or destination path contains a single colon (:) separator after a host specification. Contacting an rsync daemon directly happens when the source or destination path contains a double colon (::) separator after a host specification, OR when an rsync:// URL is specified (see also the USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION section for an exception to this latter rule).

As a special case, if a single source arg is specified without a destination, the files are listed in an output format similar to "ls -l".

As expected, if neither the source or destination path specify a remote host, the copy occurs locally (see also the --list-only option).

Rsync refers to the local side as the client and the remote side as the server. Don't confuse server with an rsync daemon. A daemon is always a server, but a server can be either a daemon or a remote-shell spawned process.

SETUP

See the file README.md for installation instructions.

Once installed, you can use rsync to any machine that you can access via a remote shell (as well as some that you can access using the rsync daemon-mode protocol). For remote transfers, a modern rsync uses ssh for its communications, but it may have been configured to use a different remote shell by default, such as rsh or remsh.

You can also specify any remote shell you like, either by using the -e command line option, or by setting the RSYNC_RSH environment variable.

Note that rsync must be installed on both the source and destination machines.

USAGE

You use rsync in the same way you use rcp. You must specify a source and a destination, one of which may be remote.

Perhaps the best way to explain the syntax is with some examples:

rsync -t *.c foo:src/

This would transfer all files matching the pattern *.c from the current directory to the directory src on the machine foo. If any of the files already exist on the remote system then the rsync remote-update protocol is used to update the file by sending only the differences in the data. Note that the expansion of wildcards on the command-line (*.c) into a list of files is handled by the shell before it runs rsync and not by rsync itself (exactly the same as all other Posix-style programs).

rsync -avz foo:src/bar /data/tmp

This would recursively transfer all files from the directory src/bar on the machine foo into the /data/tmp/bar directory on the local machine. The files are transferred in archive mode, which ensures that symbolic links, devices, attributes, permissions, ownerships, etc. are preserved in the transfer. Additionally, compression will be used to reduce the size of data portions of the transfer.

rsync -avz foo:src/bar/ /data/tmp

A trailing slash on the source changes this behavior to avoid creating an additional directory level at the destination. You can think of a trailing / on a source as meaning "copy the contents of this directory" as opposed to "copy the directory by name", but in both cases the attributes of the containing directory are transferred to the containing directory on the destination. In other words, each of the following commands copies the files in the same way, including their setting of the attributes of /dest/foo:

rsync -av /src/foo /dest
rsync -av /src/foo/ /dest/foo

Note also that host and module references don't require a trailing slash to copy the contents of the default directory. For example, both of these copy the remote directory's contents into "/dest":

rsync -av host: /dest
rsync -av host::module /dest

You can also use rsync in local-only mode, where both the source and destination don't have a ':' in the name. In this case it behaves like an improved copy command.

Finally, you can list all the (listable) modules available from a particular rsync daemon by leaving off the module name:

rsync somehost.mydomain.com::

COPYING TO A DIFFERENT NAME

When you want to copy a directory to a different name, use a trailing slash on the source directory to put the contents of the directory into any destination directory you like:

rsync -ai foo/ bar/

Rsync also has the ability to customize a destination file's name when copying a single item. The rules for this are:

  • The transfer list must consist of a single item (either a file or an empty directory)
  • The final element of the destination path must not exist as a directory
  • The destination path must not have been specified with a trailing slash

Under those circumstances, rsync will set the name of the destination's single item to the last element of the destination path. Keep in mind that it is best to only use this idiom when copying a file and use the above trailing-slash idiom when copying a directory.

The following example copies the foo.c file as bar.c in the save dir (assuming that bar.c isn't a directory):

rsync -ai src/foo.c save/bar.c

The single-item copy rule might accidentally bite you if you unknowingly copy a single item and specify a destination dir that doesn't exist (without using a trailing slash). For example, if src/*.c matches one file and save/dir doesn't exist, this will confuse you by naming the destination file save/dir:

rsync -ai src/*.c save/dir

To prevent such an accident, either make sure the destination dir exists or specify the destination path with a trailing slash:

rsync -ai src/*.c save/dir/

SORTED TRANSFER ORDER

Rsync always sorts the specified filenames into its internal transfer list. This handles the merging together of the contents of identically named directories, makes it easy to remove duplicate filenames. It can, however, confuse someone when the files are transferred in a different order than what was given on the command-line.

If you need a particular file to be transferred prior to another, either separate the files into different rsync calls, or consider using --delay-updates (which doesn't affect the sorted transfer order, but does make the final file-updating phase happen much more rapidly).

MULTI-HOST SECURITY

Rsync takes steps to ensure that the file requests that are shared in a transfer are protected against various security issues. Most of the potential problems arise on the receiving side where rsync takes steps to ensure that the list of files being transferred remains within the bounds of what was requested.

Toward this end, rsync 3.1.2 and later have aborted when a file list contains an absolute or relative path that tries to escape out of the top of the transfer. Also, beginning with version 3.2.5, rsync does two more safety checks of the file list to (1) ensure that no extra source arguments were added into the transfer other than those that the client requested and (2) ensure that the file list obeys the exclude rules that were sent to the sender.

For those that don't yet have a 3.2.5 client rsync (or those that want to be extra careful), it is safest to do a copy into a dedicated destination directory for the remote files when you don't trust the remote host. For example, instead of doing an rsync copy into your home directory:

rsync -aiv host1:dir1 ~

Dedicate a "host1-files" dir to the remote content:

rsync -aiv host1:dir1 ~/host1-files

See the --trust-sender option for additional details.

CAUTION: it is not particularly safe to use rsync to copy files from a case-preserving filesystem to a case-ignoring filesystem. If you must perform such a copy, you should either disable symlinks via --no-links or enable the munging of symlinks via --munge-links (and make sure you use the right local or remote option). This will prevent rsync from doing potentially dangerous things if a symlink name overlaps with a file or directory. It does not, however, ensure that you get a full copy of all the files (since that may not be possible when the names overlap). A potentially better solution is to list all the source files and create a safe list of filenames that you pass to the --files-from option. Any files that conflict in name would need to be copied to different destination directories using more than one copy.

While a copy of a case-ignoring filesystem to a case-ignoring filesystem can work out fairly well, if no --delete-during or --delete-before option is active, rsync can potentially update an existing file on the receiveing side without noticing that the upper-/lower-case of the filename should be changed to match the sender.

ADVANCED USAGE

The syntax for requesting multiple files from a remote host is done by specifying additional remote-host args in the same style as the first, or with the hostname omitted. For instance, all these work:

rsync -aiv host:file1 :file2 host:file{3,4} /dest/
rsync -aiv host::modname/file{1,2} host::modname/extra /dest/
rsync -aiv host::modname/first ::extra-file{1,2} /dest/

Note that a daemon connection only supports accessing one module per copy command, so if the start of a follow-up path doesn't begin with the modname of the first path, it is assumed to be a path in the module (such as the extra-file1 & extra-file2 that are grabbed above).

Really old versions of rsync (2.6.9 and before) only allowed specifying one remote-source arg, so some people have instead relied on the remote-shell performing space splitting to break up an arg into multiple paths. Such unintuitive behavior is no longer supported by default (though you can request it, as described below).

Starting in 3.2.4, filenames are passed to a remote shell in such a way as to preserve the characters you give it. Thus, if you ask for a file with spaces in the name, that's what the remote rsync looks for:

rsync -aiv host:'a simple file.pdf' /dest/

If you use scripts that have been written to manually apply extra quoting to the remote rsync args (or to require remote arg splitting), you can ask rsync to let your script handle the extra escaping. This is done by either adding the --old-args option to the rsync runs in the script (which requires a new rsync) or exporting RSYNC_OLD_ARGS=1 and RSYNC_PROTECT_ARGS=0 (which works with old or new rsync versions).

CONNECTING TO AN RSYNC DAEMON

It is also possible to use rsync without a remote shell as the transport. In this case you will directly connect to a remote rsync daemon, typically using TCP port 873. (This obviously requires the daemon to be running on the remote system, so refer to the STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS section below for information on that.)

Using rsync in this way is the same as using it with a remote shell except that:

  • Use either double-colon syntax or rsync:// URL syntax instead of the single-colon (remote shell) syntax.
  • The first element of the "path" is actually a module name.
  • Additional remote source args can use an abbreviated syntax that omits the hostname and/or the module name, as discussed in ADVANCED USAGE.
  • The remote daemon may print a "message of the day" when you connect.
  • If you specify only the host (with no module or path) then a list of accessible modules on the daemon is output.
  • If you specify a remote source path but no destination, a listing of the matching files on the remote daemon is output.
  • The --rsh (-e) option must be omitted to avoid changing the connection style from using a socket connection to USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION.

An example that copies all the files in a remote module named "src":

rsync -av host::src /dest

Some modules on the remote daemon may require authentication. If so, you will receive a password prompt when you connect. You can avoid the password prompt by setting the environment variable RSYNC_PASSWORD to the password you want to use or using the --password-file option. This may be useful when scripting rsync.

WARNING: On some systems environment variables are visible to all users. On those systems using --password-file is recommended.

You may establish the connection via a web proxy by setting the environment variable RSYNC_PROXY to a hostname:port pair pointing to your web proxy. Note that your web proxy's configuration must support proxy connections to port 873.

You may also establish a daemon connection using a program as a proxy by setting the environment variable RSYNC_CONNECT_PROG to the commands you wish to run in place of making a direct socket connection. The string may contain the escape "%H" to represent the hostname specified in the rsync command (so use "%%" if you need a single "%" in your string). For example:

export RSYNC_CONNECT_PROG='ssh proxyhost nc %H 873'
rsync -av targethost1::module/src/ /dest/
rsync -av rsync://targethost2/module/src/ /dest/

The command specified above uses ssh to run nc (netcat) on a proxyhost, which forwards all data to port 873 (the rsync daemon) on the targethost (%H).

Note also that if the RSYNC_SHELL environment variable is set, that program will be used to run the RSYNC_CONNECT_PROG command instead of using the default shell of the system() call.

USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION

It is sometimes useful to use various features of an rsync daemon (such as named modules) without actually allowing any new socket connections into a system (other than what is already required to allow remote-shell access). Rsync supports connecting to a host using a remote shell and then spawning a single-use "daemon" server that expects to read its config file in the home dir of the remote user. This can be useful if you want to encrypt a daemon-style transfer's data, but since the daemon is started up fresh by the remote user, you may not be able to use features such as chroot or change the uid used by the daemon. (For another way to encrypt a daemon transfer, consider using ssh to tunnel a local port to a remote machine and configure a normal rsync daemon on that remote host to only allow connections from "localhost".)

From the user's perspective, a daemon transfer via a remote-shell connection uses nearly the same command-line syntax as a normal rsync-daemon transfer, with the only exception being that you must explicitly set the remote shell program on the command-line with the --rsh=COMMAND option. (Setting the RSYNC_RSH in the environment will not turn on this functionality.) For example:

rsync -av --rsh=ssh host::module /dest

If you need to specify a different remote-shell user, keep in mind that the user@ prefix in front of the host is specifying the rsync-user value (for a module that requires user-based authentication). This means that you must give the '-⁠l user' option to ssh when specifying the remote-shell, as in this example that uses the short version of the --rsh option:

rsync -av -e "ssh -l ssh-user" rsync-user@host::module /dest

The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to log-in to the "module".

In this setup, the daemon is started by the ssh command that is accessing the system (which can be forced via the ~/.ssh/authorized_keys file, if desired). However, when accessing a daemon directly, it needs to be started beforehand.

STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS

In order to connect to an rsync daemon, the remote system needs to have a daemon already running (or it needs to have configured something like inetd to spawn an rsync daemon for incoming connections on a particular port). For full information on how to start a daemon that will handling incoming socket connections, see the rsyncd.conf(5) manpage -⁠-⁠ that is the config file for the daemon, and it contains the full details for how to run the daemon (including stand-alone and inetd configurations).

If you're using one of the remote-shell transports for the transfer, there is no need to manually start an rsync daemon.

EXAMPLES

Here are some examples of how rsync can be used.

To backup a home directory, which consists of large MS Word files and mail folders, a per-user cron job can be used that runs this each day:

rsync -aiz . bkhost:backup/joe/

To move some files from a remote host to the local host, you could run:

rsync -aiv --remove-source-files rhost:/tmp/{file1,file2}.c ~/src/

OPTION SUMMARY

Here is a short summary of the options available in rsync. Each option also has its own detailed description later in this manpage.

--verbose, -v            increase verbosity
--info=FLAGS             fine-grained informational verbosity
--debug=FLAGS            fine-grained debug verbosity
--stderr=e|a|c           change stderr output mode (default: errors)
--quiet, -q              suppress non-error messages
--no-motd                suppress daemon-mode MOTD
--checksum, -c           skip based on checksum, not mod-time & size
--archive, -a            archive mode is -rlptgoD (no -A,-X,-U,-N,-H)
--no-OPTION              turn off an implied OPTION (e.g. --no-D)
--recursive, -r          recurse into directories
--relative, -R           use relative path names
--no-implied-dirs        don't send implied dirs with --relative
--backup, -b             make backups (see --suffix & --backup-dir)
--backup-dir=DIR         make backups into hierarchy based in DIR
--suffix=SUFFIX          backup suffix (default ~ w/o --backup-dir)
--update, -u             skip files that are newer on the receiver
--inplace                update destination files in-place
--append                 append data onto shorter files
--append-verify          --append w/old data in file checksum
--dirs, -d               transfer directories without recursing
--old-dirs, --old-d      works like --dirs when talking to old rsync
--mkpath                 create destination's missing path components
--links, -l              copy symlinks as symlinks
--copy-links, -L         transform symlink into referent file/dir
--copy-unsafe-links      only "unsafe" symlinks are transformed
--safe-links             ignore symlinks that point outside the tree
--munge-links            munge symlinks to make them safe & unusable
--copy-dirlinks, -k      transform symlink to dir into referent dir
--keep-dirlinks, -K      treat symlinked dir on receiver as dir
--hard-links, -H         preserve hard links
--perms, -p              preserve permissions
--executability, -E      preserve executability
--chmod=CHMOD            affect file and/or directory permissions
--acls, -A               preserve ACLs (implies --perms)
--xattrs, -X             preserve extended attributes
--owner, -o              preserve owner (super-user only)
--group, -g              preserve group
--devices                preserve device files (super-user only)
--copy-devices           copy device contents as a regular file
--write-devices          write to devices as files (implies --inplace)
--specials               preserve special files
-D                       same as --devices --specials
--times, -t              preserve modification times
--atimes, -U             preserve access (use) times
--open-noatime           avoid changing the atime on opened files
--crtimes, -N            preserve create times (newness)
--omit-dir-times, -O     omit directories from --times
--omit-link-times, -J    omit symlinks from --times
--super                  receiver attempts super-user activities
--fake-super             store/recover privileged attrs using xattrs
--sparse, -S             turn sequences of nulls into sparse blocks
--preallocate            allocate dest files before writing them
--dry-run, -n            perform a trial run with no changes made
--whole-file, -W         copy files whole (w/o delta-xfer algorithm)
--checksum-choice=STR    choose the checksum algorithm (aka --cc)
--one-file-system, -x    don't cross filesystem boundaries
--block-size=SIZE, -B    force a fixed checksum block-size
--rsh=COMMAND, -e        specify the remote shell to use
--rsync-path=PROGRAM     specify the rsync to run on remote machine
--existing               skip creating new files on receiver
--ignore-existing        skip updating files that exist on receiver
--remove-source-files    sender removes synchronized files (non-dir)
--del                    an alias for --delete-during
--delete                 delete extraneous files from dest dirs
--delete-before          receiver deletes before xfer, not during
--delete-during          receiver deletes during the transfer
--delete-delay           find deletions during, delete after
--delete-after           receiver deletes after transfer, not during
--delete-excluded        also delete excluded files from dest dirs
--ignore-missing-args    ignore missing source args without error
--delete-missing-args    delete missing source args from destination
--ignore-errors          delete even if there are I/O errors
--force                  force deletion of dirs even if not empty
--max-delete=NUM         don't delete more than NUM files
--max-size=SIZE          don't transfer any file larger than SIZE
--min-size=SIZE          don't transfer any file smaller than SIZE
--max-alloc=SIZE         change a limit relating to memory alloc
--partial                keep partially transferred files
--partial-dir=DIR        put a partially transferred file into DIR
--delay-updates          put all updated files into place at end
--prune-empty-dirs, -m   prune empty directory chains from file-list
--numeric-ids            don't map uid/gid values by user/group name
--usermap=STRING         custom username mapping
--groupmap=STRING        custom groupname mapping
--chown=USER:GROUP       simple username/groupname mapping
--timeout=SECONDS        set I/O timeout in seconds
--contimeout=SECONDS     set daemon connection timeout in seconds
--ignore-times, -I       don't skip files that match size and time
--size-only              skip files that match in size
--modify-window=NUM, -@  set the accuracy for mod-time comparisons
--temp-dir=DIR, -T       create temporary files in directory DIR
--fuzzy, -y              find similar file for basis if no dest file
--compare-dest=DIR       also compare destination files relative to DIR
--copy-dest=DIR          ... and include copies of unchanged files
--link-dest=DIR          hardlink to files in DIR when unchanged
--compress, -z           compress file data during the transfer
--compress-choice=STR    choose the compression algorithm (aka --zc)
--compress-level=NUM     explicitly set compression level (aka --zl)
--skip-compress=LIST     skip compressing files with suffix in LIST
--cvs-exclude, -C        auto-ignore files in the same way CVS does
--filter=RULE, -f        add a file-filtering RULE
-F                       same as --filter='dir-merge /.rsync-filter'
                         repeated: --filter='- .rsync-filter'
--exclude=PATTERN        exclude files matching PATTERN
--exclude-from=FILE      read exclude patterns from FILE
--include=PATTERN        don't exclude files matching PATTERN
--include-from=FILE      read include patterns from FILE
--files-from=FILE        read list of source-file names from FILE
--from0, -0              all *-from/filter files are delimited by 0s
--old-args               disable the modern arg-protection idiom
--secluded-args, -s      use the protocol to safely send the args
--trust-sender           trust the remote sender's file list
--copy-as=USER[:GROUP]   specify user & optional group for the copy
--address=ADDRESS        bind address for outgoing socket to daemon
--port=PORT              specify double-colon alternate port number
--sockopts=OPTIONS       specify custom TCP options
--blocking-io            use blocking I/O for the remote shell
--outbuf=N|L|B           set out buffering to None, Line, or Block
--stats                  give some file-transfer stats
--8-bit-output, -8       leave high-bit chars unescaped in output
--human-readable, -h     output numbers in a human-readable format
--progress               show progress during transfer
-P                       same as --partial --progress
--itemize-changes, -i    output a change-summary for all updates
--remote-option=OPT, -M  send OPTION to the remote side only
--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
--password-file=FILE     read daemon-access password from FILE
--early-input=FILE       use FILE for daemon's early exec input
--list-only              list the files instead of copying them
--bwlimit=RATE           limit socket I/O bandwidth
--stop-after=MINS        Stop rsync after MINS minutes have elapsed
--stop-at=y-m-dTh:m      Stop rsync at the specified point in time
--fsync                  fsync every written file
--write-batch=FILE       write a batched update to FILE
--only-write-batch=FILE  like --write-batch but w/o updating dest
--read-batch=FILE        read a batched update from FILE
--protocol=NUM           force an older protocol version to be used
--iconv=CONVERT_SPEC     request charset conversion of filenames
--checksum-seed=NUM      set block/file checksum seed (advanced)
--ipv4, -4               prefer IPv4
--ipv6, -6               prefer IPv6
--version, -V            print the version + other info and exit
--help, -h (*)           show this help (* -h is help only on its own)

Rsync can also be run as a daemon, in which case the following options are accepted:

--daemon                 run as an rsync daemon
--address=ADDRESS        bind to the specified address
--bwlimit=RATE           limit socket I/O bandwidth
--config=FILE            specify alternate rsyncd.conf file
--dparam=OVERRIDE, -M    override global daemon config parameter
--no-detach              do not detach from the parent
--port=PORT              listen on alternate port number
--log-file=FILE          override the "log file" setting
--log-file-format=FMT    override the "log format" setting
--sockopts=OPTIONS       specify custom TCP options
--verbose, -v            increase verbosity
--ipv4, -4               prefer IPv4
--ipv6, -6               prefer IPv6
--help, -h               show this help (when used with --daemon)

OPTIONS

Rsync accepts both long (double-dash + word) and short (single-dash + letter) options. The full list of the available options are described below. If an option can be specified in more than one way, the choices are comma-separated. Some options only have a long variant, not a short.

If the option takes a parameter, the parameter is only listed after the long variant, even though it must also be specified for the short. When specifying a parameter, you can either use the form --option=param, --option param, -o=param, -o param, or -oparam (the latter choices assume that your option has a short variant).

The parameter may need to be quoted in some manner for it to survive the shell's command-line parsing. Also keep in mind that a leading tilde (~) in a pathname is substituted by your shell, so make sure that you separate the option name from the pathname using a space if you want the local shell to expand it.

--help

Print a short help page describing the options available in rsync and exit. You can also use -h for --help when it is used without any other options (since it normally means --human-readable).

--version, -V

Print the rsync version plus other info and exit. When repeated, the information is output is a JSON format that is still fairly readable (client side only).

The output includes a list of compiled-in capabilities, a list of optimizations, the default list of checksum algorithms, the default list of compression algorithms, the default list of daemon auth digests, a link to the rsync web site, and a few other items.

--verbose, -v

This option increases the amount of information you are given during the transfer. By default, rsync works silently. A single -v will give you information about what files are being transferred and a brief summary at the end. Two -v options will give you information on what files are being skipped and slightly more information at the end. More than two -v options should only be used if you are debugging rsync.

The end-of-run summary tells you the number of bytes sent to the remote rsync (which is the receiving side on a local copy), the number of bytes received from the remote host, and the average bytes per second of the transferred data computed over the entire length of the rsync run. The second line shows the total size (in bytes), which is the sum of all the file sizes that rsync considered transferring. It also shows a "speedup" value, which is a ratio of the total file size divided by the sum of the sent and received bytes (which is really just a feel-good bigger-is-better number). Note that these byte values can be made more (or less) human-readable by using the --human-readable (or --no-human-readable) options.

In a modern rsync, the -v option is equivalent to the setting of groups of --info and --debug options. You can choose to use these newer options in addition to, or in place of using --verbose, as any fine-grained settings override the implied settings of -v. Both --info and --debug have a way to ask for help that tells you exactly what flags are set for each increase in verbosity.

However, do keep in mind that a daemon's "max verbosity" setting will limit how high of a level the various individual flags can be set on the daemon side. For instance, if the max is 2, then any info and/or debug flag that is set to a higher value than what would be set by -vv will be downgraded to the -vv level in the daemon's logging.

--info=FLAGS

This option lets you have fine-grained control over the information output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use --info=help to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples:

rsync -a --info=progress2 src/ dest/
rsync -avv --info=stats2,misc1,flist0 src/ dest/

Note that --info=name's output is affected by the --out-format and --itemize-changes (-i) options. See those options for more information on what is output and when.

This option was added to 3.1.0, so an older rsync on the server side might reject your attempts at fine-grained control (if one or more flags needed to be send to the server and the server was too old to understand them). See also the "max verbosity" caveat above when dealing with a daemon.

--debug=FLAGS

This option lets you have fine-grained control over the debug output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use --debug=help to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples:

rsync -avvv --debug=none src/ dest/
rsync -avA --del --debug=del2,acl src/ dest/

Note that some debug messages will only be output when the --stderr=all option is specified, especially those pertaining to I/O and buffer debugging.

Beginning in 3.2.0, this option is no longer auto-forwarded to the server side in order to allow you to specify different debug values for each side of the transfer, as well as to specify a new debug option that is only present in one of the rsync versions. If you want to duplicate the same option on both sides, using brace expansion is an easy way to save you some typing. This works in zsh and bash:

rsync -aiv {-M,}--debug=del2 src/ dest/
--stderr=errors|all|client

This option controls which processes output to stderr and if info messages are also changed to stderr. The mode strings can be abbreviated, so feel free to use a single letter value. The 3 possible choices are:

  • errors -⁠ (the default) causes all the rsync processes to send an error directly to stderr, even if the process is on the remote side of the transfer. Info messages are sent to the client side via the protocol stream. If stderr is not available (i.e. when directly connecting with a daemon via a socket) errors fall back to being sent via the protocol stream.

  • all -⁠ causes all rsync messages (info and error) to get written directly to stderr from all (possible) processes. This causes stderr to become line-buffered (instead of raw) and eliminates the ability to divide up the info and error messages by file handle. For those doing debugging or using several levels of verbosity, this option can help to avoid clogging up the transfer stream (which should prevent any chance of a deadlock bug hanging things up). It also allows --debug to enable some extra I/O related messages.

  • client -⁠ causes all rsync messages to be sent to the client side via the protocol stream. One client process outputs all messages, with errors on stderr and info messages on stdout. This was the default in older rsync versions, but can cause error delays when a lot of transfer data is ahead of the messages. If you're pushing files to an older rsync, you may want to use --stderr=all since that idiom has been around for several releases.

This option was added in rsync 3.2.3. This version also began the forwarding of a non-default setting to the remote side, though rsync uses the backward-compatible options --msgs2stderr and --no-msgs2stderr to represent the all and client settings, respectively. A newer rsync will continue to accept these older option names to maintain compatibility.

--quiet, -q

This option decreases the amount of information you are given during the transfer, notably suppressing information messages from the remote server. This option is useful when invoking rsync from cron.

--no-motd

This option affects the information that is output by the client at the start of a daemon transfer. This suppresses the message-of-the-day (MOTD) text, but it also affects the list of modules that the daemon sends in response to the "rsync host::" request (due to a limitation in the rsync protocol), so omit this option if you want to request the list of modules from the daemon.

--ignore-times, -I

Normally rsync will skip any files that are already the same size and have the same modification timestamp. This option turns off this "quick check" behavior, causing all files to be updated.

This option can be confusing compared to --ignore-existing and --ignore-non-existing in that that they cause rsync to transfer fewer files, while this option causes rsync to transfer more files.

--size-only

This modifies rsync's "quick check" algorithm for finding files that need to be transferred, changing it from the default of transferring files with either a changed size or a changed last-modified time to just looking for files that have changed in size. This is useful when starting to use rsync after using another mirroring system which may not preserve timestamps exactly.

--modify-window=NUM, -@

When comparing two timestamps, rsync treats the timestamps as being equal if they differ by no more than the modify-window value. The default is 0, which matches just integer seconds. If you specify a negative value (and the receiver is at least version 3.1.3) then nanoseconds will also be taken into account. Specifying 1 is useful for copies to/from MS Windows FAT filesystems, because FAT represents times with a 2-second resolution (allowing times to differ from the original by up to 1 second).

If you want all your transfers to default to comparing nanoseconds, you can create a ~/.popt file and put these lines in it:

rsync alias -a -a@-1
rsync alias -t -t@-1

With that as the default, you'd need to specify --modify-window=0 (aka -@0) to override it and ignore nanoseconds, e.g. if you're copying between ext3 and ext4, or if the receiving rsync is older than 3.1.3.

--checksum, -c

This changes the way rsync checks if the files have been changed and are in need of a transfer. Without this option, rsync uses a "quick check" that (by default) checks if each file's size and time of last modification match between the sender and receiver. This option changes this to compare a 128-bit checksum for each file that has a matching size. Generating the checksums means that both sides will expend a lot of disk I/O reading all the data in the files in the transfer, so this can slow things down significantly (and this is prior to any reading that will be done to transfer changed files)

The sending side generates its checksums while it is doing the file-system scan that builds the list of the available files. The receiver generates its checksums when it is scanning for changed files, and will checksum any file that has the same size as the corresponding sender's file: files with either a changed size or a changed checksum are selected for transfer.

Note that rsync always verifies that each transferred file was correctly reconstructed on the receiving side by checking a whole-file checksum that is generated as the file is transferred, but that automatic after-the-transfer verification has nothing to do with this option's before-the-transfer "Does this file need to be updated?" check.

The checksum used is auto-negotiated between the client and the server, but can be overridden using either the --checksum-choice (--cc) option or an environment variable that is discussed in that option's section.

--archive, -a

This is equivalent to -rlptgoD. It is a quick way of saying you want recursion and want to preserve almost everything. Be aware that it does not include preserving ACLs (-A), xattrs (-X), atimes (-U), crtimes (-N), nor the finding and preserving of hardlinks (-H).

The only exception to the above equivalence is when --files-from is specified, in which case -r is not implied.

--no-OPTION

You may turn off one or more implied options by prefixing the option name with "no-". Not all positive options have a negated opposite, but a lot do, including those that can be used to disable an implied option (e.g. --no-D, --no-perms) or have different defaults in various circumstances (e.g. --no-whole-file, --no-blocking-io, --no-dirs). Every valid negated option accepts both the short and the long option name after the "no-" prefix (e.g. --no-R is the same as --no-relative).

As an example, if you want to use --archive (-a) but don't want --owner (-o), instead of converting -a into -rlptgD, you can specify -a --no-o (aka --archive --no-owner).

The order of the options is important: if you specify --no-r -a, the -r option would end up being turned on, the opposite of -a --no-r. Note also that the side-effects of the --files-from option are NOT positional, as it affects the default state of several options and slightly changes the meaning of -a (see the --files-from option for more details).

--recursive, -r

This tells rsync to copy directories recursively. See also --dirs (-d) for an option that allows the scanning of a single directory.

See the --inc-recursive option for a discussion of the incremental recursion for creating the list of files to transfer.

--inc-recursive, --i-r

This option explicitly enables on incremental recursion when scanning for files, which is enabled by default when using the --recursive option and both sides of the transfer are running rsync 3.0.0 or newer.

Incremental recursion uses much less memory than non-incremental, while also beginning the transfer more quickly (since it doesn't need to scan the entire transfer hierarchy before it starts transferring files). If no recursion is enabled in the source files, this option has no effect.

Some options require rsync to know the full file list, so these options disable the incremental recursion mode. These include:

In order to make --delete compatible with incremental recursion, rsync 3.0.0 made --delete-during the default delete mode (which was first added in 2.6.4).

One side-effect of incremental recursion is that any missing sub-directories inside a recursively-scanned directory are (by default) created prior to recursing into the sub-dirs. This earlier creation point (compared to a non-incremental recursion) allows rsync to then set the modify time of the finished directory right away (without having to delay that until a bunch of recursive copying has finished). However, these early directories don't yet have their completed mode, mtime, or ownership set -⁠-⁠ they have more restrictive rights until the subdirectory's copying actually begins. This early-creation idiom can be avoided by using the --omit-dir-times option.

Incremental recursion can be disabled using the --no-inc-recursive (--no-i-r) option.

--no-inc-recursive, --no-i-r

Disables the new incremental recursion algorithm of the --recursive option. This makes rsync scan the full file list before it begins to transfer files. See --inc-recursive for more info.

--relative, -R

Use relative paths. This means that the full path names specified on the command line are sent to the server rather than just the last parts of the filenames. This is particularly useful when you want to send several different directories at the same time. For example, if you used this command:

rsync -av /foo/bar/baz.c remote:/tmp/

would create a file named baz.c in /tmp/ on the remote machine. If instead you used

rsync -avR /foo/bar/baz.c remote:/tmp/

then a file named /tmp/foo/bar/baz.c would be created on the remote machine, preserving its full path. These extra path elements are called "implied directories" (i.e. the "foo" and the "foo/bar" directories in the above example).

Beginning with rsync 3.0.0, rsync always sends these implied directories as real directories in the file list, even if a path element is really a symlink on the sending side. This prevents some really unexpected behaviors when copying the full path of a file that you didn't realize had a symlink in its path. If you want to duplicate a server-side symlink, include both the symlink via its path, and referent directory via its real path. If you're dealing with an older rsync on the sending side, you may need to use the --no-implied-dirs option.

It is also possible to limit the amount of path information that is sent as implied directories for each path you specify. With a modern rsync on the sending side (beginning with 2.6.7), you can insert a dot and a slash into the source path, like this:

rsync -avR /foo/./bar/baz.c remote:/tmp/

That would create /tmp/bar/baz.c on the remote machine. (Note that the dot must be followed by a slash, so "/foo/." would not be abbreviated.) For older rsync versions, you would need to use a chdir to limit the source path. For example, when pushing files:

(cd /foo; rsync -avR bar/baz.c remote:/tmp/)

(Note that the parens put the two commands into a sub-shell, so that the "cd" command doesn't remain in effect for future commands.) If you're pulling files from an older rsync, use this idiom (but only for a non-daemon transfer):

rsync -avR --rsync-path="cd /foo; rsync" \
     remote:bar/baz.c /tmp/
--no-implied-dirs

This option affects the default behavior of the --relative option. When it is specified, the attributes of the implied directories from the source names are not included in the transfer. This means that the corresponding path elements on the destination system are left unchanged if they exist, and any missing implied directories are created with default attributes. This even allows these implied path elements to have big differences, such as being a symlink to a directory on the receiving side.

For instance, if a command-line arg or a files-from entry told rsync to transfer the file "path/foo/file", the directories "path" and "path/foo" are implied when --relative is used. If "path/foo" is a symlink to "bar" on the destination system, the receiving rsync would ordinarily delete "path/foo", recreate it as a directory, and receive the file into the new directory. With --no-implied-dirs, the receiving rsync updates "path/foo/file" using the existing path elements, which means that the file ends up being created in "path/bar". Another way to accomplish this link preservation is to use the --keep-dirlinks option (which will also affect symlinks to directories in the rest of the transfer).

When pulling files from an rsync older than 3.0.0, you may need to use this option if the sending side has a symlink in the path you request and you wish the implied directories to be transferred as normal directories.

--backup, -b

With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the --backup-dir and --suffix options.

If you don't specify --backup-dir:

  1. the --omit-dir-times option will be forced on
  2. the use of --delete (without --delete-excluded), causes rsync to add a "protect" filter-rule for the backup suffix to the end of all your existing filters that looks like this: -f "P *~". This rule prevents previously backed-up files from being deleted.

Note that if you are supplying your own filter rules, you may need to manually insert your own exclude/protect rule somewhere higher up in the list so that it has a high enough priority to be effective (e.g. if your rules specify a trailing inclusion/exclusion of *, the auto-added rule would never be reached).

--backup-dir=DIR

This implies the --backup option, and tells rsync to store all backups in the specified directory on the receiving side. This can be used for incremental backups. You can additionally specify a backup suffix using the --suffix option (otherwise the files backed up in the specified directory will keep their original filenames).

Note that if you specify a relative path, the backup directory will be relative to the destination directory, so you probably want to specify either an absolute path or a path that starts with "../". If an rsync daemon is the receiver, the backup dir cannot go outside the module's path hierarchy, so take extra care not to delete it or copy into it.

--suffix=SUFFIX

This option allows you to override the default backup suffix used with the --backup (-b) option. The default suffix is a ~ if no --backup-dir was specified, otherwise it is an empty string.

--update, -u

This forces rsync to skip any files which exist on the destination and have a modified time that is newer than the source file. (If an existing destination file has a modification time equal to the source file's, it will be updated if the sizes are different.)

Note that this does not affect the copying of dirs, symlinks, or other special files. Also, a difference of file format between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects. In other words, if the source has a directory where the destination has a file, the transfer would occur regardless of the timestamps.

This option is a TRANSFER RULE, so don't expect any exclude side effects.

A caution for those that choose to combine --inplace with --update: an interrupted transfer will leave behind a partial file on the receiving side that has a very recent modified time, so re-running the transfer will probably not continue the interrupted file. As such, it is usually best to avoid combining this with --inplace unless you have implemented manual steps to handle any interrupted in-progress files.

--inplace

This option changes how rsync transfers a file when its data needs to be updated: instead of the default method of creating a new copy of the file and moving it into place when it is complete, rsync instead writes the updated data directly to the destination file.

This has several effects:

  • Hard links are not broken. This means the new data will be visible through other hard links to the destination file. Moreover, attempts to copy differing source files onto a multiply-linked destination file will result in a "tug of war" with the destination data changing back and forth.
  • In-use binaries cannot be updated (either the OS will prevent this from happening, or binaries that attempt to swap-in their data will misbehave or crash).
  • The file's data will be in an inconsistent state during the transfer and will be left that way if the transfer is interrupted or if an update fails.
  • A file that rsync cannot write to cannot be updated. While a super user can update any file, a normal user needs to be granted write permission for the open of the file for writing to be successful.
  • The efficiency of rsync's delta-transfer algorithm may be reduced if some data in the destination file is overwritten before it can be copied to a position later in the file. This does not apply if you use --backup, since rsync is smart enough to use the backup file as the basis file for the transfer.

WARNING: you should not use this option to update files that are being accessed by others, so be careful when choosing to use this for a copy.

This option is useful for transferring large files with block-based changes or appended data, and also on systems that are disk bound, not network bound. It can also help keep a copy-on-write filesystem snapshot from diverging the entire contents of a file that only has minor changes.

The option implies --partial (since an interrupted transfer does not delete the file), but conflicts with --partial-dir and --delay-updates. Prior to rsync 2.6.4 --inplace was also incompatible with --compare-dest and --link-dest.

--append

This special copy mode only works to efficiently update files that are known to be growing larger where any existing content on the receiving side is also known to be the same as the content on the sender. The use of --append can be dangerous if you aren't 100% sure that all the files in the transfer are shared, growing files. You should thus use filter rules to ensure that you weed out any files that do not fit this criteria.

Rsync updates these growing file in-place without verifying any of the existing content in the file (it only verifies the content that it is appending). Rsync skips any files that exist on the receiving side that are not shorter than the associated file on the sending side (which means that new files are transferred). It also skips any files whose size on the sending side gets shorter during the send negotiations (rsync warns about a "diminished" file when this happens).

This does not interfere with the updating of a file's non-content attributes (e.g. permissions, ownership, etc.) when the file does not need to be transferred, nor does it affect the updating of any directories or non-regular files.

--append-verify

This special copy mode works like --append except that all the data in the file is included in the checksum verification (making it less efficient but also potentially safer). This option can be dangerous if you aren't 100% sure that all the files in the transfer are shared, growing files. See the --append option for more details.

Note: prior to rsync 3.0.0, the --append option worked like --append-verify, so if you are interacting with an older rsync (or the transfer is using a protocol prior to 30), specifying either append option will initiate an --append-verify transfer.

--dirs, -d

Tell the sending side to include any directories that are encountered. Unlike --recursive, a directory's contents are not copied unless the directory name specified is "." or ends with a trailing slash (e.g. ".", "dir/.", "dir/", etc.). Without this option or the --recursive option, rsync will skip all directories it encounters (and output a message to that effect for each one). If you specify both --dirs and --recursive, --recursive takes precedence.

The --dirs option is implied by the --files-from option or the --list-only option (including an implied --list-only usage) if --recursive wasn't specified (so that directories are seen in the listing). Specify --no-dirs (or --no-d) if you want to turn this off.

There is also a backward-compatibility helper option, --old-dirs (--old-d) that tells rsync to use a hack of -r --exclude='/*/*' to get an older rsync to list a single directory without recursing.

--mkpath

Create all missing path components of the destination path.

By default, rsync allows only the final component of the destination path to not exist, which is an attempt to help you to validate your destination path. With this option, rsync creates all the missing destination-path components, just as if mkdir -p $DEST_PATH had been run on the receiving side.

When specifying a destination path, including a trailing slash ensures that the whole path is treated as directory names to be created, even when the file list has a single item. See the COPYING TO A DIFFERENT NAME section for full details on how rsync decides if a final destination-path component should be created as a directory or not.

If you would like the newly-created destination dirs to match the dirs on the sending side, you should be using --relative (-R) instead of --mkpath. For instance, the following two commands result in the same destination tree, but only the second command ensures that the "some/extra/path" components match the dirs on the sending side:

rsync -ai --mkpath host:some/extra/path/*.c some/extra/path/
rsync -aiR host:some/extra/path/*.c ./

Add symlinks to the transferred files instead of noisily ignoring them with a "non-regular file" warning for each symlink encountered. You can alternately silence the warning by specifying --info=nonreg0.

The default handling of symlinks is to recreate each symlink's unchanged value on the receiving side.

See the SYMBOLIC LINKS section for multi-option info.

The sender transforms each symlink encountered in the transfer into the referent item, following the symlink chain to the file or directory that it references. If a symlink chain is broken, an error is output and the file is dropped from the transfer.

This option supersedes any other options that affect symlinks in the transfer, since there are no symlinks left in the transfer.

This option does not change the handling of existing symlinks on the receiving side, unlike versions of rsync prior to 2.6.3 which had the side-effect of telling the receiving side to also follow symlinks. A modern rsync won't forward this option to a remote receiver (since only the sender needs to know about it), so this caveat should only affect someone using an rsync client older than 2.6.7 (which is when -L stopped being forwarded to the receiver).

See the --keep-dirlinks (-K) if you need a symlink to a directory to be treated as a real directory on the receiving side.

See the SYMBOLIC LINKS section for multi-option info.

This tells rsync to copy the referent of symbolic links that point outside the copied tree. Absolute symlinks are also treated like ordinary files, and so are any symlinks in the source path itself when --relative is used.

Note that the cut-off point is the top of the transfer, which is the part of the path that rsync isn't mentioning in the verbose output. If you copy "/src/subdir" to "/dest/" then the "subdir" directory is a name inside the transfer tree, not the top of the transfer (which is /src) so it is legal for created relative symlinks to refer to other names inside the /src and /dest directories. If you instead copy "/src/subdir/" (with a trailing slash) to "/dest/subdir" that would not allow symlinks to any files outside of "subdir".

Note that safe symlinks are only copied if --links was also specified or implied. The --copy-unsafe-links option has no extra effect when combined with --copy-links.

See the SYMBOLIC LINKS section for multi-option info.

This tells the receiving rsync to ignore any symbolic links in the transfer which point outside the copied tree. All absolute symlinks are also ignored.

Since this ignoring is happening on the receiving side, it will still be effective even when the sending side has munged symlinks (when it is using --munge-links). It also affects deletions, since the file being present in the transfer prevents any matching file on the receiver from being deleted when the symlink is deemed to be unsafe and is skipped.

This option must be combined with --links (or --archive) to have any symlinks in the transfer to conditionally ignore. Its effect is superseded by --copy-unsafe-links.

Using this option in conjunction with --relative may give unexpected results.

See the SYMBOLIC LINKS section for multi-option info.

This option affects just one side of the transfer and tells rsync to munge symlink values when it is receiving files or unmunge symlink values when it is sending files. The munged values make the symlinks unusable on disk but allows the original contents of the symlinks to be recovered.

The server-side rsync often enables this option without the client's knowledge, such as in an rsync daemon's configuration file or by an option given to the rrsync (restricted rsync) script. When specified on the client side, specify the option normally if it is the client side that has/needs the munged symlinks, or use -M--munge-links to give the option to the server when it has/needs the munged symlinks. Note that on a local transfer, the client is the sender, so specifying the option directly unmunges symlinks while specifying it as a remote option munges symlinks.

This option has no effect when sent to a daemon via --remote-option because the daemon configures whether it wants munged symlinks via its "munge symlinks" parameter.

The symlink value is munged/unmunged once it is in the transfer, so any option that transforms symlinks into non-symlinks occurs prior to the munging/unmunging except for --safe-links, which is a choice that the receiver makes, so it bases its decision on the munged/unmunged value. This does mean that if a receiver has munging enabled, that using --safe-links will cause all symlinks to be ignored (since they are all absolute).

The method that rsync uses to munge the symlinks is to prefix each one's value with the string "/rsyncd-munged/". This prevents the links from being used as long as the directory does not exist. When this option is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory (though it only checks at startup). See also the "munge-symlinks" python script in the support directory of the source code for a way to munge/unmunge one or more symlinks in-place.

This option causes the sending side to treat a symlink to a directory as though it were a real directory. This is useful if you don't want symlinks to non-directories to be affected, as they would be using --copy-links.

Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as --force or --delete is in effect).

See also --keep-dirlinks for an analogous option for the receiving side.

--copy-dirlinks applies to all symlinks to directories in the source. If you want to follow only a few specified symlinks, a trick you can use is to pass them as additional source args with a trailing slash, using --relative to make the paths match up right. For example:

rsync -r --relative src/./ src/./follow-me/ dest/

This works because rsync calls lstat(2) on the source arg as given, and the trailing slash makes lstat(2) follow the symlink, giving rise to a directory in the file-list which overrides the symlink found during the scan of "src/./".

See the SYMBOLIC LINKS section for multi-option info.

This option causes the receiving side to treat a symlink to a directory as though it were a real directory, but only if it matches a real directory from the sender. Without this option, the receiver's symlink would be deleted and replaced with a real directory.

For example, suppose you transfer a directory "foo" that contains a file "file", but "foo" is a symlink to directory "bar" on the receiver. Without --keep-dirlinks, the receiver deletes symlink "foo", recreates it as a directory, and receives the file into the new directory. With --keep-dirlinks, the receiver keeps the symlink and "file" ends up in "bar".

One note of caution: if you use --keep-dirlinks, you must trust all the symlinks in the copy or enable the --munge-links option on the receiving side! If it is possible for an untrusted user to create their own symlink to any real directory, the user could then (on a subsequent copy) replace the symlink with a real directory and affect the content of whatever directory the symlink references. For backup copies, you are better off using something like a bind mount instead of a symlink to modify your receiving hierarchy.

See also --copy-dirlinks for an analogous option for the sending side.

See the SYMBOLIC LINKS section for multi-option info.

This tells rsync to look for hard-linked files in the source and link together the corresponding files on the destination. Without this option, hard-linked files in the source are treated as though they were separate files.

This option does NOT necessarily ensure that the pattern of hard links on the destination exactly matches that on the source. Cases in which the destination may end up with extra hard links include the following:

  • If the destination contains extraneous hard-links (more linking than what is present in the source file list), the copying algorithm will not break them explicitly. However, if one or more of the paths have content differences, the normal file-update process will break those extra links (unless you are using the --inplace option).
  • If you specify a --link-dest directory that contains hard links, the linking of the destination files against the --link-dest files can cause some paths in the destination to become linked together due to the --link-dest associations.

Note that rsync can only detect hard links between files that are inside the transfer set. If rsync updates a file that has extra hard-link connections to files outside the transfer, that linkage will be broken. If you are tempted to use the --inplace option to avoid this breakage, be very careful that you know how your files are being updated so that you are certain that no unintended changes happen due to lingering hard links (and see the --inplace option for more caveats).

If incremental recursion is active (see --inc-recursive), rsync may transfer a missing hard-linked file before it finds that another link for that contents exists elsewhere in the hierarchy. This does not affect the accuracy of the transfer (i.e. which files are hard-linked together), just its efficiency (i.e. copying the data for a new, early copy of a hard-linked file that could have been found later in the transfer in another member of the hard-linked set of files). One way to avoid this inefficiency is to disable incremental recursion using the --no-inc-recursive option.

--perms, -p

This option causes the receiving rsync to set the destination permissions to be the same as the source permissions. (See also the --chmod option for a way to modify what rsync considers to be the source permissions.)

When this option is off, permissions are set as follows:

  • Existing files (including updated files) retain their existing permissions, though the --executability option might change just the execute permission for the file.
  • New files get their "normal" permission bits set to the source file's permissions masked with the receiving directory's default permissions (either the receiving process's umask, or the permissions specified via the destination directory's default ACL), and their special permission bits disabled except in the case where a new directory inherits a setgid bit from its parent directory.

Thus, when --perms and --executability are both disabled, rsync's behavior is the same as that of other file-copy utilities, such as cp(1) and tar(1).

In summary: to give destination files (both old and new) the source permissions, use --perms. To give new files the destination-default permissions (while leaving existing files unchanged), make sure that the --perms option is off and use --chmod=ugo=rwX (which ensures that all non-masked bits get enabled). If you'd care to make this latter behavior easier to type, you could define a popt alias for it, such as putting this line in the file ~/.popt (the following defines the -Z option, and includes --no-g to use the default group of the destination dir):

 rsync alias -Z --no-p --no-g --chmod=ugo=rwX

You could then use this new option in a command such as this one:

 rsync -avZ src/ dest/

(Caveat: make sure that -a does not follow -Z, or it will re-enable the two --no-* options mentioned above.)

The preservation of the destination's setgid bit on newly-created directories when --perms is off was added in rsync 2.6.7. Older rsync versions erroneously preserved the three special permission bits for newly-created files when --perms was off, while overriding the destination's setgid bit setting on a newly-created directory. Default ACL observance was added to the ACL patch for rsync 2.6.7, so older (or non-ACL-enabled) rsyncs use the umask even if default ACLs are present. (Keep in mind that it is the version of the receiving rsync that affects these behaviors.)

--executability, -E

This option causes rsync to preserve the executability (or non-executability) of regular files when --perms is not enabled. A regular file is considered to be executable if at least one 'x' is turned on in its permissions. When an existing destination file's executability differs from that of the corresponding source file, rsync modifies the destination file's permissions as follows:

  • To make a file non-executable, rsync turns off all its 'x' permissions.
  • To make a file executable, rsync turns on each 'x' permission that has a corresponding 'r' permission enabled.

If --perms is enabled, this option is ignored.

--acls, -A

This option causes rsync to update the destination ACLs to be the same as the source ACLs. The option also implies --perms.

The source and destination systems must have compatible ACL entries for this option to work properly. See the --fake-super option for a way to backup and restore ACLs that are not compatible.

--xattrs, -X

This option causes rsync to update the destination extended attributes to be the same as the source ones.

For systems that support extended-attribute namespaces, a copy being done by a super-user copies all namespaces except system.*. A normal user only copies the user.* namespace. To be able to backup and restore non-user namespaces as a normal user, see the --fake-super option.

The above name filtering can be overridden by using one or more filter options with the x modifier. When you specify an xattr-affecting filter rule, rsync requires that you do your own system/user filtering, as well as any additional filtering for what xattr names are copied and what names are allowed to be deleted. For example, to skip the system namespace, you could specify:

--filter='-x system.*'

To skip all namespaces except the user namespace, you could specify a negated-user match:

--filter='-x! user.*'

To prevent any attributes from being deleted, you could specify a receiver-only rule that excludes all names:

--filter='-xr *'

Note that the -X option does not copy rsync's special xattr values (e.g. those used by --fake-super) unless you repeat the option (e.g. -XX). This "copy all xattrs" mode cannot be used with --fake-super.

--chmod=CHMOD

This option tells rsync to apply one or more comma-separated "chmod" modes to the permission of the files in the transfer. The resulting value is treated as though it were the permissions that the sending side supplied for the file, which means that this option can seem to have no effect on existing files if --perms is not enabled.

In addition to the normal parsing rules specified in the chmod(1) manpage, you can specify an item that should only apply to a directory by prefixing it with a 'D', or specify an item that should only apply to a file by prefixing it with a 'F'. For example, the following will ensure that all directories get marked set-gid, that no files are other-writable, that both are user-writable and group-writable, and that both have consistent executability across all bits:

--chmod=Dg+s,ug+w,Fo-w,+X

Using octal mode numbers is also allowed:

--chmod=D2775,F664

It is also legal to specify multiple --chmod options, as each additional option is just appended to the list of changes to make.

See the --perms and --executability options for how the resulting permission value can be applied to the files in the transfer.

--owner, -o

This option causes rsync to set the owner of the destination file to be the same as the source file, but only if the receiving rsync is being run as the super-user (see also the --super and --fake-super options). Without this option, the owner of new and/or transferred files are set to the invoking user on the receiving side.

The preservation of ownership will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the --numeric-ids option for a full discussion).

--group, -g

This option causes rsync to set the group of the destination file to be the same as the source file. If the receiving program is not running as the super-user (or if --no-super was specified), only groups that the invoking user on the receiving side is a member of will be preserved. Without this option, the group is set to the default group of the invoking user on the receiving side.

The preservation of group information will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the --numeric-ids option for a full discussion).

--devices

This option causes rsync to transfer character and block device files to the remote system to recreate these devices. If the receiving rsync is not being run as the super-user, rsync silently skips creating the device files (see also the --super and --fake-super options).

By default, rsync generates a "non-regular file" warning for each device file encountered when this option is not set. You can silence the warning by specifying --info=nonreg0.

--specials

This option causes rsync to transfer special files, such as named sockets and fifos. If the receiving rsync is not being run as the super-user, rsync silently skips creating the special files (see also the --super and --fake-super options).

By default, rsync generates a "non-regular file" warning for each special file encountered when this option is not set. You can silence the warning by specifying --info=nonreg0.

-D

The -D option is equivalent to "--devices --specials".

--copy-devices

This tells rsync to treat a device on the sending side as a regular file, allowing it to be copied to a normal destination file (or another device if --write-devices was also specified).

This option is refused by default by an rsync daemon.

--write-devices

This tells rsync to treat a device on the receiving side as a regular file, allowing the writing of file data into a device.

This option implies the --inplace option.

Be careful using this, as you should know what devices are present on the receiving side of the transfer, especially when running rsync as root.

This option is refused by default by an rsync daemon.

--times, -t

This tells rsync to transfer modification times along with the files and update them on the remote system. Note that if this option is not used, the optimization that excludes files that have not been modified cannot be effective; in other words, a missing -t (or -a) will cause the next transfer to behave as if it used --ignore-times (-I), causing all files to be updated (though rsync's delta-transfer algorithm will make the update fairly efficient if the files haven't actually changed, you're much better off using -t).

A modern rsync that is using transfer protocol 30 or 31 conveys a modify time using up to 8-bytes. If rsync is forced to speak an older protocol (perhaps due to the remote rsync being older than 3.0.0) a modify time is conveyed using 4-bytes. Prior to 3.2.7, these shorter values could convey a date range of 13-Dec-1901 to 19-Jan-2038. Beginning with 3.2.7, these 4-byte values now convey a date range of 1-Jan-1970 to 7-Feb-2106. If you have files dated older than 1970, make sure your rsync executables are upgraded so that the full range of dates can be conveyed.

--atimes, -U

This tells rsync to set the access (use) times of the destination files to the same value as the source files.

If repeated, it also sets the --open-noatime option, which can help you to make the sending and receiving systems have the same access times on the transferred files without needing to run rsync an extra time after a file is transferred.

Note that some older rsync versions (prior to 3.2.0) may have been built with a pre-release --atimes patch that does not imply --open-noatime when this option is repeated.

--open-noatime

This tells rsync to open files with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred. If your OS does not support the O_NOATIME flag then rsync will silently ignore this option. Note also that some filesystems are mounted to avoid updating the atime on read access even without the O_NOATIME flag being set.

--crtimes, -N,

This tells rsync to set the create times (newness) of the destination files to the same value as the source files.

--omit-dir-times, -O

This tells rsync to omit directories when it is preserving modification, access, and create times. If NFS is sharing the directories on the receiving side, it is a good idea to use -O. This option is inferred if you use --backup without --backup-dir.

This option also has the side-effect of avoiding early creation of missing sub-directories when incremental recursion is enabled, as discussed in the --inc-recursive section.

This tells rsync to omit symlinks when it is preserving modification, access, and create times.

--super

This tells the receiving side to attempt super-user activities even if the receiving rsync wasn't run by the super-user. These activities include: preserving users via the --owner option, preserving all groups (not just the current user's groups) via the --group option, and copying devices via the --devices option. This is useful for systems that allow such activities without being the super-user, and also for ensuring that you will get errors if the receiving side isn't being run as the super-user. To turn off super-user activities, the super-user can use --no-super.

--fake-super

When this option is enabled, rsync simulates super-user activities by saving/restoring the privileged attributes via special extended attributes that are attached to each file (as needed). This includes the file's owner and group (if it is not the default), the file's device info (device & special files are created as empty text files), and any permission bits that we won't allow to be set on the real file (e.g. the real file gets u-s,g-s,o-t for safety) or that would limit the owner's access (since the real super-user can always access/change a file, the files we create can always be accessed/changed by the creating user). This option also handles ACLs (if --acls was specified) and non-user extended attributes (if --xattrs was specified).

This is a good way to backup data without using a super-user, and to store ACLs from incompatible systems.

The --fake-super option only affects the side where the option is used. To affect the remote side of a remote-shell connection, use the --remote-option (-M) option:

rsync -av -M--fake-super /src/ host:/dest/

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 -M--fake-super. If you wish a local copy to enable this option just for the source files, combine --fake-super with -M--super.

This option is overridden by both --super and --no-super.

See also the fake super setting in the daemon's rsyncd.conf file.

--sparse, -S

Try to handle sparse files efficiently so they take up less space on the destination. If combined with --inplace the file created might not end up with sparse blocks with some combinations of kernel version and/or filesystem type. If --whole-file is in effect (e.g. for a local copy) then it will always work because rsync truncates the file prior to writing out the updated version.

Note that versions of rsync older than 3.1.3 will reject the combination of --sparse and --inplace.

--preallocate

This tells the receiver to allocate each destination file to its eventual size before writing data to the file. Rsync will only use the real filesystem-level preallocation support provided by Linux's fallocate(2) system call or Cygwin's posix_fallocate(3), not the slow glibc implementation that writes a null byte into each block.

Without this option, larger files may not be entirely contiguous on the filesystem, but with this option rsync will probably copy more slowly. If the destination is not an extent-supporting filesystem (such as ext4, xfs, NTFS, etc.), this option may have no positive effect at all.

If combined with --sparse, the file will only have sparse blocks (as opposed to allocated sequences of null bytes) if the kernel version and filesystem type support creating holes in the allocated data.

--dry-run, -n

This makes rsync perform a trial run that doesn't make any changes (and produces mostly the same output as a real run). It is most commonly used in combination with the --verbose (-v) and/or --itemize-changes (-i) options to see what an rsync command is going to do before one actually runs it.

The output of --itemize-changes is supposed to be exactly the same on a dry run and a subsequent real run (barring intentional trickery and system call failures); if it isn't, that's a bug. Other output should be mostly unchanged, but may differ in some areas. Notably, a dry run does not send the actual data for file transfers, so --progress has no effect, the "bytes sent", "bytes received", "literal data", and "matched data" statistics are too small, and the "speedup" value is equivalent to a run where no file transfers were needed.

--whole-file, -W

This option disables rsync's delta-transfer algorithm, which causes all transferred files to be sent whole. The transfer may be faster if this option is used when the bandwidth between the source and destination machines is higher than the bandwidth to disk (especially when the "disk" is actually a networked filesystem). This is the default when both the source and destination are specified as local paths, but only if no batch-writing option is in effect.

--no-whole-file, --no-W

Disable whole-file updating when it is enabled by default for a local transfer. This usually slows rsync down, but it can be useful if you are trying to minimize the writes to the destination file (if combined with --inplace) or for testing the checksum-based update algorithm.

See also the --whole-file option.

--checksum-choice=STR, --cc=STR

This option overrides the checksum algorithms. If one algorithm name is specified, it is used for both the transfer checksums and (assuming --checksum is specified) the pre-transfer checksums. If two comma-separated names are supplied, the first name affects the transfer checksums, and the second name affects the pre-transfer checksums (-c).

The checksum options that you may be able to use are:

  • auto (the default automatic choice)
  • xxh128
  • xxh3
  • xxh64 (aka xxhash)
  • md5
  • md4
  • sha1
  • none

Run rsync --version to see the default checksum list compiled into your version (which may differ from the list above).

If "none" is specified for the first (or only) name, the --whole-file option is forced on and no checksum verification is performed on the transferred data. If "none" is specified for the second (or only) name, the --checksum option cannot be used.

The "auto" option is the default, where rsync bases its algorithm choice on a negotiation between the client and the server as follows:

When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common checksum choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, a value is chosen based on the protocol version (which chooses between MD5 and various flavors of MD4 based on protocol age).

The default order can be customized by setting the environment variable RSYNC_CHECKSUM_LIST to a space-separated list of acceptable checksum names. If the string contains a "&" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default checksum list is used. This method does not allow you to specify the transfer checksum separately from the pre-transfer checksum, and it discards "auto" and all unknown checksum names. A list with only invalid names results in a failed negotiation.

The use of the --checksum-choice option overrides this environment list.

--one-file-system, -x

This tells rsync to avoid crossing a filesystem boundary when recursing. This does not limit the user's ability to specify items to copy from multiple filesystems, just rsync's recursion through the hierarchy of each directory that the user specified, and also the analogous recursion on the receiving side during deletion. Also keep in mind that rsync treats a "bind" mount to the same device as being on the same filesystem.

If this option is repeated, rsync omits all mount-point directories from the copy. Otherwise, it includes an empty directory at each mount-point it encounters (using the attributes of the mounted directory because those of the underlying mount-point directory are inaccessible).

If rsync has been told to collapse symlinks (via --copy-links or --copy-unsafe-links), a symlink to a directory on another device is treated like a mount-point. Symlinks to non-directories are unaffected by this option.

--ignore-non-existing, --existing

This tells rsync to skip creating files (including directories) that do not exist yet on the destination. If this option is combined with the --ignore-existing option, no files will be updated (which can be useful if all you want to do is delete extraneous files).

This option is a TRANSFER RULE, so don't expect any exclude side effects.

--ignore-existing

This tells rsync to skip updating files that already exist on the destination (this does not ignore existing directories, or nothing would get done). See also --ignore-non-existing.

This option is a TRANSFER RULE, so don't expect any exclude side effects.

This option can be useful for those doing backups using the --link-dest option when they need to continue a backup run that got interrupted. Since a --link-dest run is copied into a new directory hierarchy (when it is used properly), using [--ignore-existing will ensure that the already-handled files don't get tweaked (which avoids a change in permissions on the hard-linked files). This does mean that this option is only looking at the existing files in the destination hierarchy itself.

When --info=skip2 is used rsync will output "FILENAME exists (INFO)" messages where the INFO indicates one of "type change", "sum change" (requires -c), "file change" (based on the quick check), "attr change", or "uptodate". Using --info=skip1 (which is also implied by 2 -v options) outputs the exists message without the INFO suffix.

--remove-source-files

This tells rsync to remove from the sending side the files (meaning non-directories) that are a part of the transfer and have been successfully duplicated on the receiving side.

Note that you should only use this option on source files that are quiescent. If you are using this to move files that show up in a particular directory over to another host, make sure that the finished files get renamed into the source directory, not directly written into it, so that rsync can't possibly transfer a file that is not yet fully written. If you can't first write the files into a different directory, you should use a naming idiom that lets rsync avoid transferring files that are not yet finished (e.g. name the file "foo.new" when it is written, rename it to "foo" when it is done, and then use the option --exclude='*.new' for the rsync transfer).

Starting with 3.1.0, rsync will skip the sender-side removal (and output an error) if the file's size or modify time has not stayed unchanged.

Starting with 3.2.6, a local rsync copy will ensure that the sender does not remove a file the receiver just verified, such as when the user accidentally makes the source and destination directory the same path.

--delete

This tells rsync to delete extraneous files from the receiving side (ones that aren't on the sending side), but only for the directories that are being synchronized. You must have asked rsync to send the whole directory (e.g. "dir" or "dir/") without using a wildcard for the directory's contents (e.g. "dir/*") since the wildcard is expanded by the shell and rsync thus gets a request to transfer individual files, not the files' parent directory. Files that are excluded from the transfer are also excluded from being deleted unless you use the --delete-excluded option or mark the rules as only matching on the sending side (see the include/exclude modifiers in the FILTER RULES section).

Prior to rsync 2.6.7, this option would have no effect unless --recursive was enabled. Beginning with 2.6.7, deletions will also occur when --dirs (-d) is enabled, but only for directories whose contents are being copied.

This option can be dangerous if used incorrectly! It is a very good idea to first try a run using the --dry-run (-n) option to see what files are going to be deleted.

If the sending side detects any I/O errors, then the deletion of any files at the destination will be automatically disabled. This is to prevent temporary filesystem failures (such as NFS errors) on the sending side from causing a massive deletion of files on the destination. You can override this with the --ignore-errors option.

The --delete option may be combined with one of the -⁠-⁠delete-WHEN options without conflict, as well as --delete-excluded. However, if none of the --delete-WHEN options are specified, rsync will choose the --delete-during algorithm when talking to rsync 3.0.0 or newer, or the --delete-before algorithm when talking to an older rsync. See also --delete-delay and --delete-after.

--delete-before

Request that the file-deletions on the receiving side be done before the transfer starts. See --delete (which is implied) for more details on file-deletion.

Deleting before the transfer is helpful if the filesystem is tight for space and removing extraneous files would help to make the transfer possible. However, it does introduce a delay before the start of the transfer, and this delay might cause the transfer to timeout (if --timeout was specified). It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see --recursive).

--delete-during, --del

Request that the file-deletions on the receiving side be done incrementally as the transfer happens. The per-directory delete scan is done right before each directory is checked for updates, so it behaves like a more efficient --delete-before, including doing the deletions prior to any per-directory filter files being updated. This option was first added in rsync version 2.6.4. See --delete (which is implied) for more details on file-deletion.

--delete-delay

Request that the file-deletions on the receiving side be computed during the transfer (like --delete-during), and then removed after the transfer completes. This is useful when combined with --delay-updates and/or --fuzzy, and is more efficient than using --delete-after (but can behave differently, since --delete-after computes the deletions in a separate pass after all updates are done). If the number of removed files overflows an internal buffer, a temporary file will be created on the receiving side to hold the names (it is removed while open, so you shouldn't see it during the transfer). If the creation of the temporary file fails, rsync will try to fall back to using --delete-after (which it cannot do if --recursive is doing an incremental scan). See --delete (which is implied) for more details on file-deletion.

--delete-after

Request that the file-deletions on the receiving side be done after the transfer has completed. This is useful if you are sending new per-directory merge files as a part of the transfer and you want their exclusions to take effect for the delete phase of the current transfer. It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see --recursive). See --delete (which is implied) for more details on file-deletion.

See also the --delete-delay option that might be a faster choice for those that just want the deletions to occur at the end of the transfer.

--delete-excluded

This option turns any unqualified exclude/include rules into server-side rules that do not affect the receiver's deletions.

By default, an exclude or include has both a server-side effect (to "hide" and "show" files when building the server's file list) and a receiver-side effect (to "protect" and "risk" files when deletions are occurring). Any rule that has no modifier to specify what sides it is executed on will be instead treated as if it were a server-side rule only, avoiding any "protect" effects of the rules.

A rule can still apply to both sides even with this option specified if the rule is given both the sender & receiver modifier letters (e.g., -f'-sr foo'). Receiver-side protect/risk rules can also be explicitly specified to limit the deletions. This saves you from having to edit a bunch of -f'- foo' rules into -f'-s foo' (aka -f'H foo') rules (not to mention the corresponding includes).

See the FILTER RULES section for more information. See --delete (which is implied) for more details on deletion.

--ignore-missing-args

When rsync is first processing the explicitly requested source files (e.g. command-line arguments or --files-from entries), it is normally an error if the file cannot be found. This option suppresses that error, and does not try to transfer the file. This does not affect subsequent vanished-file errors if a file was initially found to be present and later is no longer there.

--delete-missing-args

This option takes the behavior of the (implied) --ignore-missing-args option a step farther: each missing arg will become a deletion request of the corresponding destination file on the receiving side (should it exist). If the destination file is a non-empty directory, it will only be successfully deleted if --force or --delete are in effect. Other than that, this option is independent of any other type of delete processing.

The missing source files are represented by special file-list entries which display as a "*missing" entry in the --list-only output.

--ignore-errors

Tells --delete to go ahead and delete files even when there are I/O errors.

--force

This option tells rsync to delete a non-empty directory when it is to be replaced by a non-directory. This is only relevant if deletions are not active (see --delete for details).

Note for older rsync versions: --force used to still be required when using --delete-after, and it used to be non-functional unless the --recursive option was also enabled.

--max-delete=NUM

This tells rsync not to delete more than NUM files or directories. If that limit is exceeded, all further deletions are skipped through the end of the transfer. At the end, rsync outputs a warning (including a count of the skipped deletions) and exits with an error code of 25 (unless some more important error condition also occurred).

Beginning with version 3.0.0, you may specify --max-delete=0 to be warned about any extraneous files in the destination without removing any of them. Older clients interpreted this as "unlimited", so if you don't know what version the client is, you can use the less obvious --max-delete=-1 as a backward-compatible way to specify that no deletions be allowed (though really old versions didn't warn when the limit was exceeded).

--max-size=SIZE

This tells rsync to avoid transferring any file that is larger than the specified SIZE. A numeric value can be suffixed with a string to indicate the numeric units or left unqualified to specify bytes. Feel free to use a fractional value along with the units, such as --max-size=1.5m.

This option is a TRANSFER RULE, so don't expect any exclude side effects.

The first letter of a units string can be B (bytes), K (kilo), M (mega), G (giga), T (tera), or P (peta). If the string is a single char or has "ib" added to it (e.g. "G" or "GiB") then the units are multiples of 1024. If you use a two-letter suffix that ends with a "B" (e.g. "kb") then you get units that are multiples of 1000. The string's letters can be any mix of upper and lower-case that you want to use.

Finally, if the string ends with either "+1" or "-⁠1", it is offset by one byte in the indicated direction. The largest possible value is usually 8192P-1.

Examples: --max-size=1.5mb-1 is 1499999 bytes, and --max-size=2g+1 is 2147483649 bytes.

Note that rsync versions prior to 3.1.0 did not allow --max-size=0.

--min-size=SIZE

This tells rsync to avoid transferring any file that is smaller than the specified SIZE, which can help in not transferring small, junk files. See the --max-size option for a description of SIZE and other info.

Note that rsync versions prior to 3.1.0 did not allow --min-size=0.

--max-alloc=SIZE

By default rsync limits an individual malloc/realloc to about 1GB in size. For most people this limit works just fine and prevents a protocol error causing rsync to request massive amounts of memory. However, if you have many millions of files in a transfer, a large amount of server memory, and you don't want to split up your transfer into multiple parts, you can increase the per-allocation limit to something larger and rsync will consume more memory.

Keep in mind that this is not a limit on the total size of allocated memory. It is a sanity-check value for each individual allocation.

See the --max-size option for a description of how SIZE can be specified. The default suffix if none is given is bytes.

Beginning in 3.2.3, a value of 0 specifies no limit.

You can set a default value using the environment variable RSYNC_MAX_ALLOC using the same SIZE values as supported by this option. If the remote rsync doesn't understand the --max-alloc option, you can override an environmental value by specifying --max-alloc=1g, which will make rsync avoid sending the option to the remote side (because "1G" is the default).

--block-size=SIZE, -B

This forces the block size used in rsync's delta-transfer algorithm to a fixed value. It is normally selected based on the size of each file being updated. See the technical report for details.

Beginning in 3.2.3 the SIZE can be specified with a suffix as detailed in the --max-size option. Older versions only accepted a byte count.

--rsh=COMMAND, -e

This option allows you to choose an alternative remote shell program to use for communication between the local and remote copies of rsync. Typically, rsync is configured to use ssh by default, but you may prefer to use rsh on a local network.

If this option is used with [user@]host::module/path, then the remote shell COMMAND will be used to run an rsync daemon on the remote host, and all data will be transmitted through that remote shell connection, rather than through a direct socket connection to a running rsync daemon on the remote host. See the USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION section above.

Beginning with rsync 3.2.0, the RSYNC_PORT environment variable will be set when a daemon connection is being made via a remote-shell connection. It is set to 0 if the default daemon port is being assumed, or it is set to the value of the rsync port that was specified via either the --port option or a non-empty port value in an rsync:// URL. This allows the script to discern if a non-default port is being requested, allowing for things such as an SSL or stunnel helper script to connect to a default or alternate port.

Command-line arguments are permitted in COMMAND provided that COMMAND is presented to rsync as a single argument. You must use spaces (not tabs or other whitespace) to separate the command and args from each other, and you can use single- and/or double-quotes to preserve spaces in an argument (but not backslashes). Note that doubling a single-quote inside a single-quoted string gives you a single-quote; likewise for double-quotes (though you need to pay attention to which quotes your shell is parsing and which quotes rsync is parsing). Some examples:

-e 'ssh -p 2234'
-e 'ssh -o "ProxyCommand nohup ssh firewall nc -w1 %h %p"'

(Note that ssh users can alternately customize site-specific connect options in their .ssh/config file.)

You can also choose the remote shell program using the RSYNC_RSH environment variable, which accepts the same range of values as -e.

See also the --blocking-io option which is affected by this option.

--rsync-path=PROGRAM

Use this to specify what program is to be run on the remote machine to start-up rsync. Often used when rsync is not in the default remote-shell's path (e.g. --rsync-path=/usr/local/bin/rsync). Note that PROGRAM is run with the help of a shell, so it can be any program, script, or command sequence you'd care to run, so long as it does not corrupt the standard-in & standard-out that rsync is using to communicate.

One tricky example is to set a different default directory on the remote machine for use with the --relative option. For instance:

rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/
--remote-option=OPTION, -M

This option is used for more advanced situations where you want certain effects to be limited to one side of the transfer only. For instance, if you want to pass --log-file=FILE and --fake-super to the remote system, specify it like this:

rsync -av -M --log-file=foo -M--fake-super src/ dest/

If you want to have an option affect only the local side of a transfer when it normally affects both sides, send its negation to the remote side. Like this:

rsync -av -x -M--no-x src/ dest/

Be cautious using this, as it is possible to toggle an option that will cause rsync to have a different idea about what data to expect next over the socket, and that will make it fail in a cryptic fashion.

Note that you should use a separate -M option for each remote option you want to pass. On older rsync versions, the presence of any spaces in the remote-option arg could cause it to be split into separate remote args, but this requires the use of --old-args in a modern rsync.

When performing a local transfer, the "local" side is the sender and the "remote" side is the receiver.

Note some versions of the popt option-parsing library have a bug in them that prevents you from using an adjacent arg with an equal in it next to a short option letter (e.g. -M--log-file=/tmp/foo). If this bug affects your version of popt, you can use the version of popt that is included with rsync.

--cvs-exclude, -C

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 a file should be ignored.

The exclude list is initialized to exclude the following items (these initial items are marked as perishable -⁠-⁠ see the FILTER RULES section):

RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state .nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej .del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/ .git/ .hg/ .bzr/

then, files listed in a $HOME/.cvsignore are added to the list and any files listed in the CVSIGNORE environment variable (all cvsignore names are delimited by whitespace).

Finally, any file is ignored if it is in the same directory as a .cvsignore file and matches one of the patterns listed therein. Unlike rsync's filter/exclude files, these patterns are split on whitespace. See the cvs(1) manual for more information.

If you're combining -C with your own --filter rules, you should note that these CVS excludes are appended at the end of your own rules, regardless of where the -C was placed on the command-line. This makes them a lower priority than any rules you specified explicitly. If you want to control where these CVS excludes get inserted into your filter rules, you should omit the -C as a command-line option and use a combination of --filter=:C and --filter=-C (either on your command-line or by putting the ":C" and "-⁠C" rules into a filter file with your other rules). The first option turns on the per-directory scanning for the .cvsignore file. The second option does a one-time import of the CVS excludes mentioned above.

--filter=RULE, -f

This option allows you to add rules to selectively exclude certain files from the list of files to be transferred. This is most useful in combination with a recursive transfer.

You may use as many --filter options on the command line as you like to build up the list of files to exclude. If the filter contains whitespace, be sure to quote it so that the shell gives the rule to rsync as a single argument. The text below also mentions that you can use an underscore to replace the space that separates a rule from its arg.

See the FILTER RULES section for detailed information on this option.

-F

The -F option is a shorthand for adding two --filter rules to your command. The first time it is used is a shorthand for this rule:

--filter='dir-merge /.rsync-filter'

This tells rsync to look for per-directory .rsync-filter files that have been sprinkled through the hierarchy and use their rules to filter the files in the transfer. If -F is repeated, it is a shorthand for this rule:

--filter='exclude .rsync-filter'

This filters out the .rsync-filter files themselves from the transfer.

See the FILTER RULES section for detailed information on how these options work.

--exclude=PATTERN

This option is a simplified form of the --filter option that specifies an exclude rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying -f'- PATTERN'.

See the FILTER RULES section for detailed information on this option.

--exclude-from=FILE

This option is related to the --exclude option, but it specifies a FILE that contains exclude patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with ';' or '#' (filename rules that contain those characters are unaffected).

If a line begins with "- " (dash, space) or "+ " (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an exclude.

If a line consists of just "!", then the current filter rules are cleared before adding any further rules.

If FILE is '-', the list will be read from standard input.

--include=PATTERN

This option is a simplified form of the --filter option that specifies an include rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying -f'+ PATTERN'.

See the FILTER RULES section for detailed information on this option.

--include-from=FILE

This option is related to the --include option, but it specifies a FILE that contains include patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with ';' or '#' (filename rules that contain those characters are unaffected).

If a line begins with "- " (dash, space) or "+ " (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an include.

If a line consists of just "!", then the current filter rules are cleared before adding any further rules.

If FILE is '-', the list will be read from standard input.

--files-from=FILE

Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or '-' for standard input). It also tweaks the default behavior of rsync to make transferring just the specified files and directories easier:

  • The --relative (-R) option is implied, which preserves the path information that is specified for each item in the file (use --no-relative or --no-R if you want to turn that off).
  • The --dirs (-d) option is implied, which will create directories specified in the list on the destination rather than noisily skipping them (use --no-dirs or --no-d if you want to turn that off).
  • The --archive (-a) option's behavior does not imply --recursive (-r), so specify it explicitly, if you want it.
  • These side-effects change the default state of rsync, so the position of the --files-from option on the command-line has no bearing on how other options are parsed (e.g. -a works the same before or after --files-from, as does --no-R and all other options).

The filenames that are read from the FILE are all relative to the source dir -⁠-⁠ any leading slashes are removed and no ".." references are allowed to go higher than the source dir. For example, take this command:

rsync -a --files-from=/tmp/foo /usr remote:/backup

If /tmp/foo contains the string "bin" (or even "/bin"), the /usr/bin directory will be created as /backup/bin on the remote host. If it contains "bin/" (note the trailing slash), the immediate contents of the directory would also be sent (without needing to be explicitly mentioned in the file -⁠-⁠ this began in version 2.6.4). In both cases, if the -r option was enabled, that dir's entire hierarchy would also be transferred (keep in mind that -r needs to be specified explicitly with --files-from, since it is not implied by -a. Also note that the effect of the (enabled by default) -r option is to duplicate only the path info that is read from the file -⁠-⁠ it does not force the duplication of the source-spec path (/usr in this case).

In addition, the --files-from file can be read from the remote host instead of the local host if you specify a "host:" in front of the file (the host must match one end of the transfer). As a short-cut, you can specify just a prefix of ":" to mean "use the remote end of the transfer". For example:

rsync -a --files-from=:/path/file-list src:/ /tmp/copy

This would copy all the files specified in the /path/file-list file that was located on the remote "src" host.

If the --iconv and --secluded-args options are specified and the --files-from filenames are being sent from one host to another, the filenames will be translated from the sending host's charset to the receiving host's charset.

NOTE: sorting the list of files in the --files-from input helps rsync to be more efficient, as it will avoid re-visiting the path elements that are shared between adjacent entries. If the input is not sorted, some path elements (implied directories) may end up being scanned multiple times, and rsync will eventually unduplicate them after they get turned into file-list elements.

--from0, -0

This tells rsync that the rules/filenames it reads from a file are terminated by a null ('\0') character, not a NL, CR, or CR+LF. This affects --exclude-from, --include-from, --files-from, and any merged files specified in a --filter rule. It does not affect --cvs-exclude (since all names read from a .cvsignore file are split on whitespace).

--old-args

This option tells rsync to stop trying to protect the arg values on the remote side from unintended word-splitting or other misinterpretation. It also allows the client to treat an empty arg as a "." instead of generating an error.

The default in a modern rsync is for "shell-active" characters (including spaces) to be backslash-escaped in the args that are sent to the remote shell. The wildcard characters *, ?, [, & ] are not escaped in filename args (allowing them to expand into multiple filenames) while being protected in option args, such as --usermap.

If you have a script that wants to use old-style arg splitting in its filenames, specify this option once. If the remote shell has a problem with any backslash escapes at all, specify this option twice.

You may also control this setting via the RSYNC_OLD_ARGS environment variable. If it has the value "1", rsync will default to a single-option setting. If it has the value "2" (or more), rsync will default to a repeated-option setting. If it is "0", you'll get the default escaping behavior. The environment is always overridden by manually specified positive or negative options (the negative is --no-old-args).

Note that this option also disables the extra safety check added in 3.2.5 that ensures that a remote sender isn't including extra top-level items in the file-list that you didn't request. This side-effect is necessary because we can't know for sure what names to expect when the remote shell is interpreting the args.

This option conflicts with the --secluded-args option.

--secluded-args, -s

This option sends all filenames and most options to the remote rsync via the protocol (not the remote shell command line) which avoids letting the remote shell modify them. Wildcards are expanded on the remote host by rsync instead of a shell.

This is similar to the default backslash-escaping of args that was added in 3.2.4 (see --old-args) in that it prevents things like space splitting and unwanted special-character side-effects. However, it has the drawbacks of being incompatible with older rsync versions (prior to 3.0.0) and of being refused by restricted shells that want to be able to inspect all the option values for safety.

This option is useful for those times that you need the argument's character set to be converted for the remote host, if the remote shell is incompatible with the default backslash-escpaing method, or there is some other reason that you want the majority of the options and arguments to bypass the command-line of the remote shell.

If you combine this option with --iconv, the args related to the remote side will be translated from the local to the remote character-set. The translation happens before wild-cards are expanded. See also the --files-from option.

You may also control this setting via the RSYNC_PROTECT_ARGS environment variable. If it has a non-zero value, this setting will be enabled by default, otherwise it will be disabled by default. Either state is overridden by a manually specified positive or negative version of this option (note that --no-s and --no-secluded-args are the negative versions). This environment variable is also superseded by a non-zero RSYNC_OLD_ARGS export.

This option conflicts with the --old-args option.

This option used to be called --protect-args (before 3.2.6) and that older name can still be used (though specifying it as -s is always the easiest and most compatible choice).

--trust-sender

This option disables two extra validation checks that a local client performs on the file list generated by a remote sender. This option should only be used if you trust the sender to not put something malicious in the file list (something that could possibly be done via a modified rsync, a modified shell, or some other similar manipulation).

Normally, the rsync client (as of version 3.2.5) runs two extra validation checks when pulling files from a remote rsync:

  • It verifies that additional arg items didn't get added at the top of the transfer.
  • It verifies that none of the items in the file list are names that should have been excluded (if filter rules were specified).

Note that various options can turn off one or both of these checks if the option interferes with the validation. For instance:

  • Using a per-directory filter file reads filter rules that only the server knows about, so the filter checking is disabled.
  • Using the --old-args option allows the sender to manipulate the requested args, so the arg checking is disabled.
  • Reading the files-from list from the server side means that the client doesn't know the arg list, so the arg checking is disabled.
  • Using --read-batch disables both checks since the batch file's contents will have been verified when it was created.

This option may help an under-powered client server if the extra pattern matching is slowing things down on a huge transfer. It can also be used to work around a currently-unknown bug in the verification logic for a transfer from a trusted sender.

When using this option it is a good idea to specify a dedicated destination directory, as discussed in the MULTI-HOST SECURITY section.

--copy-as=USER[:GROUP]

This option instructs rsync to use the USER and (if specified after a colon) the GROUP for the copy operations. This only works if the user that is running rsync has the ability to change users. If the group is not specified then the user's default groups are used.

This option can help to reduce the risk of an rsync being run as root into or out of a directory that might have live changes happening to it and you want to make sure that root-level read or write actions of system files are not possible. While you could alternatively run all of rsync as the specified user, sometimes you need the root-level host-access credentials to be used, so this allows rsync to drop root for the copying part of the operation after the remote-shell or daemon connection is established.

The option only affects one side of the transfer unless the transfer is local, in which case it affects both sides. Use the --remote-option to affect the remote side, such as -M--copy-as=joe. For a local transfer, the lsh (or lsh.sh) support file provides a local-shell helper script that can be used to allow a "localhost:" or "lh:" host-spec to be specified without needing to setup any remote shells, allowing you to specify remote options that affect the side of the transfer that is using the host-spec (and using hostname "lh" avoids the overriding of the remote directory to the user's home dir).

For example, the following rsync writes the local files as user "joe":

sudo rsync -aiv --copy-as=joe host1:backups/joe/ /home/joe/

This makes all files owned by user "joe", limits the groups to those that are available to that user, and makes it impossible for the joe user to do a timed exploit of the path to induce a change to a file that the joe user has no permissions to change.

The following command does a local copy into the "dest/" dir as user "joe" (assuming you've installed support/lsh into a dir on your $PATH):

sudo rsync -aive lsh -M--copy-as=joe src/ lh:dest/
--temp-dir=DIR, -T

This option instructs rsync to use DIR as a scratch directory when creating temporary copies of the files transferred on the receiving side. The default behavior is to create each temporary file in the same directory as the associated destination file. Beginning with rsync 3.1.1, the temp-file names inside the specified DIR will not be prefixed with an extra dot (though they will still have a random suffix added).

This option is most often used when the receiving disk partition does not have enough free space to hold a copy of the largest file in the transfer. In this case (i.e. when the scratch directory is on a different disk partition), rsync will not be able to rename each received temporary file over the top of the associated destination file, but instead must copy it into place. Rsync does this by copying the file over the top of the destination file, which means that the destination file will contain truncated data during this copy. If this were not done this way (even if the destination file were first removed, the data locally copied to a temporary file in the destination directory, and then renamed into place) it would be possible for the old file to continue taking up disk space (if someone had it open), and thus there might not be enough room to fit the new version on the disk at the same time.

If you are using this option for reasons other than a shortage of disk space, you may wish to combine it with the --delay-updates option, which will ensure that all copied files get put into subdirectories in the destination hierarchy, awaiting the end of the transfer. If you don't have enough room to duplicate all the arriving files on the destination partition, another way to tell rsync that you aren't overly concerned about disk space is to use the --partial-dir option with a relative path; because this tells rsync that it is OK to stash off a copy of a single file in a subdir in the destination hierarchy, rsync will use the partial-dir as a staging area to bring over the copied file, and then rename it into place from there. (Specifying a --partial-dir with an absolute path does not have this side-effect.)

--fuzzy, -y

This option tells rsync that it should look for a basis file for any destination file that is missing. The current algorithm looks in the same directory as the destination file for either a file that has an identical size and modified-time, or a similarly-named file. If found, rsync uses the fuzzy basis file to try to speed up the transfer.

If the option is repeated, the fuzzy scan will also be done in any matching alternate destination directories that are specified via --compare-dest, --copy-dest, or --link-dest.

Note that the use of the --delete option might get rid of any potential fuzzy-match files, so either use --delete-after or specify some filename exclusions if you need to prevent this.

--compare-dest=DIR

This option instructs rsync to use DIR on the destination machine as an additional hierarchy to compare destination files against doing transfers (if the files are missing in the destination directory). If a file is found in DIR that is identical to the sender's file, the file will NOT be transferred to the destination directory. This is useful for creating a sparse backup of just files that have changed from an earlier backup. This option is typically used to copy into an empty (or newly created) directory.

Beginning in version 2.6.4, multiple --compare-dest directories may be provided, which will cause rsync to search the list in the order specified for an exact match. If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the DIRs will be selected to try to speed up the transfer.

If DIR is a relative path, it is relative to the destination directory. See also --copy-dest and --link-dest.

NOTE: beginning with version 3.1.0, rsync will remove a file from a non-empty destination hierarchy if an exact match is found in one of the compare-dest hierarchies (making the end result more closely match a fresh copy).

--copy-dest=DIR

This option behaves like --compare-dest, but rsync will also copy unchanged files found in DIR to the destination directory using a local copy. This is useful for doing transfers to a new destination while leaving existing files intact, and then doing a flash-cutover when all files have been successfully transferred.

Multiple --copy-dest directories may be provided, which will cause rsync to search the list in the order specified for an unchanged file. If a match is not found, a basis file from one of the DIRs will be selected to try to speed up the transfer.

If DIR is a relative path, it is relative to the destination directory. See also --compare-dest and --link-dest.

This option behaves like --copy-dest, but unchanged files are hard linked from DIR to the destination directory. The files must be identical in all preserved attributes (e.g. permissions, possibly ownership) in order for the files to be linked together. An example:

rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/

If files aren't linking, double-check their attributes. Also check if some attributes are getting forced outside of rsync's control, such a mount option that squishes root to a single user, or mounts a removable drive with generic ownership (such as OS X's "Ignore ownership on this volume" option).

Beginning in version 2.6.4, multiple --link-dest directories may be provided, which will cause rsync to search the list in the order specified for an exact match (there is a limit of 20 such directories). If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the DIRs will be selected to try to speed up the transfer.

This option works best when copying into an empty destination hierarchy, as existing files may get their attributes tweaked, and that can affect alternate destination files via hard-links. Also, itemizing of changes can get a bit muddled. Note that prior to version 3.1.0, an alternate-directory exact match would never be found (nor linked into the destination) when a destination file already exists.

Note that if you combine this option with --ignore-times, rsync will not link any files together because it only links identical files together as a substitute for transferring the file, never as an additional check after the file is updated.

If DIR is a relative path, it is relative to the destination directory. See also --compare-dest and --copy-dest.

Note that rsync versions prior to 2.6.1 had a bug that could prevent --link-dest from working properly for a non-super-user when --owner (-o) was specified (or implied). You can work-around this bug by avoiding the -o option (or using --no-o) when sending to an old rsync.

--compress, -z

With this option, rsync compresses the file data as it is sent to the destination machine, which reduces the amount of data being transmitted -⁠-⁠ something that is useful over a slow connection.

Rsync supports multiple compression methods and will choose one for you unless you force the choice using the --compress-choice (--zc) option.

Run rsync --version to see the default compress list compiled into your version.

When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common compress choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, its list is assumed to be "zlib".

The default order can be customized by setting the environment variable RSYNC_COMPRESS_LIST to a space-separated list of acceptable compression names. If the string contains a "&" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default compress list is used. Any unknown compression names are discarded from the list, but a list with only invalid names results in a failed negotiation.

There are some older rsync versions that were configured to reject a -z option and require the use of -zz because their compression library was not compatible with the default zlib compression method. You can usually ignore this weirdness unless the rsync server complains and tells you to specify -zz.

--compress-choice=STR, --zc=STR

This option can be used to override the automatic negotiation of the compression algorithm that occurs when --compress is used. The option implies --compress unless "none" was specified, which instead implies --no-compress.

The compression options that you may be able to use are:

  • zstd
  • lz4
  • zlibx
  • zlib
  • none

Run rsync --version to see the default compress list compiled into your version (which may differ from the list above).

Note that if you see an error about an option named --old-compress or --new-compress, this is rsync trying to send the --compress-choice=zlib or --compress-choice=zlibx option in a backward-compatible manner that more rsync versions understand. This error indicates that the older rsync version on the server will not allow you to force the compression type.

Note that the "zlibx" compression algorithm is just the "zlib" algorithm with matched data excluded from the compression stream (to try to make it more compatible with an external zlib implementation).

--compress-level=NUM, --zl=NUM

Explicitly set the compression level to use (see --compress, -z) instead of letting it default. The --compress option is implied as long as the level chosen is not a "don't compress" level for the compression algorithm that is in effect (e.g. zlib compression treats level 0 as "off").

The level values vary depending on the checksum in effect. Because rsync will negotiate a checksum choice by default (when the remote rsync is new enough), it can be good to combine this option with a --compress-choice (--zc) option unless you're sure of the choice in effect. For example:

rsync -aiv --zc=zstd --zl=22 host:src/ dest/

For zlib & zlibx compression the valid values are from 1 to 9 with 6 being the default. Specifying --zl=0 turns compression off, and specifying --zl=-1 chooses the default level of 6.

For zstd compression the valid values are from -⁠131072 to 22 with 3 being the default. Specifying 0 chooses the default of 3.

For lz4 compression there are no levels, so the value is always 0.

If you specify a too-large or too-small value, the number is silently limited to a valid value. This allows you to specify something like --zl=999999999 and be assured that you'll end up with the maximum compression level no matter what algorithm was chosen.

If you want to know the compression level that is in effect, specify --debug=nstr to see the "negotiated string" results. This will report something like "Client compress: zstd (level 3)" (along with the checksum choice in effect).

--skip-compress=LIST

NOTE: no compression method currently supports per-file compression changes, so this option has no effect.

Override the list of file suffixes that will be compressed as little as possible. Rsync sets the compression level on a per-file basis based on the file's suffix. If the compression algorithm has an "off" level, then no compression occurs for those files. Other algorithms that support changing the streaming level on-the-fly will have the level minimized to reduces the CPU usage as much as possible for a matching file.

The LIST should be one or more file suffixes (without the dot) separated by slashes (/). You may specify an empty string to indicate that no files should be skipped.

Simple character-class matching is supported: each must consist of a list of letters inside the square brackets (e.g. no special classes, such as "[:alpha:]", are supported, and '-⁠' has no special meaning).

The characters asterisk (*) and question-mark (?) have no special meaning.

Here's an example that specifies 6 suffixes to skip (since 1 of the 5 rules matches 2 suffixes):

--skip-compress=gz/jpg/mp[34]/7z/bz2

The default file suffixes in the skip-compress list in this version of rsync are:

3g2 3gp 7z aac ace apk avi bz2 deb dmg ear f4v flac flv gpg gz iso jar jpeg jpg lrz lz lz4 lzma lzo m1a m1v m2a m2ts m2v m4a m4b m4p m4r m4v mka mkv mov mp1 mp2 mp3 mp4 mpa mpeg mpg mpv mts odb odf odg odi odm odp ods odt oga ogg ogm ogv ogx opus otg oth otp ots ott oxt png qt rar rpm rz rzip spx squashfs sxc sxd sxg sxm sxw sz tbz tbz2 tgz tlz ts txz tzo vob war webm webp xz z zip zst

This list will be replaced by your --skip-compress list in all but one situation: a copy from a daemon rsync will add your skipped suffixes to its list of non-compressing files (and its list may be configured to a different default).

--numeric-ids

With this option rsync will transfer numeric group and user IDs rather than using user and group names and mapping them at both ends.

By default rsync will use the username and groupname to determine what ownership to give files. The special uid 0 and the special group 0 are never mapped via user/group names even if the --numeric-ids option is not specified.

If a user or group has no name on the source system or it has no match on the destination system, then the numeric ID from the source system is used instead. See also the use chroot setting in the rsyncd.conf manpage for some comments on how the chroot setting affects rsync's ability to look up the names of the users and groups and what you can do about it.

--usermap=STRING, --groupmap=STRING

These options allow you to specify users and groups that should be mapped to other values by the receiving side. The STRING is one or more FROM:TO pairs of values separated by commas. Any matching FROM value from the sender is replaced with a TO value from the receiver. You may specify usernames or user IDs for the FROM and TO values, and the FROM value may also be a wild-card string, which will be matched against the sender's names (wild-cards do NOT match against ID numbers, though see below for why a '*' matches everything). You may instead specify a range of ID numbers via an inclusive range: LOW-HIGH. For example:

--usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr

The first match in the list is the one that is used. You should specify all your user mappings using a single --usermap option, and/or all your group mappings using a single --groupmap option.

Note that the sender's name for the 0 user and group are not transmitted to the receiver, so you should either match these values using a 0, or use the names in effect on the receiving side (typically "root"). All other FROM names match those in use on the sending side. All TO names match those in use on the receiving side.

Any IDs that do not have a name on the sending side are treated as having an empty name for the purpose of matching. This allows them to be matched via a "*" or using an empty name. For instance:

--usermap=:nobody --groupmap=*:nobody

When the --numeric-ids option is used, the sender does not send any names, so all the IDs are treated as having an empty name. This means that you will need to specify numeric FROM values if you want to map these nameless IDs to different values.

For the --usermap option to work, the receiver will need to be running as a super-user (see also the --super and --fake-super options). For the --groupmap option to work, the receiver will need to have permissions to set that group.

Starting with rsync 3.2.4, the --usermap option implies the --owner (-o) option while the --groupmap option implies the --group (-g) option (since rsync needs to have those options enabled for the mapping options to work).

An older rsync client may need to use -s to avoid a complaint about wildcard characters, but a modern rsync handles this automatically.

--chown=USER:GROUP

This option forces all files to be owned by USER with group GROUP. This is a simpler interface than using --usermap & --groupmap directly, but it is implemented using those options internally so they cannot be mixed. If either the USER or GROUP is empty, no mapping for the omitted user/group will occur. If GROUP is empty, the trailing colon may be omitted, but if USER is empty, a leading colon must be supplied.

If you specify "--chown=foo:bar", this is exactly the same as specifying "--usermap=*:foo --groupmap=*:bar", only easier (and with the same implied --owner and/or --group options).

An older rsync client may need to use -s to avoid a complaint about wildcard characters, but a modern rsync handles this automatically.

--timeout=SECONDS

This option allows you to set a maximum I/O timeout in seconds. If no data is transferred for the specified time then rsync will exit. The default is 0, which means no timeout.

--contimeout=SECONDS

This option allows you to set the amount of time that rsync will wait for its connection to an rsync daemon to succeed. If the timeout is reached, rsync exits with an error.

--address=ADDRESS

By default rsync will bind to the wildcard address when connecting to an rsync daemon. The --address option allows you to specify a specific IP address (or hostname) to bind to.

See also the daemon version of the --address option.

--port=PORT

This specifies an alternate TCP port number to use rather than the default of 873. This is only needed if you are using the double-colon (::) syntax to connect with an rsync daemon (since the URL syntax has a way to specify the port as a part of the URL).

See also the daemon version of the --port option.

--sockopts=OPTIONS

This option can provide endless fun for people who like to tune their systems to the utmost degree. You can set all sorts of socket options which may make transfers faster (or slower!). Read the manpage for the setsockopt() system call for details on some of the options you may be able to set. By default no special socket options are set. This only affects direct socket connections to a remote rsync daemon.

See also the daemon version of the --sockopts option.

--blocking-io

This tells rsync to use blocking I/O when launching a remote shell transport. If the remote shell is either rsh or remsh, rsync defaults to using blocking I/O, otherwise it defaults to using non-blocking I/O. (Note that ssh prefers non-blocking I/O.)

--outbuf=MODE

This sets the output buffering mode. The mode can be None (aka Unbuffered), Line, or Block (aka Full). You may specify as little as a single letter for the mode, and use upper or lower case.

The main use of this option is to change Full buffering to Line buffering when rsync's output is going to a file or pipe.

--itemize-changes, -i

Requests a simple itemized list of the changes that are being made to each file, including attribute changes. This is exactly the same as specifying --out-format='%i %n%L'. If you repeat the option, unchanged files will also be output, but only if the receiving rsync is at least version 2.6.7 (you can use -vv with older versions of rsync, but that also turns on the output of other verbose messages).

The "%i" escape has a cryptic output that is 11 letters long. The general format is like the string YXcstpoguax, where Y is replaced by the type of update being done, X is replaced by the file-type, and the other letters represent attributes that may be output if they are being modified.

The update types that replace the Y are as follows:

  • A < means that a file is being transferred to the remote host (sent).
  • A > means that a file is being transferred to the local host (received).
  • A c means that a local change/creation is occurring for the item (such as the creation of a directory or the changing of a symlink, etc.).
  • A h means that the item is a hard link to another item (requires --hard-links).
  • A . means that the item is not being updated (though it might have attributes that are being modified).
  • A * means that the rest of the itemized-output area contains a message (e.g. "deleting").

The file-types that replace the X are: f for a file, a d for a directory, an L for a symlink, a D for a device, and a S for a special file (e.g. named sockets and fifos).

The other letters in the string indicate if some attributes of the file have changed, as follows:

  • "." -⁠ the attribute is unchanged.
  • "+" -⁠ the file is newly created.
  • " " -⁠ all the attributes are unchanged (all dots turn to spaces).
  • "?" -⁠ the change is unknown (when the remote rsync is old).
  • A letter indicates an attribute is being updated.

The attribute that is associated with each letter is as follows:

  • A c means either that a regular file has a different checksum (requires --checksum) or that a symlink, device, or special file has a changed value. Note that if you are sending files to an rsync prior to 3.0.1, this change flag will be present only for checksum-differing regular files.
  • A s means the size of a regular file is different and will be updated by the file transfer.
  • A t means the modification time is different and is being updated to the sender's value (requires --times). An alternate value of T means that the modification time will be set to the transfer time, which happens when a file/symlink/device is updated without --times and when a symlink is changed and the receiver can't set its time. (Note: when using an rsync 3.0.0 client, you might see the s flag combined with t instead of the proper T flag for this time-setting failure.)
  • A p means the permissions are different and are being updated to the sender's value (requires --perms).
  • An o means the owner is different and is being updated to the sender's value (requires --owner and super-user privileges).
  • A g means the group is different and is being updated to the sender's value (requires --group and the authority to set the group).
  • A u|n|b indicates the following information:
    • u means the access (use) time is different and is being updated to the sender's value (requires --atimes)
    • n means the create time (newness) is different and is being updated to the sender's value (requires --crtimes)
    • b means that both the access and create times are being updated
  • The a means that the ACL information is being changed.
  • The x means that the extended attribute information is being changed.

One other output is possible: when deleting files, the "%i" will output the string "*deleting" for each item that is being removed (assuming that you are talking to a recent enough rsync that it logs deletions instead of outputting them as a verbose message).

--out-format=FORMAT

This allows you to specify exactly what the rsync client outputs to the user on a per-update basis. The format is a text string containing embedded single-character escape sequences prefixed with a percent (%) character. A default format of "%n%L" is assumed if either --info=name or -v is specified (this tells you just the name of the file and, if the item is a link, where it points). For a full list of the possible escape characters, see the log format setting in the rsyncd.conf manpage.

Specifying the --out-format option implies the --info=name option, which will mention each file, dir, etc. that gets updated in a significant way (a transferred file, a recreated symlink/device, or a touched directory). In addition, if the itemize-changes escape (%i) is included in the string (e.g. if the --itemize-changes option was used), the logging of names increases to mention any item that is changed in any way (as long as the receiving side is at least 2.6.4). See the --itemize-changes option for a description of the output of "%i".

Rsync will output the out-format string prior to a file's transfer unless one of the transfer-statistic escapes is requested, in which case the logging is done at the end of the file's transfer. When this late logging is in effect and --progress is also specified, rsync will also output the name of the file being transferred prior to its progress information (followed, of course, by the out-format output).

--log-file=FILE

This option causes rsync to log what it is doing to a file. This is similar to the logging that a daemon does, but can be requested for the client side and/or the server side of a non-daemon transfer. If specified as a client option, transfer logging will be enabled with a default format of "%i %n%L". See the --log-file-format option if you wish to override this.

Here's an example command that requests the remote side to log what is happening:

rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/

This is very useful if you need to debug why a connection is closing unexpectedly.

See also the daemon version of the --log-file option.

--log-file-format=FORMAT

This allows you to specify exactly what per-update logging is put into the file specified by the --log-file option (which must also be specified for this option to have any effect). If you specify an empty string, updated files will not be mentioned in the log file. For a list of the possible escape characters, see the log format setting in the rsyncd.conf manpage.

The default FORMAT used if --log-file is specified and this option is not is '%i %n%L'.

See also the daemon version of the --log-file-format option.

--stats

This tells rsync to print a verbose set of statistics on the file transfer, allowing you to tell how effective rsync's delta-transfer algorithm is for your data. This option is equivalent to --info=stats2 if combined with 0 or 1 -v options, or --info=stats3 if combined with 2 or more -v options.

The current statistics are as follows:

  • Number of files is the count of all "files" (in the generic sense), which includes directories, symlinks, etc. The total count will be followed by a list of counts by filetype (if the total is non-zero). For example: "(reg: 5, dir: 3, link: 2, dev: 1, special: 1)" lists the totals for regular files, directories, symlinks, devices, and special files. If any of value is 0, it is completely omitted from the list.
  • Number of created files is the count of how many "files" (generic sense) were created (as opposed to updated). The total count will be followed by a list of counts by filetype (if the total is non-zero).
  • Number of deleted files is the count of how many "files" (generic sense) were deleted. The total count will be followed by a list of counts by filetype (if the total is non-zero). Note that this line is only output if deletions are in effect, and only if protocol 31 is being used (the default for rsync 3.1.x).
  • Number of regular files transferred is the count of normal files that were updated via rsync's delta-transfer algorithm, which does not include dirs, symlinks, etc. Note that rsync 3.1.0 added the word "regular" into this heading.
  • Total file size is the total sum of all file sizes in the transfer. This does not count any size for directories or special files, but does include the size of symlinks.
  • Total transferred file size is the total sum of all files sizes for just the transferred files.
  • Literal data is how much unmatched file-update data we had to send to the receiver for it to recreate the updated files.
  • Matched data is how much data the receiver got locally when recreating the updated files.
  • File list size is how big the file-list data was when the sender sent it to the receiver. This is smaller than the in-memory size for the file list due to some compressing of duplicated data when rsync sends the list.
  • File list generation time is the number of seconds that the sender spent creating the file list. This requires a modern rsync on the sending side for this to be present.
  • File list transfer time is the number of seconds that the sender spent sending the file list to the receiver.
  • Total bytes sent is the count of all the bytes that rsync sent from the client side to the server side.
  • Total bytes received is the count of all non-message bytes that rsync received by the client side from the server side. "Non-message" bytes means that we don't count the bytes for a verbose message that the server sent to us, which makes the stats more consistent.
--8-bit-output, -8

This tells rsync to leave all high-bit characters unescaped in the output instead of trying to test them to see if they're valid in the current locale and escaping the invalid ones. All control characters (but never tabs) are always escaped, regardless of this option's setting.

The escape idiom that started in 2.6.7 is to output a literal backslash (\) and a hash (#), followed by exactly 3 octal digits. For example, a newline would output as "\#012". A literal backslash that is in a filename is not escaped unless it is followed by a hash and 3 digits (0-9).

--human-readable, -h

Output numbers in a more human-readable format. There are 3 possible levels:

  1. output numbers with a separator between each set of 3 digits (either a comma or a period, depending on if the decimal point is represented by a period or a comma).
  2. output numbers in units of 1000 (with a character suffix for larger units -⁠-⁠ see below).
  3. output numbers in units of 1024.

The default is human-readable level 1. Each -h option increases the level by one. You can take the level down to 0 (to output numbers as pure digits) by specifying the --no-human-readable (--no-h) option.

The unit letters that are appended in levels 2 and 3 are: K (kilo), M (mega), G (giga), T (tera), or P (peta). For example, a 1234567-byte file would output as 1.23M in level-2 (assuming that a period is your local decimal point).

Backward compatibility note: versions of rsync prior to 3.1.0 do not support human-readable level 1, and they default to level 0. Thus, specifying one or two -h options will behave in a comparable manner in old and new versions as long as you didn't specify a --no-h option prior to one or more -h options. See the --list-only option for one difference.

--partial

By default, rsync will delete any partially transferred file if the transfer is interrupted. In some circumstances it is more desirable to keep partially transferred files. Using the --partial option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster.

--partial-dir=DIR

This option modifies the behavior of the --partial option while also implying that it be enabled. This enhanced partial-file method puts any partially transferred files into the specified DIR instead of writing the partial file out to the destination file. On the next transfer, rsync will use a file found in this dir as data to speed up the resumption of the transfer and then delete it after it has served its purpose.

Note that if --whole-file is specified (or implied), any partial-dir files that are found for a file that is being updated will simply be removed (since rsync is sending files without using rsync's delta-transfer algorithm).

Rsync will create the DIR if it is missing, but just the last dir -⁠-⁠ not the whole path. This makes it easy to use a relative path (such as "--partial-dir=.rsync-partial") to have rsync create the partial-directory in the destination file's directory when it is needed, and then remove it again when the partial file is deleted. Note that this directory removal is only done for a relative pathname, as it is expected that an absolute path is to a directory that is reserved for partial-dir work.

If the partial-dir value is not an absolute path, rsync will add an exclude rule at the end of all your existing excludes. This will prevent the sending of any partial-dir files that may exist on the sending side, and will also prevent the untimely deletion of partial-dir items on the receiving side. An example: the above --partial-dir option would add the equivalent of this "perishable" exclude at the end of any other filter rules: -f '-p .rsync-partial/'

If you are supplying your own exclude rules, you may need to add your own exclude/hide/protect rule for the partial-dir because:

  1. the auto-added rule may be ineffective at the end of your other rules, or
  2. you may wish to override rsync's exclude choice.

For instance, if you want to make rsync clean-up any left-over partial-dirs that may be lying around, you should specify --delete-after and add a "risk" filter rule, e.g. -f 'R .rsync-partial/'. Avoid using --delete-before or --delete-during unless you don't need rsync to use any of the left-over partial-dir data during the current run.

IMPORTANT: the --partial-dir should not be writable by other users or it is a security risk! E.g. AVOID "/tmp"!

You can also set the partial-dir value the RSYNC_PARTIAL_DIR environment variable. Setting this in the environment does not force --partial to be enabled, but rather it affects where partial files go when --partial is specified. For instance, instead of using --partial-dir=.rsync-tmp along with --progress, you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your environment and then use the -P option to turn on the use of the .rsync-tmp dir for partial transfers. The only times that the --partial option does not look for this environment value are:

  1. when --inplace was specified (since --inplace conflicts with --partial-dir), and
  2. when --delay-updates was specified (see below).

When a modern rsync resumes the transfer of a file in the partial-dir, that partial file is now updated in-place instead of creating yet another tmp-file copy (so it maxes out at dest + tmp instead of dest + partial + tmp). This requires both ends of the transfer to be at least version 3.2.0.

For the purposes of the daemon-config's "refuse options" setting, --partial-dir does not imply --partial. This is so that a refusal of the --partial option can be used to disallow the overwriting of destination files with a partial transfer, while still allowing the safer idiom provided by --partial-dir.

--delay-updates

This option puts the temporary file from each updated file into a holding directory until the end of the transfer, at which time all the files are renamed into place in rapid succession. This attempts to make the updating of the files a little more atomic. By default the files are placed into a directory named .~tmp~ in each file's destination directory, but if you've specified the --partial-dir option, that directory will be used instead. See the comments in the --partial-dir section for a discussion of how this .~tmp~ dir will be excluded from the transfer, and what you can do if you want rsync to cleanup old .~tmp~ dirs that might be lying around. Conflicts with --inplace and --append.

This option implies --no-inc-recursive since it needs the full file list in memory in order to be able to iterate over it at the end.

This option uses more memory on the receiving side (one bit per file transferred) and also requires enough free disk space on the receiving side to hold an additional copy of all the updated files. Note also that you should not use an absolute path to --partial-dir unless:

  1. there is no chance of any of the files in the transfer having the same name (since all the updated files will be put into a single directory if the path is absolute), and
  2. there are no mount points in the hierarchy (since the delayed updates will fail if they can't be renamed into place).

See also the "atomic-rsync" python script in the "support" subdir for an update algorithm that is even more atomic (it uses --link-dest and a parallel hierarchy of files).

--prune-empty-dirs, -m

This option tells the receiving rsync to get rid of empty directories from the file-list, including nested directories that have no non-directory children. This is useful for avoiding the creation of a bunch of useless directories when the sending rsync is recursively scanning a hierarchy of files using include/exclude/filter rules.

This option can still leave empty directories on the receiving side if you make use of TRANSFER_RULES.

Because the file-list is actually being pruned, this option also affects what directories get deleted when a delete is active. However, keep in mind that excluded files and directories can prevent existing items from being deleted due to an exclude both hiding source files and protecting destination files. See the perishable filter-rule option for how to avoid this.

You can prevent the pruning of certain empty directories from the file-list by using a global "protect" filter. For instance, this option would ensure that the directory "emptydir" was kept in the file-list:

--filter 'protect emptydir/'

Here's an example that copies all .pdf files in a hierarchy, only creating the necessary destination directories to hold the .pdf files, and ensures that any superfluous files and directories in the destination are removed (note the hide filter of non-directories being used instead of an exclude):

rsync -avm --del --include='*.pdf' -f 'hide,! */' src/ dest

If you didn't want to remove superfluous destination files, the more time-honored options of --include='*/' --exclude='*' would work fine in place of the hide-filter (if that is more natural to you).

--progress

This option tells rsync to print information showing the progress of the transfer. This gives a bored user something to watch. With a modern rsync this is the same as specifying --info=flist2,name,progress, but any user-supplied settings for those info flags takes precedence (e.g. --info=flist0 --progress).

While rsync is transferring a regular file, it updates a progress line that looks like this:

782448  63%  110.64kB/s    0:00:04

In this example, the receiver has reconstructed 782448 bytes or 63% of the sender's file, which is being reconstructed at a rate of 110.64 kilobytes per second, and the transfer will finish in 4 seconds if the current rate is maintained until the end.

These statistics can be misleading if rsync's delta-transfer algorithm is in use. For example, if the sender's file consists of the basis file followed by additional data, the reported rate will probably drop dramatically when the receiver gets to the literal data, and the transfer will probably take much longer to finish than the receiver estimated as it was finishing the matched part of the file.

When the file transfer finishes, rsync replaces the progress line with a summary line that looks like this:

1,238,099 100%  146.38kB/s    0:00:08  (xfr#5, to-chk=169/396)

In this example, the file was 1,238,099 bytes long in total, the average rate of transfer for the whole file was 146.38 kilobytes per second over the 8 seconds that it took to complete, it was the 5th transfer of a regular file during the current rsync session, and there are 169 more files for the receiver to check (to see if they are up-to-date or not) remaining out of the 396 total files in the file-list.

In an incremental recursion scan, rsync won't know the total number of files in the file-list until it reaches the ends of the scan, but since it starts to transfer files during the scan, it will display a line with the text "ir-chk" (for incremental recursion check) instead of "to-chk" until the point that it knows the full size of the list, at which point it will switch to using "to-chk". Thus, seeing "ir-chk" lets you know that the total count of files in the file list is still going to increase (and each time it does, the count of files left to check will increase by the number of the files added to the list).

-P

The -P option is equivalent to "--partial --progress". Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted.

There is also a --info=progress2 option that outputs statistics based on the whole transfer, rather than individual files. Use this flag without outputting a filename (e.g. avoid -v or specify --info=name0) if you want to see how the transfer is doing without scrolling the screen with a lot of names. (You don't need to specify the --progress option in order to use --info=progress2.)

Finally, you can get an instant progress report by sending rsync a signal of either SIGINFO or SIGVTALRM. On BSD systems, a SIGINFO is generated by typing a Ctrl+T (Linux doesn't currently support a SIGINFO signal). When the client-side process receives one of those signals, it sets a flag to output a single progress report which is output when the current file transfer finishes (so it may take a little time if a big file is being handled when the signal arrives). A filename is output (if needed) followed by the --info=progress2 format of progress info. If you don't know which of the 3 rsync processes is the client process, it's OK to signal all of them (since the non-client processes ignore the signal).

CAUTION: sending SIGVTALRM to an older rsync (pre-3.2.0) will kill it.

--password-file=FILE

This option allows you to provide a password for accessing an rsync daemon via a file or via standard input if FILE is -. The file should contain just the password on the first line (all other lines are ignored). Rsync will exit with an error if FILE is world readable or if a root-run rsync command finds a non-root-owned file.

This option does not supply a password to a remote shell transport such as ssh; to learn how to do that, consult the remote shell's documentation. When accessing an rsync daemon using a remote shell as the transport, this option only comes into effect after the remote shell finishes its authentication (i.e. if you have also specified a password in the daemon's config file).

--early-input=FILE

This option allows rsync to send up to 5K of data to the "early exec" script on its stdin. One possible use of this data is to give the script a secret that can be used to mount an encrypted filesystem (which you should unmount in the the "post-xfer exec" script).

The daemon must be at least version 3.2.1.

--list-only

This option will cause the source files to be listed instead of transferred. This option is inferred if there is a single source arg and no destination specified, so its main uses are:

  1. to turn a copy command that includes a destination arg into a file-listing command, or
  2. to be able to specify more than one source arg. Note: be sure to include the destination.

CAUTION: keep in mind that a source arg with a wild-card is expanded by the shell into multiple args, so it is never safe to try to specify a single wild-card arg to try to infer this option. A safe example is:

rsync -av --list-only foo* dest/

This option always uses an output format that looks similar to this:

drwxrwxr-x          4,096 2022/09/30 12:53:11 support
-rw-rw-r--             80 2005/01/11 10:37:37 support/Makefile

The only option that affects this output style is (as of 3.1.0) the --human-readable (-h) option. The default is to output sizes as byte counts with digit separators (in a 14-character-width column). Specifying at least one -h option makes the sizes output with unit suffixes. If you want old-style bytecount sizes without digit separators (and an 11-character-width column) use --no-h.

Compatibility note: when requesting a remote listing of files from an rsync that is version 2.6.3 or older, you may encounter an error if you ask for a non-recursive listing. This is because a file listing implies the --dirs option w/o --recursive, and older rsyncs don't have that option. To avoid this problem, either specify the --no-dirs option (if you don't need to expand a directory's content), or turn on recursion and exclude the content of subdirectories: -r --exclude='/*/*'.

--bwlimit=RATE

This option allows you to specify the maximum transfer rate for the data sent over the socket, specified in units per second. The RATE value can be suffixed with a string to indicate a size multiplier, and may be a fractional value (e.g. --bwlimit=1.5m). If no suffix is specified, the value will be assumed to be in units of 1024 bytes (as if "K" or "KiB" had been appended). See the --max-size option for a description of all the available suffixes. A value of 0 specifies no limit.

For backward-compatibility reasons, the rate limit will be rounded to the nearest KiB unit, so no rate smaller than 1024 bytes per second is possible.

Rsync writes data over the socket in blocks, and this option both limits the size of the blocks that rsync writes, and tries to keep the average transfer rate at the requested limit. Some burstiness may be seen where rsync writes out a block of data and then sleeps to bring the average rate into compliance.

Due to the internal buffering of data, the --progress option may not be an accurate reflection on how fast the data is being sent. This is because some files can show up as being rapidly sent when the data is quickly buffered, while other can show up as very slow when the flushing of the output buffer occurs. This may be fixed in a future version.

See also the daemon version of the --bwlimit option.

--stop-after=MINS, (--time-limit=MINS)

This option tells rsync to stop copying when the specified number of minutes has elapsed.

For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using --remote-option (-M), should the need arise.

The --time-limit version of this option is deprecated.

--stop-at=y-m-dTh:m

This option tells rsync to stop copying when the specified point in time has been reached. The date & time can be fully specified in a numeric format of year-month-dayThour:minute (e.g. 2000-12-31T23:59) in the local timezone. You may choose to separate the date numbers using slashes instead of dashes.

The value can also be abbreviated in a variety of ways, such as specifying a 2-digit year and/or leaving off various values. In all cases, the value will be taken to be the next possible point in time where the supplied information matches. If the value specifies the current time or a past time, rsync exits with an error.

For example, "1-30" specifies the next January 30th (at midnight local time), "14:00" specifies the next 2 P.M., "1" specifies the next 1st of the month at midnight, "31" specifies the next month where we can stop on its 31st day, and ":59" specifies the next 59th minute after the hour.

For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using --remote-option (-M), should the need arise. Do keep in mind that the remote host may have a different default timezone than your local host.

--fsync

Cause the receiving side to fsync each finished file. This may slow down the transfer, but can help to provide peace of mind when updating critical files.

--write-batch=FILE

Record a file that can later be applied to another identical destination with --read-batch. See the "BATCH MODE" section for details, and also the --only-write-batch option.

This option overrides the negotiated checksum & compress lists and always negotiates a choice based on old-school md5/md4/zlib choices. If you want a more modern choice, use the --checksum-choice (--cc) and/or --compress-choice (--zc) options.

--only-write-batch=FILE

Works like --write-batch, except that no updates are made on the destination system when creating the batch. This lets you transport the changes to the destination system via some other means and then apply the changes via --read-batch.

Note that you can feel free to write the batch directly to some portable media: if this media fills to capacity before the end of the transfer, you can just apply that partial transfer to the destination and repeat the whole process to get the rest of the changes (as long as you don't mind a partially updated destination system while the multi-update cycle is happening).

Also note that you only save bandwidth when pushing changes to a remote system because this allows the batched data to be diverted from the sender into the batch file without having to flow over the wire to the receiver (when pulling, the sender is remote, and thus can't write the batch).

--read-batch=FILE

Apply all of the changes stored in FILE, a file previously generated by --write-batch. If FILE is -, the batch data will be read from standard input. See the "BATCH MODE" section for details.

--protocol=NUM

Force an older protocol version to be used. This is useful for creating a batch file that is compatible with an older version of rsync. For instance, if rsync 2.6.4 is being used with the --write-batch option, but rsync 2.6.3 is what will be used to run the --read-batch option, you should use "-⁠-⁠protocol=28" when creating the batch file to force the older protocol version to be used in the batch file (assuming you can't upgrade the rsync on the reading system).

--iconv=CONVERT_SPEC

Rsync can convert filenames between character sets using this option. Using a CONVERT_SPEC of "." tells rsync to look up the default character-set via the locale setting. Alternately, you can fully specify what conversion to do by giving a local and a remote charset separated by a comma in the order --iconv=LOCAL,REMOTE, e.g. --iconv=utf8,iso88591. This order ensures that the option will stay the same whether you're pushing or pulling files. Finally, you can specify either --no-iconv or a CONVERT_SPEC of "-⁠" to turn off any conversion. The default setting of this option is site-specific, and can also be affected via the RSYNC_ICONV environment variable.

For a list of what charset names your local iconv library supports, you can run "iconv --list".

If you specify the --secluded-args (-s) option, rsync will translate the filenames you specify on the command-line that are being sent to the remote host. See also the --files-from option.

Note that rsync does not do any conversion of names in filter files (including include/exclude files). It is up to you to ensure that you're specifying matching rules that can match on both sides of the transfer. For instance, you can specify extra include/exclude rules if there are filename differences on the two sides that need to be accounted for.

When you pass an --iconv option to an rsync daemon that allows it, the daemon uses the charset specified in its "charset" configuration parameter regardless of the remote charset you actually pass. Thus, you may feel free to specify just the local charset for a daemon transfer (e.g. --iconv=utf8).

--ipv4, -4 or --ipv6, -6

Tells rsync to prefer IPv4/IPv6 when creating sockets or running ssh. This affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an rsync daemon, as well as the forwarding of the -4 or -6 option to ssh when rsync can deduce that ssh is being used as the remote shell. For other remote shells you'll need to specify the "--rsh SHELL -4" option directly (or whatever IPv4/IPv6 hint options it uses).

See also the daemon version of these options.

If rsync was compiled without support for IPv6, the --ipv6 option will have no effect. The rsync --version output will contain "no IPv6" if is the case.

--checksum-seed=NUM

Set the checksum seed to the integer NUM. This 4 byte checksum seed is included in each block and MD4 file checksum calculation (the more modern MD5 file checksums don't use a seed). By default the checksum seed is generated by the server and defaults to the current time(). This option is used to set a specific checksum seed, which is useful for applications that want repeatable block checksums, or in the case where the user wants a more random checksum seed. Setting NUM to 0 causes rsync to use the default of time() for checksum seed.

DAEMON OPTIONS

The options allowed when starting an rsync daemon are as follows:

--daemon

This tells rsync that it is to run as a daemon. The daemon you start running may be accessed using an rsync client using the host::module or rsync://host/module/ syntax.

If standard input is a socket then rsync will assume that it is being run via inetd, otherwise it will detach from the current terminal and become a background daemon. The daemon will read the config file (rsyncd.conf) on each connect made by a client and respond to requests accordingly.

See the rsyncd.conf(5) manpage for more details.

--address=ADDRESS

By default rsync will bind to the wildcard address when run as a daemon with the --daemon option. The --address option allows you to specify a specific IP address (or hostname) to bind to. This makes virtual hosting possible in conjunction with the --config option.

See also the address global option in the rsyncd.conf manpage and the client version of the --address option.

--bwlimit=RATE

This option allows you to specify the maximum transfer rate for the data the daemon sends over the socket. The client can still specify a smaller --bwlimit value, but no larger value will be allowed.

See the client version of the --bwlimit option for some extra details.

--config=FILE

This specifies an alternate config file than the default. This is only relevant when --daemon is specified. The default is /etc/rsyncd.conf unless the daemon is running over a remote shell program and the remote user is not the super-user; in that case the default is rsyncd.conf in the current directory (typically $HOME).

--dparam=OVERRIDE, -M

This option can be used to set a daemon-config parameter when starting up rsync in daemon mode. It is equivalent to adding the parameter at the end of the global settings prior to the first module's definition. The parameter names can be specified without spaces, if you so desire. For instance:

rsync --daemon -M pidfile=/path/rsync.pid
--no-detach

When running as a daemon, this option instructs rsync to not detach itself and become a background process. This option is required when running as a service on Cygwin, and may also be useful when rsync is supervised by a program such as daemontools or AIX's System Resource Controller. --no-detach is also recommended when rsync is run under a debugger. This option has no effect if rsync is run from inetd or sshd.

--port=PORT

This specifies an alternate TCP port number for the daemon to listen on rather than the default of 873.

See also the client version of the --port option and the port global setting in the rsyncd.conf manpage.

--log-file=FILE

This option tells the rsync daemon to use the given log-file name instead of using the "log file" setting in the config file.

See also the client version of the --log-file option.

--log-file-format=FORMAT

This option tells the rsync daemon to use the given FORMAT string instead of using the "log format" setting in the config file. It also enables "transfer logging" unless the string is empty, in which case transfer logging is turned off.

See also the client version of the --log-file-format option.

--sockopts

This overrides the socket options setting in the rsyncd.conf file and has the same syntax.

See also the client version of the --sockopts option.

--verbose, -v

This option increases the amount of information the daemon logs during its startup phase. After the client connects, the daemon's verbosity level will be controlled by the options that the client used and the "max verbosity" setting in the module's config section.

See also the client version of the --verbose option.

--ipv4, -4 or --ipv6, -6

Tells rsync to prefer IPv4/IPv6 when creating the incoming sockets that the rsync daemon will use to listen for connections. One of these options may be required in older versions of Linux to work around an IPv6 bug in the kernel (if you see an "address already in use" error when nothing else is using the port, try specifying --ipv6 or --ipv4 when starting the daemon).

See also the client version of these options.

If rsync was compiled without support for IPv6, the --ipv6 option will have no effect. The rsync --version output will contain "no IPv6" if is the case.

--help, -h

When specified after --daemon, print a short help page describing the options available for starting an rsync daemon.

FILTER RULES

The filter rules allow for custom control of several aspects of how files are handled:

  • Control which files the sending side puts into the file list that describes the transfer hierarchy
  • Control which files the receiving side protects from deletion when the file is not in the sender's file list
  • Control which extended attribute names are skipped when copying xattrs

The rules are either directly specified via option arguments or they can be read in from one or more files. The filter-rule files can even be a part of the hierarchy of files being copied, affecting different parts of the tree in different ways.

SIMPLE INCLUDE/EXCLUDE RULES

We will first cover the basics of how include & exclude rules affect what files are transferred, ignoring any deletion side-effects. Filter rules mainly affect the contents of directories that rsync is "recursing" into, but they can also affect a top-level item in the transfer that was specified as a argument.

The default for any unmatched file/dir is for it to be included in the transfer, which puts the file/dir into the sender's file list. The use of an exclude rule causes one or more matching files/dirs to be left out of the sender's file list. An include rule can be used to limit the effect of an exclude rule that is matching too many files.

The order of the rules is important because the first rule that matches is the one that takes effect. Thus, if an early rule excludes a file, no include rule that comes after it can have any effect. This means that you must place any include overrides somewhere prior to the exclude that it is intended to limit.

When a directory is excluded, all its contents and sub-contents are also excluded. The sender doesn't scan through any of it at all, which can save a lot of time when skipping large unneeded sub-trees.

It is also important to understand that the include/exclude rules are applied to every file and directory that the sender is recursing into. Thus, if you want a particular deep file to be included, you have to make sure that none of the directories that must be traversed on the way down to that file are excluded or else the file will never be discovered to be included. As an example, if the directory "a/path" was given as a transfer argument and you want to ensure that the file "a/path/down/deep/wanted.txt" is a part of the transfer, then the sender must not exclude the directories "a/path", "a/path/down", or "a/path/down/deep" as it makes it way scanning through the file tree.

When you are working on the rules, it can be helpful to ask rsync to tell you what is being excluded/included and why. Specifying --debug=FILTER or (when pulling files) -M--debug=FILTER turns on level 1 of the FILTER debug information that will output a message any time that a file or directory is included or excluded and which rule it matched. Beginning in 3.2.4 it will also warn if a filter rule has trailing whitespace, since an exclude of "foo " (with a trailing space) will not exclude a file named "foo".

Exclude and include rules can specify wildcard PATTERN MATCHING RULES (similar to shell wildcards) that allow you to match things like a file suffix or a portion of a filename.

A rule can be limited to only affecting a directory by putting a trailing slash onto the filename.

SIMPLE INCLUDE/EXCLUDE EXAMPLE

With the following file tree created on the sending side:

mkdir x/
touch x/file.txt
mkdir x/y/
touch x/y/file.txt
touch x/y/zzz.txt
mkdir x/z/
touch x/z/file.txt

Then the following rsync command will transfer the file "x/y/file.txt" and the directories needed to hold it, resulting in the path "/tmp/x/y/file.txt" existing on the remote host:

rsync -ai -f'+ x/' -f'+ x/y/' -f'+ x/y/file.txt' -f'- *' x host:/tmp/

Aside: this copy could also have been accomplished using the -R option (though the 2 commands behave differently if deletions are enabled):

rsync -aiR x/y/file.txt host:/tmp/

The following command does not need an include of the "x" directory because it is not a part of the transfer (note the traililng slash). Running this command would copy just "/tmp/x/file.txt" because the "y" and "z" dirs get excluded:

rsync -ai -f'+ file.txt' -f'- *' x/ host:/tmp/x/

This command would omit the zzz.txt file while copying "x" and everything else it contains:

rsync -ai -f'- zzz.txt' x host:/tmp/

FILTER RULES WHEN DELETING

By default the include & exclude filter rules affect both the sender (as it creates its file list) and the receiver (as it creates its file lists for calculating deletions). If no delete option is in effect, the receiver skips creating the delete-related file lists. This two-sided default can be manually overridden so that you are only specifying sender rules or receiver rules, as described in the FILTER RULES IN DEPTH section.

When deleting, an exclude protects a file from being removed on the receiving side while an include overrides that protection (putting the file at risk of deletion). The default is for a file to be at risk -⁠-⁠ its safety depends on it matching a corresponding file from the sender.

An example of the two-sided exclude effect can be illustrated by the copying of a C development directory between 2 systems. When doing a touch-up copy, you might want to skip copying the built executable and the .o files (sender hide) so that the receiving side can build their own and not lose any object files that are already correct (receiver protect). For instance:

rsync -ai --del -f'- *.o' -f'- cmd' src host:/dest/

Note that using -f'-p *.o' is even better than -f'- *.o' if there is a chance that the directory structure may have changed. The "p" modifier is discussed in FILTER RULE MODIFIERS.

One final note, if your shell doesn't mind unexpanded wildcards, you could simplify the typing of the filter options by using an underscore in place of the space and leaving off the quotes. For instance, -f -_*.o -f -_cmd (and similar) could be used instead of the filter options above.

FILTER RULES IN DEPTH

Rsync supports old-style include/exclude rules and new-style filter rules. The older rules are specified using --include and --exclude as well as the --include-from and --exclude-from. These are limited in behavior but they don't require a "-⁠" or "+" prefix. An old-style exclude rule is turned into a "- name" filter rule (with no modifiers) and an old-style include rule is turned into a "+ name" filter rule (with no modifiers).

Rsync builds an ordered list of filter rules as specified on the command-line and/or read-in from files. New style filter rules have the following syntax:

RULE [PATTERN_OR_FILENAME]
RULE,MODIFIERS [PATTERN_OR_FILENAME]

You have your choice of using either short or long RULE names, as described below. If you use a short-named rule, the ',' separating the RULE from the MODIFIERS is optional. The PATTERN or FILENAME that follows (when present) must come after either a single space or an underscore (_). Any additional spaces and/or underscores are considered to be a part of the pattern name. Here are the available rule prefixes:

exclude, '-'
specifies an exclude pattern that (by default) is both a hide and a protect.
include, '+'
specifies an include pattern that (by default) is both a show and a risk.
merge, '.'
specifies a merge-file on the client side to read for more rules.
dir-merge, ':'
specifies a per-directory merge-file. Using this kind of filter rule requires that you trust the sending side's filter checking, so it has the side-effect mentioned under the --trust-sender option.
hide, 'H'
specifies a pattern for hiding files from the transfer. Equivalent to a sender-only exclude, so -f'H foo' could also be specified as -f'-s foo'.
show, 'S'
files that match the pattern are not hidden. Equivalent to a sender-only include, so -f'S foo' could also be specified as -f'+s foo'.
protect, 'P'
specifies a pattern for protecting files from deletion. Equivalent to a receiver-only exclude, so -f'P foo' could also be specified as -f'-r foo'.
risk, 'R'
files that match the pattern are not protected. Equivalent to a receiver-only include, so -f'R foo' could also be specified as -f'+r foo'.
clear, '!'
clears the current include/exclude list (takes no arg)

When rules are being read from a file (using merge or dir-merge), empty lines are ignored, as are whole-line comments that start with a '#' (filename rules that contain a hash character are unaffected).

Note also that the --filter, --include, and --exclude options take one rule/pattern each. To add multiple ones, you can repeat the options on the command-line, use the merge-file syntax of the --filter option, or the --include-from / --exclude-from options.

PATTERN MATCHING RULES

Most of the rules mentioned above take an argument that specifies what the rule should match. If rsync is recursing through a directory hierarchy, keep in mind that each pattern is matched against the name of every directory in the descent path as rsync finds the filenames to send.

The matching rules for the pattern argument take several forms:

  • If a pattern contains a / (not counting a trailing slash) or a "**" (which can match a slash), then the pattern is matched against the full pathname, including any leading directories within the transfer. If the pattern doesn't contain a (non-trailing) / or a "**", then it is matched only against the final component of the filename or pathname. For example, foo means that the final path component must be "foo" while foo/bar would match the last 2 elements of the path (as long as both elements are within the transfer).
  • A pattern that ends with a / only matches a directory, not a regular file, symlink, or device.
  • A pattern that starts with a / is anchored to the start of the transfer path instead of the end. For example, /foo/** or /foo/bar/** match only leading elements in the path. If the rule is read from a per-directory filter file, the transfer path being matched will begin at the level of the filter file instead of the top of the transfer. See the section on ANCHORING INCLUDE/EXCLUDE PATTERNS for a full discussion of how to specify a pattern that matches at the root of the transfer.

Rsync chooses between doing a simple string match and wildcard matching by checking if the pattern contains one of these three wildcard characters: '*', '?', and '[' :

  • a '?' matches any single character except a slash (/).
  • a '*' matches zero or more non-slash characters.
  • a '**' matches zero or more characters, including slashes.
  • a '[' introduces a character class, such as [a-z] or [[:alpha:]], that must match one character.
  • a trailing *** in the pattern is a shorthand that allows you to match a directory and all its contents using a single rule. For example, specifying "dir_name/***" will match both the "dir_name" directory (as if "dir_name/" had been specified) and everything in the directory (as if "dir_name/**" had been specified).
  • a backslash can be used to escape a wildcard character, but it is only interpreted as an escape character if at least one wildcard character is present in the match pattern. For instance, the pattern "foo\bar" matches that single backslash literally, while the pattern "foo\bar*" would need to be changed to "foo\\bar*" to avoid the "\b" becoming just "b".

Here are some examples of exclude/include matching:

  • Option -f'- *.o' would exclude all filenames ending with .o
  • Option -f'- /foo' would exclude a file (or directory) named foo in the transfer-root directory
  • Option -f'- foo/' would exclude any directory named foo
  • Option -f'- foo/*/bar' would exclude any file/dir named bar which is at two levels below a directory named foo (if foo is in the transfer)
  • Option -f'- /foo/**/bar' would exclude any file/dir named bar that was two or more levels below a top-level directory named foo (note that /foo/bar is not excluded by this)
  • Options -f'+ */' -f'+ *.c' -f'- *' would include all directories and .c source files but nothing else
  • Options -f'+ foo/' -f'+ foo/bar.c' -f'- *' would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "- *")

FILTER RULE MODIFIERS

The following modifiers are accepted after an include (+) or exclude (-⁠) rule:

  • A / specifies that the include/exclude rule should be matched against the absolute pathname of the current item. For example, -f'-/ /etc/passwd' would exclude the passwd file any time the transfer was sending files from the "/etc" directory, and "-⁠/ subdir/foo" would always exclude "foo" when it is in a dir named "subdir", even if "foo" is at the root of the current transfer.
  • A ! specifies that the include/exclude should take effect if the pattern fails to match. For instance, -f'-! */' would exclude all non-directories.
  • A C is used to indicate that all the global CVS-exclude rules should be inserted as excludes in place of the "-⁠C". No arg should follow.
  • An s is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it affects what files are put into the sender's file list. The default is for a rule to affect both sides unless --delete-excluded was specified, in which case default rules become sender-side only. See also the hide (H) and show (S) rules, which are an alternate way to specify sending-side includes/excludes.
  • An r is used to indicate that the rule applies to the receiving side. When a rule affects the receiving side, it prevents files from being deleted. See the s modifier for more info. See also the protect (P) and risk (R) rules, which are an alternate way to specify receiver-side includes/excludes.
  • A p indicates that a rule is perishable, meaning that it is ignored in directories that are being deleted. For instance, the --cvs-exclude (-C) option's default rules that exclude things like "CVS" and "*.o" are marked as perishable, and will not prevent a directory that was removed on the source from being deleted on the destination.
  • An x indicates that a rule affects xattr names in xattr copy/delete operations (and is thus ignored when matching file/dir names). If no xattr-matching rules are specified, a default xattr filtering rule is used (see the --xattrs option).

MERGE-FILE FILTER RULES

You can merge whole files into your filter rules by specifying either a merge (.) or a dir-merge (:) filter rule (as introduced in the FILTER RULES section above).

There are two kinds of merged files -⁠-⁠ single-instance ('.') and per-directory (':'). A single-instance merge file is read one time, and its rules are incorporated into the filter list in the place of the "." rule. For per-directory merge files, rsync will scan every directory that it traverses for the named file, merging its contents when the file exists into the current list of inherited rules. These per-directory rule files must be created on the sending side because it is the sending side that is being scanned for the available files to transfer. These rule files may also need to be transferred to the receiving side if you want them to affect what files don't get deleted (see PER-DIRECTORY RULES AND DELETE below).

Some examples:

merge /etc/rsync/default.rules
. /etc/rsync/default.rules
dir-merge .per-dir-filter
dir-merge,n- .non-inherited-per-dir-excludes
:n- .non-inherited-per-dir-excludes

The following modifiers are accepted after a merge or dir-merge rule:

  • A - specifies that the file should consist of only exclude patterns, with no other rule-parsing except for in-file comments.
  • A + specifies that the file should consist of only include patterns, with no other rule-parsing except for in-file comments.
  • A C is a way to specify that the file should be read in a CVS-compatible manner. This turns on 'n', 'w', and '-⁠', but also allows the list-clearing token (!) to be specified. If no filename is provided, ".cvsignore" is assumed.
  • A e will exclude the merge-file name from the transfer; e.g. "dir-merge,e .rules" is like "dir-merge .rules" and "-⁠ .rules".
  • An n specifies that the rules are not inherited by subdirectories.
  • A w specifies that the rules are word-split on whitespace instead of the normal line-splitting. This also turns off comments. Note: the space that separates the prefix from the rule is treated specially, so "-⁠ foo + bar" is parsed as two rules (assuming that prefix-parsing wasn't also disabled).
  • You may also specify any of the modifiers for the "+" or "-⁠" rules (above) in order to have the rules that are read in from the file default to having that modifier set (except for the ! modifier, which would not be useful). For instance, "merge,-⁠/ .excl" would treat the contents of .excl as absolute-path excludes, while "dir-merge,s .filt" and ":sC" would each make all their per-directory rules apply only on the sending side. If the merge rule specifies sides to affect (via the s or r modifier or both), then the rules in the file must not specify sides (via a modifier or a rule prefix such as hide).

Per-directory rules are inherited in all subdirectories of the directory where the merge-file was found unless the 'n' modifier was used. Each subdirectory's rules are prefixed to the inherited per-directory rules from its parents, which gives the newest rules a higher priority than the inherited rules. The entire set of dir-merge rules are grouped together in the spot where the merge-file was specified, so it is possible to override dir-merge rules via a rule that got specified earlier in the list of global rules. When the list-clearing rule ("!") is read from a per-directory file, it only clears the inherited rules for the current merge file.

Another way to prevent a single rule from a dir-merge file from being inherited is to anchor it with a leading slash. Anchored rules in a per-directory merge-file are relative to the merge-file's directory, so a pattern "/foo" would only match the file "foo" in the directory where the dir-merge filter file was found.

Here's an example filter file which you'd specify via --filter=". file":

merge /home/user/.global-filter
- *.gz
dir-merge .rules
+ *.[ch]
- *.o
- foo*

This will merge the contents of the /home/user/.global-filter file at the start of the list and also turns the ".rules" filename into a per-directory filter file. All rules read in prior to the start of the directory scan follow the global anchoring rules (i.e. a leading slash matches at the root of the transfer).

If a per-directory merge-file is specified with a path that is a parent directory of the first transfer directory, rsync will scan all the parent dirs from that starting point to the transfer directory for the indicated per-directory file. For instance, here is a common filter (see -F):

--filter=': /.rsync-filter'

That rule tells rsync to scan for the file .rsync-filter in all directories from the root down through the parent directory of the transfer prior to the start of the normal directory scan of the file in the directories that are sent as a part of the transfer. (Note: for an rsync daemon, the root is always the same as the module's "path".)

Some examples of this pre-scanning for per-directory files:

rsync -avF /src/path/ /dest/dir
rsync -av --filter=': ../../.rsync-filter' /src/path/ /dest/dir
rsync -av --filter=': .rsync-filter' /src/path/ /dest/dir

The first two commands above will look for ".rsync-filter" in "/" and "/src" before the normal scan begins looking for the file in "/src/path" and its subdirectories. The last command avoids the parent-dir scan and only looks for the ".rsync-filter" files in each directory that is a part of the transfer.

If you want to include the contents of a ".cvsignore" in your patterns, you should use the rule ":C", which creates a dir-merge of the .cvsignore file, but parsed in a CVS-compatible manner. You can use this to affect where the --cvs-exclude (-C) option's inclusion of the per-directory .cvsignore file gets placed into your rules by putting the ":C" wherever you like in your filter rules. Without this, rsync would add the dir-merge rule for the .cvsignore file at the end of all your other rules (giving it a lower priority than your command-line rules). For example:

cat <<EOT | rsync -avC --filter='. -' a/ b
+ foo.o
:C
- *.old
EOT
rsync -avC --include=foo.o -f :C --exclude='*.old' a/ b

Both of the above rsync commands are identical. Each one will merge all the per-directory .cvsignore rules in the middle of the list rather than at the end. This allows their dir-specific rules to supersede the rules that follow the :C instead of being subservient to all your rules. To affect the other CVS exclude rules (i.e. the default list of exclusions, the contents of $HOME/.cvsignore, and the value of $CVSIGNORE) you should omit the -C command-line option and instead insert a "-⁠C" rule into your filter rules; e.g. "--filter=-C".

LIST-CLEARING FILTER RULE

You can clear the current include/exclude list by using the "!" filter rule (as introduced in the FILTER RULES section above). The "current" list is either the global list of rules (if the rule is encountered while parsing the filter options) or a set of per-directory rules (which are inherited in their own sub-list, so a subdirectory can use this to clear out the parent's rules).

ANCHORING INCLUDE/EXCLUDE PATTERNS

As mentioned earlier, global include/exclude patterns are anchored at the "root of the transfer" (as opposed to per-directory patterns, which are anchored at the merge-file's directory). If you think of the transfer as a subtree of names that are being sent from sender to receiver, the transfer-root is where the tree starts to be duplicated in the destination directory. This root governs where patterns that start with a / match.

Because the matching is relative to the transfer-root, changing the trailing slash on a source path or changing your use of the --relative option affects the path you need to use in your matching (in addition to changing how much of the file tree is duplicated on the destination host). The following examples demonstrate this.

Let's say that we want to match two source files, one with an absolute path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz". Here is how the various command choices differ for a 2-source transfer:

Example cmd: rsync -a /home/me /home/you /dest
+/- pattern: /me/foo/bar
+/- pattern: /you/bar/baz
Target file: /dest/me/foo/bar
Target file: /dest/you/bar/baz
Example cmd: rsync -a /home/me/ /home/you/ /dest
+/- pattern: /foo/bar               (note missing "me")
+/- pattern: /bar/baz               (note missing "you")
Target file: /dest/foo/bar
Target file: /dest/bar/baz
Example cmd: rsync -a --relative /home/me/ /home/you /dest
+/- pattern: /home/me/foo/bar       (note full path)
+/- pattern: /home/you/bar/baz      (ditto)
Target file: /dest/home/me/foo/bar
Target file: /dest/home/you/bar/baz
Example cmd: cd /home; rsync -a --relative me/foo you/ /dest
+/- pattern: /me/foo/bar      (starts at specified path)
+/- pattern: /you/bar/baz     (ditto)
Target file: /dest/me/foo/bar
Target file: /dest/you/bar/baz

The easiest way to see what name you should filter is to just look at the output when using --verbose and put a / in front of the name (use the --dry-run option if you're not yet ready to copy any files).

PER-DIRECTORY RULES AND DELETE

Without a delete option, per-directory rules are only relevant on the sending side, so you can feel free to exclude the merge files themselves without affecting the transfer. To make this easy, the 'e' modifier adds this exclude for you, as seen in these two equivalent commands:

rsync -av --filter=': .excl' --exclude=.excl host:src/dir /dest
rsync -av --filter=':e .excl' host:src/dir /dest

However, if you want to do a delete on the receiving side AND you want some files to be excluded from being deleted, you'll need to be sure that the receiving side knows what files to exclude. The easiest way is to include the per-directory merge files in the transfer and use --delete-after, because this ensures that the receiving side gets all the same exclude rules as the sending side before it tries to delete anything:

rsync -avF --delete-after host:src/dir /dest

However, if the merge files are not a part of the transfer, you'll need to either specify some global exclude rules (i.e. specified on the command line), or you'll need to maintain your own per-directory merge files on the receiving side. An example of the first is this (assume that the remote .rules files exclude themselves):

rsync -av --filter=': .rules' --filter='. /my/extra.rules'
   --delete host:src/dir /dest

In the above example the extra.rules file can affect both sides of the transfer, but (on the sending side) the rules are subservient to the rules merged from the .rules files because they were specified after the per-directory merge rule.

In one final example, the remote side is excluding the .rsync-filter files from the transfer, but we want to use our own .rsync-filter files to control what gets deleted on the receiving side. To do this we must specifically exclude the per-directory merge files (so that they don't get deleted) and then put rules into the local files to control what else should not get deleted. Like one of these commands:

rsync -av --filter=':e /.rsync-filter' --delete \
    host:src/dir /dest
rsync -avFF --delete host:src/dir /dest

TRANSFER RULES

In addition to the FILTER RULES that affect the recursive file scans that generate the file list on the sending and (when deleting) receiving sides, there are transfer rules. These rules affect which files the generator decides need to be transferred without the side effects of an exclude filter rule. Transfer rules affect only files and never directories.

Because a transfer rule does not affect what goes into the sender's (and receiver's) file list, it cannot have any effect on which files get deleted on the receiving side. For example, if the file "foo" is present in the sender's list but its size is such that it is omitted due to a transfer rule, the receiving side does not request the file. However, its presence in the file list means that a delete pass will not remove a matching file named "foo" on the receiving side. On the other hand, a server-side exclude (hide) of the file "foo" leaves the file out of the server's file list, and absent a receiver-side exclude (protect) the receiver will remove a matching file named "foo" if deletions are requested.

Given that the files are still in the sender's file list, the --prune-empty-dirs option will not judge a directory as being empty even if it contains only files that the transfer rules omitted.

Similarly, a transfer rule does not have any extra effect on which files are deleted on the receiving side, so setting a maximum file size for the transfer does not prevent big files from being deleted.

Examples of transfer rules include the default "quick check" algorithm (which compares size & modify time), the --update option, the --max-size option, the --ignore-non-existing option, and a few others.

BATCH MODE

Batch mode can be used to apply the same set of updates to many identical systems. Suppose one has a tree which is replicated on a number of hosts. Now suppose some changes have been made to this source tree and those changes need to be propagated to the other hosts. In order to do this using batch mode, rsync is run with the write-batch option to apply the changes made to the source tree to one of the destination trees. The write-batch option causes the rsync client to store in a "batch file" all the information needed to repeat this operation against other, identical destination trees.

Generating the batch file once saves having to perform the file status, checksum, and data block generation more than once when updating multiple destination trees. Multicast transport protocols can be used to transfer the batch update files in parallel to many hosts at once, instead of sending the same data to every host individually.

To apply the recorded changes to another destination tree, run rsync with the read-batch option, specifying the name of the same batch file, and the destination tree. Rsync updates the destination tree using the information stored in the batch file.

For your convenience, a script file is also created when the write-batch option is used: it will be named the same as the batch file with ".sh" appended. This script file contains a command-line suitable for updating a destination tree using the associated batch file. It can be executed using a Bourne (or Bourne-like) shell, optionally passing in an alternate destination tree pathname which is then used instead of the original destination path. This is useful when the destination tree path on the current host differs from the one used to create the batch file.

Examples:

$ rsync --write-batch=foo -a host:/source/dir/ /adest/dir/
$ scp foo* remote:
$ ssh remote ./foo.sh /bdest/dir/
$ rsync --write-batch=foo -a /source/dir/ /adest/dir/
$ ssh remote rsync --read-batch=- -a /bdest/dir/ <foo

In these examples, rsync is used to update /adest/dir/ from /source/dir/ and the information to repeat this operation is stored in "foo" and "foo.sh". The host "remote" is then updated with the batched data going into the directory /bdest/dir. The differences between the two examples reveals some of the flexibility you have in how you deal with batches:

  • The first example shows that the initial copy doesn't have to be local -⁠-⁠ you can push or pull data to/from a remote host using either the remote-shell syntax or rsync daemon syntax, as desired.
  • The first example uses the created "foo.sh" file to get the right rsync options when running the read-batch command on the remote host.
  • The second example reads the batch data via standard input so that the batch file doesn't need to be copied to the remote machine first. This example avoids the foo.sh script because it needed to use a modified --read-batch option, but you could edit the script file if you wished to make use of it (just be sure that no other option is trying to use standard input, such as the --exclude-from=- option).

Caveats:

The read-batch option expects the destination tree that it is updating to be identical to the destination tree that was used to create the batch update fileset. When a difference between the destination trees is encountered the update might be discarded with a warning (if the file appears to be up-to-date already) or the file-update may be attempted and then, if the file fails to verify, the update discarded with an error. This means that it should be safe to re-run a read-batch operation if the command got interrupted. If you wish to force the batched-update to always be attempted regardless of the file's size and date, use the -I option (when reading the batch). If an error occurs, the destination tree will probably be in a partially updated state. In that case, rsync can be used in its regular (non-batch) mode of operation to fix up the destination tree.

The rsync version used on all destinations must be at least as new as the one used to generate the batch file. Rsync will die with an error if the protocol version in the batch file is too new for the batch-reading rsync to handle. See also the --protocol option for a way to have the creating rsync generate a batch file that an older rsync can understand. (Note that batch files changed format in version 2.6.3, so mixing versions older than that with newer versions will not work.)

When reading a batch file, rsync will force the value of certain options to match the data in the batch file if you didn't set them to the same as the batch-writing command. Other options can (and should) be changed. For instance --write-batch changes to --read-batch, --files-from is dropped, and the --filter / --include / --exclude options are not needed unless one of the --delete options is specified.

The code that creates the BATCH.sh file transforms any filter/include/exclude options into a single list that is appended as a "here" document to the shell script file. An advanced user can use this to modify the exclude list if a change in what gets deleted by --delete is desired. A normal user can ignore this detail and just use the shell script as an easy way to run the appropriate --read-batch command for the batched data.

The original batch mode in rsync was based on "rsync+", but the latest version uses a new implementation.

Three basic behaviors are possible when rsync encounters a symbolic link in the source directory.

By default, symbolic links are not transferred at all. A message "skipping non-regular" file is emitted for any symlinks that exist.

If --links is specified, then symlinks are added to the transfer (instead of being noisily ignored), and the default handling is to recreate them with the same target on the destination. Note that --archive implies --links.

If --copy-links is specified, then symlinks are "collapsed" by copying their referent, rather than the symlink.

Rsync can also distinguish "safe" and "unsafe" symbolic links. An example where this might be used is a web site mirror that wishes to ensure that the rsync module that is copied does not include symbolic links to /etc/passwd in the public section of the site. Using --copy-unsafe-links will cause any links to be copied as the file they point to on the destination. Using --safe-links will cause unsafe links to be omitted by the receiver. (Note that you must specify or imply --links for --safe-links to have any effect.)

Symbolic links are considered unsafe if they are absolute symlinks (start with /), empty, or if they contain enough ".." components to ascend from the top of the transfer.

Here's a summary of how the symlink options are interpreted. The list is in order of precedence, so if your combination of options isn't mentioned, use the first line that is a complete subset of your options:

--copy-links
Turn all symlinks into normal files and directories (leaving no symlinks in the transfer for any other options to affect).
--copy-dirlinks
Turn just symlinks to directories into real directories, leaving all other symlinks to be handled as described below.
--links --copy-unsafe-links
Turn all unsafe symlinks into files and create all safe symlinks.
--copy-unsafe-links
Turn all unsafe symlinks into files, noisily skip all safe symlinks.
--links --safe-links
The receiver skips creating unsafe symlinks found in the transfer and creates the safe ones.
--links
Create all symlinks.

For the effect of --munge-links, see the discussion in that option's section.

Note that the --keep-dirlinks option does not effect symlinks in the transfer but instead affects how rsync treats a symlink to a directory that already exists on the receiving side. See that option's section for a warning.

DIAGNOSTICS

Rsync occasionally produces error messages that may seem a little cryptic. The one that seems to cause the most confusion is "protocol version mismatch -⁠-⁠ is your shell clean?".

This message is usually caused by your startup scripts or remote shell facility producing unwanted garbage on the stream that rsync is using for its transport. The way to diagnose this problem is to run your remote shell like this:

ssh remotehost /bin/true > out.dat

then look at out.dat. If everything is working correctly then out.dat should be a zero length file. If you are getting the above error from rsync then you will probably find that out.dat contains some text or data. Look at the contents and try to work out what is producing it. The most common cause is incorrectly configured shell startup scripts (such as .cshrc or .profile) that contain output statements for non-interactive logins.

If you are having trouble debugging filter patterns, then try specifying the -vv option. At this level of verbosity rsync will show why each individual file is included or excluded.

EXIT VALUES

  • 0 -⁠ Success
  • 1 -⁠ Syntax or usage error
  • 2 -⁠ Protocol incompatibility
  • 3 -⁠ Errors selecting input/output files, dirs
  • 4 -⁠ Requested action not supported. Either:
    • an attempt was made to manipulate 64-bit files on a platform that cannot support them
    • an option was specified that is supported by the client and not by the server
  • 5 -⁠ Error starting client-server protocol
  • 6 -⁠ Daemon unable to append to log-file
  • 10 -⁠ Error in socket I/O
  • 11 -⁠ Error in file I/O
  • 12 -⁠ Error in rsync protocol data stream
  • 13 -⁠ Errors with program diagnostics
  • 14 -⁠ Error in IPC code
  • 20 -⁠ Received SIGUSR1 or SIGINT
  • 21 -⁠ Some error returned by waitpid()
  • 22 -⁠ Error allocating core memory buffers
  • 23 -⁠ Partial transfer due to error
  • 24 -⁠ Partial transfer due to vanished source files
  • 25 -⁠ The -⁠-⁠max-delete limit stopped deletions
  • 30 -⁠ Timeout in data send/receive
  • 35 -⁠ Timeout waiting for daemon connection

ENVIRONMENT VARIABLES

CVSIGNORE

The CVSIGNORE environment variable supplements any ignore patterns in .cvsignore files. See the --cvs-exclude option for more details.

RSYNC_ICONV

Specify a default --iconv setting using this environment variable. First supported in 3.0.0.

RSYNC_OLD_ARGS

Specify a "1" if you want the --old-args option to be enabled by default, a "2" (or more) if you want it to be enabled in the repeated-option state, or a "0" to make sure that it is disabled by default. When this environment variable is set to a non-zero value, it supersedes the RSYNC_PROTECT_ARGS variable.

This variable is ignored if --old-args, --no-old-args, or --secluded-args is specified on the command line.

First supported in 3.2.4.

RSYNC_PROTECT_ARGS

Specify a non-zero numeric value if you want the --secluded-args option to be enabled by default, or a zero value to make sure that it is disabled by default.

This variable is ignored if --secluded-args, --no-secluded-args, or --old-args is specified on the command line.

First supported in 3.1.0. Starting in 3.2.4, this variable is ignored if RSYNC_OLD_ARGS is set to a non-zero value.

RSYNC_RSH

This environment variable allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name, just as in the --rsh (-e) option.

RSYNC_PROXY

This environment variable allows you to redirect your rsync client to use a web proxy when connecting to an rsync daemon. You should set RSYNC_PROXY to a hostname:port pair.

RSYNC_PASSWORD

This environment variable allows you to set the password for an rsync daemon connection, which avoids the password prompt. Note that this does not supply a password to a remote shell transport such as ssh (consult its documentation for how to do that).

USER or LOGNAME

The USER or LOGNAME environment variables are used to determine the default username sent to an rsync daemon. If neither is set, the username defaults to "nobody". If both are set, USER takes precedence.

RSYNC_PARTIAL_DIR

This environment variable specifies the directory to use for a --partial transfer without implying that partial transfers be enabled. See the --partial-dir option for full details.

RSYNC_COMPRESS_LIST

This environment variable allows you to customize the negotiation of the compression algorithm by specifying an alternate order or a reduced list of names. Use the command rsync --version to see the available compression names. See the --compress option for full details.

RSYNC_CHECKSUM_LIST

This environment variable allows you to customize the negotiation of the checksum algorithm by specifying an alternate order or a reduced list of names. Use the command rsync --version to see the available checksum names. See the --checksum-choice option for full details.

RSYNC_MAX_ALLOC

This environment variable sets an allocation maximum as if you had used the --max-alloc option.

RSYNC_PORT

This environment variable is not read by rsync, but is instead set in its sub-environment when rsync is running the remote shell in combination with a daemon connection. This allows a script such as rsync-ssl to be able to know the port number that the user specified on the command line.

HOME

This environment variable is used to find the user's default .cvsignore file.

RSYNC_CONNECT_PROG

This environment variable is mainly used in debug setups to set the program to use when making a daemon connection. See CONNECTING TO AN RSYNC DAEMON for full details.

RSYNC_SHELL

This environment variable is mainly used in debug setups to set the program to use to run the program specified by RSYNC_CONNECT_PROG. See CONNECTING TO AN RSYNC DAEMON for full details.

FILES

/etc/rsyncd.conf or rsyncd.conf

SEE ALSO

rsync-ssl(1), rsyncd.conf(5), rrsync(1)

BUGS

  • Times are transferred as *nix time_t values.
  • When transferring to FAT filesystems rsync may re-sync unmodified files. See the comments on the --modify-window option.
  • File permissions, devices, etc. are transferred as native numerical values.
  • See also the comments on the --delete option.

Please report bugs! See the web site at https://rsync.samba.org/.

VERSION

This manpage is current for version 3.2.7 of rsync.

INTERNAL OPTIONS

The options --server and --sender are used internally by rsync, and should never be typed by a user under normal circumstances. Some awareness of these options may be needed in certain scenarios, such as when setting up a login that can only run an rsync command. For instance, the support directory of the rsync distribution has an example script named rrsync (for restricted rsync) that can be used with a restricted ssh login.

CREDITS

Rsync is distributed under the GNU General Public License. See the file COPYING for details.

An rsync web site is available at https://rsync.samba.org/. The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page.

The rsync github project is https://github.com/WayneD/rsync.

We would be delighted to hear from you if you like this program. Please contact the mailing-list at rsync@lists.samba.org.

This program uses the excellent zlib compression library written by Jean-loup Gailly and Mark Adler.

THANKS

Special thanks go out to: John Van Essen, Matt McCutchen, Wesley W. Terpstra, David Dykstra, Jos Backus, Sebastian Krahmer, Martin Pool, and our gone-but-not-forgotten compadre, J.W. Schultz.

Thanks also to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell and David Bell. I've probably missed some people, my apologies if I have.

AUTHOR

Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. It is currently maintained by Wayne Davison.

Mailing lists for support and development are available at https://lists.samba.org/.

20 Oct 2022

rsync-3.2.7/lib/0000775000000000000000000000000014324367162012137 5ustar rootrootrsync-3.2.7/lib/pool_alloc.c0000664000000000000000000002144514005564302014423 0ustar rootroot#include "rsync.h" #define POOL_DEF_EXTENT (32 * 1024) #define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */ struct alloc_pool { size_t size; /* extent size */ size_t quantum; /* allocation quantum */ struct pool_extent *extents; /* top extent is "live" */ void (*bomb)(); /* called if malloc fails */ int flags; /* statistical data */ unsigned long e_created; /* extents created */ unsigned long e_freed; /* extents destroyed */ int64 n_allocated; /* calls to alloc */ int64 n_freed; /* calls to free */ int64 b_allocated; /* cum. bytes allocated */ int64 b_freed; /* cum. bytes freed */ }; struct pool_extent { struct pool_extent *next; void *start; /* starting address */ size_t free; /* free bytecount */ size_t bound; /* trapped free bytes */ }; struct align_test { uchar foo; union { int64 i; void *p; } bar; }; #define MINALIGN offsetof(struct align_test, bar) /* Temporarily cast a void* var into a char* var when adding an offset (to * keep some compilers from complaining about the pointer arithmetic). */ #define PTR_ADD(b,o) ( (void*) ((char*)(b) + (o)) ) alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags) { struct alloc_pool *pool; if ((MINALIGN & (MINALIGN - 1)) != (0)) { if (bomb) (*bomb)("Compiler error: MINALIGN is not a power of 2", __FILE__, __LINE__); return NULL; } if (!(pool = new0(struct alloc_pool))) return NULL; if (!size) size = POOL_DEF_EXTENT; if (!quantum) quantum = MINALIGN; if (flags & POOL_INTERN) { if (size <= sizeof (struct pool_extent)) size = quantum; else size -= sizeof (struct pool_extent); flags |= POOL_PREPEND; } if (quantum <= 1) flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2; else if (!(flags & POOL_NO_QALIGN)) { if (size % quantum) size += quantum - size % quantum; /* If quantum is a power of 2, we'll avoid using modulus. */ if (!(quantum & (quantum - 1))) flags |= POOL_QALIGN_P2; } pool->size = size; pool->quantum = quantum; pool->bomb = bomb; pool->flags = flags; return pool; } void pool_destroy(alloc_pool_t p) { struct alloc_pool *pool = (struct alloc_pool *) p; struct pool_extent *cur, *next; if (!pool) return; for (cur = pool->extents; cur; cur = next) { next = cur->next; if (pool->flags & POOL_PREPEND) free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); else { free(cur->start); free(cur); } } free(pool); } void * pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg) { struct alloc_pool *pool = (struct alloc_pool *) p; if (!pool) return NULL; if (!len) len = pool->quantum; else if (pool->flags & POOL_QALIGN_P2) { if (len & (pool->quantum - 1)) len += pool->quantum - (len & (pool->quantum - 1)); } else if (!(pool->flags & POOL_NO_QALIGN)) { if (len % pool->quantum) len += pool->quantum - len % pool->quantum; } if (len > pool->size) goto bomb_out; if (!pool->extents || len > pool->extents->free) { void *start; size_t asize; struct pool_extent *ext; asize = pool->size; if (pool->flags & POOL_PREPEND) asize += sizeof (struct pool_extent); if (!(start = new_array(char, asize))) goto bomb_out; if (pool->flags & POOL_CLEAR) memset(start, 0, asize); if (pool->flags & POOL_PREPEND) { ext = start; start = PTR_ADD(start, sizeof (struct pool_extent)); } else if (!(ext = new(struct pool_extent))) goto bomb_out; ext->start = start; ext->free = pool->size; ext->bound = 0; ext->next = pool->extents; pool->extents = ext; pool->e_created++; } pool->n_allocated++; pool->b_allocated += len; pool->extents->free -= len; return PTR_ADD(pool->extents->start, pool->extents->free); bomb_out: if (pool->bomb) (*pool->bomb)(bomb_msg, __FILE__, __LINE__); return NULL; } /* This function allows you to declare memory in the pool that you are done * using. If you free all the memory in a pool's extent, that extent will * be freed. */ void pool_free(alloc_pool_t p, size_t len, void *addr) { struct alloc_pool *pool = (struct alloc_pool *)p; struct pool_extent *cur, *prev; if (!pool) return; if (!addr) { /* A NULL addr starts a fresh extent for new allocations. */ if ((cur = pool->extents) != NULL && cur->free != pool->size) { cur->bound += cur->free; cur->free = 0; } return; } if (!len) len = pool->quantum; else if (pool->flags & POOL_QALIGN_P2) { if (len & (pool->quantum - 1)) len += pool->quantum - (len & (pool->quantum - 1)); } else if (!(pool->flags & POOL_NO_QALIGN)) { if (len % pool->quantum) len += pool->quantum - len % pool->quantum; } pool->n_freed++; pool->b_freed += len; for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) { if (addr >= cur->start && addr < PTR_ADD(cur->start, pool->size)) break; } if (!cur) return; if (!prev) { /* The "live" extent is kept ready for more allocations. */ if (cur->free + cur->bound + len >= pool->size) { if (pool->flags & POOL_CLEAR) { memset(PTR_ADD(cur->start, cur->free), 0, pool->size - cur->free); } cur->free = pool->size; cur->bound = 0; } else if (addr == PTR_ADD(cur->start, cur->free)) { if (pool->flags & POOL_CLEAR) memset(addr, 0, len); cur->free += len; } else cur->bound += len; } else { cur->bound += len; if (cur->free + cur->bound >= pool->size) { prev->next = cur->next; if (pool->flags & POOL_PREPEND) free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); else { free(cur->start); free(cur); } pool->e_freed++; } else if (prev != pool->extents) { /* Move the extent to be the first non-live extent. */ prev->next = cur->next; cur->next = pool->extents->next; pool->extents->next = cur; } } } /* This allows you to declare that the given address marks the edge of some * pool memory that is no longer needed. Any extents that hold only data * older than the boundary address are freed. NOTE: You MUST NOT USE BOTH * pool_free() and pool_free_old() on the same pool!! */ void pool_free_old(alloc_pool_t p, void *addr) { struct alloc_pool *pool = (struct alloc_pool *)p; struct pool_extent *cur, *prev, *next; if (!pool || !addr) return; for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) { if (addr >= cur->start && addr < PTR_ADD(cur->start, pool->size)) break; } if (!cur) return; if (addr == PTR_ADD(cur->start, cur->free)) { if (prev) { prev->next = NULL; next = cur; } else { /* The most recent live extent can just be reset. */ if (pool->flags & POOL_CLEAR) memset(addr, 0, pool->size - cur->free); cur->free = pool->size; cur->bound = 0; next = cur->next; cur->next = NULL; } } else { next = cur->next; cur->next = NULL; } while ((cur = next) != NULL) { next = cur->next; if (pool->flags & POOL_PREPEND) free(PTR_ADD(cur->start, -sizeof (struct pool_extent))); else { free(cur->start); free(cur); } pool->e_freed++; } } /* If the current extent doesn't have "len" free space in it, mark it as full * so that the next alloc will start a new extent. If len is (size_t)-1, this * bump will always occur. The function returns a boundary address that can * be used with pool_free_old(), or a NULL if no memory is allocated. */ void * pool_boundary(alloc_pool_t p, size_t len) { struct alloc_pool *pool = (struct alloc_pool *)p; struct pool_extent *cur; if (!pool || !pool->extents) return NULL; cur = pool->extents; if (cur->free < len) { cur->bound += cur->free; cur->free = 0; } return PTR_ADD(cur->start, cur->free); } #define FDPRINT(label, value) \ do { \ int len = snprintf(buf, sizeof buf, label, value); \ if (write(fd, buf, len) != len) \ ret = -1; \ } while (0) #define FDEXTSTAT(ext) \ do { \ int len = snprintf(buf, sizeof buf, " %12ld %5ld\n", \ (long)ext->free, (long)ext->bound); \ if (write(fd, buf, len) != len) \ ret = -1; \ } while (0) int pool_stats(alloc_pool_t p, int fd, int summarize) { struct alloc_pool *pool = (struct alloc_pool *) p; struct pool_extent *cur; char buf[BUFSIZ]; int ret = 0; if (!pool) return ret; FDPRINT(" Extent size: %12ld\n", (long) pool->size); FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum); FDPRINT(" Extents created: %12ld\n", pool->e_created); FDPRINT(" Extents freed: %12ld\n", pool->e_freed); FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated); FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed); FDPRINT(" Bytes allocated: %12.0f\n", (double) pool->b_allocated); FDPRINT(" Bytes freed: %12.0f\n", (double) pool->b_freed); if (summarize) return ret; if (!pool->extents) return ret; if (write(fd, "\n", 1) != 1) ret = -1; for (cur = pool->extents; cur; cur = cur->next) FDEXTSTAT(cur); return ret; } rsync-3.2.7/lib/pool_alloc.h0000664000000000000000000000156513702777121014441 0ustar rootroot#include #define POOL_CLEAR (1<<0) /* zero fill allocations */ #define POOL_NO_QALIGN (1<<1) /* don't align data to quanta */ #define POOL_INTERN (1<<2) /* Allocate extent structures */ #define POOL_PREPEND (1<<3) /* or prepend to extent data */ typedef void *alloc_pool_t; alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(const char*, const char*, int), int flags); void pool_destroy(alloc_pool_t pool); void *pool_alloc(alloc_pool_t pool, size_t size, const char *bomb_msg); void pool_free(alloc_pool_t pool, size_t size, void *addr); void pool_free_old(alloc_pool_t pool, void *addr); void *pool_boundary(alloc_pool_t pool, size_t size); #define pool_talloc(pool, type, count, bomb_msg) \ ((type *)pool_alloc(pool, sizeof(type) * count, bomb_msg)) #define pool_tfree(pool, type, count, addr) \ (pool_free(pool, sizeof(type) * count, addr)) rsync-3.2.7/lib/mdigest.h0000664000000000000000000000125714307156014013742 0ustar rootroot/* The include file for both the MD4 and MD5 routines. */ #ifdef USE_OPENSSL #include #include #endif #include "md-defines.h" typedef struct { uint32 A, B, C, D; uint32 totalN; /* bit count, lower 32 bits */ uint32 totalN2; /* bit count, upper 32 bits */ uchar buffer[CSUM_CHUNK]; } md_context; void mdfour_begin(md_context *md); void mdfour_update(md_context *md, const uchar *in, uint32 length); void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]); void md5_begin(md_context *ctx); void md5_update(md_context *ctx, const uchar *input, uint32 length); void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]); rsync-3.2.7/lib/sysxattrs.h0000664000000000000000000000133013673154116014370 0ustar rootroot#ifdef SUPPORT_XATTRS #if defined HAVE_SYS_XATTR_H #include #elif defined HAVE_ATTR_XATTR_H #include #elif defined HAVE_SYS_EXTATTR_H #include #endif /* Linux 2.4 does not define this as a distinct errno value: */ #ifndef ENOATTR #define ENOATTR ENODATA #endif ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size); ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size); int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size); int sys_lremovexattr(const char *path, const char *name); ssize_t sys_llistxattr(const char *path, char *list, size_t size); #else /* No xattrs available */ #endif rsync-3.2.7/lib/sysxattrs.c0000664000000000000000000001567214170671375014405 0ustar rootroot/* * Extended attribute support for rsync. * * Copyright (C) 2004 Red Hat, Inc. * Copyright (C) 2003-2022 Wayne Davison * Written by Jay Fenlason. * * 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 "sysxattrs.h" #ifdef SUPPORT_XATTRS #ifdef HAVE_OSX_XATTRS #define GETXATTR_FETCH_LIMIT (64*1024*1024) #endif #if defined HAVE_LINUX_XATTRS ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) { return lgetxattr(path, name, value, size); } ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { return fgetxattr(filedes, name, value, size); } int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) { return lsetxattr(path, name, value, size, 0); } int sys_lremovexattr(const char *path, const char *name) { return lremovexattr(path, name); } ssize_t sys_llistxattr(const char *path, char *list, size_t size) { return llistxattr(path, list, size); } #elif HAVE_OSX_XATTRS ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) { ssize_t len = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); /* If we're retrieving data, handle resource forks > 64MB specially */ if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) { /* getxattr will only return 64MB of data at a time, need to call again with a new offset */ u_int32_t offset = len; size_t data_retrieved = len; while (data_retrieved < size) { len = getxattr(path, name, (char*)value + offset, size - data_retrieved, offset, XATTR_NOFOLLOW); if (len <= 0) break; data_retrieved += len; offset += (u_int32_t)len; } len = data_retrieved; } return len; } ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { return fgetxattr(filedes, name, value, size, 0, 0); } int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) { return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW); } int sys_lremovexattr(const char *path, const char *name) { return removexattr(path, name, XATTR_NOFOLLOW); } ssize_t sys_llistxattr(const char *path, char *list, size_t size) { return listxattr(path, list, size, XATTR_NOFOLLOW); } #elif HAVE_FREEBSD_XATTRS ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) { return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size); } ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size); } int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) { return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size); } int sys_lremovexattr(const char *path, const char *name) { return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name); } ssize_t sys_llistxattr(const char *path, char *list, size_t size) { unsigned char keylen; ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size); if (len <= 0 || (size_t)len > size) return len; /* FreeBSD puts a single-byte length before each string, with no '\0' * terminator. We need to change this into a series of null-terminted * strings. Since the size is the same, we can simply transform the * output in place. */ for (off = 0; off < len; off += keylen + 1) { keylen = ((unsigned char*)list)[off]; if (off + keylen >= len) { /* Should be impossible, but kernel bugs happen! */ errno = EINVAL; return -1; } memmove(list+off, list+off+1, keylen); list[off+keylen] = '\0'; } return len; } #elif HAVE_SOLARIS_XATTRS static ssize_t read_xattr(int attrfd, void *buf, size_t buflen) { STRUCT_STAT sb; ssize_t ret; if (fstat(attrfd, &sb) < 0) ret = -1; else if (sb.st_size > SSIZE_MAX) { errno = ERANGE; ret = -1; } else if (buflen == 0) ret = sb.st_size; else if (sb.st_size > buflen) { errno = ERANGE; ret = -1; } else { size_t bufpos; for (bufpos = 0; bufpos < sb.st_size; ) { ssize_t cnt = read(attrfd, (char*)buf + bufpos, sb.st_size - bufpos); if (cnt <= 0) { if (cnt < 0 && errno == EINTR) continue; bufpos = -1; break; } bufpos += cnt; } ret = bufpos; } close(attrfd); return ret; } ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size) { int attrfd; if ((attrfd = attropen(path, name, O_RDONLY)) < 0) { errno = ENOATTR; return -1; } return read_xattr(attrfd, value, size); } ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { int attrfd; if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) { errno = ENOATTR; return -1; } return read_xattr(attrfd, value, size); } int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) { int attrfd; size_t bufpos; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0) return -1; for (bufpos = 0; bufpos < size; ) { ssize_t cnt = write(attrfd, (char*)value + bufpos, size); if (cnt <= 0) { if (cnt < 0 && errno == EINTR) continue; bufpos = -1; break; } bufpos += cnt; } close(attrfd); return bufpos > 0 ? 0 : -1; } int sys_lremovexattr(const char *path, const char *name) { int attrdirfd; int ret; if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) return -1; ret = unlinkat(attrdirfd, name, 0); close(attrdirfd); return ret; } ssize_t sys_llistxattr(const char *path, char *list, size_t size) { int attrdirfd; DIR *dirp; struct dirent *dp; ssize_t ret = 0; if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) { errno = ENOTSUP; return -1; } if ((dirp = fdopendir(attrdirfd)) == NULL) { close(attrdirfd); return -1; } while ((dp = readdir(dirp))) { int len = strlen(dp->d_name); if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.'))) continue; if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0 && (dp->d_name[10] == 'o' || dp->d_name[10] == 'w')) continue; ret += len + 1; if ((size_t)ret > size) { if (size == 0) continue; ret = -1; errno = ERANGE; break; } memcpy(list, dp->d_name, len+1); list += len+1; } closedir(dirp); close(attrdirfd); return ret; } #else #error You need to create xattr compatibility functions. #endif #endif /* SUPPORT_XATTRS */ rsync-3.2.7/lib/wildmatch.h0000664000000000000000000000043210356263344014261 0ustar rootroot/* wildmatch.h */ int wildmatch(const char *pattern, const char *text); int iwildmatch(const char *pattern, const char *text); int wildmatch_array(const char *pattern, const char*const *texts, int where); int litmatch_array(const char *string, const char*const *texts, int where); rsync-3.2.7/lib/wildmatch.c0000664000000000000000000002261310624503243014252 0ustar rootroot/* ** Do shell-style pattern matching for ?, \, [], and * characters. ** It is 8bit clean. ** ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. ** Rich $alz is now . ** ** Modified by Wayne Davison to special-case '/' matching, to make '**' ** work differently than '*', and to fix the character-class code. */ #include "rsync.h" /* What character marks an inverted character class? */ #define NEGATE_CLASS '!' #define NEGATE_CLASS2 '^' #define FALSE 0 #define TRUE 1 #define ABORT_ALL -1 #define ABORT_TO_STARSTAR -2 #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \ && *(class) == *(litmatch) \ && strncmp((char*)class, litmatch, len) == 0) #if defined STDC_HEADERS || !defined isascii # define ISASCII(c) 1 #else # define ISASCII(c) isascii(c) #endif #ifdef isblank # define ISBLANK(c) (ISASCII(c) && isblank(c)) #else # define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif #ifdef isgraph # define ISGRAPH(c) (ISASCII(c) && isgraph(c)) #else # define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c)) #endif #define ISPRINT(c) (ISASCII(c) && isprint(c)) #define ISDIGIT(c) (ISASCII(c) && isdigit(c)) #define ISALNUM(c) (ISASCII(c) && isalnum(c)) #define ISALPHA(c) (ISASCII(c) && isalpha(c)) #define ISCNTRL(c) (ISASCII(c) && iscntrl(c)) #define ISLOWER(c) (ISASCII(c) && islower(c)) #define ISPUNCT(c) (ISASCII(c) && ispunct(c)) #define ISSPACE(c) (ISASCII(c) && isspace(c)) #define ISUPPER(c) (ISASCII(c) && isupper(c)) #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c)) #ifdef WILD_TEST_ITERATIONS int wildmatch_iteration_count; #endif static int force_lower_case = 0; /* Match pattern "p" against the a virtually-joined string consisting * of "text" and any strings in array "a". */ static int dowild(const uchar *p, const uchar *text, const uchar*const *a) { uchar p_ch; #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count++; #endif for ( ; (p_ch = *p) != '\0'; text++, p++) { int matched, special; uchar t_ch, prev_ch; while ((t_ch = *text) == '\0') { if (*a == NULL) { if (p_ch != '*') return ABORT_ALL; break; } text = *a++; } if (force_lower_case && ISUPPER(t_ch)) t_ch = tolower(t_ch); switch (p_ch) { case '\\': /* Literal match with following character. Note that the test * in "default" handles the p[1] == '\0' failure case. */ p_ch = *++p; /* FALLTHROUGH */ default: if (t_ch != p_ch) return FALSE; continue; case '?': /* Match anything but '/'. */ if (t_ch == '/') return FALSE; continue; case '*': if (*++p == '*') { while (*++p == '*') {} special = TRUE; } else special = FALSE; if (*p == '\0') { /* Trailing "**" matches everything. Trailing "*" matches * only if there are no more slash characters. */ if (!special) { do { if (strchr((char*)text, '/') != NULL) return FALSE; } while ((text = *a++) != NULL); } return TRUE; } while (1) { if (t_ch == '\0') { if ((text = *a++) == NULL) break; t_ch = *text; continue; } if ((matched = dowild(p, text, a)) != FALSE) { if (!special || matched != ABORT_TO_STARSTAR) return matched; } else if (!special && t_ch == '/') return ABORT_TO_STARSTAR; t_ch = *++text; } return ABORT_ALL; case '[': p_ch = *++p; #ifdef NEGATE_CLASS2 if (p_ch == NEGATE_CLASS2) p_ch = NEGATE_CLASS; #endif /* Assign literal TRUE/FALSE because of "matched" comparison. */ special = p_ch == NEGATE_CLASS? TRUE : FALSE; if (special) { /* Inverted character class. */ p_ch = *++p; } prev_ch = 0; matched = FALSE; do { if (!p_ch) return ABORT_ALL; if (p_ch == '\\') { p_ch = *++p; if (!p_ch) return ABORT_ALL; if (t_ch == p_ch) matched = TRUE; } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') { p_ch = *++p; if (p_ch == '\\') { p_ch = *++p; if (!p_ch) return ABORT_ALL; } if (t_ch <= p_ch && t_ch >= prev_ch) matched = TRUE; p_ch = 0; /* This makes "prev_ch" get set to 0. */ } else if (p_ch == '[' && p[1] == ':') { const uchar *s; int i; for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/ if (!p_ch) return ABORT_ALL; i = p - s - 1; if (i < 0 || p[-1] != ':') { /* Didn't find ":]", so treat like a normal set. */ p = s - 2; p_ch = '['; if (t_ch == p_ch) matched = TRUE; continue; } if (CC_EQ(s,i, "alnum")) { if (ISALNUM(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "alpha")) { if (ISALPHA(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "blank")) { if (ISBLANK(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "cntrl")) { if (ISCNTRL(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "digit")) { if (ISDIGIT(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "graph")) { if (ISGRAPH(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "lower")) { if (ISLOWER(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "print")) { if (ISPRINT(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "punct")) { if (ISPUNCT(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "space")) { if (ISSPACE(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "upper")) { if (ISUPPER(t_ch)) matched = TRUE; } else if (CC_EQ(s,i, "xdigit")) { if (ISXDIGIT(t_ch)) matched = TRUE; } else /* malformed [:class:] string */ return ABORT_ALL; p_ch = 0; /* This makes "prev_ch" get set to 0. */ } else if (t_ch == p_ch) matched = TRUE; } while (prev_ch = p_ch, (p_ch = *++p) != ']'); if (matched == special || t_ch == '/') return FALSE; continue; } } do { if (*text) return FALSE; } while ((text = *a++) != NULL); return TRUE; } /* Match literal string "s" against the a virtually-joined string consisting * of "text" and any strings in array "a". */ static int doliteral(const uchar *s, const uchar *text, const uchar*const *a) { for ( ; *s != '\0'; text++, s++) { while (*text == '\0') { if ((text = *a++) == NULL) return FALSE; } if (*text != *s) return FALSE; } do { if (*text) return FALSE; } while ((text = *a++) != NULL); return TRUE; } /* Return the last "count" path elements from the concatenated string. * We return a string pointer to the start of the string, and update the * array pointer-pointer to point to any remaining string elements. */ static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count) { const uchar*const *a = *a_ptr; const uchar*const *first_a = a; while (*a) a++; while (a != first_a) { const uchar *s = *--a; s += strlen((char*)s); while (--s >= *a) { if (*s == '/' && !--count) { *a_ptr = a+1; return s+1; } } } if (count == 1) { *a_ptr = a+1; return *a; } return NULL; } /* Match the "pattern" against the "text" string. */ int wildmatch(const char *pattern, const char *text) { static const uchar *nomore[1]; /* A NULL pointer. */ #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count = 0; #endif return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE; } /* Match the "pattern" against the forced-to-lower-case "text" string. */ int iwildmatch(const char *pattern, const char *text) { static const uchar *nomore[1]; /* A NULL pointer. */ int ret; #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count = 0; #endif force_lower_case = 1; ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE; force_lower_case = 0; return ret; } /* Match pattern "p" against the a virtually-joined string consisting * of all the pointers in array "texts" (which has a NULL pointer at the * end). The int "where" can be 0 (normal matching), > 0 (match only * the trailing N slash-separated filename components of "texts"), or < 0 * (match the "pattern" at the start or after any slash in "texts"). */ int wildmatch_array(const char *pattern, const char*const *texts, int where) { const uchar *p = (const uchar*)pattern; const uchar*const *a = (const uchar*const*)texts; const uchar *text; int matched; #ifdef WILD_TEST_ITERATIONS wildmatch_iteration_count = 0; #endif if (where > 0) text = trailing_N_elements(&a, where); else text = *a++; if (!text) return FALSE; if ((matched = dowild(p, text, a)) != TRUE && where < 0 && matched != ABORT_ALL) { while (1) { if (*text == '\0') { if ((text = (uchar*)*a++) == NULL) return FALSE; continue; } if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE && matched != ABORT_TO_STARSTAR) break; } } return matched == TRUE; } /* Match literal string "s" against the a virtually-joined string consisting * of all the pointers in array "texts" (which has a NULL pointer at the * end). The int "where" can be 0 (normal matching), or > 0 (match * only the trailing N slash-separated filename components of "texts"). */ int litmatch_array(const char *string, const char*const *texts, int where) { const uchar *s = (const uchar*)string; const uchar*const *a = (const uchar* const*)texts; const uchar *text; if (where > 0) text = trailing_N_elements(&a, where); else text = *a++; if (!text) return FALSE; return doliteral(s, text, a) == TRUE; } rsync-3.2.7/lib/md5-asm-x86_64.S0000664000000000000000000006324314210262311014452 0ustar rootroot/* * x86-64 optimized assembler MD5 implementation * * Author: Marc Bevand, 2004 * * This code was placed in the public domain by the author. The original * publication can be found at: * * https://www.zorinaq.com/papers/md5-amd64.html */ /* * No modifications were made aside from changing the function and file names. * The MD5_CTX structure as expected here (from OpenSSL) is binary compatible * with the md_context used by rsync, for the fields accessed. * * Benchmarks (in MB/s) C ASM * - Intel Atom D2700 302 334 * - Intel i7-7700hq 351 376 * - AMD ThreadRipper 2950x 728 784 * * The original code was also incorporated into OpenSSL. It has since been * modified there. Those changes have not been made here due to licensing * incompatibilities. Benchmarks of those changes on the above CPUs did not * show any significant difference in performance, though. */ #include "config.h" #include "md-defines.h" #ifdef USE_MD5_ASM /* { */ #ifdef __APPLE__ #define md5_process_asm _md5_process_asm #endif .text .align 16 .globl md5_process_asm md5_process_asm: push %rbp push %rbx push %r12 push %r13 # not really useful (r13 is unused) push %r14 push %r15 # rdi = arg #1 (ctx, MD5_CTX pointer) # rsi = arg #2 (ptr, data pointer) # rdx = arg #3 (nbr, number of 16-word blocks to process) mov %rdi, %rbp # rbp = ctx shl $6, %rdx # rdx = nbr in bytes lea (%rsi,%rdx), %rdi # rdi = end mov 0*4(%rbp), %eax # eax = ctx->A mov 1*4(%rbp), %ebx # ebx = ctx->B mov 2*4(%rbp), %ecx # ecx = ctx->C mov 3*4(%rbp), %edx # edx = ctx->D # end is 'rdi' # ptr is 'rsi' # A is 'eax' # B is 'ebx' # C is 'ecx' # D is 'edx' cmp %rdi, %rsi # cmp end with ptr je 1f # jmp if ptr == end # BEGIN of loop over 16-word blocks 2: # save old values of A, B, C, D mov %eax, %r8d mov %ebx, %r9d mov %ecx, %r14d mov %edx, %r15d mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ xor %ecx, %r11d /* y ^ ... */ lea -680876936(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r11d /* x & ... */ xor %edx, %r11d /* z ^ ... */ mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */ add %r11d, %eax /* dst += ... */ rol $7, %eax /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %ebx, %eax /* dst += x */ xor %ebx, %r11d /* y ^ ... */ lea -389564586(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r11d /* x & ... */ xor %ecx, %r11d /* z ^ ... */ mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */ add %r11d, %edx /* dst += ... */ rol $12, %edx /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %eax, %edx /* dst += x */ xor %eax, %r11d /* y ^ ... */ lea 606105819(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r11d /* x & ... */ xor %ebx, %r11d /* z ^ ... */ mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */ add %r11d, %ecx /* dst += ... */ rol $17, %ecx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %edx, %ecx /* dst += x */ xor %edx, %r11d /* y ^ ... */ lea -1044525330(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r11d /* x & ... */ xor %eax, %r11d /* z ^ ... */ mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */ add %r11d, %ebx /* dst += ... */ rol $22, %ebx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %ecx, %ebx /* dst += x */ xor %ecx, %r11d /* y ^ ... */ lea -176418897(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r11d /* x & ... */ xor %edx, %r11d /* z ^ ... */ mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */ add %r11d, %eax /* dst += ... */ rol $7, %eax /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %ebx, %eax /* dst += x */ xor %ebx, %r11d /* y ^ ... */ lea 1200080426(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r11d /* x & ... */ xor %ecx, %r11d /* z ^ ... */ mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */ add %r11d, %edx /* dst += ... */ rol $12, %edx /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %eax, %edx /* dst += x */ xor %eax, %r11d /* y ^ ... */ lea -1473231341(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r11d /* x & ... */ xor %ebx, %r11d /* z ^ ... */ mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */ add %r11d, %ecx /* dst += ... */ rol $17, %ecx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %edx, %ecx /* dst += x */ xor %edx, %r11d /* y ^ ... */ lea -45705983(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r11d /* x & ... */ xor %eax, %r11d /* z ^ ... */ mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */ add %r11d, %ebx /* dst += ... */ rol $22, %ebx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %ecx, %ebx /* dst += x */ xor %ecx, %r11d /* y ^ ... */ lea 1770035416(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r11d /* x & ... */ xor %edx, %r11d /* z ^ ... */ mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */ add %r11d, %eax /* dst += ... */ rol $7, %eax /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %ebx, %eax /* dst += x */ xor %ebx, %r11d /* y ^ ... */ lea -1958414417(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r11d /* x & ... */ xor %ecx, %r11d /* z ^ ... */ mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */ add %r11d, %edx /* dst += ... */ rol $12, %edx /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %eax, %edx /* dst += x */ xor %eax, %r11d /* y ^ ... */ lea -42063(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r11d /* x & ... */ xor %ebx, %r11d /* z ^ ... */ mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */ add %r11d, %ecx /* dst += ... */ rol $17, %ecx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %edx, %ecx /* dst += x */ xor %edx, %r11d /* y ^ ... */ lea -1990404162(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r11d /* x & ... */ xor %eax, %r11d /* z ^ ... */ mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */ add %r11d, %ebx /* dst += ... */ rol $22, %ebx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %ecx, %ebx /* dst += x */ xor %ecx, %r11d /* y ^ ... */ lea 1804603682(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r11d /* x & ... */ xor %edx, %r11d /* z ^ ... */ mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */ add %r11d, %eax /* dst += ... */ rol $7, %eax /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %ebx, %eax /* dst += x */ xor %ebx, %r11d /* y ^ ... */ lea -40341101(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r11d /* x & ... */ xor %ecx, %r11d /* z ^ ... */ mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */ add %r11d, %edx /* dst += ... */ rol $12, %edx /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %eax, %edx /* dst += x */ xor %eax, %r11d /* y ^ ... */ lea -1502002290(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r11d /* x & ... */ xor %ebx, %r11d /* z ^ ... */ mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */ add %r11d, %ecx /* dst += ... */ rol $17, %ecx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %edx, %ecx /* dst += x */ xor %edx, %r11d /* y ^ ... */ lea 1236535329(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r11d /* x & ... */ xor %eax, %r11d /* z ^ ... */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ add %r11d, %ebx /* dst += ... */ rol $22, %ebx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %ecx, %ebx /* dst += x */ mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ mov %edx, %r12d /* (NEXT STEP) z' = %edx */ not %r11d /* not z */ lea -165796510(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r12d /* x & z */ and %ecx, %r11d /* y & (not z) */ mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %r12d, %eax /* dst += ... */ mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */ rol $5, %eax /* dst <<< s */ add %ebx, %eax /* dst += x */ not %r11d /* not z */ lea -1069501632(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r12d /* x & z */ and %ebx, %r11d /* y & (not z) */ mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %r12d, %edx /* dst += ... */ mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */ rol $9, %edx /* dst <<< s */ add %eax, %edx /* dst += x */ not %r11d /* not z */ lea 643717713(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r12d /* x & z */ and %eax, %r11d /* y & (not z) */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %r12d, %ecx /* dst += ... */ mov %eax, %r12d /* (NEXT STEP) z' = %eax */ rol $14, %ecx /* dst <<< s */ add %edx, %ecx /* dst += x */ not %r11d /* not z */ lea -373897302(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r12d /* x & z */ and %edx, %r11d /* y & (not z) */ mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %r12d, %ebx /* dst += ... */ mov %edx, %r12d /* (NEXT STEP) z' = %edx */ rol $20, %ebx /* dst <<< s */ add %ecx, %ebx /* dst += x */ not %r11d /* not z */ lea -701558691(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r12d /* x & z */ and %ecx, %r11d /* y & (not z) */ mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %r12d, %eax /* dst += ... */ mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */ rol $5, %eax /* dst <<< s */ add %ebx, %eax /* dst += x */ not %r11d /* not z */ lea 38016083(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r12d /* x & z */ and %ebx, %r11d /* y & (not z) */ mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %r12d, %edx /* dst += ... */ mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */ rol $9, %edx /* dst <<< s */ add %eax, %edx /* dst += x */ not %r11d /* not z */ lea -660478335(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r12d /* x & z */ and %eax, %r11d /* y & (not z) */ mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %r12d, %ecx /* dst += ... */ mov %eax, %r12d /* (NEXT STEP) z' = %eax */ rol $14, %ecx /* dst <<< s */ add %edx, %ecx /* dst += x */ not %r11d /* not z */ lea -405537848(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r12d /* x & z */ and %edx, %r11d /* y & (not z) */ mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %r12d, %ebx /* dst += ... */ mov %edx, %r12d /* (NEXT STEP) z' = %edx */ rol $20, %ebx /* dst <<< s */ add %ecx, %ebx /* dst += x */ not %r11d /* not z */ lea 568446438(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r12d /* x & z */ and %ecx, %r11d /* y & (not z) */ mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %r12d, %eax /* dst += ... */ mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */ rol $5, %eax /* dst <<< s */ add %ebx, %eax /* dst += x */ not %r11d /* not z */ lea -1019803690(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r12d /* x & z */ and %ebx, %r11d /* y & (not z) */ mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %r12d, %edx /* dst += ... */ mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */ rol $9, %edx /* dst <<< s */ add %eax, %edx /* dst += x */ not %r11d /* not z */ lea -187363961(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r12d /* x & z */ and %eax, %r11d /* y & (not z) */ mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %r12d, %ecx /* dst += ... */ mov %eax, %r12d /* (NEXT STEP) z' = %eax */ rol $14, %ecx /* dst <<< s */ add %edx, %ecx /* dst += x */ not %r11d /* not z */ lea 1163531501(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r12d /* x & z */ and %edx, %r11d /* y & (not z) */ mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %r12d, %ebx /* dst += ... */ mov %edx, %r12d /* (NEXT STEP) z' = %edx */ rol $20, %ebx /* dst <<< s */ add %ecx, %ebx /* dst += x */ not %r11d /* not z */ lea -1444681467(%eax,%r10d),%eax /* Const + dst + ... */ and %ebx, %r12d /* x & z */ and %ecx, %r11d /* y & (not z) */ mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ecx, %r11d /* (NEXT STEP) z' = %ecx */ add %r12d, %eax /* dst += ... */ mov %ecx, %r12d /* (NEXT STEP) z' = %ecx */ rol $5, %eax /* dst <<< s */ add %ebx, %eax /* dst += x */ not %r11d /* not z */ lea -51403784(%edx,%r10d),%edx /* Const + dst + ... */ and %eax, %r12d /* x & z */ and %ebx, %r11d /* y & (not z) */ mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %ebx, %r11d /* (NEXT STEP) z' = %ebx */ add %r12d, %edx /* dst += ... */ mov %ebx, %r12d /* (NEXT STEP) z' = %ebx */ rol $9, %edx /* dst <<< s */ add %eax, %edx /* dst += x */ not %r11d /* not z */ lea 1735328473(%ecx,%r10d),%ecx /* Const + dst + ... */ and %edx, %r12d /* x & z */ and %eax, %r11d /* y & (not z) */ mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %eax, %r11d /* (NEXT STEP) z' = %eax */ add %r12d, %ecx /* dst += ... */ mov %eax, %r12d /* (NEXT STEP) z' = %eax */ rol $14, %ecx /* dst <<< s */ add %edx, %ecx /* dst += x */ not %r11d /* not z */ lea -1926607734(%ebx,%r10d),%ebx /* Const + dst + ... */ and %ecx, %r12d /* x & z */ and %edx, %r11d /* y & (not z) */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ or %r11d, %r12d /* (y & (not z)) | (x & z) */ mov %edx, %r11d /* (NEXT STEP) z' = %edx */ add %r12d, %ebx /* dst += ... */ mov %edx, %r12d /* (NEXT STEP) z' = %edx */ rol $20, %ebx /* dst <<< s */ add %ecx, %ebx /* dst += x */ mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */ mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */ lea -378558(%eax,%r10d),%eax /* Const + dst + ... */ mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */ xor %edx, %r11d /* z ^ ... */ xor %ebx, %r11d /* x ^ ... */ add %r11d, %eax /* dst += ... */ rol $4, %eax /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */ add %ebx, %eax /* dst += x */ lea -2022574463(%edx,%r10d),%edx /* Const + dst + ... */ mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */ xor %ecx, %r11d /* z ^ ... */ xor %eax, %r11d /* x ^ ... */ add %r11d, %edx /* dst += ... */ rol $11, %edx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) y' = %eax */ add %eax, %edx /* dst += x */ lea 1839030562(%ecx,%r10d),%ecx /* Const + dst + ... */ mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */ xor %ebx, %r11d /* z ^ ... */ xor %edx, %r11d /* x ^ ... */ add %r11d, %ecx /* dst += ... */ rol $16, %ecx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) y' = %edx */ add %edx, %ecx /* dst += x */ lea -35309556(%ebx,%r10d),%ebx /* Const + dst + ... */ mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */ xor %eax, %r11d /* z ^ ... */ xor %ecx, %r11d /* x ^ ... */ add %r11d, %ebx /* dst += ... */ rol $23, %ebx /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */ add %ecx, %ebx /* dst += x */ lea -1530992060(%eax,%r10d),%eax /* Const + dst + ... */ mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */ xor %edx, %r11d /* z ^ ... */ xor %ebx, %r11d /* x ^ ... */ add %r11d, %eax /* dst += ... */ rol $4, %eax /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */ add %ebx, %eax /* dst += x */ lea 1272893353(%edx,%r10d),%edx /* Const + dst + ... */ mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */ xor %ecx, %r11d /* z ^ ... */ xor %eax, %r11d /* x ^ ... */ add %r11d, %edx /* dst += ... */ rol $11, %edx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) y' = %eax */ add %eax, %edx /* dst += x */ lea -155497632(%ecx,%r10d),%ecx /* Const + dst + ... */ mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */ xor %ebx, %r11d /* z ^ ... */ xor %edx, %r11d /* x ^ ... */ add %r11d, %ecx /* dst += ... */ rol $16, %ecx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) y' = %edx */ add %edx, %ecx /* dst += x */ lea -1094730640(%ebx,%r10d),%ebx /* Const + dst + ... */ mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */ xor %eax, %r11d /* z ^ ... */ xor %ecx, %r11d /* x ^ ... */ add %r11d, %ebx /* dst += ... */ rol $23, %ebx /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */ add %ecx, %ebx /* dst += x */ lea 681279174(%eax,%r10d),%eax /* Const + dst + ... */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ xor %edx, %r11d /* z ^ ... */ xor %ebx, %r11d /* x ^ ... */ add %r11d, %eax /* dst += ... */ rol $4, %eax /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */ add %ebx, %eax /* dst += x */ lea -358537222(%edx,%r10d),%edx /* Const + dst + ... */ mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */ xor %ecx, %r11d /* z ^ ... */ xor %eax, %r11d /* x ^ ... */ add %r11d, %edx /* dst += ... */ rol $11, %edx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) y' = %eax */ add %eax, %edx /* dst += x */ lea -722521979(%ecx,%r10d),%ecx /* Const + dst + ... */ mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */ xor %ebx, %r11d /* z ^ ... */ xor %edx, %r11d /* x ^ ... */ add %r11d, %ecx /* dst += ... */ rol $16, %ecx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) y' = %edx */ add %edx, %ecx /* dst += x */ lea 76029189(%ebx,%r10d),%ebx /* Const + dst + ... */ mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */ xor %eax, %r11d /* z ^ ... */ xor %ecx, %r11d /* x ^ ... */ add %r11d, %ebx /* dst += ... */ rol $23, %ebx /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */ add %ecx, %ebx /* dst += x */ lea -640364487(%eax,%r10d),%eax /* Const + dst + ... */ mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */ xor %edx, %r11d /* z ^ ... */ xor %ebx, %r11d /* x ^ ... */ add %r11d, %eax /* dst += ... */ rol $4, %eax /* dst <<< s */ mov %ebx, %r11d /* (NEXT STEP) y' = %ebx */ add %ebx, %eax /* dst += x */ lea -421815835(%edx,%r10d),%edx /* Const + dst + ... */ mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */ xor %ecx, %r11d /* z ^ ... */ xor %eax, %r11d /* x ^ ... */ add %r11d, %edx /* dst += ... */ rol $11, %edx /* dst <<< s */ mov %eax, %r11d /* (NEXT STEP) y' = %eax */ add %eax, %edx /* dst += x */ lea 530742520(%ecx,%r10d),%ecx /* Const + dst + ... */ mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */ xor %ebx, %r11d /* z ^ ... */ xor %edx, %r11d /* x ^ ... */ add %r11d, %ecx /* dst += ... */ rol $16, %ecx /* dst <<< s */ mov %edx, %r11d /* (NEXT STEP) y' = %edx */ add %edx, %ecx /* dst += x */ lea -995338651(%ebx,%r10d),%ebx /* Const + dst + ... */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ xor %eax, %r11d /* z ^ ... */ xor %ecx, %r11d /* x ^ ... */ add %r11d, %ebx /* dst += ... */ rol $23, %ebx /* dst <<< s */ mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */ add %ecx, %ebx /* dst += x */ mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */ mov $0xffffffff, %r11d xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/ lea -198630844(%eax,%r10d),%eax /* Const + dst + ... */ or %ebx, %r11d /* x | ... */ xor %ecx, %r11d /* y ^ ... */ add %r11d, %eax /* dst += ... */ mov 7*4(%rsi),%r10d /* (NEXT STEP) X[7] */ mov $0xffffffff, %r11d rol $6, %eax /* dst <<< s */ xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */ add %ebx, %eax /* dst += x */ lea 1126891415(%edx,%r10d),%edx /* Const + dst + ... */ or %eax, %r11d /* x | ... */ xor %ebx, %r11d /* y ^ ... */ add %r11d, %edx /* dst += ... */ mov 14*4(%rsi),%r10d /* (NEXT STEP) X[14] */ mov $0xffffffff, %r11d rol $10, %edx /* dst <<< s */ xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */ add %eax, %edx /* dst += x */ lea -1416354905(%ecx,%r10d),%ecx /* Const + dst + ... */ or %edx, %r11d /* x | ... */ xor %eax, %r11d /* y ^ ... */ add %r11d, %ecx /* dst += ... */ mov 5*4(%rsi),%r10d /* (NEXT STEP) X[5] */ mov $0xffffffff, %r11d rol $15, %ecx /* dst <<< s */ xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */ add %edx, %ecx /* dst += x */ lea -57434055(%ebx,%r10d),%ebx /* Const + dst + ... */ or %ecx, %r11d /* x | ... */ xor %edx, %r11d /* y ^ ... */ add %r11d, %ebx /* dst += ... */ mov 12*4(%rsi),%r10d /* (NEXT STEP) X[12] */ mov $0xffffffff, %r11d rol $21, %ebx /* dst <<< s */ xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */ add %ecx, %ebx /* dst += x */ lea 1700485571(%eax,%r10d),%eax /* Const + dst + ... */ or %ebx, %r11d /* x | ... */ xor %ecx, %r11d /* y ^ ... */ add %r11d, %eax /* dst += ... */ mov 3*4(%rsi),%r10d /* (NEXT STEP) X[3] */ mov $0xffffffff, %r11d rol $6, %eax /* dst <<< s */ xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */ add %ebx, %eax /* dst += x */ lea -1894986606(%edx,%r10d),%edx /* Const + dst + ... */ or %eax, %r11d /* x | ... */ xor %ebx, %r11d /* y ^ ... */ add %r11d, %edx /* dst += ... */ mov 10*4(%rsi),%r10d /* (NEXT STEP) X[10] */ mov $0xffffffff, %r11d rol $10, %edx /* dst <<< s */ xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */ add %eax, %edx /* dst += x */ lea -1051523(%ecx,%r10d),%ecx /* Const + dst + ... */ or %edx, %r11d /* x | ... */ xor %eax, %r11d /* y ^ ... */ add %r11d, %ecx /* dst += ... */ mov 1*4(%rsi),%r10d /* (NEXT STEP) X[1] */ mov $0xffffffff, %r11d rol $15, %ecx /* dst <<< s */ xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */ add %edx, %ecx /* dst += x */ lea -2054922799(%ebx,%r10d),%ebx /* Const + dst + ... */ or %ecx, %r11d /* x | ... */ xor %edx, %r11d /* y ^ ... */ add %r11d, %ebx /* dst += ... */ mov 8*4(%rsi),%r10d /* (NEXT STEP) X[8] */ mov $0xffffffff, %r11d rol $21, %ebx /* dst <<< s */ xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */ add %ecx, %ebx /* dst += x */ lea 1873313359(%eax,%r10d),%eax /* Const + dst + ... */ or %ebx, %r11d /* x | ... */ xor %ecx, %r11d /* y ^ ... */ add %r11d, %eax /* dst += ... */ mov 15*4(%rsi),%r10d /* (NEXT STEP) X[15] */ mov $0xffffffff, %r11d rol $6, %eax /* dst <<< s */ xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */ add %ebx, %eax /* dst += x */ lea -30611744(%edx,%r10d),%edx /* Const + dst + ... */ or %eax, %r11d /* x | ... */ xor %ebx, %r11d /* y ^ ... */ add %r11d, %edx /* dst += ... */ mov 6*4(%rsi),%r10d /* (NEXT STEP) X[6] */ mov $0xffffffff, %r11d rol $10, %edx /* dst <<< s */ xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */ add %eax, %edx /* dst += x */ lea -1560198380(%ecx,%r10d),%ecx /* Const + dst + ... */ or %edx, %r11d /* x | ... */ xor %eax, %r11d /* y ^ ... */ add %r11d, %ecx /* dst += ... */ mov 13*4(%rsi),%r10d /* (NEXT STEP) X[13] */ mov $0xffffffff, %r11d rol $15, %ecx /* dst <<< s */ xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */ add %edx, %ecx /* dst += x */ lea 1309151649(%ebx,%r10d),%ebx /* Const + dst + ... */ or %ecx, %r11d /* x | ... */ xor %edx, %r11d /* y ^ ... */ add %r11d, %ebx /* dst += ... */ mov 4*4(%rsi),%r10d /* (NEXT STEP) X[4] */ mov $0xffffffff, %r11d rol $21, %ebx /* dst <<< s */ xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */ add %ecx, %ebx /* dst += x */ lea -145523070(%eax,%r10d),%eax /* Const + dst + ... */ or %ebx, %r11d /* x | ... */ xor %ecx, %r11d /* y ^ ... */ add %r11d, %eax /* dst += ... */ mov 11*4(%rsi),%r10d /* (NEXT STEP) X[11] */ mov $0xffffffff, %r11d rol $6, %eax /* dst <<< s */ xor %ecx, %r11d /* (NEXT STEP) not z' = not %ecx */ add %ebx, %eax /* dst += x */ lea -1120210379(%edx,%r10d),%edx /* Const + dst + ... */ or %eax, %r11d /* x | ... */ xor %ebx, %r11d /* y ^ ... */ add %r11d, %edx /* dst += ... */ mov 2*4(%rsi),%r10d /* (NEXT STEP) X[2] */ mov $0xffffffff, %r11d rol $10, %edx /* dst <<< s */ xor %ebx, %r11d /* (NEXT STEP) not z' = not %ebx */ add %eax, %edx /* dst += x */ lea 718787259(%ecx,%r10d),%ecx /* Const + dst + ... */ or %edx, %r11d /* x | ... */ xor %eax, %r11d /* y ^ ... */ add %r11d, %ecx /* dst += ... */ mov 9*4(%rsi),%r10d /* (NEXT STEP) X[9] */ mov $0xffffffff, %r11d rol $15, %ecx /* dst <<< s */ xor %eax, %r11d /* (NEXT STEP) not z' = not %eax */ add %edx, %ecx /* dst += x */ lea -343485551(%ebx,%r10d),%ebx /* Const + dst + ... */ or %ecx, %r11d /* x | ... */ xor %edx, %r11d /* y ^ ... */ add %r11d, %ebx /* dst += ... */ mov 0*4(%rsi),%r10d /* (NEXT STEP) X[0] */ mov $0xffffffff, %r11d rol $21, %ebx /* dst <<< s */ xor %edx, %r11d /* (NEXT STEP) not z' = not %edx */ add %ecx, %ebx /* dst += x */ # add old values of A, B, C, D add %r8d, %eax add %r9d, %ebx add %r14d, %ecx add %r15d, %edx # loop control add $64, %rsi # ptr += 64 cmp %rdi, %rsi # cmp end with ptr jb 2b # jmp if ptr < end # END of loop over 16-word blocks 1: mov %eax, 0*4(%rbp) # ctx->A = A mov %ebx, 1*4(%rbp) # ctx->B = B mov %ecx, 2*4(%rbp) # ctx->C = C mov %edx, 3*4(%rbp) # ctx->D = D pop %r15 pop %r14 pop %r13 # not really useful (r13 is unused) pop %r12 pop %rbx pop %rbp ret #endif /* } USE_MD5_ASM */ rsync-3.2.7/lib/getaddrinfo.c0000664000000000000000000002502011203060555014555 0ustar rootroot/* PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*------------------------------------------------------------------------- * * getaddrinfo.c * Support getaddrinfo() on platforms that don't have it. * * We also supply getnameinfo() here, assuming that the platform will have * it if and only if it has getaddrinfo(). If this proves false on some * platform, we'll need to split this file and provide a separate configure * test for getnameinfo(). * * Copyright (c) 2003-2007, PostgreSQL Global Development Group * * Copyright (C) 2007 Jeremy Allison. * Modified to return multiple IPv4 addresses for Samba. * *------------------------------------------------------------------------- */ #include "rsync.h" #ifndef SMB_MALLOC #define SMB_MALLOC(s) malloc(s) #endif #ifndef SMB_STRDUP #define SMB_STRDUP(s) strdup(s) #endif #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 #endif static int check_hostent_err(struct hostent *hp) { #ifndef INET6 extern int h_errno; #endif if (!hp) { switch (h_errno) { case HOST_NOT_FOUND: case NO_DATA: return EAI_NONAME; case TRY_AGAIN: return EAI_AGAIN; case NO_RECOVERY: default: return EAI_FAIL; } } if (!hp->h_name || hp->h_addrtype != AF_INET) { return EAI_FAIL; } return 0; } static char *canon_name_from_hostent(struct hostent *hp, int *perr) { char *ret = NULL; *perr = check_hostent_err(hp); if (*perr) { return NULL; } ret = SMB_STRDUP(hp->h_name); if (!ret) { *perr = EAI_MEMORY; } return ret; } static char *get_my_canon_name(int *perr) { char name[HOST_NAME_MAX+1]; if (gethostname(name, HOST_NAME_MAX) == -1) { *perr = EAI_FAIL; return NULL; } /* Ensure null termination. */ name[HOST_NAME_MAX] = '\0'; return canon_name_from_hostent(gethostbyname(name), perr); } static char *get_canon_name_from_addr(struct in_addr ip, int *perr) { return canon_name_from_hostent( gethostbyaddr((void *)&ip, sizeof ip, AF_INET), perr); } static struct addrinfo *alloc_entry(const struct addrinfo *hints, struct in_addr ip, unsigned short port) { struct sockaddr_in *psin = NULL; struct addrinfo *ai = SMB_MALLOC(sizeof(*ai)); if (!ai) { return NULL; } memset(ai, '\0', sizeof(*ai)); psin = SMB_MALLOC(sizeof(*psin)); if (!psin) { free(ai); return NULL; } memset(psin, '\0', sizeof(*psin)); psin->sin_family = AF_INET; psin->sin_port = htons(port); psin->sin_addr = ip; ai->ai_flags = 0; ai->ai_family = AF_INET; ai->ai_socktype = hints->ai_socktype; ai->ai_protocol = hints->ai_protocol; ai->ai_addrlen = sizeof(*psin); ai->ai_addr = (struct sockaddr *) psin; ai->ai_canonname = NULL; ai->ai_next = NULL; return ai; } /* * get address info for a single ipv4 address. * * Bugs: - servname can only be a number, not text. */ static int getaddr_info_single_addr(const char *service, uint32 addr, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *ai = NULL; struct in_addr ip; unsigned short port = 0; if (service) { port = (unsigned short)atoi(service); } ip.s_addr = htonl(addr); ai = alloc_entry(hints, ip, port); if (!ai) { return EAI_MEMORY; } /* If we're asked for the canonical name, * make sure it returns correctly. */ if (!(hints->ai_flags & AI_NUMERICSERV) && hints->ai_flags & AI_CANONNAME) { int err; if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) { ai->ai_canonname = get_my_canon_name(&err); } else { ai->ai_canonname = get_canon_name_from_addr(ip,&err); } if (ai->ai_canonname == NULL) { freeaddrinfo(ai); return err; } } *res = ai; return 0; } /* * get address info for multiple ipv4 addresses. * * Bugs: - servname can only be a number, not text. */ static int getaddr_info_name(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo *listp = NULL, *prevp = NULL; char **pptr = NULL; int err; struct hostent *hp = NULL; unsigned short port = 0; if (service) { port = (unsigned short)atoi(service); } hp = gethostbyname(node); err = check_hostent_err(hp); if (err) { return err; } for(pptr = hp->h_addr_list; *pptr; pptr++) { struct in_addr ip = *(struct in_addr *)*pptr; struct addrinfo *ai = alloc_entry(hints, ip, port); if (!ai) { freeaddrinfo(listp); return EAI_MEMORY; } if (!listp) { listp = ai; prevp = ai; ai->ai_canonname = SMB_STRDUP(hp->h_name); if (!ai->ai_canonname) { freeaddrinfo(listp); return EAI_MEMORY; } } else { prevp->ai_next = ai; prevp = ai; } } *res = listp; return 0; } /* * get address info for ipv4 sockets. * * Bugs: - servname can only be a number, not text. */ int getaddrinfo(const char *node, const char *service, const struct addrinfo * hintp, struct addrinfo ** res) { struct addrinfo hints; /* Setup the hints struct. */ if (hintp == NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; } else { memcpy(&hints, hintp, sizeof(hints)); } if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) { return EAI_FAMILY; } if (hints.ai_socktype == 0) { hints.ai_socktype = SOCK_STREAM; } if (!node && !service) { return EAI_NONAME; } if (node) { if (node[0] == '\0') { return getaddr_info_single_addr(service, INADDR_ANY, &hints, res); } else if (hints.ai_flags & AI_NUMERICHOST) { struct in_addr ip; if (inet_pton(AF_INET, node, &ip) <= 0) return EAI_FAIL; return getaddr_info_single_addr(service, ntohl(ip.s_addr), &hints, res); } else { return getaddr_info_name(node, service, &hints, res); } } else if (hints.ai_flags & AI_PASSIVE) { return getaddr_info_single_addr(service, INADDR_ANY, &hints, res); } return getaddr_info_single_addr(service, INADDR_LOOPBACK, &hints, res); } void freeaddrinfo(struct addrinfo *res) { struct addrinfo *next = NULL; for (;res; res = next) { next = res->ai_next; if (res->ai_canonname) { free(res->ai_canonname); } if (res->ai_addr) { free(res->ai_addr); } free(res); } } const char *gai_strerror(int errcode) { #ifdef HAVE_HSTRERROR int hcode; switch (errcode) { case EAI_NONAME: hcode = HOST_NOT_FOUND; break; case EAI_AGAIN: hcode = TRY_AGAIN; break; case EAI_FAIL: default: hcode = NO_RECOVERY; break; } return hstrerror(hcode); #else /* !HAVE_HSTRERROR */ switch (errcode) { case EAI_NONAME: return "Unknown host"; case EAI_AGAIN: return "Host name lookup failure"; #ifdef EAI_BADFLAGS case EAI_BADFLAGS: return "Invalid argument"; #endif #ifdef EAI_FAMILY case EAI_FAMILY: return "Address family not supported"; #endif #ifdef EAI_MEMORY case EAI_MEMORY: return "Not enough memory"; #endif #ifdef EAI_NODATA case EAI_NODATA: return "No host data of that type was found"; #endif #ifdef EAI_SERVICE case EAI_SERVICE: return "Class type not found"; #endif #ifdef EAI_SOCKTYPE case EAI_SOCKTYPE: return "Socket type not supported"; #endif default: return "Unknown server error"; } #endif /* HAVE_HSTRERROR */ } static int gethostnameinfo(const struct sockaddr *sa, char *node, size_t nodelen, int flags) { int ret = -1; char *p = NULL; if (!(flags & NI_NUMERICHOST)) { struct hostent *hp = gethostbyaddr( (void *)&((struct sockaddr_in *)sa)->sin_addr, sizeof (struct in_addr), sa->sa_family); ret = check_hostent_err(hp); if (ret == 0) { /* Name looked up successfully. */ ret = snprintf(node, nodelen, "%s", hp->h_name); if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } if (flags & NI_NOFQDN) { p = strchr(node,'.'); if (p) { *p = '\0'; } } return 0; } if (flags & NI_NAMEREQD) { /* If we require a name and didn't get one, * automatically fail. */ return ret; } /* Otherwise just fall into the numeric host code... */ } p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); ret = snprintf(node, nodelen, "%s", p); if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } return 0; } static int getservicenameinfo(const struct sockaddr *sa, char *service, size_t servicelen, int flags) { int ret = -1; int port = ntohs(((struct sockaddr_in *)sa)->sin_port); if (!(flags & NI_NUMERICSERV)) { struct servent *se = getservbyport( port, (flags & NI_DGRAM) ? "udp" : "tcp"); if (se && se->s_name) { /* Service name looked up successfully. */ ret = snprintf(service, servicelen, "%s", se->s_name); if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; } /* Otherwise just fall into the numeric service code... */ } ret = snprintf(service, servicelen, "%d", port); if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; } /* * Convert an ipv4 address to a hostname. * * Bugs: - No IPv6 support. */ int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, size_t nodelen, char *service, size_t servicelen, int flags) { /* Invalid arguments. */ if (sa == NULL || (node == NULL && service == NULL)) { return EAI_FAIL; } if (sa->sa_family != AF_INET) { return EAI_FAIL; } if (salen < (socklen_t)sizeof (struct sockaddr_in)) { return EAI_FAIL; } if (node) { int ret = gethostnameinfo(sa, node, nodelen, flags); if (ret) return ret; } if (service) { return getservicenameinfo(sa, service, servicelen, flags); } return 0; } rsync-3.2.7/lib/dummy.in0000664000000000000000000000014606506102135013611 0ustar rootrootThis is a dummy file to ensure that the lib directory gets created by configure when a VPATH is used. rsync-3.2.7/lib/inet_pton.c0000664000000000000000000001173507607624054014313 0ustar rootroot/* * Copyright (C) 1996-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "rsync.h" #define NS_INT16SZ 2 #define NS_INADDRSZ 4 #define NS_IN6ADDRSZ 16 /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4(const char *src, unsigned char *dst); #ifdef INET6 static int inet_pton6(const char *src, unsigned char *dst); #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return (inet_pton4(src, dst)); #ifdef INET6 case AF_INET6: return (inet_pton6(src, dst)); #endif default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(src, dst) const char *src; unsigned char *dst; { static const char digits[] = "0123456789"; int saw_digit, octets, ch; unsigned char tmp[NS_INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { unsigned int new = *tp * 10 + (pch - digits); if (new > 255) return (0); *tp = new; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ #ifdef INET6 static int inet_pton6(src, dst) const char *src; unsigned char *dst; { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; unsigned int val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (unsigned char) (val >> 8) & 0xff; *tp++ = (unsigned char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } #endif rsync-3.2.7/lib/permstring.c0000664000000000000000000000345013443220465014472 0ustar rootroot/* * A single utility routine. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001 Martin Pool * Copyright (C) 2003-2019 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" /* Produce a string representation of Unix mode bits like that used by ls(1). * The "buf" buffer must be at least 11 characters. */ void permstring(char *perms, mode_t mode) { static const char *perm_map = "rwxrwxrwx"; int i; strlcpy(perms, "----------", 11); for (i = 0; i < 9; i++) { if (mode & (1 << i)) perms[9-i] = perm_map[8-i]; } /* Handle setuid/sticky bits. You might think the indices are * off by one, but remember there's a type char at the * start. */ if (mode & S_ISUID) perms[3] = (mode & S_IXUSR) ? 's' : 'S'; if (mode & S_ISGID) perms[6] = (mode & S_IXGRP) ? 's' : 'S'; #ifdef S_ISVTX if (mode & S_ISVTX) perms[9] = (mode & S_IXOTH) ? 't' : 'T'; #endif if (S_ISDIR(mode)) perms[0] = 'd'; else if (S_ISLNK(mode)) perms[0] = 'l'; else if (S_ISBLK(mode)) perms[0] = 'b'; else if (S_ISCHR(mode)) perms[0] = 'c'; else if (S_ISSOCK(mode)) perms[0] = 's'; else if (S_ISFIFO(mode)) perms[0] = 'p'; } rsync-3.2.7/lib/pool_alloc.30000664000000000000000000001530013702777121014344 0ustar rootroot.ds d \-\^\- .ds o \fR[\fP .ds c \fR]\fP .ds | \fR|\fP .de D \\.B \*d\\$1 .. .de DI \\.BI \*d\\$1 \\$2 .. .de DR \\.BR \*d\\$1 \\$2 .. .de Di \\.BI \*d\\$1 " \\$2" .. .de Db \\.B \*d\\$1 " \\$2" .. .de Df \\.B \*d\*ono\*c\\$1 .. .de See See \fB\\$1\fP for details. .. .de SeeIn See \fB\\$1\fP in \fB\\$2\fP for details. .. .TH POOL_ALLOC 3 .SH NAME pool_alloc, pool_free, pool_free_old, pool_talloc, pool_tfree, pool_create, pool_destroy, pool_boundary \- Allocate and free memory in managed allocation pools. .SH SYNOPSIS .B #include "pool_alloc.h" \fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char*,char*,int), int \fIflags\fB); \fBvoid pool_destroy(struct alloc_pool *\fIpool\fB); \fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB); \fBvoid pool_free(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, void *\fIaddr\fB); \fBvoid pool_free_old(struct alloc_pool *\fIpool\fB, void *\fIaddr\fB); \fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB); \fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB); \fBvoid pool_boundary(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB); .SH DESCRIPTION .P The pool allocation routines use .B malloc() for underlying memory management. What allocation pools do is cause memory within a given pool to be allocated in large contiguous blocks (called extents) that will be reusable when freed. Unlike .BR malloc() , the allocations are not managed individually. Instead, each extent tracks the total free memory within the extent. Each extent can either be used to allocate memory or to manage the freeing of memory within that extent. When an extent has less free memory than a given allocation request, the current extent ceases to be used for allocation. See also the .B pool_boundary() function. .P This form of memory management is suited to large numbers of small related allocations that are held for a while and then freed as a group. Because the underlying allocations are done in large contiguous extents, when an extent is freed, it can release a large enough contiguous block of memory to allow the memory to be returned to the OS for use by whatever program needs it. You can allocate from one or more memory pools and/or .B malloc() all at the same time without interfering with how pools work. .P .B pool_create() Creates an allocation pool for subsequent calls to the pool allocation functions. When an extent is created for allocations it will be .I size bytes. Allocations from the pool have their sizes rounded up to a multiple of .I quantum bytes in length. Specifying .B 0 for .I quantum will produce a quantum that should meet maximal alignment on most platforms. Unless .B POOL_NO_QALIGN is set in the .IR flags , allocations will be aligned to addresses that are a multiple of .IR quantum . A .B NULL may be specified for the .I bomb function pointer if it is not needed. (See the .B pool_alloc() function for how it is used.) If .B POOL_CLEAR is set in the .IR flags , all allocations from the pool will be initialized to zeros. If either .B POOL_PREPEND or .B POOL_INTERN is specified in the .IR flags , each extent's data structure will be allocated at the start of the .IR size -length buffer (rather than as a separate, non-pool allocation), with the former extending the .I size to hold the structure, and the latter subtracting the structure's length from the indicated .IR size . .P .B pool_destroy() destroys an allocation .I pool and frees all its associated memory. .P .B pool_alloc() allocates .I size bytes from the specified .IR pool . If .I size is .BR 0 , .I quantum bytes will be allocated. If the pool has been created without .BR POOL_NO_QALIGN , every chunk of memory that is returned will be suitably aligned. You can use this with the default .I quantum size to ensure that all memory can store a variable of any type. If the requested memory cannot be allocated, the .I bomb() function will be called with .I msg as its sole argument (if the function was defined at the time the pool was created), and then a .B NULL address is returned (assuming that the bomb function didn't exit). .P .B pool_free() frees .I size bytes pointed to by an .I addr that was previously allocated in the specified .IR pool . If .I size is .BR 0 , .I quantum bytes will be freed. The memory freed within an extent will not be reusable until all of the memory in that extent has been freed with one exception: the most recent pool allocation may be freed back into the pool prior to making any further allocations. If enough free calls are made to indicate that an extent has no remaining allocated objects (as computed by the total freed size for an extent), its memory will be completely freed back to the system. If .I addr is .BR NULL , no memory will be freed, but subsequent allocations will come from a new extent. .P .B pool_free_old() takes a boundary .I addr value that was returned by .B pool_boundary() and frees up any extents in the .I pool that have data allocated from that point backward in time. NOTE: you must NOT mix calls to both .B pool_free and .B pool_free_old on the same pool! .P .B pool_boundary() asks for a boundary value that can be sent to .B pool_free_old() at a later time to free up all memory allocated prior to a particular moment in time. If the extent that holds the boundary point has allocations from after the boundary point, it will not be freed until a future .B pool_free_old() call encompasses the entirety of the extent's data. If .I len is non-zero, the call will also check if the active extent has at least that much free memory available in it, and if not, it will mark the extent as inactive, forcing a new extent to be used for future allocations. (You can specify -1 for .I len if you want to force a new extent to start.) .P .B pool_talloc() is a macro that takes a .I type and a .I count instead of a .IR size . It casts the return value to the correct pointer type. .P .B pool_tfree is a macro that calls .B pool_free on memory that was allocated by .BR pool_talloc() . .SH RETURN VALUE .B pool_create() returns a pointer to .BR "struct alloc_pool" . .P .B pool_alloc() and .B pool_talloc() return pointers to the allocated memory, or NULL if the request fails. The return type of .B pool_alloc() will normally require casting to the desired type but .B pool_talloc() will returns a pointer of the requested .IR type . .P .B pool_boundary() returns a pointer that should only be used in a call to .BR pool_free_old() . .P .BR pool_free() , .BR pool_free_old() , .B pool_tfree() and .B pool_destroy() return no value. .SH SEE ALSO .nf malloc(3) .SH AUTHOR pool_alloc was created by J.W. Schultz of Pegasystems Technologies. .SH BUGS AND ISSUES rsync-3.2.7/lib/compat.c0000664000000000000000000001412313702403550013556 0ustar rootroot/* * Reimplementations of standard functions for platforms that don't have them. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2020 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 "itypes.h" static char number_separator; char get_number_separator(void) { if (!number_separator) { char buf[32]; snprintf(buf, sizeof buf, "%f", 3.14); if (strchr(buf, '.') != NULL) number_separator = ','; else number_separator = '.'; } return number_separator; } char get_decimal_point(void) { return get_number_separator() == ',' ? '.' : ','; } #ifndef HAVE_GETCWD char *getcwd(char *buf, int size) { return getwd(buf); } #endif #ifndef HAVE_WAITPID pid_t waitpid(pid_t pid, int *statptr, int options) { #ifdef HAVE_WAIT4 return wait4(pid, statptr, options, NULL); #else /* If wait4 is also not available, try wait3 for SVR3 variants */ /* Less ideal because can't actually request a specific pid */ /* At least the WNOHANG option is supported */ /* Code borrowed from apache fragment written by dwd@bell-labs.com */ int tmp_pid, dummystat;; if (kill(pid, 0) == -1) { errno = ECHILD; return -1; } if (statptr == NULL) statptr = &dummystat; while (((tmp_pid = wait3(statptr, options, 0)) != pid) && (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1)) ; return tmp_pid; #endif } #endif #ifndef HAVE_MEMMOVE void *memmove(void *dest, const void *src, size_t n) { bcopy((char *) src, (char *) dest, n); return dest; } #endif #ifndef HAVE_STRPBRK /** * Find the first occurrence in @p s of any character in @p accept. * * Derived from glibc **/ char *strpbrk(const char *s, const char *accept) { while (*s != '\0') { const char *a = accept; while (*a != '\0') { if (*a++ == *s) return (char *)s; } ++s; } return NULL; } #endif #ifndef HAVE_STRLCPY /** * Like strncpy but does not 0 fill the buffer and always null * terminates. * * @param bufsize is the size of the destination buffer. * * @return index of the terminating byte. **/ size_t strlcpy(char *d, const char *s, size_t bufsize) { size_t len = strlen(s); size_t ret = len; if (bufsize > 0) { if (len >= bufsize) len = bufsize-1; memcpy(d, s, len); d[len] = 0; } return ret; } #endif #ifndef HAVE_STRLCAT /** * Like strncat() but does not 0 fill the buffer and always null * terminates. * * @param bufsize length of the buffer, which should be one more than * the maximum resulting string length. **/ size_t strlcat(char *d, const char *s, size_t bufsize) { size_t len1 = strlen(d); size_t len2 = strlen(s); size_t ret = len1 + len2; if (len1 < bufsize - 1) { if (len2 >= bufsize - len1) len2 = bufsize - len1 - 1; memcpy(d+len1, s, len2); d[len1+len2] = 0; } return ret; } #endif /* some systems don't take the 2nd argument */ int sys_gettimeofday(struct timeval *tv) { #ifdef HAVE_GETTIMEOFDAY_TZ return gettimeofday(tv, NULL); #else return gettimeofday(tv); #endif } /* Return the int64 number as a string. If the human_flag arg is non-zero, * we may output the number in K, M, G, or T units. If we don't add a unit * suffix, we will append the fract string, if it is non-NULL. We can * return up to 4 buffers at a time. */ char *do_big_num(int64 num, int human_flag, const char *fract) { static char bufs[4][128]; /* more than enough room */ static unsigned int n; char *s; int len, negated; if (human_flag && !number_separator) (void)get_number_separator(); n = (n + 1) % (sizeof bufs / sizeof bufs[0]); if (human_flag > 1) { int mult = human_flag == 2 ? 1000 : 1024; if (num >= mult || num <= -mult) { double dnum = (double)num / mult; char units; if (num < 0) dnum = -dnum; if (dnum < mult) units = 'K'; else if ((dnum /= mult) < mult) units = 'M'; else if ((dnum /= mult) < mult) units = 'G'; else if ((dnum /= mult) < mult) units = 'T'; else { dnum /= mult; units = 'P'; } if (num < 0) dnum = -dnum; snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); return bufs[n]; } } s = bufs[n] + sizeof bufs[0] - 1; if (fract) { len = strlen(fract); s -= len; strlcpy(s, fract, len + 1); } else *s = '\0'; len = 0; if (!num) *--s = '0'; if (num < 0) { /* A maximum-size negated number can't fit as a positive, * so do one digit in negated form to start us off. */ *--s = (char)(-(num % 10)) + '0'; num = -(num / 10); len++; negated = 1; } else negated = 0; while (num) { if (human_flag) { if (len == 3) { *--s = number_separator; len = 1; } else len++; } *--s = (char)(num % 10) + '0'; num /= 10; } if (negated) *--s = '-'; return s; } /* Return the double number as a string. If the human_flag option is > 1, * we may output the number in K, M, G, or T units. The buffer we use for * our result is either a single static buffer defined here, or a buffer * we get from do_big_num(). */ char *do_big_dnum(double dnum, int human_flag, int decimal_digits) { static char tmp_buf[128]; #if SIZEOF_INT64 >= 8 char *fract; snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum); if (!human_flag || (dnum < 1000.0 && dnum > -1000.0)) return tmp_buf; for (fract = tmp_buf+1; isDigit(fract); fract++) {} return do_big_num((int64)dnum, human_flag, fract); #else /* A big number might lose digits converting to a too-short int64, * so let's just return the raw double conversion. */ snprintf(tmp_buf, sizeof tmp_buf, "%.*f", decimal_digits, dnum); return tmp_buf; #endif } rsync-3.2.7/lib/addrinfo.h0000664000000000000000000001127210714461012014065 0ustar rootroot/* PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*------------------------------------------------------------------------- * * getaddrinfo.h * Support getaddrinfo() on platforms that don't have it. * * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, * whether or not the library routine getaddrinfo() can be found. This * policy is needed because on some platforms a manually installed libbind.a * may provide getaddrinfo(), yet the system headers may not provide the * struct definitions needed to call it. To avoid conflict with the libbind * definition in such cases, we rename our routines to pg_xxx() via macros. * * This code will also work on platforms where struct addrinfo is defined * in the system headers but no getaddrinfo() can be located. * * Copyright (c) 2003-2007, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ #ifndef ADDRINFO_H #define ADDRINFO_H /* Various macros that ought to be in , but might not be */ #ifndef EAI_FAIL #define EAI_BADFLAGS (-1) #define EAI_NONAME (-2) #define EAI_AGAIN (-3) #define EAI_FAIL (-4) #define EAI_FAMILY (-6) #define EAI_SOCKTYPE (-7) #define EAI_SERVICE (-8) #define EAI_MEMORY (-10) #define EAI_SYSTEM (-11) #endif /* !EAI_FAIL */ #ifndef AI_PASSIVE #define AI_PASSIVE 0x0001 #endif #ifndef AI_NUMERICHOST /* * some platforms don't support AI_NUMERICHOST; define as zero if using * the system version of getaddrinfo... */ #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_NUMERICHOST 0 #else #define AI_NUMERICHOST 0x0004 #endif #endif #ifndef AI_CANONNAME #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_CANONNAME 0 #else #define AI_CANONNAME 0x0008 #endif #endif #ifndef AI_NUMERICSERV #if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) #define AI_NUMERICSERV 0 #else #define AI_NUMERICSERV 0x0010 #endif #endif #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 1 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 2 #endif #ifndef NI_NOFQDN #define NI_NOFQDN 4 #endif #ifndef NI_NAMEREQD #define NI_NAMEREQD 8 #endif #ifndef NI_DGRAM #define NI_DGRAM 16 #endif #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif #ifndef HAVE_STRUCT_ADDRINFO struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; #endif /* !HAVE_STRUCT_ADDRINFO */ #ifndef HAVE_STRUCT_SOCKADDR_STORAGE struct sockaddr_storage { unsigned short ss_family; unsigned long ss_align; char ss_padding[128 - sizeof (unsigned long)]; }; #endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ #ifndef HAVE_GETADDRINFO /* Rename private copies per comments above */ #ifdef getaddrinfo #undef getaddrinfo #endif #define getaddrinfo pg_getaddrinfo #ifdef freeaddrinfo #undef freeaddrinfo #endif #define freeaddrinfo pg_freeaddrinfo #ifdef gai_strerror #undef gai_strerror #endif #define gai_strerror pg_gai_strerror #ifdef getnameinfo #undef getnameinfo #endif #define getnameinfo pg_getnameinfo extern int getaddrinfo(const char *node, const char *service, const struct addrinfo * hints, struct addrinfo ** res); extern void freeaddrinfo(struct addrinfo * res); extern const char *gai_strerror(int errcode); extern int getnameinfo(const struct sockaddr * sa, socklen_t salen, char *node, size_t nodelen, char *service, size_t servicelen, int flags); #endif /* !HAVE_GETADDRINFO */ #endif /* ADDRINFO_H */ rsync-3.2.7/lib/md5.c0000664000000000000000000001664514307154751013003 0ustar rootroot/* * RFC 1321 compliant MD5 implementation * * Copyright (C) 2001-2003 Christophe Devine * Copyright (C) 2007-2022 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" void md5_begin(md_context *ctx) { ctx->A = 0x67452301; ctx->B = 0xEFCDAB89; ctx->C = 0x98BADCFE; ctx->D = 0x10325476; ctx->totalN = ctx->totalN2 = 0; } static void md5_process(md_context *ctx, const uchar data[CSUM_CHUNK]) { uint32 X[16], A, B, C, D; A = ctx->A; B = ctx->B; C = ctx->C; D = ctx->D; X[0] = IVALu(data, 0); X[1] = IVALu(data, 4); X[2] = IVALu(data, 8); X[3] = IVALu(data, 12); X[4] = IVALu(data, 16); X[5] = IVALu(data, 20); X[6] = IVALu(data, 24); X[7] = IVALu(data, 28); X[8] = IVALu(data, 32); X[9] = IVALu(data, 36); X[10] = IVALu(data, 40); X[11] = IVALu(data, 44); X[12] = IVALu(data, 48); X[13] = IVALu(data, 52); X[14] = IVALu(data, 56); X[15] = IVALu(data, 60); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a,b,c,d,k,s,t) a += F(b,c,d) + X[k] + t, a = S(a,s) + b #define F(x,y,z) (z ^ (x & (y ^ z))) P(A, B, C, D, 0, 7, 0xD76AA478); P(D, A, B, C, 1, 12, 0xE8C7B756); P(C, D, A, B, 2, 17, 0x242070DB); P(B, C, D, A, 3, 22, 0xC1BDCEEE); P(A, B, C, D, 4, 7, 0xF57C0FAF); P(D, A, B, C, 5, 12, 0x4787C62A); P(C, D, A, B, 6, 17, 0xA8304613); P(B, C, D, A, 7, 22, 0xFD469501); P(A, B, C, D, 8, 7, 0x698098D8); P(D, A, B, C, 9, 12, 0x8B44F7AF); P(C, D, A, B, 10, 17, 0xFFFF5BB1); P(B, C, D, A, 11, 22, 0x895CD7BE); P(A, B, C, D, 12, 7, 0x6B901122); P(D, A, B, C, 13, 12, 0xFD987193); P(C, D, A, B, 14, 17, 0xA679438E); P(B, C, D, A, 15, 22, 0x49B40821); #undef F #define F(x,y,z) (y ^ (z & (x ^ y))) P(A, B, C, D, 1, 5, 0xF61E2562); P(D, A, B, C, 6, 9, 0xC040B340); P(C, D, A, B, 11, 14, 0x265E5A51); P(B, C, D, A, 0, 20, 0xE9B6C7AA); P(A, B, C, D, 5, 5, 0xD62F105D); P(D, A, B, C, 10, 9, 0x02441453); P(C, D, A, B, 15, 14, 0xD8A1E681); P(B, C, D, A, 4, 20, 0xE7D3FBC8); P(A, B, C, D, 9, 5, 0x21E1CDE6); P(D, A, B, C, 14, 9, 0xC33707D6); P(C, D, A, B, 3, 14, 0xF4D50D87); P(B, C, D, A, 8, 20, 0x455A14ED); P(A, B, C, D, 13, 5, 0xA9E3E905); P(D, A, B, C, 2, 9, 0xFCEFA3F8); P(C, D, A, B, 7, 14, 0x676F02D9); P(B, C, D, A, 12, 20, 0x8D2A4C8A); #undef F #define F(x,y,z) (x ^ y ^ z) P(A, B, C, D, 5, 4, 0xFFFA3942); P(D, A, B, C, 8, 11, 0x8771F681); P(C, D, A, B, 11, 16, 0x6D9D6122); P(B, C, D, A, 14, 23, 0xFDE5380C); P(A, B, C, D, 1, 4, 0xA4BEEA44); P(D, A, B, C, 4, 11, 0x4BDECFA9); P(C, D, A, B, 7, 16, 0xF6BB4B60); P(B, C, D, A, 10, 23, 0xBEBFBC70); P(A, B, C, D, 13, 4, 0x289B7EC6); P(D, A, B, C, 0, 11, 0xEAA127FA); P(C, D, A, B, 3, 16, 0xD4EF3085); P(B, C, D, A, 6, 23, 0x04881D05); P(A, B, C, D, 9, 4, 0xD9D4D039); P(D, A, B, C, 12, 11, 0xE6DB99E5); P(C, D, A, B, 15, 16, 0x1FA27CF8); P(B, C, D, A, 2, 23, 0xC4AC5665); #undef F #define F(x,y,z) (y ^ (x | ~z)) P(A, B, C, D, 0, 6, 0xF4292244); P(D, A, B, C, 7, 10, 0x432AFF97); P(C, D, A, B, 14, 15, 0xAB9423A7); P(B, C, D, A, 5, 21, 0xFC93A039); P(A, B, C, D, 12, 6, 0x655B59C3); P(D, A, B, C, 3, 10, 0x8F0CCC92); P(C, D, A, B, 10, 15, 0xFFEFF47D); P(B, C, D, A, 1, 21, 0x85845DD1); P(A, B, C, D, 8, 6, 0x6FA87E4F); P(D, A, B, C, 15, 10, 0xFE2CE6E0); P(C, D, A, B, 6, 15, 0xA3014314); P(B, C, D, A, 13, 21, 0x4E0811A1); P(A, B, C, D, 4, 6, 0xF7537E82); P(D, A, B, C, 11, 10, 0xBD3AF235); P(C, D, A, B, 2, 15, 0x2AD7D2BB); P(B, C, D, A, 9, 21, 0xEB86D391); #undef F ctx->A += A; ctx->B += B; ctx->C += C; ctx->D += D; } #ifdef USE_MD5_ASM #if CSUM_CHUNK != 64 #error The MD5 ASM code does not support CSUM_CHUNK != 64 #endif extern void md5_process_asm(md_context *ctx, const void *data, size_t num); #endif void md5_update(md_context *ctx, const uchar *input, uint32 length) { uint32 left, fill; if (!length) return; left = ctx->totalN & 0x3F; fill = CSUM_CHUNK - left; ctx->totalN += length; ctx->totalN &= 0xFFFFFFFF; if (ctx->totalN < length) ctx->totalN2++; if (left && length >= fill) { memcpy(ctx->buffer + left, input, fill); md5_process(ctx, ctx->buffer); length -= fill; input += fill; left = 0; } #ifdef USE_MD5_ASM /* { */ if (length >= CSUM_CHUNK) { uint32 chunks = length / CSUM_CHUNK; md5_process_asm(ctx, input, chunks); length -= chunks * CSUM_CHUNK; input += chunks * CSUM_CHUNK; } #else /* } { */ while (length >= CSUM_CHUNK) { md5_process(ctx, input); length -= CSUM_CHUNK; input += CSUM_CHUNK; } #endif /* } */ if (length) memcpy(ctx->buffer + left, input, length); } static uchar md5_padding[CSUM_CHUNK] = { 0x80 }; void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]) { uint32 last, padn; uint32 high, low; uchar msglen[8]; high = (ctx->totalN >> 29) | (ctx->totalN2 << 3); low = (ctx->totalN << 3); SIVALu(msglen, 0, low); SIVALu(msglen, 4, high); last = ctx->totalN & 0x3F; padn = last < 56 ? 56 - last : 120 - last; md5_update(ctx, md5_padding, padn); md5_update(ctx, msglen, 8); SIVALu(digest, 0, ctx->A); SIVALu(digest, 4, ctx->B); SIVALu(digest, 8, ctx->C); SIVALu(digest, 12, ctx->D); } #ifdef TEST_MD5 /* { */ void get_md5(uchar *out, const uchar *input, int n) { md_context ctx; md5_begin(&ctx); md5_update(&ctx, input, n); md5_result(&ctx, out); } #include #include /* * those are the standard RFC 1321 test vectors */ static struct { char *str, *md5; } tests[] = { { "", "d41d8cd98f00b204e9800998ecf8427e" }, { "a", "0cc175b9c0f1b6a831c399e269772661" }, { "abc", "900150983cd24fb0d6963f7d28e17f72" }, { "message digest", "f96b697d7cb7938d525a2f31aaf161d0" }, { "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b" }, { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f" }, { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" }, { NULL, NULL } }; int main(int argc, char *argv[]) { FILE *f; int i, j; char output[33]; md_context ctx; uchar buf[1000]; uchar md5sum[MD5_DIGEST_LEN]; if (argc < 2) { printf("\nMD5 Validation Tests:\n\n"); for (i = 0; tests[i].str; i++) { char *str = tests[i].str; char *chk = tests[i].md5; printf(" Test %d ", i + 1); get_md5(md5sum, str, strlen(str)); for (j = 0; j < MD5_DIGEST_LEN; j++) sprintf(output + j * 2, "%02x", md5sum[j]); if (memcmp(output, chk, 32)) { printf("failed!\n"); return 1; } printf("passed.\n"); } printf("\n"); return 0; } while (--argc) { if (!(f = fopen(*++argv, "rb"))) { perror("fopen"); return 1; } md5_begin(&ctx); while ((i = fread(buf, 1, sizeof buf, f)) > 0) md5_update(&ctx, buf, i); md5_result(&ctx, md5sum); for (j = 0; j < MD5_DIGEST_LEN; j++) printf("%02x", md5sum[j]); printf(" %s\n", *argv); } return 0; } #endif /* } */ rsync-3.2.7/lib/snprintf.c0000664000000000000000000010637514171062362014154 0ustar rootroot/* * NOTE: If you change this file, please merge it into rsync, samba, etc. */ /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nasty effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formatted the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -I.. -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * * tridge@samba.org, idra@samba.org, April 2001 * got rid of fcvt code (twas buggy and made testing harder) * added C99 semantics * * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 * actually print args for %g and %e * * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 * Since includes.h isn't included here, VA_COPY has to be defined here. I don't * see any include file that is guaranteed to be here, so I'm defining it * locally. Fixes AIX and Solaris builds. * * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of * functions * * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 * Fix usage of va_list passed as an arg. Use __va_copy before using it * when it exists. * * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 * Fix incorrect zpadlen handling in fmtfp. * Thanks to Ollie Oldham for spotting it. * few mods to make it easier to compile the tests. * added the "Ollie" test to the floating point ones. * * Martin Pool (mbp@samba.org) April 2003 * Remove NO_CONFIG_H so that the test case can be built within a source * tree with less trouble. * Remove unnecessary SAFE_FREE() definition. * * Martin Pool (mbp@samba.org) May 2003 * Put in a prototype for dummy_snprintf() to quiet compiler warnings. * * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even * if the C library has some snprintf functions already. * * Darren Tucker (dtucker@zip.com.au) 2005 * Fix bug allowing read overruns of the source string with "%.*s" * Usually harmless unless the read runs outside the process' allocation * (eg if your malloc does guard pages) in which case it will segfault. * From OpenSSH. Also added test for same. * * Simo Sorce (idra@samba.org) Jan 2006 * * Add support for position independent parameters * fix fmtstr now it conforms to sprintf wrt min.max * **************************************************************/ #include "config.h" #ifdef TEST_SNPRINTF /* need math library headers for testing */ /* In test mode, we pretend that this system doesn't have any snprintf * functions, regardless of what config.h says. */ # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # undef HAVE_C99_VSNPRINTF # undef HAVE_ASPRINTF # undef HAVE_VASPRINTF # include #endif /* TEST_SNPRINTF */ #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #include #include #ifdef HAVE_STDLIB_H #include #endif #if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) /* only include stdio.h if we are not re-defining snprintf or vsnprintf */ #include /* make the compiler happy with an empty file */ void dummy_snprintf(void); void dummy_snprintf(void) {} #endif /* HAVE_SNPRINTF, etc */ #ifdef STDC_HEADERS #include #endif #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else #define LDOUBLE double #endif #if !defined HAVE_LONG_LONG && SIZEOF_LONG_LONG #define HAVE_LONG_LONG 1 #endif #ifdef HAVE_LONG_LONG #define LLONG long long #else #define LLONG long #endif #ifndef VA_COPY #if defined HAVE_VA_COPY || defined va_copy #define VA_COPY(dest, src) va_copy(dest, src) #else #ifdef HAVE___VA_COPY #define VA_COPY(dest, src) __va_copy(dest, src) #else #define VA_COPY(dest, src) (dest) = (src) #endif #endif #endif /* yes this really must be a ||. Don't muck with this (tridge) */ #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_CHAR 1 #define DP_C_SHORT 2 #define DP_C_LONG 3 #define DP_C_LDOUBLE 4 #define DP_C_LLONG 5 #define DP_C_SIZET 6 /* Chunk types */ #define CNK_FMT_STR 0 #define CNK_INT 1 #define CNK_OCTAL 2 #define CNK_UINT 3 #define CNK_HEX 4 #define CNK_FLOAT 5 #define CNK_CHAR 6 #define CNK_STRING 7 #define CNK_PTR 8 #define CNK_NUM 9 #define CNK_PRCNT 10 #define char_to_int(p) ((p)- '0') #ifndef MAX #define MAX(p,q) (((p) >= (q)) ? (p) : (q)) #endif struct pr_chunk { int type; /* chunk type */ int num; /* parameter number */ int min; int max; int flags; int cflags; int start; int len; LLONG value; LDOUBLE fvalue; char *strvalue; void *pnum; struct pr_chunk *min_star; struct pr_chunk *max_star; struct pr_chunk *next; }; struct pr_chunk_x { struct pr_chunk **chunks; int num; }; static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in); static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); static struct pr_chunk *new_chunk(void); static int add_cnk_list_entry(struct pr_chunk_x **list, int max_num, struct pr_chunk *chunk); static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) { char ch; int state; int pflag; int pnum; int pfirst; size_t currlen; va_list args; const char *base; struct pr_chunk *chunks = NULL; struct pr_chunk *cnk = NULL; struct pr_chunk_x *clist = NULL; int max_pos; int ret = -1; VA_COPY(args, args_in); state = DP_S_DEFAULT; pfirst = 1; pflag = 0; pnum = 0; max_pos = 0; base = format; ch = *format++; /* retrieve the string structure as chunks */ while (state != DP_S_DONE) { if (ch == '\0') state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: if (cnk) { cnk->next = new_chunk(); cnk = cnk->next; } else { cnk = new_chunk(); } if (!cnk) goto done; if (!chunks) chunks = cnk; if (ch == '%') { state = DP_S_FLAGS; ch = *format++; } else { cnk->type = CNK_FMT_STR; cnk->start = format - base -1; while ((ch != '\0') && (ch != '%')) ch = *format++; cnk->len = format - base - cnk->start -1; } break; case DP_S_FLAGS: switch (ch) { case '-': cnk->flags |= DP_F_MINUS; ch = *format++; break; case '+': cnk->flags |= DP_F_PLUS; ch = *format++; break; case ' ': cnk->flags |= DP_F_SPACE; ch = *format++; break; case '#': cnk->flags |= DP_F_NUM; ch = *format++; break; case '0': cnk->flags |= DP_F_ZERO; ch = *format++; break; case 'I': /* internationalization not supported yet */ ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { cnk->min = 10 * cnk->min + char_to_int (ch); ch = *format++; } else if (ch == '$') { if (!pfirst && !pflag) { /* parameters must be all positioned or none */ goto done; } if (pfirst) { pfirst = 0; pflag = 1; } if (cnk->min == 0) /* what ?? */ goto done; cnk->num = cnk->min; cnk->min = 0; ch = *format++; } else if (ch == '*') { if (pfirst) pfirst = 0; cnk->min_star = new_chunk(); if (!cnk->min_star) /* out of memory :-( */ goto done; cnk->min_star->type = CNK_INT; if (pflag) { int num; ch = *format++; if (!isdigit((unsigned char)ch)) { /* parameters must be all positioned or none */ goto done; } for (num = 0; isdigit((unsigned char)ch); ch = *format++) { num = 10 * num + char_to_int(ch); } cnk->min_star->num = num; if (ch != '$') /* what ?? */ goto done; } else { cnk->min_star->num = ++pnum; } max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); if (max_pos == 0) /* out of memory :-( */ goto done; ch = *format++; state = DP_S_DOT; } else { if (pfirst) pfirst = 0; state = DP_S_DOT; } break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else { state = DP_S_MOD; } break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { if (cnk->max < 0) cnk->max = 0; cnk->max = 10 * cnk->max + char_to_int (ch); ch = *format++; } else if (ch == '$') { if (!pfirst && !pflag) { /* parameters must be all positioned or none */ goto done; } if (cnk->max <= 0) /* what ?? */ goto done; cnk->num = cnk->max; cnk->max = -1; ch = *format++; } else if (ch == '*') { cnk->max_star = new_chunk(); if (!cnk->max_star) /* out of memory :-( */ goto done; cnk->max_star->type = CNK_INT; if (pflag) { int num; ch = *format++; if (!isdigit((unsigned char)ch)) { /* parameters must be all positioned or none */ goto done; } for (num = 0; isdigit((unsigned char)ch); ch = *format++) { num = 10 * num + char_to_int(ch); } cnk->max_star->num = num; if (ch != '$') /* what ?? */ goto done; } else { cnk->max_star->num = ++pnum; } max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); if (max_pos == 0) /* out of memory :-( */ goto done; ch = *format++; state = DP_S_MOD; } else { state = DP_S_MOD; } break; case DP_S_MOD: switch (ch) { case 'h': cnk->cflags = DP_C_SHORT; ch = *format++; if (ch == 'h') { cnk->cflags = DP_C_CHAR; ch = *format++; } break; case 'l': cnk->cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { /* It's a long long */ cnk->cflags = DP_C_LLONG; ch = *format++; } break; case 'L': cnk->cflags = DP_C_LDOUBLE; ch = *format++; break; case 'z': cnk->cflags = DP_C_SIZET; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: if (cnk->num == 0) cnk->num = ++pnum; max_pos = add_cnk_list_entry(&clist, max_pos, cnk); if (max_pos == 0) /* out of memory :-( */ goto done; switch (ch) { case 'd': case 'i': cnk->type = CNK_INT; break; case 'o': cnk->type = CNK_OCTAL; cnk->flags |= DP_F_UNSIGNED; break; case 'u': cnk->type = CNK_UINT; cnk->flags |= DP_F_UNSIGNED; break; case 'X': cnk->flags |= DP_F_UP; case 'x': cnk->type = CNK_HEX; cnk->flags |= DP_F_UNSIGNED; break; case 'A': /* hex float not supported yet */ case 'E': case 'G': case 'F': cnk->flags |= DP_F_UP; case 'a': /* hex float not supported yet */ case 'e': case 'f': case 'g': cnk->type = CNK_FLOAT; break; case 'c': cnk->type = CNK_CHAR; break; case 's': cnk->type = CNK_STRING; break; case 'p': cnk->type = CNK_PTR; cnk->flags |= DP_F_UNSIGNED; break; case 'n': cnk->type = CNK_NUM; break; case '%': cnk->type = CNK_PRCNT; break; default: /* Unknown, bail out*/ goto done; } ch = *format++; state = DP_S_DEFAULT; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } /* retrieve the format arguments */ for (pnum = 0; pnum < max_pos; pnum++) { int i; if (clist[pnum].num == 0) { /* ignoring a parameter should not be permitted * all parameters must be matched at least once * BUT seem some system ignore this rule ... * at least my glibc based system does --SSS */ #ifdef DEBUG_SNPRINTF printf("parameter at position %d not used\n", pnum+1); #endif /* eat the parameter */ va_arg (args, int); continue; } for (i = 1; i < clist[pnum].num; i++) { if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) { /* nooo noo no! * all the references to a parameter * must be of the same type */ goto done; } } cnk = clist[pnum].chunks[0]; switch (cnk->type) { case CNK_INT: if (cnk->cflags == DP_C_SHORT) cnk->value = va_arg (args, int); else if (cnk->cflags == DP_C_LONG) cnk->value = va_arg (args, long int); else if (cnk->cflags == DP_C_LLONG) cnk->value = va_arg (args, LLONG); else if (cnk->cflags == DP_C_SIZET) cnk->value = va_arg (args, ssize_t); else cnk->value = va_arg (args, int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_OCTAL: case CNK_UINT: case CNK_HEX: if (cnk->cflags == DP_C_SHORT) cnk->value = va_arg (args, unsigned int); else if (cnk->cflags == DP_C_LONG) cnk->value = (unsigned long int)va_arg (args, unsigned long int); else if (cnk->cflags == DP_C_LLONG) cnk->value = (LLONG)va_arg (args, unsigned LLONG); else if (cnk->cflags == DP_C_SIZET) cnk->value = (size_t)va_arg (args, size_t); else cnk->value = (unsigned int)va_arg (args, unsigned int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_FLOAT: if (cnk->cflags == DP_C_LDOUBLE) cnk->fvalue = va_arg (args, LDOUBLE); else cnk->fvalue = va_arg (args, double); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->fvalue = cnk->fvalue; } break; case CNK_CHAR: cnk->value = va_arg (args, int); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->value = cnk->value; } break; case CNK_STRING: cnk->strvalue = va_arg (args, char *); if (!cnk->strvalue) cnk->strvalue = "(NULL)"; for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->strvalue = cnk->strvalue; } break; case CNK_PTR: cnk->strvalue = va_arg (args, void *); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->strvalue = cnk->strvalue; } break; case CNK_NUM: if (cnk->cflags == DP_C_CHAR) cnk->pnum = va_arg (args, char *); else if (cnk->cflags == DP_C_SHORT) cnk->pnum = va_arg (args, short int *); else if (cnk->cflags == DP_C_LONG) cnk->pnum = va_arg (args, long int *); else if (cnk->cflags == DP_C_LLONG) cnk->pnum = va_arg (args, LLONG *); else if (cnk->cflags == DP_C_SIZET) cnk->pnum = va_arg (args, ssize_t *); else cnk->pnum = va_arg (args, int *); for (i = 1; i < clist[pnum].num; i++) { clist[pnum].chunks[i]->pnum = cnk->pnum; } break; case CNK_PRCNT: break; default: /* what ?? */ goto done; } } /* print out the actual string from chunks */ currlen = 0; cnk = chunks; while (cnk) { int len, min, max; if (cnk->min_star) min = cnk->min_star->value; else min = cnk->min; if (cnk->max_star) max = cnk->max_star->value; else max = cnk->max; switch (cnk->type) { case CNK_FMT_STR: if (maxlen != 0 && maxlen > currlen) { if (maxlen > (currlen + cnk->len)) len = cnk->len; else len = maxlen - currlen; memcpy(&(buffer[currlen]), &(base[cnk->start]), len); } currlen += cnk->len; break; case CNK_INT: case CNK_UINT: fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags); break; case CNK_OCTAL: fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags); break; case CNK_HEX: fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags); break; case CNK_FLOAT: fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags); break; case CNK_CHAR: dopr_outch (buffer, &currlen, maxlen, cnk->value); break; case CNK_STRING: if (max == -1) { max = strlen(cnk->strvalue); } fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max); break; case CNK_PTR: fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags); break; case CNK_NUM: if (cnk->cflags == DP_C_CHAR) *((char *)(cnk->pnum)) = (char)currlen; else if (cnk->cflags == DP_C_SHORT) *((short int *)(cnk->pnum)) = (short int)currlen; else if (cnk->cflags == DP_C_LONG) *((long int *)(cnk->pnum)) = (long int)currlen; else if (cnk->cflags == DP_C_LLONG) *((LLONG *)(cnk->pnum)) = (LLONG)currlen; else if (cnk->cflags == DP_C_SIZET) *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen; else *((int *)(cnk->pnum)) = (int)currlen; break; case CNK_PRCNT: dopr_outch (buffer, &currlen, maxlen, '%'); break; default: /* what ?? */ goto done; } cnk = cnk->next; } if (maxlen != 0) { if (currlen < maxlen - 1) buffer[currlen] = '\0'; else if (maxlen > 0) buffer[maxlen - 1] = '\0'; } ret = currlen; done: va_end(args); while (chunks) { cnk = chunks->next; free(chunks); chunks = cnk; } if (clist) { for (pnum = 0; pnum < max_pos; pnum++) { if (clist[pnum].chunks) free(clist[pnum].chunks); } free(clist); } return ret; } static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max) { int padlen, strln; /* amount to pad */ int cnt = 0; #ifdef DEBUG_SNPRINTF printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); #endif if (value == 0) { value = ""; } for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } while (*value && (cnt < max)) { dopr_outch (buffer, currlen, maxlen, *value++); ++cnt; } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base, int min, int max, int flags) { int signvalue = 0; unsigned LLONG uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; if (max < 0) max = 0; uvalue = value; if(!(flags & DP_F_UNSIGNED)) { if( value < 0 ) { signvalue = '-'; uvalue = -value; } else { if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; } } if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ do { convert[place++] = (caps? "0123456789ABCDEF":"0123456789abcdef") [uvalue % (unsigned)base ]; uvalue = (uvalue / (unsigned)base ); } while(uvalue && (place < 20)); if (place == 20) place--; convert[place] = 0; zpadlen = max - place; spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */ #ifdef DEBUG_SNPRINTF printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place); #endif /* Spaces */ while (spadlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) dopr_outch (buffer, currlen, maxlen, convert[--place]); /* Left Justified spaces */ while (spadlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++spadlen; } } static LDOUBLE abs_val(LDOUBLE value) { LDOUBLE result = value; if (value < 0) result = -value; return result; } static LDOUBLE POW10(int exp) { LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result; } static LLONG ROUND(LDOUBLE value) { LLONG intpart; intpart = (LLONG)value; value = value - intpart; if (value >= 0.5) intpart++; return intpart; } /* a replacement for modf that doesn't need the math library. Should be portable, but slow */ static double my_modf(double x0, double *iptr) { int i; LLONG l=0; double x = x0; double f = 1.0; for (i=0;i<100;i++) { l = (long)x; if (l <= (x+1) && l >= (x-1)) break; x *= 0.1; f *= 10.0; } if (i == 100) { /* yikes! the number is beyond what we can handle. What do we do? */ (*iptr) = 0; return 0; } if (i != 0) { double i2; double ret; ret = my_modf(x0-l*f, &i2); (*iptr) = l*f + i2; return ret; } (*iptr) = l; return x - (*iptr); } static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags) { int signvalue = 0; double ufvalue; char iconvert[311]; char fconvert[311]; int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; int idx; double intpart; double fracpart; double temp; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) max = 6; ufvalue = abs_val (fvalue); if (fvalue < 0) { signvalue = '-'; } else { if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ signvalue = '+'; } else { if (flags & DP_F_SPACE) signvalue = ' '; } } #if 0 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ #endif #if 0 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ #endif /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) max = 9; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ temp = ufvalue; my_modf(temp, &intpart); fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); if (fracpart >= POW10(max)) { intpart++; fracpart -= POW10(max); } /* Convert integer part */ do { temp = intpart*0.1; my_modf(temp, &intpart); idx = (int) ((temp -intpart +0.05)* 10.0); /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ iconvert[iplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while (intpart && (iplace < 311)); if (iplace == 311) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ if (fracpart) { do { temp = fracpart*0.1; my_modf(temp, &fracpart); idx = (int) ((temp -fracpart +0.05)* 10.0); /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ fconvert[fplace++] = (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; } while(fracpart && (fplace < 311)); if (fplace == 311) fplace--; } fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch (buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch (buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) dopr_outch (buffer, currlen, maxlen, signvalue); while (iplace > 0) dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); #ifdef DEBUG_SNPRINTF printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); #endif /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { dopr_outch (buffer, currlen, maxlen, '.'); while (zpadlen > 0) { dopr_outch (buffer, currlen, maxlen, '0'); --zpadlen; } while (fplace > 0) dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); } while (padlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) { if (*currlen < maxlen) { buffer[(*currlen)] = c; } (*currlen)++; } static struct pr_chunk *new_chunk(void) { struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk)); if (!new_c) return NULL; new_c->type = 0; new_c->num = 0; new_c->min = 0; new_c->min_star = NULL; new_c->max = -1; new_c->max_star = NULL; new_c->flags = 0; new_c->cflags = 0; new_c->start = 0; new_c->len = 0; new_c->value = 0; new_c->fvalue = 0; new_c->strvalue = NULL; new_c->pnum = NULL; new_c->next = NULL; return new_c; } static int add_cnk_list_entry(struct pr_chunk_x **list, int max_num, struct pr_chunk *chunk) { struct pr_chunk_x *l; struct pr_chunk **c; int max; int cnum; int i, pos; if (chunk->num > max_num) { max = chunk->num; if (*list == NULL) { l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max); pos = 0; } else { l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max); pos = max_num; } if (l == NULL) { for (i = 0; i < max; i++) { if ((*list)[i].chunks) free((*list)[i].chunks); } return 0; } for (i = pos; i < max; i++) { l[i].chunks = NULL; l[i].num = 0; } } else { l = *list; max = max_num; } i = chunk->num - 1; cnum = l[i].num + 1; if (l[i].chunks == NULL) { c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); } else { c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum); } if (c == NULL) { for (i = 0; i < max; i++) { if (l[i].chunks) free(l[i].chunks); } return 0; } c[l[i].num] = chunk; l[i].chunks = c; l[i].num = cnum; *list = l; return max; } int rsync_vsnprintf (char *str, size_t count, const char *fmt, va_list args) { return dopr(str, count, fmt, args); } #define vsnprintf rsync_vsnprintf #endif /* yes this really must be a ||. Don't muck with this (tridge) * * The logic for these two is that we need our own definition if the * OS *either* has no definition of *sprintf, or if it does have one * that doesn't work properly according to the autoconf test. */ #if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) int rsync_snprintf(char *str,size_t count,const char *fmt,...) { size_t ret; va_list ap; va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap); return ret; } #define snprintf rsync_snprintf #endif #ifndef HAVE_VASPRINTF int vasprintf(char **ptr, const char *format, va_list ap) { int ret; va_list ap2; VA_COPY(ap2, ap); ret = vsnprintf(NULL, 0, format, ap2); va_end(ap2); if (ret < 0) return ret; (*ptr) = (char *)malloc(ret+1); if (!*ptr) return -1; VA_COPY(ap2, ap); ret = vsnprintf(*ptr, ret+1, format, ap2); va_end(ap2); return ret; } #endif #ifndef HAVE_ASPRINTF int asprintf(char **ptr, const char *format, ...) { va_list ap; int ret; *ptr = NULL; va_start(ap, format); ret = vasprintf(ptr, format, ap); va_end(ap); return ret; } #endif #ifdef TEST_SNPRINTF int sprintf(char *str,const char *fmt,...); int printf(const char *fmt,...); int main (void) { char buf1[1024]; char buf2[1024]; char *buf3; char *fp_fmt[] = { "%1.1f", "%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f", "%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f", "%3.2f", "%.0f", "%f", "%-8.8f", "%-9.9f", NULL }; double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 0.9996, 1.996, 4.136, 5.030201, 0.00205, /* END LIST */ 0}; char *int_fmt[] = { "%-1.5d", "%1.5d", "%123.9d", "%5.5d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%4d", "%d", NULL }; long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; char *str_fmt[] = { "%10.5s", "%-10.5s", "%5.10s", "%-5.10s", "%10.1s", "%0.10s", "%10.0s", "%1.10s", "%s", "%.1s", "%.10s", "%10s", NULL }; char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; #ifdef HAVE_LONG_LONG char *ll_fmt[] = { "%llu", NULL }; LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0}; #endif int x, y; int fail = 0; int num = 0; int l1, l2; char *ss_fmt[] = { "%zd", "%zu", NULL }; size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0}; printf ("Testing snprintf format codes against system sprintf...\n"); for (x = 0; fp_fmt[x] ; x++) { for (y = 0; fp_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", fp_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } for (x = 0; int_fmt[x] ; x++) { for (y = 0; int_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); l2 = sprintf (buf2, int_fmt[x], int_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", int_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } for (x = 0; str_fmt[x] ; x++) { for (y = 0; str_vals[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); l2 = sprintf (buf2, str_fmt[x], str_vals[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", str_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #ifdef HAVE_LONG_LONG for (x = 0; ll_fmt[x] ; x++) { for (y = 0; ll_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]); l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", ll_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #endif #define BUFSZ 2048 buf1[0] = buf2[0] = '\0'; if ((buf3 = malloc(BUFSZ)) == NULL) { fail++; } else { num++; memset(buf3, 'a', BUFSZ); snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3); buf1[1023] = '\0'; if (strcmp(buf1, "a") != 0) { printf("length limit buf1 '%s' expected 'a'\n", buf1); fail++; } } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); fail++; } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); fail++; } for (x = 0; ss_fmt[x] ; x++) { for (y = 0; ss_nums[y] != 0 ; y++) { buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]); l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]); buf1[1023] = buf2[1023] = '\0'; if (strcmp (buf1, buf2) || (l1 != l2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", ss_fmt[x], l1, buf1, l2, buf2); fail++; } num++; } } #if 0 buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890); l2 = sprintf(buf2, "%lld", (LLONG)1234567890); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%lld", l1, buf1, l2, buf2); fail++; } buf1[0] = buf2[0] = '\0'; l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123); l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123); buf1[1023] = buf2[1023] = '\0'; if (strcmp(buf1, buf2)) { printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", "%Lf", l1, buf1, l2, buf2); fail++; } #endif printf ("%d tests failed out of %d.\n", fail, num); printf("seeing how many digits we support\n"); { double v0 = 0.12345678901234567890123456789012345678901; for (x=0; x<100; x++) { double p = pow(10, x); double r = v0*p; snprintf(buf1, sizeof(buf1), "%1.1f", r); sprintf(buf2, "%1.1f", r); if (strcmp(buf1, buf2)) { printf("we seem to support %d digits\n", x-1); break; } } } return 0; } #endif /* TEST_SNPRINTF */ rsync-3.2.7/lib/sysacls.c0000664000000000000000000020301714276226634013773 0ustar rootroot/* * Unix SMB/CIFS implementation. * Based on the Samba ACL support code. * Copyright (C) Jeremy Allison 2000. * Copyright (C) 2007-2022 Wayne Davison * * The permission functions have been changed to get/set all bits via * one call. Some functions that rsync doesn't need were also removed. * * 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 * with this program; if not, visit the http://fsf.org website. */ #include "rsync.h" #include "sysacls.h" #ifdef SUPPORT_ACLS #ifdef DEBUG #undef DEBUG #endif #define DEBUG(x, y) void SAFE_FREE(void *mem) { if (mem) free(mem); } /* This file wraps all differing system ACL interfaces into a consistent one based on the POSIX interface. It also returns the correct errors for older UNIX systems that don't support ACLs. The interfaces that each ACL implementation must support are as follows : int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) SMB_ACL_T sys_acl_get_fd(int fd) SMB_ACL_T sys_acl_init(int count) int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) int sys_acl_valid(SMB_ACL_T theacl) int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) int sys_acl_set_fd(int fd, SMB_ACL_T theacl) int sys_acl_delete_def_file(const char *path) int sys_acl_free_acl(SMB_ACL_T posix_acl) */ #if defined(HAVE_POSIX_ACLS) /*--------------------------------------------*/ /* Identity mapping - easy. */ int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) { return acl_get_entry(the_acl, entry_id, entry_p); } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) { return acl_get_tag_type(entry_d, tag_type_p); } SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { return acl_get_file(path_p, type); } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { return acl_get_fd(fd); } #endif #if defined(HAVE_ACL_GET_PERM_NP) #define acl_get_perm(p, b) acl_get_perm_np(p, b) #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { acl_permset_t permset; if (acl_get_tag_type(entry, tag_type_p) != 0 || acl_get_permset(entry, &permset) != 0) return -1; *bits_p = (acl_get_perm(permset, ACL_READ) ? 4 : 0) | (acl_get_perm(permset, ACL_WRITE) ? 2 : 0) | (acl_get_perm(permset, ACL_EXECUTE) ? 1 : 0); if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) { void *qual; if ((qual = acl_get_qualifier(entry)) == NULL) return -1; *u_g_id_p = *(id_t*)qual; acl_free(qual); } return 0; } SMB_ACL_T sys_acl_init(int count) { return acl_init(count); } int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) { return acl_create_entry(pacl, pentry); } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { if (acl_set_tag_type(entry, tag_type) != 0) return -1; if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) { if (acl_set_qualifier(entry, (void*)&u_g_id) != 0) return -1; } return sys_acl_set_access_bits(entry, bits); } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) { acl_permset_t permset; int rc; if ((rc = acl_get_permset(entry, &permset)) != 0) return rc; acl_clear_perms(permset); if (bits & 4) acl_add_perm(permset, ACL_READ); if (bits & 2) acl_add_perm(permset, ACL_WRITE); if (bits & 1) acl_add_perm(permset, ACL_EXECUTE); return acl_set_permset(entry, permset); } int sys_acl_valid(SMB_ACL_T theacl) { return acl_valid(theacl); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { return acl_set_file(name, acltype, theacl); } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T theacl) { return acl_set_fd(fd, theacl); } #endif int sys_acl_delete_def_file(const char *name) { return acl_delete_def_file(name); } int sys_acl_free_acl(SMB_ACL_T the_acl) { return acl_free(the_acl); } #elif defined(HAVE_TRU64_ACLS) /*--------------------------------------------*/ /* * The interface to DEC/Compaq Tru64 UNIX ACLs * is based on Draft 13 of the POSIX spec which is * slightly different from the Draft 16 interface. * * Also, some of the permset manipulation functions * such as acl_clear_perm() and acl_add_perm() appear * to be broken on Tru64 so we have to manipulate * the permission bits in the permset directly. */ int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) { SMB_ACL_ENTRY_T entry; if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) { return -1; } errno = 0; if ((entry = acl_get_entry(the_acl)) != NULL) { *entry_p = entry; return 1; } return errno ? -1 : 0; } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) { return acl_get_tag_type(entry_d, tag_type_p); } SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { return acl_get_file((char *)path_p, type); } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { return acl_get_fd(fd, ACL_TYPE_ACCESS); } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { acl_permset_t permset; if (acl_get_tag_type(entry, tag_type_p) != 0 || acl_get_permset(entry, &permset) != 0) return -1; *bits_p = *permset & 7; /* Tru64 doesn't have acl_get_perm() */ if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) { void *qual; if ((qual = acl_get_qualifier(entry)) == NULL) return -1; *u_g_id_p = *(id_t*)qual; acl_free_qualifier(qual, *tag_type_p); } return 0; } SMB_ACL_T sys_acl_init(int count) { return acl_init(count); } int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) { SMB_ACL_ENTRY_T entry; if ((entry = acl_create_entry(pacl)) == NULL) { return -1; } *pentry = entry; return 0; } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { if (acl_set_tag_type(entry, tag_type) != 0) return -1; if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) { if (acl_set_qualifier(entry, (void*)&u_g_id) != 0) return -1; } return sys_acl_set_access_bits(entry, bits); } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) { acl_permset_t permset; int rc; if ((rc = acl_get_permset(entry, &permset)) != 0) return rc; *permset = bits & 7; return acl_set_permset(entry, permset); } int sys_acl_valid(SMB_ACL_T theacl) { acl_entry_t entry; return acl_valid(theacl, &entry); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { return acl_set_file((char *)name, acltype, theacl); } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T theacl) { return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl); } #endif int sys_acl_delete_def_file(const char *name) { return acl_delete_def_file((char *)name); } int sys_acl_free_acl(SMB_ACL_T the_acl) { return acl_free(the_acl); } #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /*-----------*/ /* * Donated by Michael Davidson for UnixWare / OpenUNIX. * Modified by Toomas Soome for Solaris. */ /* * Note that while this code implements sufficient functionality * to support the sys_acl_* interfaces it does not provide all * of the semantics of the POSIX ACL interfaces. * * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned * from a call to sys_acl_get_entry() should not be assumed to be * valid after calling any of the following functions, which may * reorder the entries in the ACL. * * sys_acl_valid() * sys_acl_set_file() * sys_acl_set_fd() */ /* * The only difference between Solaris and UnixWare / OpenUNIX is * that the #defines for the ACL operations have different names */ #if defined(HAVE_UNIXWARE_ACLS) #define SETACL ACL_SET #define GETACL ACL_GET #define GETACLCNT ACL_CNT #endif int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) { if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { errno = EINVAL; return -1; } if (entry_p == NULL) { errno = EINVAL; return -1; } if (entry_id == SMB_ACL_FIRST_ENTRY) { acl_d->next = 0; } if (acl_d->next < 0) { errno = EINVAL; return -1; } if (acl_d->next >= acl_d->count) { return 0; } *entry_p = &acl_d->acl[acl_d->next++]; return 1; } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) { *type_p = entry_d->a_type; return 0; } /* * There is no way of knowing what size the ACL returned by * GETACL will be unless you first call GETACLCNT which means * making an additional system call. * * In the hope of avoiding the cost of the additional system * call in most cases, we initially allocate enough space for * an ACL with INITIAL_ACL_SIZE entries. If this turns out to * be too small then we use GETACLCNT to find out the actual * size, reallocate the ACL buffer, and then call GETACL again. */ #define INITIAL_ACL_SIZE 16 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { SMB_ACL_T acl_d; int count; /* # of ACL entries allocated */ int naccess; /* # of access ACL entries */ int ndefault; /* # of default ACL entries */ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { errno = EINVAL; return NULL; } count = INITIAL_ACL_SIZE; if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } /* * If there isn't enough space for the ACL entries we use * GETACLCNT to determine the actual number of ACL entries * reallocate and try again. This is in a loop because it * is possible that someone else could modify the ACL and * increase the number of entries between the call to * GETACLCNT and the call to GETACL. */ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) { sys_acl_free_acl(acl_d); if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) { return NULL; } if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } } if (count < 0) { sys_acl_free_acl(acl_d); return NULL; } /* * calculate the number of access and default ACL entries * * Note: we assume that the acl() system call returned a * well formed ACL which is sorted so that all of the * access ACL entries precede any default ACL entries */ for (naccess = 0; naccess < count; naccess++) { if (acl_d->acl[naccess].a_type & ACL_DEFAULT) break; } ndefault = count - naccess; /* * if the caller wants the default ACL we have to copy * the entries down to the start of the acl[] buffer * and mask out the ACL_DEFAULT flag from the type field */ if (type == SMB_ACL_TYPE_DEFAULT) { int i, j; for (i = 0, j = naccess; i < ndefault; i++, j++) { acl_d->acl[i] = acl_d->acl[j]; acl_d->acl[i].a_type &= ~ACL_DEFAULT; } acl_d->count = ndefault; } else { acl_d->count = naccess; } return acl_d; } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { SMB_ACL_T acl_d; int count; /* # of ACL entries allocated */ int naccess; /* # of access ACL entries */ count = INITIAL_ACL_SIZE; if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) { sys_acl_free_acl(acl_d); if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) { return NULL; } if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } } if (count < 0) { sys_acl_free_acl(acl_d); return NULL; } /* * calculate the number of access ACL entries */ for (naccess = 0; naccess < count; naccess++) { if (acl_d->acl[naccess].a_type & ACL_DEFAULT) break; } acl_d->count = naccess; return acl_d; } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { *tag_type_p = entry->a_type; *bits_p = entry->a_perm; if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) *u_g_id_p = entry->a_id; return 0; } SMB_ACL_T sys_acl_init(int count) { SMB_ACL_T a; if (count < 0) { errno = EINVAL; return NULL; } /* * note that since the definition of the structure pointed * to by the SMB_ACL_T includes the first element of the * acl[] array, this actually allocates an ACL with room * for (count+1) entries */ if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) { errno = ENOMEM; return NULL; } a->size = count + 1; a->count = 0; a->next = -1; return a; } int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) { SMB_ACL_T acl_d; SMB_ACL_ENTRY_T entry_d; if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { errno = EINVAL; return -1; } if (acl_d->count >= acl_d->size) { errno = ENOSPC; return -1; } entry_d = &acl_d->acl[acl_d->count++]; entry_d->a_type = 0; entry_d->a_id = -1; entry_d->a_perm = 0; *entry_p = entry_d; return 0; } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { entry->a_type = tag_type; if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) entry->a_id = u_g_id; entry->a_perm = bits; return 0; } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) { entry_d->a_perm = bits; return 0; } /* * sort the ACL and check it for validity * * if it's a minimal ACL with only 4 entries then we * need to recalculate the mask permissions to make * sure that they are the same as the GROUP_OBJ * permissions as required by the UnixWare acl() system call. * * (note: since POSIX allows minimal ACLs which only contain * 3 entries - ie there is no mask entry - we should, in theory, * check for this and add a mask entry if necessary - however * we "know" that the caller of this interface always specifies * a mask so, in practice "this never happens" (tm) - if it *does* * happen aclsort() will fail and return an error and someone will * have to fix it ...) */ static int acl_sort(SMB_ACL_T acl_d) { int fixmask = (acl_d->count <= 4); if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) { errno = EINVAL; return -1; } return 0; } int sys_acl_valid(SMB_ACL_T acl_d) { return acl_sort(acl_d); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) { struct stat s; struct acl *acl_p; int acl_count; struct acl *acl_buf = NULL; int ret; if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { errno = EINVAL; return -1; } if (acl_sort(acl_d) != 0) { return -1; } acl_p = &acl_d->acl[0]; acl_count = acl_d->count; /* * if it's a directory there is extra work to do * since the acl() system call will replace both * the access ACLs and the default ACLs (if any) */ if (stat(name, &s) != 0) { return -1; } if (S_ISDIR(s.st_mode)) { SMB_ACL_T acc_acl; SMB_ACL_T def_acl; SMB_ACL_T tmp_acl; int i; if (type == SMB_ACL_TYPE_ACCESS) { acc_acl = acl_d; def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); } else { def_acl = acl_d; acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); } if (tmp_acl == NULL) { return -1; } /* * allocate a temporary buffer for the complete ACL */ acl_count = acc_acl->count + def_acl->count; acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); if (acl_buf == NULL) { sys_acl_free_acl(tmp_acl); errno = ENOMEM; return -1; } /* * copy the access control and default entries into the buffer */ memcpy(&acl_buf[0], &acc_acl->acl[0], acc_acl->count * sizeof acl_buf[0]); memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], def_acl->count * sizeof acl_buf[0]); /* * set the ACL_DEFAULT flag on the default entries */ for (i = acc_acl->count; i < acl_count; i++) { acl_buf[i].a_type |= ACL_DEFAULT; } sys_acl_free_acl(tmp_acl); } else if (type != SMB_ACL_TYPE_ACCESS) { errno = EINVAL; return -1; } ret = acl(name, SETACL, acl_count, acl_p); SAFE_FREE(acl_buf); return ret; } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) { if (acl_sort(acl_d) != 0) { return -1; } return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]); } #endif int sys_acl_delete_def_file(const char *path) { SMB_ACL_T acl_d; int ret; /* * fetching the access ACL and rewriting it has * the effect of deleting the default ACL */ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { return -1; } ret = acl(path, SETACL, acl_d->count, acl_d->acl); sys_acl_free_acl(acl_d); return ret; } int sys_acl_free_acl(SMB_ACL_T acl_d) { SAFE_FREE(acl_d); return 0; } #elif defined(HAVE_HPUX_ACLS) /*---------------------------------------------*/ #ifdef HAVE_DL_H #include #endif /* * Based on the Solaris/SCO code - with modifications. */ /* * Note that while this code implements sufficient functionality * to support the sys_acl_* interfaces it does not provide all * of the semantics of the POSIX ACL interfaces. * * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned * from a call to sys_acl_get_entry() should not be assumed to be * valid after calling any of the following functions, which may * reorder the entries in the ACL. * * sys_acl_valid() * sys_acl_set_file() * sys_acl_set_fd() */ /* This checks if the POSIX ACL system call is defined */ /* which basically corresponds to whether JFS 3.3 or */ /* higher is installed. If acl() was called when it */ /* isn't defined, it causes the process to core dump */ /* so it is important to check this and avoid acl() */ /* calls if it isn't there. */ #ifdef __TANDEM inline int do_acl(const char *path_p, int cmd, int nentries, struct acl *aclbufp) { return acl((char*)path_p, cmd, nentries, aclbufp); } #define acl(p,c,n,a) do_acl(p,c,n,a) #endif static BOOL hpux_acl_call_presence(void) { #ifndef __TANDEM shl_t handle = NULL; void *value; int ret_val=0; static BOOL already_checked=0; if (already_checked) return True; ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value); if (ret_val != 0) { DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n", ret_val, errno, strerror(errno))); DEBUG(5, ("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n")); return False; } DEBUG(10, ("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n")); already_checked = True; #endif return True; } int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) { if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { errno = EINVAL; return -1; } if (entry_p == NULL) { errno = EINVAL; return -1; } if (entry_id == SMB_ACL_FIRST_ENTRY) { acl_d->next = 0; } if (acl_d->next < 0) { errno = EINVAL; return -1; } if (acl_d->next >= acl_d->count) { return 0; } *entry_p = &acl_d->acl[acl_d->next++]; return 1; } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) { *type_p = entry_d->a_type; return 0; } /* * There is no way of knowing what size the ACL returned by * ACL_GET will be unless you first call ACL_CNT which means * making an additional system call. * * In the hope of avoiding the cost of the additional system * call in most cases, we initially allocate enough space for * an ACL with INITIAL_ACL_SIZE entries. If this turns out to * be too small then we use ACL_CNT to find out the actual * size, reallocate the ACL buffer, and then call ACL_GET again. */ #define INITIAL_ACL_SIZE 16 #ifndef NACLENTRIES #define NACLENTRIES 0 #endif SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { SMB_ACL_T acl_d; int count; /* # of ACL entries allocated */ int naccess; /* # of access ACL entries */ int ndefault; /* # of default ACL entries */ if (hpux_acl_call_presence() == False) { /* Looks like we don't have the acl() system call on HPUX. * May be the system doesn't have the latest version of JFS. */ return NULL; } if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { errno = EINVAL; return NULL; } count = INITIAL_ACL_SIZE; if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } /* * If there isn't enough space for the ACL entries we use * ACL_CNT to determine the actual number of ACL entries * reallocate and try again. This is in a loop because it * is possible that someone else could modify the ACL and * increase the number of entries between the call to * ACL_CNT and the call to ACL_GET. */ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) { sys_acl_free_acl(acl_d); if ((count = acl(path_p, ACL_CNT, NACLENTRIES, NULL)) < 0) { return NULL; } if ((acl_d = sys_acl_init(count)) == NULL) { return NULL; } } if (count < 0) { sys_acl_free_acl(acl_d); return NULL; } /* * calculate the number of access and default ACL entries * * Note: we assume that the acl() system call returned a * well formed ACL which is sorted so that all of the * access ACL entries precede any default ACL entries */ for (naccess = 0; naccess < count; naccess++) { if (acl_d->acl[naccess].a_type & ACL_DEFAULT) break; } ndefault = count - naccess; /* * if the caller wants the default ACL we have to copy * the entries down to the start of the acl[] buffer * and mask out the ACL_DEFAULT flag from the type field */ if (type == SMB_ACL_TYPE_DEFAULT) { int i, j; for (i = 0, j = naccess; i < ndefault; i++, j++) { acl_d->acl[i] = acl_d->acl[j]; acl_d->acl[i].a_type &= ~ACL_DEFAULT; } acl_d->count = ndefault; } else { acl_d->count = naccess; } return acl_d; } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { /* * HPUX doesn't have the facl call. Fake it using the path.... JRA. */ files_struct *fsp = file_find_fd(fd); if (fsp == NULL) { errno = EBADF; return NULL; } /* * We know we're in the same conn context. So we * can use the relative path. */ return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS); } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { *tag_type_p = entry->a_type; *bits_p = entry->a_perm; if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) *u_g_id_p = entry->a_id; return 0; } SMB_ACL_T sys_acl_init(int count) { SMB_ACL_T a; if (count < 0) { errno = EINVAL; return NULL; } /* * note that since the definition of the structure pointed * to by the SMB_ACL_T includes the first element of the * acl[] array, this actually allocates an ACL with room * for (count+1) entries */ if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) { errno = ENOMEM; return NULL; } a->size = count + 1; a->count = 0; a->next = -1; return a; } int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) { SMB_ACL_T acl_d; SMB_ACL_ENTRY_T entry_d; if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { errno = EINVAL; return -1; } if (acl_d->count >= acl_d->size) { errno = ENOSPC; return -1; } entry_d = &acl_d->acl[acl_d->count++]; entry_d->a_type = 0; entry_d->a_id = -1; entry_d->a_perm = 0; *entry_p = entry_d; return 0; } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { entry->a_type = tag_type; if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) entry->a_id = u_g_id; entry->a_perm = bits; return 0; } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) { entry_d->a_perm = bits; return 0; } /* Structure to capture the count for each type of ACE. */ struct hpux_acl_types { int n_user; int n_def_user; int n_user_obj; int n_def_user_obj; int n_group; int n_def_group; int n_group_obj; int n_def_group_obj; int n_other; int n_other_obj; int n_def_other_obj; int n_class_obj; int n_def_class_obj; int n_illegal_obj; }; /* count_obj: * Counts the different number of objects in a given array of ACL * structures. * Inputs: * * acl_count - Count of ACLs in the array of ACL structures. * aclp - Array of ACL structures. * acl_type_count - Pointer to acl_types structure. Should already be * allocated. * Output: * * acl_type_count - This structure is filled up with counts of various * acl types. */ static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count) { int i; memset(acl_type_count, 0, sizeof (struct hpux_acl_types)); for (i = 0; i < acl_count; i++) { switch (aclp[i].a_type) { case USER: acl_type_count->n_user++; break; case USER_OBJ: acl_type_count->n_user_obj++; break; case DEF_USER_OBJ: acl_type_count->n_def_user_obj++; break; case GROUP: acl_type_count->n_group++; break; case GROUP_OBJ: acl_type_count->n_group_obj++; break; case DEF_GROUP_OBJ: acl_type_count->n_def_group_obj++; break; case OTHER_OBJ: acl_type_count->n_other_obj++; break; case DEF_OTHER_OBJ: acl_type_count->n_def_other_obj++; break; case CLASS_OBJ: acl_type_count->n_class_obj++; break; case DEF_CLASS_OBJ: acl_type_count->n_def_class_obj++; break; case DEF_USER: acl_type_count->n_def_user++; break; case DEF_GROUP: acl_type_count->n_def_group++; break; default: acl_type_count->n_illegal_obj++; break; } } } /* swap_acl_entries: Swaps two ACL entries. * * Inputs: aclp0, aclp1 - ACL entries to be swapped. */ static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1) { struct acl temp_acl; temp_acl.a_type = aclp0->a_type; temp_acl.a_id = aclp0->a_id; temp_acl.a_perm = aclp0->a_perm; aclp0->a_type = aclp1->a_type; aclp0->a_id = aclp1->a_id; aclp0->a_perm = aclp1->a_perm; aclp1->a_type = temp_acl.a_type; aclp1->a_id = temp_acl.a_id; aclp1->a_perm = temp_acl.a_perm; } /* prohibited_duplicate_type * Identifies if given ACL type can have duplicate entries or * not. * * Inputs: acl_type - ACL Type. * * Outputs: * * Return.. * * True - If the ACL type matches any of the prohibited types. * False - If the ACL type doesn't match any of the prohibited types. */ static BOOL hpux_prohibited_duplicate_type(int acl_type) { switch (acl_type) { case USER: case GROUP: case DEF_USER: case DEF_GROUP: return True; default: return False; } } /* get_needed_class_perm * Returns the permissions of a ACL structure only if the ACL * type matches one of the pre-determined types for computing * CLASS_OBJ permissions. * * Inputs: aclp - Pointer to ACL structure. */ static int hpux_get_needed_class_perm(struct acl *aclp) { switch (aclp->a_type) { case USER: case GROUP_OBJ: case GROUP: case DEF_USER_OBJ: case DEF_USER: case DEF_GROUP_OBJ: case DEF_GROUP: case DEF_CLASS_OBJ: case DEF_OTHER_OBJ: return aclp->a_perm; default: return 0; } } /* acl_sort for HPUX. * Sorts the array of ACL structures as per the description in * aclsort man page. Refer to aclsort man page for more details * * Inputs: * * acl_count - Count of ACLs in the array of ACL structures. * calclass - If this is not zero, then we compute the CLASS_OBJ * permissions. * aclp - Array of ACL structures. * * Outputs: * * aclp - Sorted array of ACL structures. * * Outputs: * * Returns 0 for success -1 for failure. Prints a message to the Samba * debug log in case of failure. */ static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp) { #if !defined(HAVE_HPUX_ACLSORT) /* * The aclsort() system call is available on the latest HPUX General * Patch Bundles. So for HPUX, we developed our version of acl_sort * function. Because, we don't want to update to a new * HPUX GR bundle just for aclsort() call. */ struct hpux_acl_types acl_obj_count; int n_class_obj_perm = 0; int i, j; if (!acl_count) { DEBUG(10, ("Zero acl count passed. Returning Success\n")); return 0; } if (aclp == NULL) { DEBUG(0, ("Null ACL pointer in hpux_acl_sort. Returning Failure. \n")); return -1; } /* Count different types of ACLs in the ACLs array */ hpux_count_obj(acl_count, aclp, &acl_obj_count); /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, * CLASS_OBJ and OTHER_OBJ */ if (acl_obj_count.n_user_obj != 1 || acl_obj_count.n_group_obj != 1 || acl_obj_count.n_class_obj != 1 || acl_obj_count.n_other_obj != 1) { DEBUG(0, ("hpux_acl_sort: More than one entry or no entries for \ USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n")); return -1; } /* If any of the default objects are present, there should be only * one of them each. */ if (acl_obj_count.n_def_user_obj > 1 || acl_obj_count.n_def_group_obj > 1 || acl_obj_count.n_def_other_obj > 1 || acl_obj_count.n_def_class_obj > 1) { DEBUG(0, ("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \ or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n")); return -1; } /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl * structures. * * Sorting crieteria - First sort by ACL type. If there are multiple entries of * same ACL type, sort by ACL id. * * I am using the trivial kind of sorting method here because, performance isn't * really effected by the ACLs feature. More over there aren't going to be more * than 17 entries on HPUX. */ for (i = 0; i < acl_count; i++) { for (j = i+1; j < acl_count; j++) { if (aclp[i].a_type > aclp[j].a_type) { /* ACL entries out of order, swap them */ hpux_swap_acl_entries((aclp+i), (aclp+j)); } else if (aclp[i].a_type == aclp[j].a_type) { /* ACL entries of same type, sort by id */ if (aclp[i].a_id > aclp[j].a_id) { hpux_swap_acl_entries((aclp+i), (aclp+j)); } else if (aclp[i].a_id == aclp[j].a_id) { /* We have a duplicate entry. */ if (hpux_prohibited_duplicate_type(aclp[i].a_type)) { DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n", aclp[i].a_type, aclp[i].a_id)); return -1; } } } } } /* set the class obj permissions to the computed one. */ if (calclass) { int n_class_obj_index = -1; for (i = 0;i < acl_count; i++) { n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i)); if (aclp[i].a_type == CLASS_OBJ) n_class_obj_index = i; } aclp[n_class_obj_index].a_perm = n_class_obj_perm; } return 0; #else return aclsort(acl_count, calclass, aclp); #endif } /* * sort the ACL and check it for validity * * if it's a minimal ACL with only 4 entries then we * need to recalculate the mask permissions to make * sure that they are the same as the GROUP_OBJ * permissions as required by the UnixWare acl() system call. * * (note: since POSIX allows minimal ACLs which only contain * 3 entries - ie there is no mask entry - we should, in theory, * check for this and add a mask entry if necessary - however * we "know" that the caller of this interface always specifies * a mask so, in practice "this never happens" (tm) - if it *does* * happen aclsort() will fail and return an error and someone will * have to fix it ...) */ static int acl_sort(SMB_ACL_T acl_d) { int fixmask = (acl_d->count <= 4); if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) { errno = EINVAL; return -1; } return 0; } int sys_acl_valid(SMB_ACL_T acl_d) { return acl_sort(acl_d); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) { struct stat s; struct acl *acl_p; int acl_count; struct acl *acl_buf = NULL; int ret; if (hpux_acl_call_presence() == False) { /* Looks like we don't have the acl() system call on HPUX. * May be the system doesn't have the latest version of JFS. */ errno=ENOSYS; return -1; } if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { errno = EINVAL; return -1; } if (acl_sort(acl_d) != 0) { return -1; } acl_p = &acl_d->acl[0]; acl_count = acl_d->count; /* * if it's a directory there is extra work to do * since the acl() system call will replace both * the access ACLs and the default ACLs (if any) */ if (stat(name, &s) != 0) { return -1; } if (S_ISDIR(s.st_mode)) { SMB_ACL_T acc_acl; SMB_ACL_T def_acl; SMB_ACL_T tmp_acl; int i; if (type == SMB_ACL_TYPE_ACCESS) { acc_acl = acl_d; def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); } else { def_acl = acl_d; acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); } if (tmp_acl == NULL) { return -1; } /* * allocate a temporary buffer for the complete ACL */ acl_count = acc_acl->count + def_acl->count; acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); if (acl_buf == NULL) { sys_acl_free_acl(tmp_acl); errno = ENOMEM; return -1; } /* * copy the access control and default entries into the buffer */ memcpy(&acl_buf[0], &acc_acl->acl[0], acc_acl->count * sizeof acl_buf[0]); memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], def_acl->count * sizeof acl_buf[0]); /* * set the ACL_DEFAULT flag on the default entries */ for (i = acc_acl->count; i < acl_count; i++) { acl_buf[i].a_type |= ACL_DEFAULT; } sys_acl_free_acl(tmp_acl); } else if (type != SMB_ACL_TYPE_ACCESS) { errno = EINVAL; return -1; } ret = acl(name, ACL_SET, acl_count, acl_p); if (acl_buf) { free(acl_buf); } return ret; } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) { /* * HPUX doesn't have the facl call. Fake it using the path.... JRA. */ files_struct *fsp = file_find_fd(fd); if (fsp == NULL) { errno = EBADF; return NULL; } if (acl_sort(acl_d) != 0) { return -1; } /* * We know we're in the same conn context. So we * can use the relative path. */ return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d); } #endif int sys_acl_delete_def_file(const char *path) { SMB_ACL_T acl_d; int ret; /* * fetching the access ACL and rewriting it has * the effect of deleting the default ACL */ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { return -1; } ret = acl(path, ACL_SET, acl_d->count, acl_d->acl); sys_acl_free_acl(acl_d); return ret; } int sys_acl_free_acl(SMB_ACL_T acl_d) { free(acl_d); return 0; } #elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/ int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) { if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { errno = EINVAL; return -1; } if (entry_p == NULL) { errno = EINVAL; return -1; } if (entry_id == SMB_ACL_FIRST_ENTRY) { acl_d->next = 0; } if (acl_d->next < 0) { errno = EINVAL; return -1; } if (acl_d->next >= acl_d->aclp->acl_cnt) { return 0; } *entry_p = &acl_d->aclp->acl_entry[acl_d->next++]; return 1; } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) { *type_p = entry_d->ae_tag; return 0; } SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { SMB_ACL_T a; if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { errno = ENOMEM; return NULL; } if ((a->aclp = acl_get_file(path_p, type)) == NULL) { SAFE_FREE(a); return NULL; } a->next = -1; a->freeaclp = True; return a; } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { SMB_ACL_T a; if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { errno = ENOMEM; return NULL; } if ((a->aclp = acl_get_fd(fd)) == NULL) { SAFE_FREE(a); return NULL; } a->next = -1; a->freeaclp = True; return a; } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { *tag_type_p = entry->ae_tag; *bits_p = entry->ae_perm; if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) *u_g_id_p = entry->ae_id; return 0; } SMB_ACL_T sys_acl_init(int count) { SMB_ACL_T a; if (count < 0) { errno = EINVAL; return NULL; } if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) { errno = ENOMEM; return NULL; } a->next = -1; a->freeaclp = False; a->aclp = (struct acl *)((char *)a + sizeof a[0]); a->aclp->acl_cnt = 0; return a; } int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) { SMB_ACL_T acl_d; SMB_ACL_ENTRY_T entry_d; if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { errno = EINVAL; return -1; } if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) { errno = ENOSPC; return -1; } entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++]; entry_d->ae_tag = 0; entry_d->ae_id = 0; entry_d->ae_perm = 0; *entry_p = entry_d; return 0; } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { entry->ae_tag = tag_type; if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) entry->ae_id = u_g_id; entry->ae_perm = bits; return 0; } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) { entry_d->ae_perm = bits; return 0; } int sys_acl_valid(SMB_ACL_T acl_d) { return acl_valid(acl_d->aclp); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) { return acl_set_file(name, type, acl_d->aclp); } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) { return acl_set_fd(fd, acl_d->aclp); } #endif int sys_acl_delete_def_file(const char *name) { return acl_delete_def_file(name); } int sys_acl_free_acl(SMB_ACL_T acl_d) { if (acl_d->freeaclp) { acl_free(acl_d->aclp); } acl_free(acl_d); return 0; } #elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/ /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */ int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) { struct acl_entry_link *link; int keep_going; if (entry_id == SMB_ACL_FIRST_ENTRY) theacl->count = 0; else if (entry_id != SMB_ACL_NEXT_ENTRY) { errno = EINVAL; return -1; } DEBUG(10, ("This is the count: %d\n", theacl->count)); /* Check if count was previously set to -1. * * If it was, that means we reached the end * * of the acl last time. */ if (theacl->count == -1) return 0; link = theacl; /* To get to the next acl, traverse linked list until index * * of acl matches the count we are keeping. This count is * * incremented each time we return an acl entry. */ for (keep_going = 0; keep_going < theacl->count; keep_going++) link = link->nextp; *entry_p = link->entryp; #if 0 { struct new_acl_entry *entry = *entry_p; DEBUG(10, ("*entry_p is %lx\n", (long)entry)); DEBUG(10, ("*entry_p->ace_access is %d\n", entry->ace_access)); } #endif /* Increment count */ theacl->count++; if (link->nextp == NULL) theacl->count = -1; return 1; } int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) { /* Initialize tag type */ *tag_type_p = -1; DEBUG(10, ("the tagtype is %d\n", entry_d->ace_id->id_type)); /* Depending on what type of entry we have, * * return tag type. */ switch (entry_d->ace_id->id_type) { case ACEID_USER: *tag_type_p = SMB_ACL_USER; break; case ACEID_GROUP: *tag_type_p = SMB_ACL_GROUP; break; case SMB_ACL_USER_OBJ: case SMB_ACL_GROUP_OBJ: case SMB_ACL_OTHER: *tag_type_p = entry_d->ace_id->id_type; break; default: return -1; } return 0; } SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { struct acl *file_acl = (struct acl *)NULL; struct acl_entry *acl_entry; struct new_acl_entry *new_acl_entry; struct ace_id *idp; struct acl_entry_link *acl_entry_link; struct acl_entry_link *acl_entry_link_head; int i; int rc = 0; /* AIX has no DEFAULT */ if (type == SMB_ACL_TYPE_DEFAULT) { #ifdef ENOTSUP errno = ENOTSUP; #else errno = ENOSYS; #endif return NULL; } /* Get the acl using statacl */ DEBUG(10, ("Entering sys_acl_get_file\n")); DEBUG(10, ("path_p is %s\n", path_p)); file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if (file_acl == NULL) { errno=ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file: %d\n", errno)); return NULL; } memset(file_acl, 0, BUFSIZ); rc = statacl((char *)path_p, 0, file_acl, BUFSIZ); if (rc == -1) { DEBUG(0, ("statacl returned %d with errno %d\n", rc, errno)); SAFE_FREE(file_acl); return NULL; } DEBUG(10, ("Got facl and returned it\n")); /* Point to the first acl entry in the acl */ acl_entry = file_acl->acl_ext; /* Begin setting up the head of the linked list * * that will be used for the storing the acl * * in a way that is useful for the posix_acls.c * * code. */ acl_entry_link_head = acl_entry_link = sys_acl_init(0); if (acl_entry_link_head == NULL) return NULL; acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); return NULL; } DEBUG(10, ("acl_entry is %d\n", acl_entry)); DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl))); /* Check if the extended acl bit is on. * * If it isn't, do not show the * * contents of the acl since AIX intends * * the extended info to remain unused */ if (file_acl->acl_mode & S_IXACL){ /* while we are not pointing to the very end */ while (acl_entry < acl_last(file_acl)) { /* before we malloc anything, make sure this is */ /* a valid acl entry and one that we want to map */ idp = id_nxt(acl_entry->ace_id); if ((acl_entry->ace_type == ACC_SPECIFY || acl_entry->ace_type == ACC_PERMIT) && idp != id_last(acl_entry)) { acl_entry = acl_nxt(acl_entry); continue; } idp = acl_entry->ace_id; /* Check if this is the first entry in the linked list. * * The first entry needs to keep prevp pointing to NULL * * and already has entryp allocated. */ if (acl_entry_link_head->count != 0) { acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); if (acl_entry_link->nextp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); return NULL; } acl_entry_link->nextp->prevp = acl_entry_link; acl_entry_link = acl_entry_link->nextp; acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); return NULL; } acl_entry_link->nextp = NULL; } acl_entry_link->entryp->ace_len = acl_entry->ace_len; /* Don't really need this since all types are going * * to be specified but, it's better than leaving it 0 */ acl_entry_link->entryp->ace_type = acl_entry->ace_type; acl_entry_link->entryp->ace_access = acl_entry->ace_access; memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id)); /* The access in the acl entries must be left shifted by * * three bites, because they will ultimately be compared * * to S_IRUSR, S_IWUSR, and S_IXUSR. */ switch (acl_entry->ace_type){ case ACC_PERMIT: case ACC_SPECIFY: acl_entry_link->entryp->ace_access = acl_entry->ace_access; acl_entry_link->entryp->ace_access <<= 6; acl_entry_link_head->count++; break; case ACC_DENY: /* Since there is no way to return a DENY acl entry * * change to PERMIT and then shift. */ DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access)); acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access)); acl_entry_link->entryp->ace_access <<= 6; acl_entry_link_head->count++; break; default: return 0; } DEBUG(10, ("acl_entry = %d\n", acl_entry)); DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type)); acl_entry = acl_nxt(acl_entry); } } /* end of if enabled */ /* Since owner, group, other acl entries are not * * part of the acl entries in an acl, they must * * be dummied up to become part of the list. */ for (i = 1; i < 4; i++) { DEBUG(10, ("i is %d\n", i)); if (acl_entry_link_head->count != 0) { acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); if (acl_entry_link->nextp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); return NULL; } acl_entry_link->nextp->prevp = acl_entry_link; acl_entry_link = acl_entry_link->nextp; acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); return NULL; } } acl_entry_link->nextp = NULL; new_acl_entry = acl_entry_link->entryp; idp = new_acl_entry->ace_id; new_acl_entry->ace_len = sizeof (struct acl_entry); new_acl_entry->ace_type = ACC_PERMIT; idp->id_len = sizeof (struct ace_id); DEBUG(10, ("idp->id_len = %d\n", idp->id_len)); memset(idp->id_data, 0, sizeof (uid_t)); switch (i) { case 2: new_acl_entry->ace_access = file_acl->g_access << 6; idp->id_type = SMB_ACL_GROUP_OBJ; break; case 3: new_acl_entry->ace_access = file_acl->o_access << 6; idp->id_type = SMB_ACL_OTHER; break; case 1: new_acl_entry->ace_access = file_acl->u_access << 6; idp->id_type = SMB_ACL_USER_OBJ; break; default: return NULL; } acl_entry_link_head->count++; DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access)); } acl_entry_link_head->count = 0; SAFE_FREE(file_acl); return acl_entry_link_head; } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { struct acl *file_acl = (struct acl *)NULL; struct acl_entry *acl_entry; struct new_acl_entry *new_acl_entry; struct ace_id *idp; struct acl_entry_link *acl_entry_link; struct acl_entry_link *acl_entry_link_head; int i; int rc = 0; /* Get the acl using fstatacl */ DEBUG(10, ("Entering sys_acl_get_fd\n")); DEBUG(10, ("fd is %d\n", fd)); file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if (file_acl == NULL) { errno=ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); return NULL; } memset(file_acl, 0, BUFSIZ); rc = fstatacl(fd, 0, file_acl, BUFSIZ); if (rc == -1) { DEBUG(0, ("The fstatacl call returned %d with errno %d\n", rc, errno)); SAFE_FREE(file_acl); return NULL; } DEBUG(10, ("Got facl and returned it\n")); /* Point to the first acl entry in the acl */ acl_entry = file_acl->acl_ext; /* Begin setting up the head of the linked list * * that will be used for the storing the acl * * in a way that is useful for the posix_acls.c * * code. */ acl_entry_link_head = acl_entry_link = sys_acl_init(0); if (acl_entry_link_head == NULL){ SAFE_FREE(file_acl); return NULL; } acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); SAFE_FREE(file_acl); return NULL; } DEBUG(10, ("acl_entry is %d\n", acl_entry)); DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl))); /* Check if the extended acl bit is on. * * If it isn't, do not show the * * contents of the acl since AIX intends * * the extended info to remain unused */ if (file_acl->acl_mode & S_IXACL){ /* while we are not pointing to the very end */ while (acl_entry < acl_last(file_acl)) { /* before we malloc anything, make sure this is */ /* a valid acl entry and one that we want to map */ idp = id_nxt(acl_entry->ace_id); if ((acl_entry->ace_type == ACC_SPECIFY || (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) { acl_entry = acl_nxt(acl_entry); continue; } idp = acl_entry->ace_id; /* Check if this is the first entry in the linked list. * * The first entry needs to keep prevp pointing to NULL * * and already has entryp allocated. */ if (acl_entry_link_head->count != 0) { acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); if (acl_entry_link->nextp == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); SAFE_FREE(file_acl); return NULL; } acl_entry_link->nextp->prevp = acl_entry_link; acl_entry_link = acl_entry_link->nextp; acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); SAFE_FREE(file_acl); return NULL; } acl_entry_link->nextp = NULL; } acl_entry_link->entryp->ace_len = acl_entry->ace_len; /* Don't really need this since all types are going * * to be specified but, it's better than leaving it 0 */ acl_entry_link->entryp->ace_type = acl_entry->ace_type; acl_entry_link->entryp->ace_access = acl_entry->ace_access; memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id)); /* The access in the acl entries must be left shifted by * * three bites, because they will ultimately be compared * * to S_IRUSR, S_IWUSR, and S_IXUSR. */ switch (acl_entry->ace_type){ case ACC_PERMIT: case ACC_SPECIFY: acl_entry_link->entryp->ace_access = acl_entry->ace_access; acl_entry_link->entryp->ace_access <<= 6; acl_entry_link_head->count++; break; case ACC_DENY: /* Since there is no way to return a DENY acl entry * * change to PERMIT and then shift. */ DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access)); acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access)); acl_entry_link->entryp->ace_access <<= 6; acl_entry_link_head->count++; break; default: return 0; } DEBUG(10, ("acl_entry = %d\n", acl_entry)); DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type)); acl_entry = acl_nxt(acl_entry); } } /* end of if enabled */ /* Since owner, group, other acl entries are not * * part of the acl entries in an acl, they must * * be dummied up to become part of the list. */ for (i = 1; i < 4; i++) { DEBUG(10, ("i is %d\n", i)); if (acl_entry_link_head->count != 0){ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); if (acl_entry_link->nextp == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); SAFE_FREE(file_acl); return NULL; } acl_entry_link->nextp->prevp = acl_entry_link; acl_entry_link = acl_entry_link->nextp; acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); if (acl_entry_link->entryp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); return NULL; } } acl_entry_link->nextp = NULL; new_acl_entry = acl_entry_link->entryp; idp = new_acl_entry->ace_id; new_acl_entry->ace_len = sizeof (struct acl_entry); new_acl_entry->ace_type = ACC_PERMIT; idp->id_len = sizeof (struct ace_id); DEBUG(10, ("idp->id_len = %d\n", idp->id_len)); memset(idp->id_data, 0, sizeof (uid_t)); switch (i) { case 2: new_acl_entry->ace_access = file_acl->g_access << 6; idp->id_type = SMB_ACL_GROUP_OBJ; break; case 3: new_acl_entry->ace_access = file_acl->o_access << 6; idp->id_type = SMB_ACL_OTHER; break; case 1: new_acl_entry->ace_access = file_acl->u_access << 6; idp->id_type = SMB_ACL_USER_OBJ; break; default: return NULL; } acl_entry_link_head->count++; DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access)); } acl_entry_link_head->count = 0; SAFE_FREE(file_acl); return acl_entry_link_head; } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { uint *permset; if (sys_acl_get_tag_type(entry, tag_type_p) != 0) return -1; if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t)); permset = &entry->ace_access; DEBUG(10, ("*permset is %d\n", *permset)); *bits_p = (*permset & S_IRUSR ? 4 : 0) | (*permset & S_IWUSR ? 2 : 0) | (*permset & S_IXUSR ? 1 : 0); return 0; } SMB_ACL_T sys_acl_init(int count) { struct acl_entry_link *theacl = NULL; if (count < 0) { errno = EINVAL; return NULL; } DEBUG(10, ("Entering sys_acl_init\n")); theacl = SMB_MALLOC_P(struct acl_entry_link); if (theacl == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_init is %d\n", errno)); return NULL; } theacl->count = 0; theacl->nextp = NULL; theacl->prevp = NULL; theacl->entryp = NULL; DEBUG(10, ("Exiting sys_acl_init\n")); return theacl; } int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) { struct acl_entry_link *theacl; struct acl_entry_link *acl_entryp; struct acl_entry_link *temp_entry = NULL; int counting; DEBUG(10, ("Entering the sys_acl_create_entry\n")); theacl = acl_entryp = *pacl; /* Get to the end of the acl before adding entry */ for (counting = 0; counting < theacl->count; counting++){ DEBUG(10, ("The acl_entryp is %d\n", acl_entryp)); temp_entry = acl_entryp; acl_entryp = acl_entryp->nextp; } if (theacl->count != 0){ temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link); if (acl_entryp == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno)); return -1; } DEBUG(10, ("The acl_entryp is %d\n", acl_entryp)); acl_entryp->prevp = temp_entry; DEBUG(10, ("The acl_entryp->prevp is %d\n", acl_entryp->prevp)); } *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry); if (*pentry == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno)); return -1; } memset(*pentry, 0, sizeof (struct new_acl_entry)); acl_entryp->entryp->ace_len = sizeof (struct acl_entry); acl_entryp->entryp->ace_type = ACC_PERMIT; acl_entryp->entryp->ace_id->id_len = sizeof (struct ace_id); acl_entryp->nextp = NULL; theacl->count++; DEBUG(10, ("Exiting sys_acl_create_entry\n")); return 0; } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { entry->ace_id->id_type = tag_type; DEBUG(10, ("The tag type is %d\n", entry->ace_id->id_type)); if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t)); entry->ace_access = bits; DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access)); return 0; } int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) { DEBUG(10, ("Starting AIX sys_acl_set_permset\n")); entry->ace_access = bits; DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access)); DEBUG(10, ("Ending AIX sys_acl_set_permset\n")); return 0; } int sys_acl_valid(SMB_ACL_T theacl) { int user_obj = 0; int group_obj = 0; int other_obj = 0; struct acl_entry_link *acl_entry; for (acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) { user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ); group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ); other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER); } DEBUG(10, ("user_obj=%d, group_obj=%d, other_obj=%d\n", user_obj, group_obj, other_obj)); if (user_obj != 1 || group_obj != 1 || other_obj != 1) return -1; return 0; } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { struct acl_entry_link *acl_entry_link = NULL; struct acl *file_acl = NULL; struct acl *file_acl_temp = NULL; struct acl_entry *acl_entry = NULL; struct ace_id *ace_id = NULL; uint id_type; uint user_id; uint acl_length; uint rc; DEBUG(10, ("Entering sys_acl_set_file\n")); DEBUG(10, ("File name is %s\n", name)); /* AIX has no default ACL */ if (acltype == SMB_ACL_TYPE_DEFAULT) return 0; acl_length = BUFSIZ; file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if (file_acl == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno)); return -1; } memset(file_acl, 0, BUFSIZ); file_acl->acl_len = ACL_SIZ; file_acl->acl_mode = S_IXACL; for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { acl_entry_link->entryp->ace_access >>= 6; id_type = acl_entry_link->entryp->ace_id->id_type; switch (id_type) { case SMB_ACL_USER_OBJ: file_acl->u_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_GROUP_OBJ: file_acl->g_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_OTHER: file_acl->o_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_MASK: continue; } if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) { acl_length += sizeof (struct acl_entry); file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); if (file_acl_temp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno)); return -1; } memcpy(file_acl_temp, file_acl, file_acl->acl_len); SAFE_FREE(file_acl); file_acl = file_acl_temp; } acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); file_acl->acl_len += sizeof (struct acl_entry); acl_entry->ace_len = acl_entry_link->entryp->ace_len; acl_entry->ace_access = acl_entry_link->entryp->ace_access; /* In order to use this, we'll need to wait until we can get denies */ /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) acl_entry->ace_type = ACC_SPECIFY; */ acl_entry->ace_type = ACC_SPECIFY; ace_id = acl_entry->ace_id; ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; DEBUG(10, ("The id type is %d\n", ace_id->id_type)); ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t)); memcpy(acl_entry->ace_id->id_data, &user_id, sizeof (uid_t)); } rc = chacl((char*)name, file_acl, file_acl->acl_len); DEBUG(10, ("errno is %d\n", errno)); DEBUG(10, ("return code is %d\n", rc)); SAFE_FREE(file_acl); DEBUG(10, ("Exiting the sys_acl_set_file\n")); return rc; } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T theacl) { struct acl_entry_link *acl_entry_link = NULL; struct acl *file_acl = NULL; struct acl *file_acl_temp = NULL; struct acl_entry *acl_entry = NULL; struct ace_id *ace_id = NULL; uint id_type; uint user_id; uint acl_length; uint rc; DEBUG(10, ("Entering sys_acl_set_fd\n")); acl_length = BUFSIZ; file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if (file_acl == NULL) { errno = ENOMEM; DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno)); return -1; } memset(file_acl, 0, BUFSIZ); file_acl->acl_len = ACL_SIZ; file_acl->acl_mode = S_IXACL; for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { acl_entry_link->entryp->ace_access >>= 6; id_type = acl_entry_link->entryp->ace_id->id_type; DEBUG(10, ("The id_type is %d\n", id_type)); switch (id_type) { case SMB_ACL_USER_OBJ: file_acl->u_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_GROUP_OBJ: file_acl->g_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_OTHER: file_acl->o_access = acl_entry_link->entryp->ace_access; continue; case SMB_ACL_MASK: continue; } if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) { acl_length += sizeof (struct acl_entry); file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); if (file_acl_temp == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno)); return -1; } memcpy(file_acl_temp, file_acl, file_acl->acl_len); SAFE_FREE(file_acl); file_acl = file_acl_temp; } acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); file_acl->acl_len += sizeof (struct acl_entry); acl_entry->ace_len = acl_entry_link->entryp->ace_len; acl_entry->ace_access = acl_entry_link->entryp->ace_access; /* In order to use this, we'll need to wait until we can get denies */ /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) acl_entry->ace_type = ACC_SPECIFY; */ acl_entry->ace_type = ACC_SPECIFY; ace_id = acl_entry->ace_id; ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; DEBUG(10, ("The id type is %d\n", ace_id->id_type)); ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t)); memcpy(ace_id->id_data, &user_id, sizeof (uid_t)); } rc = fchacl(fd, file_acl, file_acl->acl_len); DEBUG(10, ("errno is %d\n", errno)); DEBUG(10, ("return code is %d\n", rc)); SAFE_FREE(file_acl); DEBUG(10, ("Exiting sys_acl_set_fd\n")); return rc; } #endif int sys_acl_delete_def_file(UNUSED(const char *name)) { /* AIX has no default ACL */ return 0; } int sys_acl_free_acl(SMB_ACL_T posix_acl) { struct acl_entry_link *acl_entry_link; for (acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) { SAFE_FREE(acl_entry_link->prevp->entryp); SAFE_FREE(acl_entry_link->prevp); } SAFE_FREE(acl_entry_link->prevp->entryp); SAFE_FREE(acl_entry_link->prevp); SAFE_FREE(acl_entry_link->entryp); SAFE_FREE(acl_entry_link); return 0; } #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/ #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */ #include int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) { int ret = acl_get_entry(the_acl, entry_id, entry_p); #ifdef OSX_BROKEN_GETENTRY if (ret == 0) ret = 1; else if (ret == -1 && errno == 22) ret = 0; #endif return ret; } SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) { if (type == ACL_TYPE_DEFAULT) { errno = ENOTSUP; return NULL; } errno = 0; return acl_get_file(path_p, type); } #if 0 SMB_ACL_T sys_acl_get_fd(int fd) { return acl_get_fd(fd); } #endif int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p) { uuid_t *uup; acl_tag_t tag; acl_flagset_t flagset; acl_permset_t permset; uint32 bits, fb, bb, pb; int id_type = -1; int rc; if (acl_get_tag_type(entry, &tag) != 0 || acl_get_flagset_np(entry, &flagset) != 0 || acl_get_permset(entry, &permset) != 0 || (uup = acl_get_qualifier(entry)) == NULL) return -1; rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type); acl_free(uup); if (rc != 0) return rc; if (id_type == ID_TYPE_UID) *tag_type_p = SMB_ACL_USER; else *tag_type_p = SMB_ACL_GROUP; bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0; for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) { if (acl_get_flag_np(flagset, fb) == 1) bits |= bb; } for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) { if (acl_get_perm_np(permset, pb) == 1) bits |= bb; } *bits_p = bits; return 0; } SMB_ACL_T sys_acl_init(int count) { return acl_init(count); } int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) { return acl_create_entry(pacl, pentry); } int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) { acl_flagset_t flagset; acl_permset_t permset; uint32 fb, bb, pb; int is_user = tag_type == SMB_ACL_USER; uuid_t uu; int rc; tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY; if (acl_get_flagset_np(entry, &flagset) != 0 || acl_get_permset(entry, &permset) != 0) return -1; acl_clear_flags_np(flagset); acl_clear_perms(permset); for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) { if (bits & bb) acl_add_flag_np(flagset, fb); } for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) { if (bits & bb) acl_add_perm(permset, pb); } if (is_user) rc = mbr_uid_to_uuid(u_g_id, uu); else rc = mbr_gid_to_uuid(u_g_id, uu); if (rc != 0) return rc; if (acl_set_tag_type(entry, tag_type) != 0 || acl_set_qualifier(entry, &uu) != 0 || acl_set_permset(entry, permset) != 0 || acl_set_flagset_np(entry, flagset) != 0) return -1; return 0; } #if 0 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) { return -1; /* Not needed for OS X. */ } #endif int sys_acl_valid(SMB_ACL_T theacl) { return acl_valid(theacl); } int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { return acl_set_file(name, acltype, theacl); } #if 0 int sys_acl_set_fd(int fd, SMB_ACL_T theacl) { return acl_set_fd(fd, theacl); } #endif int sys_acl_delete_def_file(const char *name) { return acl_delete_def_file(name); } int sys_acl_free_acl(SMB_ACL_T the_acl) { return acl_free(the_acl); } #else /* No ACLs. */ #error No ACL functions defined for this platform! #endif /************************************************************************ Deliberately outside the ACL defines. Return 1 if this is a "no acls" errno, 0 if not. ************************************************************************/ int no_acl_syscall_error(int err) { #ifdef HAVE_OSX_ACLS if (err == ENOENT) return 1; /* Weird problem with directory ACLs. */ #endif #if defined(ENOSYS) if (err == ENOSYS) { return 1; } #endif #if defined(ENOTSUP) if (err == ENOTSUP) { return 1; } #endif if (err == EINVAL) { /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT * isn't valid, then the ACLs must be non-POSIX. */ return 1; } return 0; } #endif /* SUPPORT_ACLS */ rsync-3.2.7/lib/mdfour.c0000664000000000000000000001374113662656273013615 0ustar rootroot/* * Unix SMB/Netbios implementation. * Version 1.9. * An implementation of MD4 designed for use in the SMB authentication protocol. * * Copyright (C) 1997-1998 Andrew Tridgell * Copyright (C) 2005-2020 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" /* NOTE: This code makes no attempt to be fast! * * It assumes that a int is at least 32 bits long. */ static md_context *m; #define MASK32 (0xffffffff) #define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z)))) #define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))) #define H(X,Y,Z) (((X)^(Y)^(Z))) #define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32))) #define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s) #define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s) #define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s) /* this applies md4 to 64 byte chunks */ static void mdfour64(uint32 *M) { uint32 AA, BB, CC, DD; uint32 A,B,C,D; A = m->A; B = m->B; C = m->C; D = m->D; AA = A; BB = B; CC = C; DD = D; ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); A += AA; B += BB; C += CC; D += DD; A &= MASK32; B &= MASK32; C &= MASK32; D &= MASK32; m->A = A; m->B = B; m->C = C; m->D = D; } static void copy64(uint32 *M, const uchar *in) { int i; for (i = 0; i < MD4_DIGEST_LEN; i++) { M[i] = (in[i*4+3] << 24) | (in[i*4+2] << 16) | (in[i*4+1] << 8) | (in[i*4+0] << 0); } } static void copy4(uchar *out,uint32 x) { out[0] = x&0xFF; out[1] = (x>>8)&0xFF; out[2] = (x>>16)&0xFF; out[3] = (x>>24)&0xFF; } void mdfour_begin(md_context *md) { md->A = 0x67452301; md->B = 0xefcdab89; md->C = 0x98badcfe; md->D = 0x10325476; md->totalN = 0; md->totalN2 = 0; } static void mdfour_tail(const uchar *in, uint32 length) { uchar buf[128]; uint32 M[16]; extern int protocol_version; /* * Count total number of bits, modulo 2^64 */ m->totalN += length << 3; if (m->totalN < (length << 3)) m->totalN2++; m->totalN2 += length >> 29; memset(buf, 0, 128); if (length) memcpy(buf, in, length); buf[length] = 0x80; if (length <= 55) { copy4(buf+56, m->totalN); /* * Prior to protocol version 27 only the number of bits * modulo 2^32 was included. MD4 requires the number * of bits modulo 2^64, which was fixed starting with * protocol version 27. */ if (protocol_version >= 27) copy4(buf+60, m->totalN2); copy64(M, buf); mdfour64(M); } else { copy4(buf+120, m->totalN); /* * Prior to protocol version 27 only the number of bits * modulo 2^32 was included. MD4 requires the number * of bits modulo 2^64, which was fixed starting with * protocol version 27. */ if (protocol_version >= 27) copy4(buf+124, m->totalN2); copy64(M, buf); mdfour64(M); copy64(M, buf+64); mdfour64(M); } } void mdfour_update(md_context *md, const uchar *in, uint32 length) { uint32 M[16]; m = md; if (length == 0) mdfour_tail(in, length); while (length >= 64) { copy64(M, in); mdfour64(M); in += 64; length -= 64; m->totalN += 64 << 3; if (m->totalN < 64 << 3) m->totalN2++; } if (length) mdfour_tail(in, length); } void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]) { m = md; copy4(digest, m->A); copy4(digest+4, m->B); copy4(digest+8, m->C); copy4(digest+12, m->D); } #ifdef TEST_MDFOUR void mdfour(uchar digest[MD4_DIGEST_LEN], uchar *in, int length) { md_context md; mdfour_begin(&md); mdfour_update(&md, in, length); mdfour_result(&md, digest); } int protocol_version = 28; static void file_checksum1(char *fname) { int fd, i, was_multiple_of_64 = 1; md_context md; uchar buf[64*1024], sum[MD4_DIGEST_LEN]; fd = open(fname,O_RDONLY); if (fd == -1) { perror("fname"); exit(1); } mdfour_begin(&md); while (1) { int n = read(fd, buf, sizeof buf); if (n <= 0) break; was_multiple_of_64 = !(n % 64); mdfour_update(&md, buf, n); } if (was_multiple_of_64 && protocol_version >= 27) mdfour_update(&md, buf, 0); close(fd); mdfour_result(&md, sum); for (i = 0; i < MD4_DIGEST_LEN; i++) printf("%02X", sum[i]); printf("\n"); } int main(int argc, char *argv[]) { while (--argc) file_checksum1(*++argv); return 0; } #endif rsync-3.2.7/lib/getpass.c0000664000000000000000000000343712146245671013760 0ustar rootroot/* * An implementation of getpass for systems that lack one. * * Copyright (C) 2013 Roman Donchenko * * 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 #include #include #include "rsync.h" char *getpass(const char *prompt) { static char password[256]; BOOL tty_changed = False, read_success; struct termios tty_old, tty_new; FILE *in = stdin, *out = stderr; FILE *tty = fopen("/dev/tty", "w+"); if (tty) in = out = tty; if (tcgetattr(fileno(in), &tty_old) == 0) { tty_new = tty_old; tty_new.c_lflag &= ~(ECHO | ISIG); if (tcsetattr(fileno(in), TCSAFLUSH, &tty_new) == 0) tty_changed = True; } if (!tty_changed) fputs("(WARNING: will be visible) ", out); fputs(prompt, out); fflush(out); read_success = fgets(password, sizeof password, in) != NULL; /* Print the newline that hasn't been echoed. */ fputc('\n', out); if (tty_changed) tcsetattr(fileno(in), TCSAFLUSH, &tty_old); if (tty) fclose(tty); if (read_success) { /* Remove the trailing newline. */ size_t password_len = strlen(password); if (password_len && password[password_len - 1] == '\n') password[password_len - 1] = '\0'; return password; } return NULL; } rsync-3.2.7/lib/inet_ntop.c0000664000000000000000000001147510514745514014310 0ustar rootroot/* * Copyright (C) 1996-2001 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "rsync.h" #define NS_INT16SZ 2 #define NS_IN6ADDRSZ 16 /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size); #ifdef AF_INET6 static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size); #endif /* char * * isc_net_ntop(af, src, dst, size) * convert a network format address to presentation format. * return: * pointer to presentation format address (`dst'), or NULL (see errno). * author: * Paul Vixie, 1996. */ const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET: return (inet_ntop4(src, dst, size)); #ifdef AF_INET6 case AF_INET6: return (inet_ntop6(src, dst, size)); #endif default: errno = EAFNOSUPPORT; return (NULL); } /* NOTREACHED */ } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a unsigned char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char * inet_ntop4(const unsigned char *src, char *dst, size_t size) { static const char *fmt = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; size_t len; len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]); if (len >= size) { errno = ENOSPC; return (NULL); } memcpy(dst, tmp, len + 1); return (dst); } /* const char * * isc_inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ #ifdef AF_INET6 static const char * inet_ntop6(const unsigned char *src, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; struct { int base, len; } best, cur; unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; int i, inc; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ memset(words, '\0', sizeof words); for (i = 0; i < NS_IN6ADDRSZ; i++) words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); best.base = -1; cur.base = -1; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { if (words[i] == 0) { if (cur.base == -1) cur.base = i, cur.len = 1; else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; } if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) *tp++ = ':'; /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) return (NULL); tp += strlen(tp); break; } inc = snprintf(tp, 5, "%x", words[i]); assert(inc < 5); tp += inc; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { errno = ENOSPC; return (NULL); } memcpy(dst, tmp, tp - tmp); return (dst); } #endif /* AF_INET6 */ rsync-3.2.7/lib/permstring.h0000664000000000000000000000010710367260137014475 0ustar rootroot#define PERMSTRING_SIZE 11 void permstring(char *perms, mode_t mode); rsync-3.2.7/lib/md-defines.h0000664000000000000000000000157314307156014014322 0ustar rootroot/* Keep this simple so both C and ASM can use it */ /* These allow something like CFLAGS=-DDISABLE_SHA512_DIGEST */ #ifdef DISABLE_SHA256_DIGEST #undef SHA256_DIGEST_LENGTH #endif #ifdef DISABLE_SHA512_DIGEST #undef SHA512_DIGEST_LENGTH #endif #define MD4_DIGEST_LEN 16 #define MD5_DIGEST_LEN 16 #if defined SHA512_DIGEST_LENGTH #define MAX_DIGEST_LEN SHA512_DIGEST_LENGTH #elif defined SHA256_DIGEST_LENGTH #define MAX_DIGEST_LEN SHA256_DIGEST_LENGTH #elif defined SHA_DIGEST_LENGTH #define MAX_DIGEST_LEN SHA_DIGEST_LENGTH #else #define MAX_DIGEST_LEN MD5_DIGEST_LEN #endif #define CSUM_CHUNK 64 #define CSUM_gone -1 #define CSUM_NONE 0 #define CSUM_MD4_ARCHAIC 1 #define CSUM_MD4_BUSTED 2 #define CSUM_MD4_OLD 3 #define CSUM_MD4 4 #define CSUM_MD5 5 #define CSUM_XXH64 6 #define CSUM_XXH3_64 7 #define CSUM_XXH3_128 8 #define CSUM_SHA1 9 #define CSUM_SHA256 10 #define CSUM_SHA512 11 rsync-3.2.7/lib/sysacls.h0000664000000000000000000001750714276226634014007 0ustar rootroot/* * Unix SMB/Netbios implementation. * Version 2.2.x * Portable SMB ACL interface * Copyright (C) Jeremy Allison 2000 * Copyright (C) 2007-2022 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 * with this program; if not, visit the http://fsf.org website. */ #ifdef SUPPORT_ACLS #ifdef HAVE_SYS_ACL_H #include #endif #ifdef HAVE_ACL_LIBACL_H #include #endif #define SMB_MALLOC(cnt) new_array(char, cnt) #define SMB_MALLOC_P(obj) new_array(obj, 1) #define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt) #define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt) #define slprintf snprintf #if defined HAVE_POSIX_ACLS /*-----------------------------------------------*/ /* This is an identity mapping (just remove the SMB_). */ #define SMB_ACL_TAG_T acl_tag_t #define SMB_ACL_TYPE_T acl_type_t /* Types of ACLs. */ #define SMB_ACL_USER ACL_USER #define SMB_ACL_USER_OBJ ACL_USER_OBJ #define SMB_ACL_GROUP ACL_GROUP #define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ #define SMB_ACL_OTHER ACL_OTHER #define SMB_ACL_MASK ACL_MASK #define SMB_ACL_T acl_t #define SMB_ACL_ENTRY_T acl_entry_t #define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY #define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY #define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS #define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #elif defined HAVE_TRU64_ACLS /*---------------------------------------------*/ /* This is for DEC/Compaq Tru64 UNIX */ #define SMB_ACL_TAG_T acl_tag_t #define SMB_ACL_TYPE_T acl_type_t /* Types of ACLs. */ #define SMB_ACL_USER ACL_USER #define SMB_ACL_USER_OBJ ACL_USER_OBJ #define SMB_ACL_GROUP ACL_GROUP #define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ #define SMB_ACL_OTHER ACL_OTHER #define SMB_ACL_MASK ACL_MASK #define SMB_ACL_T acl_t #define SMB_ACL_ENTRY_T acl_entry_t #define SMB_ACL_FIRST_ENTRY 0 #define SMB_ACL_NEXT_ENTRY 1 #define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS #define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS /*-------------*/ /* Donated by Michael Davidson for UnixWare / OpenUNIX. * Modified by Toomas Soome for Solaris. */ /* SVR4.2 ES/MP ACLs */ typedef int SMB_ACL_TAG_T; typedef int SMB_ACL_TYPE_T; /* Types of ACLs. */ #define SMB_ACL_USER USER #define SMB_ACL_USER_OBJ USER_OBJ #define SMB_ACL_GROUP GROUP #define SMB_ACL_GROUP_OBJ GROUP_OBJ #define SMB_ACL_OTHER OTHER_OBJ #define SMB_ACL_MASK CLASS_OBJ typedef struct SMB_ACL_T { int size; int count; int next; struct acl acl[1]; } *SMB_ACL_T; typedef struct acl *SMB_ACL_ENTRY_T; #define SMB_ACL_FIRST_ENTRY 0 #define SMB_ACL_NEXT_ENTRY 1 #define SMB_ACL_TYPE_ACCESS 0 #define SMB_ACL_TYPE_DEFAULT 1 #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #ifdef __CYGWIN__ #define SMB_ACL_LOSES_SPECIAL_MODE_BITS #endif #elif defined HAVE_HPUX_ACLS /*----------------------------------------------*/ /* Based on the Solaris & UnixWare code. */ #ifndef __TANDEM #undef GROUP #endif #include /* SVR4.2 ES/MP ACLs */ typedef int SMB_ACL_TAG_T; typedef int SMB_ACL_TYPE_T; /* Types of ACLs. */ #define SMB_ACL_USER USER #define SMB_ACL_USER_OBJ USER_OBJ #define SMB_ACL_GROUP GROUP #define SMB_ACL_GROUP_OBJ GROUP_OBJ #define SMB_ACL_OTHER OTHER_OBJ #define SMB_ACL_MASK CLASS_OBJ typedef struct SMB_ACL_T { int size; int count; int next; struct acl acl[1]; } *SMB_ACL_T; typedef struct acl *SMB_ACL_ENTRY_T; #define SMB_ACL_FIRST_ENTRY 0 #define SMB_ACL_NEXT_ENTRY 1 #define SMB_ACL_TYPE_ACCESS 0 #define SMB_ACL_TYPE_DEFAULT 1 #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #elif defined HAVE_IRIX_ACLS /*----------------------------------------------*/ /* IRIX ACLs */ #define SMB_ACL_TAG_T acl_tag_t #define SMB_ACL_TYPE_T acl_type_t /* Types of ACLs. */ #define SMB_ACL_USER ACL_USER #define SMB_ACL_USER_OBJ ACL_USER_OBJ #define SMB_ACL_GROUP ACL_GROUP #define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ #define SMB_ACL_OTHER ACL_OTHER_OBJ #define SMB_ACL_MASK ACL_MASK typedef struct SMB_ACL_T { int next; BOOL freeaclp; struct acl *aclp; } *SMB_ACL_T; #define SMB_ACL_ENTRY_T acl_entry_t #define SMB_ACL_FIRST_ENTRY 0 #define SMB_ACL_NEXT_ENTRY 1 #define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS #define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #elif defined HAVE_AIX_ACLS /*-----------------------------------------------*/ /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */ #include "/usr/include/acl.h" struct acl_entry_link{ struct acl_entry_link *prevp; struct new_acl_entry *entryp; struct acl_entry_link *nextp; int count; }; struct new_acl_entry{ unsigned short ace_len; unsigned short ace_type; unsigned int ace_access; struct ace_id ace_id[1]; }; #define SMB_ACL_ENTRY_T struct new_acl_entry* #define SMB_ACL_T struct acl_entry_link* #define SMB_ACL_TAG_T unsigned short #define SMB_ACL_TYPE_T int /* Types of ACLs. */ #define SMB_ACL_USER ACEID_USER #define SMB_ACL_USER_OBJ 3 #define SMB_ACL_GROUP ACEID_GROUP #define SMB_ACL_GROUP_OBJ 4 #define SMB_ACL_OTHER 5 #define SMB_ACL_MASK 6 #define SMB_ACL_FIRST_ENTRY 1 #define SMB_ACL_NEXT_ENTRY 2 #define SMB_ACL_TYPE_ACCESS 0 #define SMB_ACL_TYPE_DEFAULT 1 #define SMB_ACL_VALID_NAME_BITS (4 | 2 | 1) #define SMB_ACL_VALID_OBJ_BITS (4 | 2 | 1) #define SMB_ACL_NEED_SORT #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/ /* Special handling for OS X ACLs */ #define SMB_ACL_TAG_T acl_tag_t #define SMB_ACL_TYPE_T acl_type_t #define SMB_ACL_T acl_t #define SMB_ACL_ENTRY_T acl_entry_t #define SMB_ACL_USER 1 #define SMB_ACL_GROUP 2 #define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY #define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY #define SMB_ACL_TYPE_ACCESS ACL_TYPE_EXTENDED #define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT #define SMB_ACL_VALID_NAME_BITS ((1<<25)-1) #define SMB_ACL_VALID_OBJ_BITS 0 /*#undef SMB_ACL_NEED_SORT*/ #else /*---------------------------------------------------------------------*/ /* Unknown platform. */ #error Cannot handle ACLs on this platform! #endif int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p); int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p); int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p); SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type); SMB_ACL_T sys_acl_get_fd(int fd); SMB_ACL_T sys_acl_init(int count); int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry); int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype, uint32 bits, id_t u_g_id); int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits); int sys_acl_valid(SMB_ACL_T theacl); int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl); int sys_acl_set_fd(int fd, SMB_ACL_T theacl); int sys_acl_delete_def_file(const char *name); int sys_acl_free_acl(SMB_ACL_T the_acl); int no_acl_syscall_error(int err); #endif /* SUPPORT_ACLS */ rsync-3.2.7/usage.c0000664000000000000000000002213314324366276012647 0ustar rootroot/* * Some usage & version related functions. * * Copyright (C) 2002-2022 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 "version.h" #include "latest-year.h" #include "git-version.h" #include "default-cvsignore.h" #include "itypes.h" extern struct name_num_obj valid_checksums, valid_compressions, valid_auth_checksums; static char *istring(const char *fmt, int val) { char *str; if (asprintf(&str, fmt, val) < 0) out_of_memory("istring"); return str; } static void print_info_flags(enum logcode f) { STRUCT_STAT *dumstat; BOOL as_json = f == FNONE ? 1 : 0; /* We use 1 == first attribute, 2 == need closing array */ char line_buf[75], item_buf[32]; int line_len, j; char *info_flags[] = { "*Capabilities", istring("%d-bit files", (int)(sizeof (OFF_T) * 8)), istring("%d-bit inums", (int)(sizeof dumstat->st_ino * 8)), /* Don't check ino_t! */ istring("%d-bit timestamps", (int)(sizeof (time_t) * 8)), istring("%d-bit long ints", (int)(sizeof (int64) * 8)), #ifndef HAVE_SOCKETPAIR "no " #endif "socketpairs", #ifndef SUPPORT_LINKS "no " #endif "symlinks", #ifndef CAN_SET_SYMLINK_TIMES "no " #endif "symtimes", #ifndef SUPPORT_HARD_LINKS "no " #endif "hardlinks", #ifndef CAN_HARDLINK_SPECIAL "no " #endif "hardlink-specials", #ifndef CAN_HARDLINK_SYMLINK "no " #endif "hardlink-symlinks", #ifndef INET6 "no " #endif "IPv6", #ifndef SUPPORT_ATIMES "no " #endif "atimes", "batchfiles", #ifndef HAVE_FTRUNCATE "no " #endif "inplace", #ifndef HAVE_FTRUNCATE "no " #endif "append", #ifndef SUPPORT_ACLS "no " #endif "ACLs", #ifndef SUPPORT_XATTRS "no " #endif "xattrs", #ifdef RSYNC_USE_SECLUDED_ARGS "default " #else "optional " #endif "secluded-args", #ifndef ICONV_OPTION "no " #endif "iconv", #ifndef SUPPORT_PREALLOCATION "no " #endif "prealloc", #ifndef HAVE_MKTIME "no " #endif "stop-at", #ifndef SUPPORT_CRTIMES "no " #endif "crtimes", "*Optimizations", #ifndef USE_ROLL_SIMD "no " #endif "SIMD-roll", #ifndef USE_ROLL_ASM "no " #endif "asm-roll", #ifndef USE_OPENSSL "no " #endif "openssl-crypto", #ifndef USE_MD5_ASM "no " #endif "asm-MD5", NULL }; for (line_len = 0, j = 0; ; j++) { char *str = info_flags[j], *next_nfo = str ? info_flags[j+1] : NULL; int need_comma = next_nfo && *next_nfo != '*' ? 1 : 0; int item_len; if (!str || *str == '*') item_len = 1000; else if (as_json) { char *space = strchr(str, ' '); int is_no = space && strncmp(str, "no ", 3) == 0; int is_bits = space && isDigit(str); char *quot = space && !is_no && !is_bits ? "\"" : ""; char *item = space ? space + 1 : str; char *val = !space ? "true" : is_no ? "false" : str; int val_len = !space ? 4 : is_no ? 5 : space - str; if (is_bits && (space = strchr(val, '-')) != NULL) val_len = space - str; item_len = snprintf(item_buf, sizeof item_buf, " \"%s%s\": %s%.*s%s%s", item, is_bits ? "bits" : "", quot, val_len, val, quot, need_comma ? "," : ""); if (is_bits) item_buf[strlen(item)+2-1] = '_'; /* Turn the 's' into a '_' */ for (space = item; (space = strpbrk(space, " -")) != NULL; space++) item_buf[space - item + 2] = '_'; } else item_len = snprintf(item_buf, sizeof item_buf, " %s%s", str, need_comma ? "," : ""); if (line_len && line_len + item_len >= (int)sizeof line_buf) { if (as_json) printf(" %s\n", line_buf); else rprintf(f, " %s\n", line_buf); line_len = 0; } if (!str) break; if (*str == '*') { if (as_json) { if (as_json == 2) printf(" }"); else as_json = 2; printf(",\n \"%c%s\": {\n", toLower(str+1), str+2); } else rprintf(f, "%s:\n", str+1); } else { strlcpy(line_buf + line_len, item_buf, sizeof line_buf - line_len); line_len += item_len; } } if (as_json == 2) printf(" }"); } static void output_nno_list(enum logcode f, const char *name, struct name_num_obj *nno) { char namebuf[64], tmpbuf[256]; char *tok, *next_tok, *comma = ","; char *cp; /* Using '(' ensures that we get a trailing "none" but also includes aliases. */ get_default_nno_list(nno, tmpbuf, sizeof tmpbuf - 1, '('); if (f != FNONE) { rprintf(f, "%s:\n", name); rprintf(f, " %s\n", tmpbuf); return; } strlcpy(namebuf, name, sizeof namebuf); for (cp = namebuf; *cp; cp++) { if (*cp == ' ') *cp = '_'; else if (isUpper(cp)) *cp = toLower(cp); } printf(",\n \"%s\": [\n ", namebuf); for (tok = strtok(tmpbuf, " "); tok; tok = next_tok) { next_tok = strtok(NULL, " "); if (*tok != '(') /* Ignore the alises in the JSON output */ printf(" \"%s\"%s", tok, comma + (next_tok ? 0 : 1)); } printf("\n ]"); } /* A request of f == FNONE wants json on stdout. */ void print_rsync_version(enum logcode f) { char copyright[] = "(C) 1996-" LATEST_YEAR " by Andrew Tridgell, Wayne Davison, and others."; char url[] = "https://rsync.samba.org/"; BOOL first_line = 1; #define json_line(name, value) \ do { \ printf("%c\n \"%s\": \"%s\"", first_line ? '{' : ',', name, value); \ first_line = 0; \ } while (0) if (f == FNONE) { char verbuf[32]; json_line("program", RSYNC_NAME); json_line("version", rsync_version()); (void)snprintf(verbuf, sizeof verbuf, "%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION); json_line("protocol", verbuf); json_line("copyright", copyright); json_line("url", url); } else { #if SUBPROTOCOL_VERSION != 0 char *subprotocol = istring(".PR%d", SUBPROTOCOL_VERSION); #else char *subprotocol = ""; #endif rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol); rprintf(f, "Copyright %s\n", copyright); rprintf(f, "Web site: %s\n", url); } print_info_flags(f); init_checksum_choices(); output_nno_list(f, "Checksum list", &valid_checksums); output_nno_list(f, "Compress list", &valid_compressions); output_nno_list(f, "Daemon auth list", &valid_auth_checksums); if (f == FNONE) { json_line("license", "GPLv3"); json_line("caveat", "rsync comes with ABSOLUTELY NO WARRANTY"); printf("\n}\n"); return; } #ifdef MAINTAINER_MODE rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); #endif #if SIZEOF_INT64 < 8 rprintf(f, "WARNING: no 64-bit integers on this platform!\n"); #endif if (sizeof (int64) != SIZEOF_INT64) { rprintf(f, "WARNING: size mismatch in SIZEOF_INT64 define (%d != %d)\n", (int) SIZEOF_INT64, (int) sizeof (int64)); } rprintf(f,"\n"); rprintf(f,"rsync comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"); rprintf(f,"are welcome to redistribute it under certain conditions. See the GNU\n"); rprintf(f,"General Public Licence for details.\n"); } void usage(enum logcode F) { print_rsync_version(F); rprintf(F,"\n"); rprintf(F,"rsync is a file transfer program capable of efficient remote update\n"); rprintf(F,"via a fast differencing algorithm.\n"); rprintf(F,"\n"); rprintf(F,"Usage: rsync [OPTION]... SRC [SRC]... DEST\n"); rprintf(F," or rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST\n"); rprintf(F," or rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST\n"); rprintf(F," or rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST\n"); rprintf(F," or rsync [OPTION]... [USER@]HOST:SRC [DEST]\n"); rprintf(F," or rsync [OPTION]... [USER@]HOST::SRC [DEST]\n"); rprintf(F," or rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]\n"); rprintf(F,"The ':' usages connect via remote shell, while '::' & 'rsync://' usages connect\n"); rprintf(F,"to an rsync daemon, and require SRC or DEST to start with a module name.\n"); rprintf(F,"\n"); rprintf(F,"Options\n"); #include "help-rsync.h" rprintf(F,"\n"); rprintf(F,"Use \"rsync --daemon --help\" to see the daemon-mode command-line options.\n"); rprintf(F,"Please see the rsync(1) and rsyncd.conf(5) manpages for full documentation.\n"); rprintf(F,"See https://rsync.samba.org/ for updates, bug reports, and answers\n"); } void daemon_usage(enum logcode F) { print_rsync_version(F); rprintf(F,"\n"); rprintf(F,"Usage: rsync --daemon [OPTION]...\n"); #include "help-rsyncd.h" rprintf(F,"\n"); rprintf(F,"If you were not trying to invoke rsync as a daemon, avoid using any of the\n"); rprintf(F,"daemon-specific rsync options. See also the rsyncd.conf(5) manpage.\n"); } const char *rsync_version(void) { char *ver; #ifdef RSYNC_GITVER ver = RSYNC_GITVER; #else ver = RSYNC_VERSION; #endif return *ver == 'v' ? ver+1 : ver; } const char *default_cvsignore(void) { return DEFAULT_CVSIGNORE; } rsync-3.2.7/m4/0000775000000000000000000000000014324367162011711 5ustar rootrootrsync-3.2.7/m4/socklen_t.m40000664000000000000000000000312212704751766014141 0ustar rootrootdnl Check for socklen_t: historically on BSD it is an int, and in dnl POSIX 1g it is a type of its own, but some platforms use different dnl types for the argument to getsockopt, getpeername, etc. So we dnl have to test to find something that will work. dnl This is no good, because passing the wrong pointer on C compilers is dnl likely to only generate a warning, not an error. We don't call this at dnl the moment. AC_DEFUN([TYPE_SOCKLEN_T], [ AC_CHECK_TYPE([socklen_t], ,[ AC_MSG_CHECKING([for socklen_t equivalent]) AC_CACHE_VAL([rsync_cv_socklen_t_equiv], [ # Systems have either "struct sockaddr *" or # "void *" as the second argument to getpeername rsync_cv_socklen_t_equiv= for arg2 in "struct sockaddr" void; do for t in int size_t unsigned long "unsigned long"; do AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include int getpeername (int, $arg2 *, $t *); ]],[[ $t len; getpeername(0,0,&len); ]])],[ rsync_cv_socklen_t_equiv="$t" break ]) done done if test "x$rsync_cv_socklen_t_equiv" = x; then AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) fi ]) AC_MSG_RESULT($rsync_cv_socklen_t_equiv) AC_DEFINE_UNQUOTED(socklen_t, $rsync_cv_socklen_t_equiv, [type to use in place of socklen_t if not defined])], [#include #include ]) ]) rsync-3.2.7/m4/header_major_fixed.m40000664000000000000000000000153513643177546015766 0ustar rootrootAC_DEFUN([AC_HEADER_MAJOR_FIXED], [AC_CACHE_CHECK(whether sys/types.h defines makedev, ac_cv_header_sys_types_h_makedev, [AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], [[return makedev(0, 0);]])], [if grep sys/sysmacros.h conftest.err >/dev/null; then ac_cv_header_sys_types_h_makedev=no else ac_cv_header_sys_types_h_makedev=yes fi], [ac_cv_header_sys_types_h_makedev=no]) ]) if test $ac_cv_header_sys_types_h_makedev = no; then AC_CHECK_HEADER(sys/mkdev.h, [AC_DEFINE(MAJOR_IN_MKDEV, 1, [Define to 1 if `major', `minor', and `makedev' are declared in .])]) if test $ac_cv_header_sys_mkdev_h = no; then AC_CHECK_HEADER(sys/sysmacros.h, [AC_DEFINE(MAJOR_IN_SYSMACROS, 1, [Define to 1 if `major', `minor', and `makedev' are declared in .])]) fi fi ]) rsync-3.2.7/m4/validate_cache_system_type.m40000664000000000000000000000167712517304256017544 0ustar rootrootdnl AC_VALIDATE_CACHE_SYSTEM_TYPE[(cmd)] dnl if the cache file is inconsistent with the current host, dnl target and build system types, execute CMD or print a default dnl error message. AC_DEFUN([AC_VALIDATE_CACHE_SYSTEM_TYPE], [ AC_REQUIRE([AC_CANONICAL_SYSTEM]) AC_MSG_CHECKING([config.cache system type]) if { test x"${ac_cv_host_system_type+set}" = x"set" && test x"$ac_cv_host_system_type" != x"$host"; } || { test x"${ac_cv_build_system_type+set}" = x"set" && test x"$ac_cv_build_system_type" != x"$build"; } || { test x"${ac_cv_target_system_type+set}" = x"set" && test x"$ac_cv_target_system_type" != x"$target"; }; then AC_MSG_RESULT([different]) ifelse($#, 1, [$1], [AC_MSG_ERROR(["you must remove config.cache and restart configure"])]) else AC_MSG_RESULT([same]) fi ac_cv_host_system_type="$host" ac_cv_build_system_type="$build" ac_cv_target_system_type="$target" ]) rsync-3.2.7/m4/have_type.m40000664000000000000000000000112214323037532014125 0ustar rootrootdnl AC_HAVE_TYPE(TYPE,INCLUDES) AC_DEFUN([AC_HAVE_TYPE], [ cv=`echo "$1" | sed 'y%./+- %__p__%'` AC_MSG_CHECKING(for $1) AC_CACHE_VAL([ac_cv_type_$cv], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ AC_INCLUDES_DEFAULT $2]], [[$1 foo;]])], [eval "ac_cv_type_$cv=yes"], [eval "ac_cv_type_$cv=no"]))dnl ac_foo=`eval echo \\$ac_cv_type_$cv` AC_MSG_RESULT($ac_foo) if test "$ac_foo" = yes; then ac_tr_hdr=HAVE_`echo $1 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'` if false; then AC_CHECK_TYPES($1) fi AC_DEFINE_UNQUOTED($ac_tr_hdr, 1, [Define if you have type `$1']) fi ]) rsync-3.2.7/simd-checksum-x86_64.cpp0000664000000000000000000005756314210262311015565 0ustar rootroot/* * SSE2/SSSE3/AVX2-optimized routines to support checksumming of bytes. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2004-2020 Wayne Davison * Copyright (C) 2020 Jorrit Jongma * * 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. */ /* * Optimization target for get_checksum1() was the Intel Atom D2700, the * slowest CPU in the test set and the most likely to be CPU limited during * transfers. The combination of intrinsics was chosen specifically for the * most gain on that CPU, other combinations were occasionally slightly * faster on the others. * * While on more modern CPUs transfers are less likely to be CPU limited * (at least by this specific function), lower CPU usage is always better. * Improvements may still be seen when matching chunks from NVMe storage * even on newer CPUs. * * Benchmarks (in MB/s) C SSE2 SSSE3 AVX2 * - Intel Atom D2700 550 750 1000 N/A * - Intel i7-7700hq 1850 2550 4050 6200 * - AMD ThreadRipper 2950x 2900 5600 8950 8100 * * Curiously the AMD is slower with AVX2 than SSSE3, while the Intel is * significantly faster. AVX2 is kept because it's more likely to relieve * the bottleneck on the slower CPU. * * This optimization for get_checksum1() is intentionally limited to x86-64 * as no 32-bit CPU was available for testing. As 32-bit CPUs only have half * the available xmm registers, this optimized version may not be faster than * the pure C version anyway. Note that all x86-64 CPUs support at least SSE2. * * This file is compiled using GCC 4.8+/clang 6+'s C++ front end to allow the * use of the target attribute, selecting the fastest code path based on * dispatch priority (GCC 5) or runtime detection of CPU capabilities (GCC 6+). * GCC 4.x are not supported to ease configure.ac logic. */ #ifdef __x86_64__ /* { */ #ifdef __cplusplus /* { */ #include "rsync.h" #ifdef USE_ROLL_SIMD /* { */ #include /* Some clang versions don't like it when you use static with multi-versioned functions: linker errors */ #ifdef __clang__ #define MVSTATIC #else #define MVSTATIC static #endif // Missing from the headers on gcc 6 and older, clang 8 and older typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(1))); /* Compatibility macros to let our SSSE3 algorithm run with only SSE2. These used to be neat individual functions with target attributes switching between SSE2 and SSSE3 implementations as needed, but though this works perfectly with GCC, clang fails to inline those properly leading to a near 50% performance drop - combined with static and inline modifiers gets you linker errors and even compiler crashes... */ #define SSE2_INTERLEAVE_ODD_EPI16(a, b) _mm_packs_epi32(_mm_srai_epi32(a, 16), _mm_srai_epi32(b, 16)) #define SSE2_INTERLEAVE_EVEN_EPI16(a, b) SSE2_INTERLEAVE_ODD_EPI16(_mm_slli_si128(a, 2), _mm_slli_si128(b, 2)) #define SSE2_MULU_ODD_EPI8(a, b) _mm_mullo_epi16(_mm_srli_epi16(a, 8), _mm_srai_epi16(b, 8)) #define SSE2_MULU_EVEN_EPI8(a, b) _mm_mullo_epi16(_mm_and_si128(a, _mm_set1_epi16(0xFF)), _mm_srai_epi16(_mm_slli_si128(b, 1), 8)) #define SSE2_HADDS_EPI16(a, b) _mm_adds_epi16(SSE2_INTERLEAVE_EVEN_EPI16(a, b), SSE2_INTERLEAVE_ODD_EPI16(a, b)) #define SSE2_MADDUBS_EPI16(a, b) _mm_adds_epi16(SSE2_MULU_EVEN_EPI8(a, b), SSE2_MULU_ODD_EPI8(a, b)) #ifndef USE_ROLL_ASM __attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_avx2_64(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; } #endif __attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_ssse3_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; } __attribute__ ((target("default"))) MVSTATIC int32 get_checksum1_sse2_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { return i; } /* Original loop per 4 bytes: s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET; s1 += buf[i] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET; SSE2/SSSE3 loop per 32 bytes: int16 t1[8]; int16 t2[8]; for (int j = 0; j < 8; j++) { t1[j] = buf[j*4 + i] + buf[j*4 + i+1] + buf[j*4 + i+2] + buf[j*4 + i+3]; t2[j] = 4*buf[j*4 + i] + 3*buf[j*4 + i+1] + 2*buf[j*4 + i+2] + buf[j*4 + i+3]; } s2 += 32*s1 + (uint32)( 28*t1[0] + 24*t1[1] + 20*t1[2] + 16*t1[3] + 12*t1[4] + 8*t1[5] + 4*t1[6] + t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] ) + 528*CHAR_OFFSET; s1 += (uint32)(t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7]) + 32*CHAR_OFFSET; */ __attribute__ ((target("ssse3"))) MVSTATIC int32 get_checksum1_ssse3_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { if (len > 32) { int aligned = ((uintptr_t)buf & 15) == 0; uint32 x[4] = {0}; x[0] = *ps1; __m128i ss1 = _mm_loadu_si128((__m128i_u*)x); x[0] = *ps2; __m128i ss2 = _mm_loadu_si128((__m128i_u*)x); const int16 mul_t1_buf[8] = {28, 24, 20, 16, 12, 8, 4, 0}; __m128i mul_t1 = _mm_loadu_si128((__m128i_u*)mul_t1_buf); for (; i < (len-32); i+=32) { // Load ... 2*[int8*16] __m128i in8_1, in8_2; if (!aligned) { // Synonymous with _mm_loadu_si128 on all but a handful of old CPUs in8_1 = _mm_lddqu_si128((__m128i_u*)&buf[i]); in8_2 = _mm_lddqu_si128((__m128i_u*)&buf[i + 16]); } else { in8_1 = _mm_load_si128((__m128i_u*)&buf[i]); in8_2 = _mm_load_si128((__m128i_u*)&buf[i + 16]); } // (1*buf[i] + 1*buf[i+1]), (1*buf[i+2], 1*buf[i+3]), ... 2*[int16*8] // Fastest, even though multiply by 1 __m128i mul_one = _mm_set1_epi8(1); __m128i add16_1 = _mm_maddubs_epi16(mul_one, in8_1); __m128i add16_2 = _mm_maddubs_epi16(mul_one, in8_2); // (4*buf[i] + 3*buf[i+1]), (2*buf[i+2], buf[i+3]), ... 2*[int16*8] __m128i mul_const = _mm_set1_epi32(4 + (3 << 8) + (2 << 16) + (1 << 24)); __m128i mul_add16_1 = _mm_maddubs_epi16(mul_const, in8_1); __m128i mul_add16_2 = _mm_maddubs_epi16(mul_const, in8_2); // s2 += 32*s1 ss2 = _mm_add_epi32(ss2, _mm_slli_epi32(ss1, 5)); // [sum(t1[0]..t1[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 // Shifting left, then shifting right again and shuffling (rather than just // shifting right as with mul32 below) to cheaply end up with the correct sign // extension as we go from int16 to int32. __m128i sum_add32 = _mm_add_epi16(add16_1, add16_2); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 2)); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 4)); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 8)); sum_add32 = _mm_srai_epi32(sum_add32, 16); sum_add32 = _mm_shuffle_epi32(sum_add32, 3); // [sum(t2[0]..t2[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 __m128i sum_mul_add32 = _mm_add_epi16(mul_add16_1, mul_add16_2); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 2)); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 4)); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 8)); sum_mul_add32 = _mm_srai_epi32(sum_mul_add32, 16); sum_mul_add32 = _mm_shuffle_epi32(sum_mul_add32, 3); // s1 += t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7] ss1 = _mm_add_epi32(ss1, sum_add32); // s2 += t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] ss2 = _mm_add_epi32(ss2, sum_mul_add32); // [t1[0] + t1[1], t1[2] + t1[3] ...] [int16*8] // We could've combined this with generating sum_add32 above and // save an instruction but benchmarking shows that as being slower __m128i add16 = _mm_hadds_epi16(add16_1, add16_2); // [t1[0], t1[1], ...] -> [t1[0]*28 + t1[1]*24, ...] [int32*4] __m128i mul32 = _mm_madd_epi16(add16, mul_t1); // [sum(mul32), X, X, X] [int32*4]; faster than multiple _mm_hadd_epi32 mul32 = _mm_add_epi32(mul32, _mm_srli_si128(mul32, 4)); mul32 = _mm_add_epi32(mul32, _mm_srli_si128(mul32, 8)); // s2 += 28*t1[0] + 24*t1[1] + 20*t1[2] + 16*t1[3] + 12*t1[4] + 8*t1[5] + 4*t1[6] ss2 = _mm_add_epi32(ss2, mul32); #if CHAR_OFFSET != 0 // s1 += 32*CHAR_OFFSET __m128i char_offset_multiplier = _mm_set1_epi32(32 * CHAR_OFFSET); ss1 = _mm_add_epi32(ss1, char_offset_multiplier); // s2 += 528*CHAR_OFFSET char_offset_multiplier = _mm_set1_epi32(528 * CHAR_OFFSET); ss2 = _mm_add_epi32(ss2, char_offset_multiplier); #endif } _mm_store_si128((__m128i_u*)x, ss1); *ps1 = x[0]; _mm_store_si128((__m128i_u*)x, ss2); *ps2 = x[0]; } return i; } /* Same as SSSE3 version, but using macros defined above to emulate SSSE3 calls that are not available with SSE2. For GCC-only the SSE2 and SSSE3 versions could be a single function calling other functions with the right target attributes to emulate SSSE3 calls on SSE2 if needed, but clang doesn't inline those properly leading to a near 50% performance drop. */ __attribute__ ((target("sse2"))) MVSTATIC int32 get_checksum1_sse2_32(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { if (len > 32) { int aligned = ((uintptr_t)buf & 15) == 0; uint32 x[4] = {0}; x[0] = *ps1; __m128i ss1 = _mm_loadu_si128((__m128i_u*)x); x[0] = *ps2; __m128i ss2 = _mm_loadu_si128((__m128i_u*)x); const int16 mul_t1_buf[8] = {28, 24, 20, 16, 12, 8, 4, 0}; __m128i mul_t1 = _mm_loadu_si128((__m128i_u*)mul_t1_buf); for (; i < (len-32); i+=32) { // Load ... 2*[int8*16] __m128i in8_1, in8_2; if (!aligned) { in8_1 = _mm_loadu_si128((__m128i_u*)&buf[i]); in8_2 = _mm_loadu_si128((__m128i_u*)&buf[i + 16]); } else { in8_1 = _mm_load_si128((__m128i_u*)&buf[i]); in8_2 = _mm_load_si128((__m128i_u*)&buf[i + 16]); } // (1*buf[i] + 1*buf[i+1]), (1*buf[i+2], 1*buf[i+3]), ... 2*[int16*8] // Fastest, even though multiply by 1 __m128i mul_one = _mm_set1_epi8(1); __m128i add16_1 = SSE2_MADDUBS_EPI16(mul_one, in8_1); __m128i add16_2 = SSE2_MADDUBS_EPI16(mul_one, in8_2); // (4*buf[i] + 3*buf[i+1]), (2*buf[i+2], buf[i+3]), ... 2*[int16*8] __m128i mul_const = _mm_set1_epi32(4 + (3 << 8) + (2 << 16) + (1 << 24)); __m128i mul_add16_1 = SSE2_MADDUBS_EPI16(mul_const, in8_1); __m128i mul_add16_2 = SSE2_MADDUBS_EPI16(mul_const, in8_2); // s2 += 32*s1 ss2 = _mm_add_epi32(ss2, _mm_slli_epi32(ss1, 5)); // [sum(t1[0]..t1[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 // Shifting left, then shifting right again and shuffling (rather than just // shifting right as with mul32 below) to cheaply end up with the correct sign // extension as we go from int16 to int32. __m128i sum_add32 = _mm_add_epi16(add16_1, add16_2); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 2)); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 4)); sum_add32 = _mm_add_epi16(sum_add32, _mm_slli_si128(sum_add32, 8)); sum_add32 = _mm_srai_epi32(sum_add32, 16); sum_add32 = _mm_shuffle_epi32(sum_add32, 3); // [sum(t2[0]..t2[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 __m128i sum_mul_add32 = _mm_add_epi16(mul_add16_1, mul_add16_2); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 2)); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 4)); sum_mul_add32 = _mm_add_epi16(sum_mul_add32, _mm_slli_si128(sum_mul_add32, 8)); sum_mul_add32 = _mm_srai_epi32(sum_mul_add32, 16); sum_mul_add32 = _mm_shuffle_epi32(sum_mul_add32, 3); // s1 += t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7] ss1 = _mm_add_epi32(ss1, sum_add32); // s2 += t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] ss2 = _mm_add_epi32(ss2, sum_mul_add32); // [t1[0] + t1[1], t1[2] + t1[3] ...] [int16*8] // We could've combined this with generating sum_add32 above and // save an instruction but benchmarking shows that as being slower __m128i add16 = SSE2_HADDS_EPI16(add16_1, add16_2); // [t1[0], t1[1], ...] -> [t1[0]*28 + t1[1]*24, ...] [int32*4] __m128i mul32 = _mm_madd_epi16(add16, mul_t1); // [sum(mul32), X, X, X] [int32*4]; faster than multiple _mm_hadd_epi32 mul32 = _mm_add_epi32(mul32, _mm_srli_si128(mul32, 4)); mul32 = _mm_add_epi32(mul32, _mm_srli_si128(mul32, 8)); // s2 += 28*t1[0] + 24*t1[1] + 20*t1[2] + 16*t1[3] + 12*t1[4] + 8*t1[5] + 4*t1[6] ss2 = _mm_add_epi32(ss2, mul32); #if CHAR_OFFSET != 0 // s1 += 32*CHAR_OFFSET __m128i char_offset_multiplier = _mm_set1_epi32(32 * CHAR_OFFSET); ss1 = _mm_add_epi32(ss1, char_offset_multiplier); // s2 += 528*CHAR_OFFSET char_offset_multiplier = _mm_set1_epi32(528 * CHAR_OFFSET); ss2 = _mm_add_epi32(ss2, char_offset_multiplier); #endif } _mm_store_si128((__m128i_u*)x, ss1); *ps1 = x[0]; _mm_store_si128((__m128i_u*)x, ss2); *ps2 = x[0]; } return i; } #ifdef USE_ROLL_ASM /* { */ extern "C" __attribute__ ((target("avx2"))) int32 get_checksum1_avx2_asm(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2); #else /* } { */ /* AVX2 loop per 64 bytes: int16 t1[16]; int16 t2[16]; for (int j = 0; j < 16; j++) { t1[j] = buf[j*4 + i] + buf[j*4 + i+1] + buf[j*4 + i+2] + buf[j*4 + i+3]; t2[j] = 4*buf[j*4 + i] + 3*buf[j*4 + i+1] + 2*buf[j*4 + i+2] + buf[j*4 + i+3]; } s2 += 64*s1 + (uint32)( 60*t1[0] + 56*t1[1] + 52*t1[2] + 48*t1[3] + 44*t1[4] + 40*t1[5] + 36*t1[6] + 32*t1[7] + 28*t1[8] + 24*t1[9] + 20*t1[10] + 16*t1[11] + 12*t1[12] + 8*t1[13] + 4*t1[14] + t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] + t2[8] + t2[9] + t2[10] + t2[11] + t2[12] + t2[13] + t2[14] + t2[15] ) + 2080*CHAR_OFFSET; s1 += (uint32)(t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7] + t1[8] + t1[9] + t1[10] + t1[11] + t1[12] + t1[13] + t1[14] + t1[15]) + 64*CHAR_OFFSET; */ __attribute__ ((target("avx2"))) MVSTATIC int32 get_checksum1_avx2_64(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { if (len > 64) { uint32 x[4] = {0}; __m128i ss1 = _mm_cvtsi32_si128(*ps1); __m128i ss2 = _mm_cvtsi32_si128(*ps2); const char mul_t1_buf[16] = {60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0}; __m128i tmp = _mm_load_si128((__m128i*) mul_t1_buf); __m256i mul_t1 = _mm256_cvtepu8_epi16(tmp); __m256i mul_const = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(4 | (3 << 8) | (2 << 16) | (1 << 24))); __m256i mul_one; mul_one = _mm256_abs_epi8(_mm256_cmpeq_epi16(mul_one,mul_one)); // set all vector elements to 1 for (; i < (len-64); i+=64) { // Load ... 4*[int8*16] __m256i in8_1, in8_2; __m128i in8_1_low, in8_2_low, in8_1_high, in8_2_high; in8_1_low = _mm_loadu_si128((__m128i_u*)&buf[i]); in8_2_low = _mm_loadu_si128((__m128i_u*)&buf[i+16]); in8_1_high = _mm_loadu_si128((__m128i_u*)&buf[i+32]); in8_2_high = _mm_loadu_si128((__m128i_u*)&buf[i+48]); in8_1 = _mm256_inserti128_si256(_mm256_castsi128_si256(in8_1_low), in8_1_high,1); in8_2 = _mm256_inserti128_si256(_mm256_castsi128_si256(in8_2_low), in8_2_high,1); // (1*buf[i] + 1*buf[i+1]), (1*buf[i+2], 1*buf[i+3]), ... 2*[int16*8] // Fastest, even though multiply by 1 __m256i add16_1 = _mm256_maddubs_epi16(mul_one, in8_1); __m256i add16_2 = _mm256_maddubs_epi16(mul_one, in8_2); // (4*buf[i] + 3*buf[i+1]), (2*buf[i+2], buf[i+3]), ... 2*[int16*8] __m256i mul_add16_1 = _mm256_maddubs_epi16(mul_const, in8_1); __m256i mul_add16_2 = _mm256_maddubs_epi16(mul_const, in8_2); // s2 += 64*s1 ss2 = _mm_add_epi32(ss2, _mm_slli_epi32(ss1, 6)); // [sum(t1[0]..t1[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 __m256i sum_add32 = _mm256_add_epi16(add16_1, add16_2); sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_epi32(sum_add32, 16)); sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_si256(sum_add32, 4)); sum_add32 = _mm256_add_epi16(sum_add32, _mm256_srli_si256(sum_add32, 8)); // [sum(t2[0]..t2[7]), X, X, X] [int32*4]; faster than multiple _mm_hadds_epi16 __m256i sum_mul_add32 = _mm256_add_epi16(mul_add16_1, mul_add16_2); sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_epi32(sum_mul_add32, 16)); sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_si256(sum_mul_add32, 4)); sum_mul_add32 = _mm256_add_epi16(sum_mul_add32, _mm256_srli_si256(sum_mul_add32, 8)); // s1 += t1[0] + t1[1] + t1[2] + t1[3] + t1[4] + t1[5] + t1[6] + t1[7] __m128i sum_add32_hi = _mm256_extracti128_si256(sum_add32, 0x1); ss1 = _mm_add_epi32(ss1, _mm256_castsi256_si128(sum_add32)); ss1 = _mm_add_epi32(ss1, sum_add32_hi); // s2 += t2[0] + t2[1] + t2[2] + t2[3] + t2[4] + t2[5] + t2[6] + t2[7] __m128i sum_mul_add32_hi = _mm256_extracti128_si256(sum_mul_add32, 0x1); ss2 = _mm_add_epi32(ss2, _mm256_castsi256_si128(sum_mul_add32)); ss2 = _mm_add_epi32(ss2, sum_mul_add32_hi); // [t1[0] + t1[1], t1[2] + t1[3] ...] [int16*8] // We could've combined this with generating sum_add32 above and // save an instruction but benchmarking shows that as being slower __m256i add16 = _mm256_hadds_epi16(add16_1, add16_2); // [t1[0], t1[1], ...] -> [t1[0]*28 + t1[1]*24, ...] [int32*4] __m256i mul32 = _mm256_madd_epi16(add16, mul_t1); // [sum(mul32), X, X, X] [int32*4]; faster than multiple _mm_hadd_epi32 mul32 = _mm256_add_epi32(mul32, _mm256_srli_si256(mul32, 4)); mul32 = _mm256_add_epi32(mul32, _mm256_srli_si256(mul32, 8)); // prefetch 2 cacheline ahead _mm_prefetch(&buf[i + 160], _MM_HINT_T0); // s2 += 28*t1[0] + 24*t1[1] + 20*t1[2] + 16*t1[3] + 12*t1[4] + 8*t1[5] + 4*t1[6] __m128i mul32_hi = _mm256_extracti128_si256(mul32, 0x1); ss2 = _mm_add_epi32(ss2, _mm256_castsi256_si128(mul32)); ss2 = _mm_add_epi32(ss2, mul32_hi); #if CHAR_OFFSET != 0 // s1 += 32*CHAR_OFFSET __m128i char_offset_multiplier = _mm_set1_epi32(32 * CHAR_OFFSET); ss1 = _mm_add_epi32(ss1, char_offset_multiplier); // s2 += 528*CHAR_OFFSET char_offset_multiplier = _mm_set1_epi32(528 * CHAR_OFFSET); ss2 = _mm_add_epi32(ss2, char_offset_multiplier); #endif } _mm_store_si128((__m128i_u*)x, ss1); *ps1 = x[0]; _mm_store_si128((__m128i_u*)x, ss2); *ps2 = x[0]; } return i; } #endif /* } !USE_ROLL_ASM */ static int32 get_checksum1_default_1(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { uint32 s1 = *ps1; uint32 s2 = *ps2; for (; i < (len-4); i+=4) { s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET; s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET); } for (; i < len; i++) { s1 += (buf[i]+CHAR_OFFSET); s2 += s1; } *ps1 = s1; *ps2 = s2; return i; } /* With GCC 10 putting this implementation inside 'extern "C"' causes an assembler error. That worked fine on GCC 5-9 and clang 6-10... */ static inline uint32 get_checksum1_cpp(char *buf1, int32 len) { int32 i = 0; uint32 s1 = 0; uint32 s2 = 0; // multiples of 64 bytes using AVX2 (if available) #ifdef USE_ROLL_ASM i = get_checksum1_avx2_asm((schar*)buf1, len, i, &s1, &s2); #else i = get_checksum1_avx2_64((schar*)buf1, len, i, &s1, &s2); #endif // multiples of 32 bytes using SSSE3 (if available) i = get_checksum1_ssse3_32((schar*)buf1, len, i, &s1, &s2); // multiples of 32 bytes using SSE2 (if available) i = get_checksum1_sse2_32((schar*)buf1, len, i, &s1, &s2); // whatever is left i = get_checksum1_default_1((schar*)buf1, len, i, &s1, &s2); return (s1 & 0xffff) + (s2 << 16); } extern "C" { uint32 get_checksum1(char *buf1, int32 len) { return get_checksum1_cpp(buf1, len); } } // extern "C" #ifdef BENCHMARK_SIMD_CHECKSUM1 #pragma clang optimize off #pragma GCC push_options #pragma GCC optimize ("O0") #define ROUNDS 1024 #define BLOCK_LEN 1024*1024 #ifndef CLOCK_MONOTONIC_RAW #define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC #endif static void benchmark(const char* desc, int32 (*func)(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2), schar* buf, int32 len) { struct timespec start, end; uint64_t us; uint32_t cs, s1, s2; int i, next; clock_gettime(CLOCK_MONOTONIC_RAW, &start); for (i = 0; i < ROUNDS; i++) { s1 = s2 = 0; next = func((schar*)buf, len, 0, &s1, &s2); get_checksum1_default_1((schar*)buf, len, next, &s1, &s2); } clock_gettime(CLOCK_MONOTONIC_RAW, &end); us = next == 0 ? 0 : (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000; cs = next == 0 ? 0 : (s1 & 0xffff) + (s2 << 16); printf("%-5s :: %5.0f MB/s :: %08x\n", desc, us ? (float)(len / (1024 * 1024) * ROUNDS) / ((float)us / 1000000.0f) : 0, cs); } static int32 get_checksum1_auto(schar* buf, int32 len, int32 i, uint32* ps1, uint32* ps2) { uint32 cs = get_checksum1((char*)buf, len); *ps1 = cs & 0xffff; *ps2 = cs >> 16; return len; } int main() { int i; unsigned char* buf = (unsigned char*)aligned_alloc(64,BLOCK_LEN); for (i = 0; i < BLOCK_LEN; i++) buf[i] = (i + (i % 3) + (i % 11)) % 256; benchmark("Auto", get_checksum1_auto, (schar*)buf, BLOCK_LEN); benchmark("Raw-C", get_checksum1_default_1, (schar*)buf, BLOCK_LEN); benchmark("SSE2", get_checksum1_sse2_32, (schar*)buf, BLOCK_LEN); benchmark("SSSE3", get_checksum1_ssse3_32, (schar*)buf, BLOCK_LEN); #ifdef USE_ROLL_ASM benchmark("AVX2-ASM", get_checksum1_avx2_asm, (schar*)buf, BLOCK_LEN); #else benchmark("AVX2", get_checksum1_avx2_64, (schar*)buf, BLOCK_LEN); #endif free(buf); return 0; } #pragma GCC pop_options #pragma clang optimize on #endif /* BENCHMARK_SIMD_CHECKSUM1 */ #endif /* } USE_ROLL_SIMD */ #endif /* } __cplusplus */ #endif /* } __x86_64__ */ rsync-3.2.7/md2man0000777000000000000000000000000014162436405014463 2md-convertustar rootrootrsync-3.2.7/rsyncd.conf.5.md0000664000000000000000000016661514315642342014317 0ustar rootroot## NAME rsyncd.conf - configuration file for rsync in daemon mode ## SYNOPSIS rsyncd.conf The online version of this manpage (that includes cross-linking of topics) is available at . ## DESCRIPTION The rsyncd.conf file is the runtime configuration file for rsync when run as an rsync daemon. The rsyncd.conf file controls authentication, access, logging and available modules. ## FILE FORMAT The file consists of modules and parameters. A module begins with the name of the module in square brackets and continues until the next module begins. Modules contain parameters of the form `name = value`. The file is line-based -- that is, each newline-terminated line represents either a comment, a module name or a parameter. Only the first equals sign in a parameter is significant. Whitespace before or after the first equals sign is discarded. Leading, trailing and internal whitespace in module and parameter names is irrelevant. Leading and trailing whitespace in a parameter value is discarded. Internal whitespace within a parameter value is retained verbatim. Any line **beginning** with a hash (`#`) is ignored, as are lines containing only whitespace. (If a hash occurs after anything other than leading whitespace, it is considered a part of the line's content.) Any line ending in a `\` is "continued" on the next line in the customary UNIX fashion. The values following the equals sign in parameters are all either a string (no quotes needed) or a boolean, which may be given as yes/no, 0/1 or true/false. Case is not significant in boolean values, but is preserved in string values. ## LAUNCHING THE RSYNC DAEMON The rsync daemon is launched by specifying the `--daemon` option to rsync. The daemon must run with root privileges if you wish to use chroot, to bind to a port numbered under 1024 (as is the default 873), or to set file ownership. Otherwise, it must just have permission to read and write the appropriate data, log, and lock files. You can launch it either via inetd, as a stand-alone daemon, or from an rsync client via a remote shell. If run as a stand-alone daemon then just run the command "`rsync --daemon`" from a suitable startup script. When run via inetd you should add a line like this to /etc/services: > rsync 873/tcp and a single line something like this to /etc/inetd.conf: > rsync stream tcp nowait root @BINDIR@/rsync rsyncd --daemon Replace "@BINDIR@/rsync" with the path to where you have rsync installed on your system. You will then need to send inetd a HUP signal to tell it to reread its config file. Note that you should **not** send the rsync daemon a HUP signal to force it to reread the `rsyncd.conf` file. The file is re-read on each client connection. ## GLOBAL PARAMETERS The first parameters in the file (before a [module] header) are the global parameters. Rsync also allows for the use of a "[global]" module name to indicate the start of one or more global-parameter sections (the name must be lower case). You may also include any module parameters in the global part of the config file in which case the supplied value will override the default for that parameter. You may use references to environment variables in the values of parameters. String parameters will have %VAR% references expanded as late as possible (when the string is first used in the program), allowing for the use of variables that rsync sets at connection time, such as RSYNC_USER_NAME. Non-string parameters (such as true/false settings) are expanded when read from the config file. If a variable does not exist in the environment, or if a sequence of characters is not a valid reference (such as an un-paired percent sign), the raw characters are passed through unchanged. This helps with backward compatibility and safety (e.g. expanding a non-existent %VAR% to an empty string in a path could result in a very unsafe path). The safest way to insert a literal % into a value is to use %%. [comment]: # (An OL starting at 0 is converted into a DL by the parser.) 0. `motd file` This parameter allows you to specify a "message of the day" (MOTD) to display to clients on each connect. This usually contains site information and any legal notices. The default is no MOTD file. This can be overridden by the `--dparam=motdfile=FILE` command-line option when starting the daemon. 0. `pid file` This parameter tells the rsync daemon to write its process ID to that file. The rsync keeps the file locked so that it can know when it is safe to overwrite an existing file. The filename can be overridden by the `--dparam=pidfile=FILE` command-line option when starting the daemon. 0. `port` You can override the default port the daemon will listen on by specifying this value (defaults to 873). This is ignored if the daemon is being run by inetd, and is superseded by the `--port` command-line option. 0. `address` You can override the default IP address the daemon will listen on by specifying this value. This is ignored if the daemon is being run by inetd, and is superseded by the `--address` command-line option. 0. `socket options` This parameter can provide endless fun for people who like to tune their systems to the utmost degree. You can set all sorts of socket options which may make transfers faster (or slower!). Read the manpage for the **setsockopt()** system call for details on some of the options you may be able to set. By default no special socket options are set. These settings can also be specified via the `--sockopts` command-line option. 0. `listen backlog` You can override the default backlog value when the daemon listens for connections. It defaults to 5. ## MODULE PARAMETERS After the global parameters you should define a number of modules, each module exports a directory tree as a symbolic name. Modules are exported by specifying a module name in square brackets [module] followed by the parameters for that module. The module name cannot contain a slash or a closing square bracket. If the name contains whitespace, each internal sequence of whitespace will be changed into a single space, while leading or trailing whitespace will be discarded. Also, the name cannot be "global" as that exact name indicates that global parameters follow (see above). As with GLOBAL PARAMETERS, you may use references to environment variables in the values of parameters. See the GLOBAL PARAMETERS section for more details. 0. `comment` This parameter specifies a description string that is displayed next to the module name when clients obtain a list of available modules. The default is no comment. 0. `path` This parameter specifies the directory in the daemon's filesystem to make available in this module. You must specify this parameter for each module in `rsyncd.conf`. If the value contains a "/./" element then the path will be divided at that point into a chroot dir and an inner-chroot subdir. If [`use chroot`](#) is set to false, though, the extraneous dot dir is just cleaned out of the path. An example of this idiom is: > path = /var/rsync/./module1 This will (when chrooting) chroot to "/var/rsync" and set the inside-chroot path to "/module1". You may base the path's value off of an environment variable by surrounding the variable name with percent signs. You can even reference a variable that is set by rsync when the user connects. For example, this would use the authorizing user's name in the path: > path = /home/%RSYNC_USER_NAME% It is fine if the path includes internal spaces -- they will be retained verbatim (which means that you shouldn't try to escape them). If your final directory has a trailing space (and this is somehow not something you wish to fix), append a trailing slash to the path to avoid losing the trailing whitespace. 0. `use chroot` If "use chroot" is true, the rsync daemon will chroot to the "[path](#)" before starting the file transfer with the client. This has the advantage of extra protection against possible implementation security holes, but it has the disadvantages of requiring super-user privileges, of not being able to follow symbolic links that are either absolute or outside of the new root path, and of complicating the preservation of users and groups by name (see below). If `use chroot` is not set, it defaults to trying to enable a chroot but allows the daemon to continue (after logging a warning) if it fails. The one exception to this is when a module's [`path`](#) has a "/./" chroot divider in it -- this causes an unset value to be treated as true for that module. Prior to rsync 3.2.7, the default value was "true". The new "unset" default makes it easier to setup an rsync daemon as a non-root user or to run a daemon on a system where chroot fails. Explicitly setting the value to "true" in rsyncd.conf will always require the chroot to succeed. It is also possible to specify a dot-dir in the module's "[path](#)" to indicate that you want to chdir to the earlier part of the path and then serve files from inside the latter part of the path (with sanitizing and default symlink munging). This can be useful if you need some library dirs inside the chroot (typically for uid & gid lookups) but don't want to put the lib dir into the top of the served path (even though they can be hidden with an [`exclude`](#) directive). However, a better choice for a modern rsync setup is to use a [`name converter`](#)" and try to avoid inner lib dirs altogether. See also the [`daemon chroot`](#) parameter, which causes rsync to chroot into its own chroot area before doing any path-related chrooting. If the daemon is serving the "/" dir (either directly or due to being chrooted to the module's path), rsync does not do any path sanitizing or (default) munging. When it has to limit access to a particular subdir (either due to chroot being disabled or having an inside-chroot path set), rsync will munge symlinks (by default) and sanitize paths. Those that dislike munged symlinks (and really, really trust their users to not break out of the subdir) can disable the symlink munging via the "[munge symlinks](#)" parameter. When rsync is sanitizing paths, it trims ".." path elements from args that it believes would escape the module hierarchy. It also substitutes leading slashes in absolute paths with the module's path (so that options such as `--backup-dir` & `--compare-dest` interpret an absolute path as rooted in the module's "[path](#)" dir). When a chroot is in effect *and* the "[name converter](#)" parameter is *not* set, the "[numeric ids](#)" parameter will default to being enabled (disabling name lookups). This means that if you manually setup name-lookup libraries in your chroot (instead of using a name converter) that you need to explicitly set `numeric ids = false` for rsync to do name lookups. If you copy library resources into the module's chroot area, you should protect them through your OS's normal user/group or ACL settings (to prevent the rsync module's user from being able to change them), and then hide them from the user's view via "[exclude](#)" (see how in the discussion of that parameter). However, it's easier and safer to setup a name converter. 0. `daemon chroot` This parameter specifies a path to which the daemon will chroot before beginning communication with clients. Module paths (and any "[use chroot](#)" settings) will then be related to this one. This lets you choose if you want the whole daemon to be chrooted (with this setting), just the transfers to be chrooted (with "[use chroot](#)"), or both. Keep in mind that the "daemon chroot" area may need various OS/lib/etc files installed to allow the daemon to function. By default the daemon runs without any chrooting. 0. `proxy protocol` When this parameter is enabled, all incoming connections must start with a V1 or V2 proxy protocol header. If the header is not found, the connection is closed. Setting this to `true` requires a proxy server to forward source IP information to rsync, allowing you to log proper IP/host info and make use of client-oriented IP restrictions. The default of `false` means that the IP information comes directly from the socket's metadata. If rsync is not behind a proxy, this should be disabled. _CAUTION_: using this option can be dangerous if you do not ensure that only the proxy is allowed to connect to the rsync port. If any non-proxied connections are allowed through, the client will be able to use a modified rsync to spoof any remote IP address that they desire. You can lock this down using something like iptables `-uid-owner root` rules (for strict localhost access), various firewall rules, or you can require password authorization so that any spoofing by users will not grant extra access. This setting is global. If you need some modules to require this and not others, then you will need to setup multiple rsync daemon processes on different ports. 0. `name converter` This parameter lets you specify a program that will be run by the rsync daemon to do user & group conversions between names & ids. This script is started prior to any chroot being setup, and runs as the daemon user (not the transfer user). You can specify a fully qualified pathname or a program name that is on the $PATH. The program can be used to do normal user & group lookups without having to put any extra files into the chroot area of the module *or* you can do customized conversions. The nameconvert program has access to all of the environment variables that are described in the section on `pre-xfer exec`. This is useful if you want to customize the conversion using information about the module and/or the copy request. There is a sample python script in the support dir named "nameconvert" that implements the normal user & group lookups. Feel free to customize it or just use it as documentation to implement your own. 0. `numeric ids` Enabling this parameter disables the mapping of users and groups by name for the current daemon module. This prevents the daemon from trying to load any user/group-related files or libraries. This enabling makes the transfer behave as if the client had passed the `--numeric-ids` command-line option. By default, this parameter is enabled for chroot modules and disabled for non-chroot modules. Also keep in mind that uid/gid preservation requires the module to be running as root (see "[uid](#)") or for "[fake super](#)" to be configured. A chroot-enabled module should not have this parameter set to false unless you're using a "[name converter](#)" program *or* you've taken steps to ensure that the module has the necessary resources it needs to translate names and that it is not possible for a user to change those resources. 0. `munge symlinks` This parameter tells rsync to modify all symlinks in the same way as the (non-daemon-affecting) `--munge-links` command-line option (using a method described below). This should help protect your files from user trickery when your daemon module is writable. The default is disabled when "[use chroot](#)" is on with an inside-chroot path of "/", OR if "[daemon chroot](#)" is on, otherwise it is enabled. If you disable this parameter on a daemon that is not read-only, there are tricks that a user can play with uploaded symlinks to access daemon-excluded items (if your module has any), and, if "[use chroot](#)" is off, rsync can even be tricked into showing or changing data that is outside the module's path (as access-permissions allow). The way rsync disables the use of symlinks is to prefix each one with the string "/rsyncd-munged/". This prevents the links from being used as long as that directory does not exist. When this parameter is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory. When using the "munge symlinks" parameter in a chroot area that has an inside-chroot path of "/", you should add "/rsyncd-munged/" to the exclude setting for the module so that a user can't try to create it. Note: rsync makes no attempt to verify that any pre-existing symlinks in the module's hierarchy are as safe as you want them to be (unless, of course, it just copied in the whole hierarchy). If you setup an rsync daemon on a new area or locally add symlinks, you can manually protect your symlinks from being abused by prefixing "/rsyncd-munged/" to the start of every symlink's value. There is a perl script in the support directory of the source code named "munge-symlinks" that can be used to add or remove this prefix from your symlinks. When this parameter is disabled on a writable module and "[use chroot](#)" is off (or the inside-chroot path is not "/"), incoming symlinks will be modified to drop a leading slash and to remove ".." path elements that rsync believes will allow a symlink to escape the module's hierarchy. There are tricky ways to work around this, though, so you had better trust your users if you choose this combination of parameters. 0. `charset` This specifies the name of the character set in which the module's filenames are stored. If the client uses an `--iconv` option, the daemon will use the value of the "charset" parameter regardless of the character set the client actually passed. This allows the daemon to support charset conversion in a chroot module without extra files in the chroot area, and also ensures that name-translation is done in a consistent manner. If the "charset" parameter is not set, the `--iconv` option is refused, just as if "iconv" had been specified via "[refuse options](#)". If you wish to force users to always use `--iconv` for a particular module, add "no-iconv" to the "[refuse options](#)" parameter. Keep in mind that this will restrict access to your module to very new rsync clients. 0. `max connections` This parameter allows you to specify the maximum number of simultaneous connections you will allow. Any clients connecting when the maximum has been reached will receive a message telling them to try later. The default is 0, which means no limit. A negative value disables the module. See also the "[lock file](#)" parameter. 0. `log file` When the "log file" parameter is set to a non-empty string, the rsync daemon will log messages to the indicated file rather than using syslog. This is particularly useful on systems (such as AIX) where **syslog()** doesn't work for chrooted programs. The file is opened before **chroot()** is called, allowing it to be placed outside the transfer. If this value is set on a per-module basis instead of globally, the global log will still contain any authorization failures or config-file error messages. If the daemon fails to open the specified file, it will fall back to using syslog and output an error about the failure. (Note that the failure to open the specified log file used to be a fatal error.) This setting can be overridden by using the `--log-file=FILE` or `--dparam=logfile=FILE` command-line options. The former overrides all the log-file parameters of the daemon and all module settings. The latter sets the daemon's log file and the default for all the modules, which still allows modules to override the default setting. 0. `syslog facility` This parameter allows you to specify the syslog facility name to use when logging messages from the rsync daemon. You may use any standard syslog facility name which is defined on your system. Common names are auth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0, local1, local2, local3, local4, local5, local6 and local7. The default is daemon. This setting has no effect if the "[log file](#)" setting is a non-empty string (either set in the per-modules settings, or inherited from the global settings). 0. `syslog tag` This parameter allows you to specify the syslog tag to use when logging messages from the rsync daemon. The default is "rsyncd". This setting has no effect if the "[log file](#)" setting is a non-empty string (either set in the per-modules settings, or inherited from the global settings). For example, if you wanted each authenticated user's name to be included in the syslog tag, you could do something like this: > syslog tag = rsyncd.%RSYNC_USER_NAME% 0. `max verbosity` This parameter allows you to control the maximum amount of verbose information that you'll allow the daemon to generate (since the information goes into the log file). The default is 1, which allows the client to request one level of verbosity. This also affects the user's ability to request higher levels of `--info` and `--debug` logging. If the max value is 2, then no info and/or debug value that is higher than what would be set by `-vv` will be honored by the daemon in its logging. To see how high of a verbosity level you need to accept for a particular info/debug level, refer to `rsync --info=help` and `rsync --debug=help`. For instance, it takes max-verbosity 4 to be able to output debug TIME2 and FLIST3. 0. `lock file` This parameter specifies the file to use to support the "[max connections](#)" parameter. The rsync daemon uses record locking on this file to ensure that the max connections limit is not exceeded for the modules sharing the lock file. The default is `/var/run/rsyncd.lock`. 0. `read only` This parameter determines whether clients will be able to upload files or not. If "read only" is true then any attempted uploads will fail. If "read only" is false then uploads will be possible if file permissions on the daemon side allow them. The default is for all modules to be read only. Note that "[auth users](#)" can override this setting on a per-user basis. 0. `write only` This parameter determines whether clients will be able to download files or not. If "write only" is true then any attempted downloads will fail. If "write only" is false then downloads will be possible if file permissions on the daemon side allow them. The default is for this parameter to be disabled. Helpful hint: you probably want to specify "refuse options = delete" for a write-only module. 0. `open noatime` When set to True, this parameter tells the rsync daemon to open files with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred. If your OS does not support the O_NOATIME flag then rsync will silently ignore this option. Note also that some filesystems are mounted to avoid updating the atime on read access even without the O_NOATIME flag being set. When set to False, this parameters ensures that files on the server are not opened with O_NOATIME. When set to Unset (the default) the user controls the setting via `--open-noatime`. 0. `list` This parameter determines whether this module is listed when the client asks for a listing of available modules. In addition, if this is false, the daemon will pretend the module does not exist when a client denied by "[hosts allow](#)" or "[hosts deny](#)" attempts to access it. Realize that if "[reverse lookup](#)" is disabled globally but enabled for the module, the resulting reverse lookup to a potentially client-controlled DNS server may still reveal to the client that it hit an existing module. The default is for modules to be listable. 0. `uid` This parameter specifies the user name or user ID that file transfers to and from that module should take place as when the daemon was run as root. In combination with the "[gid](#)" parameter this determines what file permissions are available. The default when run by a super-user is to switch to the system's "nobody" user. The default for a non-super-user is to not try to change the user. See also the "[gid](#)" parameter. The RSYNC_USER_NAME environment variable may be used to request that rsync run as the authorizing user. For example, if you want a rsync to run as the same user that was received for the rsync authentication, this setup is useful: > uid = %RSYNC_USER_NAME% > gid = * 0. `gid` This parameter specifies one or more group names/IDs that will be used when accessing the module. The first one will be the default group, and any extra ones be set as supplemental groups. You may also specify a "`*`" as the first gid in the list, which will be replaced by all the normal groups for the transfer's user (see "[uid](#)"). The default when run by a super-user is to switch to your OS's "nobody" (or perhaps "nogroup") group with no other supplementary groups. The default for a non-super-user is to not change any group attributes (and indeed, your OS may not allow a non-super-user to try to change their group settings). The specified list is normally split into tokens based on spaces and commas. However, if the list starts with a comma, then the list is only split on commas, which allows a group name to contain a space. In either case any leading and/or trailing whitespace is removed from the tokens and empty tokens are ignored. 0. `daemon uid` This parameter specifies a uid under which the daemon will run. The daemon usually runs as user root, and when this is left unset the user is left unchanged. See also the "[uid](#)" parameter. 0. `daemon gid` This parameter specifies a gid under which the daemon will run. The daemon usually runs as group root, and when this is left unset, the group is left unchanged. See also the "[gid](#)" parameter. 0. `fake super` Setting "fake super = yes" for a module causes the daemon side to behave as if the `--fake-super` command-line option had been specified. This allows the full attributes of a file to be stored without having to have the daemon actually running as root. 0. `filter` The daemon has its own filter chain that determines what files it will let the client access. This chain is not sent to the client and is independent of any filters the client may have specified. Files excluded by the daemon filter chain (`daemon-excluded` files) are treated as non-existent if the client tries to pull them, are skipped with an error message if the client tries to push them (triggering exit code 23), and are never deleted from the module. You can use daemon filters to prevent clients from downloading or tampering with private administrative files, such as files you may add to support uid/gid name translations. The daemon filter chain is built from the "filter", "[include from](#)", "[include](#)", "[exclude from](#)", and "[exclude](#)" parameters, in that order of priority. Anchored patterns are anchored at the root of the module. To prevent access to an entire subtree, for example, "`/secret`", you **must** exclude everything in the subtree; the easiest way to do this is with a triple-star pattern like "`/secret/***`". The "filter" parameter takes a space-separated list of daemon filter rules, though it is smart enough to know not to split a token at an internal space in a rule (e.g. "`- /foo - /bar`" is parsed as two rules). You may specify one or more merge-file rules using the normal syntax. Only one "filter" parameter can apply to a given module in the config file, so put all the rules you want in a single parameter. Note that per-directory merge-file rules do not provide as much protection as global rules, but they can be used to make `--delete` work better during a client download operation if the per-dir merge files are included in the transfer and the client requests that they be used. 0. `exclude` This parameter takes a space-separated list of daemon exclude patterns. As with the client `--exclude` option, patterns can be qualified with "`- `" or "`+ `" to explicitly indicate exclude/include. Only one "exclude" parameter can apply to a given module. See the "filter" parameter for a description of how excluded files affect the daemon. 0. `include` Use an "include" to override the effects of the "[exclude](#)" parameter. Only one "include" parameter can apply to a given module. See the "[filter](#)" parameter for a description of how excluded files affect the daemon. 0. `exclude from` This parameter specifies the name of a file on the daemon that contains daemon exclude patterns, one per line. Only one "exclude from" parameter can apply to a given module; if you have multiple exclude-from files, you can specify them as a merge file in the "[filter](#)" parameter. See the "[filter](#)" parameter for a description of how excluded files affect the daemon. 0. `include from` Analogue of "[exclude from](#)" for a file of daemon include patterns. Only one "include from" parameter can apply to a given module. See the "[filter](#)" parameter for a description of how excluded files affect the daemon. 0. `incoming chmod` This parameter allows you to specify a set of comma-separated chmod strings that will affect the permissions of all incoming files (files that are being received by the daemon). These changes happen after all other permission calculations, and this will even override destination-default and/or existing permissions when the client does not specify `--perms`. See the description of the `--chmod` rsync option and the **chmod**(1) manpage for information on the format of this string. 0. `outgoing chmod` This parameter allows you to specify a set of comma-separated chmod strings that will affect the permissions of all outgoing files (files that are being sent out from the daemon). These changes happen first, making the sent permissions appear to be different than those stored in the filesystem itself. For instance, you could disable group write permissions on the server while having it appear to be on to the clients. See the description of the `--chmod` rsync option and the **chmod**(1) manpage for information on the format of this string. 0. `auth users` This parameter specifies a comma and/or space-separated list of authorization rules. In its simplest form, you list the usernames that will be allowed to connect to this module. The usernames do not need to exist on the local system. The rules may contain shell wildcard characters that will be matched against the username provided by the client for authentication. If "auth users" is set then the client will be challenged to supply a username and password to connect to the module. A challenge response authentication protocol is used for this exchange. The plain text usernames and passwords are stored in the file specified by the "[secrets file](#)" parameter. The default is for all users to be able to connect without a password (this is called "anonymous rsync"). In addition to username matching, you can specify groupname matching via a '@' prefix. When using groupname matching, the authenticating username must be a real user on the system, or it will be assumed to be a member of no groups. For example, specifying "@rsync" will match the authenticating user if the named user is a member of the rsync group. Finally, options may be specified after a colon (:). The options allow you to "deny" a user or a group, set the access to "ro" (read-only), or set the access to "rw" (read/write). Setting an auth-rule-specific ro/rw setting overrides the module's "[read only](#)" setting. Be sure to put the rules in the order you want them to be matched, because the checking stops at the first matching user or group, and that is the only auth that is checked. For example: > auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam In the above rule, user joe will be denied access no matter what. Any user that is in the group "guest" is also denied access. The user "admin" gets access in read/write mode, but only if the admin user is not in group "guest" (because the admin user-matching rule would never be reached if the user is in group "guest"). Any other user who is in group "rsync" will get read-only access. Finally, users susan, joe, and sam get the ro/rw setting of the module, but only if the user didn't match an earlier group-matching rule. If you need to specify a user or group name with a space in it, start your list with a comma to indicate that the list should only be split on commas (though leading and trailing whitespace will also be removed, and empty entries are just ignored). For example: > auth users = , joe:deny, @Some Group:deny, admin:rw, @RO Group:ro See the description of the secrets file for how you can have per-user passwords as well as per-group passwords. It also explains how a user can authenticate using their user password or (when applicable) a group password, depending on what rule is being authenticated. See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE SHELL CONNECTION" in **rsync**(1) for information on how handle an rsyncd.conf-level username that differs from the remote-shell-level username when using a remote shell to connect to an rsync daemon. 0. `secrets file` This parameter specifies the name of a file that contains the username:password and/or @groupname:password pairs used for authenticating this module. This file is only consulted if the "[auth users](#)" parameter is specified. The file is line-based and contains one name:password pair per line. Any line has a hash (#) as the very first character on the line is considered a comment and is skipped. The passwords can contain any characters but be warned that many operating systems limit the length of passwords that can be typed at the client end, so you may find that passwords longer than 8 characters don't work. The use of group-specific lines are only relevant when the module is being authorized using a matching "@groupname" rule. When that happens, the user can be authorized via either their "username:password" line or the "@groupname:password" line for the group that triggered the authentication. It is up to you what kind of password entries you want to include, either users, groups, or both. The use of group rules in "[auth users](#)" does not require that you specify a group password if you do not want to use shared passwords. There is no default for the "secrets file" parameter, you must choose a name (such as `/etc/rsyncd.secrets`). The file must normally not be readable by "other"; see "[strict modes](#)". If the file is not found or is rejected, no logins for an "[auth users](#)" module will be possible. 0. `strict modes` This parameter determines whether or not the permissions on the secrets file will be checked. If "strict modes" is true, then the secrets file must not be readable by any user ID other than the one that the rsync daemon is running under. If "strict modes" is false, the check is not performed. The default is true. This parameter was added to accommodate rsync running on the Windows operating system. 0. `hosts allow` This parameter allows you to specify a list of comma- and/or whitespace-separated patterns that are matched against a connecting client's hostname and IP address. If none of the patterns match, then the connection is rejected. Each pattern can be in one of six forms: - a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address of the form a:b:c::d:e:f. In this case the incoming machine's IP address must match exactly. - an address/mask in the form ipaddr/n where ipaddr is the IP address and n is the number of one bits in the netmask. All IP addresses which match the masked IP address will be allowed in. - an address/mask in the form ipaddr/maskaddr where ipaddr is the IP address and maskaddr is the netmask in dotted decimal notation for IPv4, or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP addresses which match the masked IP address will be allowed in. - a hostname pattern using wildcards. If the hostname of the connecting IP (as determined by a reverse lookup) matches the wildcarded name (using the same rules as normal Unix filename matching), the client is allowed in. This only works if "[reverse lookup](#)" is enabled (the default). - a hostname. A plain hostname is matched against the reverse DNS of the connecting IP (if "[reverse lookup](#)" is enabled), and/or the IP of the given hostname is matched against the connecting IP (if "[forward lookup](#)" is enabled, as it is by default). Any match will be allowed in. - an '@' followed by a netgroup name, which will match if the reverse DNS of the connecting IP is in the specified netgroup. Note IPv6 link-local addresses can have a scope in the address specification: > fe80::1%link1 > fe80::%link1/64 > fe80::%link1/ffff:ffff:ffff:ffff:: You can also combine "hosts allow" with "[hosts deny](#)" as a way to add exceptions to your deny list. When both parameters are specified, the "hosts allow" parameter is checked first and a match results in the client being able to connect. A non-allowed host is then matched against the "[hosts deny](#)" list to see if it should be rejected. A host that does not match either list is allowed to connect. The default is no "hosts allow" parameter, which means all hosts can connect. 0. `hosts deny` This parameter allows you to specify a list of comma- and/or whitespace-separated patterns that are matched against a connecting clients hostname and IP address. If the pattern matches then the connection is rejected. See the "[hosts allow](#)" parameter for more information. The default is no "hosts deny" parameter, which means all hosts can connect. 0. `reverse lookup` Controls whether the daemon performs a reverse lookup on the client's IP address to determine its hostname, which is used for "[hosts allow](#)" & "[hosts deny](#)" checks and the "%h" log escape. This is enabled by default, but you may wish to disable it to save time if you know the lookup will not return a useful result, in which case the daemon will use the name "UNDETERMINED" instead. If this parameter is enabled globally (even by default), rsync performs the lookup as soon as a client connects, so disabling it for a module will not avoid the lookup. Thus, you probably want to disable it globally and then enable it for modules that need the information. 0. `forward lookup` Controls whether the daemon performs a forward lookup on any hostname specified in an hosts allow/deny setting. By default this is enabled, allowing the use of an explicit hostname that would not be returned by reverse DNS of the connecting IP. 0. `ignore errors` This parameter tells rsyncd to ignore I/O errors on the daemon when deciding whether to run the delete phase of the transfer. Normally rsync skips the `--delete` step if any I/O errors have occurred in order to prevent disastrous deletion due to a temporary resource shortage or other I/O error. In some cases this test is counter productive so you can use this parameter to turn off this behavior. 0. `ignore nonreadable` This tells the rsync daemon to completely ignore files that are not readable by the user. This is useful for public archives that may have some non-readable files among the directories, and the sysadmin doesn't want those files to be seen at all. 0. `transfer logging` This parameter enables per-file logging of downloads and uploads in a format somewhat similar to that used by ftp daemons. The daemon always logs the transfer at the end, so if a transfer is aborted, no mention will be made in the log file. If you want to customize the log lines, see the "[log format](#)" parameter. 0. `log format` This parameter allows you to specify the format used for logging file transfers when transfer logging is enabled. The format is a text string containing embedded single-character escape sequences prefixed with a percent (%) character. An optional numeric field width may also be specified between the percent and the escape letter (e.g. "`%-50n %8l %07p`"). In addition, one or more apostrophes may be specified prior to a numerical escape to indicate that the numerical value should be made more human-readable. The 3 supported levels are the same as for the `--human-readable` command-line option, though the default is for human-readability to be off. Each added apostrophe increases the level (e.g. "`%''l %'b %f`"). The default log format is "`%o %h [%a] %m (%u) %f %l`", and a "`%t [%p] `" is always prefixed when using the "[log file](#)" parameter. (A perl script that will summarize this default log format is included in the rsync source code distribution in the "support" subdirectory: rsyncstats.) The single-character escapes that are understood are as follows: - %a the remote IP address (only available for a daemon) - %b the number of bytes actually transferred - %B the permission bits of the file (e.g. rwxrwxrwt) - %c the total size of the block checksums received for the basis file (only when sending) - %C the full-file checksum if it is known for the file. For older rsync protocols/versions, the checksum was salted, and is thus not a useful value (and is not displayed when that is the case). For the checksum to output for a file, either the `--checksum` option must be in-effect or the file must have been transferred without a salted checksum being used. See the `--checksum-choice` option for a way to choose the algorithm. - %f the filename (long form on sender; no trailing "/") - %G the gid of the file (decimal) or "DEFAULT" - %h the remote host name (only available for a daemon) - %i an itemized list of what is being updated - %l the length of the file in bytes - %L the string "` -> SYMLINK`", "` => HARDLINK`", or "" (where `SYMLINK` or `HARDLINK` is a filename) - %m the module name - %M the last-modified time of the file - %n the filename (short form; trailing "/" on dir) - %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period) - %p the process ID of this rsync session - %P the module path - %t the current date time - %u the authenticated username or an empty string - %U the uid of the file (decimal) For a list of what the characters mean that are output by "%i", see the `--itemize-changes` option in the rsync manpage. Note that some of the logged output changes when talking with older rsync versions. For instance, deleted files were only output as verbose messages prior to rsync 2.6.4. 0. `timeout` This parameter allows you to override the clients choice for I/O timeout for this module. Using this parameter you can ensure that rsync won't wait on a dead client forever. The timeout is specified in seconds. A value of zero means no timeout and is the default. A good choice for anonymous rsync daemons may be 600 (giving a 10 minute timeout). 0. `refuse options` This parameter allows you to specify a space-separated list of rsync command-line options that will be refused by your rsync daemon. You may specify the full option name, its one-letter abbreviation, or a wild-card string that matches multiple options. Beginning in 3.2.0, you can also negate a match term by starting it with a "!". When an option is refused, the daemon prints an error message and exits. For example, this would refuse `--checksum` (`-c`) and all the various delete options: > refuse options = c delete The reason the above refuses all delete options is that the options imply `--delete`, and implied options are refused just like explicit options. The use of a negated match allows you to fine-tune your refusals after a wild-card, such as this: > refuse options = delete-* !delete-during Negated matching can also turn your list of refused options into a list of accepted options. To do this, begin the list with a "`*`" (to refuse all options) and then specify one or more negated matches to accept. For example: > refuse options = * !a !v !compress* Don't worry that the "`*`" will refuse certain vital options such as `--dry-run`, `--server`, `--no-iconv`, `--seclude-args`, etc. These important options are not matched by wild-card, so they must be overridden by their exact name. For instance, if you're forcing iconv transfers you could use something like this: > refuse options = * no-iconv !a !v As an additional aid (beginning in 3.2.0), refusing (or "`!refusing`") the "a" or "archive" option also affects all the options that the `--archive` option implies (`-rdlptgoD`), but only if the option is matched explicitly (not using a wildcard). If you want to do something tricky, you can use "`archive*`" to avoid this side-effect, but keep in mind that no normal rsync client ever sends the actual archive option to the server. As an additional safety feature, the refusal of "delete" also refuses `remove-source-files` when the daemon is the sender; if you want the latter without the former, instead refuse "`delete-*`" as that refuses all the delete modes without affecting `--remove-source-files`. (Keep in mind that the client's `--delete` option typically results in `--delete-during`.) When un-refusing delete options, you should either specify "`!delete*`" (to accept all delete options) or specify a limited set that includes "delete", such as: > refuse options = * !a !delete !delete-during ... whereas this accepts any delete option except `--delete-after`: > refuse options = * !a !delete* delete-after A note on refusing "compress": it may be better to set the "[dont compress](#)" daemon parameter to "`*`" and ensure that `RSYNC_COMPRESS_LIST=zlib` is set in the environment of the daemon in order to disable compression silently instead of returning an error that forces the client to remove the `-z` option. If you are un-refusing the compress option, you may want to match "`!compress*`" if you also want to allow the `--compress-level` option. Note that the "copy-devices" & "write-devices" options are refused by default, but they can be explicitly accepted with "`!copy-devices`" and/or "`!write-devices`". The options "log-file" and "log-file-format" are forcibly refused and cannot be accepted. Here are all the options that are not matched by wild-cards: - `--server`: Required for rsync to even work. - `--rsh`, `-e`: Required to convey compatibility flags to the server. - `--out-format`: This is required to convey output behavior to a remote receiver. While rsync passes the older alias `--log-format` for compatibility reasons, this options should not be confused with `--log-file-format`. - `--sender`: Use "[write only](#)" parameter instead of refusing this. - `--dry-run`, `-n`: Who would want to disable this? - `--seclude-args`, `-s`: Is the oldest arg-protection method. - `--from0`, `-0`: Makes it easier to accept/refuse `--files-from` without affecting this helpful modifier. - `--iconv`: This is auto-disabled based on "[charset](#)" parameter. - `--no-iconv`: Most transfers use this option. - `--checksum-seed`: Is a fairly rare, safe option. - `--write-devices`: Is non-wild but also auto-disabled. 0. `dont compress` **NOTE:** This parameter currently has no effect except in one instance: if it is set to "`*`" then it minimizes or disables compression for all files (for those that don't want to refuse the `--compress` option completely). This parameter allows you to select filenames based on wildcard patterns that should not be compressed when pulling files from the daemon (no analogous parameter exists to govern the pushing of files to a daemon). Compression can be expensive in terms of CPU usage, so it is usually good to not try to compress files that won't compress well, such as already compressed files. The "dont compress" parameter takes a space-separated list of case-insensitive wildcard patterns. Any source filename matching one of the patterns will be compressed as little as possible during the transfer. If the compression algorithm has an "off" level, then no compression occurs for those files. If an algorithms has the ability to change the level in mid-stream, it will be minimized to reduce the CPU usage as much as possible. See the `--skip-compress` parameter in the **rsync**(1) manpage for the list of file suffixes that are skipped by default if this parameter is not set. 0. `early exec`, `pre-xfer exec`, `post-xfer exec` You may specify a command to be run in the early stages of the connection, or right before and/or after the transfer. If the `early exec` or `pre-xfer exec` command returns an error code, the transfer is aborted before it begins. Any output from the `pre-xfer exec` command on stdout (up to several KB) will be displayed to the user when aborting, but is _not_ displayed if the script returns success. The other programs cannot send any text to the user. All output except for the `pre-xfer exec` stdout goes to the corresponding daemon's stdout/stderr, which is typically discarded. See the `--no-detatch` option for a way to see the daemon's output, which can assist with debugging. Note that the `early exec` command runs before any part of the transfer request is known except for the module name. This helper script can be used to setup a disk mount or decrypt some data into a module dir, but you may need to use `lock file` and `max connections` to avoid concurrency issues. If the client rsync specified the `--early-input=FILE` option, it can send up to about 5K of data to the stdin of the early script. The stdin will otherwise be empty. Note that the `post-xfer exec` command is still run even if one of the other scripts returns an error code. The `pre-xfer exec` command will _not_ be run, however, if the `early exec` command fails. The following environment variables will be set, though some are specific to the pre-xfer or the post-xfer environment: - `RSYNC_MODULE_NAME`: The name of the module being accessed. - `RSYNC_MODULE_PATH`: The path configured for the module. - `RSYNC_HOST_ADDR`: The accessing host's IP address. - `RSYNC_HOST_NAME`: The accessing host's name. - `RSYNC_USER_NAME`: The accessing user's name (empty if no user). - `RSYNC_PID`: A unique number for this transfer. - `RSYNC_REQUEST`: (pre-xfer only) The module/path info specified by the user. Note that the user can specify multiple source files, so the request can be something like "mod/path1 mod/path2", etc. - `RSYNC_ARG#`: (pre-xfer only) The pre-request arguments are set in these numbered values. RSYNC_ARG0 is always "rsyncd", followed by the options that were used in RSYNC_ARG1, and so on. There will be a value of "." indicating that the options are done and the path args are beginning -- these contain similar information to RSYNC_REQUEST, but with values separated and the module name stripped off. - `RSYNC_EXIT_STATUS`: (post-xfer only) the server side's exit value. This will be 0 for a successful run, a positive value for an error that the server generated, or a -1 if rsync failed to exit properly. Note that an error that occurs on the client side does not currently get sent to the server side, so this is not the final exit status for the whole transfer. - `RSYNC_RAW_STATUS`: (post-xfer only) the raw exit value from **waitpid()**. Even though the commands can be associated with a particular module, they are run using the permissions of the user that started the daemon (not the module's uid/gid setting) without any chroot restrictions. These settings honor 2 environment variables: use RSYNC_SHELL to set a shell to use when running the command (which otherwise uses your **system()** call's default shell), and use RSYNC_NO_XFER_EXEC to disable both options completely. ## CONFIG DIRECTIVES There are currently two config directives available that allow a config file to incorporate the contents of other files: `&include` and `&merge`. Both allow a reference to either a file or a directory. They differ in how segregated the file's contents are considered to be. The `&include` directive treats each file as more distinct, with each one inheriting the defaults of the parent file, starting the parameter parsing as globals/defaults, and leaving the defaults unchanged for the parsing of the rest of the parent file. The `&merge` directive, on the other hand, treats the file's contents as if it were simply inserted in place of the directive, and thus it can set parameters in a module started in another file, can affect the defaults for other files, etc. When an `&include` or `&merge` directive refers to a directory, it will read in all the `*.conf` or `*.inc` files (respectively) that are contained inside that directory (without any recursive scanning), with the files sorted into alpha order. So, if you have a directory named "rsyncd.d" with the files "foo.conf", "bar.conf", and "baz.conf" inside it, this directive: > &include /path/rsyncd.d would be the same as this set of directives: > &include /path/rsyncd.d/bar.conf > &include /path/rsyncd.d/baz.conf > &include /path/rsyncd.d/foo.conf except that it adjusts as files are added and removed from the directory. The advantage of the `&include` directive is that you can define one or more modules in a separate file without worrying about unintended side-effects between the self-contained module files. The advantage of the `&merge` directive is that you can load config snippets that can be included into multiple module definitions, and you can also set global values that will affect connections (such as `motd file`), or globals that will affect other include files. For example, this is a useful /etc/rsyncd.conf file: > port = 873 > log file = /var/log/rsync.log > pid file = /var/lock/rsync.lock > > &merge /etc/rsyncd.d > &include /etc/rsyncd.d This would merge any `/etc/rsyncd.d/*.inc` files (for global values that should stay in effect), and then include any `/etc/rsyncd.d/*.conf` files (defining modules without any global-value cross-talk). ## AUTHENTICATION STRENGTH The authentication protocol used in rsync is a 128 bit MD4 based challenge response system. This is fairly weak protection, though (with at least one brute-force hash-finding algorithm publicly available), so if you want really top-quality security, then I recommend that you run rsync over ssh. (Yes, a future version of rsync will switch over to a stronger hashing method.) Also note that the rsync daemon protocol does not currently provide any encryption of the data that is transferred over the connection. Only authentication is provided. Use ssh as the transport if you want encryption. You can also make use of SSL/TLS encryption if you put rsync behind an SSL proxy. ## SSL/TLS Daemon Setup When setting up an rsync daemon for access via SSL/TLS, you will need to configure a TCP proxy (such as haproxy or nginx) as the front-end that handles the encryption. - You should limit the access to the backend-rsyncd port to only allow the proxy to connect. If it is on the same host as the proxy, then configuring it to only listen on localhost is a good idea. - You should consider turning on the `proxy protocol` rsync-daemon parameter if your proxy supports sending that information. The examples below assume that this is enabled. An example haproxy setup is as follows: > ``` > frontend fe_rsync-ssl > bind :::874 ssl crt /etc/letsencrypt/example.com/combined.pem > mode tcp > use_backend be_rsync > > backend be_rsync > mode tcp > server local-rsync 127.0.0.1:873 check send-proxy > ``` An example nginx proxy setup is as follows: > ``` > stream { > server { > listen 874 ssl; > listen [::]:874 ssl; > > ssl_certificate /etc/letsencrypt/example.com/fullchain.pem; > ssl_certificate_key /etc/letsencrypt/example.com/privkey.pem; > > proxy_pass localhost:873; > proxy_protocol on; # Requires rsyncd.conf "proxy protocol = true" > proxy_timeout 1m; > proxy_connect_timeout 5s; > } > } > ``` ## DAEMON CONFIG EXAMPLES A simple rsyncd.conf file that allow anonymous rsync to a ftp area at `/home/ftp` would be: > ``` > [ftp] > path = /home/ftp > comment = ftp export area > ``` A more sophisticated example would be: > ``` > uid = nobody > gid = nobody > use chroot = yes > max connections = 4 > syslog facility = local5 > pid file = /var/run/rsyncd.pid > > [ftp] > path = /var/ftp/./pub > comment = whole ftp area (approx 6.1 GB) > > [sambaftp] > path = /var/ftp/./pub/samba > comment = Samba ftp area (approx 300 MB) > > [rsyncftp] > path = /var/ftp/./pub/rsync > comment = rsync ftp area (approx 6 MB) > > [sambawww] > path = /public_html/samba > comment = Samba WWW pages (approx 240 MB) > > [cvs] > path = /data/cvs > comment = CVS repository (requires authentication) > auth users = tridge, susan > secrets file = /etc/rsyncd.secrets > ``` The /etc/rsyncd.secrets file would look something like this: > tridge:mypass > susan:herpass ## FILES /etc/rsyncd.conf or rsyncd.conf ## SEE ALSO [**rsync**(1)](rsync.1), [**rsync-ssl**(1)](rsync-ssl.1) ## BUGS Please report bugs! The rsync bug tracking system is online at . ## VERSION This manpage is current for version @VERSION@ of rsync. ## CREDITS Rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. An rsync web site is available at and its github project is . ## THANKS Thanks to Warren Stanley for his original idea and patch for the rsync daemon. Thanks to Karsten Thygesen for his many suggestions and documentation! ## AUTHOR Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. It is currently maintained by Wayne Davison. Mailing lists for support and development are available at . rsync-3.2.7/daemon-parm.awk0000775000000000000000000000547513700171313014277 0ustar rootroot#!/usr/bin/awk -f # The caller must pass arg: daemon-parm.txt # The resulting code is output into daemon-parm.h BEGIN { heading = "/* DO NOT EDIT THIS FILE! It is auto-generated from a list of values in " ARGV[1] "! */\n\n" sect = psect = defines = accessors = prior_ptype = "" parms = "\nstatic struct parm_struct parm_table[] = {" comment_fmt = "\n/********** %s **********/\n" tdstruct = "typedef struct {" } /^\s*$/ { next } /^#/ { next } /^Globals:/ { if (defines != "") { print "The Globals section must come first!" defines = "" exit } defines = tdstruct values = "\nstatic const all_vars Defaults = {\n { /* Globals: */\n" exps = exp_values = sprintf(comment_fmt, "EXP") sect = "GLOBAL" psect = ", P_GLOBAL, &Vars.g." next } /^Locals:/ { if (sect == "") { print "The Locals section must come after the Globals!" exit } defines = defines exps "} global_vars;\n\n" tdstruct values = values exp_values "\n }, { /* Locals: */\n" exps = exp_values = sprintf(comment_fmt, "EXP") sect = "LOCAL" psect = ", P_LOCAL, &Vars.l." next } /^(STRING|CHAR|PATH|INTEGER|ENUM|OCTAL|BOOL|BOOLREV|BOOL3)[ \t]/ { ptype = $1 name = $2 $1 = $2 = "" sub(/^[ \t]+/, "") if (ptype != prior_ptype) { comment = sprintf(comment_fmt, ptype) defines = defines comment values = values comment parms = parms "\n" accessors = accessors "\n" prior_ptype = ptype } if (ptype == "STRING" || ptype == "PATH") { atype = "STRING" vtype = "char*" } else if (ptype ~ /BOOL/) { atype = vtype = "BOOL" } else if (ptype == "CHAR") { atype = "CHAR" vtype = "char" } else { atype = "INTEGER" vtype = "int" } # The name might be var_name|public_name pubname = name sub(/\|.*/, "", name) sub(/.*\|/, "", pubname) gsub(/_/, " ", pubname) gsub(/-/, "", name) if (ptype == "ENUM") enum = "enum_" name else enum = "NULL" defines = defines "\t" vtype " " name ";\n" values = values "\t" $0 ", /* " name " */\n" parms = parms " {\"" pubname "\", P_" ptype psect name ", " enum ", 0},\n" accessors = accessors "FN_" sect "_" atype "(lp_" name ", " name ")\n" if (vtype == "char*") { exps = exps "\tBOOL " name "_EXP;\n" exp_values = exp_values "\tFalse, /* " name "_EXP */\n" } next } /./ { print "Extraneous line:" $0 defines = "" exit } END { if (sect != "" && defines != "") { defines = defines exps "} local_vars;\n\n" defines = defines tdstruct "\n\tglobal_vars g;\n\tlocal_vars l;\n} all_vars;\n" values = values exp_values "\n }\n};\n\nstatic all_vars Vars;\n" parms = parms "\n {NULL, P_BOOL, P_NONE, NULL, NULL, 0}\n};\n" print heading defines values parms accessors > "daemon-parm.h" } else { print "Failed to parse the data in " ARGV[1] exit 1 } } rsync-3.2.7/config.guess0000664000000000000000000013733213672315367013724 0ustar rootroot#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-04-26' # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$driver" break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; esac # Note: order is significant - the case branches are not exclusive. case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; *:OS108:*:*) echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Twizzler:*:*) echo "$UNAME_MACHINE"-unknown-twizzler exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ [ "$TARGET_BINARY_INTERFACE"x = x ] then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi else echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf fi exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; *:Minix:*:*) echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then LIBCABI="$LIBC"x32 fi fi echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; *:Unleashed:*:*) echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" exit ;; esac # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsync-3.2.7/hlink.c0000664000000000000000000003700614306711271012642 0ustar rootroot/* * Routines to support hard-linking. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2022 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 "inums.h" #include "ifuncs.h" extern int dry_run; extern int list_only; extern int am_sender; extern int inc_recurse; extern int do_xfers; extern int alt_dest_type; extern int preserve_acls; extern int preserve_xattrs; extern int protocol_version; extern int remove_source_files; extern int stdout_format_has_i; extern int maybe_ATTRS_REPORT; extern int unsort_ndx; extern char *basis_dir[MAX_BASIS_DIRS+1]; extern struct file_list *cur_flist; #ifdef SUPPORT_HARD_LINKS /* Starting with protocol 30, we use a simple hashtable on the sending side * for hashing the st_dev and st_ino info. The receiving side gets told * (via flags and a "group index") which items are hard-linked together, so * we can avoid the pool of dev+inode data. For incremental recursion mode, * the receiver will use a ndx hash to remember old pathnames. */ static void *data_when_new = ""; static struct hashtable *dev_tbl; static struct hashtable *prior_hlinks; static struct file_list *hlink_flist; void init_hard_links(void) { if (am_sender || protocol_version < 30) dev_tbl = hashtable_create(16, HT_KEY64); else if (inc_recurse) prior_hlinks = hashtable_create(1024, HT_KEY32); } struct ht_int64_node *idev_find(int64 dev, int64 ino) { static struct ht_int64_node *dev_node = NULL; /* Note that some OSes have a dev == 0, so increment to avoid storing a 0. */ if (!dev_node || dev_node->key != dev+1) { /* We keep a separate hash table of inodes for every device. */ dev_node = hashtable_find(dev_tbl, dev+1, data_when_new); if (dev_node->data == data_when_new) { dev_node->data = hashtable_create(512, HT_KEY64); if (DEBUG_GTE(HLINK, 3)) { rprintf(FINFO, "[%s] created hashtable for dev %s\n", who_am_i(), big_num(dev)); } } } return hashtable_find(dev_node->data, ino, (void*)-1L); } void idev_destroy(void) { int i; for (i = 0; i < dev_tbl->size; i++) { struct ht_int32_node *node = HT_NODE(dev_tbl, dev_tbl->nodes, i); if (node->data) hashtable_destroy(node->data); } hashtable_destroy(dev_tbl); } static int hlink_compare_gnum(int *int1, int *int2) { struct file_struct *f1 = hlink_flist->sorted[*int1]; struct file_struct *f2 = hlink_flist->sorted[*int2]; int32 gnum1 = F_HL_GNUM(f1); int32 gnum2 = F_HL_GNUM(f2); if (gnum1 != gnum2) return gnum1 > gnum2 ? 1 : -1; return *int1 > *int2 ? 1 : -1; } static void match_gnums(int32 *ndx_list, int ndx_count) { int32 from, prev; struct file_struct *file, *file_next; struct ht_int32_node *node = NULL; int32 gnum, gnum_next; qsort(ndx_list, ndx_count, sizeof ndx_list[0], (int (*)()) hlink_compare_gnum); for (from = 0; from < ndx_count; from++) { file = hlink_flist->sorted[ndx_list[from]]; gnum = F_HL_GNUM(file); if (inc_recurse) { node = hashtable_find(prior_hlinks, gnum, data_when_new); if (node->data == data_when_new) { node->data = new_array0(char, 5); assert(gnum >= hlink_flist->ndx_start); file->flags |= FLAG_HLINK_FIRST; prev = -1; } else if (CVAL(node->data, 0) == 0) { struct file_list *flist; prev = IVAL(node->data, 1); flist = flist_for_ndx(prev, NULL); if (flist) flist->files[prev - flist->ndx_start]->flags &= ~FLAG_HLINK_LAST; else { /* We skipped all prior files in this * group, so mark this as a "first". */ file->flags |= FLAG_HLINK_FIRST; prev = -1; } } else prev = -1; } else { file->flags |= FLAG_HLINK_FIRST; prev = -1; } for ( ; from < ndx_count-1; file = file_next, gnum = gnum_next, from++) { /*SHARED ITERATOR*/ file_next = hlink_flist->sorted[ndx_list[from+1]]; gnum_next = F_HL_GNUM(file_next); if (gnum != gnum_next) break; F_HL_PREV(file) = prev; /* The linked list uses over-the-wire ndx values. */ if (unsort_ndx) prev = F_NDX(file); else prev = ndx_list[from] + hlink_flist->ndx_start; } if (prev < 0 && !inc_recurse) { /* Disable hard-link bit and set DONE so that * HLINK_BUMP()-dependent values are unaffected. */ file->flags &= ~(FLAG_HLINKED | FLAG_HLINK_FIRST); file->flags |= FLAG_HLINK_DONE; continue; } file->flags |= FLAG_HLINK_LAST; F_HL_PREV(file) = prev; if (inc_recurse && CVAL(node->data, 0) == 0) { if (unsort_ndx) prev = F_NDX(file); else prev = ndx_list[from] + hlink_flist->ndx_start; SIVAL(node->data, 1, prev); } } } /* Analyze the hard-links in the file-list by creating a list of all the * items that have hlink data, sorting them, and matching up identical * values into clusters. These will be a single linked list from last * to first when we're done. */ void match_hard_links(struct file_list *flist) { if (!list_only && flist->used) { int i, ndx_count = 0; int32 *ndx_list; ndx_list = new_array(int32, flist->used); for (i = 0; i < flist->used; i++) { if (F_IS_HLINKED(flist->sorted[i])) ndx_list[ndx_count++] = i; } hlink_flist = flist; if (ndx_count) match_gnums(ndx_list, ndx_count); free(ndx_list); } if (protocol_version < 30) idev_destroy(); } static int maybe_hard_link(struct file_struct *file, int ndx, char *fname, int statret, stat_x *sxp, const char *oldname, STRUCT_STAT *old_stp, const char *realname, int itemizing, enum logcode code) { if (statret == 0) { if (sxp->st.st_dev == old_stp->st_dev && sxp->st.st_ino == old_stp->st_ino) { if (itemizing) { itemize(fname, file, ndx, statret, sxp, ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, ""); } if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); file->flags |= FLAG_HLINK_DONE; return 0; } } if (atomic_create(file, fname, NULL, oldname, MAKEDEV(0, 0), sxp, statret == 0 ? DEL_FOR_FILE : 0)) { if (itemizing) { itemize(fname, file, ndx, statret, sxp, ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, realname); } if (code != FNONE && INFO_GTE(NAME, 1)) rprintf(code, "%s => %s\n", fname, realname); return 0; } return -1; } /* Figure out if a prior entry is still there or if we just have a * cached name for it. */ static char *check_prior(struct file_struct *file, int gnum, int *prev_ndx_p, struct file_list **flist_p) { struct file_struct *fp; struct ht_int32_node *node; int prev_ndx = F_HL_PREV(file); while (1) { struct file_list *flist; if (prev_ndx < 0 || (flist = flist_for_ndx(prev_ndx, NULL)) == NULL) break; fp = flist->files[prev_ndx - flist->ndx_start]; if (!(fp->flags & FLAG_SKIP_HLINK)) { *prev_ndx_p = prev_ndx; *flist_p = flist; return NULL; } F_HL_PREV(file) = prev_ndx = F_HL_PREV(fp); } if (inc_recurse && (node = hashtable_find(prior_hlinks, gnum, NULL)) != NULL) { assert(node->data != NULL); if (CVAL(node->data, 0) != 0) { *prev_ndx_p = -1; *flist_p = NULL; return node->data; } /* The prior file must have been skipped. */ F_HL_PREV(file) = -1; } *prev_ndx_p = -1; *flist_p = NULL; return NULL; } /* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns: * 0 = process the file, 1 = skip the file, -1 = error occurred. */ int hard_link_check(struct file_struct *file, int ndx, char *fname, int statret, stat_x *sxp, int itemizing, enum logcode code) { STRUCT_STAT prev_st; char namebuf[MAXPATHLEN], altbuf[MAXPATHLEN]; char *realname, *prev_name; struct file_list *flist; int gnum = inc_recurse ? F_HL_GNUM(file) : -1; int prev_ndx; prev_name = realname = check_prior(file, gnum, &prev_ndx, &flist); if (!prev_name) { struct file_struct *prev_file; if (!flist) { /* The previous file was skipped, so this one is * treated as if it were the first in its group. */ if (DEBUG_GTE(HLINK, 2)) { rprintf(FINFO, "hlink for %d (%s,%d): virtual first\n", ndx, f_name(file, NULL), gnum); } return 0; } prev_file = flist->files[prev_ndx - flist->ndx_start]; /* Is the previous link not complete yet? */ if (!(prev_file->flags & FLAG_HLINK_DONE)) { /* Is the previous link being transferred? */ if (prev_file->flags & FLAG_FILE_SENT) { /* Add ourselves to the list of files that will * be updated when the transfer completes, and * mark ourself as waiting for the transfer. */ F_HL_PREV(file) = F_HL_PREV(prev_file); F_HL_PREV(prev_file) = ndx; file->flags |= FLAG_FILE_SENT; cur_flist->in_progress++; if (DEBUG_GTE(HLINK, 2)) { rprintf(FINFO, "hlink for %d (%s,%d): waiting for %d\n", ndx, f_name(file, NULL), gnum, F_HL_PREV(file)); } return 1; } if (DEBUG_GTE(HLINK, 2)) { rprintf(FINFO, "hlink for %d (%s,%d): looking for a leader\n", ndx, f_name(file, NULL), gnum); } return 0; } /* There is a finished file to link with! */ if (!(prev_file->flags & FLAG_HLINK_FIRST)) { /* The previous previous is FIRST when prev is not. */ prev_name = realname = check_prior(prev_file, gnum, &prev_ndx, &flist); /* Update our previous pointer to point to the FIRST. */ F_HL_PREV(file) = prev_ndx; } if (!prev_name) { int alt_dest; assert(flist != NULL); prev_file = flist->files[prev_ndx - flist->ndx_start]; /* F_HL_PREV() is alt_dest value when DONE && FIRST. */ alt_dest = F_HL_PREV(prev_file); if (DEBUG_GTE(HLINK, 2)) { rprintf(FINFO, "hlink for %d (%s,%d): found flist match (alt %d)\n", ndx, f_name(file, NULL), gnum, alt_dest); } if (alt_dest >= 0 && dry_run) { pathjoin(namebuf, MAXPATHLEN, basis_dir[alt_dest], f_name(prev_file, NULL)); prev_name = namebuf; realname = f_name(prev_file, altbuf); } else { prev_name = f_name(prev_file, namebuf); realname = prev_name; } } } if (DEBUG_GTE(HLINK, 2)) { rprintf(FINFO, "hlink for %d (%s,%d): leader is %d (%s)\n", ndx, f_name(file, NULL), gnum, prev_ndx, prev_name); } if (link_stat(prev_name, &prev_st, 0) < 0) { if (!dry_run || errno != ENOENT) { rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(prev_name)); return -1; } /* A new hard-link will get a new dev & inode, so approximate * those values in dry-run mode by zeroing them. */ memset(&prev_st, 0, sizeof prev_st); } if (statret < 0 && basis_dir[0] != NULL) { /* If we match an alt-dest item, we don't output this as a change. */ char cmpbuf[MAXPATHLEN]; stat_x alt_sx; int j = 0; init_stat_x(&alt_sx); do { pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &alt_sx.st, 0) < 0) continue; if (alt_dest_type == LINK_DEST) { if (prev_st.st_dev != alt_sx.st.st_dev || prev_st.st_ino != alt_sx.st.st_ino) continue; statret = 1; if (stdout_format_has_i == 0 || (!INFO_GTE(NAME, 2) && stdout_format_has_i < 2)) { itemizing = 0; code = FNONE; if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); } break; } if (!quick_check_ok(FT_REG, cmpbuf, file, &alt_sx.st)) continue; statret = 1; if (unchanged_attrs(cmpbuf, file, &alt_sx)) break; } while (basis_dir[++j] != NULL); if (statret == 1) { sxp->st = alt_sx.st; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { free_acl(sxp); if (!ACL_READY(alt_sx)) get_acl(cmpbuf, sxp); else { sxp->acc_acl = alt_sx.acc_acl; sxp->def_acl = alt_sx.def_acl; alt_sx.acc_acl = alt_sx.def_acl = NULL; } } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { free_xattr(sxp); if (!XATTR_READY(alt_sx)) get_xattr(cmpbuf, sxp); else { sxp->xattr = alt_sx.xattr; alt_sx.xattr = NULL; } } #endif } else free_stat_x(&alt_sx); } if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st, realname, itemizing, code) < 0) return -1; if (remove_source_files == 1 && do_xfers) send_msg_success(fname, ndx); return 1; } int hard_link_one(struct file_struct *file, const char *fname, const char *oldname, int terse) { if (do_link(oldname, fname) < 0) { enum logcode code; if (terse) { if (!INFO_GTE(NAME, 1)) return 0; code = FINFO; } else code = FERROR_XFER; rsyserr(code, errno, "link %s => %s failed", full_fname(fname), oldname); return 0; } file->flags |= FLAG_HLINK_DONE; return 1; } void finish_hard_link(struct file_struct *file, const char *fname, int fin_ndx, STRUCT_STAT *stp, int itemizing, enum logcode code, int alt_dest) { stat_x prev_sx; STRUCT_STAT st; char prev_name[MAXPATHLEN], alt_name[MAXPATHLEN]; const char *our_name; struct file_list *flist; int prev_statret, ndx, prev_ndx = F_HL_PREV(file); if (stp == NULL && prev_ndx >= 0) { if (link_stat(fname, &st, 0) < 0 && !dry_run) { rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(fname)); return; } stp = &st; } /* FIRST combined with DONE means we were the first to get done. */ file->flags |= FLAG_HLINK_FIRST | FLAG_HLINK_DONE; F_HL_PREV(file) = alt_dest; if (alt_dest >= 0 && dry_run) { pathjoin(alt_name, MAXPATHLEN, basis_dir[alt_dest], f_name(file, NULL)); our_name = alt_name; } else our_name = fname; init_stat_x(&prev_sx); while ((ndx = prev_ndx) >= 0) { int val; flist = flist_for_ndx(ndx, "finish_hard_link"); file = flist->files[ndx - flist->ndx_start]; file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE; prev_ndx = F_HL_PREV(file); F_HL_PREV(file) = fin_ndx; prev_statret = link_stat(f_name(file, prev_name), &prev_sx.st, 0); val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx, our_name, stp, fname, itemizing, code); flist->in_progress--; free_stat_x(&prev_sx); if (val < 0) continue; if (remove_source_files == 1 && do_xfers) send_msg_success(fname, ndx); } if (inc_recurse) { int gnum = F_HL_GNUM(file); struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, NULL); if (node == NULL) { rprintf(FERROR, "Unable to find a hlink node for %d (%s)\n", gnum, f_name(file, prev_name)); exit_cleanup(RERR_MESSAGEIO); } if (node->data == NULL) { rprintf(FERROR, "Hlink node data for %d is NULL (%s)\n", gnum, f_name(file, prev_name)); exit_cleanup(RERR_MESSAGEIO); } if (CVAL(node->data, 0) != 0) { rprintf(FERROR, "Hlink node data for %d already has path=%s (%s)\n", gnum, (char*)node->data, f_name(file, prev_name)); exit_cleanup(RERR_MESSAGEIO); } free(node->data); node->data = strdup(our_name); } } int skip_hard_link(struct file_struct *file, struct file_list **flist_p) { struct file_list *flist; int prev_ndx; file->flags |= FLAG_SKIP_HLINK; if (!(file->flags & FLAG_HLINK_LAST)) return -1; check_prior(file, F_HL_GNUM(file), &prev_ndx, &flist); if (prev_ndx >= 0) { file = flist->files[prev_ndx - flist->ndx_start]; if (file->flags & (FLAG_HLINK_DONE|FLAG_FILE_SENT)) return -1; file->flags |= FLAG_HLINK_LAST; *flist_p = flist; } return prev_ndx; } #endif rsync-3.2.7/Makefile.in0000664000000000000000000003103214316353744013437 0ustar rootroot# The Makefile for rsync (configure creates it from Makefile.in). prefix=@prefix@ datarootdir=@datarootdir@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@/rsync mandir=@mandir@ with_rrsync=@with_rrsync@ LIBS=@LIBS@ CC=@CC@ AWK=@AWK@ CFLAGS=@CFLAGS@ CPPFLAGS=@CPPFLAGS@ CXX=@CXX@ CXXFLAGS=@CXXFLAGS@ EXEEXT=@EXEEXT@ LDFLAGS=@LDFLAGS@ LIBOBJDIR=lib/ INSTALLCMD=@INSTALL@ INSTALLMAN=@INSTALL@ srcdir=@srcdir@ MKDIR_P=@MKDIR_P@ VPATH=$(srcdir) SHELL=/bin/sh .SUFFIXES: .SUFFIXES: .c .o ROLL_SIMD_x86_64=simd-checksum-x86_64.o ROLL_ASM_x86_64=simd-checksum-avx2.o MD5_ASM_x86_64=lib/md5-asm-x86_64.o GENFILES=configure.sh aclocal.m4 config.h.in rsync.1 rsync.1.html \ rsync-ssl.1 rsync-ssl.1.html rsyncd.conf.5 rsyncd.conf.5.html \ @GEN_RRSYNC@ HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \ lib/pool_alloc.h lib/mdigest.h lib/md-defines.h LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o \ lib/permstring.o lib/pool_alloc.o lib/sysacls.o lib/sysxattrs.o @LIBOBJS@ zlib_OBJS=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \ zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \ util1.o util2.o main.o checksum.o match.o syscall.o log.o backup.o delete.o OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \ usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@ DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ popt/popthelp.o popt/poptparse.o OBJS=$(OBJS1) $(OBJS2) $(OBJS3) $(DAEMON_OBJ) $(LIBOBJ) @BUILD_ZLIB@ @BUILD_POPT@ TLS_OBJ = tls.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/permstring.o lib/sysxattrs.o @BUILD_POPT@ # Programs we must have to run the test cases CHECK_PROGS = rsync$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT) CHECK_SYMLINKS = testsuite/chown-fake.test testsuite/devices-fake.test testsuite/xattrs-hlink.test # Objects for CHECK_PROGS to clean CHECK_OBJS=tls.o testrun.o getgroups.o getfsdev.o t_stub.o t_unsafe.o trimslash.o wildtest.o # note that the -I. is needed to handle config.h when using VPATH .c.o: @OBJ_SAVE@ $(CC) -I. -I$(srcdir) $(CFLAGS) $(CPPFLAGS) -c $< @CC_SHOBJ_FLAG@ @OBJ_RESTORE@ # NOTE: consider running "packaging/smart-make" instead of "make" to auto-handle # any changes to configure.sh and the main Makefile prior to a "make all". all: Makefile rsync$(EXEEXT) stunnel-rsyncd.conf @MAKE_RRSYNC@ @MAKE_MAN@ .PHONY: all .PHONY: install install: all -$(MKDIR_P) $(DESTDIR)$(bindir) $(INSTALLCMD) $(INSTALL_STRIP) -m 755 rsync$(EXEEXT) $(DESTDIR)$(bindir) $(INSTALLCMD) -m 755 $(srcdir)/rsync-ssl $(DESTDIR)$(bindir) -$(MKDIR_P) $(DESTDIR)$(mandir)/man1 -$(MKDIR_P) $(DESTDIR)$(mandir)/man5 if test -f rsync.1; then $(INSTALLMAN) -m 644 rsync.1 $(DESTDIR)$(mandir)/man1; fi if test -f rsync-ssl.1; then $(INSTALLMAN) -m 644 rsync-ssl.1 $(DESTDIR)$(mandir)/man1; fi if test -f rsyncd.conf.5; then $(INSTALLMAN) -m 644 rsyncd.conf.5 $(DESTDIR)$(mandir)/man5; fi if test "$(with_rrsync)" = yes; then \ $(INSTALLCMD) -m 755 rrsync $(DESTDIR)$(bindir); \ if test -f rrsync.1; then $(INSTALLMAN) -m 644 rrsync.1 $(DESTDIR)$(mandir)/man1; fi; \ fi install-ssl-daemon: stunnel-rsyncd.conf -$(MKDIR_P) $(DESTDIR)/etc/stunnel $(INSTALLCMD) -m 644 stunnel-rsyncd.conf $(DESTDIR)/etc/stunnel/rsyncd.conf @if ! ls /etc/rsync-ssl/certs/server.* >/dev/null 2>/dev/null; then \ echo "Note that you'll need to install the certificate used by /etc/stunnel/rsyncd.conf"; \ fi install-all: install install-ssl-daemon install-strip: $(MAKE) INSTALL_STRIP='-s' install rsync$(EXEEXT): $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) rrsync: support/rrsync cp -p $(srcdir)/support/rrsync rrsync $(OBJS): $(HEADERS) $(CHECK_OBJS): $(HEADERS) tls.o xattrs.o: lib/sysxattrs.h usage.o: version.h latest-year.h help-rsync.h help-rsyncd.h git-version.h default-cvsignore.h loadparm.o: default-dont-compress.h daemon-parm.h flist.o: rounding.h default-cvsignore.h default-dont-compress.h: rsync.1.md define-from-md.awk $(AWK) -f $(srcdir)/define-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md help-rsync.h help-rsyncd.h: rsync.1.md help-from-md.awk $(AWK) -f $(srcdir)/help-from-md.awk -v hfile=$@ $(srcdir)/rsync.1.md daemon-parm.h: daemon-parm.txt daemon-parm.awk $(AWK) -f $(srcdir)/daemon-parm.awk $(srcdir)/daemon-parm.txt rounding.h: rounding.c rsync.h proto.h @for r in 0 1 3; do \ if $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o rounding -DEXTRA_ROUNDING=$$r -I. $(srcdir)/rounding.c >rounding.out 2>&1; then \ echo "#define EXTRA_ROUNDING $$r" >rounding.h; \ if test -f "$$HOME/build_farm/build_test.fns"; then \ echo "EXTRA_ROUNDING is $$r" >&2; \ fi; \ break; \ fi; \ done @rm -f rounding @if test -f rounding.h; then : ; else \ cat rounding.out 1>&2; \ echo "Failed to create rounding.h!" 1>&2; \ exit 1; \ fi @rm -f rounding.out git-version.h: ALWAYS_RUN $(srcdir)/mkgitver .PHONY: ALWAYS_RUN ALWAYS_RUN: simd-checksum-x86_64.o: simd-checksum-x86_64.cpp @$(srcdir)/cmd-or-msg disable-roll-simd $(CXX) -I. $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/simd-checksum-x86_64.cpp simd-checksum-avx2.o: simd-checksum-avx2.S @$(srcdir)/cmd-or-msg disable-roll-asm $(CC) $(CFLAGS) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/simd-checksum-avx2.S lib/md5-asm-x86_64.o: lib/md5-asm-x86_64.S lib/md-defines.h @$(srcdir)/cmd-or-msg disable-md5-asm $(CC) -I. @NOEXECSTACK@ -c -o $@ $(srcdir)/lib/md5-asm-x86_64.S tls$(EXEEXT): $(TLS_OBJ) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TLS_OBJ) $(LIBS) testrun$(EXEEXT): testrun.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ testrun.o getgroups$(EXEEXT): getgroups.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getgroups.o $(LIBS) getfsdev$(EXEEXT): getfsdev.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ getfsdev.o $(LIBS) TRIMSLASH_OBJ = trimslash.o syscall.o util2.o t_stub.o lib/compat.o lib/snprintf.o trimslash$(EXEEXT): $(TRIMSLASH_OBJ) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(TRIMSLASH_OBJ) $(LIBS) T_UNSAFE_OBJ = t_unsafe.o syscall.o util1.o util2.o t_stub.o lib/compat.o lib/snprintf.o lib/wildmatch.o t_unsafe$(EXEEXT): $(T_UNSAFE_OBJ) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(T_UNSAFE_OBJ) $(LIBS) .PHONY: conf conf: configure.sh config.h.in .PHONY: gen gen: conf proto.h man git-version.h .PHONY: gensend gensend: gen if ! diff git-version.h $(srcdir)/gists/rsync-git-version.h >/dev/null; then \ ./rsync -ai git-version.h $(srcdir)/gists/rsync-git-version.h && \ (cd $(srcdir)/gists && git commit --allow-empty-message -m '' rsync-git-version.h && git push) ; \ fi rsync -aic $(GENFILES) git-version.h $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/ || true aclocal.m4: $(srcdir)/m4/*.m4 aclocal -I $(srcdir)/m4 configure.sh config.h.in: configure.ac aclocal.m4 @if test -f configure.sh; then cp -p configure.sh configure.sh.old; else touch configure.sh.old; fi @if test -f config.h.in; then cp -p config.h.in config.h.in.old; else touch config.h.in.old; fi autoconf -o configure.sh autoheader && touch config.h.in @if diff configure.sh configure.sh.old >/dev/null 2>&1; then \ echo "configure.sh is unchanged."; \ rm configure.sh.old; \ else \ echo "configure.sh has CHANGED."; \ fi @if diff config.h.in config.h.in.old >/dev/null 2>&1; then \ echo "config.h.in is unchanged."; \ rm config.h.in.old; \ else \ echo "config.h.in has CHANGED."; \ fi @if test -f configure.sh.old || test -f config.h.in.old; then \ if test "$(MAKECMDGOALS)" = reconfigure; then \ echo 'Continuing with "make reconfigure".'; \ else \ echo 'You may need to run:'; \ echo ' make reconfigure'; \ exit 1; \ fi \ fi .PHONY: reconfigure reconfigure: configure.sh ./config.status --recheck ./config.status .PHONY: restatus restatus: ./config.status Makefile: Makefile.in config.status configure.sh config.h.in @if test -f Makefile; then cp -p Makefile Makefile.old; else touch Makefile.old; fi @./config.status @if diff Makefile Makefile.old >/dev/null 2>&1; then \ echo "Makefile is unchanged."; \ rm Makefile.old; \ else \ if test "$(MAKECMDGOALS)" = reconfigure; then \ echo 'Continuing with "make reconfigure".'; \ else \ echo "Makefile updated -- rerun your make command."; \ exit 1; \ fi \ fi stunnel-rsyncd.conf: $(srcdir)/stunnel-rsyncd.conf.in Makefile sed 's;\@bindir\@;$(bindir);g' <$(srcdir)/stunnel-rsyncd.conf.in >stunnel-rsyncd.conf .PHONY: proto proto: proto.h-tstamp proto.h: proto.h-tstamp @if test -f proto.h; then :; else cp -p $(srcdir)/proto.h .; fi proto.h-tstamp: $(srcdir)/*.c $(srcdir)/lib/compat.c daemon-parm.h $(AWK) -f $(srcdir)/mkproto.awk $(srcdir)/*.c $(srcdir)/lib/compat.c daemon-parm.h .PHONY: man man: rsync.1 rsync-ssl.1 rsyncd.conf.5 @MAKE_RRSYNC_1@ rsync.1: rsync.1.md md-convert version.h Makefile @$(srcdir)/maybe-make-man rsync.1.md rsync-ssl.1: rsync-ssl.1.md md-convert version.h Makefile @$(srcdir)/maybe-make-man rsync-ssl.1.md rsyncd.conf.5: rsyncd.conf.5.md md-convert version.h Makefile @$(srcdir)/maybe-make-man rsyncd.conf.5.md rrsync.1: support/rrsync.1.md md-convert Makefile @$(srcdir)/maybe-make-man support/rrsync.1.md .PHONY: clean clean: cleantests rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) @MAKE_RRSYNC@ \ git-version.h rounding rounding.h *.old rsync*.1 rsync*.5 @MAKE_RRSYNC_1@ \ *.html daemon-parm.h help-*.h default-*.h proto.h proto.h-tstamp .PHONY: cleantests cleantests: rm -rf ./testtmp* # We try to delete built files from both the source and build # directories, just in case somebody previously configured things in # the source directory. .PHONY: distclean distclean: clean for dir in $(srcdir) . ; do \ (cd "$$dir" && rm -rf Makefile config.h config.status stunnel-rsyncd.conf \ lib/dummy popt/dummy zlib/dummy config.cache config.log shconfig \ $(GENFILES) autom4te.cache) ; \ done # this target is really just for my use. It only works on a limited # range of machines and is used to produce a list of potentially # dead (ie. unused) functions in the code. (tridge) .PHONY: finddead finddead: nm *.o */*.o |grep 'U ' | awk '{print $$2}' | sort -u > nmused.txt nm *.o */*.o |grep 'T ' | awk '{print $$3}' | sort -u > nmfns.txt comm -13 nmused.txt nmfns.txt @rm nmused.txt nmfns.txt # 'check' is the GNU name, 'test' is the name for everybody else :-) .PHONY: test test: check # There seems to be no standard way to specify some variables as # exported from a Makefile apart from listing them like this. # This depends on building rsync; if we need any helper programs it # should depend on them too. # We try to run the scripts with POSIX mode on, in the hope that will # catch Bash-isms earlier even if we're running on GNU. Of course, we # might lose in the future where POSIX diverges from old sh. .PHONY: check check: all $(CHECK_PROGS) $(CHECK_SYMLINKS) rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh .PHONY: check29 check29: all $(CHECK_PROGS) $(CHECK_SYMLINKS) rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=29 .PHONY: check30 check30: all $(CHECK_PROGS) $(CHECK_SYMLINKS) rsync_bin=`pwd`/rsync$(EXEEXT) $(srcdir)/runtests.sh --protocol=30 wildtest.o: wildtest.c t_stub.o lib/wildmatch.c rsync.h config.h wildtest$(EXEEXT): wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ wildtest.o lib/compat.o lib/snprintf.o @BUILD_POPT@ $(LIBS) testsuite/chown-fake.test: ln -s chown.test $(srcdir)/testsuite/chown-fake.test testsuite/devices-fake.test: ln -s devices.test $(srcdir)/testsuite/devices-fake.test testsuite/xattrs-hlink.test: ln -s xattrs.test $(srcdir)/testsuite/xattrs-hlink.test # This does *not* depend on building or installing: you can use it to # check a version installed from a binary or some other source tree, # if you want. .PHONY: installcheck installcheck: $(CHECK_PROGS) $(CHECK_SYMLINKS) POSIXLY_CORRECT=1 TOOLDIR=`pwd` rsync_bin="$(bindir)/rsync$(EXEEXT)" srcdir="$(srcdir)" $(srcdir)/runtests.sh # TODO: Add 'dist' target; need to know which files will be included # Run the SPLINT (Secure Programming Lint) tool. .PHONY: splint splint: splint +unixlib +gnuextensions -weak rsync.c .PHONY: doxygen doxygen: cd $(srcdir) && rm dox/html/* && doxygen # for maintainers only .PHONY: doxygen-upload doxygen-upload: rsync -avzv $(srcdir)/dox/html/ --delete \ $${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/ rsync-3.2.7/batch.c0000664000000000000000000001757614276226634012642 0ustar rootroot/* * Support for the batch-file options. * * Copyright (C) 1999 Weiss * Copyright (C) 2004 Chris Shoemaker * Copyright (C) 2004-2022 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 #include extern int eol_nulls; extern int recurse; extern int xfer_dirs; extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_uid; extern int preserve_gid; extern int preserve_acls; extern int preserve_xattrs; extern int always_checksum; extern int do_compression; extern int inplace; extern int append_mode; extern int write_batch; extern int protocol_version; extern int raw_argc, cooked_argc; extern char **raw_argv, **cooked_argv; extern char *batch_name; #ifdef ICONV_OPTION extern char *iconv_opt; #endif extern filter_rule_list filter_list; int batch_fd = -1; int batch_sh_fd = -1; int batch_stream_flags; static int tweaked_append; static int tweaked_append_verify; static int tweaked_iconv; static int *flag_ptr[] = { &recurse, /* 0 */ &preserve_uid, /* 1 */ &preserve_gid, /* 2 */ &preserve_links, /* 3 */ &preserve_devices, /* 4 */ &preserve_hard_links, /* 5 */ &always_checksum, /* 6 */ &xfer_dirs, /* 7 (protocol 29) */ &do_compression, /* 8 (protocol 29) */ &tweaked_iconv, /* 9 (protocol 30) */ &preserve_acls, /* 10 (protocol 30) */ &preserve_xattrs, /* 11 (protocol 30) */ &inplace, /* 12 (protocol 30) */ &tweaked_append, /* 13 (protocol 30) */ &tweaked_append_verify, /* 14 (protocol 30) */ NULL }; static char *flag_name[] = { "--recurse (-r)", "--owner (-o)", "--group (-g)", "--links (-l)", "--devices (-D)", "--hard-links (-H)", "--checksum (-c)", "--dirs (-d)", "--compress (-z)", "--iconv", "--acls (-A)", "--xattrs (-X)", "--inplace", "--append", "--append-verify", NULL }; void write_stream_flags(int fd) { int i, flags; tweaked_append = append_mode == 1; tweaked_append_verify = append_mode == 2; #ifdef ICONV_OPTION tweaked_iconv = iconv_opt != NULL; #endif /* Start the batch file with a bitmap of data-stream-affecting * flags. */ for (i = 0, flags = 0; flag_ptr[i]; i++) { if (*flag_ptr[i]) flags |= 1 << i; } write_int(fd, flags); } void read_stream_flags(int fd) { batch_stream_flags = read_int(fd); } void check_batch_flags(void) { int i; if (protocol_version < 29) flag_ptr[7] = NULL; else if (protocol_version < 30) flag_ptr[9] = NULL; tweaked_append = append_mode == 1; tweaked_append_verify = append_mode == 2; #ifdef ICONV_OPTION tweaked_iconv = iconv_opt != NULL; #endif for (i = 0; flag_ptr[i]; i++) { int set = batch_stream_flags & (1 << i) ? 1 : 0; if (*flag_ptr[i] != set) { if (i == 9) { rprintf(FERROR, "%s specify the --iconv option to use this batch file.\n", set ? "Please" : "Do not"); exit_cleanup(RERR_SYNTAX); } if (INFO_GTE(MISC, 1)) { rprintf(FINFO, "%sing the %s option to match the batchfile.\n", set ? "Sett" : "Clear", flag_name[i]); } *flag_ptr[i] = set; } } if (protocol_version < 29) { if (recurse) xfer_dirs |= 1; else if (xfer_dirs < 2) xfer_dirs = 0; } if (tweaked_append) append_mode = 1; else if (tweaked_append_verify) append_mode = 2; } static int write_arg(const char *arg) { const char *x, *s; int len, err = 0; if (*arg == '-' && (x = strchr(arg, '=')) != NULL) { err |= write(batch_sh_fd, arg, x - arg + 1) != x - arg + 1; arg += x - arg + 1; } if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) { err |= write(batch_sh_fd, "'", 1) != 1; for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) { err |= write(batch_sh_fd, s, x - s + 1) != x - s + 1; err |= write(batch_sh_fd, "'", 1) != 1; } len = strlen(s); err |= write(batch_sh_fd, s, len) != len; err |= write(batch_sh_fd, "'", 1) != 1; return err; } len = strlen(arg); err |= write(batch_sh_fd, arg, len) != len; return err; } /* Writes out a space and then an option (or other string) with an optional "=" + arg suffix. */ static int write_opt(const char *opt, const char *arg) { int len = strlen(opt); int err = write(batch_sh_fd, " ", 1) != 1; err = write(batch_sh_fd, opt, len) != len ? 1 : 0; if (arg) { err |= write(batch_sh_fd, "=", 1) != 1; err |= write_arg(arg); } return err; } static void write_filter_rules(int fd) { filter_rule *ent; write_sbuf(fd, " <<'#E#'\n"); for (ent = filter_list.head; ent; ent = ent->next) { unsigned int plen; char *p = get_rule_prefix(ent, "- ", 0, &plen); write_buf(fd, p, plen); write_sbuf(fd, ent->pattern); if (ent->rflags & FILTRULE_DIRECTORY) write_byte(fd, '/'); write_byte(fd, eol_nulls ? 0 : '\n'); } if (eol_nulls) write_sbuf(fd, ";\n"); write_sbuf(fd, "#E#"); } /* This sets batch_fd and (for --write-batch) batch_sh_fd. */ void open_batch_files(void) { if (write_batch) { char filename[MAXPATHLEN]; stringjoin(filename, sizeof filename, batch_name, ".sh", NULL); batch_sh_fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); if (batch_sh_fd < 0) { rsyserr(FERROR, errno, "Batch file %s open error", full_fname(filename)); exit_cleanup(RERR_FILESELECT); } batch_fd = do_open(batch_name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); } else if (strcmp(batch_name, "-") == 0) batch_fd = STDIN_FILENO; else batch_fd = do_open(batch_name, O_RDONLY, S_IRUSR | S_IWUSR); if (batch_fd < 0) { rsyserr(FERROR, errno, "Batch file %s open error", full_fname(batch_name)); exit_cleanup(RERR_FILEIO); } } /* This routine tries to write out an equivalent --read-batch command * given the user's --write-batch args. However, it doesn't really * understand most of the options, so it uses some overly simple * heuristics to munge the command line into something that will * (hopefully) work. */ void write_batch_shell_file(void) { int i, j, len, err = 0; char *p, *p2; /* Write argvs info to BATCH.sh file */ err |= write_arg(raw_argv[0]); if (filter_list.head) { if (protocol_version >= 29) err |= write_opt("--filter", "._-"); else err |= write_opt("--exclude-from", "-"); } /* Elide the filename args from the option list, but scan for them in reverse. */ for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) { if (strcmp(raw_argv[i], cooked_argv[j]) == 0) { raw_argv[i] = NULL; j--; } } for (i = 1; i < raw_argc; i++) { if (!(p = raw_argv[i])) continue; if (strncmp(p, "--files-from", 12) == 0 || strncmp(p, "--filter", 8) == 0 || strncmp(p, "--include", 9) == 0 || strncmp(p, "--exclude", 9) == 0) { if (strchr(p, '=') == NULL) i++; continue; } if (strcmp(p, "-f") == 0) { i++; continue; } if (strncmp(p, "--write-batch", len = 13) == 0 || strncmp(p, "--only-write-batch", len = 18) == 0) err |= write_opt("--read-batch", p[len] == '=' ? p + len + 1 : NULL); else { err |= write(batch_sh_fd, " ", 1) != 1; err |= write_arg(p); } } if (!(p = check_for_hostspec(cooked_argv[cooked_argc - 1], &p2, &i))) p = cooked_argv[cooked_argc - 1]; err |= write_opt("${1:-", NULL); err |= write_arg(p); err |= write(batch_sh_fd, "}", 1) != 1; if (filter_list.head) write_filter_rules(batch_sh_fd); if (write(batch_sh_fd, "\n", 1) != 1 || close(batch_sh_fd) < 0 || err) { rsyserr(FERROR, errno, "Batch file %s.sh write error", batch_name); exit_cleanup(RERR_FILEIO); } batch_sh_fd = -1; } rsync-3.2.7/prepare-source.mak0000664000000000000000000000034713710675312015020 0ustar rootrootSHELL=/bin/sh conf: configure.sh config.h.in .PHONY: conf aclocal.m4: m4/*.m4 aclocal -I m4 configure.sh: configure.ac aclocal.m4 autoconf -o configure.sh config.h.in: configure.ac aclocal.m4 autoheader && touch config.h.in rsync-3.2.7/compat.c0000664000000000000000000006274614307154751013036 0ustar rootroot/* * Compatibility routines for older rsync protocol versions. * * Copyright (C) Andrew Tridgell 1996 * Copyright (C) Paul Mackerras 1996 * Copyright (C) 2004-2022 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 "itypes.h" #include "ifuncs.h" extern int am_server; extern int am_sender; extern int local_server; extern int inplace; extern int recurse; extern int use_qsort; extern int allow_inc_recurse; extern int preallocate_files; extern int append_mode; extern int fuzzy_basis; extern int read_batch; extern int write_batch; extern int delay_updates; extern int checksum_seed; extern int basis_dir_cnt; extern int prune_empty_dirs; extern int protocol_version; extern int protect_args; extern int preserve_uid; extern int preserve_gid; extern int preserve_atimes; extern int preserve_crtimes; extern int preserve_acls; extern int preserve_xattrs; extern int xfer_flags_as_varint; extern int need_messages_from_generator; extern int delete_mode, delete_before, delete_during, delete_after; extern int do_compression; extern int do_compression_level; extern int saw_stderr_opt; extern int msgs2stderr; extern char *shell_cmd; extern char *partial_dir; extern char *files_from; extern char *filesfrom_host; extern const char *checksum_choice; extern const char *compress_choice; extern char *daemon_auth_choices; extern filter_rule_list filter_list; extern int need_unsorted_flist; #ifdef ICONV_OPTION extern iconv_t ic_send, ic_recv; extern char *iconv_opt; #endif extern struct name_num_obj valid_checksums, valid_auth_checksums; extern struct name_num_item *xfer_sum_nni; int remote_protocol = 0; int file_extra_cnt = 0; /* count of file-list extras that everyone gets */ int inc_recurse = 0; int compat_flags = 0; int use_safe_inc_flist = 0; int want_xattr_optim = 0; int proper_seed_order = 0; int inplace_partial = 0; int do_negotiated_strings = 0; int xmit_id0_names = 0; struct name_num_item *xattr_sum_nni; int xattr_sum_len = 0; /* These index values are for the file-list's extra-attribute array. */ int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ int sender_symlink_iconv = 0; /* sender should convert symlink content */ #ifdef ICONV_OPTION int filesfrom_convert = 0; #endif #define MAX_NSTR_STRLEN 256 struct name_num_item valid_compressions_items[] = { #ifdef SUPPORT_ZSTD { CPRES_ZSTD, 0, "zstd", NULL }, #endif #ifdef SUPPORT_LZ4 { CPRES_LZ4, 0, "lz4", NULL }, #endif { CPRES_ZLIBX, 0, "zlibx", NULL }, { CPRES_ZLIB, 0, "zlib", NULL }, { CPRES_NONE, 0, "none", NULL }, { 0, 0, NULL, NULL } }; struct name_num_obj valid_compressions = { "compress", NULL, 0, 0, valid_compressions_items }; #define CF_INC_RECURSE (1<<0) #define CF_SYMLINK_TIMES (1<<1) #define CF_SYMLINK_ICONV (1<<2) #define CF_SAFE_FLIST (1<<3) #define CF_AVOID_XATTR_OPTIM (1<<4) #define CF_CHKSUM_SEED_FIX (1<<5) #define CF_INPLACE_PARTIAL_DIR (1<<6) #define CF_VARINT_FLIST_FLAGS (1<<7) #define CF_ID0_NAMES (1<<8) static const char *client_info; /* The server makes sure that if either side only supports a pre-release * version of a protocol, that both sides must speak a compatible version * of that protocol for it to be advertised as available. */ static void check_sub_protocol(void) { char *dot; int their_protocol, their_sub; int our_sub = get_subprotocol_version(); /* client_info starts with VER.SUB string if client is a pre-release. */ if (!(their_protocol = atoi(client_info)) || !(dot = strchr(client_info, '.')) || !(their_sub = atoi(dot+1))) { #if SUBPROTOCOL_VERSION != 0 if (our_sub) protocol_version--; #endif return; } if (their_protocol < protocol_version) { if (their_sub) protocol_version = their_protocol - 1; return; } if (their_protocol > protocol_version) their_sub = 0; /* 0 == final version of older protocol */ if (their_sub != our_sub) protocol_version--; } void set_allow_inc_recurse(void) { if (!local_server) client_info = shell_cmd ? shell_cmd : ""; else if (am_server) { char buf[64]; maybe_add_e_option(buf, sizeof buf); client_info = *buf ? strdup(buf+1) : ""; /* The +1 skips the leading "e". */ } if (!recurse || use_qsort) allow_inc_recurse = 0; else if (!am_sender && (delete_before || delete_after || delay_updates || prune_empty_dirs)) allow_inc_recurse = 0; else if (am_server && strchr(client_info, 'i') == NULL) allow_inc_recurse = 0; } void parse_compress_choice(int final_call) { if (valid_compressions.negotiated_nni) do_compression = valid_compressions.negotiated_nni->num; else if (compress_choice) { struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1); if (!nni) { rprintf(FERROR, "unknown compress name: %s\n", compress_choice); exit_cleanup(RERR_UNSUPPORTED); } do_compression = nni->num; if (am_server) validate_choice_vs_env(NSTR_COMPRESS, do_compression, -1); } else if (do_compression) do_compression = CPRES_ZLIB; else do_compression = CPRES_NONE; if (do_compression != CPRES_NONE && final_call) init_compression_level(); /* There's a chance this might turn compression off! */ if (do_compression == CPRES_NONE) compress_choice = NULL; /* Snag the compression name for both write_batch's option output & the following debug output. */ if (valid_compressions.negotiated_nni) compress_choice = valid_compressions.negotiated_nni->name; else if (compress_choice == NULL) { struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression); compress_choice = nni ? nni->name : "UNKNOWN"; } if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1) && (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) { rprintf(FINFO, "%s%s compress: %s (level %d)\n", am_server ? "Server" : "Client", valid_compressions.negotiated_nni ? " negotiated" : "", compress_choice, do_compression_level); } } struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len) { struct name_num_item *nni; if (len < 0) len = strlen(name); for (nni = nno->list; nni->name; nni++) { if (nni->num == CSUM_gone) continue; if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0') return nni; } return NULL; } struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num) { struct name_num_item *nni; for (nni = nno->list; nni->name; nni++) { if (num == nni->num) return nni; } return NULL; } static void init_nno_saw(struct name_num_obj *nno, int val) { struct name_num_item *nni; int cnt; if (!nno->saw_len) { for (nni = nno->list; nni->name; nni++) { if (nni->num >= nno->saw_len) nno->saw_len = nni->num + 1; } } if (!nno->saw) { nno->saw = new_array0(uchar, nno->saw_len); /* We'll take this opportunity to set the main_nni values for duplicates. */ for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) { if (nni->num == CSUM_gone) continue; if (nno->saw[nni->num]) nni->main_nni = &nno->list[nno->saw[nni->num]-1]; else nno->saw[nni->num] = cnt; } } memset(nno->saw, val, nno->saw_len); } /* Simplify the user-provided string so that it contains valid names without any duplicates. * It also sets the "saw" flags to a 1-relative count of which name was seen first. */ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len) { char *to = tobuf, *tok = NULL; int saw_tok = 0, cnt = 0; while (1) { int at_space = isSpace(from); char ch = *from++; if (ch == '&') ch = '\0'; if (!ch || at_space) { if (tok) { struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok); if (nni && !nno->saw[nni->num]) { nno->saw[nni->num] = ++cnt; if (nni->main_nni) { to = tok + strlcpy(tok, nni->main_nni->name, tobuf_len - (tok - tobuf)); if (to - tobuf >= tobuf_len) { to = tok - 1; break; } } } else to = tok - (tok != tobuf); saw_tok = 1; tok = NULL; } if (!ch) break; continue; } if (!tok) { if (to != tobuf) *to++ = ' '; tok = to; } if (to - tobuf >= tobuf_len - 1) { to = tok - (tok != tobuf); break; } *to++ = ch; } *to = '\0'; if (saw_tok && to == tobuf) return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN); return to - tobuf; } static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf) { struct name_num_item *nni, *ret = NULL; int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */ char *space, *tok = tmpbuf; while (tok) { while (*tok == ' ') tok++; /* Should be unneeded... */ if (!*tok) break; if ((space = strchr(tok, ' ')) != NULL) *space = '\0'; nni = get_nni_by_name(nno, tok, -1); if (space) { *space = ' '; tok = space + 1; } else tok = NULL; if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num]) continue; ret = nni; best = nno->saw[nni->num]; if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */ break; } if (ret) { free(nno->saw); nno->saw = NULL; nno->negotiated_nni = ret->main_nni ? ret->main_nni : ret; return 1; } return 0; } /* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the * buffer may be pre-populated with a "len" length string to use OR a len of -1 * to tell us to read a string from the fd. */ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len) { if (len < 0) len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN); if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) { if (am_server) rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf); else rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf); } if (len > 0 && parse_negotiate_str(nno, tmpbuf)) return; if (!am_server || !do_negotiated_strings) { char *cp = tmpbuf; int j; rprintf(FERROR, "Failed to negotiate a %s choice.\n", nno->type); rprintf(FERROR, "%s list: %s\n", am_server ? "Client" : "Server", tmpbuf); /* Recreate our original list from the saw values. This can't overflow our huge * buffer because we don't have enough valid entries to get anywhere close. */ for (j = 1, *cp = '\0'; j <= nno->saw_len; j++) { struct name_num_item *nni; for (nni = nno->list; nni->name; nni++) { if (nno->saw[nni->num] == j) { *cp++ = ' '; cp += strlcpy(cp, nni->name, MAX_NSTR_STRLEN - (cp - tmpbuf)); break; } } } if (!*tmpbuf) strlcpy(cp, " INVALID", MAX_NSTR_STRLEN); rprintf(FERROR, "%s list:%s\n", am_server ? "Server" : "Client", tmpbuf); } exit_cleanup(RERR_UNSUPPORTED); } static const char *getenv_nstr(int ntype) { const char *env_str = getenv(ntype == NSTR_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST"); /* When writing a batch file, we always negotiate an old-style choice. */ if (write_batch) env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4"; if (am_server && env_str) { char *cp = strchr(env_str, '&'); if (cp) env_str = cp + 1; } return env_str; } void validate_choice_vs_env(int ntype, int num1, int num2) { struct name_num_obj *nno = ntype == NSTR_COMPRESS ? &valid_compressions : &valid_checksums; const char *list_str = getenv_nstr(ntype); char tmpbuf[MAX_NSTR_STRLEN]; if (!list_str) return; while (isSpace(list_str)) list_str++; if (!*list_str) return; init_nno_saw(nno, 0); parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); if (ntype == NSTR_CHECKSUM) /* If "md4" is in the env list, all the old MD4 choices are OK too. */ nno->saw[CSUM_MD4_ARCHAIC] = nno->saw[CSUM_MD4_BUSTED] = nno->saw[CSUM_MD4_OLD] = nno->saw[CSUM_MD4]; if (!nno->saw[num1] || (num2 >= 0 && !nno->saw[num2])) { rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n", ntype == NSTR_COMPRESS ? "compress" : "checksum", ntype == NSTR_COMPRESS ? compress_choice : checksum_choice); exit_cleanup(RERR_UNSUPPORTED); } free(nno->saw); nno->saw = NULL; } /* The saw buffer is initialized and used to store ordinal values from 1 to N * for the order of the args in the array. If dup_markup == '\0', duplicates * are removed otherwise the char is prefixed to the duplicate term and, if it * is an opening paren/bracket/brace, the matching closing char is suffixed. * "none" is removed on the client side unless dup_markup != '\0'. */ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, char dup_markup) { struct name_num_item *nni; int len = 0, cnt = 0; char delim = '\0', post_delim; switch (dup_markup) { case '(': post_delim = ')'; break; case '[': post_delim = ']'; break; case '{': post_delim = '}'; break; default: post_delim = '\0'; break; } init_nno_saw(nno, 0); for (nni = nno->list, len = 0; nni->name; nni++) { if (nni->num == CSUM_gone) continue; if (nni->main_nni) { if (!dup_markup || nni->main_nni->num == CSUM_gone) continue; delim = dup_markup; } if (nni->num == 0 && !am_server && !dup_markup) continue; if (len) to_buf[len++]= ' '; if (delim) { to_buf[len++]= delim; delim = post_delim; } len += strlcpy(to_buf+len, nni->name, to_buf_len - len); if (len >= to_buf_len - 3) exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE... */ if (delim) { to_buf[len++]= delim; delim = '\0'; } nno->saw[nni->num] = ++cnt; } return len; } static void send_negotiate_str(int f_out, struct name_num_obj *nno, int ntype) { char tmpbuf[MAX_NSTR_STRLEN]; const char *list_str = getenv_nstr(ntype); int len; if (list_str && *list_str) { init_nno_saw(nno, 0); len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); list_str = tmpbuf; } else list_str = NULL; if (!list_str || !*list_str) len = get_default_nno_list(nno, tmpbuf, MAX_NSTR_STRLEN, '\0'); if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) { if (am_server) rprintf(FINFO, "Server %s list (on server): %s\n", nno->type, tmpbuf); else rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf); } /* Each side sends their list of valid names to the other side and then both sides * pick the first name in the client's list that is also in the server's list. */ if (do_negotiated_strings) write_vstring(f_out, tmpbuf, len); } static void negotiate_the_strings(int f_in, int f_out) { /* We send all the negotiation strings before we start to read them to help avoid a slow startup. */ init_checksum_choices(); if (!checksum_choice) send_negotiate_str(f_out, &valid_checksums, NSTR_CHECKSUM); if (do_compression && !compress_choice) send_negotiate_str(f_out, &valid_compressions, NSTR_COMPRESS); if (valid_checksums.saw) { char tmpbuf[MAX_NSTR_STRLEN]; int len; if (do_negotiated_strings) len = -1; else len = strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN); recv_negotiate_str(f_in, &valid_checksums, tmpbuf, len); } if (valid_compressions.saw) { char tmpbuf[MAX_NSTR_STRLEN]; int len; if (do_negotiated_strings) len = -1; else len = strlcpy(tmpbuf, "zlib", MAX_NSTR_STRLEN); recv_negotiate_str(f_in, &valid_compressions, tmpbuf, len); } /* If the other side is too old to negotiate, the above steps just made sure that * the env didn't disallow the old algorithm. Mark things as non-negotiated. */ if (!do_negotiated_strings) valid_checksums.negotiated_nni = valid_compressions.negotiated_nni = NULL; } void setup_protocol(int f_out,int f_in) { assert(file_extra_cnt == 0); assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1); /* All int64 values must be set first so that they are guaranteed to be * aligned for direct int64-pointer memory access. */ if (preserve_atimes) atimes_ndx = (file_extra_cnt += EXTRA64_CNT); if (preserve_crtimes) crtimes_ndx = (file_extra_cnt += EXTRA64_CNT); if (am_sender) /* This is most likely in the file_extras64 union as well. */ pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT); else depth_ndx = ++file_extra_cnt; if (preserve_uid) uid_ndx = ++file_extra_cnt; if (preserve_gid) gid_ndx = ++file_extra_cnt; if (preserve_acls && !am_sender) acls_ndx = ++file_extra_cnt; if (preserve_xattrs) xattrs_ndx = ++file_extra_cnt; if (am_server) set_allow_inc_recurse(); if (remote_protocol == 0) { if (am_server && !local_server) check_sub_protocol(); if (!read_batch) write_int(f_out, protocol_version); remote_protocol = read_int(f_in); if (protocol_version > remote_protocol) protocol_version = remote_protocol; } if (read_batch && remote_protocol > protocol_version) { rprintf(FERROR, "The protocol version in the batch file is too new (%d > %d).\n", remote_protocol, protocol_version); exit_cleanup(RERR_PROTOCOL); } if (DEBUG_GTE(PROTO, 1)) { rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n", am_server? "Server" : "Client", remote_protocol, protocol_version); } if (remote_protocol < MIN_PROTOCOL_VERSION || remote_protocol > MAX_PROTOCOL_VERSION) { rprintf(FERROR,"protocol version mismatch -- is your shell clean?\n"); rprintf(FERROR,"(see the rsync manpage for an explanation)\n"); exit_cleanup(RERR_PROTOCOL); } if (remote_protocol < OLD_PROTOCOL_VERSION) { rprintf(FINFO,"%s is very old version of rsync, upgrade recommended.\n", am_server? "Client" : "Server"); } if (protocol_version < MIN_PROTOCOL_VERSION) { rprintf(FERROR, "--protocol must be at least %d on the %s.\n", MIN_PROTOCOL_VERSION, am_server? "Server" : "Client"); exit_cleanup(RERR_PROTOCOL); } if (protocol_version > PROTOCOL_VERSION) { rprintf(FERROR, "--protocol must be no more than %d on the %s.\n", PROTOCOL_VERSION, am_server? "Server" : "Client"); exit_cleanup(RERR_PROTOCOL); } if (read_batch) check_batch_flags(); if (!saw_stderr_opt && protocol_version <= 28 && am_server) msgs2stderr = 0; /* The client side may not have stderr setup for us. */ #ifndef SUPPORT_PREALLOCATION if (preallocate_files && !am_sender) { rprintf(FERROR, "preallocation is not supported on this %s\n", am_server ? "Server" : "Client"); exit_cleanup(RERR_SYNTAX); } #endif if (protocol_version < 30) { if (append_mode == 1) append_mode = 2; if (preserve_acls && !local_server) { rprintf(FERROR, "--acls requires protocol 30 or higher" " (negotiated %d).\n", protocol_version); exit_cleanup(RERR_PROTOCOL); } if (preserve_xattrs && !local_server) { rprintf(FERROR, "--xattrs requires protocol 30 or higher" " (negotiated %d).\n", protocol_version); exit_cleanup(RERR_PROTOCOL); } } if (delete_mode && !(delete_before+delete_during+delete_after)) { if (protocol_version < 30) delete_before = 1; else delete_during = 1; } if (protocol_version < 29) { if (fuzzy_basis) { rprintf(FERROR, "--fuzzy requires protocol 29 or higher" " (negotiated %d).\n", protocol_version); exit_cleanup(RERR_PROTOCOL); } if (basis_dir_cnt && inplace) { rprintf(FERROR, "%s with --inplace requires protocol 29 or higher" " (negotiated %d).\n", alt_dest_opt(0), protocol_version); exit_cleanup(RERR_PROTOCOL); } if (basis_dir_cnt > 1) { rprintf(FERROR, "Using more than one %s option requires protocol" " 29 or higher (negotiated %d).\n", alt_dest_opt(0), protocol_version); exit_cleanup(RERR_PROTOCOL); } if (prune_empty_dirs) { rprintf(FERROR, "--prune-empty-dirs requires protocol 29 or higher" " (negotiated %d).\n", protocol_version); exit_cleanup(RERR_PROTOCOL); } } else if (protocol_version >= 30) { if (am_server) { compat_flags = allow_inc_recurse ? CF_INC_RECURSE : 0; #ifdef CAN_SET_SYMLINK_TIMES compat_flags |= CF_SYMLINK_TIMES; #endif #ifdef ICONV_OPTION compat_flags |= CF_SYMLINK_ICONV; #endif if (strchr(client_info, 'f') != NULL) compat_flags |= CF_SAFE_FLIST; if (strchr(client_info, 'x') != NULL) compat_flags |= CF_AVOID_XATTR_OPTIM; if (strchr(client_info, 'C') != NULL) compat_flags |= CF_CHKSUM_SEED_FIX; if (strchr(client_info, 'I') != NULL) compat_flags |= CF_INPLACE_PARTIAL_DIR; if (strchr(client_info, 'u') != NULL) compat_flags |= CF_ID0_NAMES; if (strchr(client_info, 'v') != NULL) { do_negotiated_strings = 1; compat_flags |= CF_VARINT_FLIST_FLAGS; } if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */ if (!write_batch) compat_flags |= CF_VARINT_FLIST_FLAGS; write_byte(f_out, compat_flags); } else write_varint(f_out, compat_flags); } else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */ compat_flags = read_varint(f_in); if (compat_flags & CF_VARINT_FLIST_FLAGS) do_negotiated_strings = 1; } /* The inc_recurse var MUST be set to 0 or 1. */ inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0; want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM); proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0; xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0; xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0; if (!xfer_flags_as_varint && preserve_crtimes) { fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n"); exit_cleanup(RERR_PROTOCOL); } if (am_sender) { receiver_symlink_times = am_server ? strchr(client_info, 'L') != NULL : !!(compat_flags & CF_SYMLINK_TIMES); } #ifdef CAN_SET_SYMLINK_TIMES else receiver_symlink_times = 1; #endif #ifdef ICONV_OPTION sender_symlink_iconv = iconv_opt && (am_server ? strchr(client_info, 's') != NULL : !!(compat_flags & CF_SYMLINK_ICONV)); #endif if (inc_recurse && !allow_inc_recurse) { /* This should only be able to happen in a batch. */ fprintf(stderr, "Incompatible options specified for inc-recursive %s.\n", read_batch ? "batch file" : "connection"); exit_cleanup(RERR_SYNTAX); } use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31; need_messages_from_generator = 1; if (compat_flags & CF_INPLACE_PARTIAL_DIR) inplace_partial = 1; #ifdef CAN_SET_SYMLINK_TIMES } else if (!am_sender) { receiver_symlink_times = 1; #endif } if (read_batch) do_negotiated_strings = 0; if (need_unsorted_flist && (!am_sender || inc_recurse)) unsort_ndx = ++file_extra_cnt; if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) { int rflags = FILTRULE_NO_PREFIXES | FILTRULE_DIRECTORY; if (!am_sender || protocol_version >= 30) rflags |= FILTRULE_PERISHABLE; parse_filter_str(&filter_list, partial_dir, rule_template(rflags), 0); } #ifdef ICONV_OPTION if (protect_args && files_from) { if (am_sender) filesfrom_convert = filesfrom_host && ic_send != (iconv_t)-1; else filesfrom_convert = !filesfrom_host && ic_recv != (iconv_t)-1; } #endif negotiate_the_strings(f_in, f_out); if (am_server) { if (!checksum_seed) checksum_seed = time(NULL) ^ (getpid() << 6); write_int(f_out, checksum_seed); } else { checksum_seed = read_int(f_in); } parse_checksum_choice(1); /* Sets file_sum_nni & xfer_sum_nni */ parse_compress_choice(1); /* Sets do_compression */ /* TODO in the future allow this algorithm to be chosen somehow, but it can't get too * long or the size starts to cause a problem in the xattr abbrev/non-abbrev code. */ xattr_sum_nni = parse_csum_name(NULL, 0); xattr_sum_len = csum_len_for_type(xattr_sum_nni->num, 0); if (write_batch && !am_server) write_batch_shell_file(); init_flist(); } void output_daemon_greeting(int f_out, int am_client) { char tmpbuf[MAX_NSTR_STRLEN]; int our_sub = get_subprotocol_version(); get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0'); io_printf(f_out, "@RSYNCD: %d.%d %s\n", protocol_version, our_sub, tmpbuf); if (am_client && DEBUG_GTE(NSTR, 2)) rprintf(FINFO, "Client %s list (on client): %s\n", valid_auth_checksums.type, tmpbuf); } void negotiate_daemon_auth(int f_out, int am_client) { char tmpbuf[MAX_NSTR_STRLEN]; int save_am_server = am_server; int md4_is_old = 0; if (!am_client) am_server = 1; if (daemon_auth_choices) strlcpy(tmpbuf, daemon_auth_choices, MAX_NSTR_STRLEN); else { strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN); md4_is_old = 1; } if (am_client) { recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf)); if (DEBUG_GTE(NSTR, 1)) { rprintf(FINFO, "Client negotiated %s: %s\n", valid_auth_checksums.type, valid_auth_checksums.negotiated_nni->name); } } else { if (!parse_negotiate_str(&valid_auth_checksums, tmpbuf)) { get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0'); io_printf(f_out, "@ERROR: your client does not support one of our daemon-auth checksums: %s\n", tmpbuf); exit_cleanup(RERR_UNSUPPORTED); } } am_server = save_am_server; if (md4_is_old && valid_auth_checksums.negotiated_nni->num == CSUM_MD4) valid_auth_checksums.negotiated_nni->num = CSUM_MD4_OLD; } int get_subprotocol_version() { #if SUBPROTOCOL_VERSION != 0 return protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; #else return 0; #endif } rsync-3.2.7/match.c0000664000000000000000000003057314315642465012643 0ustar rootroot/* * Block matching used by the file-transfer code. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2022 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 "inums.h" extern int checksum_seed; extern int append_mode; extern struct name_num_item *xfer_sum_nni; extern int xfer_sum_len; int updating_basis_file; char sender_file_sum[MAX_DIGEST_LEN]; static int false_alarms; static int hash_hits; static int matches; static int64 data_transfer; static int total_false_alarms; static int total_hash_hits; static int total_matches; extern struct stats stats; #define TRADITIONAL_TABLESIZE (1<<16) static uint32 tablesize; static int32 *hash_table; #define SUM2HASH2(s1,s2) (((s1) + (s2)) & 0xFFFF) #define SUM2HASH(sum) SUM2HASH2((sum)&0xFFFF,(sum)>>16) #define BIG_SUM2HASH(sum) ((sum)%tablesize) static void build_hash_table(struct sum_struct *s) { static uint32 alloc_size; int32 i; /* Dynamically calculate the hash table size so that the hash load * for big files is about 80%. A number greater than the traditional * size must be odd or s2 will not be able to span the entire set. */ tablesize = (uint32)(s->count/8) * 10 + 11; if (tablesize < TRADITIONAL_TABLESIZE) tablesize = TRADITIONAL_TABLESIZE; if (tablesize > alloc_size || tablesize < alloc_size - 16*1024) { if (hash_table) free(hash_table); hash_table = new_array(int32, tablesize); alloc_size = tablesize; } memset(hash_table, 0xFF, tablesize * sizeof hash_table[0]); if (tablesize == TRADITIONAL_TABLESIZE) { for (i = 0; i < s->count; i++) { uint32 t = SUM2HASH(s->sums[i].sum1); s->sums[i].chain = hash_table[t]; hash_table[t] = i; } } else { for (i = 0; i < s->count; i++) { uint32 t = BIG_SUM2HASH(s->sums[i].sum1); s->sums[i].chain = hash_table[t]; hash_table[t] = i; } } } static OFF_T last_match; /* Transmit a literal and/or match token. * * This delightfully-named function is called either when we find a * match and need to transmit all the unmatched data leading up to it, * or when we get bored of accumulating literal data and just need to * transmit it. As a result of this second case, it is called even if * we have not matched at all! * * If i >= 0, the number of a matched token. If < 0, indicates we have * only literal data. A -1 will send a 0-token-int too, and a -2 sends * only literal data, w/o any token-int. */ static void matched(int f, struct sum_struct *s, struct map_struct *buf, OFF_T offset, int32 i) { int32 n = (int32)(offset - last_match); /* max value: block_size (int32) */ int32 j; if (DEBUG_GTE(DELTASUM, 2) && i >= 0) { rprintf(FINFO, "match at %s last_match=%s j=%d len=%ld n=%ld\n", big_num(offset), big_num(last_match), i, (long)s->sums[i].len, (long)n); } send_token(f, i, buf, last_match, n, i < 0 ? 0 : s->sums[i].len); data_transfer += n; if (i >= 0) { stats.matched_data += s->sums[i].len; n += s->sums[i].len; } for (j = 0; j < n; j += CHUNK_SIZE) { int32 n1 = MIN(CHUNK_SIZE, n - j); sum_update(map_ptr(buf, last_match + j, n1), n1); } if (i >= 0) last_match = offset + s->sums[i].len; else last_match = offset; if (buf && INFO_GTE(PROGRESS, 1)) show_progress(last_match, buf->file_size); } static void hash_search(int f,struct sum_struct *s, struct map_struct *buf, OFF_T len) { OFF_T offset, aligned_offset, end; int32 k, want_i, aligned_i, backup; char sum2[SUM_LENGTH]; uint32 s1, s2, sum; int more; schar *map; /* want_i is used to encourage adjacent matches, allowing the RLL * coding of the output to work more efficiently. */ want_i = 0; if (DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "hash search b=%ld len=%s\n", (long)s->blength, big_num(len)); } k = (int32)MIN(len, (OFF_T)s->blength); map = (schar *)map_ptr(buf, 0, k); sum = get_checksum1((char *)map, k); s1 = sum & 0xFFFF; s2 = sum >> 16; if (DEBUG_GTE(DELTASUM, 3)) rprintf(FINFO, "sum=%.8x k=%ld\n", sum, (long)k); offset = aligned_offset = aligned_i = 0; end = len + 1 - s->sums[s->count-1].len; if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "hash search s->blength=%ld len=%s count=%s\n", (long)s->blength, big_num(len), big_num(s->count)); } do { int done_csum2 = 0; uint32 hash_entry; int32 i, *prev; if (DEBUG_GTE(DELTASUM, 4)) { rprintf(FINFO, "offset=%s sum=%04x%04x\n", big_num(offset), s2 & 0xFFFF, s1 & 0xFFFF); } if (tablesize == TRADITIONAL_TABLESIZE) { hash_entry = SUM2HASH2(s1,s2); if ((i = hash_table[hash_entry]) < 0) goto null_hash; sum = (s1 & 0xffff) | (s2 << 16); } else { sum = (s1 & 0xffff) | (s2 << 16); hash_entry = BIG_SUM2HASH(sum); if ((i = hash_table[hash_entry]) < 0) goto null_hash; } prev = &hash_table[hash_entry]; hash_hits++; do { int32 l; /* When updating in-place, the chunk's offset must be * either >= our offset or identical data at that offset. * Remove any bypassed entries that we can never use. */ if (updating_basis_file && s->sums[i].offset < offset && !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) { *prev = s->sums[i].chain; continue; } prev = &s->sums[i].chain; if (sum != s->sums[i].sum1) continue; /* also make sure the two blocks are the same length */ l = (int32)MIN((OFF_T)s->blength, len-offset); if (l != s->sums[i].len) continue; if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "potential match at %s i=%ld sum=%08x\n", big_num(offset), (long)i, sum); } if (!done_csum2) { map = (schar *)map_ptr(buf,offset,l); get_checksum2((char *)map,l,sum2); done_csum2 = 1; } if (memcmp(sum2,s->sums[i].sum2,s->s2length) != 0) { false_alarms++; continue; } /* When updating in-place, the best possible match is * one with an identical offset, so we prefer that over * the adjacent want_i optimization. */ if (updating_basis_file) { /* All the generator's chunks start at blength boundaries. */ while (aligned_offset < offset) { aligned_offset += s->blength; aligned_i++; } if ((offset == aligned_offset || (sum == 0 && l == s->blength && aligned_offset + l <= len)) && aligned_i < s->count) { if (i != aligned_i) { if (sum != s->sums[aligned_i].sum1 || l != s->sums[aligned_i].len || memcmp(sum2, s->sums[aligned_i].sum2, s->s2length) != 0) goto check_want_i; i = aligned_i; } if (offset != aligned_offset) { /* We've matched some zeros in a spot that is also zeros * further along in the basis file, if we find zeros ahead * in the sender's file, we'll output enough literal data * to re-align with the basis file, and get back to seeking * instead of writing. */ backup = (int32)(aligned_offset - last_match); if (backup < 0) backup = 0; map = (schar *)map_ptr(buf, aligned_offset - backup, l + backup) + backup; sum = get_checksum1((char *)map, l); if (sum != s->sums[i].sum1) goto check_want_i; get_checksum2((char *)map, l, sum2); if (memcmp(sum2, s->sums[i].sum2, s->s2length) != 0) goto check_want_i; /* OK, we have a re-alignment match. Bump the offset * forward to the new match point. */ offset = aligned_offset; } /* This identical chunk is in the same spot in the old and new file. */ s->sums[i].flags |= SUMFLG_SAME_OFFSET; want_i = i; } } check_want_i: /* we've found a match, but now check to see * if want_i can hint at a better match. */ if (i != want_i && want_i < s->count && (!updating_basis_file || s->sums[want_i].offset >= offset || s->sums[want_i].flags & SUMFLG_SAME_OFFSET) && sum == s->sums[want_i].sum1 && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) { /* we've found an adjacent match - the RLL coder * will be happy */ i = want_i; } want_i = i + 1; matched(f,s,buf,offset,i); offset += s->sums[i].len - 1; k = (int32)MIN((OFF_T)s->blength, len-offset); map = (schar *)map_ptr(buf, offset, k); sum = get_checksum1((char *)map, k); s1 = sum & 0xFFFF; s2 = sum >> 16; matches++; break; } while ((i = s->sums[i].chain) >= 0); null_hash: backup = (int32)(offset - last_match); /* We sometimes read 1 byte prior to last_match... */ if (backup < 0) backup = 0; /* Trim off the first byte from the checksum */ more = offset + k < len; map = (schar *)map_ptr(buf, offset - backup, k + more + backup) + backup; s1 -= map[0] + CHAR_OFFSET; s2 -= k * (map[0]+CHAR_OFFSET); /* Add on the next byte (if there is one) to the checksum */ if (more) { s1 += map[k] + CHAR_OFFSET; s2 += s1; } else --k; /* By matching early we avoid re-reading the data 3 times in the case where a token match comes a long way after last match. The 3 reads are caused by the running match, the checksum update and the literal send. */ if (backup >= s->blength+CHUNK_SIZE && end-offset > CHUNK_SIZE) matched(f, s, buf, offset - s->blength, -2); } while (++offset < end); matched(f, s, buf, len, -1); map_ptr(buf, len-1, 1); } /** * Scan through a origin file, looking for sections that match * checksums from the generator, and transmit either literal or token * data. * * Also calculates the MD4 checksum of the whole file, using the md * accumulator. This is transmitted with the file as protection * against corruption on the wire. * * @param s Checksums received from the generator. If s->count == * 0, then there are actually no checksums for this file. * * @param len Length of the file to send. **/ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len) { last_match = 0; false_alarms = 0; hash_hits = 0; matches = 0; data_transfer = 0; sum_init(xfer_sum_nni, checksum_seed); if (append_mode > 0) { if (append_mode == 2) { OFF_T j = 0; for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) { if (buf && INFO_GTE(PROGRESS, 1)) show_progress(last_match, buf->file_size); sum_update(map_ptr(buf, last_match, CHUNK_SIZE), CHUNK_SIZE); last_match = j; } if (last_match < s->flength) { int32 n = (int32)(s->flength - last_match); if (buf && INFO_GTE(PROGRESS, 1)) show_progress(last_match, buf->file_size); sum_update(map_ptr(buf, last_match, n), n); } } last_match = s->flength; s->count = 0; } if (len > 0 && s->count > 0) { build_hash_table(s); if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"built hash table\n"); hash_search(f, s, buf, len); if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"done hash search\n"); } else { OFF_T j; /* by doing this in pieces we avoid too many seeks */ for (j = last_match + CHUNK_SIZE; j < len; j += CHUNK_SIZE) matched(f, s, buf, j, -2); matched(f, s, buf, len, -1); } sum_end(sender_file_sum); /* If we had a read error, send a bad checksum. We use all bits * off as long as the checksum doesn't happen to be that, in * which case we turn the last 0 bit into a 1. */ if (buf && buf->status != 0) { int i; for (i = 0; i < xfer_sum_len && sender_file_sum[i] == 0; i++) {} memset(sender_file_sum, 0, xfer_sum_len); if (i == xfer_sum_len) sender_file_sum[i-1]++; } if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"sending file_sum\n"); write_buf(f, sender_file_sum, xfer_sum_len); if (DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n", false_alarms, hash_hits, matches); } total_hash_hits += hash_hits; total_false_alarms += false_alarms; total_matches += matches; stats.literal_data += data_transfer; } void match_report(void) { if (!DEBUG_GTE(DELTASUM, 1)) return; rprintf(FINFO, "total: matches=%d hash_hits=%d false_alarms=%d data=%s\n", total_matches, total_hash_hits, total_false_alarms, big_num(stats.literal_data)); } rsync-3.2.7/delete.c0000664000000000000000000001454213671304046013001 0ustar rootroot/* * Deletion routines used in rsync. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2020 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" extern int am_root; extern int make_backups; extern int max_delete; extern char *backup_dir; extern char *backup_suffix; extern int backup_suffix_len; extern struct stats stats; int ignore_perishable = 0; int non_perishable_cnt = 0; int skipped_deletes = 0; static inline int is_backup_file(char *fn) { int k = strlen(fn) - backup_suffix_len; return k > 0 && strcmp(fn+k, backup_suffix) == 0; } /* The directory is about to be deleted: if DEL_RECURSE is given, delete all * its contents, otherwise just checks for content. Returns DR_SUCCESS or * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The * buffer is used for recursion, but returned unchanged.) */ static enum delret delete_dir_contents(char *fname, uint16 flags) { struct file_list *dirlist; enum delret ret; unsigned remainder; void *save_filters; int j, dlen; char *p; if (DEBUG_GTE(DEL, 3)) { rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n", fname, flags); } dlen = strlen(fname); save_filters = push_local_filters(fname, dlen); non_perishable_cnt = 0; dirlist = get_dirlist(fname, dlen, 0); ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; if (!dirlist->used) goto done; if (!(flags & DEL_RECURSE)) { ret = DR_NOT_EMPTY; goto done; } p = fname + dlen; if (dlen != 1 || *fname != '/') *p++ = '/'; remainder = MAXPATHLEN - (p - fname); /* We do our own recursion, so make delete_item() non-recursive. */ flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE)) | DEL_DIR_IS_EMPTY; for (j = dirlist->used; j--; ) { struct file_struct *fp = dirlist->files[j]; if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { if (DEBUG_GTE(DEL, 1)) { rprintf(FINFO, "mount point, %s, pins parent directory\n", f_name(fp, NULL)); } ret = DR_NOT_EMPTY; continue; } strlcpy(p, fp->basename, remainder); if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) do_chmod(fname, fp->mode | S_IWUSR); /* Save stack by recursing to ourself directly. */ if (S_ISDIR(fp->mode)) { if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) ret = DR_NOT_EMPTY; } if (delete_item(fname, fp->mode, flags) != DR_SUCCESS) ret = DR_NOT_EMPTY; } fname[dlen] = '\0'; done: flist_free(dirlist); pop_local_filters(save_filters); if (ret == DR_NOT_EMPTY) { rprintf(FINFO, "cannot delete non-empty directory: %s\n", fname); } return ret; } /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will * delete recursively. * * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's * a directory! (The buffer is used for recursion, but returned unchanged.) */ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) { enum delret ret; char *what; int ok; if (DEBUG_GTE(DEL, 2)) { rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n", fbuf, (int)mode, (int)flags); } if (flags & DEL_NO_UID_WRITE) do_chmod(fbuf, mode | S_IWUSR); if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { /* This only happens on the first call to delete_item() since * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ ignore_perishable = 1; /* If DEL_RECURSE is not set, this just reports emptiness. */ ret = delete_dir_contents(fbuf, flags); ignore_perishable = 0; if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT) goto check_ret; /* OK: try to delete the directory. */ } if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) { skipped_deletes++; return DR_AT_LIMIT; } if (S_ISDIR(mode)) { what = "rmdir"; ok = do_rmdir(fbuf) == 0; } else { if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) { what = "make_backup"; ok = make_backup(fbuf, True); if (ok == 2) { what = "unlink"; ok = robust_unlink(fbuf) == 0; } } else { what = "unlink"; ok = robust_unlink(fbuf) == 0; } } if (ok) { if (!(flags & DEL_MAKE_ROOM)) { log_delete(fbuf, mode); stats.deleted_files++; if (S_ISREG(mode)) { /* Nothing more to count */ } else if (S_ISDIR(mode)) stats.deleted_dirs++; #ifdef SUPPORT_LINKS else if (S_ISLNK(mode)) stats.deleted_symlinks++; #endif else if (IS_DEVICE(mode)) stats.deleted_symlinks++; else stats.deleted_specials++; } ret = DR_SUCCESS; } else { if (S_ISDIR(mode) && errno == ENOTEMPTY) { rprintf(FINFO, "cannot delete non-empty directory: %s\n", fbuf); ret = DR_NOT_EMPTY; } else if (errno != ENOENT) { rsyserr(FERROR_XFER, errno, "delete_file: %s(%s) failed", what, fbuf); ret = DR_FAILURE; } else ret = DR_SUCCESS; } check_ret: if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) { const char *desc; switch (flags & DEL_MAKE_ROOM) { case DEL_FOR_FILE: desc = "regular file"; break; case DEL_FOR_DIR: desc = "directory"; break; case DEL_FOR_SYMLINK: desc = "symlink"; break; case DEL_FOR_DEVICE: desc = "device file"; break; case DEL_FOR_SPECIAL: desc = "special file"; break; default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ } rprintf(FERROR_XFER, "could not make way for %s %s: %s\n", flags & DEL_FOR_BACKUP ? "backup" : "new", desc, fbuf); } return ret; } uint16 get_del_for_flag(uint16 mode) { if (S_ISREG(mode)) return DEL_FOR_FILE; if (S_ISDIR(mode)) return DEL_FOR_DIR; if (S_ISLNK(mode)) return DEL_FOR_SYMLINK; if (IS_DEVICE(mode)) return DEL_FOR_DEVICE; if (IS_SPECIAL(mode)) return DEL_FOR_SPECIAL; exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ } rsync-3.2.7/ifuncs.h0000664000000000000000000000430214170671375013033 0ustar rootroot/* Inline functions for rsync. * * Copyright (C) 2007-2022 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. */ static inline void alloc_xbuf(xbuf *xb, size_t sz) { xb->buf = new_array(char, sz); xb->size = sz; xb->len = xb->pos = 0; } static inline void realloc_xbuf(xbuf *xb, size_t sz) { char *bf = realloc_array(xb->buf, char, sz); xb->buf = bf; xb->size = sz; } static inline void free_xbuf(xbuf *xb) { if (xb->buf) free(xb->buf); memset(xb, 0, sizeof (xbuf)); } static inline int to_wire_mode(mode_t mode) { #ifdef SUPPORT_LINKS #if _S_IFLNK != 0120000 if (S_ISLNK(mode)) return (mode & ~(_S_IFMT)) | 0120000; #endif #endif return mode; } static inline mode_t from_wire_mode(int mode) { #if _S_IFLNK != 0120000 if ((mode & (_S_IFMT)) == 0120000) return (mode & ~(_S_IFMT)) | _S_IFLNK; #endif return mode; } static inline char * d_name(struct dirent *di) { #ifdef HAVE_BROKEN_READDIR return (di->d_name - 2); #else return di->d_name; #endif } static inline void init_stat_x(stat_x *sx_p) { sx_p->crtime = 0; #ifdef SUPPORT_ACLS sx_p->acc_acl = sx_p->def_acl = NULL; #endif #ifdef SUPPORT_XATTRS sx_p->xattr = NULL; #endif } static inline void free_stat_x(stat_x *sx_p) { #ifdef SUPPORT_ACLS { extern int preserve_acls; if (preserve_acls) free_acl(sx_p); } #endif #ifdef SUPPORT_XATTRS { extern int preserve_xattrs; if (preserve_xattrs) free_xattr(sx_p); } #endif } static inline char *my_strdup(const char *str, const char *file, int line) { int len = strlen(str)+1; char *buf = my_alloc(NULL, len, 1, file, line); memcpy(buf, str, len); return buf; } rsync-3.2.7/INSTALL.md0000664000000000000000000002250314272524227013022 0ustar rootroot# How to build and install rsync When building rsync, you'll want to install various libraries in order to get all the features enabled. The configure script will alert you when the newest libraries are missing and tell you the appropriate `--disable-LIB` option to use if you want to just skip that feature. What follows are various support libraries that you may want to install to build rsync with the maximum features (the impatient can skip down to the package summary): ## The basic setup You need to have a C compiler installed and optionally a C++ compiler in order to try to build some hardware-accelerated checksum routines. Rsync also needs a modern awk, which might be provided via gawk or nawk on some OSes. ## Autoconf & manpages If you're installing from the git repo (instead of a release tar file) you'll also need the GNU autotools (autoconf & automake) and your choice of 2 python3 markdown libraries: cmarkgfm or commonmark (needed to generate the manpages). If your OS doesn't provide a python3-cmarkgfm or python3-commonmark package, you can run the following to install the commonmark python library for your build user (after installing python3's pip package): > python3 -mpip install --user commonmark You can test if you've got it fixed by running (from the rsync checkout): > ./md-convert --test rsync-ssl.1.md Alternately, you can avoid generating the manpages by fetching the very latest versions (that match the latest git source) from the [generated-files][6] dir. One way to do that is to run: > ./prepare-source fetchgen [6]: https://download.samba.org/pub/rsync/generated-files/ ## ACL support To support copying ACL file information, make sure you have an acl development library installed. It also helps to have the helper programs installed to manipulate ACLs and to run the rsync testsuite. ## Xattr support To support copying xattr file information, make sure you have an attr development library installed. It also helps to have the helper programs installed to manipulate xattrs and to run the rsync testsuite. ## xxhash The [xxHash library][1] provides extremely fast checksum functions that can make the "rsync algorithm" run much more quickly, especially when matching blocks in large files. Installing this development library adds xxhash checksums as the default checksum algorithm. You'll need at least v0.8.0 if you want rsync to include the full range of its checksum algorithms. [1]: https://cyan4973.github.io/xxHash/ ## zstd The [zstd library][2] compression algorithm that uses less CPU than the default zlib algorithm at the same compression level. Note that you need at least version 1.4, so you might need to skip the zstd compression if you can only install a 1.3 release. Installing this development library adds zstd compression as the default compression algorithm. [2]: http://facebook.github.io/zstd/ ## lz4 The [lz4 library][3] compression algorithm that uses very little CPU, though it also has the smallest compression ratio of other algorithms. Installing this development library adds lz4 compression as an available compression algorithm. [3]: https://lz4.github.io/lz4/ ## openssl crypto The [openssl crypto library][4] provides some hardware accelerated checksum algorithms for MD4 and MD5. Installing this development library makes rsync use the (potentially) faster checksum routines when computing MD4 & MD5 checksums. [4]: https://www.openssl.org/docs/man1.0.2/man3/crypto.html ## Package summary To help you get the libraries installed, here are some package install commands for various OSes. The commands are split up to correspond with the above items, but feel free to combine the package names into a single install, if you like. - For Debian and Ubuntu (Debian Buster users may want to briefly(?) enable buster-backports to update zstd from 1.3 to 1.4): > sudo apt install -y gcc g++ gawk autoconf automake python3-cmarkgfm > sudo apt install -y acl libacl1-dev > sudo apt install -y attr libattr1-dev > sudo apt install -y libxxhash-dev > sudo apt install -y libzstd-dev > sudo apt install -y liblz4-dev > sudo apt install -y libssl-dev - For CentOS (use EPEL for python3-pip): > sudo yum -y install epel-release > sudo yum -y install gcc g++ gawk autoconf automake python3-pip > sudo yum -y install acl libacl-devel > sudo yum -y install attr libattr-devel > sudo yum -y install xxhash-devel > sudo yum -y install libzstd-devel > sudo yum -y install lz4-devel > sudo yum -y install openssl-devel > python3 -mpip install --user commonmark - For Fedora 33: > sudo dnf -y install acl libacl-devel > sudo dnf -y install attr libattr-devel > sudo dnf -y install xxhash-devel > sudo dnf -y install libzstd-devel > sudo dnf -y install lz4-devel > sudo dnf -y install openssl-devel - For FreeBSD (this assumes that the python3 version is 3.7): > sudo pkg install -y autotools python3 py37-CommonMark > sudo pkg install -y xxhash > sudo pkg install -y zstd > sudo pkg install -y liblz4 - For macOS: > brew install automake > brew install xxhash > brew install zstd > brew install lz4 > brew install openssl - For Cygwin (with all cygwin programs stopped, run the appropriate setup program from a cmd shell): > setup-x86_64 --quiet-mode -P make,gawk,autoconf,automake,gcc-core,python38,python38-pip > setup-x86_64 --quiet-mode -P attr,libattr-devel > setup-x86_64 --quiet-mode -P libzstd-devel > setup-x86_64 --quiet-mode -P liblz4-devel > setup-x86_64 --quiet-mode -P libssl-devel Sometimes cygwin has commonmark packaged and sometimes it doesn't. Now that its python38 has stabilized, you could install python38-commonmark. Or just avoid the issue by running this from a bash shell as your build user: > python3 -mpip install --user commonmark ## Build and install After installing the various libraries, you need to configure, build, and install the source: > ./configure > make > sudo make install The default install path is /usr/local/bin, but you can set the installation directory and other parameters using options to ./configure. To see them, use: > ./configure --help Configure tries to figure out if the local system uses group "nobody" or "nogroup" by looking in the /etc/group file. (This is only used for the default group of an rsync daemon, which attempts to run with "nobody" user and group permissions.) You can change the default user and group for the daemon by editing the NOBODY_USER and NOBODY_GROUP defines in config.h, or just override them in your /etc/rsyncd.conf file. As of 2.4.7, rsync uses Eric Troan's popt option-parsing library. A cut-down copy of a recent release is included in the rsync distribution, and will be used if there is no popt library on your build host, or if the `--with-included-popt` option is passed to ./configure. If you configure using `--enable-maintainer-mode`, then rsync will try to pop up an xterm on DISPLAY=:0 if it crashes. You might find this useful, but it should be turned off for production builds. If you want to automatically use a separate "build" directory based on the current git branch name, start with a pristine git checkout and run "mkdir auto-build-save" before you run the first ./configure command. That will cause a fresh build dir to spring into existence along with a special Makefile symlink that allows you to run "make" and "./configure" from the source dir (the "build" dir gets auto switched based on branch). This is helpful when using the branch-from-patch and patch-update scripts to maintain the official rsync patches. If you ever need to build from a "detached head" git position then you'll need to manually chdir into the build dir to run make. I also like to create 2 more symlinks in the source dir: `ln -s build/rsync . ; ln -s build/testtmp .` ## Make compatibility Note that Makefile.in has a rule that uses a wildcard in a prerequisite. If your make has a problem with this rule, you will see an error like this: Don't know how to make ./*.c You can change the "proto.h-tstamp" target in Makefile.in to list all the \*.c filenames explicitly in order to avoid this issue. ## RPM notes Under packaging you will find .spec files for several distributions. The .spec file in packaging/lsb can be used for Linux systems that adhere to the Linux Standards Base (e.g., RedHat and others). ## HP-UX notes The HP-UX 10.10 "bundled" C compiler seems not to be able to cope with ANSI C. You may see this error message in config.log if ./configure fails: (Bundled) cc: "configure", line 2162: error 1705: Function prototypes are an ANSI feature. Install gcc or HP's "ANSI/C Compiler". ## Mac OS X notes Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do not completely implement the "New Sockets" API. [This site][5] says that Apple started to support IPv6 in 10.2 (Jaguar). If your build fails, try again after running configure with `--disable-ipv6`. [5]: http://www.ipv6.org/impl/mac.html ## IBM AIX notes IBM AIX has a largefile problem with mkstemp. See IBM PR-51921. The workaround is to append the following to config.h: > #ifdef _LARGE_FILES > #undef HAVE_SECURE_MKSTEMP > #endif rsync-3.2.7/loadparm.c0000664000000000000000000003557013734713224013344 0ustar rootroot/* * 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. * * This is based on loadparm.c from Samba, written by Andrew Tridgell * and Karl Auer. Some of the changes are: * * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2020 Wayne Davison */ /* Load parameters. * * This module provides suitable callback functions for the params * module. It builds the internal table of section details which is * then used by the rest of the server. * * To add a parameter: * * 1) add it to the global_vars or local_vars structure definition * 2) add it to the parm_table * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING()) * 4) initialise it in the Defaults static structure * * Notes: * The configuration file is processed sequentially for speed. For this * reason, there is a fair bit of sequence-dependent code here - ie., code * which assumes that certain things happen before others. In particular, the * code which happens at the boundary between sections is delicately poised, * so be careful! */ #include "rsync.h" #include "itypes.h" #include "ifuncs.h" #include "default-dont-compress.h" extern item_list dparam_list; #define strequal(a, b) (strcasecmp(a, b)==0) #ifndef LOG_DAEMON #define LOG_DAEMON 0 #endif /* the following are used by loadparm for option lists */ typedef enum { P_BOOL, P_BOOLREV, P_BOOL3, P_CHAR, P_INTEGER, P_OCTAL, P_PATH, P_STRING, P_ENUM } parm_type; typedef enum { P_LOCAL, P_GLOBAL, P_NONE } parm_class; struct enum_list { int value; char *name; }; struct parm_struct { char *label; parm_type type; parm_class class; void *ptr; struct enum_list *enum_list; unsigned flags; }; #ifndef GLOBAL_NAME #define GLOBAL_NAME "global" #endif /* some helpful bits */ #define iSECTION(i) ((local_vars*)section_list.items)[i] #define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count) #define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char*)(p))-(char*)&Vars.l)) /* Stack of "Vars" values used by the &include directive. */ static item_list Vars_stack = EMPTY_ITEM_LIST; /* The array of section values that holds all the defined modules. */ static item_list section_list = EMPTY_ITEM_LIST; static int iSectionIndex = -1; static BOOL bInGlobalSection = True; static struct enum_list enum_syslog_facility[] = { #ifdef LOG_AUTH { LOG_AUTH, "auth" }, #endif #ifdef LOG_AUTHPRIV { LOG_AUTHPRIV, "authpriv" }, #endif #ifdef LOG_CRON { LOG_CRON, "cron" }, #endif #ifdef LOG_DAEMON { LOG_DAEMON, "daemon" }, #endif #ifdef LOG_FTP { LOG_FTP, "ftp" }, #endif #ifdef LOG_KERN { LOG_KERN, "kern" }, #endif #ifdef LOG_LPR { LOG_LPR, "lpr" }, #endif #ifdef LOG_MAIL { LOG_MAIL, "mail" }, #endif #ifdef LOG_NEWS { LOG_NEWS, "news" }, #endif #ifdef LOG_AUTH { LOG_AUTH, "security" }, #endif #ifdef LOG_SYSLOG { LOG_SYSLOG, "syslog" }, #endif #ifdef LOG_USER { LOG_USER, "user" }, #endif #ifdef LOG_UUCP { LOG_UUCP, "uucp" }, #endif #ifdef LOG_LOCAL0 { LOG_LOCAL0, "local0" }, #endif #ifdef LOG_LOCAL1 { LOG_LOCAL1, "local1" }, #endif #ifdef LOG_LOCAL2 { LOG_LOCAL2, "local2" }, #endif #ifdef LOG_LOCAL3 { LOG_LOCAL3, "local3" }, #endif #ifdef LOG_LOCAL4 { LOG_LOCAL4, "local4" }, #endif #ifdef LOG_LOCAL5 { LOG_LOCAL5, "local5" }, #endif #ifdef LOG_LOCAL6 { LOG_LOCAL6, "local6" }, #endif #ifdef LOG_LOCAL7 { LOG_LOCAL7, "local7" }, #endif { -1, NULL } }; /* Expand %VAR% references. Any unknown vars or unrecognized * syntax leaves the raw chars unchanged. */ static char *expand_vars(const char *str) { char *buf, *t; const char *f; int bufsize; if (!str || !strchr(str, '%')) return (char *)str; /* TODO change return value to const char* at some point. */ bufsize = strlen(str) + 2048; buf = new_array(char, bufsize+1); /* +1 for trailing '\0' */ for (t = buf, f = str; bufsize && *f; ) { if (*f == '%' && isUpper(f+1)) { char *percent = strchr(f+1, '%'); if (percent && percent - f < bufsize) { char *val; strlcpy(t, f+1, percent - f); val = getenv(t); if (val) { int len = strlcpy(t, val, bufsize+1); if (len > bufsize) break; bufsize -= len; t += len; f = percent + 1; continue; } } } *t++ = *f++; bufsize--; } *t = '\0'; if (*f) { rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str); exit_cleanup(RERR_MALLOC); } if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL) out_of_memory("expand_vars"); return buf; } /* Each "char* foo" has an associated "BOOL foo_EXP" that tracks if the string has been expanded yet or not. */ /* NOTE: use this function and all the FN_{GLOBAL,LOCAL} ones WITHOUT a trailing semicolon! */ #define RETURN_EXPANDED(val) {if (!val ## _EXP) {val = expand_vars(val); val ## _EXP = True;} return val ? val : "";} /* In this section all the functions that are used to access the * parameters from the rest of the program are defined. */ #define FN_GLOBAL_STRING(fn_name, val) \ char *fn_name(void) RETURN_EXPANDED(Vars.g.val) #define FN_GLOBAL_BOOL(fn_name, val) \ BOOL fn_name(void) {return Vars.g.val;} #define FN_GLOBAL_CHAR(fn_name, val) \ char fn_name(void) {return Vars.g.val;} #define FN_GLOBAL_INTEGER(fn_name, val) \ int fn_name(void) {return Vars.g.val;} #define FN_LOCAL_STRING(fn_name, val) \ char *fn_name(int i) {if (LP_SNUM_OK(i) && iSECTION(i).val) RETURN_EXPANDED(iSECTION(i).val) else RETURN_EXPANDED(Vars.l.val)} #define FN_LOCAL_BOOL(fn_name, val) \ BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;} #define FN_LOCAL_CHAR(fn_name, val) \ char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;} #define FN_LOCAL_INTEGER(fn_name, val) \ int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;} /* The following include file contains: * * typedef global_vars - describes global (ie., server-wide) parameters. * typedef local_vars - describes a single section. * typedef all_vars - a combination of global_vars & local_vars. * all_vars Defaults - the default values for all the variables. * all_vars Vars - the currently configured values for all the variables. * struct parm_struct parm_table - the strings & variables for the parser. * FN_{LOCAL,GLOBAL}_{TYPE}() definition for all the lp_var_name() accessors. */ #include "daemon-parm.h" /* Initialise the Default all_vars structure. */ void reset_daemon_vars(void) { memcpy(&Vars, &Defaults, sizeof Vars); } /* Assign a copy of v to *s. Handles NULL strings. We don't worry * about overwriting a malloc'd string because the long-running * (port-listening) daemon only loads the config file once, and the * per-job (forked or xinitd-ran) daemon only re-reads the file at * the start, so any lost memory is inconsequential. */ static inline void string_set(char **s, const char *v) { *s = v ? strdup(v) : NULL; } /* Copy local_vars into a new section. No need to strdup since we don't free. */ static void copy_section(local_vars *psectionDest, local_vars *psectionSource) { memcpy(psectionDest, psectionSource, sizeof psectionDest[0]); } /* Initialise a section to the defaults. */ static void init_section(local_vars *psection) { memset(psection, 0, sizeof (local_vars)); copy_section(psection, &Vars.l); } /* Do a case-insensitive, whitespace-ignoring string equality check. */ static int strwiEQ(char *psz1, char *psz2) { /* If one or both strings are NULL, we return equality right away. */ if (psz1 == psz2) return 1; if (psz1 == NULL || psz2 == NULL) return 0; /* sync the strings on first non-whitespace */ while (1) { while (isSpace(psz1)) psz1++; while (isSpace(psz2)) psz2++; if (*psz1 == '\0' || *psz2 == '\0') break; if (toUpper(psz1) != toUpper(psz2)) break; psz1++; psz2++; } return *psz1 == *psz2; } /* Find a section by name. Otherwise works like get_section. */ static int getsectionbyname(char *name) { int i; for (i = section_list.count - 1; i >= 0; i--) { if (strwiEQ(iSECTION(i).name, name)) break; } return i; } /* Add a new section to the sections array w/the default values. */ static int add_a_section(char *name) { int i; local_vars *s; /* it might already exist */ if (name) { i = getsectionbyname(name); if (i >= 0) return i; } i = section_list.count; s = EXPAND_ITEM_LIST(§ion_list, local_vars, 2); init_section(s); if (name) string_set(&s->name, name); return i; } /* Map a parameter's string representation to something we can use. * Returns False if the parameter string is not recognised, else TRUE. */ static int map_parameter(char *parmname) { int iIndex; if (*parmname == '-') return -1; for (iIndex = 0; parm_table[iIndex].label; iIndex++) { if (strwiEQ(parm_table[iIndex].label, parmname)) return iIndex; } rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname); return -1; } /* Set a boolean variable from the text value stored in the passed string. * Returns True in success, False if the passed string does not correctly * represent a boolean. */ static BOOL set_boolean(BOOL *pb, char *parmvalue, int allow_unset) { if (strwiEQ(parmvalue, "yes") || strwiEQ(parmvalue, "true") || strwiEQ(parmvalue, "1")) *pb = True; else if (strwiEQ(parmvalue, "no") || strwiEQ(parmvalue, "false") || strwiEQ(parmvalue, "0")) *pb = False; else if (allow_unset && (strwiEQ(parmvalue, "unset") || strwiEQ(parmvalue, "-1"))) *pb = Unset; else { rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n", parmvalue); return False; } return True; } /* Process a parameter. */ static BOOL do_parameter(char *parmname, char *parmvalue) { int parmnum, i; void *parm_ptr; /* where we are going to store the result */ void *def_ptr; char *cp; parmnum = map_parameter(parmname); if (parmnum < 0) { rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname); return True; } def_ptr = parm_table[parmnum].ptr; if (bInGlobalSection) parm_ptr = def_ptr; else { if (parm_table[parmnum].class == P_GLOBAL) { rprintf(FLOG, "Global parameter %s found in module section!\n", parmname); return True; } parm_ptr = SECTION_PTR(&iSECTION(iSectionIndex), def_ptr); } /* now switch on the type of variable it is */ switch (parm_table[parmnum].type) { case P_PATH: case P_STRING: /* delay expansion of %VAR% strings */ break; default: /* expand any %VAR% strings now */ parmvalue = expand_vars(parmvalue); break; } switch (parm_table[parmnum].type) { case P_BOOL: set_boolean(parm_ptr, parmvalue, False); break; case P_BOOL3: set_boolean(parm_ptr, parmvalue, True); break; case P_BOOLREV: set_boolean(parm_ptr, parmvalue, False); *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr; break; case P_INTEGER: *(int *)parm_ptr = atoi(parmvalue); break; case P_CHAR: *(char *)parm_ptr = *parmvalue; break; case P_OCTAL: sscanf(parmvalue, "%o", (unsigned int *)parm_ptr); break; case P_PATH: string_set(parm_ptr, parmvalue); if ((cp = *(char**)parm_ptr) != NULL) { int len = strlen(cp); while (len > 1 && cp[len-1] == '/') len--; cp[len] = '\0'; } break; case P_STRING: string_set(parm_ptr, parmvalue); break; case P_ENUM: for (i=0; parm_table[parmnum].enum_list[i].name; i++) { if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) { *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value; break; } } if (!parm_table[parmnum].enum_list[i].name) { if (atoi(parmvalue) > 0) *(int *)parm_ptr = atoi(parmvalue); } break; } return True; } /* Process a new section (rsync module). * Returns True on success, False on failure. */ static BOOL do_section(char *sectionname) { BOOL isglobal; if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */ bInGlobalSection = 1; if (strcmp(sectionname+1, "push") == 0) { all_vars *vp = EXPAND_ITEM_LIST(&Vars_stack, all_vars, 2); memcpy(vp, &Vars, sizeof Vars); } else if (strcmp(sectionname+1, "pop") == 0 || strcmp(sectionname+1, "reset") == 0) { all_vars *vp = ((all_vars*)Vars_stack.items) + Vars_stack.count - 1; if (!Vars_stack.count) return False; memcpy(&Vars, vp, sizeof Vars); if (sectionname[1] == 'p') Vars_stack.count--; } else return False; return True; } isglobal = strwiEQ(sectionname, GLOBAL_NAME); /* At the end of the global section, add any --dparam items. */ if (bInGlobalSection && !isglobal) { if (!section_list.count) set_dparams(0); } /* if we've just struck a global section, note the fact. */ bInGlobalSection = isglobal; /* check for multiple global sections */ if (bInGlobalSection) return True; #if 0 /* If we have a current section, tidy it up before moving on. */ if (iSectionIndex >= 0) { /* Add any tidy work as needed ... */ if (problem) return False; } #endif if (strchr(sectionname, '/') != NULL) { rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname); return False; } if ((iSectionIndex = add_a_section(sectionname)) < 0) { rprintf(FLOG, "Failed to add a new module\n"); bInGlobalSection = True; return False; } return True; } /* Load the modules from the config file. Return True on success, * False on failure. */ int lp_load(char *pszFname, int globals_only) { bInGlobalSection = True; reset_daemon_vars(); /* We get sections first, so have to start 'behind' to make up. */ iSectionIndex = -1; return pm_process(pszFname, globals_only ? NULL : do_section, do_parameter); } BOOL set_dparams(int syntax_check_only) { char *equal, *val, **params = dparam_list.items; unsigned j; for (j = 0; j < dparam_list.count; j++) { equal = strchr(params[j], '='); /* options.c verified this */ *equal = '\0'; if (syntax_check_only) { if (map_parameter(params[j]) < 0) { rprintf(FERROR, "Unknown parameter \"%s\"\n", params[j]); *equal = '='; return False; } } else { for (val = equal+1; isSpace(val); val++) {} do_parameter(params[j], val); } *equal = '='; } return True; } /* Return the max number of modules (sections). */ int lp_num_modules(void) { return section_list.count; } /* Return the number of the module with the given name, or -1 if it doesn't * exist. Note that this is a DIFFERENT ANIMAL from the internal function * getsectionbyname()! This works ONLY if all sections have been loaded, * and does not copy the found section. */ int lp_number(char *name) { int i; for (i = section_list.count - 1; i >= 0; i--) { if (strcmp(lp_name(i), name) == 0) break; } return i; } rsync-3.2.7/receiver.c0000664000000000000000000006713614307154751013355 0ustar rootroot/* * Routines only used by the receiving process. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2022 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 "inums.h" extern int dry_run; extern int do_xfers; extern int am_root; extern int am_server; extern int inc_recurse; extern int log_before_transfer; extern int stdout_format_has_i; extern int logfile_format_has_i; extern int want_xattr_optim; extern int csum_length; extern int read_batch; extern int write_batch; extern int batch_gen_fd; extern int protocol_version; extern int relative_paths; extern int preserve_hard_links; extern int preserve_perms; extern int write_devices; extern int preserve_xattrs; extern int do_fsync; extern int basis_dir_cnt; extern int make_backups; extern int cleanup_got_literal; extern int remove_source_files; extern int append_mode; extern int sparse_files; extern int preallocate_files; extern int keep_partial; extern int checksum_seed; extern int whole_file; extern int inplace; extern int inplace_partial; extern int allowed_lull; extern int delay_updates; extern BOOL want_progress_now; extern mode_t orig_umask; extern struct stats stats; extern char *tmpdir; extern char *partial_dir; extern char *basis_dir[MAX_BASIS_DIRS+1]; extern char sender_file_sum[MAX_DIGEST_LEN]; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern filter_rule_list daemon_filter_list; extern OFF_T preallocated_len; extern struct name_num_item *xfer_sum_nni; extern int xfer_sum_len; static struct bitbag *delayed_bits = NULL; static int phase = 0, redoing = 0; static flist_ndx_list batch_redo_list; /* This is non-0 when we are updating the basis file or an identical copy: */ static int updating_basis_or_equiv; #define TMPNAME_SUFFIX ".XXXXXX" #define TMPNAME_SUFFIX_LEN ((int)sizeof TMPNAME_SUFFIX - 1) #define MAX_UNIQUE_NUMBER 999999 #define MAX_UNIQUE_LOOP 100 /* get_tmpname() - create a tmp filename for a given filename * * If a tmpdir is defined, use that as the directory to put it in. Otherwise, * the tmp filename is in the same directory as the given name. Note that * there may be no directory at all in the given name! * * The tmp filename is basically the given filename with a dot prepended, and * .XXXXXX appended (for mkstemp() to put its unique gunk in). We take care * to not exceed either the MAXPATHLEN or NAME_MAX, especially the last, as * the basename basically becomes 8 characters longer. In such a case, the * original name is shortened sufficiently to make it all fit. * * If the make_unique arg is True, the XXXXXX string is replaced with a unique * string that doesn't exist at the time of the check. This is intended to be * used for creating hard links, symlinks, devices, and special files, since * normal files should be handled by mkstemp() for safety. * * Of course, the only reason the file is based on the original name is to * make it easier to figure out what purpose a temp file is serving when a * transfer is in progress. */ int get_tmpname(char *fnametmp, const char *fname, BOOL make_unique) { int maxname, length = 0; const char *f; char *suf; if (tmpdir) { /* Note: this can't overflow, so the return value is safe */ length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2); fnametmp[length++] = '/'; } if ((f = strrchr(fname, '/')) != NULL) { ++f; if (!tmpdir) { length = f - fname; /* copy up to and including the slash */ strlcpy(fnametmp, fname, length + 1); } } else f = fname; if (!tmpdir) { /* using a tmpdir avoids the leading dot on our temp names */ if (*f == '.') /* avoid an extra leading dot for OS X's sake */ f++; fnametmp[length++] = '.'; } /* The maxname value is bufsize, and includes space for the '\0'. * NAME_MAX needs an extra -1 for the name's leading dot. */ maxname = MIN(MAXPATHLEN - length - TMPNAME_SUFFIX_LEN, NAME_MAX - 1 - TMPNAME_SUFFIX_LEN); if (maxname < 0) { rprintf(FERROR_XFER, "temporary filename too long: %s\n", fname); fnametmp[0] = '\0'; return 0; } if (maxname) { int added = strlcpy(fnametmp + length, f, maxname); if (added >= maxname) added = maxname - 1; suf = fnametmp + length + added; /* Trim any dangling high-bit chars if the first-trimmed char (if any) is * also a high-bit char, just in case we cut into a multi-byte sequence. * We are guaranteed to stop because of the leading '.' we added. */ if ((int)f[added] & 0x80) { while ((int)suf[-1] & 0x80) suf--; } /* trim one trailing dot before our suffix's dot */ if (suf[-1] == '.') suf--; } else suf = fnametmp + length - 1; /* overwrite the leading dot with suffix's dot */ if (make_unique) { static unsigned counter_limit; unsigned counter; if (!counter_limit) { counter_limit = (unsigned)getpid() + MAX_UNIQUE_LOOP; if (counter_limit > MAX_UNIQUE_NUMBER || counter_limit < MAX_UNIQUE_LOOP) counter_limit = MAX_UNIQUE_LOOP; } counter = counter_limit - MAX_UNIQUE_LOOP; /* This doesn't have to be very good because we don't need * to worry about someone trying to guess the values: all * a conflict will do is cause a device, special file, hard * link, or symlink to fail to be created. Also: avoid * using mktemp() due to gcc's annoying warning. */ while (1) { snprintf(suf, TMPNAME_SUFFIX_LEN+1, ".%d", counter); if (access(fnametmp, 0) < 0) break; if (++counter >= counter_limit) return 0; } } else memcpy(suf, TMPNAME_SUFFIX, TMPNAME_SUFFIX_LEN+1); return 1; } /* Opens a temporary file for writing. * Success: Writes name into fnametmp, returns fd. * Failure: Clobbers fnametmp, returns -1. * Calling cleanup_set() is the caller's job. */ int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file) { int fd; mode_t added_perms; if (!get_tmpname(fnametmp, fname, False)) return -1; if (am_root < 0) { /* For --fake-super, the file must be useable by the copying * user, just like it would be for root. */ added_perms = S_IRUSR|S_IWUSR; } else { /* For a normal copy, we need to be able to tweak things like xattrs. */ added_perms = S_IWUSR; } /* We initially set the perms without the setuid/setgid bits or group * access to ensure that there is no race condition. They will be * correctly updated after the right owner and group info is set. * (Thanks to snabb@epipe.fi for pointing this out.) */ fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS); #if 0 /* In most cases parent directories will already exist because their * information should have been previously transferred, but that may * not be the case with -R */ if (fd == -1 && relative_paths && errno == ENOENT && make_path(fnametmp, MKP_SKIP_SLASH | MKP_DROP_NAME) == 0) { /* Get back to name with XXXXXX in it. */ get_tmpname(fnametmp, fname, False); fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS); } #endif if (fd == -1) { rsyserr(FERROR_XFER, errno, "mkstemp %s failed", full_fname(fnametmp)); return -1; } return fd; } static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, const char *fname, int fd, struct file_struct *file, int inplace_sizing) { static char file_sum1[MAX_DIGEST_LEN]; struct map_struct *mapbuf; struct sum_struct sum; int32 len; OFF_T total_size = F_LENGTH(file); OFF_T offset = 0; OFF_T offset2; char *data; int32 i; char *map = NULL; #ifdef SUPPORT_PREALLOCATION if (preallocate_files && fd != -1 && total_size > 0 && (!inplace_sizing || total_size > size_r)) { /* Try to preallocate enough space for file's eventual length. Can * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */ if ((preallocated_len = do_fallocate(fd, 0, total_size)) < 0) rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname)); } else #endif if (inplace_sizing) { #ifdef HAVE_FTRUNCATE /* The most compatible way to create a sparse file is to start with no length. */ if (sparse_files > 0 && whole_file && fd >= 0 && do_ftruncate(fd, 0) == 0) preallocated_len = 0; else #endif preallocated_len = size_r; } else preallocated_len = 0; read_sum_head(f_in, &sum); if (fd_r >= 0 && size_r > 0) { int32 read_size = MAX(sum.blength * 2, 16*1024); mapbuf = map_file(fd_r, size_r, read_size, sum.blength); if (DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "recv mapped %s of size %s\n", fname_r, big_num(size_r)); } } else mapbuf = NULL; sum_init(xfer_sum_nni, checksum_seed); if (append_mode > 0) { OFF_T j; sum.flength = (OFF_T)sum.count * sum.blength; if (sum.remainder) sum.flength -= sum.blength - sum.remainder; if (append_mode == 2 && mapbuf) { for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) { if (INFO_GTE(PROGRESS, 1)) show_progress(offset, total_size); sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE), CHUNK_SIZE); offset = j; } if (offset < sum.flength) { int32 len = (int32)(sum.flength - offset); if (INFO_GTE(PROGRESS, 1)) show_progress(offset, total_size); sum_update(map_ptr(mapbuf, offset, len), len); } } offset = sum.flength; if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %s, not %s", full_fname(fname), big_num(j), big_num(offset)); exit_cleanup(RERR_FILEIO); } } while ((i = recv_token(f_in, &data)) != 0) { if (INFO_GTE(PROGRESS, 1)) show_progress(offset, total_size); if (allowed_lull) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH | MSK_ACTIVE_RECEIVER); if (i > 0) { if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO,"data recv %d at %s\n", i, big_num(offset)); } stats.literal_data += i; cleanup_got_literal = 1; sum_update(data, i); if (fd != -1 && write_file(fd, 0, offset, data, i) != i) goto report_write_error; offset += i; continue; } i = -(i+1); offset2 = i * (OFF_T)sum.blength; len = sum.blength; if (i == (int)sum.count-1 && sum.remainder != 0) len = sum.remainder; stats.matched_data += len; if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "chunk[%d] of size %ld at %s offset=%s%s\n", i, (long)len, big_num(offset2), big_num(offset), updating_basis_or_equiv && offset == offset2 ? " (seek)" : ""); } if (mapbuf) { map = map_ptr(mapbuf,offset2,len); see_token(map, len); sum_update(map, len); } if (updating_basis_or_equiv) { if (offset == offset2 && fd != -1) { if (skip_matched(fd, offset, map, len) < 0) goto report_write_error; offset += len; continue; } } if (fd != -1 && map && write_file(fd, 0, offset, map, len) != (int)len) goto report_write_error; offset += len; } if (fd != -1 && offset > 0) { if (sparse_files > 0) { if (sparse_end(fd, offset) != 0) goto report_write_error; } else if (flush_write_file(fd) < 0) { report_write_error: rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname)); exit_cleanup(RERR_FILEIO); } } #ifdef HAVE_FTRUNCATE /* inplace: New data could be shorter than old data. * preallocate_files: total_size could have been an overestimate. * Cut off any extra preallocated zeros from dest file. */ if ((inplace_sizing || preallocated_len > offset) && fd != -1 && !IS_DEVICE(file->mode)) { if (do_ftruncate(fd, offset) < 0) rsyserr(FERROR_XFER, errno, "ftruncate failed on %s", full_fname(fname)); } #endif if (INFO_GTE(PROGRESS, 1)) end_progress(total_size); sum_end(file_sum1); if (do_fsync && fd != -1 && fsync(fd) != 0) { rsyserr(FERROR, errno, "fsync failed on %s", full_fname(fname)); exit_cleanup(RERR_FILEIO); } if (mapbuf) unmap_file(mapbuf); read_buf(f_in, sender_file_sum, xfer_sum_len); if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"got file_sum\n"); if (fd != -1 && memcmp(file_sum1, sender_file_sum, xfer_sum_len) != 0) return 0; return 1; } static void discard_receive_data(int f_in, struct file_struct *file) { receive_data(f_in, NULL, -1, 0, NULL, -1, file, 0); } static void handle_delayed_updates(char *local_name) { char *fname, *partialptr; int ndx; for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) { struct file_struct *file = cur_flist->files[ndx]; fname = local_name ? local_name : f_name(file, NULL); if ((partialptr = partial_dir_fname(fname)) != NULL) { if (make_backups > 0 && !make_backup(fname, False)) continue; if (DEBUG_GTE(RECV, 1)) { rprintf(FINFO, "renaming %s to %s\n", partialptr, fname); } /* We don't use robust_rename() here because the * partial-dir must be on the same drive. */ if (do_rename(partialptr, fname) < 0) { rsyserr(FERROR_XFER, errno, "rename failed for %s (from %s)", full_fname(fname), partialptr); } else { if (remove_source_files || (preserve_hard_links && F_IS_HLINKED(file))) send_msg_success(fname, ndx); handle_partial_dir(partialptr, PDIR_DELETE); } } } } static void no_batched_update(int ndx, BOOL is_redo) { struct file_list *flist = flist_for_ndx(ndx, "no_batched_update"); struct file_struct *file = flist->files[ndx - flist->ndx_start]; rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n", is_redo ? " resend of" : "", f_name(file, NULL)); if (inc_recurse && !dry_run) send_msg_int(MSG_NO_SEND, ndx); } static int we_want_redo(int desired_ndx) { static int redo_ndx = -1; while (redo_ndx < desired_ndx) { if (redo_ndx >= 0) no_batched_update(redo_ndx, True); if ((redo_ndx = flist_ndx_pop(&batch_redo_list)) < 0) return 0; } if (redo_ndx == desired_ndx) { redo_ndx = -1; return 1; } return 0; } static int gen_wants_ndx(int desired_ndx, int flist_num) { static int next_ndx = -1; static int done_cnt = 0; static BOOL got_eof = False; if (got_eof) return 0; /* TODO: integrate gen-reading I/O into perform_io() so this is not needed? */ io_flush(FULL_FLUSH); while (next_ndx < desired_ndx) { if (inc_recurse && flist_num <= done_cnt) return 0; if (next_ndx >= 0) no_batched_update(next_ndx, False); if ((next_ndx = read_int(batch_gen_fd)) < 0) { if (inc_recurse) { done_cnt++; continue; } got_eof = True; return 0; } } if (next_ndx == desired_ndx) { next_ndx = -1; return 1; } return 0; } /** * main routine for receiver process. * * Receiver process runs on the same host as the generator process. */ int recv_files(int f_in, int f_out, char *local_name) { int fd1,fd2; STRUCT_STAT st; int iflags, xlen; char *fname, fbuf[MAXPATHLEN]; char xname[MAXPATHLEN]; char *fnametmp, fnametmpbuf[MAXPATHLEN]; char *fnamecmp, *partialptr; char fnamecmpbuf[MAXPATHLEN]; uchar fnamecmp_type; struct file_struct *file; int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i; enum logcode log_code = log_before_transfer ? FLOG : FINFO; int max_phase = protocol_version >= 29 ? 2 : 1; int dflt_perms = (ACCESSPERMS & ~orig_umask); #ifdef SUPPORT_ACLS const char *parent_dirname = ""; #endif int ndx, recv_ok, one_inplace; if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used); if (delay_updates) delayed_bits = bitbag_create(cur_flist->used + 1); if (whole_file < 0) whole_file = 0; progress_init(); while (1) { cleanup_disable(); /* This call also sets cur_flist. */ ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type, xname, &xlen); if (ndx == NDX_DONE) { if (!am_server && cur_flist) { set_current_file_index(NULL, 0); if (INFO_GTE(PROGRESS, 2)) end_progress(0); } if (inc_recurse && first_flist) { if (read_batch) { ndx = first_flist->used + first_flist->ndx_start; gen_wants_ndx(ndx, first_flist->flist_num); } flist_free(first_flist); if (first_flist) continue; } else if (read_batch && first_flist) { ndx = first_flist->used; gen_wants_ndx(ndx, first_flist->flist_num); } if (++phase > max_phase) break; if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "recv_files phase=%d\n", phase); if (phase == 2 && delay_updates) handle_delayed_updates(local_name); write_int(f_out, NDX_DONE); continue; } if (ndx - cur_flist->ndx_start >= 0) file = cur_flist->files[ndx - cur_flist->ndx_start]; else file = dir_flist->files[cur_flist->parent_ndx]; fname = local_name ? local_name : f_name(file, fbuf); if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "recv_files(%s)\n", fname); if (daemon_filter_list.head && (*fname != '.' || fname[1] != '\0')) { int filt_flags = S_ISDIR(file->mode) ? NAME_IS_DIR : NAME_IS_FILE; if (check_filter(&daemon_filter_list, FLOG, fname, filt_flags) < 0) { rprintf(FERROR, "ERROR: rejecting file transfer request for daemon excluded file: %s\n", fname); exit_cleanup(RERR_PROTOCOL); } } #ifdef SUPPORT_XATTRS if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) recv_xattr_request(file, f_in); #endif if (!(iflags & ITEM_TRANSFER)) { maybe_log_item(file, iflags, itemizing, xname); #ifdef SUPPORT_XATTRS if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers && !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)) set_file_attrs(fname, file, NULL, fname, 0); #endif if (iflags & ITEM_IS_NEW) { stats.created_files++; if (S_ISREG(file->mode)) { /* Nothing further to count. */ } else if (S_ISDIR(file->mode)) stats.created_dirs++; #ifdef SUPPORT_LINKS else if (S_ISLNK(file->mode)) stats.created_symlinks++; #endif else if (IS_DEVICE(file->mode)) stats.created_devices++; else stats.created_specials++; } continue; } if (phase == 2) { rprintf(FERROR, "got transfer request in phase 2 [%s]\n", who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (file->flags & FLAG_FILE_SENT) { if (csum_length == SHORT_SUM_LENGTH) { if (keep_partial && !partial_dir) make_backups = -make_backups; /* prevents double backup */ if (append_mode) sparse_files = -sparse_files; append_mode = -append_mode; csum_length = SUM_LENGTH; redoing = 1; } } else { if (csum_length != SHORT_SUM_LENGTH) { if (keep_partial && !partial_dir) make_backups = -make_backups; if (append_mode) sparse_files = -sparse_files; append_mode = -append_mode; csum_length = SHORT_SUM_LENGTH; redoing = 0; } if (iflags & ITEM_IS_NEW) stats.created_files++; } if (!am_server) set_current_file_index(file, ndx); stats.xferred_files++; stats.total_transferred_size += F_LENGTH(file); cleanup_got_literal = 0; if (read_batch) { int wanted = redoing ? we_want_redo(ndx) : gen_wants_ndx(ndx, cur_flist->flist_num); if (!wanted) { rprintf(FINFO, "(Skipping batched update for%s \"%s\")\n", redoing ? " resend of" : "", fname); discard_receive_data(f_in, file); file->flags |= FLAG_FILE_SENT; continue; } } remember_initial_stats(); if (!do_xfers) { /* log the transfer */ log_item(FCLIENT, file, iflags, NULL); if (read_batch) discard_receive_data(f_in, file); continue; } if (write_batch < 0) { log_item(FCLIENT, file, iflags, NULL); if (!am_server) discard_receive_data(f_in, file); if (inc_recurse) send_msg_success(fname, ndx); continue; } partialptr = partial_dir ? partial_dir_fname(fname) : fname; if (protocol_version >= 29) { switch (fnamecmp_type) { case FNAMECMP_FNAME: fnamecmp = fname; break; case FNAMECMP_PARTIAL_DIR: fnamecmp = partialptr; break; case FNAMECMP_BACKUP: fnamecmp = get_backup_name(fname); break; case FNAMECMP_FUZZY: if (file->dirname) { pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, file->dirname, xname); fnamecmp = fnamecmpbuf; } else fnamecmp = xname; break; default: if (fnamecmp_type > FNAMECMP_FUZZY && fnamecmp_type-FNAMECMP_FUZZY <= basis_dir_cnt) { fnamecmp_type -= FNAMECMP_FUZZY + 1; if (file->dirname) { stringjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], "/", file->dirname, "/", xname, NULL); } else pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], xname); } else if (fnamecmp_type >= basis_dir_cnt) { rprintf(FERROR, "invalid basis_dir index: %d.\n", fnamecmp_type); exit_cleanup(RERR_PROTOCOL); } else pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[fnamecmp_type], fname); fnamecmp = fnamecmpbuf; break; } if (!fnamecmp || (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fnamecmp, 0) < 0)) { fnamecmp = fname; fnamecmp_type = FNAMECMP_FNAME; } } else { /* Reminder: --inplace && --partial-dir are never * enabled at the same time. */ if (inplace && make_backups > 0) { if (!(fnamecmp = get_backup_name(fname))) fnamecmp = fname; else fnamecmp_type = FNAMECMP_BACKUP; } else if (partial_dir && partialptr) fnamecmp = partialptr; else fnamecmp = fname; } /* open the file */ fd1 = do_open(fnamecmp, O_RDONLY, 0); if (fd1 == -1 && protocol_version < 29) { if (fnamecmp != fname) { fnamecmp = fname; fnamecmp_type = FNAMECMP_FNAME; fd1 = do_open(fnamecmp, O_RDONLY, 0); } if (fd1 == -1 && basis_dir[0]) { /* pre-29 allowed only one alternate basis */ pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, basis_dir[0], fname); fnamecmp = fnamecmpbuf; fnamecmp_type = FNAMECMP_BASIS_DIR_LOW; fd1 = do_open(fnamecmp, O_RDONLY, 0); } } one_inplace = inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR; updating_basis_or_equiv = one_inplace || (inplace && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP)); if (fd1 == -1) { st.st_mode = 0; st.st_size = 0; } else if (do_fstat(fd1,&st) != 0) { rsyserr(FERROR_XFER, errno, "fstat %s failed", full_fname(fnamecmp)); discard_receive_data(f_in, file); close(fd1); if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); continue; } if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) { /* this special handling for directories * wouldn't be necessary if robust_rename() * and the underlying robust_unlink could cope * with directories */ rprintf(FERROR_XFER, "recv_files: %s is a directory\n", full_fname(fnamecmp)); discard_receive_data(f_in, file); close(fd1); if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); continue; } if (write_devices && IS_DEVICE(st.st_mode)) { if (fd1 != -1 && st.st_size == 0) st.st_size = get_device_size(fd1, fname); /* Mark the file entry as a device so that we don't try to truncate it later on. */ file->mode = S_IFBLK | (file->mode & ACCESSPERMS); } else if (fd1 != -1 && !(S_ISREG(st.st_mode))) { close(fd1); fd1 = -1; } /* If we're not preserving permissions, change the file-list's * mode based on the local permissions and some heuristics. */ if (!preserve_perms) { int exists = fd1 != -1; #ifdef SUPPORT_ACLS const char *dn = file->dirname ? file->dirname : "."; if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { dflt_perms = default_perms_for_dir(dn); parent_dirname = dn; } #endif file->mode = dest_mode(file->mode, st.st_mode, dflt_perms, exists); } /* We now check to see if we are writing the file "inplace" */ if (inplace || one_inplace) { fnametmp = one_inplace ? partialptr : fname; fd2 = do_open(fnametmp, O_WRONLY|O_CREAT, 0600); #ifdef linux if (fd2 == -1 && errno == EACCES) { /* Maybe the error was due to protected_regular setting? */ fd2 = do_open(fname, O_WRONLY, 0600); } #endif if (fd2 == -1) { rsyserr(FERROR_XFER, errno, "open %s failed", full_fname(fnametmp)); } else if (updating_basis_or_equiv) cleanup_set(NULL, NULL, file, fd1, fd2); } else { fnametmp = fnametmpbuf; fd2 = open_tmpfile(fnametmp, fname, file); if (fd2 != -1) cleanup_set(fnametmp, partialptr, file, fd1, fd2); } if (fd2 == -1) { discard_receive_data(f_in, file); if (fd1 != -1) close(fd1); if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); continue; } /* log the transfer */ if (log_before_transfer) log_item(FCLIENT, file, iflags, NULL); else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1)) rprintf(FINFO, "%s\n", fname); /* recv file data */ recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, fname, fd2, file, inplace || one_inplace); log_item(log_code, file, iflags, NULL); if (want_progress_now) instant_progress(fname); if (fd1 != -1) close(fd1); if (close(fd2) < 0) { rsyserr(FERROR, errno, "close failed on %s", full_fname(fnametmp)); exit_cleanup(RERR_FILEIO); } if ((recv_ok && (!delay_updates || !partialptr)) || inplace) { if (partialptr == fname) partialptr = NULL; if (!finish_transfer(fname, fnametmp, fnamecmp, partialptr, file, recv_ok, 1)) recv_ok = -1; else if (fnamecmp == partialptr) { if (!one_inplace) do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); } } else if (keep_partial && partialptr && (!one_inplace || delay_updates)) { if (!handle_partial_dir(partialptr, PDIR_CREATE)) { rprintf(FERROR, "Unable to create partial-dir for %s -- discarding %s.\n", local_name ? local_name : f_name(file, NULL), recv_ok ? "completed file" : "partial file"); do_unlink(fnametmp); recv_ok = -1; } else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL, file, recv_ok, !partial_dir)) recv_ok = -1; else if (delay_updates && recv_ok) { bitbag_set_bit(delayed_bits, ndx); recv_ok = 2; } else partialptr = NULL; } else if (!one_inplace) do_unlink(fnametmp); cleanup_disable(); if (read_batch) file->flags |= FLAG_FILE_SENT; switch (recv_ok) { case 2: break; case 1: if (remove_source_files || inc_recurse || (preserve_hard_links && F_IS_HLINKED(file))) send_msg_success(fname, ndx); break; case 0: { enum logcode msgtype = redoing ? FERROR_XFER : FWARNING; if (msgtype == FERROR_XFER || INFO_GTE(NAME, 1) || stdout_format_has_i) { char *errstr, *redostr, *keptstr; if (!(keep_partial && partialptr) && !inplace) keptstr = "discarded"; else if (partial_dir) keptstr = "put into partial-dir"; else keptstr = "retained"; if (msgtype == FERROR_XFER) { errstr = "ERROR"; redostr = ""; } else { errstr = "WARNING"; redostr = read_batch ? " (may try again)" : " (will try again)"; } rprintf(msgtype, "%s: %s failed verification -- update %s%s.\n", errstr, local_name ? f_name(file, NULL) : fname, keptstr, redostr); } if (!redoing) { if (read_batch) flist_ndx_push(&batch_redo_list, ndx); send_msg_int(MSG_REDO, ndx); file->flags |= FLAG_FILE_SENT; } else if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); break; } case -1: if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); break; } } if (make_backups < 0) make_backups = -make_backups; if (phase == 2 && delay_updates) /* for protocol_version < 29 */ handle_delayed_updates(local_name); if (DEBUG_GTE(RECV, 1)) rprintf(FINFO,"recv_files finished\n"); return 0; } rsync-3.2.7/chmod.c0000664000000000000000000001273613646104106012631 0ustar rootroot/* * Implement the core of the --chmod option. * * Copyright (C) 2002 Scott Howard * Copyright (C) 2005-2020 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 "itypes.h" extern mode_t orig_umask; #define FLAG_X_KEEP (1<<0) #define FLAG_DIRS_ONLY (1<<1) #define FLAG_FILES_ONLY (1<<2) struct chmod_mode_struct { struct chmod_mode_struct *next; int ModeAND, ModeOR; char flags; }; #define CHMOD_ADD 1 #define CHMOD_SUB 2 #define CHMOD_EQ 3 #define CHMOD_SET 4 #define STATE_ERROR 0 #define STATE_1ST_HALF 1 #define STATE_2ND_HALF 2 #define STATE_OCTAL_NUM 3 /* Parse a chmod-style argument, and break it down into one or more AND/OR * pairs in a linked list. We return a pointer to new items on success * (appending the items to the specified list), or NULL on error. */ struct chmod_mode_struct *parse_chmod(const char *modestr, struct chmod_mode_struct **root_mode_ptr) { int state = STATE_1ST_HALF; int where = 0, what = 0, op = 0, topbits = 0, topoct = 0, flags = 0; struct chmod_mode_struct *first_mode = NULL, *curr_mode = NULL, *prev_mode = NULL; while (state != STATE_ERROR) { if (!*modestr || *modestr == ',') { int bits; if (!op) { state = STATE_ERROR; break; } prev_mode = curr_mode; curr_mode = new_array(struct chmod_mode_struct, 1); if (prev_mode) prev_mode->next = curr_mode; else first_mode = curr_mode; curr_mode->next = NULL; if (where) bits = where * what; else { where = 0111; bits = (where * what) & ~orig_umask; } switch (op) { case CHMOD_ADD: curr_mode->ModeAND = CHMOD_BITS; curr_mode->ModeOR = bits + topoct; break; case CHMOD_SUB: curr_mode->ModeAND = CHMOD_BITS - bits - topoct; curr_mode->ModeOR = 0; break; case CHMOD_EQ: curr_mode->ModeAND = CHMOD_BITS - (where * 7) - (topoct ? topbits : 0); curr_mode->ModeOR = bits + topoct; break; case CHMOD_SET: curr_mode->ModeAND = 0; curr_mode->ModeOR = bits; break; } curr_mode->flags = flags; if (!*modestr) break; modestr++; state = STATE_1ST_HALF; where = what = op = topoct = topbits = flags = 0; } switch (state) { case STATE_1ST_HALF: switch (*modestr) { case 'D': if (flags & FLAG_FILES_ONLY) state = STATE_ERROR; flags |= FLAG_DIRS_ONLY; break; case 'F': if (flags & FLAG_DIRS_ONLY) state = STATE_ERROR; flags |= FLAG_FILES_ONLY; break; case 'u': where |= 0100; topbits |= 04000; break; case 'g': where |= 0010; topbits |= 02000; break; case 'o': where |= 0001; break; case 'a': where |= 0111; break; case '+': op = CHMOD_ADD; state = STATE_2ND_HALF; break; case '-': op = CHMOD_SUB; state = STATE_2ND_HALF; break; case '=': op = CHMOD_EQ; state = STATE_2ND_HALF; break; default: if (isDigit(modestr) && *modestr < '8' && !where) { op = CHMOD_SET; state = STATE_OCTAL_NUM; where = 1; what = *modestr - '0'; } else state = STATE_ERROR; break; } break; case STATE_2ND_HALF: switch (*modestr) { case 'r': what |= 4; break; case 'w': what |= 2; break; case 'X': flags |= FLAG_X_KEEP; /* FALL THROUGH */ case 'x': what |= 1; break; case 's': if (topbits) topoct |= topbits; else topoct = 04000; break; case 't': topoct |= 01000; break; default: state = STATE_ERROR; break; } break; case STATE_OCTAL_NUM: if (isDigit(modestr) && *modestr < '8') { what = what*8 + *modestr - '0'; if (what > CHMOD_BITS) state = STATE_ERROR; } else state = STATE_ERROR; break; } modestr++; } if (state == STATE_ERROR) { free_chmod_mode(first_mode); return NULL; } if (!(curr_mode = *root_mode_ptr)) *root_mode_ptr = first_mode; else { while (curr_mode->next) curr_mode = curr_mode->next; curr_mode->next = first_mode; } return first_mode; } /* Takes an existing file permission and a list of AND/OR changes, and * create a new permissions. */ int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes) { int IsX = mode & 0111; int NonPerm = mode & ~CHMOD_BITS; for ( ; chmod_modes; chmod_modes = chmod_modes->next) { if ((chmod_modes->flags & FLAG_DIRS_ONLY) && !S_ISDIR(NonPerm)) continue; if ((chmod_modes->flags & FLAG_FILES_ONLY) && S_ISDIR(NonPerm)) continue; mode &= chmod_modes->ModeAND; if ((chmod_modes->flags & FLAG_X_KEEP) && !IsX && !S_ISDIR(NonPerm)) mode |= chmod_modes->ModeOR & ~0111; else mode |= chmod_modes->ModeOR; } return mode | NonPerm; } /* Free the linked list created by parse_chmod. */ int free_chmod_mode(struct chmod_mode_struct *chmod_modes) { struct chmod_mode_struct *next; while (chmod_modes) { next = chmod_modes->next; free(chmod_modes); chmod_modes = next; } return 0; } rsync-3.2.7/access.c0000664000000000000000000001415614170671375013010 0ustar rootroot/* * Routines to authenticate access to a daemon (hosts allow/deny). * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2004-2022 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" #ifdef HAVE_NETGROUP_H #include #endif static int allow_forward_dns; extern const char undetermined_hostname[]; static int match_hostname(const char **host_ptr, const char *addr, const char *tok) { struct hostent *hp; unsigned int i; const char *host = *host_ptr; if (!host || !*host) return 0; #ifdef HAVE_INNETGR if (*tok == '@' && tok[1]) return innetgr(tok + 1, host, NULL, NULL); #endif /* First check if the reverse-DNS-determined hostname matches. */ if (iwildmatch(tok, host)) return 1; if (!allow_forward_dns) return 0; /* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */ if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")]) return 0; /* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */ if (!(hp = gethostbyname(tok))) return 0; for (i = 0; hp->h_addr_list[i] != NULL; i++) { if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) { /* If reverse lookups are off, we'll use the conf-specified * hostname in preference to UNDETERMINED. */ if (host == undetermined_hostname) *host_ptr = strdup(tok); return 1; } } return 0; } static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen) { int i; for (i = 0; i < addrlen; i++) { if ((b1[i] ^ b2[i]) & mask[i]) return 0; } return 1; } static void make_mask(char *mask, int plen, int addrlen) { int w, b; w = plen >> 3; b = plen & 0x7; if (w) memset(mask, 0xff, w); if (w < addrlen) mask[w] = 0xff & (0xff<<(8-b)); if (w+1 < addrlen) memset(mask+w+1, 0, addrlen-w-1); return; } static int match_address(const char *addr, const char *tok) { char *p; struct addrinfo hints, *resa, *rest; int gai; int ret = 0; int addrlen = 0; #ifdef HAVE_STRTOL long int bits; #else int bits; #endif char mask[16]; char *a = NULL, *t = NULL; if (!addr || !*addr) return 0; p = strchr(tok,'/'); if (p) *p = '\0'; /* Fail quietly if tok is a hostname, not an address. */ if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) { if (p) *p = '/'; return 0; } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifdef AI_NUMERICHOST hints.ai_flags = AI_NUMERICHOST; #endif if (getaddrinfo(addr, NULL, &hints, &resa) != 0) { if (p) *p = '/'; return 0; } gai = getaddrinfo(tok, NULL, &hints, &rest); if (p) *p++ = '/'; if (gai != 0) { rprintf(FLOG, "error matching address %s: %s\n", tok, gai_strerror(gai)); freeaddrinfo(resa); return 0; } if (rest->ai_family != resa->ai_family) { ret = 0; goto out; } switch(resa->ai_family) { case PF_INET: a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr; t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr; addrlen = 4; break; #ifdef INET6 case PF_INET6: { struct sockaddr_in6 *sin6a, *sin6t; sin6a = (struct sockaddr_in6 *)resa->ai_addr; sin6t = (struct sockaddr_in6 *)rest->ai_addr; a = (char *)&sin6a->sin6_addr; t = (char *)&sin6t->sin6_addr; addrlen = 16; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID if (sin6t->sin6_scope_id && sin6a->sin6_scope_id != sin6t->sin6_scope_id) { ret = 0; goto out; } #endif break; } #endif default: rprintf(FLOG, "unknown family %u\n", rest->ai_family); ret = 0; goto out; } bits = -1; if (p) { if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) { #ifdef HAVE_STRTOL char *ep = NULL; #else unsigned char *pp; #endif #ifdef HAVE_STRTOL bits = strtol(p, &ep, 10); if (!*p || *ep) { rprintf(FLOG, "malformed mask in %s\n", tok); ret = 0; goto out; } #else for (pp = (unsigned char *)p; *pp; pp++) { if (!isascii(*pp) || !isdigit(*pp)) { rprintf(FLOG, "malformed mask in %s\n", tok); ret = 0; goto out; } } bits = atoi(p); #endif if (bits == 0) { ret = 1; goto out; } if (bits < 0 || bits > (addrlen << 3)) { rprintf(FLOG, "malformed mask in %s\n", tok); ret = 0; goto out; } } } else { bits = 128; } if (bits >= 0) make_mask(mask, bits, addrlen); ret = match_binary(a, t, mask, addrlen); out: freeaddrinfo(resa); freeaddrinfo(rest); return ret; } static int access_match(const char *list, const char *addr, const char **host_ptr) { char *tok; char *list2 = strdup(list); strlower(list2); for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) { if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) { free(list2); return 1; } } free(list2); return 0; } int allow_access(const char *addr, const char **host_ptr, int i) { const char *allow_list = lp_hosts_allow(i); const char *deny_list = lp_hosts_deny(i); if (allow_list && !*allow_list) allow_list = NULL; if (deny_list && !*deny_list) deny_list = NULL; allow_forward_dns = lp_forward_lookup(i); /* If we match an allow-list item, we always allow access. */ if (allow_list) { if (access_match(allow_list, addr, host_ptr)) return 1; /* For an allow-list w/o a deny-list, disallow non-matches. */ if (!deny_list) return 0; } /* If we match a deny-list item (and got past any allow-list * items), we always disallow access. */ if (deny_list && access_match(deny_list, addr, host_ptr)) return 0; /* Allow all other access. */ return 1; } rsync-3.2.7/hashtable.c0000664000000000000000000005272114315642465013501 0ustar rootroot/* * Routines to provide a memory-efficient hashtable. * * Copyright (C) 2007-2022 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" #define HASH_LOAD_LIMIT(size) ((size)*3/4) struct hashtable *hashtable_create(int size, int key64) { int req = size; struct hashtable *tbl; int node_size = key64 ? sizeof (struct ht_int64_node) : sizeof (struct ht_int32_node); /* Pick a power of 2 that can hold the requested size. */ if (size & (size-1) || size < 16) { size = 16; while (size < req) size *= 2; } tbl = new(struct hashtable); tbl->nodes = new_array0(char, size * node_size); tbl->size = size; tbl->entries = 0; tbl->node_size = node_size; tbl->key64 = key64 ? 1 : 0; if (DEBUG_GTE(HASH, 1)) { char buf[32]; if (req != size) snprintf(buf, sizeof buf, "req: %d, ", req); else *buf = '\0'; rprintf(FINFO, "[%s] created hashtable %lx (%ssize: %d, keys: %d-bit)\n", who_am_i(), (long)tbl, buf, size, key64 ? 64 : 32); } return tbl; } void hashtable_destroy(struct hashtable *tbl) { if (DEBUG_GTE(HASH, 1)) { rprintf(FINFO, "[%s] destroyed hashtable %lx (size: %d, keys: %d-bit)\n", who_am_i(), (long)tbl, tbl->size, tbl->key64 ? 64 : 32); } free(tbl->nodes); free(tbl); } /* Returns the node that holds the indicated key if it exists. When it does not * exist, it returns either NULL (when data_when_new is NULL), or it returns a * new node with its node->data set to the indicated value. * * If your code doesn't know the data value for a new node in advance (usually * because it doesn't know if a node is new or not) you should pass in a unique * (non-0) value that you can use to check if the returned node is new. You can * then overwrite the data with any value you want (even 0) since it only needs * to be different than whatever data_when_new value you use later on. * * This return is a void* just because it might be pointing at a ht_int32_node * or a ht_int64_node, and that makes the caller's assignment a little easier. */ void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new) { int key64 = tbl->key64; struct ht_int32_node *node; uint32 ndx; if (key64 ? key == 0 : (int32)key == 0) { rprintf(FERROR, "Internal hashtable error: illegal key supplied!\n"); exit_cleanup(RERR_MESSAGEIO); } if (data_when_new && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) { void *old_nodes = tbl->nodes; int size = tbl->size * 2; int i; tbl->nodes = new_array0(char, size * tbl->node_size); tbl->size = size; tbl->entries = 0; if (DEBUG_GTE(HASH, 1)) { rprintf(FINFO, "[%s] growing hashtable %lx (size: %d, keys: %d-bit)\n", who_am_i(), (long)tbl, size, key64 ? 64 : 32); } for (i = size / 2; i-- > 0; ) { struct ht_int32_node *move_node = HT_NODE(tbl, old_nodes, i); int64 move_key = HT_KEY(move_node, key64); if (move_key == 0) continue; if (move_node->data) hashtable_find(tbl, move_key, move_node->data); else { node = hashtable_find(tbl, move_key, ""); node->data = 0; } } free(old_nodes); } if (!key64) { /* Based on Jenkins One-at-a-time hash. */ uchar buf[4], *keyp = buf; int i; SIVALu(buf, 0, key); for (ndx = 0, i = 0; i < 4; i++) { ndx += keyp[i]; ndx += (ndx << 10); ndx ^= (ndx >> 6); } ndx += (ndx << 3); ndx ^= (ndx >> 11); ndx += (ndx << 15); } else { /* Based on Jenkins hashword() from lookup3.c. */ uint32 a, b, c; /* Set up the internal state */ a = b = c = 0xdeadbeef + (8 << 2); #define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k)))) #if SIZEOF_INT64 >= 8 b += (uint32)(key >> 32); #endif a += (uint32)key; c ^= b; c -= rot(b, 14); a ^= c; a -= rot(c, 11); b ^= a; b -= rot(a, 25); c ^= b; c -= rot(b, 16); a ^= c; a -= rot(c, 4); b ^= a; b -= rot(a, 14); c ^= b; c -= rot(b, 24); #undef rot ndx = c; } /* If it already exists, return the node. If we're not * allocating, return NULL if the key is not found. */ while (1) { int64 nkey; ndx &= tbl->size - 1; node = HT_NODE(tbl, tbl->nodes, ndx); nkey = HT_KEY(node, key64); if (nkey == key) return node; if (nkey == 0) { if (!data_when_new) return NULL; break; } ndx++; } /* Take over this empty spot and then return the node. */ if (key64) ((struct ht_int64_node*)node)->key = key; else node->key = (int32)key; node->data = data_when_new; tbl->entries++; return node; } #ifndef WORDS_BIGENDIAN # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 #else # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 #endif /* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hash_word(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. */ #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) /* ------------------------------------------------------------------------------- mix -- mix 3 32-bit values reversibly. This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix(). If four pairs of (a,b,c) inputs are run through mix(), or through mix() in reverse, there are at least 32 bits of the output that are sometimes the same for one pair and different for another pair. This was tested for: * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this are 4 6 8 16 19 4 9 15 3 18 27 15 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) that fail to affect some output bits of (a,b,c), especially of a. The most thoroughly mixed value is c, but it doesn't really even achieve avalanche in c. This allows some parallelism. Read-after-writes are good at doubling the number of bits affected, so the goal of mixing pulls in the opposite direction as the goal of parallelism. I did what I could. Rotates seem to cost as much as shifts on every machine I could lay my hands on, and rotates are much kinder to the top and bottom bits, so I used rotates. ------------------------------------------------------------------------------- */ #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } /* ------------------------------------------------------------------------------- final -- final mixing of 3 32-bit values (a,b,c) into c Pairs of (a,b,c) values differing in only a few bits will usually produce values of c that look totally different. This was tested for * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: 14 11 25 16 4 14 24 12 14 25 16 4 14 24 and these came close: 4 8 15 26 3 22 24 10 8 15 26 3 22 24 11 8 15 26 3 22 24 ------------------------------------------------------------------------------- */ #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c,4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } /* ------------------------------------------------------------------------------- hashlittle() -- hash a variable-length key into a 32-bit value k : the key (the unaligned variable-length array of bytes) length : the length of the key, counting by bytes val2 : IN: can be any 4-byte value OUT: second 32 bit hash. Returns a 32-bit value. Every bit of the key affects every bit of the return value. Two keys differing by one or two bits will have totally different hash values. Note that the return value is better mixed than val2, so use that first. The best hash table sizes are powers of 2. There is no need to do mod a prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. For example, if you need only 10 bits, do h = (h & hashmask(10)); In which case, the hash table should have hashsize(10) elements. If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0; i 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return NON_ZERO_32(c); } } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return NON_ZERO_32(c); /* zero length requires no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; /* FALLTHROUGH */ case 11: c+=((uint32_t)k[10])<<16; /* FALLTHROUGH */ case 10: c+=((uint32_t)k[9])<<8; /* FALLTHROUGH */ case 9 : c+=k[8]; /* FALLTHROUGH */ case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHROUGH */ case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHROUGH */ case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHROUGH */ case 5 : b+=k[4]; /* FALLTHROUGH */ case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHROUGH */ case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHROUGH */ case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHROUGH */ case 1 : a+=k[0]; break; case 0 : return NON_ZERO_32(c); } } final(a,b,c); return NON_ZERO_32(c); } #if SIZEOF_INT64 >= 8 /* * hashlittle2: return 2 32-bit hash values joined into an int64. * * This is identical to hashlittle(), except it returns two 32-bit hash * values instead of just one. This is good enough for hash table * lookup with 2^^64 buckets, or if you want a second hash if you're not * happy with the first, or if you want a probably-unique 64-bit ID for * the key. *pc is better mixed than *pb, so use *pc first. If you want * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". */ int64 hashlittle2(const void *key, size_t length) { uint32_t a,b,c; /* internal state */ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)length); u.ptr = key; if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ const uint8_t *k8; /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return NON_ZERO_64(b, c); } } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return NON_ZERO_64(b, c); /* zero length strings require no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; /* FALLTHROUGH */ case 11: c+=((uint32_t)k[10])<<16; /* FALLTHROUGH */ case 10: c+=((uint32_t)k[9])<<8; /* FALLTHROUGH */ case 9 : c+=k[8]; /* FALLTHROUGH */ case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHROUGH */ case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHROUGH */ case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHROUGH */ case 5 : b+=k[4]; /* FALLTHROUGH */ case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHROUGH */ case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHROUGH */ case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHROUGH */ case 1 : a+=k[0]; break; case 0 : return NON_ZERO_64(b, c); } } final(a,b,c); return NON_ZERO_64(b, c); } #else #define hashlittle2(key, len) hashlittle(key, len) #endif rsync-3.2.7/byteorder.h0000664000000000000000000000557014276226634013554 0ustar rootroot/* * Simple byteorder handling. * * Copyright (C) 1992-1995 Andrew Tridgell * Copyright (C) 2007-2022 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. */ #undef CAREFUL_ALIGNMENT /* We know that the x86 can handle misalignment and has the same * byte order (LSB-first) as the 32-bit numbers we transmit. */ #if defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__ || __amd64 #define CAREFUL_ALIGNMENT 0 #endif #ifndef CAREFUL_ALIGNMENT #define CAREFUL_ALIGNMENT 1 #endif #define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) #define UVAL(buf,pos) ((uint32)CVAL(buf,pos)) #if CAREFUL_ALIGNMENT static inline uint32 IVALu(const uchar *buf, int pos) { return UVAL(buf, pos) | UVAL(buf, pos + 1) << 8 | UVAL(buf, pos + 2) << 16 | UVAL(buf, pos + 3) << 24; } static inline void SIVALu(uchar *buf, int pos, uint32 val) { CVAL(buf, pos) = val; CVAL(buf, pos + 1) = val >> 8; CVAL(buf, pos + 2) = val >> 16; CVAL(buf, pos + 3) = val >> 24; } static inline int64 IVAL64(const char *buf, int pos) { return IVALu((uchar*)buf, pos) | (int64)IVALu((uchar*)buf, pos + 4) << 32; } static inline void SIVAL64(char *buf, int pos, int64 val) { SIVALu((uchar*)buf, pos, val); SIVALu((uchar*)buf, pos + 4, val >> 32); } #else /* !CAREFUL_ALIGNMENT */ /* This handles things for architectures like the 386 that can handle alignment errors. * WARNING: This section is dependent on the length of an int32 (and thus a uint32) * being correct (4 bytes)! Set CAREFUL_ALIGNMENT if it is not. */ static inline uint32 IVALu(const uchar *buf, int pos) { union { const uchar *b; const uint32 *num; } u; u.b = buf + pos; return *u.num; } static inline void SIVALu(uchar *buf, int pos, uint32 val) { union { uchar *b; uint32 *num; } u; u.b = buf + pos; *u.num = val; } static inline int64 IVAL64(const char *buf, int pos) { union { const char *b; const int64 *num; } u; u.b = buf + pos; return *u.num; } static inline void SIVAL64(char *buf, int pos, int64 val) { union { char *b; int64 *num; } u; u.b = buf + pos; *u.num = val; } #endif /* !CAREFUL_ALIGNMENT */ static inline uint32 IVAL(const char *buf, int pos) { return IVALu((uchar*)buf, pos); } static inline void SIVAL(char *buf, int pos, uint32 val) { SIVALu((uchar*)buf, pos, val); } rsync-3.2.7/getfsdev.c0000664000000000000000000000056613671304046013347 0ustar rootroot#include "rsync.h" int main(int argc, char *argv[]) { STRUCT_STAT st; int ret; while (--argc > 0) { #ifdef USE_STAT64_FUNCS ret = stat64(*++argv, &st); #else ret = stat(*++argv, &st); #endif if (ret < 0) { fprintf(stderr, "Unable to stat `%s'\n", *argv); exit(1); } printf("%ld/%ld\n", (long)major(st.st_dev), (long)minor(st.st_dev)); } return 0; } rsync-3.2.7/simd-checksum-avx2.S0000664000000000000000000000641414210262311015114 0ustar rootroot#include "config.h" #ifdef USE_ROLL_ASM /* { */ #define CHAR_OFFSET 0 /* Keep this the same as rsync.h, which isn't likely to change. */ #ifdef __APPLE__ #define get_checksum1_avx2_asm _get_checksum1_avx2_asm #endif .intel_syntax noprefix .text .p2align 5 .globl get_checksum1_avx2_asm # rdi=*buf, esi=len, edx=i, rcx= *ps1, r8= *ps2 get_checksum1_avx2_asm: vmovd xmm6,[rcx] # load *ps1 lea eax, [rsi-128] # at least 128 bytes to process? cmp edx, eax jg .exit lea rax, .mul_T2[rip] vmovntdqa ymm7, [rax] # load T2 multiplication constants vmovntdqa ymm12,[rax+32]# from memory. vpcmpeqd ymm15, ymm15, ymm15 # set all elements to -1. #if CHAR_OFFSET != 0 mov eax, 32*CHAR_OFFSET vmovd xmm10, eax vpbroadcastd ymm10, xmm10 mov eax, 528*CHAR_OFFSET vmovd xmm13, eax vpbroadcastd ymm13, xmm13 #endif vpabsb ymm15, ymm15 # set all byte size elements to 1. add rdi, rdx vmovdqu ymm2, [rdi] # preload the first 64 bytes. vmovdqu ymm3, [rdi+32] and esi, ~63 # only needed during final reduction, # done here to avoid a longer nop for # alignment below. add edx, esi shr rsi, 6 # longer opcode for alignment add rdi, 64 vpxor xmm1, xmm1, xmm1 # reset both partial sums accumulators. vpxor xmm4, xmm4, xmm4 mov eax, [r8] .p2align 4 # should fit into the LSD allocation queue. .loop: vpmaddubsw ymm0, ymm15, ymm2 # s1 partial sums vpmaddubsw ymm5, ymm15, ymm3 vmovdqu ymm8, [rdi] # preload the next vmovdqu ymm9, [rdi+32] # 64 bytes. add rdi, 64 vpaddd ymm4, ymm4, ymm6 vpaddw ymm5, ymm5, ymm0 vpsrld ymm0, ymm5, 16 vpaddw ymm5, ymm0, ymm5 vpaddd ymm6, ymm5, ymm6 vpmaddubsw ymm2, ymm7, ymm2 # s2 partial sums vpmaddubsw ymm3, ymm12, ymm3 prefetcht0 [rdi+384] # prefetch 6 cachelines ahead. vpaddw ymm3, ymm2, ymm3 vpsrldq ymm2, ymm3, 2 vpaddd ymm3, ymm2, ymm3 vpaddd ymm1, ymm1, ymm3 #if CHAR_OFFSET != 0 vpaddd ymm6, ymm10, ymm6 # 32*CHAR_OFFSET vpaddd ymm1, ymm13, ymm1 # 528*CHAR_OFFSET #endif vmovdqa ymm2, ymm8 # move the next 64 bytes vmovdqa ymm3, ymm9 # into the right registers sub esi, 1 jnz .loop # now we reduce the partial sums. vpslld ymm3, ymm4, 6 vpsrldq ymm2, ymm6, 4 vpaddd ymm0, ymm3, ymm1 vpaddd ymm6, ymm2, ymm6 vpsrlq ymm3, ymm0, 32 vpsrldq ymm2, ymm6, 8 vpaddd ymm0, ymm3, ymm0 vpsrldq ymm3, ymm0, 8 vpaddd ymm6, ymm2, ymm6 vpaddd ymm0, ymm3, ymm0 vextracti128 xmm2, ymm6, 0x1 vextracti128 xmm1, ymm0, 0x1 vpaddd xmm6, xmm2, xmm6 vmovd [rcx], xmm6 vpaddd xmm1, xmm1, xmm0 vmovd ecx, xmm1 add eax, ecx mov [r8], eax .exit: vzeroupper mov eax, edx ret #ifdef __APPLE__ .data .align 6 #else .section .rodata .p2align 6 #endif .mul_T2: .byte 64 .byte 63 .byte 62 .byte 61 .byte 60 .byte 59 .byte 58 .byte 57 .byte 56 .byte 55 .byte 54 .byte 53 .byte 52 .byte 51 .byte 50 .byte 49 .byte 48 .byte 47 .byte 46 .byte 45 .byte 44 .byte 43 .byte 42 .byte 41 .byte 40 .byte 39 .byte 38 .byte 37 .byte 36 .byte 35 .byte 34 .byte 33 .byte 32 .byte 31 .byte 30 .byte 29 .byte 28 .byte 27 .byte 26 .byte 25 .byte 24 .byte 23 .byte 22 .byte 21 .byte 20 .byte 19 .byte 18 .byte 17 .byte 16 .byte 15 .byte 14 .byte 13 .byte 12 .byte 11 .byte 10 .byte 9 .byte 8 .byte 7 .byte 6 .byte 5 .byte 4 .byte 3 .byte 2 .byte 1 #endif /* } USE_ROLL_ASM */ rsync-3.2.7/cmd-or-msg0000775000000000000000000000024614124222242013251 0ustar rootroot#!/bin/sh srcdir=`dirname $0` opt="$1" shift echo "$*" if ! "${@}"; then echo "If you can't fix the issue, re-run $srcdir/configure with --$opt." exit 1 fi rsync-3.2.7/errcode.h0000664000000000000000000000541613443220465013166 0ustar rootroot/* * Error codes returned by rsync. * * Copyright (C) 1998-2000 Andrew Tridgell * Copyright (C) 2003-2019 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. */ /* If you change these, please also update the string mappings in log.c and * the EXIT VALUES in rsync.yo. */ #define RERR_OK 0 #define RERR_SYNTAX 1 /* syntax or usage error */ #define RERR_PROTOCOL 2 /* protocol incompatibility */ #define RERR_FILESELECT 3 /* errors selecting input/output files, dirs */ #define RERR_UNSUPPORTED 4 /* requested action not supported */ #define RERR_STARTCLIENT 5 /* error starting client-server protocol */ #define RERR_SOCKETIO 10 /* error in socket IO */ #define RERR_FILEIO 11 /* error in file IO */ #define RERR_STREAMIO 12 /* error in rsync protocol data stream */ #define RERR_MESSAGEIO 13 /* errors with program diagnostics */ #define RERR_IPC 14 /* error in IPC code */ #define RERR_CRASHED 15 /* sibling crashed */ #define RERR_TERMINATED 16 /* sibling terminated abnormally */ #define RERR_SIGNAL1 19 /* status returned when sent SIGUSR1 */ #define RERR_SIGNAL 20 /* status returned when sent SIGINT, SIGTERM, SIGHUP */ #define RERR_WAITCHILD 21 /* some error returned by waitpid() */ #define RERR_MALLOC 22 /* error allocating core memory buffers */ #define RERR_PARTIAL 23 /* partial transfer */ #define RERR_VANISHED 24 /* file(s) vanished on sender side */ #define RERR_DEL_LIMIT 25 /* skipped some deletes due to --max-delete */ #define RERR_TIMEOUT 30 /* timeout in data send/receive */ #define RERR_CONTIMEOUT 35 /* timeout waiting for daemon connection */ /* Although it doesn't seem to be specified anywhere, * ssh and the shell seem to return these values: * * 124 if the command exited with status 255 * 125 if the command is killed by a signal * 126 if the command cannot be run * 127 if the command is not found * * and we could use this to give a better explanation if the remote * command is not found. */ #define RERR_CMD_FAILED 124 #define RERR_CMD_KILLED 125 #define RERR_CMD_RUN 126 #define RERR_CMD_NOTFOUND 127 rsync-3.2.7/clientserver.c0000664000000000000000000011761314315642342014247 0ustar rootroot/* * The socket based protocol for setting up a connection with rsyncd. * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2001-2002 Martin Pool * Copyright (C) 2002-2022 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 "itypes.h" #include "ifuncs.h" extern int quiet; extern int dry_run; extern int output_motd; extern int list_only; extern int am_sender; extern int am_server; extern int am_daemon; extern int am_root; extern int msgs2stderr; extern int rsync_port; extern int protect_args; extern int ignore_errors; extern int preserve_xattrs; extern int kluge_around_eof; extern int munge_symlinks; extern int open_noatime; extern int sanitize_paths; extern int numeric_ids; extern int filesfrom_fd; extern int remote_protocol; extern int protocol_version; extern int io_timeout; extern int no_detach; extern int write_batch; extern int old_style_args; extern int default_af_hint; extern int logfile_format_has_i; extern int logfile_format_has_o_or_i; extern char *bind_address; extern char *config_file; extern char *logfile_format; extern char *files_from; extern char *tmpdir; extern char *early_input_file; extern struct chmod_mode_struct *chmod_modes; extern filter_rule_list daemon_filter_list; #ifdef ICONV_OPTION extern char *iconv_opt; extern iconv_t ic_send, ic_recv; #endif extern uid_t our_uid; extern gid_t our_gid; char *auth_user; char *daemon_auth_choices; int read_only = 0; int module_id = -1; int pid_file_fd = -1; int early_input_len = 0; char *early_input = NULL; pid_t namecvt_pid = 0; struct chmod_mode_struct *daemon_chmod_modes; #define EARLY_INPUT_CMD "#early_input=" #define EARLY_INPUT_CMDLEN (sizeof EARLY_INPUT_CMD - 1) /* module_dirlen is the length of the module_dir string when in daemon * mode and module_dir is not "/"; otherwise 0. (Note that a chroot- * enabled module can have a non-"/" module_dir these days.) */ char *module_dir = NULL; unsigned int module_dirlen = 0; char *full_module_path; static int rl_nulls = 0; static int namecvt_fd_req = -1, namecvt_fd_ans = -1; #ifdef HAVE_SIGACTION static struct sigaction sigact; #endif static item_list gid_list = EMPTY_ITEM_LIST; /* Used when "reverse lookup" is off. */ const char undetermined_hostname[] = "UNDETERMINED"; /** * Run a client connected to an rsyncd. The alternative to this * function for remote-shell connections is do_cmd(). * * After negotiating which module to use and reading the server's * motd, this hands over to client_run(). Telling the server the * module will cause it to chroot/setuid/etc. * * Instead of doing a transfer, the client may at this stage instead * get a listing of remote modules and exit. * * @return -1 for error in startup, or the result of client_run(). * Either way, it eventually gets passed to exit_cleanup(). **/ int start_socket_client(char *host, int remote_argc, char *remote_argv[], int argc, char *argv[]) { int fd, ret; char *p, *user = NULL; /* This is redundant with code in start_inband_exchange(), but this * short-circuits a problem in the client before we open a socket, * and the extra check won't hurt. */ if (**remote_argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name not a /\n"); return -1; } if ((p = strrchr(host, '@')) != NULL) { user = host; host = p+1; *p = '\0'; } fd = open_socket_out_wrapped(host, rsync_port, bind_address, default_af_hint); if (fd == -1) exit_cleanup(RERR_SOCKETIO); #ifdef ICONV_CONST setup_iconv(); #endif ret = start_inband_exchange(fd, fd, user, remote_argc, remote_argv); return ret ? ret : client_run(fd, fd, -1, argc, argv); } static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client) { int remote_sub = -1; int our_sub = get_subprotocol_version(); output_daemon_greeting(f_out, am_client); if (!am_client) { char *motd = lp_motd_file(); if (motd && *motd) { FILE *f = fopen(motd, "r"); while (f && !feof(f)) { int len = fread(buf, 1, bufsiz - 1, f); if (len > 0) write_buf(f_out, buf, len); } if (f) fclose(f); write_sbuf(f_out, "\n"); } } /* This strips the \n. */ if (!read_line_old(f_in, buf, bufsiz, 0)) { if (am_client) rprintf(FERROR, "rsync: did not see server greeting\n"); return -1; } if (sscanf(buf, "@RSYNCD: %d.%d", &remote_protocol, &remote_sub) < 1) { if (am_client) rprintf(FERROR, "rsync: server sent \"%s\" rather than greeting\n", buf); else io_printf(f_out, "@ERROR: protocol startup error\n"); return -1; } if (remote_sub < 0) { if (remote_protocol >= 30) { if (am_client) rprintf(FERROR, "rsync: the server omitted the subprotocol value: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the subprotocol value: %s\n", buf); return -1; } remote_sub = 0; } daemon_auth_choices = strchr(buf + 9, ' '); if (daemon_auth_choices) { char *cp; daemon_auth_choices = strdup(daemon_auth_choices + 1); if ((cp = strchr(daemon_auth_choices, '\n')) != NULL) *cp = '\0'; } else if (remote_protocol > 31) { if (am_client) rprintf(FERROR, "rsync: the server omitted the digest name list: %s\n", buf); else io_printf(f_out, "@ERROR: your client omitted the digest name list: %s\n", buf); return -1; } if (protocol_version > remote_protocol) { protocol_version = remote_protocol; if (remote_sub) protocol_version--; } else if (protocol_version == remote_protocol) { if (remote_sub != our_sub) protocol_version--; } #if SUBPROTOCOL_VERSION != 0 else if (protocol_version < remote_protocol) { if (our_sub) protocol_version--; } #endif if (protocol_version >= 30) rl_nulls = 1; return 0; } int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]) { int i, modlen; char line[BIGPATHBUFLEN]; char *sargs[MAX_ARGS]; int sargc = 0; char *p, *modname; assert(argc > 0 && *argv != NULL); if (**argv == '/') { rprintf(FERROR, "ERROR: The remote path must start with a module name\n"); return -1; } if (!(p = strchr(*argv, '/'))) modlen = strlen(*argv); else modlen = p - *argv; modname = new_array(char, modlen+1+1); /* room for '/' & '\0' */ strlcpy(modname, *argv, modlen + 1); modname[modlen] = '/'; modname[modlen+1] = '\0'; if (!user) user = getenv("USER"); if (!user) user = getenv("LOGNAME"); if (exchange_protocols(f_in, f_out, line, sizeof line, 1) < 0) return -1; if (early_input_file) { STRUCT_STAT st; FILE *f = fopen(early_input_file, "rb"); if (!f || do_fstat(fileno(f), &st) < 0) { rsyserr(FERROR, errno, "failed to open %s", early_input_file); return -1; } early_input_len = st.st_size; if (early_input_len > (int)sizeof line) { rprintf(FERROR, "%s is > %d bytes.\n", early_input_file, (int)sizeof line); return -1; } if (early_input_len > 0) { io_printf(f_out, EARLY_INPUT_CMD "%d\n", early_input_len); while (early_input_len > 0) { int len; if (feof(f)) { rprintf(FERROR, "Early EOF in %s\n", early_input_file); return -1; } len = fread(line, 1, early_input_len, f); if (len > 0) { write_buf(f_out, line, len); early_input_len -= len; } } } fclose(f); } server_options(sargs, &sargc); if (sargc >= MAX_ARGS - 2) goto arg_overflow; sargs[sargc++] = "."; if (!old_style_args) snprintf(line, sizeof line, " %.*s/", modlen, modname); while (argc > 0) { if (sargc >= MAX_ARGS - 1) { arg_overflow: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } if (strncmp(*argv, modname, modlen) == 0 && argv[0][modlen] == '\0') sargs[sargc++] = modname; /* we send "modname/" */ else { char *arg = *argv; int extra_chars = *arg == '-' ? 2 : 0; /* a leading dash needs a "./" prefix. */ /* If --old-args was not specified, make sure that the arg won't split at a mod name! */ if (!old_style_args && (p = strstr(arg, line)) != NULL) { do { extra_chars += 2; } while ((p = strstr(p+1, line)) != NULL); } if (extra_chars) { char *f = arg; char *t = arg = new_array(char, strlen(arg) + extra_chars + 1); if (*f == '-') { *t++ = '.'; *t++ = '/'; } while (*f) { if (*f == ' ' && strncmp(f, line, modlen+2) == 0) { *t++ = '['; *t++ = *f++; *t++ = ']'; } else *t++ = *f++; } *t = '\0'; } sargs[sargc++] = arg; } argv++; argc--; } sargs[sargc] = NULL; if (DEBUG_GTE(CMD, 1)) print_child_argv("sending daemon args:", sargs); io_printf(f_out, "%.*s\n", modlen, modname); /* Old servers may just drop the connection here, rather than sending a proper EXIT command. Yuck. */ kluge_around_eof = list_only && protocol_version < 25 ? 1 : 0; while (1) { if (!read_line_old(f_in, line, sizeof line, 0)) { rprintf(FERROR, "rsync: didn't get server startup line\n"); return -1; } if (strncmp(line,"@RSYNCD: AUTHREQD ",18) == 0) { auth_client(f_out, user, line+18); continue; } if (strcmp(line,"@RSYNCD: OK") == 0) break; if (strcmp(line,"@RSYNCD: EXIT") == 0) { /* This is sent by recent versions of the * server to terminate the listing of modules. * We don't want to go on and transfer * anything; just exit. */ exit(0); } if (strncmp(line, "@ERROR", 6) == 0) { rprintf(FERROR, "%s\n", line); /* This is always fatal; the server will now * close the socket. */ return -1; } /* This might be a MOTD line or a module listing, but there is * no way to differentiate it. The manpage mentions this. */ if (output_motd) rprintf(FINFO, "%s\n", line); } kluge_around_eof = 0; if (rl_nulls) { for (i = 0; i < sargc; i++) { if (!sargs[i]) /* stop at --secluded-args NULL */ break; write_sbuf(f_out, sargs[i]); write_byte(f_out, 0); } write_byte(f_out, 0); } else { for (i = 0; i < sargc; i++) io_printf(f_out, "%s\n", sargs[i]); write_sbuf(f_out, "\n"); } if (protect_args) send_protected_args(f_out, sargs); if (protocol_version < 23) { if (protocol_version == 22 || !am_sender) io_start_multiplex_in(f_in); } free(modname); return 0; } #if defined HAVE_SETENV || defined HAVE_PUTENV static int read_arg_from_pipe(int fd, char *buf, int limit) { char *bp = buf, *eob = buf + limit - 1; while (1) { int got = read(fd, bp, 1); if (got != 1) { if (got < 0 && errno == EINTR) continue; return -1; } if (*bp == '\0') break; if (bp < eob) bp++; } *bp = '\0'; return bp - buf; } #endif void set_env_str(const char *var, const char *str) { #ifdef HAVE_SETENV if (setenv(var, str, 1) < 0) out_of_memory("set_env_str"); #else #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=%s", var, str) < 0) out_of_memory("set_env_str"); putenv(mem); #else (void)var; (void)str; #endif #endif } #if defined HAVE_SETENV || defined HAVE_PUTENV static void set_envN_str(const char *var, int num, const char *str) { #ifdef HAVE_SETENV char buf[128]; (void)snprintf(buf, sizeof buf, "%s%d", var, num); if (setenv(buf, str, 1) < 0) out_of_memory("set_env_str"); #else #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s%d=%s", var, num, str) < 0) out_of_memory("set_envN_str"); putenv(mem); #endif #endif } void set_env_num(const char *var, long num) { #ifdef HAVE_SETENV char val[64]; (void)snprintf(val, sizeof val, "%ld", num); if (setenv(var, val, 1) < 0) out_of_memory("set_env_str"); #else #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=%ld", var, num) < 0) out_of_memory("set_env_num"); putenv(mem); #endif #endif } /* Used for "early exec", "pre-xfer exec", and the "name converter" script. */ static pid_t start_pre_exec(const char *cmd, int *arg_fd_ptr, int *error_fd_ptr) { int arg_fds[2], error_fds[2], arg_fd; pid_t pid; if ((error_fd_ptr && pipe(error_fds) < 0) || pipe(arg_fds) < 0 || (pid = fork()) < 0) return (pid_t)-1; if (pid == 0) { char buf[BIGPATHBUFLEN]; int j, len, status; if (error_fd_ptr) { close(error_fds[0]); set_blocking(error_fds[1]); } close(arg_fds[1]); arg_fd = arg_fds[0]; set_blocking(arg_fd); len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN); if (len <= 0) _exit(1); set_env_str("RSYNC_REQUEST", buf); for (j = 0; ; j++) { len = read_arg_from_pipe(arg_fd, buf, BIGPATHBUFLEN); if (len <= 0) { if (!len) break; _exit(1); } set_envN_str("RSYNC_ARG", j, buf); } dup2(arg_fd, STDIN_FILENO); close(arg_fd); if (error_fd_ptr) { dup2(error_fds[1], STDOUT_FILENO); close(error_fds[1]); } status = shell_exec(cmd); if (!WIFEXITED(status)) _exit(1); _exit(WEXITSTATUS(status)); } if (error_fd_ptr) { close(error_fds[1]); *error_fd_ptr = error_fds[0]; set_blocking(error_fds[0]); } close(arg_fds[0]); arg_fd = *arg_fd_ptr = arg_fds[1]; set_blocking(arg_fd); return pid; } #endif static void write_pre_exec_args(int write_fd, char *request, char **early_argv, char **argv, int exec_type) { int j = 0; if (!request) request = "(NONE)"; write_buf(write_fd, request, strlen(request)+1); if (early_argv) { for ( ; *early_argv; early_argv++) write_buf(write_fd, *early_argv, strlen(*early_argv)+1); j = 1; /* Skip arg0 name in argv. */ } if (argv) { for ( ; argv[j]; j++) write_buf(write_fd, argv[j], strlen(argv[j])+1); } write_byte(write_fd, 0); if (exec_type == 1 && early_input_len) write_buf(write_fd, early_input, early_input_len); if (exec_type != 2) /* the name converter needs this left open */ close(write_fd); } static char *finish_pre_exec(const char *desc, pid_t pid, int read_fd) { char buf[BIGPATHBUFLEN], *bp, *cr; int j, status = -1, msglen = sizeof buf - 1; if (read_fd >= 0) { /* Read the stdout from the program. This it is only displayed * to the user if the script also returns an error status. */ for (bp = buf, cr = buf; msglen > 0; msglen -= j) { if ((j = read(read_fd, bp, msglen)) <= 0) { if (j == 0) break; if (errno == EINTR) continue; break; /* Just ignore the read error for now... */ } bp[j] = '\0'; while (1) { if ((cr = strchr(cr, '\r')) == NULL) { cr = bp + j; break; } if (!cr[1]) break; /* wait for more data before we decide what to do */ if (cr[1] == '\n') { memmove(cr, cr+1, j - (cr - bp)); j--; } else cr++; } bp += j; } *bp = '\0'; close(read_fd); } else *buf = '\0'; if (wait_process(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { char *e; if (asprintf(&e, "%s returned failure (%d)%s%s%s\n%s", desc, status, status < 0 ? ": " : "", status < 0 ? strerror(errno) : "", *buf ? ":" : "", buf) < 0) return "out_of_memory in finish_pre_exec\n"; return e; } return NULL; } static int path_failure(int f_out, const char *dir, BOOL was_chdir) { if (was_chdir) rsyserr(FLOG, errno, "chdir %s failed", dir); else rprintf(FLOG, "normalize_path(%s) failed\n", dir); io_printf(f_out, "@ERROR: chdir failed\n"); return -1; } static int add_a_group(int f_out, const char *gname) { gid_t gid, *gid_p; if (!group_to_gid(gname, &gid, True)) { rprintf(FLOG, "Invalid gid %s\n", gname); io_printf(f_out, "@ERROR: invalid gid %s\n", gname); return -1; } gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32); *gid_p = gid; return 0; } #ifdef HAVE_GETGROUPLIST static int want_all_groups(int f_out, uid_t uid) { const char *err; if ((err = getallgroups(uid, &gid_list)) != NULL) { rsyserr(FLOG, errno, "%s", err); io_printf(f_out, "@ERROR: %s\n", err); return -1; } return 0; } #elif defined HAVE_INITGROUPS static struct passwd *want_all_groups(int f_out, uid_t uid) { struct passwd *pw; gid_t *gid_p; if ((pw = getpwuid(uid)) == NULL) { rsyserr(FLOG, errno, "getpwuid failed"); io_printf(f_out, "@ERROR: getpwuid failed\n"); return NULL; } /* Start with the default group and initgroups() will add the rest. */ gid_p = EXPAND_ITEM_LIST(&gid_list, gid_t, -32); *gid_p = pw->pw_gid; return pw; } #endif static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host) { int argc; char **argv, **orig_argv, **orig_early_argv, *module_chdir; char line[BIGPATHBUFLEN]; #if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST struct passwd *pw = NULL; #endif uid_t uid; int set_uid; char *p, *err_msg = NULL; char *name = lp_name(i); int use_chroot = lp_use_chroot(i); /* might be 1 (yes), 0 (no), or -1 (unset) */ int ret, pre_exec_arg_fd = -1, pre_exec_error_fd = -1; int save_munge_symlinks; pid_t pre_exec_pid = 0; char *request = NULL; set_env_str("RSYNC_MODULE_NAME", name); #ifdef ICONV_OPTION iconv_opt = lp_charset(i); if (*iconv_opt) setup_iconv(); iconv_opt = NULL; #endif /* If reverse lookup is disabled globally but enabled for this module, * we need to do it now before the access check. */ if (host == undetermined_hostname && lp_reverse_lookup(i)) host = client_name(client_addr(f_in)); set_env_str("RSYNC_HOST_NAME", host); set_env_str("RSYNC_HOST_ADDR", addr); if (!allow_access(addr, &host, i)) { rprintf(FLOG, "rsync denied on module %s from %s (%s)\n", name, host, addr); if (!lp_list(i)) io_printf(f_out, "@ERROR: Unknown module '%s'\n", name); else { io_printf(f_out, "@ERROR: access denied to %s from %s (%s)\n", name, host, addr); } return -1; } if (am_daemon > 0) { rprintf(FLOG, "rsync allowed access on module %s from %s (%s)\n", name, host, addr); } if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) { if (errno) { rsyserr(FLOG, errno, "failed to open lock file %s", lp_lock_file(i)); io_printf(f_out, "@ERROR: failed to open lock file\n"); } else { rprintf(FLOG, "max connections (%d) reached\n", lp_max_connections(i)); io_printf(f_out, "@ERROR: max connections (%d) reached -- try again later\n", lp_max_connections(i)); } return -1; } read_only = lp_read_only(i); /* may also be overridden by auth_server() */ auth_user = auth_server(f_in, f_out, i, host, addr, "@RSYNCD: AUTHREQD "); if (!auth_user) { io_printf(f_out, "@ERROR: auth failed on module %s\n", name); return -1; } set_env_str("RSYNC_USER_NAME", auth_user); module_id = i; if (lp_transfer_logging(module_id) && !logfile_format) logfile_format = lp_log_format(module_id); if (log_format_has(logfile_format, 'i')) logfile_format_has_i = 1; if (logfile_format_has_i || log_format_has(logfile_format, 'o')) logfile_format_has_o_or_i = 1; uid = MY_UID(); am_root = (uid == ROOT_UID); p = *lp_uid(module_id) ? lp_uid(module_id) : am_root ? NOBODY_USER : NULL; if (p) { if (!user_to_uid(p, &uid, True)) { rprintf(FLOG, "Invalid uid %s\n", p); io_printf(f_out, "@ERROR: invalid uid %s\n", p); return -1; } set_uid = 1; } else set_uid = 0; p = *lp_gid(module_id) ? conf_strtok(lp_gid(module_id)) : NULL; if (p) { /* The "*" gid must be the first item in the list. */ if (strcmp(p, "*") == 0) { #ifdef HAVE_GETGROUPLIST if (want_all_groups(f_out, uid) < 0) return -1; #elif defined HAVE_INITGROUPS if ((pw = want_all_groups(f_out, uid)) == NULL) return -1; #else rprintf(FLOG, "This rsync does not support a gid of \"*\"\n"); io_printf(f_out, "@ERROR: invalid gid setting.\n"); return -1; #endif } else if (add_a_group(f_out, p) < 0) return -1; while ((p = conf_strtok(NULL)) != NULL) { #if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST if (pw) { rprintf(FLOG, "This rsync cannot add groups after \"*\".\n"); io_printf(f_out, "@ERROR: invalid gid setting.\n"); return -1; } #endif if (add_a_group(f_out, p) < 0) return -1; } } else if (am_root) { if (add_a_group(f_out, NOBODY_GROUP) < 0) return -1; } module_dir = lp_path(module_id); if (*module_dir == '\0') { rprintf(FLOG, "No path specified for module %s\n", name); io_printf(f_out, "@ERROR: no path setting.\n"); return -1; } if (use_chroot < 0) { if (strstr(module_dir, "/./") != NULL) use_chroot = 1; /* The module is expecting a chroot inner & outer path. */ else if (chroot("/") < 0) { rprintf(FLOG, "chroot test failed: %s. " "Switching 'use chroot' from unset to false.\n", strerror(errno)); use_chroot = 0; } else { if (chdir("/") < 0) rsyserr(FLOG, errno, "chdir(\"/\") failed"); use_chroot = 1; } } if (use_chroot) { if ((p = strstr(module_dir, "/./")) != NULL) { *p = '\0'; /* Temporary... */ if (!(module_chdir = normalize_path(module_dir, True, NULL))) return path_failure(f_out, module_dir, False); *p = '/'; if (!(p = normalize_path(p + 2, True, &module_dirlen))) return path_failure(f_out, strstr(module_dir, "/./"), False); if (!(full_module_path = normalize_path(module_dir, False, NULL))) full_module_path = module_dir; module_dir = p; } else { if (!(module_chdir = normalize_path(module_dir, False, NULL))) return path_failure(f_out, module_dir, False); full_module_path = module_chdir; module_dir = "/"; module_dirlen = 1; } } else { if (!(module_chdir = normalize_path(module_dir, False, &module_dirlen))) return path_failure(f_out, module_dir, False); full_module_path = module_dir = module_chdir; } set_env_str("RSYNC_MODULE_PATH", full_module_path); if (module_dirlen == 1) { module_dirlen = 0; set_filter_dir("/", 1); } else set_filter_dir(module_dir, module_dirlen); p = lp_filter(module_id); parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3); p = lp_include_from(module_id); parse_filter_file(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); p = lp_include(module_id); parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_INCLUDE | FILTRULE_WORD_SPLIT), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); p = lp_exclude_from(module_id); parse_filter_file(&daemon_filter_list, p, rule_template(0), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES | XFLG_FATAL_ERRORS); p = lp_exclude(module_id); parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); log_init(1); #if defined HAVE_SETENV || defined HAVE_PUTENV if ((*lp_early_exec(module_id) || *lp_prexfer_exec(module_id) || *lp_postxfer_exec(module_id) || *lp_name_converter(module_id)) && !getenv("RSYNC_NO_XFER_EXEC")) { set_env_num("RSYNC_PID", (long)getpid()); /* For post-xfer exec, fork a new process to run the rsync * daemon while this process waits for the exit status and * runs the indicated command at that point. */ if (*lp_postxfer_exec(module_id)) { pid_t pid = fork(); if (pid < 0) { rsyserr(FLOG, errno, "fork failed"); io_printf(f_out, "@ERROR: fork failed\n"); return -1; } if (pid) { int status; close(f_in); if (f_out != f_in) close(f_out); if (wait_process(pid, &status, 0) < 0) status = -1; set_env_num("RSYNC_RAW_STATUS", status); if (WIFEXITED(status)) status = WEXITSTATUS(status); else status = -1; set_env_num("RSYNC_EXIT_STATUS", status); if (shell_exec(lp_postxfer_exec(module_id)) < 0) status = -1; _exit(status); } } /* For early exec, fork a child process to run the indicated * command and wait for it to exit. */ if (*lp_early_exec(module_id)) { int arg_fd; pid_t pid = start_pre_exec(lp_early_exec(module_id), &arg_fd, NULL); if (pid == (pid_t)-1) { rsyserr(FLOG, errno, "early exec preparation failed"); io_printf(f_out, "@ERROR: early exec preparation failed\n"); return -1; } write_pre_exec_args(arg_fd, NULL, NULL, NULL, 1); if (finish_pre_exec("early exec", pid, -1) != NULL) { rsyserr(FLOG, errno, "early exec failed"); io_printf(f_out, "@ERROR: early exec failed\n"); return -1; } } /* For pre-xfer exec, fork a child process to run the indicated * command, though it first waits for the parent process to * send us the user's request via a pipe. */ if (*lp_prexfer_exec(module_id)) { pre_exec_pid = start_pre_exec(lp_prexfer_exec(module_id), &pre_exec_arg_fd, &pre_exec_error_fd); if (pre_exec_pid == (pid_t)-1) { rsyserr(FLOG, errno, "pre-xfer exec preparation failed"); io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n"); return -1; } } if (*lp_name_converter(module_id)) { namecvt_pid = start_pre_exec(lp_name_converter(module_id), &namecvt_fd_req, &namecvt_fd_ans); if (namecvt_pid == (pid_t)-1) { rsyserr(FLOG, errno, "name-converter exec preparation failed"); io_printf(f_out, "@ERROR: name-converter exec preparation failed\n"); return -1; } } } #endif if (early_input) { free(early_input); early_input = NULL; } if (use_chroot) { if (chroot(module_chdir)) { rsyserr(FLOG, errno, "chroot(\"%s\") failed", module_chdir); io_printf(f_out, "@ERROR: chroot failed\n"); return -1; } module_chdir = module_dir; } if (!change_dir(module_chdir, CD_NORMAL)) return path_failure(f_out, module_chdir, True); if (module_dirlen) sanitize_paths = 1; if ((munge_symlinks = lp_munge_symlinks(module_id)) < 0) munge_symlinks = !use_chroot || module_dirlen; if (munge_symlinks) { STRUCT_STAT st; char prefix[SYMLINK_PREFIX_LEN]; /* NOT +1 ! */ strlcpy(prefix, SYMLINK_PREFIX, sizeof prefix); /* trim the trailing slash */ if (do_stat(prefix, &st) == 0 && S_ISDIR(st.st_mode)) { rprintf(FLOG, "Symlink munging is unsafe when a %s directory exists.\n", prefix); io_printf(f_out, "@ERROR: daemon security issue -- contact admin\n", name); exit_cleanup(RERR_UNSUPPORTED); } } if (gid_list.count) { gid_t *gid_array = gid_list.items; if (setgid(gid_array[0])) { rsyserr(FLOG, errno, "setgid %ld failed", (long)gid_array[0]); io_printf(f_out, "@ERROR: setgid failed\n"); return -1; } #ifdef HAVE_SETGROUPS /* Set the group(s) we want to be active. */ if (setgroups(gid_list.count, gid_array)) { rsyserr(FLOG, errno, "setgroups failed"); io_printf(f_out, "@ERROR: setgroups failed\n"); return -1; } #endif #if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST /* pw is set if the user wants all the user's groups. */ if (pw && initgroups(pw->pw_name, pw->pw_gid) < 0) { rsyserr(FLOG, errno, "initgroups failed"); io_printf(f_out, "@ERROR: initgroups failed\n"); return -1; } #endif our_gid = MY_GID(); } if (set_uid) { if (setuid(uid) < 0 #ifdef HAVE_SETEUID || seteuid(uid) < 0 #endif ) { rsyserr(FLOG, errno, "setuid %ld failed", (long)uid); io_printf(f_out, "@ERROR: setuid failed\n"); return -1; } our_uid = MY_UID(); am_root = (our_uid == ROOT_UID); } if (lp_temp_dir(module_id) && *lp_temp_dir(module_id)) { tmpdir = lp_temp_dir(module_id); if (strlen(tmpdir) >= MAXPATHLEN - 10) { rprintf(FLOG, "the 'temp dir' value for %s is WAY too long -- ignoring.\n", name); tmpdir = NULL; } } io_printf(f_out, "@RSYNCD: OK\n"); read_args(f_in, name, line, sizeof line, rl_nulls, &argv, &argc, &request); orig_argv = argv; save_munge_symlinks = munge_symlinks; reset_output_levels(); /* future verbosity is controlled by client options */ ret = parse_arguments(&argc, (const char ***) &argv); if (protect_args && ret) { orig_early_argv = orig_argv; protect_args = 2; read_args(f_in, name, line, sizeof line, 1, &argv, &argc, &request); orig_argv = argv; ret = parse_arguments(&argc, (const char ***) &argv); } else orig_early_argv = NULL; /* The default is to use the user's setting unless the module sets True or False. */ if (lp_open_noatime(module_id) >= 0) open_noatime = lp_open_noatime(module_id); munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */ if (am_daemon > 0) msgs2stderr = 0; /* A non-rsh-run daemon doesn't have stderr for msgs. */ if (pre_exec_pid) { write_pre_exec_args(pre_exec_arg_fd, request, orig_early_argv, orig_argv, 0); err_msg = finish_pre_exec("pre-xfer exec", pre_exec_pid, pre_exec_error_fd); } if (namecvt_pid) write_pre_exec_args(namecvt_fd_req, request, orig_early_argv, orig_argv, 2); if (orig_early_argv) free(orig_early_argv); am_server = 1; /* Don't let someone try to be tricky. */ quiet = 0; if (lp_ignore_errors(module_id)) ignore_errors = 1; if (write_batch < 0) dry_run = 1; if (lp_fake_super(module_id)) { if (preserve_xattrs > 1) preserve_xattrs = 1; am_root = -1; } else if (am_root < 0) /* Treat --fake-super from client as --super. */ am_root = 2; if (filesfrom_fd == 0) filesfrom_fd = f_in; if (request) { if (*auth_user) { rprintf(FLOG, "rsync %s %s from %s@%s (%s)\n", am_sender ? "on" : "to", request, auth_user, host, addr); } else { rprintf(FLOG, "rsync %s %s from %s (%s)\n", am_sender ? "on" : "to", request, host, addr); } free(request); } #ifndef DEBUG /* don't allow the logs to be flooded too fast */ limit_output_verbosity(lp_max_verbosity(module_id)); #endif if (protocol_version < 23 && (protocol_version == 22 || am_sender)) io_start_multiplex_out(f_out); else if (!ret || err_msg) { /* We have to get I/O multiplexing started so that we can * get the error back to the client. This means getting * the protocol setup finished first in later versions. */ setup_protocol(f_out, f_in); if (!am_sender) { /* Since we failed in our option parsing, we may not * have finished parsing that the client sent us a * --files-from option, so look for it manually. * Without this, the socket would be in the wrong * state for the upcoming error message. */ if (!files_from) { int i; for (i = 0; i < argc; i++) { if (strncmp(argv[i], "--files-from", 12) == 0) { files_from = ""; break; } } } if (files_from) write_byte(f_out, 0); } io_start_multiplex_out(f_out); } if (!ret || err_msg) { if (err_msg) { while ((p = strchr(err_msg, '\n')) != NULL) { int len = p - err_msg + 1; rwrite(FERROR, err_msg, len, 0); err_msg += len; } if (*err_msg) rprintf(FERROR, "%s\n", err_msg); io_flush(MSG_FLUSH); } else option_error(); msleep(400); exit_cleanup(RERR_UNSUPPORTED); } #ifdef ICONV_OPTION if (!iconv_opt) { if (ic_send != (iconv_t)-1) { iconv_close(ic_send); ic_send = (iconv_t)-1; } if (ic_recv != (iconv_t)-1) { iconv_close(ic_recv); ic_recv = (iconv_t)-1; } } #endif if (!numeric_ids && (use_chroot ? lp_numeric_ids(module_id) != False && !*lp_name_converter(module_id) : lp_numeric_ids(module_id) == True)) numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */ if (lp_timeout(module_id) && (!io_timeout || lp_timeout(module_id) < io_timeout)) set_io_timeout(lp_timeout(module_id)); /* If we have some incoming/outgoing chmod changes, append them to * any user-specified changes (making our changes have priority). * We also get a pointer to just our changes so that a receiver * process can use them separately if --perms wasn't specified. */ if (am_sender) p = lp_outgoing_chmod(module_id); else p = lp_incoming_chmod(module_id); if (*p && !(daemon_chmod_modes = parse_chmod(p, &chmod_modes))) { rprintf(FLOG, "Invalid \"%sing chmod\" directive: %s\n", am_sender ? "outgo" : "incom", p); } start_server(f_in, f_out, argc, argv); return 0; } BOOL namecvt_call(const char *cmd, const char **name_p, id_t *id_p) { char buf[1024]; int got, len; if (*name_p) len = snprintf(buf, sizeof buf, "%s %s\n", cmd, *name_p); else len = snprintf(buf, sizeof buf, "%s %ld\n", cmd, (long)*id_p); if (len >= (int)sizeof buf) { rprintf(FERROR, "namecvt_call() request was too large.\n"); exit_cleanup(RERR_UNSUPPORTED); } while ((got = write(namecvt_fd_req, buf, len)) != len) { if (got < 0 && errno == EINTR) continue; rprintf(FERROR, "Connection to name-converter failed.\n"); exit_cleanup(RERR_SOCKETIO); } if (!read_line_old(namecvt_fd_ans, buf, sizeof buf, 0)) return False; if (*name_p) *id_p = (id_t)atol(buf); else *name_p = strdup(buf); return True; } /* send a list of available modules to the client. Don't list those with "list = False". */ static void send_listing(int fd) { int n = lp_num_modules(); int i; for (i = 0; i < n; i++) { if (lp_list(i)) io_printf(fd, "%-15s\t%s\n", lp_name(i), lp_comment(i)); } if (protocol_version >= 25) io_printf(fd,"@RSYNCD: EXIT\n"); } static int load_config(int globals_only) { if (!config_file) { if (am_daemon < 0 && am_root <= 0) config_file = RSYNCD_USERCONF; else config_file = RSYNCD_SYSCONF; } return lp_load(config_file, globals_only); } /* this is called when a connection is established to a client and we want to start talking. The setup of the system is done from here */ int start_daemon(int f_in, int f_out) { char line[1024]; const char *addr, *host; char *p; int i; /* At this point, am_server is only set for a daemon started via rsh. * Because am_server gets forced on soon, we'll set am_daemon to -1 as * a flag that can be checked later on to distinguish a normal daemon * from an rsh-run daemon. */ if (am_server) am_daemon = -1; io_set_sock_fds(f_in, f_out); /* We must load the config file before calling any function that * might cause log-file output to occur. This ensures that the * "log file" param gets honored for the 2 non-forked use-cases * (when rsync is run by init and run by a remote shell). */ if (!load_config(0)) exit_cleanup(RERR_SYNTAX); if (lp_proxy_protocol() && !read_proxy_protocol_header(f_in)) return -1; p = lp_daemon_chroot(); if (*p) { log_init(0); /* Make use we've initialized syslog before chrooting. */ if (chroot(p) < 0) { rsyserr(FLOG, errno, "daemon chroot(\"%s\") failed", p); return -1; } if (chdir("/") < 0) { rsyserr(FLOG, errno, "daemon chdir(\"/\") failed"); return -1; } } p = lp_daemon_gid(); if (*p) { gid_t gid; if (!group_to_gid(p, &gid, True)) { rprintf(FLOG, "Invalid daemon gid: %s\n", p); return -1; } if (setgid(gid) < 0) { rsyserr(FLOG, errno, "Unable to set group to daemon gid %ld", (long)gid); return -1; } our_gid = MY_GID(); } p = lp_daemon_uid(); if (*p) { uid_t uid; if (!user_to_uid(p, &uid, True)) { rprintf(FLOG, "Invalid daemon uid: %s\n", p); return -1; } if (setuid(uid) < 0) { rsyserr(FLOG, errno, "Unable to set user to daemon uid %ld", (long)uid); return -1; } our_uid = MY_UID(); am_root = (our_uid == ROOT_UID); } addr = client_addr(f_in); host = lp_reverse_lookup(-1) ? client_name(addr) : undetermined_hostname; rprintf(FLOG, "connect from %s (%s)\n", host, addr); if (am_daemon > 0) { set_socket_options(f_in, "SO_KEEPALIVE"); set_nonblocking(f_in); } if (exchange_protocols(f_in, f_out, line, sizeof line, 0) < 0) return -1; line[0] = 0; if (!read_line_old(f_in, line, sizeof line, 0)) return -1; if (strncmp(line, EARLY_INPUT_CMD, EARLY_INPUT_CMDLEN) == 0) { early_input_len = strtol(line + EARLY_INPUT_CMDLEN, NULL, 10); if (early_input_len <= 0 || early_input_len > BIGPATHBUFLEN) { io_printf(f_out, "@ERROR: invalid early_input length\n"); return -1; } early_input = new_array(char, early_input_len); read_buf(f_in, early_input, early_input_len); if (!read_line_old(f_in, line, sizeof line, 0)) return -1; } if (!*line || strcmp(line, "#list") == 0) { rprintf(FLOG, "module-list request from %s (%s)\n", host, addr); send_listing(f_out); return -1; } if (*line == '#') { /* it's some sort of command that I don't understand */ io_printf(f_out, "@ERROR: Unknown command '%s'\n", line); return -1; } if ((i = lp_number(line)) < 0) { rprintf(FLOG, "unknown module '%s' tried from %s (%s)\n", line, host, addr); io_printf(f_out, "@ERROR: Unknown module '%s'\n", line); return -1; } #ifdef HAVE_SIGACTION sigact.sa_flags = SA_NOCLDSTOP; #endif SIGACTION(SIGCHLD, remember_children); return rsync_module(f_in, f_out, i, addr, host); } static void create_pid_file(void) { char *pid_file = lp_pid_file(); char pidbuf[32]; STRUCT_STAT st1, st2; char *fail = NULL; if (!pid_file || !*pid_file) return; #ifdef O_NOFOLLOW #define SAFE_OPEN_FLAGS (O_CREAT|O_NOFOLLOW) #else #define SAFE_OPEN_FLAGS (O_CREAT) #endif /* These tests make sure that a temp-style lock dir is handled safely. */ st1.st_mode = 0; if (do_lstat(pid_file, &st1) == 0 && !S_ISREG(st1.st_mode) && unlink(pid_file) < 0) fail = "unlink"; else if ((pid_file_fd = do_open(pid_file, O_RDWR|SAFE_OPEN_FLAGS, 0664)) < 0) fail = S_ISREG(st1.st_mode) ? "open" : "create"; else if (!lock_range(pid_file_fd, 0, 4)) fail = "lock"; else if (do_fstat(pid_file_fd, &st1) < 0) fail = "fstat opened"; else if (st1.st_size > (int)sizeof pidbuf) fail = "find small"; else if (do_lstat(pid_file, &st2) < 0) fail = "lstat"; else if (!S_ISREG(st1.st_mode)) fail = "avoid file overwrite race for"; else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) fail = "verify stat info for"; #ifdef HAVE_FTRUNCATE else if (do_ftruncate(pid_file_fd, 0) < 0) fail = "truncate"; #endif else { pid_t pid = getpid(); int len = snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid); #ifndef HAVE_FTRUNCATE /* What can we do with a too-long file and no truncate? I guess we'll add extra newlines. */ while (len < st1.st_size) /* We already verified that st_size chars fits in the buffer. */ pidbuf[len++] = '\n'; /* We don't need the buffer to end in a '\0' (and we may not have room to add it). */ #endif if (write(pid_file_fd, pidbuf, len) != len) fail = "write"; cleanup_set_pid(pid); /* Mark the file for removal on exit, even if the write failed. */ } if (fail) { char msg[1024]; snprintf(msg, sizeof msg, "failed to %s pid file %s: %s\n", fail, pid_file, strerror(errno)); fputs(msg, stderr); rprintf(FLOG, "%s", msg); exit_cleanup(RERR_FILEIO); } /* The file is left open so that the lock remains valid. It is closed in our forked child procs. */ } /* Become a daemon, discarding the controlling terminal. */ static void become_daemon(void) { int i; pid_t pid = fork(); if (pid) { if (pid < 0) { fprintf(stderr, "failed to fork: %s\n", strerror(errno)); exit_cleanup(RERR_FILEIO); } _exit(0); } create_pid_file(); /* detach from the terminal */ #ifdef HAVE_SETSID setsid(); #elif defined TIOCNOTTY i = open("/dev/tty", O_RDWR); if (i >= 0) { ioctl(i, (int)TIOCNOTTY, (char *)0); close(i); } #endif /* make sure that stdin, stdout an stderr don't stuff things * up (library functions, for example) */ for (i = 0; i < 3; i++) { close(i); open("/dev/null", O_RDWR); } } int daemon_main(void) { if (is_a_socket(STDIN_FILENO)) { int i; /* we are running via inetd - close off stdout and * stderr so that library functions (and getopt) don't * try to use them. Redirect them to /dev/null */ for (i = 1; i < 3; i++) { close(i); open("/dev/null", O_RDWR); } return start_daemon(STDIN_FILENO, STDIN_FILENO); } if (!load_config(1)) { fprintf(stderr, "Failed to parse config file: %s\n", config_file); exit_cleanup(RERR_SYNTAX); } set_dparams(0); if (no_detach) create_pid_file(); else become_daemon(); if (rsync_port == 0 && (rsync_port = lp_rsync_port()) == 0) rsync_port = RSYNC_PORT; if (bind_address == NULL && *lp_bind_address()) bind_address = lp_bind_address(); log_init(0); rprintf(FLOG, "rsyncd version %s starting, listening on port %d\n", rsync_version(), rsync_port); /* TODO: If listening on a particular address, then show that * address too. In fact, why not just do getnameinfo on the * local address??? */ start_accept_loop(rsync_port, start_daemon); return -1; } rsync-3.2.7/packaging/0000775000000000000000000000000014324367162013315 5ustar rootrootrsync-3.2.7/packaging/patch-update0000775000000000000000000002151113747606014015622 0ustar rootroot#!/usr/bin/env -S python3 -B # This script is used to turn one or more of the "patch/BASE/*" branches # into one or more diffs in the "patches" directory. Pass the option # --gen if you want generated files in the diffs. Pass the name of # one or more diffs if you want to just update a subset of all the # diffs. import os, sys, re, argparse, time, shutil sys.path = ['packaging'] + sys.path from pkglib import * MAKE_GEN_CMDS = [ './prepare-source'.split(), 'cd build && if test -f config.status ; then ./config.status ; else ../configure ; fi', 'make -C build gen'.split(), ] TMP_DIR = "patches.gen" os.environ['GIT_MERGE_AUTOEDIT'] = 'no' def main(): global master_commit, parent_patch, description, completed, last_touch if not os.path.isdir(args.patches_dir): die(f'No "{args.patches_dir}" directory was found.') if not os.path.isdir('.git'): die('No ".git" directory present in the current dir.') starting_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir) master_commit = latest_git_hash(args.base_branch) if cmd_txt_chk(['packaging/prep-auto-dir']).out == '': die('You must setup an auto-build-save dir to use this script.') if args.gen: if os.path.lexists(TMP_DIR): die(f'"{TMP_DIR}" must not exist in the current directory.') gen_files = get_gen_files() os.mkdir(TMP_DIR, 0o700) for cmd in MAKE_GEN_CMDS: cmd_chk(cmd) cmd_chk(['rsync', '-a', *gen_files, f'{TMP_DIR}/master/']) last_touch = int(time.time()) # Start by finding all patches so that we can load all possible parents. patches = sorted(list(get_patch_branches(args.base_branch))) parent_patch = { } description = { } for patch in patches: branch = f"patch/{args.base_branch}/{patch}" desc = '' proc = cmd_pipe(['git', 'diff', '-U1000', f"{args.base_branch}...{branch}", '--', f"PATCH.{patch}"]) in_diff = False for line in proc.stdout: if in_diff: if not re.match(r'^[ +]', line): continue line = line[1:] m = re.search(r'patch -p1 = int(time.time()): time.sleep(1) cmd_chk(['git', 'checkout', starting_branch]) cmd_chk(['packaging/prep-auto-dir'], discard='output') def update_patch(patch): global last_touch completed.add(patch) # Mark it as completed early to short-circuit any (bogus) dependency loops. parent = parent_patch.get(patch, None) if parent: if parent not in completed: if not update_patch(parent): return 0 based_on = parent = f"patch/{args.base_branch}/{parent}" else: parent = args.base_branch based_on = master_commit print(f"======== {patch} ========") while args.gen and last_touch >= int(time.time()): time.sleep(1) branch = f"patch/{args.base_branch}/{patch}" s = cmd_run(['git', 'checkout', branch]) if s.returncode != 0: return 0 s = cmd_run(['git', 'merge', based_on]) ok = s.returncode == 0 skip_shell = False if not ok or args.cmd or args.make or args.shell: cmd_chk(['packaging/prep-auto-dir'], discard='output') if not ok: print(f'"git merge {based_on}" incomplete -- please fix.') if not run_a_shell(parent, patch): return 0 if not args.make and not args.cmd: skip_shell = True if args.make: if cmd_run(['packaging/smart-make']).returncode != 0: if not run_a_shell(parent, patch): return 0 if not args.cmd: skip_shell = True if args.cmd: if cmd_run(args.cmd).returncode != 0: if not run_a_shell(parent, patch): return 0 skip_shell = True if args.shell and not skip_shell: if not run_a_shell(parent, patch): return 0 with open(f"{args.patches_dir}/{patch}.diff", 'w', encoding='utf-8') as fh: fh.write(description[patch]) fh.write(f"\nbased-on: {based_on}\n") if args.gen: gen_files = get_gen_files() for cmd in MAKE_GEN_CMDS: cmd_chk(cmd) cmd_chk(['rsync', '-a', *gen_files, f"{TMP_DIR}/{patch}/"]) else: gen_files = [ ] last_touch = int(time.time()) proc = cmd_pipe(['git', 'diff', based_on]) skipping = False for line in proc.stdout: if skipping: if not re.match(r'^diff --git a/', line): continue skipping = False elif re.match(r'^diff --git a/PATCH', line): skipping = True continue if not re.match(r'^index ', line): fh.write(line) proc.communicate() if args.gen: e_tmp_dir = re.escape(TMP_DIR) diff_re = re.compile(r'^(diff -Nurp) %s/[^/]+/(.*?) %s/[^/]+/(.*)' % (e_tmp_dir, e_tmp_dir)) minus_re = re.compile(r'^\-\-\- %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir) plus_re = re.compile(r'^\+\+\+ %s/[^/]+/([^\t]+)\t.*' % e_tmp_dir) if parent == args.base_branch: parent_dir = 'master' else: m = re.search(r'([^/]+)$', parent) parent_dir = m[1] proc = cmd_pipe(['diff', '-Nurp', f"{TMP_DIR}/{parent_dir}", f"{TMP_DIR}/{patch}"]) for line in proc.stdout: line = diff_re.sub(r'\1 a/\2 b/\3', line) line = minus_re.sub(r'--- a/\1', line) line = plus_re.sub(r'+++ b/\1', line) fh.write(line) proc.communicate() return 1 def run_a_shell(parent, patch): m = re.search(r'([^/]+)$', parent) parent_dir = m[1] os.environ['PS1'] = f"[{parent_dir}] {patch}: " while True: s = cmd_run([os.environ.get('SHELL', '/bin/sh')]) if s.returncode != 0: ans = input("Abort? [n/y] ") if re.match(r'^y', ans, flags=re.I): return False continue cur_branch, is_clean, status_txt = check_git_status(0) if is_clean: break print(status_txt, end='') cmd_run('rm -f build/*.o build/*/*.o') return True if __name__ == '__main__': parser = argparse.ArgumentParser(description="Turn a git branch back into a diff files in the patches dir.", add_help=False) parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.") parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.") parser.add_argument('--make', '-m', action='store_true', help="Run the smart-make script in every patch branch.") parser.add_argument('--cmd', '-c', help="Run a command in every patch branch.") parser.add_argument('--shell', '-s', action='store_true', help="Launch a shell for every patch/BASE/* branch updated, not just when a conflict occurs.") parser.add_argument('--gen', metavar='DIR', nargs='?', const='', help='Include generated files. Optional DIR value overrides the default of using the "patches" dir.') parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.") parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() if args.gen == '': args.gen = args.patches_dir elif args.gen is not None: args.patches_dir = args.gen main() # vim: sw=4 et ft=python rsync-3.2.7/packaging/systemd/0000775000000000000000000000000014324367162015005 5ustar rootrootrsync-3.2.7/packaging/systemd/rsync.socket0000664000000000000000000000024513672441200017345 0ustar rootroot[Unit] Description=socket for fast remote file copy program daemon Conflicts=rsync.service [Socket] ListenStream=873 Accept=true [Install] WantedBy=sockets.target rsync-3.2.7/packaging/systemd/rsync@.service0000664000000000000000000000164513677157626017647 0ustar rootroot[Unit] Description=fast remote file copy program daemon After=network.target [Service] ExecStart=-/usr/bin/rsync --daemon StandardInput=socket StandardOutput=inherit StandardError=journal # Citing README.md: # # [...] Using ssh is recommended for its security features. # # Alternatively, rsync can run in `daemon' mode, listening on a socket. # This is generally used for public file distribution, [...] # # So let's assume some extra security is more than welcome here. We do full # system protection (which makes /usr, /boot, & /etc read-only) and hide # devices. To override these defaults, it's best to do so in the drop-in # directory, often done via `systemctl edit rsync@.service`. The file needs # just the bare minimum of the right [heading] and override values. # See systemd.unit(5) and search for "drop-in" for full details. ProtectSystem=full #ProtectHome=on|off|read-only PrivateDevices=on NoNewPrivileges=on rsync-3.2.7/packaging/systemd/rsync.service0000664000000000000000000000200614225051153017511 0ustar rootroot[Unit] Description=fast remote file copy program daemon ConditionPathExists=/etc/rsyncd.conf After=network.target Documentation=man:rsync(1) man:rsyncd.conf(5) [Service] ExecStart=/usr/bin/rsync --daemon --no-detach RestartSec=1 Restart=on-failure # Citing README.md: # # [...] Using ssh is recommended for its security features. # # Alternatively, rsync can run in `daemon' mode, listening on a socket. # This is generally used for public file distribution, [...] # # So let's assume some extra security is more than welcome here. We do full # system protection (which makes /usr, /boot, & /etc read-only) and hide # devices. To override these defaults, it's best to do so in the drop-in # directory, often done via `systemctl edit rsync.service`. The file needs # just the bare minimum of the right [heading] and override values. # See systemd.unit(5) and search for "drop-in" for full details. ProtectSystem=full #ProtectHome=on|off|read-only PrivateDevices=on NoNewPrivileges=on [Install] WantedBy=multi-user.target rsync-3.2.7/packaging/branch-from-patch0000775000000000000000000001474313675765530016560 0ustar rootroot#!/usr/bin/env -S python3 -B # This script turns one or more diff files in the patches dir (which is # expected to be a checkout of the rsync-patches git repo) into a branch # in the main rsync git checkout. This allows the applied patch to be # merged with the latest rsync changes and tested. To update the diff # with the resulting changes, see the patch-update script. import os, sys, re, argparse, glob sys.path = ['packaging'] + sys.path from pkglib import * def main(): global created, info, local_branch cur_branch, args.base_branch = check_git_state(args.base_branch, not args.skip_check, args.patches_dir) local_branch = get_patch_branches(args.base_branch) if args.delete_local_branches: for name in sorted(local_branch): branch = f"patch/{args.base_branch}/{name}" cmd_chk(['git', 'branch', '-D', branch]) local_branch = set() if args.add_missing: for fn in sorted(glob.glob(f"{args.patches_dir}/*.diff")): name = re.sub(r'\.diff$', '', re.sub(r'.+/', '', fn)) if name not in local_branch and fn not in args.patch_files: args.patch_files.append(fn) if not args.patch_files: return for fn in args.patch_files: if not fn.endswith('.diff'): die(f"Filename is not a .diff file: {fn}") if not os.path.isfile(fn): die(f"File not found: {fn}") scanned = set() info = { } patch_list = [ ] for fn in args.patch_files: m = re.match(r'^(?P.*?)(?P[^/]+)\.diff$', fn) patch = argparse.Namespace(**m.groupdict()) if patch.name in scanned: continue patch.fn = fn lines = [ ] commit_hash = None with open(patch.fn, 'r', encoding='utf-8') as fh: for line in fh: m = re.match(r'^based-on: (\S+)', line) if m: commit_hash = m[1] break if (re.match(r'^index .*\.\..* \d', line) or re.match(r'^diff --git ', line) or re.match(r'^--- (old|a)/', line)): break lines.append(re.sub(r'\s*\Z', "\n", line, 1)) info_txt = ''.join(lines).strip() + "\n" lines = None parent = args.base_branch patches = re.findall(r'patch -p1 <%s/(\S+)\.diff' % args.patches_dir, info_txt) if patches: last = patches.pop() if last != patch.name: warn(f"No identity patch line in {patch.fn}") patches.append(last) if patches: parent = patches.pop() if parent not in scanned: diff_fn = patch.dir + parent + '.diff' if not os.path.isfile(diff_fn): die(f"Failed to find parent of {patch.fn}: {parent}") # Add parent to args.patch_files so that we will look for the # parent's parent. Any duplicates will be ignored. args.patch_files.append(diff_fn) else: warn(f"No patch lines found in {patch.fn}") info[patch.name] = [ parent, info_txt, commit_hash ] patch_list.append(patch) created = set() for patch in patch_list: create_branch(patch) cmd_chk(['git', 'checkout', args.base_branch]) def create_branch(patch): if patch.name in created: return created.add(patch.name) parent, info_txt, commit_hash = info[patch.name] parent = argparse.Namespace(dir=patch.dir, name=parent, fn=patch.dir + parent + '.diff') if parent.name == args.base_branch: parent_branch = commit_hash if commit_hash else args.base_branch else: create_branch(parent) parent_branch = '/'.join(['patch', args.base_branch, parent.name]) branch = '/'.join(['patch', args.base_branch, patch.name]) print("\n" + '=' * 64) print(f"Processing {branch} ({parent_branch})") if patch.name in local_branch: cmd_chk(['git', 'branch', '-D', branch]) cmd_chk(['git', 'checkout', '-b', branch, parent_branch]) info_fn = 'PATCH.' + patch.name with open(info_fn, 'w', encoding='utf-8') as fh: fh.write(info_txt) cmd_chk(['git', 'add', info_fn]) with open(patch.fn, 'r', encoding='utf-8') as fh: patch_txt = fh.read() cmd_run('patch -p1'.split(), input=patch_txt) for fn in glob.glob('*.orig') + glob.glob('*/*.orig'): os.unlink(fn) pos = 0 new_file_re = re.compile(r'\nnew file mode (?P\d+)\s+--- /dev/null\s+\+\+\+ b/(?P.+)') while True: m = new_file_re.search(patch_txt, pos) if not m: break os.chmod(m['fn'], int(m['mode'], 8)) cmd_chk(['git', 'add', m['fn']]) pos = m.end() while True: cmd_chk('git status'.split()) ans = input('Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ') if ans == '': break cmd_chk("git add " + ans, shell=True) while True: s = cmd_run(['git', 'commit', '-a', '-m', f"Creating branch from {patch.name}.diff."]) if not s.returncode: break s = cmd_run(['/bin/zsh']) if s.returncode: die('Aborting due to shell error code') if __name__ == '__main__': parser = argparse.ArgumentParser(description="Create a git patch branch from an rsync patch file.", add_help=False) parser.add_argument('--branch', '-b', dest='base_branch', metavar='BASE_BRANCH', default='master', help="The branch the patch is based on. Default: master.") parser.add_argument('--add-missing', '-a', action='store_true', help="Add a branch for every patches/*.diff that doesn't have a branch.") parser.add_argument('--skip-check', action='store_true', help="Skip the check that ensures starting with a clean branch.") parser.add_argument('--delete', dest='delete_local_branches', action='store_true', help="Delete all the local patch/BASE/* branches, not just the ones that are being recreated.") parser.add_argument('--patches-dir', '-p', metavar='DIR', default='patches', help="Override the location of the rsync-patches dir. Default: patches.") parser.add_argument('patch_files', metavar='patches/DIFF_FILE', nargs='*', help="Specify what patch diff files to process. Default: all of them.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et ft=python rsync-3.2.7/packaging/cull-options0000775000000000000000000001144614300177016015670 0ustar rootroot#!/usr/bin/env python3 # This script outputs either perl or python code that parses all possible options # that the code in options.c might send to the server. The resulting code is then # included in the rrsync script. import re, argparse short_no_arg = { } short_with_num = { '@': 1 } long_opts = { # These include some extra long-args that BackupPC uses: 'block-size': 1, 'daemon': -1, 'debug': 1, 'fake-super': 0, 'fuzzy': 0, 'group': 0, 'hard-links': 0, 'ignore-times': 0, 'info': 1, 'links': 0, 'log-file': 3, 'munge-links': 0, 'no-munge-links': -1, 'one-file-system': 0, 'owner': 0, 'perms': 0, 'recursive': 0, 'stderr': 1, 'times': 0, 'copy-devices': -1, 'write-devices': -1, } def main(): last_long_opt = None with open('../options.c') as fh: for line in fh: m = re.search(r"argstr\[x\+\+\] = '([^.ie])'", line) if m: short_no_arg[m.group(1)] = 1 last_long_opt = None continue m = re.search(r'asprintf\([^,]+, "-([a-zA-Z0-9])\%l?[ud]"', line) if m: short_with_num[m.group(1)] = 1 last_long_opt = None continue m = re.search(r'args\[ac\+\+\] = "--([^"=]+)"', line) if m: last_long_opt = m.group(1) if last_long_opt not in long_opts: long_opts[last_long_opt] = 0 else: last_long_opt = None continue if last_long_opt: m = re.search(r'args\[ac\+\+\] = safe_arg\("", ([^[("\s]+)\);', line) if m: long_opts[last_long_opt] = 2 last_long_opt = None continue if 'args[ac++] = ' in line: last_long_opt = None m = re.search(r'return "--([^"]+-dest)";', line) if m: long_opts[m.group(1)] = 2 last_long_opt = None continue m = re.search(r'asprintf\([^,]+, "--([^"=]+)=', line) if not m: m = re.search(r'args\[ac\+\+\] = "--([^"=]+)=', line) if not m: m = re.search(r'args\[ac\+\+\] = safe_arg\("--([^"=]+)"', line) if not m: m = re.search(r'fmt = .*: "--([^"=]+)=', line) if m: long_opts[m.group(1)] = 1 last_long_opt = None long_opts['files-from'] = 3 txt = """\ ### START of options data produced by the cull-options script. ### # To disable a short-named option, add its letter to this string: """ txt += str_assign('short_disabled', 's') + "\n" txt += '# These are also disabled when the restricted dir is not "/":\n' txt += str_assign('short_disabled_subdir', 'KLk') + "\n" txt += '# These are all possible short options that we will accept (when not disabled above):\n' txt += str_assign('short_no_arg', ''.join(sorted(short_no_arg)), 'DO NOT REMOVE ANY') txt += str_assign('short_with_num', ''.join(sorted(short_with_num)), 'DO NOT REMOVE ANY') txt += """ # To disable a long-named option, change its value to a -1. The values mean: # 0 = the option has no arg; 1 = the arg doesn't need any checking; 2 = only # check the arg when receiving; and 3 = always check the arg. """ print(txt, end='') if args.python: print("long_opts = {") sep = ':' else: print("our %long_opt = (") sep = ' =>' for opt in sorted(long_opts): if opt.startswith(('min-', 'max-')): val = 1 else: val = long_opts[opt] print(' ', repr(opt) + sep, str(val) + ',') if args.python: print("}") else: print(");") print("\n### END of options data produced by the cull-options script. ###") def str_assign(name, val, comment=None): comment = ' # ' + comment if comment else '' if args.python: return name + ' = ' + repr(val) + comment + "\n" return 'our $' + name + ' = ' + repr(val) + ';' + comment + "\n" if __name__ == '__main__': parser = argparse.ArgumentParser(description="Output culled rsync options for rrsync.", add_help=False) out_group = parser.add_mutually_exclusive_group() out_group.add_argument('--perl', action='store_true', help="Output perl code.") out_group.add_argument('--python', action='store_true', help="Output python code (the default).") parser.add_argument('--help', '-h', action='help', help="Output this help message and exit.") args = parser.parse_args() if not args.perl: args.python = True main() # vim: sw=4 et rsync-3.2.7/packaging/var-checker0000775000000000000000000000605614125667102015440 0ustar rootroot#!/usr/bin/env -S python3 -B # This script checks the *.c files for extraneous "extern" variables, # for vars that are defined but not used, and for inconsistent array # sizes. Run it from inside the main rsync directory. import os, sys, re, argparse, glob VARS_RE = re.compile(r'^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);', re.M) EXTERNS_RE = re.compile(r'^extern\s+(.*);', re.M) sizes = { } def main(): add_syscall_c = set('t_stub.c t_unsafe.c tls.c trimslash.c'.split()) add_util_c = set('t_stub.c t_unsafe.c'.split()) if not os.path.exists('syscall.c'): if os.path.exists('var-checker'): os.chdir('..') else: print("Couldn't find the source dir.") sys.exit(1) syscall_c = slurp_file('syscall.c', True) util_c = slurp_file('util1.c', True) for fn in sorted(glob.glob('*.c')): txt = slurp_file(fn) var_list = parse_vars(fn, VARS_RE.findall(txt)) extern_list = parse_vars(fn, EXTERNS_RE.findall(txt)) if not var_list and not extern_list: continue if fn in add_syscall_c: txt += syscall_c if fn in add_util_c: txt += util_c txt = re.sub(r'INFO_GTE', 'info_levels ', txt) txt = re.sub(r'DEBUG_GTE', 'debug_levels ', txt) txt = re.sub(r'SIGACTION\(', 'sigact (', txt) find = '|'.join([ re.escape(x) for x in var_list + extern_list ]) var_re = re.compile(r'(?\w+)(?P\[.*?\])?$', item) if not m: print(f"Bogus match? ({item})") continue if m['sz']: if m['var'] in sizes: if sizes[m['var']] != m['sz']: var = m['var'] print(fn, f'has inconsistent size for "{var}":', m['sz'], 'vs', sizes[var]) else: sizes[m['var']] = m['sz'] ret.append(m['var']) return ret if __name__ == '__main__': parser = argparse.ArgumentParser(description='Check the *.c files for extraneous extern vars.', add_help=False) parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et ft=python rsync-3.2.7/packaging/lsb/0000775000000000000000000000000014324367162014075 5ustar rootrootrsync-3.2.7/packaging/lsb/rsync.xinetd0000664000000000000000000000047310771047250016447 0ustar rootroot# default: off # description: The rsync server is a good addition to an ftp server, as it # allows crc checksumming etc. service rsync { disable = yes socket_type = stream wait = no user = root server = /usr/bin/rsync server_args = --daemon log_on_failure += USERID } rsync-3.2.7/packaging/lsb/rsync.spec0000664000000000000000000000536614324367162016121 0ustar rootrootSummary: A fast, versatile, remote (and local) file-copying tool Name: rsync Version: 3.2.7 %define fullversion %{version} Release: 1 %define srcdir src Group: Applications/Internet License: GPL Source0: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-%{fullversion}.tar.gz #Source1: https://rsync.samba.org/ftp/rsync/%{srcdir}/rsync-patches-%{fullversion}.tar.gz URL: https://rsync.samba.org/ Prefix: %{_prefix} BuildRoot: /var/tmp/%{name}-root %package ssl-daemon Summary: An stunnel config file to support ssl rsync daemon connections. Group: Applications/Internet Requires: rsync, stunnel >= 4 %description Rsync is a fast and extraordinarily versatile file copying tool. It can copy locally, to/from another host over any remote shell, or to/from a remote rsync daemon. It offers a large number of options that control every aspect of its behavior and permit very flexible specification of the set of files to be copied. It is famous for its delta-transfer algorithm, which reduces the amount of data sent over the network by sending only the differences between the source files and the existing files in the destination. Rsync is widely used for backups and mirroring and as an improved copy command for everyday use. %description ssl-daemon Provides a config file for stunnel that will (if you start your stunnel service) cause stunnel to listen for ssl rsync-daemon connections and run "rsync --daemon" to handle them. %prep # Choose one -- setup source only, or setup source + rsync-patches: %setup -q -n rsync-%{fullversion} #%setup -q -b1 -n rsync-%{fullversion} # If you you used "%setup -q -b1 ...", choose the patches you wish to apply: #patch -p1 Released 3.2.7. * Fri Mar 21 2008 Wayne Davison Added installation of /etc/xinetd.d/rsync file and some commented-out lines that demonstrate how to use the rsync-patches tar file. rsync-3.2.7/packaging/smart-make0000775000000000000000000000125614007147270015302 0ustar rootroot#!/bin/sh set -e export LANG=C branch=`packaging/prep-auto-dir` if test x"$branch" = x; then srcdir=. else cd build srcdir=.. fi if test -f configure.sh; then cp -p configure.sh configure.sh.old else touch configure.sh.old fi if test -f .fetch; then $srcdir/prepare-source fetch else $srcdir/prepare-source fi if diff configure.sh configure.sh.old >/dev/null 2>&1; then echo "configure.sh is unchanged." rm configure.sh.old else echo "configure.sh has CHANGED." if test -f config.status; then ./config.status --recheck else $srcdir/configure fi fi ./config.status make all if test x"$1" = x"check"; then make check fi rsync-3.2.7/packaging/release-rsync0000775000000000000000000003611314323054046016014 0ustar rootroot#!/usr/bin/env -S python3 -B # This script expects the directory ~/samba-rsync-ftp to exist and to be a # copy of the /home/ftp/pub/rsync dir on samba.org. When the script is done, # the git repository in the current directory will be updated, and the local # ~/samba-rsync-ftp dir will be ready to be rsynced to samba.org. import os, sys, re, argparse, glob, shutil, signal from datetime import datetime from getpass import getpass sys.path = ['packaging'] + sys.path from pkglib import * os.environ['LESS'] = 'mqeiXR'; # Make sure that -F is turned off and -R is turned on. dest = os.environ['HOME'] + '/samba-rsync-ftp' ORIGINAL_PATH = os.environ['PATH'] def main(): if not os.path.isfile('packaging/release-rsync'): die('You must run this script from the top of your rsync checkout.') now = datetime.now() cl_today = now.strftime('* %a %b %d %Y') year = now.strftime('%Y') ztoday = now.strftime('%d %b %Y') today = ztoday.lstrip('0') mandate_gensend_hook() curdir = os.getcwd() signal.signal(signal.SIGINT, signal_handler) if cmd_txt_chk(['packaging/prep-auto-dir']).out == '': die('You must setup an auto-build-save dir to use this script.'); auto_dir, gen_files = get_gen_files(True) gen_pathnames = [ os.path.join(auto_dir, fn) for fn in gen_files ] dash_line = '=' * 74 print(f"""\ {dash_line} == This will release a new version of rsync onto an unsuspecting world. == {dash_line} """) with open('build/rsync.1') as fh: for line in fh: if line.startswith(r'.\" prefix='): doc_prefix = line.split('=')[1].strip() if doc_prefix != '/usr': warn(f"*** The documentation was built with prefix {doc_prefix} instead of /usr ***") die("*** Read the md2man script for a way to override this. ***") break if line.startswith('.P'): die("Failed to find the prefix comment at the start of the rsync.1 manpage.") if not os.path.isdir(dest): die(dest, "dest does not exist") if not os.path.isdir('.git'): die("There is no .git dir in the current directory.") if os.path.lexists('a'): die('"a" must not exist in the current directory.') if os.path.lexists('b'): die('"b" must not exist in the current directory.') if os.path.lexists('patches.gen'): die('"patches.gen" must not exist in the current directory.') check_git_state(args.master_branch, True, 'patches') curversion = get_rsync_version() # All version values are strings! lastversion, last_protocol_version, pdate = get_NEWS_version_info() protocol_version, subprotocol_version = get_protocol_versions() version = curversion m = re.search(r'pre(\d+)', version) if m: version = re.sub(r'pre\d+', 'pre' + str(int(m[1]) + 1), version) else: version = version.replace('dev', 'pre1') ans = input(f"Please enter the version number of this release: [{version}] ") if ans == '.': version = re.sub(r'pre\d+', '', version) elif ans != '': version = ans if not re.match(r'^[\d.]+(pre\d+)?$', version): die(f'Invalid version: "{version}"') v_ver = 'v' + version rsync_ver = 'rsync-' + version if os.path.lexists(rsync_ver): die(f'"{rsync_ver}" must not exist in the current directory.') out = cmd_txt_chk(['git', 'tag', '-l', v_ver]).out if out != '': print(f"Tag {v_ver} already exists.") ans = input("\nDelete tag or quit? [Q/del] ") if not re.match(r'^del', ans, flags=re.I): die("Aborted") cmd_chk(['git', 'tag', '-d', v_ver]) if os.path.isdir('patches/.git'): cmd_chk(f"cd patches && git tag -d '{v_ver}'") version = re.sub(r'[-.]*pre[-.]*', 'pre', version) if 'pre' in version and not curversion.endswith('dev'): lastversion = curversion ans = input(f"Enter the previous version to produce a patch against: [{lastversion}] ") if ans != '': lastversion = ans lastversion = re.sub(r'[-.]*pre[-.]*', 'pre', lastversion) rsync_lastver = 'rsync-' + lastversion if os.path.lexists(rsync_lastver): die(f'"{rsync_lastver}" must not exist in the current directory.') m = re.search(r'(pre\d+)', version) pre = m[1] if m else '' release = '0.1' if pre else '1' ans = input(f"Please enter the RPM release number of this release: [{release}] ") if ans != '': release = ans if pre: release += '.' + pre finalversion = re.sub(r'pre\d+', '', version) proto_changed = protocol_version != last_protocol_version if proto_changed: if finalversion in pdate: proto_change_date = pdate[finalversion] else: while True: ans = input("On what date did the protocol change to {protocol_version} get checked in? (dd Mmm yyyy) ") if re.match(r'^\d\d \w\w\w \d\d\d\d$', ans): break proto_change_date = ans else: proto_change_date = ' ' * 11 if 'pre' in lastversion: if not pre: die("You should not diff a release version against a pre-release version.") srcdir = srcdiffdir = lastsrcdir = 'src-previews' skipping = ' ** SKIPPING **' elif pre: srcdir = srcdiffdir = 'src-previews' lastsrcdir = 'src' skipping = ' ** SKIPPING **' else: srcdir = lastsrcdir = 'src' srcdiffdir = 'src-diffs' skipping = '' print(f""" {dash_line} version is "{version}" lastversion is "{lastversion}" dest is "{dest}" curdir is "{curdir}" srcdir is "{srcdir}" srcdiffdir is "{srcdiffdir}" lastsrcdir is "{lastsrcdir}" release is "{release}" About to: - tweak SUBPROTOCOL_VERSION in rsync.h, if needed - tweak the version in version.h and the spec files - tweak NEWS.md to ensure header values are correct - generate configure.sh, config.h.in, and proto.h - page through the differences """) ans = input(" ") specvars = { 'Version:': finalversion, 'Release:': release, '%define fullversion': f'%{{version}}{pre}', 'Released': version + '.', '%define srcdir': srcdir, } tweak_files = 'version.h rsync.h NEWS.md'.split() tweak_files += glob.glob('packaging/*.spec') tweak_files += glob.glob('packaging/*/*.spec') for fn in tweak_files: with open(fn, 'r', encoding='utf-8') as fh: old_txt = txt = fh.read() if fn == 'version.h': x_re = re.compile(r'^(#define RSYNC_VERSION).*', re.M) msg = f"Unable to update RSYNC_VERSION in {fn}" txt = replace_or_die(x_re, r'\1 "%s"' % version, txt, msg) elif '.spec' in fn: for var, val in specvars.items(): x_re = re.compile(r'^%s .*' % re.escape(var), re.M) txt = replace_or_die(x_re, var + ' ' + val, txt, f"Unable to update {var} in {fn}") x_re = re.compile(r'^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)', re.M) txt = replace_or_die(x_re, r'%s \1' % cl_today, txt, f"Unable to update ChangeLog header in {fn}") elif fn == 'rsync.h': x_re = re.compile('(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)') repl = lambda m: m[1] + ' ' + ('0' if not pre or not proto_changed else '1' if m[2] == '0' else m[2]) txt = replace_or_die(x_re, repl, txt, f"Unable to find SUBPROTOCOL_VERSION define in {fn}") elif fn == 'NEWS.md': efv = re.escape(finalversion) x_re = re.compile(r'^# NEWS for rsync %s \(UNRELEASED\)\s+## Changes in this version:\n' % efv + r'(\n### PROTOCOL NUMBER:\s+- The protocol number was changed to \d+\.\n)?') rel_day = 'UNRELEASED' if pre else today repl = (f'# NEWS for rsync {finalversion} ({rel_day})\n\n' + '## Changes in this version:\n') if proto_changed: repl += f'\n### PROTOCOL NUMBER:\n\n - The protocol number was changed to {protocol_version}.\n' good_top = re.sub(r'\(.*?\)', '(UNRELEASED)', repl, 1) msg = f"The top lines of {fn} are not in the right format. It should be:\n" + good_top txt = replace_or_die(x_re, repl, txt, msg) x_re = re.compile(r'^(\| )(\S{2} \S{3} \d{4})(\s+\|\s+%s\s+\| ).{11}(\s+\| )\S{2}(\s+\|+)$' % efv, re.M) repl = lambda m: m[1] + (m[2] if pre else ztoday) + m[3] + proto_change_date + m[4] + protocol_version + m[5] txt = replace_or_die(x_re, repl, txt, f'Unable to find "| ?? ??? {year} | {finalversion} | ... |" line in {fn}') else: die(f"Unrecognized file in tweak_files: {fn}") if txt != old_txt: print(f"Updating {fn}") with open(fn, 'w', encoding='utf-8') as fh: fh.write(txt) cmd_chk(['packaging/year-tweak']) print(dash_line) cmd_run("git diff".split()) srctar_name = f"{rsync_ver}.tar.gz" pattar_name = f"rsync-patches-{version}.tar.gz" diff_name = f"{rsync_lastver}-{version}.diffs.gz" srctar_file = os.path.join(dest, srcdir, srctar_name) pattar_file = os.path.join(dest, srcdir, pattar_name) diff_file = os.path.join(dest, srcdiffdir, diff_name) lasttar_file = os.path.join(dest, lastsrcdir, rsync_lastver + '.tar.gz') print(f"""\ {dash_line} About to: - git commit all changes - run a full build, ensuring that the manpages & configure.sh are up-to-date - merge the {args.master_branch} branch into the patch/{args.master_branch}/* branches - update the files in the "patches" dir and OPTIONALLY (if you type 'y') to run patch-update with the --make option (which opens a shell on error) """) ans = input(" ") s = cmd_run(['git', 'commit', '-a', '-m', f'Preparing for release of {version} [buildall]']) if s.returncode: die('Aborting') cmd_chk('touch configure.ac && packaging/smart-make && make gen') print('Creating any missing patch branches.') s = cmd_run(f'packaging/branch-from-patch --branch={args.master_branch} --add-missing') if s.returncode: die('Aborting') print('Updating files in "patches" dir ...') s = cmd_run(f'packaging/patch-update --branch={args.master_branch}') if s.returncode: die('Aborting') if re.match(r'^y', ans, re.I): print(f'\nRunning smart-make on all "patch/{args.master_branch}/*" branches ...') cmd_run(f"packaging/patch-update --branch={args.master_branch} --skip-check --make") if os.path.isdir('patches/.git'): s = cmd_run(f"cd patches && git commit -a -m 'The patches for {version}.'") if s.returncode: die('Aborting') print(f"""\ {dash_line} About to: - create signed tag for this release: {v_ver} - create release diffs, "{diff_name}" - create release tar, "{srctar_name}" - generate {rsync_ver}/patches/* files - create patches tar, "{pattar_name}" - update top-level README.md, NEWS.md, TODO, and ChangeLog - update top-level rsync*.html manpages - gpg-sign the release files - update hard-linked top-level release files{skipping} """) ans = input(" ") # TODO: is there a better way to ensure that our passphrase is in the agent? cmd_run("touch TeMp; gpg --sign TeMp; rm TeMp*") out = cmd_txt(f"git tag -s -m 'Version {version}.' {v_ver}", capture='combined').out print(out, end='') if 'bad passphrase' in out or 'failed' in out: die('Aborting') if os.path.isdir('patches/.git'): out = cmd_txt(f"cd patches && git tag -s -m 'Version {version}.' {v_ver}", capture='combined').out print(out, end='') if 'bad passphrase' in out or 'failed' in out: die('Aborting') os.environ['PATH'] = ORIGINAL_PATH # Extract the generated files from the old tar. tweaked_gen_files = [ os.path.join(rsync_lastver, fn) for fn in gen_files ] cmd_run(['tar', 'xzf', lasttar_file, *tweaked_gen_files]) os.rename(rsync_lastver, 'a') print(f"Creating {diff_file} ...") cmd_chk(['rsync', '-a', *gen_pathnames, 'b/']) sed_script = r's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:' # CAUTION: must not contain any single quotes! cmd_chk(f"(git diff v{lastversion} {v_ver} -- ':!.github'; diff -upN a b | sed -r '{sed_script}') | gzip -9 >{diff_file}") shutil.rmtree('a') os.rename('b', rsync_ver) print(f"Creating {srctar_file} ...") cmd_chk(f"git archive --format=tar --prefix={rsync_ver}/ {v_ver} | tar xf -") cmd_chk(f"support/git-set-file-times --quiet --prefix={rsync_ver}/") cmd_chk(['fakeroot', 'tar', 'czf', srctar_file, '--exclude=.github', rsync_ver]) shutil.rmtree(rsync_ver) print(f'Updating files in "{rsync_ver}/patches" dir ...') os.mkdir(rsync_ver, 0o755) os.mkdir(f"{rsync_ver}/patches", 0o755) cmd_chk(f"packaging/patch-update --skip-check --branch={args.master_branch} --gen={rsync_ver}/patches".split()) print(f"Creating {pattar_file} ...") cmd_chk(['fakeroot', 'tar', 'chzf', pattar_file, rsync_ver + '/patches']) shutil.rmtree(rsync_ver) print(f"Updating the other files in {dest} ...") md_files = 'README.md NEWS.md INSTALL.md'.split() html_files = [ fn for fn in gen_pathnames if fn.endswith('.html') ] cmd_chk(['rsync', '-a', *md_files, *html_files, dest]) cmd_chk(["./md-convert", "--dest", dest, *md_files]) cmd_chk(f"git log --name-status | gzip -9 >{dest}/ChangeLog.gz") for fn in (srctar_file, pattar_file, diff_file): asc_fn = fn + '.asc' if os.path.lexists(asc_fn): os.unlink(asc_fn) res = cmd_run(['gpg', '--batch', '-ba', fn]) if res.returncode != 0 and res.returncode != 2: die("gpg signing failed") if not pre: for find in f'{dest}/rsync-*.gz {dest}/rsync-*.asc {dest}/src-previews/rsync-*diffs.gz*'.split(): for fn in glob.glob(find): os.unlink(fn) top_link = [ srctar_file, f"{srctar_file}.asc", pattar_file, f"{pattar_file}.asc", diff_file, f"{diff_file}.asc", ] for fn in top_link: os.link(fn, re.sub(r'/src(-\w+)?/', '/', fn)) print(f"""\ {dash_line} Local changes are done. When you're satisfied, push the git repository and rsync the release files. Remember to announce the release on *BOTH* rsync-announce@lists.samba.org and rsync@lists.samba.org (and the web)! """) def replace_or_die(regex, repl, txt, die_msg): m = regex.search(txt) if not m: die(die_msg) return regex.sub(repl, txt, 1) def signal_handler(sig, frame): die("\nAborting due to SIGINT.") if __name__ == '__main__': parser = argparse.ArgumentParser(description="Prepare a new release of rsync in the git repo & ftp dir.", add_help=False) parser.add_argument('--branch', '-b', dest='master_branch', default='master', help="The branch to release. Default: master.") parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") args = parser.parse_args() main() # vim: sw=4 et ft=python rsync-3.2.7/packaging/prep-auto-dir0000775000000000000000000000314314142014605015721 0ustar rootroot#!/bin/sh -e # This script will setup the build dir based on the current git branch and the # directory auto-build-save/$BRANCH. We don't use a symlink for the build dir # because we want to maximize the ccache reuse, so all builds must happen in # the same real dir. When a dir is moved out of auto-build-save/$BRANCH to the # build dir, it is replaced with a symlink so that it can still be found under # that dir. The build dir also gets a .branch -> $BRANCH symlink so that we # can figure out the current build dir's branch. # To get started, just clone the rsync git repo and create the auto-build-save # dir. If you have an existing git checkout and it is not in a pristine state, # run "make distclean" before creating the auto-build-save dir. auto_top='auto-build-save' if test -d $auto_top && test -d .git; then desired_branch=`git rev-parse --abbrev-ref HEAD | tr / %` if test "$desired_branch" = HEAD; then echo "ERROR: switch to the right build dir manually when in detached HEAD mode." 1>&2 exit 1 fi auto_dir="$auto_top/$desired_branch" if test -d build; then cur_branch=`readlink build/.branch` else cur_branch='/' fi if test "$desired_branch" != "$cur_branch"; then if test "$cur_branch" != /; then rm -f "$auto_top/$cur_branch" mv build "$auto_top/$cur_branch" fi test -d "$auto_dir" || mkdir "$auto_dir" test -h "$auto_dir/.branch" || ln -s "$desired_branch" "$auto_dir/.branch" mv "$auto_dir" build ln -s ../build "$auto_dir" fi if test ! -h Makefile; then rm -f Makefile ln -s packaging/auto-Makefile Makefile fi echo $desired_branch fi rsync-3.2.7/packaging/openssl-rsync.cnf0000664000000000000000000000057714307154751016634 0ustar rootroot# This config file can be used with rsync to enable legacy digests # (such as MD4) by using the OPENSSL_CONF environment variable. # See rsync's configure --with-openssl-conf=/path/name option. openssl_conf = openssl_init [openssl_init] providers = provider_sect [provider_sect] default = default_sect legacy = legacy_sect [default_sect] activate = 1 [legacy_sect] activate = 1 rsync-3.2.7/packaging/pkglib.py0000664000000000000000000002327414317733270015146 0ustar rootrootimport os, sys, re, subprocess, argparse # This python3 library provides a few helpful routines that are # used by the latest packaging scripts. default_encoding = 'utf-8' # Output the msg args to stderr. Accepts all the args that print() accepts. def warn(*msg): print(*msg, file=sys.stderr) # Output the msg args to stderr and die with a non-zero return-code. # Accepts all the args that print() accepts. def die(*msg): warn(*msg) sys.exit(1) # Set this to an encoding name or set it to None to avoid the default encoding idiom. def set_default_encoding(enc): default_encoding = enc # Set shell=True if the cmd is a string; sets a default encoding unless raw=True was specified. def _tweak_opts(cmd, opts, **maybe_set_args): def _maybe_set(o, **msa): # Only set a value if the user didn't already set it. for var, val in msa.items(): if var not in o: o[var] = val opts = opts.copy() _maybe_set(opts, **maybe_set_args) if isinstance(cmd, str): _maybe_set(opts, shell=True) want_raw = opts.pop('raw', False) if default_encoding and not want_raw: _maybe_set(opts, encoding=default_encoding) capture = opts.pop('capture', None) if capture: if capture == 'stdout': _maybe_set(opts, stdout=subprocess.PIPE) elif capture == 'stderr': _maybe_set(opts, stderr=subprocess.PIPE) elif capture == 'output': _maybe_set(opts, stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif capture == 'combined': _maybe_set(opts, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) discard = opts.pop('discard', None) if discard: # We DO want to override any already set stdout|stderr values (unlike above). if discard == 'stdout' or discard == 'output': opts['stdout'] = subprocess.DEVNULL if discard == 'stderr' or discard == 'output': opts['stderr'] = subprocess.DEVNULL return opts # This does a normal subprocess.run() with some auto-args added to make life easier. def cmd_run(cmd, **opts): return subprocess.run(cmd, **_tweak_opts(cmd, opts)) # Like cmd_run() with a default check=True specified. def cmd_chk(cmd, **opts): return subprocess.run(cmd, **_tweak_opts(cmd, opts, check=True)) # Capture stdout in a string and return an object with out, err, and rc (return code). # It defaults to capture='stdout' (so err is empty) but can be overridden using # capture='combined' or capture='output' (the latter populates the err value). def cmd_txt(cmd, **opts): input = opts.pop('input', None) if input is not None: opts['stdin'] = subprocess.PIPE proc = subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout')) out, err = proc.communicate(input=input) return argparse.Namespace(out=out, err=err, rc=proc.returncode) # Just like calling cmd_txt() except that it raises an error if the command has a non-0 return code. # The raised error includes the cmd, the return code, and the captured output. def cmd_txt_chk(cmd, **opts): ct = cmd_txt(cmd, **opts) if ct.rc != 0: cmd_err = f'Command "{cmd}" returned non-0 exit status "{ct.rc}" and output:\n{ct.out}{ct.err}' raise Exception(cmd_err) return ct # Starts a piped-output command of stdout (by default) and leaves it up to you to read # the output and call communicate() on the returned object. def cmd_pipe(cmd, **opts): return subprocess.Popen(cmd, **_tweak_opts(cmd, opts, capture='stdout')) # Runs a "git status" command and dies if the checkout is not clean (the # arg fatal_unless_clean can be used to make that non-fatal. Returns a # tuple of the current branch, the is_clean flag, and the status text. def check_git_status(fatal_unless_clean=True, subdir='.'): status_txt = cmd_txt_chk(f"cd '{subdir}' && git status").out is_clean = re.search(r'\nnothing to commit.+working (directory|tree) clean', status_txt) != None if not is_clean and fatal_unless_clean: if subdir == '.': subdir = '' else: subdir = f" *{subdir}*" die(f"The{subdir} checkout is not clean:\n" + status_txt) m = re.match(r'^(?:# )?On branch (.+)\n', status_txt) cur_branch = m[1] if m else None return (cur_branch, is_clean, status_txt) # Calls check_git_status() on the current git checkout and (optionally) a subdir path's # checkout. Use fatal_unless_clean to indicate if an unclean checkout is fatal or not. # The master_branch arg indicates what branch we want both checkouts to be using, and # if the branch is wrong the user is given the option of either switching to the right # branch or aborting. def check_git_state(master_branch, fatal_unless_clean=True, check_extra_dir=None): cur_branch = check_git_status(fatal_unless_clean)[0] branch = re.sub(r'^patch/([^/]+)/[^/]+$', r'\1', cur_branch) # change patch/BRANCH/PATCH_NAME into BRANCH if branch != master_branch: print(f"The checkout is not on the {master_branch} branch.") if master_branch != 'master': sys.exit(1) ans = input(f"Do you want me to continue with --branch={branch}? [n] ") if not ans or not re.match(r'^y', ans, flags=re.I): sys.exit(1) master_branch = branch if check_extra_dir and os.path.isdir(os.path.join(check_extra_dir, '.git')): branch = check_git_status(fatal_unless_clean, check_extra_dir)[0] if branch != master_branch: print(f"The *{check_extra_dir}* checkout is on branch {branch}, not branch {master_branch}.") ans = input(f"Do you want to change it to branch {master_branch}? [n] ") if not ans or not re.match(r'^y', ans, flags=re.I): sys.exit(1) subdir.check_call(f"cd {check_extra_dir} && git checkout '{master_branch}'", shell=True) return (cur_branch, master_branch) # Return the git hash of the most recent commit. def latest_git_hash(branch): out = cmd_txt_chk(['git', 'log', '-1', '--no-color', branch]).out m = re.search(r'^commit (\S+)', out, flags=re.M) if not m: die(f"Unable to determine commit hash for master branch: {branch}") return m[1] # Return a set of all branch names that have the format "patch/BASE_BRANCH/NAME" # for the given base_branch string. Just the NAME portion is put into the set. def get_patch_branches(base_branch): branches = set() proc = cmd_pipe('git branch -l'.split()) for line in proc.stdout: m = re.search(r' patch/([^/]+)/(.+)', line) if m and m[1] == base_branch: branches.add(m[2]) proc.communicate() return branches def mandate_gensend_hook(): hook = '.git/hooks/pre-push' if not os.path.exists(hook): print('Creating hook file:', hook) cmd_chk(['./rsync', '-a', 'packaging/pre-push', hook]) else: ct = cmd_txt(['grep', 'make gensend', hook], discard='output') if ct.rc: die('Please add a "make gensend" into your', hook, 'script.') # Snag the GENFILES values out of the Makefile file and return them as a list. def get_gen_files(want_dir_plus_list=False): cont_re = re.compile(r'\\\n') gen_files = [ ] auto_dir = os.path.join('auto-build-save', cmd_txt('git rev-parse --abbrev-ref HEAD').out.strip().replace('/', '%')) with open(auto_dir + '/Makefile', 'r', encoding='utf-8') as fh: for line in fh: if not gen_files: chk = re.sub(r'^GENFILES=', '', line) if line == chk: continue line = chk m = re.search(r'\\$', line) line = re.sub(r'^\s+|\s*\\\n?$|\s+$', '', line) gen_files += line.split() if not m: break if want_dir_plus_list: return (auto_dir, gen_files) return [ os.path.join(auto_dir, fn) for fn in gen_files ] def get_rsync_version(): with open('version.h', 'r', encoding='utf-8') as fh: txt = fh.read() m = re.match(r'^#define\s+RSYNC_VERSION\s+"(\d.+?)"', txt) if m: return m[1] die("Unable to find RSYNC_VERSION define in version.h") def get_NEWS_version_info(): rel_re = re.compile(r'^\| \S{2} \w{3} \d{4}\s+\|\s+(?P\d+\.\d+\.\d+)\s+\|\s+(?P\d{2} \w{3} \d{4})?\s+\|\s+(?P\d+)\s+\|') last_version = last_protocol_version = None pdate = { } with open('NEWS.md', 'r', encoding='utf-8') as fh: for line in fh: if not last_version: # Find the first non-dev|pre version with a release date. m = re.search(r'rsync (\d+\.\d+\.\d+) .*\d\d\d\d', line) if m: last_version = m[1] m = rel_re.match(line) if m: if m['pdate']: pdate[m['ver']] = m['pdate'] if m['ver'] == last_version: last_protocol_version = m['pver'] if not last_protocol_version: die(f"Unable to determine protocol_version for {last_version}.") return last_version, last_protocol_version, pdate def get_protocol_versions(): protocol_version = subprotocol_version = None with open('rsync.h', 'r', encoding='utf-8') as fh: for line in fh: m = re.match(r'^#define\s+PROTOCOL_VERSION\s+(\d+)', line) if m: protocol_version = m[1] continue m = re.match(r'^#define\s+SUBPROTOCOL_VERSION\s+(\d+)', line) if m: subprotocol_version = m[1] break if not protocol_version: die("Unable to determine the current PROTOCOL_VERSION.") if not subprotocol_version: die("Unable to determine the current SUBPROTOCOL_VERSION.") return protocol_version, subprotocol_version # vim: sw=4 et rsync-3.2.7/packaging/solaris/0000775000000000000000000000000014324367162014771 5ustar rootrootrsync-3.2.7/packaging/solaris/build_pkg.sh0000664000000000000000000000476013663040422017264 0ustar rootroot#!/bin/sh # Shell script for building Solaris package of rsync # Author: Jens Apel # License: GPL # # BASEDIR is /usr/local and should be the same as the # --prefix parameter of configure # # this script should be copied under # packaging/solaris/5.8/build_pkg.sh # Definitions start here # you can edit this, if you like # The Package name under which rsync will b installed PKGNAME=SMBrsync # Extract common info requires for the 'info' part of the package. # This should be made generic and generated by the configure script # but for now it is hard coded BASEDIR=/usr/local VERSION="2.5.5" ARCH=`uname -p` NAME=rsync # Definitions end here # Please do not edit below this line or you know what you do. ## Start by faking root install echo "Creating install directory (fake $BASEDIR)..." START=`pwd` FAKE_ROOT=$START/${PKGNAME} mkdir $FAKE_ROOT # copy the binary and the man page to their places mkdir $FAKE_ROOT/bin mkdir -p $FAKE_ROOT/doc/rsync mkdir -p $FAKE_ROOT/man/man1 mkdir -p $FAKE_ROOT/man/man5 cp ../../../rsync $FAKE_ROOT/bin/rsync cp ../../../rsync.1 $FAKE_ROOT/man/man1/rsync.1 cp ../../../rsyncd.conf.5 $FAKE_ROOT/man/man5/rsyncd.conf.5 cp ../../../README.md $FAKE_ROOT/doc/rsync/README.md cp ../../../COPYING $FAKE_ROOT/doc/rsync/COPYING cp ../../../tech_report.pdf $FAKE_ROOT/doc/rsync/tech_report.pdf cp ../../../COPYING $FAKE_ROOT/COPYING ## Build info file echo "Building pkginfo file..." cat > $FAKE_ROOT/pkginfo << EOF_INFO PKG=$PKGNAME NAME=$NAME DESC="Program for efficient remote updates of files." VENDOR="Samba Team URL: http://samba.anu.edu.au/rsync/" BASEDIR=$BASEDIR ARCH=$ARCH VERSION=$VERSION CATEGORY=application CLASSES=none EOF_INFO ## Build prototype file cat > $FAKE_ROOT/prototype << EOFPROTO i copyright=COPYING i pkginfo=pkginfo d none bin 0755 bin bin f none bin/rsync 0755 bin bin d none doc 0755 bin bin d none doc/$NAME 0755 bin bin f none doc/$NAME/README.md 0644 bin bin f none doc/$NAME/COPYING 0644 bin bin f none doc/$NAME/tech_report.pdf 0644 bin bin d none man 0755 bin bin d none man/man1 0755 bin bin f none man/man1/rsync.1 0644 bin bin d none man/man5 0755 bin bin f none man/man5/rsyncd.conf.5 0644 bin bin EOFPROTO ## And now build the package. OUTPUTFILE=$PKGNAME-$VERSION-sol8-$ARCH-local.pkg echo "Building package.." echo FAKE_ROOT = $FAKE_ROOT cd $FAKE_ROOT pkgmk -d . -r . -f ./prototype -o pkgtrans -os . $OUTPUTFILE $PKGNAME mv $OUTPUTFILE .. cd .. # Comment this out if you want to see, which file structure has been created rm -rf $FAKE_ROOT rsync-3.2.7/packaging/pre-push0000775000000000000000000000051214130612250014766 0ustar rootroot#!/bin/bash -e cat >/dev/null # Just discard stdin data if [[ -f /proc/$PPID/cmdline ]]; then while read -d $'\0' arg ; do if [[ "$arg" == '--tags' ]] ; then exit 0 fi done \d\d\d\d)\S+\s+\S+\s+(?P.+)', line) if not m: print("Failed to parse line from git-set-file-times:", line) sys.exit(1) m = argparse.Namespace(**m.groupdict()) if m.year > latest_year: latest_year = m.year if m.fn.startswith('zlib/') or m.fn.startswith('popt/'): continue if re.search(r'\.(c|h|sh|test)$', m.fn): maybe_edit_copyright_year(m.fn, m.year) proc.communicate() fn = 'latest-year.h' with open(fn, 'r', encoding='utf-8') as fh: old_txt = fh.read() txt = f'#define LATEST_YEAR "{latest_year}"\n' if txt != old_txt: print(f"Updating {fn} with year {latest_year}") with open(fn, 'w', encoding='utf-8') as fh: fh.write(txt) def maybe_edit_copyright_year(fn, year): opening_lines = [ ] copyright_line = None with open(fn, 'r', encoding='utf-8') as fh: for lineno, line in enumerate(fh): opening_lines.append(line) if lineno > 3 and not re.search(r'\S', line): break m = re.match(r'^(?P
.*Copyright\s+\S+\s+)(?P\d\d\d\d(?:-\d\d\d\d)?(,\s+\d\d\d\d)*)(?P.+)', line)
            if not m:
                continue
            copyright_line = argparse.Namespace(**m.groupdict())
            copyright_line.lineno = len(opening_lines)
            copyright_line.is_maintainer_line = MAINTAINER_NAME in copyright_line.suf
            copyright_line.txt = line
            if copyright_line.is_maintainer_line:
                break

        if not copyright_line:
            return

        if copyright_line.is_maintainer_line:
            cyears = copyright_line.year.split('-')
            if year == cyears[0]:
                cyears = [ year ]
            else:
                cyears = [ cyears[0], year ]
            txt = copyright_line.pre + '-'.join(cyears) + MAINTAINER_SUF
            if txt == copyright_line.txt:
                return
            opening_lines[copyright_line.lineno - 1] = txt
        else:
            if fn.startswith('lib/') or fn.startswith('testsuite/'):
                return
            txt = copyright_line.pre + year + MAINTAINER_SUF
            opening_lines[copyright_line.lineno - 1] += txt

        remaining_txt = fh.read()

    print(f"Updating {fn} with year {year}")

    with open(fn, 'w', encoding='utf-8') as fh:
        fh.write(''.join(opening_lines))
        fh.write(remaining_txt)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Grab the year of last mod for our c & h files and make sure the Copyright comment is up-to-date.")
    args = parser.parse_args()
    main()

# vim: sw=4 et
rsync-3.2.7/packaging/auto-Makefile0000664000000000000000000000072614162171610015717 0ustar  rootrootTARGETS := all install install-ssl-daemon install-all install-strip conf gen gensend reconfigure restatus \
	proto man clean cleantests distclean test check check29 check30 installcheck splint \
	doxygen doxygen-upload finddead rrsync

.PHONY: $(TARGETS) auto-prep

$(TARGETS): auto-prep
	make -C build $@

auto-prep:
	@if test x`packaging/prep-auto-dir` = x; then echo "auto-build-save is not setup"; exit 1; fi
	@echo 'Build branch: '`readlink build/.branch | tr % /`
rsync-3.2.7/checksum.c0000664000000000000000000005061514315642342013342 0ustar  rootroot/*
 * Routines to support checksumming of bytes.
 *
 * Copyright (C) 1996 Andrew Tridgell
 * Copyright (C) 1996 Paul Mackerras
 * Copyright (C) 2004-2022 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.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to dynamically link rsync with the OpenSSL and xxhash
 * libraries when those libraries are being distributed in compliance
 * with their license terms, and to distribute a dynamically linked
 * combination of rsync and these libraries.  This is also considered
 * to be covered under the GPL's System Libraries exception.
 *
 * 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"

#ifdef SUPPORT_XXHASH
#include 
# if XXH_VERSION_NUMBER >= 800
#  define SUPPORT_XXH3 1
# endif
#endif

extern int am_server;
extern int whole_file;
extern int checksum_seed;
extern int protocol_version;
extern int proper_seed_order;
extern const char *checksum_choice;

#define NNI_BUILTIN (1<<0)
#define NNI_EVP (1<<1)
#define NNI_EVP_OK (1<<2)

struct name_num_item valid_checksums_items[] = {
#ifdef SUPPORT_XXH3
	{ CSUM_XXH3_128, 0, "xxh128", NULL },
	{ CSUM_XXH3_64, 0, "xxh3", NULL },
#endif
#ifdef SUPPORT_XXHASH
	{ CSUM_XXH64, 0, "xxh64", NULL },
	{ CSUM_XXH64, 0, "xxhash", NULL },
#endif
	{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
	{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
#ifdef SHA_DIGEST_LENGTH
	{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
#endif
	{ CSUM_NONE, 0, "none", NULL },
	{ 0, 0, NULL, NULL }
};

struct name_num_obj valid_checksums = {
	"checksum", NULL, 0, 0, valid_checksums_items
};

struct name_num_item valid_auth_checksums_items[] = {
#ifdef SHA512_DIGEST_LENGTH
	{ CSUM_SHA512, NNI_EVP, "sha512", NULL },
#endif
#ifdef SHA256_DIGEST_LENGTH
	{ CSUM_SHA256, NNI_EVP, "sha256", NULL },
#endif
#ifdef SHA_DIGEST_LENGTH
	{ CSUM_SHA1, NNI_EVP, "sha1", NULL },
#endif
	{ CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL },
	{ CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL },
	{ 0, 0, NULL, NULL }
};

struct name_num_obj valid_auth_checksums = {
	"daemon auth checksum", NULL, 0, 0, valid_auth_checksums_items
};

/* These cannot make use of openssl, so they're marked just as built-in */
struct name_num_item implied_checksum_md4 =
    { CSUM_MD4, NNI_BUILTIN, "md4", NULL };
struct name_num_item implied_checksum_md5 =
    { CSUM_MD5, NNI_BUILTIN, "md5", NULL };

struct name_num_item *xfer_sum_nni; /* used for the transfer checksum2 computations */
int xfer_sum_len;
struct name_num_item *file_sum_nni; /* used for the pre-transfer --checksum computations */
int file_sum_len, file_sum_extra_cnt;

#ifdef USE_OPENSSL
const EVP_MD *xfer_sum_evp_md;
const EVP_MD *file_sum_evp_md;
EVP_MD_CTX *ctx_evp = NULL;
#endif

static int initialized_choices = 0;

struct name_num_item *parse_csum_name(const char *name, int len)
{
	struct name_num_item *nni;

	if (len < 0 && name)
		len = strlen(name);

	init_checksum_choices();

	if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
		if (protocol_version >= 30) {
			if (!proper_seed_order)
				return &implied_checksum_md5;
			name = "md5";
			len = 3;
		} else {
			if (protocol_version >= 27)
				implied_checksum_md4.num = CSUM_MD4_OLD;
			else if (protocol_version >= 21)
				implied_checksum_md4.num = CSUM_MD4_BUSTED;
			else
				implied_checksum_md4.num = CSUM_MD4_ARCHAIC;
			return &implied_checksum_md4;
		}
	}

	nni = get_nni_by_name(&valid_checksums, name, len);

	if (!nni) {
		rprintf(FERROR, "unknown checksum name: %s\n", name);
		exit_cleanup(RERR_UNSUPPORTED);
	}

	return nni;
}

#ifdef USE_OPENSSL
static const EVP_MD *csum_evp_md(struct name_num_item *nni)
{
	const EVP_MD *emd;
	if (!(nni->flags & NNI_EVP))
		return NULL;

#ifdef USE_MD5_ASM
	if (nni->num == CSUM_MD5)
		emd = NULL;
	else
#endif
		emd = EVP_get_digestbyname(nni->name);                                               
	if (emd && !(nni->flags & NNI_EVP_OK)) { /* Make sure it works before we advertise it */
		if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
			out_of_memory("csum_evp_md");
		/* Some routines are marked as legacy and are not enabled in the openssl.cnf file.
		 * If we can't init the emd, we'll fall back to our built-in code. */
		if (EVP_DigestInit_ex(ctx_evp, emd, NULL) == 0)
			emd = NULL;
		else
			nni->flags = (nni->flags & ~NNI_BUILTIN) | NNI_EVP_OK;
	}
	if (!emd)
		nni->flags &= ~NNI_EVP;
	return emd;
}
#endif

void parse_checksum_choice(int final_call)
{
	if (valid_checksums.negotiated_nni)
		xfer_sum_nni = file_sum_nni = valid_checksums.negotiated_nni;
	else {
		char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
		if (cp) {
			xfer_sum_nni = parse_csum_name(checksum_choice, cp - checksum_choice);
			file_sum_nni = parse_csum_name(cp+1, -1);
		} else
			xfer_sum_nni = file_sum_nni = parse_csum_name(checksum_choice, -1);
		if (am_server && checksum_choice)
			validate_choice_vs_env(NSTR_CHECKSUM, xfer_sum_nni->num, file_sum_nni->num);
	}
	xfer_sum_len = csum_len_for_type(xfer_sum_nni->num, 0);
	file_sum_len = csum_len_for_type(file_sum_nni->num, 0);
#ifdef USE_OPENSSL
	xfer_sum_evp_md = csum_evp_md(xfer_sum_nni);
	file_sum_evp_md = csum_evp_md(file_sum_nni);
#endif

	file_sum_extra_cnt = (file_sum_len + EXTRA_LEN - 1) / EXTRA_LEN;

	if (xfer_sum_nni->num == CSUM_NONE)
		whole_file = 1;

	/* Snag the checksum name for both write_batch's option output & the following debug output. */
	if (valid_checksums.negotiated_nni)
		checksum_choice = valid_checksums.negotiated_nni->name;
	else if (checksum_choice == NULL)
		checksum_choice = xfer_sum_nni->name;

	if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) {
		rprintf(FINFO, "%s%s checksum: %s\n",
			am_server ? "Server" : "Client",
			valid_checksums.negotiated_nni ? " negotiated" : "",
			checksum_choice);
	}
}

int csum_len_for_type(int cst, BOOL flist_csum)
{
	switch (cst) {
	  case CSUM_NONE:
		return 1;
	  case CSUM_MD4_ARCHAIC:
		/* The oldest checksum code is rather weird: the file-list code only sent
		 * 2-byte checksums, but all other checksums were full MD4 length. */
		return flist_csum ? 2 : MD4_DIGEST_LEN;
	  case CSUM_MD4:
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
		return MD4_DIGEST_LEN;
	  case CSUM_MD5:
		return MD5_DIGEST_LEN;
#ifdef SHA_DIGEST_LENGTH
	  case CSUM_SHA1:
		return SHA_DIGEST_LENGTH;
#endif
#ifdef SHA256_DIGEST_LENGTH
	  case CSUM_SHA256:
		return SHA256_DIGEST_LENGTH;
#endif
#ifdef SHA512_DIGEST_LENGTH
	  case CSUM_SHA512:
		return SHA512_DIGEST_LENGTH;
#endif
	  case CSUM_XXH64:
	  case CSUM_XXH3_64:
		return 64/8;
	  case CSUM_XXH3_128:
		return 128/8;
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}
	return 0;
}

/* Returns 0 if the checksum is not canonical (i.e. it includes a seed value).
 * Returns 1 if the public sum order matches our internal sum order.
 * Returns -1 if the public sum order is the reverse of our internal sum order.
 */
int canonical_checksum(int csum_type)
{
	switch (csum_type) {
	  case CSUM_NONE:
	  case CSUM_MD4_ARCHAIC:
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
		break;
	  case CSUM_MD4:
	  case CSUM_MD5:
	  case CSUM_SHA1:
	  case CSUM_SHA256:
	  case CSUM_SHA512:
		return -1;
	  case CSUM_XXH64:
	  case CSUM_XXH3_64:
	  case CSUM_XXH3_128:
		return 1;
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}
	return 0;
}

#ifndef USE_ROLL_SIMD /* See simd-checksum-*.cpp. */
/*
  a simple 32 bit checksum that can be updated from either end
  (inspired by Mark Adler's Adler-32 checksum)
  */
uint32 get_checksum1(char *buf1, int32 len)
{
	int32 i;
	uint32 s1, s2;
	schar *buf = (schar *)buf1;

	s1 = s2 = 0;
	for (i = 0; i < (len-4); i+=4) {
		s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 10*CHAR_OFFSET;
		s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
	}
	for (; i < len; i++) {
		s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
	}
	return (s1 & 0xffff) + (s2 << 16);
}
#endif

void get_checksum2(char *buf, int32 len, char *sum)
{
#ifdef USE_OPENSSL
	if (xfer_sum_evp_md) {
		static EVP_MD_CTX *evp = NULL;
		uchar seedbuf[4];
		if (!evp && !(evp = EVP_MD_CTX_create()))
			out_of_memory("get_checksum2");
		EVP_DigestInit_ex(evp, xfer_sum_evp_md, NULL);
		if (checksum_seed) {
			SIVALu(seedbuf, 0, checksum_seed);
			EVP_DigestUpdate(evp, seedbuf, 4);
		}
		EVP_DigestUpdate(evp, (uchar *)buf, len);
		EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
	} else
#endif
	switch (xfer_sum_nni->num) {
#ifdef SUPPORT_XXHASH
	  case CSUM_XXH64:
		SIVAL64(sum, 0, XXH64(buf, len, checksum_seed));
		break;
#endif
#ifdef SUPPORT_XXH3
	  case CSUM_XXH3_64:
		SIVAL64(sum, 0, XXH3_64bits_withSeed(buf, len, checksum_seed));
		break;
	  case CSUM_XXH3_128: {
		XXH128_hash_t digest = XXH3_128bits_withSeed(buf, len, checksum_seed);
		SIVAL64(sum, 0, digest.low64);
		SIVAL64(sum, 8, digest.high64);
		break;
	  }
#endif
	  case CSUM_MD5: {
		md_context m5;
		uchar seedbuf[4];
		md5_begin(&m5);
		if (proper_seed_order) {
			if (checksum_seed) {
				SIVALu(seedbuf, 0, checksum_seed);
				md5_update(&m5, seedbuf, 4);
			}
			md5_update(&m5, (uchar *)buf, len);
		} else {
			md5_update(&m5, (uchar *)buf, len);
			if (checksum_seed) {
				SIVALu(seedbuf, 0, checksum_seed);
				md5_update(&m5, seedbuf, 4);
			}
		}
		md5_result(&m5, (uchar *)sum);
		break;
	  }
	  case CSUM_MD4:
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
	  case CSUM_MD4_ARCHAIC: {
		md_context m;
		int32 i;
		static char *buf1;
		static int32 len1;

		mdfour_begin(&m);

		if (len > len1) {
			if (buf1)
				free(buf1);
			buf1 = new_array(char, len+4);
			len1 = len;
		}

		memcpy(buf1, buf, len);
		if (checksum_seed) {
			SIVAL(buf1,len,checksum_seed);
			len += 4;
		}

		for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
			mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);

		/*
		 * Prior to version 27 an incorrect MD4 checksum was computed
		 * by failing to call mdfour_tail() for block sizes that
		 * are multiples of 64.  This is fixed by calling mdfour_update()
		 * even when there are no more bytes.
		 */
		if (len - i > 0 || xfer_sum_nni->num > CSUM_MD4_BUSTED)
			mdfour_update(&m, (uchar *)(buf1+i), len-i);

		mdfour_result(&m, (uchar *)sum);
		break;
	  }
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}
}

void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
{
	struct map_struct *buf;
	OFF_T i, len = st_p->st_size;
	int32 remainder;
	int fd;

	fd = do_open(fname, O_RDONLY, 0);
	if (fd == -1) {
		memset(sum, 0, file_sum_len);
		return;
	}

	buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE);

#ifdef USE_OPENSSL
	if (file_sum_evp_md) {
		static EVP_MD_CTX *evp = NULL;
		if (!evp && !(evp = EVP_MD_CTX_create()))
			out_of_memory("file_checksum");

		EVP_DigestInit_ex(evp, file_sum_evp_md, NULL);

		for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
			EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);

		remainder = (int32)(len - i);
		if (remainder > 0)
			EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, remainder), remainder);

		EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
	} else
#endif
	switch (file_sum_nni->num) {
#ifdef SUPPORT_XXHASH
	  case CSUM_XXH64: {
		static XXH64_state_t* state = NULL;
		if (!state && !(state = XXH64_createState()))
			out_of_memory("file_checksum");

		XXH64_reset(state, 0);

		for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
			XXH64_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);

		remainder = (int32)(len - i);
		if (remainder > 0)
			XXH64_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);

		SIVAL64(sum, 0, XXH64_digest(state));
		break;
	  }
#endif
#ifdef SUPPORT_XXH3
	  case CSUM_XXH3_64: {
		static XXH3_state_t* state = NULL;
		if (!state && !(state = XXH3_createState()))
			out_of_memory("file_checksum");

		XXH3_64bits_reset(state);

		for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
			XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);

		remainder = (int32)(len - i);
		if (remainder > 0)
			XXH3_64bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);

		SIVAL64(sum, 0, XXH3_64bits_digest(state));
		break;
	  }
	  case CSUM_XXH3_128: {
		XXH128_hash_t digest;
		static XXH3_state_t* state = NULL;
		if (!state && !(state = XXH3_createState()))
			out_of_memory("file_checksum");

		XXH3_128bits_reset(state);

		for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
			XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);

		remainder = (int32)(len - i);
		if (remainder > 0)
			XXH3_128bits_update(state, (uchar *)map_ptr(buf, i, remainder), remainder);

		digest = XXH3_128bits_digest(state);
		SIVAL64(sum, 0, digest.low64);
		SIVAL64(sum, 8, digest.high64);
		break;
	  }
#endif
	  case CSUM_MD5: {
		md_context m5;

		md5_begin(&m5);

		for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
			md5_update(&m5, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);

		remainder = (int32)(len - i);
		if (remainder > 0)
			md5_update(&m5, (uchar *)map_ptr(buf, i, remainder), remainder);

		md5_result(&m5, (uchar *)sum);
		break;
	  }
	  case CSUM_MD4:
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
	  case CSUM_MD4_ARCHAIC: {
		md_context m;

		mdfour_begin(&m);

		for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
			mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK), CSUM_CHUNK);

		/* Prior to version 27 an incorrect MD4 checksum was computed
		 * by failing to call mdfour_tail() for block sizes that
		 * are multiples of 64.  This is fixed by calling mdfour_update()
		 * even when there are no more bytes. */
		remainder = (int32)(len - i);
		if (remainder > 0 || file_sum_nni->num > CSUM_MD4_BUSTED)
			mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);

		mdfour_result(&m, (uchar *)sum);
		break;
	  }
	  default:
		rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n",
			file_sum_nni->name, file_sum_nni->num);
		exit_cleanup(RERR_UNSUPPORTED);
	}

	close(fd);
	unmap_file(buf);
}

static int32 sumresidue;
static md_context ctx_md;
#ifdef SUPPORT_XXHASH
static XXH64_state_t* xxh64_state;
#endif
#ifdef SUPPORT_XXH3
static XXH3_state_t* xxh3_state;
#endif
static struct name_num_item *cur_sum_nni;
int cur_sum_len;

#ifdef USE_OPENSSL
static const EVP_MD *cur_sum_evp_md;
#endif

/* Initialize a hash digest accumulator.  Data is supplied via
 * sum_update() and the resulting binary digest is retrieved via
 * sum_end().  This only supports one active sum at a time. */
int sum_init(struct name_num_item *nni, int seed)
{
	char s[4];

	if (!nni)
		nni = parse_csum_name(NULL, 0);
	cur_sum_nni = nni;
	cur_sum_len = csum_len_for_type(nni->num, 0);
#ifdef USE_OPENSSL
	cur_sum_evp_md = csum_evp_md(nni);
#endif

#ifdef USE_OPENSSL
	if (cur_sum_evp_md) {
		if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
			out_of_memory("file_checksum");
		EVP_DigestInit_ex(ctx_evp, cur_sum_evp_md, NULL);
	} else
#endif
	switch (cur_sum_nni->num) {
#ifdef SUPPORT_XXHASH
	  case CSUM_XXH64:
		if (!xxh64_state && !(xxh64_state = XXH64_createState()))
			out_of_memory("sum_init");
		XXH64_reset(xxh64_state, 0);
		break;
#endif
#ifdef SUPPORT_XXH3
	  case CSUM_XXH3_64:
		if (!xxh3_state && !(xxh3_state = XXH3_createState()))
			out_of_memory("sum_init");
		XXH3_64bits_reset(xxh3_state);
		break;
	  case CSUM_XXH3_128:
		if (!xxh3_state && !(xxh3_state = XXH3_createState()))
			out_of_memory("sum_init");
		XXH3_128bits_reset(xxh3_state);
		break;
#endif
	  case CSUM_MD5:
		md5_begin(&ctx_md);
		break;
	  case CSUM_MD4:
		mdfour_begin(&ctx_md);
		sumresidue = 0;
		break;
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
	  case CSUM_MD4_ARCHAIC:
		mdfour_begin(&ctx_md);
		sumresidue = 0;
		SIVAL(s, 0, seed);
		sum_update(s, 4);
		break;
	  case CSUM_NONE:
		break;
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}

	return cur_sum_len;
}

/* Feed data into a hash digest accumulator. */
void sum_update(const char *p, int32 len)
{
#ifdef USE_OPENSSL
	if (cur_sum_evp_md) {
		EVP_DigestUpdate(ctx_evp, (uchar *)p, len);
	} else
#endif
	switch (cur_sum_nni->num) {
#ifdef SUPPORT_XXHASH
	  case CSUM_XXH64:
		XXH64_update(xxh64_state, p, len);
		break;
#endif
#ifdef SUPPORT_XXH3
	  case CSUM_XXH3_64:
		XXH3_64bits_update(xxh3_state, p, len);
		break;
	  case CSUM_XXH3_128:
		XXH3_128bits_update(xxh3_state, p, len);
		break;
#endif
	  case CSUM_MD5:
		md5_update(&ctx_md, (uchar *)p, len);
		break;
	  case CSUM_MD4:
	  case CSUM_MD4_OLD:
	  case CSUM_MD4_BUSTED:
	  case CSUM_MD4_ARCHAIC:
		if (len + sumresidue < CSUM_CHUNK) {
			memcpy(ctx_md.buffer + sumresidue, p, len);
			sumresidue += len;
			break;
		}

		if (sumresidue) {
			int32 i = CSUM_CHUNK - sumresidue;
			memcpy(ctx_md.buffer + sumresidue, p, i);
			mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, CSUM_CHUNK);
			len -= i;
			p += i;
		}

		while (len >= CSUM_CHUNK) {
			mdfour_update(&ctx_md, (uchar *)p, CSUM_CHUNK);
			len -= CSUM_CHUNK;
			p += CSUM_CHUNK;
		}

		sumresidue = len;
		if (sumresidue)
			memcpy(ctx_md.buffer, p, sumresidue);
		break;
	  case CSUM_NONE:
		break;
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}
}

/* The sum buffer only needs to be as long as the current checksum's digest
 * len, not MAX_DIGEST_LEN. Note that for CSUM_MD4_ARCHAIC that is the full
 * MD4_DIGEST_LEN even if the file-list code is going to ignore all but the
 * first 2 bytes of it. */
void sum_end(char *sum)
{
#ifdef USE_OPENSSL
	if (cur_sum_evp_md) {
		EVP_DigestFinal_ex(ctx_evp, (uchar *)sum, NULL);
	} else
#endif
	switch (cur_sum_nni->num) {
#ifdef SUPPORT_XXHASH
	  case CSUM_XXH64:
		SIVAL64(sum, 0, XXH64_digest(xxh64_state));
		break;
#endif
#ifdef SUPPORT_XXH3
	  case CSUM_XXH3_64:
		SIVAL64(sum, 0, XXH3_64bits_digest(xxh3_state));
		break;
	  case CSUM_XXH3_128: {
		XXH128_hash_t digest = XXH3_128bits_digest(xxh3_state);
		SIVAL64(sum, 0, digest.low64);
		SIVAL64(sum, 8, digest.high64);
		break;
	  }
#endif
	  case CSUM_MD5:
		md5_result(&ctx_md, (uchar *)sum);
		break;
	  case CSUM_MD4:
	  case CSUM_MD4_OLD:
		mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue);
		mdfour_result(&ctx_md, (uchar *)sum);
		break;
	  case CSUM_MD4_BUSTED:
	  case CSUM_MD4_ARCHAIC:
		if (sumresidue)
			mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue);
		mdfour_result(&ctx_md, (uchar *)sum);
		break;
	  case CSUM_NONE:
		*sum = '\0';
		break;
	  default: /* paranoia to prevent missing case values */
		exit_cleanup(RERR_UNSUPPORTED);
	}
}

#if defined SUPPORT_XXH3 || defined USE_OPENSSL
static void verify_digest(struct name_num_item *nni, BOOL check_auth_list)
{
#ifdef SUPPORT_XXH3
	static int xxh3_result = 0;
#endif
#ifdef USE_OPENSSL
	static int prior_num = 0, prior_flags = 0, prior_result = 0;
#endif

#ifdef SUPPORT_XXH3
	if (nni->num == CSUM_XXH3_64 || nni->num == CSUM_XXH3_128) {
		if (!xxh3_result) {
			char buf[32816];
			int j;
			for (j = 0; j < (int)sizeof buf; j++)
				buf[j] = ' ' + (j % 96);
			sum_init(nni, 0);
			sum_update(buf, 32816);
			sum_update(buf, 31152);
			sum_update(buf, 32474);
			sum_update(buf, 9322);
			xxh3_result = XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de ? -1 : 1;
		}
		if (xxh3_result < 0)
			nni->num = CSUM_gone;
		return;
	}
#endif

#ifdef USE_OPENSSL
	if (BITS_SETnUNSET(nni->flags, NNI_EVP, NNI_BUILTIN|NNI_EVP_OK)) {
		if (nni->num == prior_num && nni->flags == prior_flags) {
			nni->flags = prior_result;
			if (!(nni->flags & NNI_EVP))
				nni->num = CSUM_gone;
		} else {
			prior_num = nni->num;
			prior_flags = nni->flags;
			if (!csum_evp_md(nni))
				nni->num = CSUM_gone;
			prior_result = nni->flags;
			if (check_auth_list && (nni = get_nni_by_num(&valid_auth_checksums, prior_num)) != NULL)
				verify_digest(nni, False);
		}
	}
#endif
}
#endif

void init_checksum_choices()
{
#if defined SUPPORT_XXH3 || defined USE_OPENSSL
	struct name_num_item *nni;
#endif

	if (initialized_choices)
		return;

#if defined SUPPORT_XXH3 || defined USE_OPENSSL
	for (nni = valid_checksums.list; nni->name; nni++)
		verify_digest(nni, True);

	for (nni = valid_auth_checksums.list; nni->name; nni++)
		verify_digest(nni, False);
#endif

	initialized_choices = 1;
}
rsync-3.2.7/help-from-md.awk0000775000000000000000000000140213672730211014356 0ustar  rootroot#!/usr/bin/awk -f

# The caller must pass args: -v hfile=help-NAME.h NAME.NUM.md

BEGIN {
    heading = "/* DO NOT EDIT THIS FILE!  It is auto-generated from the option list in " ARGV[1] "! */"
    findcomment = hfile
    sub("\\.", "\\.", findcomment)
    findcomment = "\\[comment\\].*" findcomment
    backtick_cnt = 0
    prints = ""
}

/^```/ {
    backtick_cnt++
    next
}

foundcomment {
    if (backtick_cnt > 1) exit
    if (backtick_cnt == 1) {
	gsub(/"/, "\\\"")
	prints = prints "\n  rprintf(F,\"" $0 "\\n\");"
    }
    next
}

$0 ~ findcomment {
    foundcomment = 1
    backtick_cnt = 0
}

END {
    if (foundcomment && backtick_cnt > 1)
	print heading "\n" prints > hfile
    else {
	print "Failed to find " hfile " section in " ARGV[1]
	exit 1
    }
}
rsync-3.2.7/testhelp/0000775000000000000000000000000014324367162013221 5ustar  rootrootrsync-3.2.7/testhelp/maketree.py0000664000000000000000000000720313672270624015373 0ustar  rootroot#!/usr/bin/env python2

# Copyright (C) 2002 by Martin Pool 

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version
# 2 as published by the Free Software Foundation.
#
# 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
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

# Populate a tree with pseudo-randomly distributed files to test
# rsync.

from __future__ import generators
import random, string, os, os.path

nfiles = 10000
depth = 5
n_children = 20
n_files = 20
n_symlinks = 10

name_chars = string.digits + string.letters

abuffer = 'a' * 1024

def random_name_chars():
    a = ""
    for i in range(10):
        a = a + random.choice(name_chars)
    return a

    
def generate_names():
    n = 0
    while 1:
        yield "%05d_%s" % (n, random_name_chars())
        n += 1


class TreeBuilder:
    def __init__(self):
        self.n_children = 20
        self.n_files = 100
        self.total_entries = 100000 # long(1e8)
        self.actual_size = 0
        self.name_gen = generate_names()
        self.all_files = []
        self.all_dirs = []
        self.all_symlinks = []


    def random_size(self):
        return random.lognormvariate(4, 4)


    def random_symlink_target(self):
        what = random.choice(['directory', 'file', 'symlink', 'none'])
        try:
            if what == 'directory':
                return random.choice(self.all_dirs)
            elif what == 'file':
                return random.choice(self.all_files)
            elif what == 'symlink':
                return random.choice(self.all_symlinks)
            elif what == 'none':
                return self.name_gen.next()
        except IndexError:
            return self.name_gen.next()


    def can_continue(self):
        self.total_entries -= 1
        return self.total_entries > 0

        
    def build_tree(self, prefix, depth):
        """Generate a breadth-first tree"""
        for count, function in [[n_files, self.make_file],
                                [n_children, self.make_child_recurse],
                                [n_symlinks, self.make_symlink]]:
            for i in range(count):
                if not self.can_continue():
                    return
                name = os.path.join(prefix, self.name_gen.next())
                function(name, depth)


    def print_summary(self):
        print "total bytes: %d" % self.actual_size


    def make_child_recurse(self, dname, depth):
        if depth > 1:
            self.make_dir(dname)
            self.build_tree(dname, depth-1)


    def make_dir(self, dname, depth='ignore'):
        print "%s/" % (dname)
        os.mkdir(dname)
        self.all_dirs.append(dname)


    def make_symlink(self, lname, depth='ignore'):
        print "%s -> %s" % (lname, self.random_symlink_target())


    def make_file(self, fname, depth='ignore'):
        size = long(self.random_size())
        print "%-70s %d" % (fname, size)
        f = open(fname, 'w')
        f.truncate(size)
        self.fill_file(f, size)
        self.all_files.append(fname)
        self.actual_size += size

    def fill_file(self, f, size):
        while size > 0:
            f.write(abuffer[:size])
            size -= len(abuffer)

    
tb = TreeBuilder()
tb.build_tree('/tmp/foo', 3)
tb.print_summary()
rsync-3.2.7/rsyncd.conf.50000664000000000000000000016417014324367163013717 0ustar  rootroot.TH "rsyncd.conf" "5" "20 Oct 2022" "rsyncd.conf from rsync 3.2.7" "User Commands"
.\" prefix=/usr
.P
.SH "NAME"
.P
rsyncd.conf \- configuration file for rsync in daemon mode
.P
.SH "SYNOPSIS"
.P
rsyncd.conf
.P
The online version of this manpage (that includes cross-linking of topics)
is available at https://download.samba.org/pub/rsync/rsyncd.conf.5.
.P
.SH "DESCRIPTION"
.P
The rsyncd.conf file is the runtime configuration file for rsync when run as an
rsync daemon.
.P
The rsyncd.conf file controls authentication, access, logging and available
modules.
.P
.SH "FILE FORMAT"
.P
The file consists of modules and parameters. A module begins with the name of
the module in square brackets and continues until the next module begins.
Modules contain parameters of the form \fBname\ =\ value\fP.
.P
The file is line-based\ \-\- that is, each newline-terminated line represents
either a comment, a module name or a parameter.
.P
Only the first equals sign in a parameter is significant. Whitespace before or
after the first equals sign is discarded. Leading, trailing and internal
whitespace in module and parameter names is irrelevant. Leading and trailing
whitespace in a parameter value is discarded. Internal whitespace within a
parameter value is retained verbatim.
.P
Any line \fBbeginning\fP with a hash (\fB#\fP) is ignored, as are lines containing
only whitespace. (If a hash occurs after anything other than leading
whitespace, it is considered a part of the line's content.)
.P
Any line ending in a \fB\\\fP is "continued" on the next line in the customary UNIX
fashion.
.P
The values following the equals sign in parameters are all either a string (no
quotes needed) or a boolean, which may be given as yes/no, 0/1 or true/false.
Case is not significant in boolean values, but is preserved in string values.
.P
.SH "LAUNCHING THE RSYNC DAEMON"
.P
The rsync daemon is launched by specifying the \fB\-\-daemon\fP option to rsync.
.P
The daemon must run with root privileges if you wish to use chroot, to bind to
a port numbered under 1024 (as is the default 873), or to set file ownership.
Otherwise, it must just have permission to read and write the appropriate data,
log, and lock files.
.P
You can launch it either via inetd, as a stand-alone daemon, or from an rsync
client via a remote shell.  If run as a stand-alone daemon then just run the
command "\fBrsync\ \-\-daemon\fP" from a suitable startup script.
.P
When run via inetd you should add a line like this to /etc/services:
.RS 4
.P
.nf
rsync           873/tcp
.fi
.RE
.P
and a single line something like this to /etc/inetd.conf:
.RS 4
.P
.nf
rsync   stream  tcp     nowait  root   /usr/bin/rsync rsyncd --daemon
.fi
.RE
.P
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
your system.  You will then need to send inetd a HUP signal to tell it to
reread its config file.
.P
Note that you should \fBnot\fP send the rsync daemon a HUP signal to force it to
reread the \fBrsyncd.conf\fP file. The file is re-read on each client connection.
.P
.SH "GLOBAL PARAMETERS"
.P
The first parameters in the file (before a [module] header) are the global
parameters.  Rsync also allows for the use of a "[global]" module name to
indicate the start of one or more global-parameter sections (the name must be
lower case).
.P
You may also include any module parameters in the global part of the config
file in which case the supplied value will override the default for that
parameter.
.P
You may use references to environment variables in the values of parameters.
String parameters will have %VAR% references expanded as late as possible (when
the string is first used in the program), allowing for the use of variables
that rsync sets at connection time, such as RSYNC_USER_NAME.  Non-string
parameters (such as true/false settings) are expanded when read from the config
file.  If a variable does not exist in the environment, or if a sequence of
characters is not a valid reference (such as an un-paired percent sign), the
raw characters are passed through unchanged.  This helps with backward
compatibility and safety (e.g. expanding a non-existent %VAR% to an empty
string in a path could result in a very unsafe path).  The safest way to insert
a literal % into a value is to use %%.
.P
.IP "\fBmotd\ file\fP"
This parameter allows you to specify a "message of the day" (MOTD) to display
to clients on each connect. This usually contains site information and any
legal notices. The default is no MOTD file.  This can be overridden by the
\fB\-\-dparam=motdfile=FILE\fP command-line option when starting the daemon.
.IP "\fBpid\ file\fP"
This parameter tells the rsync daemon to write its process ID to that file.
The rsync keeps the file locked so that it can know when it is safe to
overwrite an existing file.
.IP
The filename can be overridden by the \fB\-\-dparam=pidfile=FILE\fP command-line
option when starting the daemon.
.IP "\fBport\fP"
You can override the default port the daemon will listen on by specifying
this value (defaults to 873).  This is ignored if the daemon is being run
by inetd, and is superseded by the \fB\-\-port\fP command-line option.
.IP "\fBaddress\fP"
You can override the default IP address the daemon will listen on by
specifying this value.  This is ignored if the daemon is being run by
inetd, and is superseded by the \fB\-\-address\fP command-line option.
.IP "\fBsocket\ options\fP"
This parameter can provide endless fun for people who like to tune their
systems to the utmost degree. You can set all sorts of socket options which
may make transfers faster (or slower!). Read the manpage for the
\fBsetsockopt()\fP system call for details on some of the options you may be
able to set. By default no special socket options are set.  These settings
can also be specified via the \fB\-\-sockopts\fP command-line option.
.IP "\fBlisten\ backlog\fP"
You can override the default backlog value when the daemon listens for
connections.  It defaults to 5.
.P
.SH "MODULE PARAMETERS"
.P
After the global parameters you should define a number of modules, each module
exports a directory tree as a symbolic name. Modules are exported by specifying
a module name in square brackets [module] followed by the parameters for that
module.  The module name cannot contain a slash or a closing square bracket.
If the name contains whitespace, each internal sequence of whitespace will be
changed into a single space, while leading or trailing whitespace will be
discarded.  Also, the name cannot be "global" as that exact name indicates that
global parameters follow (see above).
.P
As with GLOBAL PARAMETERS, you may use references to environment variables in
the values of parameters.  See the GLOBAL PARAMETERS section for more details.
.P
.IP "\fBcomment\fP"
This parameter specifies a description string that is displayed next to the
module name when clients obtain a list of available modules. The default is
no comment.
.IP "\fBpath\fP"
This parameter specifies the directory in the daemon's filesystem to make
available in this module.  You must specify this parameter for each module
in \fBrsyncd.conf\fP.
.IP
If the value contains a "/./" element then the path will be divided at that
point into a chroot dir and an inner-chroot subdir.  If \fBuse\ chroot\fP
is set to false, though, the extraneous dot dir is just cleaned out of the
path.  An example of this idiom is:
.RS 4
.IP
.nf
path = /var/rsync/./module1
.fi
.RE
.IP
This will (when chrooting) chroot to "/var/rsync" and set the inside-chroot
path to "/module1".
.IP
You may base the path's value off of an environment variable by surrounding
the variable name with percent signs.  You can even reference a variable
that is set by rsync when the user connects.  For example, this would use
the authorizing user's name in the path:
.RS 4
.IP
.nf
path = /home/%RSYNC_USER_NAME%
.fi
.RE
.IP
It is fine if the path includes internal spaces\ \-\- they will be retained
verbatim (which means that you shouldn't try to escape them).  If your
final directory has a trailing space (and this is somehow not something you
wish to fix), append a trailing slash to the path to avoid losing the
trailing whitespace.
.IP "\fBuse\ chroot\fP"
If "use chroot" is true, the rsync daemon will chroot to the "path" before
starting the file transfer with the client.  This has the advantage of
extra protection against possible implementation security holes, but it has
the disadvantages of requiring super-user privileges, of not being able to
follow symbolic links that are either absolute or outside of the new root
path, and of complicating the preservation of users and groups by name (see
below).
.IP
If \fBuse\ chroot\fP is not set, it defaults to trying to enable a chroot but
allows the daemon to continue (after logging a warning) if it fails. The
one exception to this is when a module's \fBpath\fP has a "/./" chroot
divider in it\ \-\- this causes an unset value to be treated as true for that
module.
.IP
Prior to rsync 3.2.7, the default value was "true".  The new "unset"
default makes it easier to setup an rsync daemon as a non-root user or to
run a daemon on a system where chroot fails.  Explicitly setting the value
to "true" in rsyncd.conf will always require the chroot to succeed.
.IP
It is also possible to specify a dot-dir in the module's "path" to
indicate that you want to chdir to the earlier part of the path and then
serve files from inside the latter part of the path (with sanitizing and
default symlink munging).  This can be useful if you need some library dirs
inside the chroot (typically for uid & gid lookups) but don't want to put
the lib dir into the top of the served path (even though they can be hidden
with an \fBexclude\fP directive).  However, a better choice for a modern
rsync setup is to use a \fBname\ converter\fP" and try to avoid inner lib
dirs altogether.  See also the \fBdaemon\ chroot\fP parameter, which causes
rsync to chroot into its own chroot area before doing any path-related
chrooting.
.IP
If the daemon is serving the "/" dir (either directly or due to being
chrooted to the module's path), rsync does not do any path sanitizing or
(default) munging.
.IP
When it has to limit access to a particular subdir (either due to chroot
being disabled or having an inside-chroot path set), rsync will munge
symlinks (by default) and sanitize paths.  Those that dislike munged
symlinks (and really, really trust their users to not break out of the
subdir) can disable the symlink munging via the "munge symlinks"
parameter.
.IP
When rsync is sanitizing paths, it trims ".." path elements from args that
it believes would escape the module hierarchy. It also substitutes leading
slashes in absolute paths with the module's path (so that options such as
\fB\-\-backup-dir\fP & \fB\-\-compare-dest\fP interpret an absolute path as rooted in
the module's "path" dir).
.IP
When a chroot is in effect \fIand\fP the "name converter" parameter is
\fInot\fP set, the "numeric ids" parameter will default to being enabled
(disabling name lookups).  This means that if you manually setup
name-lookup libraries in your chroot (instead of using a name converter)
that you need to explicitly set \fBnumeric\ ids\ =\ false\fP for rsync to do name
lookups.
.IP
If you copy library resources into the module's chroot area, you should
protect them through your OS's normal user/group or ACL settings (to
prevent the rsync module's user from being able to change them), and then
hide them from the user's view via "exclude" (see how in the discussion of
that parameter).  However, it's easier and safer to setup a name converter.
.IP "\fBdaemon\ chroot\fP"
This parameter specifies a path to which the daemon will chroot before
beginning communication with clients. Module paths (and any "use chroot"
settings) will then be related to this one. This lets you choose if you
want the whole daemon to be chrooted (with this setting), just the
transfers to be chrooted (with "use chroot"), or both.  Keep in mind that
the "daemon chroot" area may need various OS/lib/etc files installed to
allow the daemon to function.  By default the daemon runs without any
chrooting.
.IP "\fBproxy\ protocol\fP"
When this parameter is enabled, all incoming connections must start with a
V1 or V2 proxy protocol header.  If the header is not found, the connection
is closed.
.IP
Setting this to \fBtrue\fP requires a proxy server to forward source IP
information to rsync, allowing you to log proper IP/host info and make use
of client-oriented IP restrictions.  The default of \fBfalse\fP means that the
IP information comes directly from the socket's metadata.  If rsync is not
behind a proxy, this should be disabled.
.IP
\fICAUTION\fP: using this option can be dangerous if you do not ensure that
only the proxy is allowed to connect to the rsync port.  If any non-proxied
connections are allowed through, the client will be able to use a modified
rsync to spoof any remote IP address that they desire.  You can lock this
down using something like iptables \fB\-uid-owner\ root\fP rules (for strict
localhost access), various firewall rules, or you can require password
authorization so that any spoofing by users will not grant extra access.
.IP
This setting is global.  If you need some modules to require this and not
others, then you will need to setup multiple rsync daemon processes on
different ports.
.IP "\fBname\ converter\fP"
This parameter lets you specify a program that will be run by the rsync
daemon to do user & group conversions between names & ids.  This script
is started prior to any chroot being setup, and runs as the daemon user
(not the transfer user).  You can specify a fully qualified pathname or
a program name that is on the $PATH.
.IP
The program can be used to do normal user & group lookups without having to
put any extra files into the chroot area of the module \fIor\fP you can do
customized conversions.
.IP
The nameconvert program has access to all of the environment variables that
are described in the section on \fBpre-xfer\ exec\fP.  This is useful if you
want to customize the conversion using information about the module and/or
the copy request.
.IP
There is a sample python script in the support dir named "nameconvert" that
implements the normal user & group lookups.  Feel free to customize it or
just use it as documentation to implement your own.
.IP "\fBnumeric\ ids\fP"
Enabling this parameter disables the mapping of users and groups by name
for the current daemon module.  This prevents the daemon from trying to
load any user/group-related files or libraries.  This enabling makes the
transfer behave as if the client had passed the \fB\-\-numeric-ids\fP
command-line option.  By default, this parameter is enabled for chroot
modules and disabled for non-chroot modules.  Also keep in mind that
uid/gid preservation requires the module to be running as root (see "uid")
or for "fake super" to be configured.
.IP
A chroot-enabled module should not have this parameter set to false unless
you're using a "name converter" program \fIor\fP you've taken steps to ensure
that the module has the necessary resources it needs to translate names and
that it is not possible for a user to change those resources.
.IP "\fBmunge\ symlinks\fP"
This parameter tells rsync to modify all symlinks in the same way as the
(non-daemon-affecting) \fB\-\-munge-links\fP command-line option (using a method
described below).  This should help protect your files from user trickery
when your daemon module is writable.  The default is disabled when
"use chroot" is on with an inside-chroot path of "/", OR if "daemon chroot"
is on, otherwise it is enabled.
.IP
If you disable this parameter on a daemon that is not read-only, there are
tricks that a user can play with uploaded symlinks to access
daemon-excluded items (if your module has any), and, if "use chroot" is
off, rsync can even be tricked into showing or changing data that is
outside the module's path (as access-permissions allow).
.IP
The way rsync disables the use of symlinks is to prefix each one with the
string "/rsyncd-munged/".  This prevents the links from being used as long
as that directory does not exist.  When this parameter is enabled, rsync
will refuse to run if that path is a directory or a symlink to a directory.
When using the "munge symlinks" parameter in a chroot area that has an
inside-chroot path of "/", you should add "/rsyncd-munged/" to the exclude
setting for the module so that a user can't try to create it.
.IP
Note:  rsync makes no attempt to verify that any pre-existing symlinks in
the module's hierarchy are as safe as you want them to be (unless, of
course, it just copied in the whole hierarchy).  If you setup an rsync
daemon on a new area or locally add symlinks, you can manually protect your
symlinks from being abused by prefixing "/rsyncd-munged/" to the start of
every symlink's value.  There is a perl script in the support directory of
the source code named "munge-symlinks" that can be used to add or remove
this prefix from your symlinks.
.IP
When this parameter is disabled on a writable module and "use chroot" is
off (or the inside-chroot path is not "/"), incoming symlinks will be
modified to drop a leading slash and to remove ".." path elements that
rsync believes will allow a symlink to escape the module's hierarchy.
There are tricky ways to work around this, though, so you had better trust
your users if you choose this combination of parameters.
.IP "\fBcharset\fP"
This specifies the name of the character set in which the module's
filenames are stored.  If the client uses an \fB\-\-iconv\fP option, the daemon
will use the value of the "charset" parameter regardless of the character
set the client actually passed.  This allows the daemon to support charset
conversion in a chroot module without extra files in the chroot area, and
also ensures that name-translation is done in a consistent manner.  If the
"charset" parameter is not set, the \fB\-\-iconv\fP option is refused, just as if
"iconv" had been specified via "refuse options".
.IP
If you wish to force users to always use \fB\-\-iconv\fP for a particular module,
add "no-iconv" to the "refuse options" parameter.  Keep in mind that this
will restrict access to your module to very new rsync clients.
.IP "\fBmax\ connections\fP"
This parameter allows you to specify the maximum number of simultaneous
connections you will allow.  Any clients connecting when the maximum has
been reached will receive a message telling them to try later.  The default
is 0, which means no limit.  A negative value disables the module.  See
also the "lock file" parameter.
.IP "\fBlog\ file\fP"
When the "log file" parameter is set to a non-empty string, the rsync
daemon will log messages to the indicated file rather than using syslog.
This is particularly useful on systems (such as AIX) where \fBsyslog()\fP
doesn't work for chrooted programs.  The file is opened before \fBchroot()\fP
is called, allowing it to be placed outside the transfer.  If this value is
set on a per-module basis instead of globally, the global log will still
contain any authorization failures or config-file error messages.
.IP
If the daemon fails to open the specified file, it will fall back to using
syslog and output an error about the failure.  (Note that the failure to
open the specified log file used to be a fatal error.)
.IP
This setting can be overridden by using the \fB\-\-log-file=FILE\fP or
\fB\-\-dparam=logfile=FILE\fP command-line options.  The former overrides all the
log-file parameters of the daemon and all module settings.  The latter sets
the daemon's log file and the default for all the modules, which still
allows modules to override the default setting.
.IP "\fBsyslog\ facility\fP"
This parameter allows you to specify the syslog facility name to use when
logging messages from the rsync daemon. You may use any standard syslog
facility name which is defined on your system. Common names are auth,
authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, syslog, user,
uucp, local0, local1, local2, local3, local4, local5, local6 and local7.
The default is daemon.  This setting has no effect if the "log file"
setting is a non-empty string (either set in the per-modules settings, or
inherited from the global settings).
.IP "\fBsyslog\ tag\fP"
This parameter allows you to specify the syslog tag to use when logging
messages from the rsync daemon. The default is "rsyncd".  This setting has
no effect if the "log file" setting is a non-empty string (either set in
the per-modules settings, or inherited from the global settings).
.IP
For example, if you wanted each authenticated user's name to be included in
the syslog tag, you could do something like this:
.RS 4
.IP
.nf
syslog tag = rsyncd.%RSYNC_USER_NAME%
.fi
.RE
.IP "\fBmax\ verbosity\fP"
This parameter allows you to control the maximum amount of verbose
information that you'll allow the daemon to generate (since the information
goes into the log file). The default is 1, which allows the client to
request one level of verbosity.
.IP
This also affects the user's ability to request higher levels of \fB\-\-info\fP
and \fB\-\-debug\fP logging.  If the max value is 2, then no info and/or debug
value that is higher than what would be set by \fB\-vv\fP will be honored by the
daemon in its logging.  To see how high of a verbosity level you need to
accept for a particular info/debug level, refer to \fBrsync\ \-\-info=help\fP and
\fBrsync\ \-\-debug=help\fP.  For instance, it takes max-verbosity 4 to be able to
output debug TIME2 and FLIST3.
.IP "\fBlock\ file\fP"
This parameter specifies the file to use to support the "max connections"
parameter. The rsync daemon uses record locking on this file to ensure that
the max connections limit is not exceeded for the modules sharing the lock
file.  The default is \fB/var/run/rsyncd.lock\fP.
.IP "\fBread\ only\fP"
This parameter determines whether clients will be able to upload files or
not. If "read only" is true then any attempted uploads will fail. If
"read only" is false then uploads will be possible if file permissions on
the daemon side allow them. The default is for all modules to be read only.
.IP
Note that "auth users" can override this setting on a per-user basis.
.IP "\fBwrite\ only\fP"
This parameter determines whether clients will be able to download files or
not. If "write only" is true then any attempted downloads will fail. If
"write only" is false then downloads will be possible if file permissions
on the daemon side allow them.  The default is for this parameter to be
disabled.
.IP
Helpful hint: you probably want to specify "refuse options = delete" for a
write-only module.
.IP "\fBopen\ noatime\fP"
When set to True, this parameter tells the rsync daemon to open files with
the O_NOATIME flag
(on systems that support it) to avoid changing the access time of the files
that are being transferred.  If your OS does not support the O_NOATIME flag
then rsync will silently ignore this option.  Note also that some
filesystems are mounted to avoid updating the atime on read access even
without the O_NOATIME flag being set.
.IP
When set to False, this parameters ensures that files on the server are not
opened with O_NOATIME.
.IP
When set to Unset (the default) the user controls the setting via
\fB\-\-open-noatime\fP.
.IP "\fBlist\fP"
This parameter determines whether this module is listed when the client
asks for a listing of available modules.  In addition, if this is false,
the daemon will pretend the module does not exist when a client denied by
"hosts allow" or "hosts deny" attempts to access it.  Realize that if
"reverse lookup" is disabled globally but enabled for the module, the
resulting reverse lookup to a potentially client-controlled DNS server may
still reveal to the client that it hit an existing module.  The default is
for modules to be listable.
.IP "\fBuid\fP"
This parameter specifies the user name or user ID that file transfers to
and from that module should take place as when the daemon was run as root.
In combination with the "gid" parameter this determines what file
permissions are available. The default when run by a super-user is to
switch to the system's "nobody" user.  The default for a non-super-user is
to not try to change the user.  See also the "gid" parameter.
.IP
The RSYNC_USER_NAME environment variable may be used to request that rsync
run as the authorizing user.  For example, if you want a rsync to run as
the same user that was received for the rsync authentication, this setup is
useful:
.RS 4
.IP
.nf
uid = %RSYNC_USER_NAME%
gid = *
.fi
.RE
.IP "\fBgid\fP"
This parameter specifies one or more group names/IDs that will be used when
accessing the module.  The first one will be the default group, and any
extra ones be set as supplemental groups.  You may also specify a "\fB*\fP" as
the first gid in the list, which will be replaced by all the normal groups
for the transfer's user (see "uid").  The default when run by a super-user
is to switch to your OS's "nobody" (or perhaps "nogroup") group with no
other supplementary groups.  The default for a non-super-user is to not
change any group attributes (and indeed, your OS may not allow a
non-super-user to try to change their group settings).
.IP
The specified list is normally split into tokens based on spaces and
commas.  However, if the list starts with a comma, then the list is only
split on commas, which allows a group name to contain a space.  In either
case any leading and/or trailing whitespace is removed from the tokens and
empty tokens are ignored.
.IP "\fBdaemon\ uid\fP"
This parameter specifies a uid under which the daemon will run. The daemon
usually runs as user root, and when this is left unset the user is left
unchanged. See also the "uid" parameter.
.IP "\fBdaemon\ gid\fP"
This parameter specifies a gid under which the daemon will run. The daemon
usually runs as group root, and when this is left unset, the group is left
unchanged. See also the "gid" parameter.
.IP "\fBfake\ super\fP"
Setting "fake super = yes" for a module causes the daemon side to behave as
if the \fB\-\-fake-super\fP command-line option had been specified.  This allows
the full attributes of a file to be stored without having to have the
daemon actually running as root.
.IP "\fBfilter\fP"
The daemon has its own filter chain that determines what files it will let
the client access.  This chain is not sent to the client and is independent
of any filters the client may have specified.  Files excluded by the daemon
filter chain (\fBdaemon-excluded\fP files) are treated as non-existent if the
client tries to pull them, are skipped with an error message if the client
tries to push them (triggering exit code 23), and are never deleted from
the module.  You can use daemon filters to prevent clients from downloading
or tampering with private administrative files, such as files you may add
to support uid/gid name translations.
.IP
The daemon filter chain is built from the "filter", "include from",
"include", "exclude from", and "exclude" parameters, in that order of
priority.  Anchored patterns are anchored at the root of the module.  To
prevent access to an entire subtree, for example, "\fB/secret\fP", you \fBmust\fP
exclude everything in the subtree; the easiest way to do this is with a
triple-star pattern like "\fB/secret/***\fP".
.IP
The "filter" parameter takes a space-separated list of daemon filter rules,
though it is smart enough to know not to split a token at an internal space
in a rule (e.g. "\fB\-\ /foo\ \ \-\ /bar\fP" is parsed as two rules).  You may specify
one or more merge-file rules using the normal syntax.  Only one "filter"
parameter can apply to a given module in the config file, so put all the
rules you want in a single parameter.  Note that per-directory merge-file
rules do not provide as much protection as global rules, but they can be
used to make \fB\-\-delete\fP work better during a client download operation if
the per-dir merge files are included in the transfer and the client
requests that they be used.
.IP "\fBexclude\fP"
This parameter takes a space-separated list of daemon exclude patterns.  As
with the client \fB\-\-exclude\fP option, patterns can be qualified with "\fB\-\ \fP" or
"\fB+\ \fP" to explicitly indicate exclude/include.  Only one "exclude" parameter
can apply to a given module.  See the "filter" parameter for a description
of how excluded files affect the daemon.
.IP "\fBinclude\fP"
Use an "include" to override the effects of the "exclude" parameter.  Only
one "include" parameter can apply to a given module.  See the "filter"
parameter for a description of how excluded files affect the daemon.
.IP "\fBexclude\ from\fP"
This parameter specifies the name of a file on the daemon that contains
daemon exclude patterns, one per line.  Only one "exclude from" parameter
can apply to a given module; if you have multiple exclude-from files, you
can specify them as a merge file in the "filter" parameter.  See the
"filter" parameter for a description of how excluded files affect the
daemon.
.IP "\fBinclude\ from\fP"
Analogue of "exclude from" for a file of daemon include patterns.  Only one
"include from" parameter can apply to a given module.  See the "filter"
parameter for a description of how excluded files affect the daemon.
.IP "\fBincoming\ chmod\fP"
This parameter allows you to specify a set of comma-separated chmod strings
that will affect the permissions of all incoming files (files that are
being received by the daemon).  These changes happen after all other
permission calculations, and this will even override destination-default
and/or existing permissions when the client does not specify \fB\-\-perms\fP.
See the description of the \fB\-\-chmod\fP rsync option and the \fBchmod\fP(1)
manpage for information on the format of this string.
.IP "\fBoutgoing\ chmod\fP"
This parameter allows you to specify a set of comma-separated chmod strings
that will affect the permissions of all outgoing files (files that are
being sent out from the daemon).  These changes happen first, making the
sent permissions appear to be different than those stored in the filesystem
itself.  For instance, you could disable group write permissions on the
server while having it appear to be on to the clients.  See the description
of the \fB\-\-chmod\fP rsync option and the \fBchmod\fP(1) manpage for information
on the format of this string.
.IP "\fBauth\ users\fP"
This parameter specifies a comma and/or space-separated list of
authorization rules.  In its simplest form, you list the usernames that
will be allowed to connect to this module. The usernames do not need to
exist on the local system. The rules may contain shell wildcard characters
that will be matched against the username provided by the client for
authentication. If "auth users" is set then the client will be challenged
to supply a username and password to connect to the module. A challenge
response authentication protocol is used for this exchange. The plain text
usernames and passwords are stored in the file specified by the
"secrets file" parameter. The default is for all users to be able to
connect without a password (this is called "anonymous rsync").
.IP
In addition to username matching, you can specify groupname matching via a
\&'@' prefix.  When using groupname matching, the authenticating username
must be a real user on the system, or it will be assumed to be a member of
no groups.  For example, specifying "@rsync" will match the authenticating
user if the named user is a member of the rsync group.
.IP
Finally, options may be specified after a colon (:).  The options allow you
to "deny" a user or a group, set the access to "ro" (read-only), or set the
access to "rw" (read/write).  Setting an auth-rule-specific ro/rw setting
overrides the module's "read only" setting.
.IP
Be sure to put the rules in the order you want them to be matched, because
the checking stops at the first matching user or group, and that is the
only auth that is checked.  For example:
.RS 4
.IP
.nf
auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam
.fi
.RE
.IP
In the above rule, user joe will be denied access no matter what.  Any user
that is in the group "guest" is also denied access.  The user "admin" gets
access in read/write mode, but only if the admin user is not in group
"guest" (because the admin user-matching rule would never be reached if the
user is in group "guest").  Any other user who is in group "rsync" will get
read-only access.  Finally, users susan, joe, and sam get the ro/rw setting
of the module, but only if the user didn't match an earlier group-matching
rule.
.IP
If you need to specify a user or group name with a space in it, start your
list with a comma to indicate that the list should only be split on commas
(though leading and trailing whitespace will also be removed, and empty
entries are just ignored).  For example:
.RS 4
.IP
.nf
auth users = , joe:deny, @Some Group:deny, admin:rw, @RO Group:ro
.fi
.RE
.IP
See the description of the secrets file for how you can have per-user
passwords as well as per-group passwords.  It also explains how a user can
authenticate using their user password or (when applicable) a group
password, depending on what rule is being authenticated.
.IP
See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE
SHELL CONNECTION" in \fBrsync\fP(1) for information on how handle an
rsyncd.conf-level username that differs from the remote-shell-level
username when using a remote shell to connect to an rsync daemon.
.IP "\fBsecrets\ file\fP"
This parameter specifies the name of a file that contains the
username:password and/or @groupname:password pairs used for authenticating
this module. This file is only consulted if the "auth users" parameter is
specified.  The file is line-based and contains one name:password pair per
line.  Any line has a hash (#) as the very first character on the line is
considered a comment and is skipped.  The passwords can contain any
characters but be warned that many operating systems limit the length of
passwords that can be typed at the client end, so you may find that
passwords longer than 8 characters don't work.
.IP
The use of group-specific lines are only relevant when the module is being
authorized using a matching "@groupname" rule.  When that happens, the user
can be authorized via either their "username:password" line or the
"@groupname:password" line for the group that triggered the authentication.
.IP
It is up to you what kind of password entries you want to include, either
users, groups, or both.  The use of group rules in "auth users" does not
require that you specify a group password if you do not want to use shared
passwords.
.IP
There is no default for the "secrets file" parameter, you must choose a
name (such as \fB/etc/rsyncd.secrets\fP).  The file must normally not be
readable by "other"; see "strict modes".  If the file is not found or is
rejected, no logins for an "auth users" module will be possible.
.IP "\fBstrict\ modes\fP"
This parameter determines whether or not the permissions on the secrets
file will be checked.  If "strict modes" is true, then the secrets file
must not be readable by any user ID other than the one that the rsync
daemon is running under.  If "strict modes" is false, the check is not
performed.  The default is true.  This parameter was added to accommodate
rsync running on the Windows operating system.
.IP "\fBhosts\ allow\fP"
This parameter allows you to specify a list of comma- and/or
whitespace-separated patterns that are matched against a connecting
client's hostname and IP address.  If none of the patterns match, then the
connection is rejected.
.IP
Each pattern can be in one of six forms:
.IP
.RS
.IP o
a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address of
the form a:b:c::d:e:f. In this case the incoming machine's IP address
must match exactly.
.IP o
an address/mask in the form ipaddr/n where ipaddr is the IP address and n
is the number of one bits in the netmask.  All IP addresses which match
the masked IP address will be allowed in.
.IP o
an address/mask in the form ipaddr/maskaddr where ipaddr is the IP
address and maskaddr is the netmask in dotted decimal notation for IPv4,
or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP
addresses which match the masked IP address will be allowed in.
.IP o
a hostname pattern using wildcards. If the hostname of the connecting IP
(as determined by a reverse lookup) matches the wildcarded name (using
the same rules as normal Unix filename matching), the client is allowed
in.  This only works if "reverse lookup" is enabled (the default).
.IP o
a hostname. A plain hostname is matched against the reverse DNS of the
connecting IP (if "reverse lookup" is enabled), and/or the IP of the
given hostname is matched against the connecting IP (if "forward lookup"
is enabled, as it is by default).  Any match will be allowed in.
.IP o
an '@' followed by a netgroup name, which will match if the reverse DNS
of the connecting IP is in the specified netgroup.
.RE
.IP
Note IPv6 link-local addresses can have a scope in the address
specification:
.RS 4
.IP
.nf
fe80::1%link1
fe80::%link1/64
fe80::%link1/ffff:ffff:ffff:ffff::
.fi
.RE
.IP
You can also combine "hosts allow" with "hosts deny" as a way to add
exceptions to your deny list.  When both parameters are specified, the
"hosts allow" parameter is checked first and a match results in the client
being able to connect.  A non-allowed host is then matched against the
"hosts deny" list to see if it should be rejected.  A host that does not
match either list is allowed to connect.
.IP
The default is no "hosts allow" parameter, which means all hosts can
connect.
.IP "\fBhosts\ deny\fP"
This parameter allows you to specify a list of comma- and/or
whitespace-separated patterns that are matched against a connecting clients
hostname and IP address. If the pattern matches then the connection is
rejected. See the "hosts allow" parameter for more information.
.IP
The default is no "hosts deny" parameter, which means all hosts can
connect.
.IP "\fBreverse\ lookup\fP"
Controls whether the daemon performs a reverse lookup on the client's IP
address to determine its hostname, which is used for "hosts allow" &
"hosts deny" checks and the "%h" log escape.  This is enabled by default,
but you may wish to disable it to save time if you know the lookup will not
return a useful result, in which case the daemon will use the name
"UNDETERMINED" instead.
.IP
If this parameter is enabled globally (even by default), rsync performs the
lookup as soon as a client connects, so disabling it for a module will not
avoid the lookup.  Thus, you probably want to disable it globally and then
enable it for modules that need the information.
.IP "\fBforward\ lookup\fP"
Controls whether the daemon performs a forward lookup on any hostname
specified in an hosts allow/deny setting.  By default this is enabled,
allowing the use of an explicit hostname that would not be returned by
reverse DNS of the connecting IP.
.IP "\fBignore\ errors\fP"
This parameter tells rsyncd to ignore I/O errors on the daemon when
deciding whether to run the delete phase of the transfer. Normally rsync
skips the \fB\-\-delete\fP step if any I/O errors have occurred in order to
prevent disastrous deletion due to a temporary resource shortage or other
I/O error. In some cases this test is counter productive so you can use
this parameter to turn off this behavior.
.IP "\fBignore\ nonreadable\fP"
This tells the rsync daemon to completely ignore files that are not
readable by the user. This is useful for public archives that may have some
non-readable files among the directories, and the sysadmin doesn't want
those files to be seen at all.
.IP "\fBtransfer\ logging\fP"
This parameter enables per-file logging of downloads and uploads in a
format somewhat similar to that used by ftp daemons.  The daemon always
logs the transfer at the end, so if a transfer is aborted, no mention will
be made in the log file.
.IP
If you want to customize the log lines, see the "log format" parameter.
.IP "\fBlog\ format\fP"
This parameter allows you to specify the format used for logging file
transfers when transfer logging is enabled.  The format is a text string
containing embedded single-character escape sequences prefixed with a
percent (%) character.  An optional numeric field width may also be
specified between the percent and the escape letter (e.g.
"\fB%\-50n\ %8l\ %07p\fP").  In addition, one or more apostrophes may be specified
prior to a numerical escape to indicate that the numerical value should be
made more human-readable.  The 3 supported levels are the same as for the
\fB\-\-human-readable\fP command-line option, though the default is for
human-readability to be off.  Each added apostrophe increases the level
(e.g. "\fB%''l\ %'b\ %f\fP").
.IP
The default log format is "\fB%o\ %h\ [%a]\ %m\ (%u)\ %f\ %l\fP", and a "\fB%t\ [%p]\ \fP"
is always prefixed when using the "log file" parameter.  (A perl script
that will summarize this default log format is included in the rsync source
code distribution in the "support" subdirectory: rsyncstats.)
.IP
The single-character escapes that are understood are as follows:
.IP
.RS
.IP o
%a the remote IP address (only available for a daemon)
.IP o
%b the number of bytes actually transferred
.IP o
%B the permission bits of the file (e.g. rwxrwxrwt)
.IP o
%c the total size of the block checksums received for the basis file
(only when sending)
.IP o
%C the full-file checksum if it is known for the file. For older rsync
protocols/versions, the checksum was salted, and is thus not a useful
value (and is not displayed when that is the case). For the checksum to
output for a file, either the \fB\-\-checksum\fP option must be in-effect or
the file must have been transferred without a salted checksum being used.
See the \fB\-\-checksum-choice\fP option for a way to choose the algorithm.
.IP o
%f the filename (long form on sender; no trailing "/")
.IP o
%G the gid of the file (decimal) or "DEFAULT"
.IP o
%h the remote host name (only available for a daemon)
.IP o
%i an itemized list of what is being updated
.IP o
%l the length of the file in bytes
.IP o
%L the string "\fB\ \->\ SYMLINK\fP", "\fB\ =>\ HARDLINK\fP", or "" (where \fBSYMLINK\fP
or \fBHARDLINK\fP is a filename)
.IP o
%m the module name
.IP o
%M the last-modified time of the file
.IP o
%n the filename (short form; trailing "/" on dir)
.IP o
%o the operation, which is "send", "recv", or "del." (the latter includes
the trailing period)
.IP o
%p the process ID of this rsync session
.IP o
%P the module path
.IP o
%t the current date time
.IP o
%u the authenticated username or an empty string
.IP o
%U the uid of the file (decimal)
.RE
.IP
For a list of what the characters mean that are output by "%i", see the
\fB\-\-itemize-changes\fP option in the rsync manpage.
.IP
Note that some of the logged output changes when talking with older rsync
versions.  For instance, deleted files were only output as verbose messages
prior to rsync 2.6.4.
.IP "\fBtimeout\fP"
This parameter allows you to override the clients choice for I/O timeout
for this module. Using this parameter you can ensure that rsync won't wait
on a dead client forever. The timeout is specified in seconds. A value of
zero means no timeout and is the default. A good choice for anonymous rsync
daemons may be 600 (giving a 10 minute timeout).
.IP "\fBrefuse\ options\fP"
This parameter allows you to specify a space-separated list of rsync
command-line options that will be refused by your rsync daemon.  You may
specify the full option name, its one-letter abbreviation, or a wild-card
string that matches multiple options. Beginning in 3.2.0, you can also
negate a match term by starting it with a "!".
.IP
When an option is refused, the daemon prints an error message and exits.
.IP
For example, this would refuse \fB\-\-checksum\fP (\fB\-c\fP) and all the various
delete options:
.RS 4
.IP
.nf
refuse options = c delete
.fi
.RE
.IP
The reason the above refuses all delete options is that the options imply
\fB\-\-delete\fP, and implied options are refused just like explicit options.
.IP
The use of a negated match allows you to fine-tune your refusals after a
wild-card, such as this:
.RS 4
.IP
.nf
refuse options = delete-* !delete-during
.fi
.RE
.IP
Negated matching can also turn your list of refused options into a list of
accepted options. To do this, begin the list with a "\fB*\fP" (to refuse all
options) and then specify one or more negated matches to accept.  For
example:
.RS 4
.IP
.nf
refuse options = * !a !v !compress*
.fi
.RE
.IP
Don't worry that the "\fB*\fP" will refuse certain vital options such as
\fB\-\-dry-run\fP, \fB\-\-server\fP, \fB\-\-no-iconv\fP, \fB\-\-seclude-args\fP, etc. These
important options are not matched by wild-card, so they must be overridden
by their exact name.  For instance, if you're forcing iconv transfers you
could use something like this:
.RS 4
.IP
.nf
refuse options = * no-iconv !a !v
.fi
.RE
.IP
As an additional aid (beginning in 3.2.0), refusing (or "\fB!refusing\fP") the
"a" or "archive"  option also affects all the options that the \fB\-\-archive\fP
option implies (\fB\-rdlptgoD\fP), but only if the option  is matched explicitly
(not using a wildcard). If you want to do something tricky, you can use
"\fBarchive*\fP" to avoid this side-effect, but keep in mind that no normal
rsync client ever sends the actual archive option to the server.
.IP
As an additional safety feature, the refusal of "delete" also refuses
\fBremove-source-files\fP when the daemon is the sender; if you want the latter
without the former, instead refuse "\fBdelete-*\fP" as that refuses all the
delete modes without affecting \fB\-\-remove-source-files\fP. (Keep in mind that
the client's \fB\-\-delete\fP option typically results in \fB\-\-delete-during\fP.)
.IP
When un-refusing delete options, you should either specify "\fB!delete*\fP" (to
accept all delete options) or specify a limited set that includes "delete",
such as:
.RS 4
.IP
.nf
refuse options = * !a !delete !delete-during
.fi
.RE
.IP
\&... whereas this accepts any delete option except \fB\-\-delete-after\fP:
.RS 4
.IP
.nf
refuse options = * !a !delete* delete-after
.fi
.RE
.IP
A note on refusing "compress": it may be better to set the "dont compress"
daemon parameter to "\fB*\fP" and ensure that \fBRSYNC_COMPRESS_LIST=zlib\fP is set
in the environment of the daemon in order to disable compression silently
instead of returning an error that forces the client to remove the \fB\-z\fP
option.
.IP
If you are un-refusing the compress option, you may want to match
"\fB!compress*\fP" if you also want to allow the \fB\-\-compress-level\fP option.
.IP
Note that the "copy-devices" & "write-devices" options are refused by
default, but they can be explicitly accepted with "\fB!copy-devices\fP" and/or
"\fB!write-devices\fP".  The options "log-file" and "log-file-format" are
forcibly refused and cannot be accepted.
.IP
Here are all the options that are not matched by wild-cards:
.IP
.RS
.IP o
\fB\-\-server\fP: Required for rsync to even work.
.IP o
\fB\-\-rsh\fP, \fB\-e\fP: Required to convey compatibility flags to the server.
.IP o
\fB\-\-out-format\fP: This is required to convey output behavior to a remote
receiver.  While rsync passes the older alias \fB\-\-log-format\fP for
compatibility reasons, this options should not be confused with
\fB\-\-log-file-format\fP.
.IP o
\fB\-\-sender\fP: Use "write only" parameter instead of refusing this.
.IP o
\fB\-\-dry-run\fP, \fB\-n\fP: Who would want to disable this?
.IP o
\fB\-\-seclude-args\fP, \fB\-s\fP: Is the oldest arg-protection method.
.IP o
\fB\-\-from0\fP, \fB\-0\fP: Makes it easier to accept/refuse \fB\-\-files-from\fP without
affecting this helpful modifier.
.IP o
\fB\-\-iconv\fP: This is auto-disabled based on "charset" parameter.
.IP o
\fB\-\-no-iconv\fP: Most transfers use this option.
.IP o
\fB\-\-checksum-seed\fP: Is a fairly rare, safe option.
.IP o
\fB\-\-write-devices\fP: Is non-wild but also auto-disabled.
.RE
.IP "\fBdont\ compress\fP"
\fBNOTE:\fP This parameter currently has no effect except in one instance: if
it is set to "\fB*\fP" then it minimizes or disables compression for all files
(for those that don't want to refuse the \fB\-\-compress\fP option completely).
.IP
This parameter allows you to select filenames based on wildcard patterns
that should not be compressed when pulling files from the daemon (no
analogous parameter exists to govern the pushing of files to a daemon).
Compression can be expensive in terms of CPU usage, so it is usually good
to not try to compress files that won't compress well, such as already
compressed files.
.IP
The "dont compress" parameter takes a space-separated list of
case-insensitive wildcard patterns. Any source filename matching one of the
patterns will be compressed as little as possible during the transfer.  If
the compression algorithm has an "off" level, then no compression occurs
for those files.  If an algorithms has the ability to change the level in
mid-stream, it will be minimized to reduce the CPU usage as much as
possible.
.IP
See the \fB\-\-skip-compress\fP parameter in the \fBrsync\fP(1) manpage for the
list of file suffixes that are skipped by default if this parameter is not
set.
.IP "\fBearly\ exec\fP, \fBpre-xfer\ exec\fP, \fBpost-xfer\ exec\fP"
You may specify a command to be run in the early stages of the connection,
or right before and/or after the transfer.  If the \fBearly\ exec\fP or
\fBpre-xfer\ exec\fP command returns an error code, the transfer is aborted
before it begins.  Any output from the \fBpre-xfer\ exec\fP command on stdout
(up to several KB) will be displayed to the user when aborting, but is
\fInot\fP displayed if the script returns success.  The other programs cannot
send any text to the user.  All output except for the \fBpre-xfer\ exec\fP
stdout goes to the corresponding daemon's stdout/stderr, which is typically
discarded.  See the \fB\-\-no-detatch\fP option for a way to see the daemon's
output, which can assist with debugging.
.IP
Note that the \fBearly\ exec\fP command runs before any part of the transfer
request is known except for the module name.  This helper script can be
used to setup a disk mount or decrypt some data into a module dir, but you
may need to use \fBlock\ file\fP and \fBmax\ connections\fP to avoid concurrency
issues.  If the client rsync specified the \fB\-\-early-input=FILE\fP option, it
can send up to about 5K of data to the stdin of the early script.  The
stdin will otherwise be empty.
.IP
Note that the \fBpost-xfer\ exec\fP command is still run even if one of the
other scripts returns an error code. The \fBpre-xfer\ exec\fP command will \fInot\fP
be run, however, if the \fBearly\ exec\fP command fails.
.IP
The following environment variables will be set, though some are specific
to the pre-xfer or the post-xfer environment:
.IP
.RS
.IP o
\fBRSYNC_MODULE_NAME\fP: The name of the module being accessed.
.IP o
\fBRSYNC_MODULE_PATH\fP: The path configured for the module.
.IP o
\fBRSYNC_HOST_ADDR\fP: The accessing host's IP address.
.IP o
\fBRSYNC_HOST_NAME\fP: The accessing host's name.
.IP o
\fBRSYNC_USER_NAME\fP: The accessing user's name (empty if no user).
.IP o
\fBRSYNC_PID\fP: A unique number for this transfer.
.IP o
\fBRSYNC_REQUEST\fP: (pre-xfer only) The module/path info specified by the
user.  Note that the user can specify multiple source files, so the
request can be something like "mod/path1 mod/path2", etc.
.IP o
\fBRSYNC_ARG#\fP: (pre-xfer only) The pre-request arguments are set in these
numbered values. RSYNC_ARG0 is always "rsyncd", followed by the options
that were used in RSYNC_ARG1, and so on.  There will be a value of "."
indicating that the options are done and the path args are beginning\ \-\-
these contain similar information to RSYNC_REQUEST, but with values
separated and the module name stripped off.
.IP o
\fBRSYNC_EXIT_STATUS\fP: (post-xfer only) the server side's exit value.  This
will be 0 for a successful run, a positive value for an error that the
server generated, or a \-1 if rsync failed to exit properly.  Note that an
error that occurs on the client side does not currently get sent to the
server side, so this is not the final exit status for the whole transfer.
.IP o
\fBRSYNC_RAW_STATUS\fP: (post-xfer only) the raw exit value from
\fBwaitpid()\fP.
.RE
.IP
Even though the commands can be associated with a particular module, they
are run using the permissions of the user that started the daemon (not the
module's uid/gid setting) without any chroot restrictions.
.IP
These settings honor 2 environment variables: use RSYNC_SHELL to set a
shell to use when running the command (which otherwise uses your
\fBsystem()\fP call's default shell), and use RSYNC_NO_XFER_EXEC to disable
both options completely.
.P
.SH "CONFIG DIRECTIVES"
.P
There are currently two config directives available that allow a config file to
incorporate the contents of other files:  \fB&include\fP and \fB&merge\fP.  Both allow
a reference to either a file or a directory.  They differ in how segregated the
file's contents are considered to be.
.P
The \fB&include\fP directive treats each file as more distinct, with each one
inheriting the defaults of the parent file, starting the parameter parsing as
globals/defaults, and leaving the defaults unchanged for the parsing of the
rest of the parent file.
.P
The \fB&merge\fP directive, on the other hand, treats the file's contents as if it
were simply inserted in place of the directive, and thus it can set parameters
in a module started in another file, can affect the defaults for other files,
etc.
.P
When an \fB&include\fP or \fB&merge\fP directive refers to a directory, it will read in
all the \fB*.conf\fP or \fB*.inc\fP files (respectively) that are contained inside that
directory (without any recursive scanning), with the files sorted into alpha
order.  So, if you have a directory named "rsyncd.d" with the files "foo.conf",
"bar.conf", and "baz.conf" inside it, this directive:
.RS 4
.P
.nf
&include /path/rsyncd.d
.fi
.RE
.P
would be the same as this set of directives:
.RS 4
.P
.nf
&include /path/rsyncd.d/bar.conf
&include /path/rsyncd.d/baz.conf
&include /path/rsyncd.d/foo.conf
.fi
.RE
.P
except that it adjusts as files are added and removed from the directory.
.P
The advantage of the \fB&include\fP directive is that you can define one or more
modules in a separate file without worrying about unintended side-effects
between the self-contained module files.
.P
The advantage of the \fB&merge\fP directive is that you can load config snippets
that can be included into multiple module definitions, and you can also set
global values that will affect connections (such as \fBmotd\ file\fP), or globals
that will affect other include files.
.P
For example, this is a useful /etc/rsyncd.conf file:
.RS 4
.P
.nf
port = 873
log file = /var/log/rsync.log
pid file = /var/lock/rsync.lock

&merge /etc/rsyncd.d
&include /etc/rsyncd.d
.fi
.RE
.P
This would merge any \fB/etc/rsyncd.d/*.inc\fP files (for global values that should
stay in effect), and then include any \fB/etc/rsyncd.d/*.conf\fP files (defining
modules without any global-value cross-talk).
.P
.SH "AUTHENTICATION STRENGTH"
.P
The authentication protocol used in rsync is a 128 bit MD4 based challenge
response system. This is fairly weak protection, though (with at least one
brute-force hash-finding algorithm publicly available), so if you want really
top-quality security, then I recommend that you run rsync over ssh.  (Yes, a
future version of rsync will switch over to a stronger hashing method.)
.P
Also note that the rsync daemon protocol does not currently provide any
encryption of the data that is transferred over the connection. Only
authentication is provided. Use ssh as the transport if you want encryption.
.P
You can also make use of SSL/TLS encryption if you put rsync behind an
SSL proxy.
.P
.SH "SSL/TLS Daemon Setup"
.P
When setting up an rsync daemon for access via SSL/TLS, you will need to
configure a TCP proxy (such as haproxy or nginx) as the front-end that handles
the encryption.
.P
.IP o
You should limit the access to the backend-rsyncd port to only allow the
proxy to connect.  If it is on the same host as the proxy, then configuring
it to only listen on localhost is a good idea.
.IP o
You should consider turning on the \fBproxy\ protocol\fP rsync-daemon parameter if
your proxy supports sending that information.  The examples below assume that
this is enabled.
.P
An example haproxy setup is as follows:
.RS 4
.P
.nf
frontend fe_rsync-ssl
   bind :::874 ssl crt /etc/letsencrypt/example.com/combined.pem
   mode tcp
   use_backend be_rsync

backend be_rsync
   mode tcp
   server local-rsync 127.0.0.1:873 check send-proxy
.fi
.RE
.P
An example nginx proxy setup is as follows:
.RS 4
.P
.nf
stream {
   server {
       listen 874 ssl;
       listen [::]:874 ssl;

       ssl_certificate /etc/letsencrypt/example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/example.com/privkey.pem;

       proxy_pass localhost:873;
       proxy_protocol on; # Requires rsyncd.conf "proxy protocol = true"
       proxy_timeout 1m;
       proxy_connect_timeout 5s;
   }
}
.fi
.RE
.P
.SH "DAEMON CONFIG EXAMPLES"
.P
A simple rsyncd.conf file that allow anonymous rsync to a ftp area at
\fB/home/ftp\fP would be:
.RS 4
.P
.nf
[ftp]
        path = /home/ftp
        comment = ftp export area
.fi
.RE
.P
A more sophisticated example would be:
.RS 4
.P
.nf
uid = nobody
gid = nobody
use chroot = yes
max connections = 4
syslog facility = local5
pid file = /var/run/rsyncd.pid

[ftp]
        path = /var/ftp/./pub
        comment = whole ftp area (approx 6.1 GB)

[sambaftp]
        path = /var/ftp/./pub/samba
        comment = Samba ftp area (approx 300 MB)

[rsyncftp]
        path = /var/ftp/./pub/rsync
        comment = rsync ftp area (approx 6 MB)

[sambawww]
        path = /public_html/samba
        comment = Samba WWW pages (approx 240 MB)

[cvs]
        path = /data/cvs
        comment = CVS repository (requires authentication)
        auth users = tridge, susan
        secrets file = /etc/rsyncd.secrets
.fi
.RE
.P
The /etc/rsyncd.secrets file would look something like this:
.RS 4
.P
.nf
tridge:mypass
susan:herpass
.fi
.RE
.P
.SH "FILES"
.P
/etc/rsyncd.conf or rsyncd.conf
.P
.SH "SEE ALSO"
.P
\fBrsync\fP(1), \fBrsync-ssl\fP(1)
.P
.SH "BUGS"
.P
Please report bugs! The rsync bug tracking system is online at
https://rsync.samba.org/.
.P
.SH "VERSION"
.P
This manpage is current for version 3.2.7 of rsync.
.P
.SH "CREDITS"
.P
Rsync is distributed under the GNU General Public License.  See the file
COPYING for details.
.P
An rsync web site is available at https://rsync.samba.org/ and its github
project is https://github.com/WayneD/rsync.
.P
.SH "THANKS"
.P
Thanks to Warren Stanley for his original idea and patch for the rsync daemon.
Thanks to Karsten Thygesen for his many suggestions and documentation!
.P
.SH "AUTHOR"
.P
Rsync was originally written by Andrew Tridgell and Paul Mackerras.  Many
people have later contributed to it. It is currently maintained by Wayne
Davison.
.P
Mailing lists for support and development are available at
https://lists.samba.org/.
rsync-3.2.7/rsync-ssl.10000664000000000000000000001141414324367163013412 0ustar  rootroot.TH "rsync-ssl" "1" "20 Oct 2022" "rsync-ssl from rsync 3.2.7" "User Commands"
.\" prefix=/usr
.P
.SH "NAME"
.P
rsync-ssl \- a helper script for connecting to an ssl rsync daemon
.P
.SH "SYNOPSIS"
.P
.nf
rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS
.fi
.P
The online version of this manpage (that includes cross-linking of topics)
is available at https://download.samba.org/pub/rsync/rsync-ssl.1.
.P
.SH "DESCRIPTION"
.P
The rsync-ssl script helps you to run an rsync copy to/from an rsync daemon
that requires ssl connections.
.P
The script requires that you specify an rsync-daemon arg in the style of either
\fBhostname::\fP (with 2 colons) or \fBrsync://hostname/\fP.  The default port used for
connecting is 874 (one higher than the normal 873) unless overridden in the
environment.  You can specify an overriding port via \fB\-\-port\fP or by including
it in the normal spot in the URL format, though both of those require your
rsync version to be at least 3.2.0.
.P
.SH "OPTIONS"
.P
If the \fBfirst\fP arg is a \fB\-\-type=SSL_TYPE\fP option, the script will only use
that particular program to open an ssl connection instead of trying to find an
openssl or stunnel executable via a simple heuristic (assuming that the
\fBRSYNC_SSL_TYPE\fP environment variable is not set as well\ \-\- see below).  This
option must specify one of \fBopenssl\fP or \fBstunnel\fP.  The equal sign is
required for this particular option.
.P
All the other options are passed through to the rsync command, so consult the
\fBrsync\fP(1) manpage for more information on how it works.
.P
.SH "ENVIRONMENT VARIABLES"
.P
The ssl helper scripts are affected by the following environment variables:
.P
.IP "\fBRSYNC_SSL_TYPE\fP"
Specifies the program type that should be used to open the ssl connection.
It must be one of \fBopenssl\fP or \fBstunnel\fP.  The \fB\-\-type=SSL_TYPE\fP option
overrides this, when specified.
.IP "\fBRSYNC_SSL_PORT\fP"
If specified, the value is the port number that is used as the default when
the user does not specify a port in their rsync command.  When not
specified, the default port number is 874.  (Note that older rsync versions
(prior to 3.2.0) did not communicate an overriding port number value to the
helper script.)
.IP "\fBRSYNC_SSL_CERT\fP"
If specified, the value is a filename that contains a certificate to use
for the connection.
.IP "\fBRSYNC_SSL_KEY\fP"
If specified, the value is a filename that contains a key for the provided
certificate to use for the connection.
.IP "\fBRSYNC_SSL_CA_CERT\fP"
If specified, the value is a filename that contains a certificate authority
certificate that is used to validate the connection.
.IP "\fBRSYNC_SSL_OPENSSL\fP"
Specifies the openssl executable to run when the connection type is set to
openssl.  If unspecified, the $PATH is searched for "openssl".
.IP "\fBRSYNC_SSL_GNUTLS\fP"
Specifies the gnutls-cli executable to run when the connection type is set
to gnutls.  If unspecified, the $PATH is searched for "gnutls-cli".
.IP "\fBRSYNC_SSL_STUNNEL\fP"
Specifies the stunnel executable to run when the connection type is set to
stunnel.  If unspecified, the $PATH is searched first for "stunnel4" and
then for "stunnel".
.P
.SH "EXAMPLES"
.RS 4
.P
.nf
rsync-ssl -aiv example.com::mod/ dest
.fi
.RE
.RS 4
.P
.nf
rsync-ssl --type=openssl -aiv example.com::mod/ dest
.fi
.RE
.RS 4
.P
.nf
rsync-ssl -aiv --port 9874 example.com::mod/ dest
.fi
.RE
.RS 4
.P
.nf
rsync-ssl -aiv rsync://example.com:9874/mod/ dest
.fi
.RE
.P
.SH "THE SERVER SIDE"
.P
For help setting up an SSL/TLS supporting rsync, see the instructions in
rsyncd.conf.
.P
.SH "SEE ALSO"
.P
\fBrsync\fP(1), \fBrsyncd.conf\fP(5)
.P
.SH "CAVEATS"
.P
Note that using an stunnel connection requires at least version 4 of stunnel,
which should be the case on modern systems.  Also, it does not verify a
connection against the CA certificate collection, so it only encrypts the
connection without any cert validation unless you have specified the
certificate environment options.
.P
This script also supports a \fB\-\-type=gnutls\fP option, but at the time of this
release the gnutls-cli command was dropping output, making it unusable.  If
that bug has been fixed in your version, feel free to put gnutls into an
exported RSYNC_SSL_TYPE environment variable to make its use the default.
.P
.SH "BUGS"
.P
Please report bugs! See the web site at https://rsync.samba.org/.
.P
.SH "VERSION"
.P
This manpage is current for version 3.2.7 of rsync.
.P
.SH "CREDITS"
.P
Rsync is distributed under the GNU General Public License.  See the file
COPYING for details.
.P
A web site is available at https://rsync.samba.org/.  The site includes an
FAQ-O-Matic which may cover questions unanswered by this manual page.
.P
.SH "AUTHOR"
.P
This manpage was written by Wayne Davison.
.P
Mailing lists for support and development are available at
https://lists.samba.org/.
rsync-3.2.7/version.h0000664000000000000000000000010014324367162013216 0ustar  rootroot#define RSYNC_VERSION "3.2.7"
#define MAINTAINER_TZ_OFFSET -7.0
rsync-3.2.7/xattrs.c0000664000000000000000000010014114310264745013055 0ustar  rootroot/*
 * Extended Attribute support for rsync.
 * Written by Jay Fenlason, vaguely based on the ACLs patch.
 *
 * Copyright (C) 2004 Red Hat, Inc.
 * Copyright (C) 2006-2022 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"
#include "inums.h"
#include "lib/sysxattrs.h"

#ifdef SUPPORT_XATTRS

extern int dry_run;
extern int am_root;
extern int am_sender;
extern int am_generator;
extern int read_only;
extern int list_only;
extern int preserve_xattrs;
extern int preserve_links;
extern int preserve_devices;
extern int preserve_specials;
extern int checksum_seed;
extern int saw_xattr_filter;

extern struct name_num_item *xattr_sum_nni;
extern int xattr_sum_len;

#define RSYNC_XAL_INITIAL 5
#define RSYNC_XAL_LIST_INITIAL 100

#define MAX_XATTR_DIGEST_LEN MD5_DIGEST_LEN
#define MAX_FULL_DATUM 32

#define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0)

#define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len)

#define XSTATE_ABBREV	1
#define XSTATE_DONE	2
#define XSTATE_TODO	3

#define USER_PREFIX "user."
#define UPRE_LEN ((int)sizeof USER_PREFIX - 1)
#define SYSTEM_PREFIX "system."
#define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)

#ifdef HAVE_LINUX_XATTRS
#define MIGHT_NEED_RPRE (am_root <= 0)
#define RSYNC_PREFIX USER_PREFIX "rsync."
#else
#define MIGHT_NEED_RPRE am_root
#define RSYNC_PREFIX "rsync."
#endif
#define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)

#define XSTAT_SUFFIX "stat"
#define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
#define XACC_ACL_SUFFIX "aacl"
#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
#define XDEF_ACL_SUFFIX "dacl"
#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX

typedef struct {
	char *datum, *name;
	size_t datum_len, name_len;
	int num;
} rsync_xa;

struct _rsync_xa_list;

typedef struct _rsync_xa_list_ref {
	struct _rsync_xa_list_ref *next;
	int ndx;
} rsync_xa_list_ref;

typedef struct _rsync_xa_list {
	int ndx;
	int64 key;
	item_list xa_items;
} rsync_xa_list;

static size_t namebuf_len = 0;
static char *namebuf = NULL;

static const rsync_xa_list empty_xa_list = {
	.xa_items = EMPTY_ITEM_LIST,
};
static const item_list empty_xattr = EMPTY_ITEM_LIST;
static item_list rsync_xal_l = EMPTY_ITEM_LIST;
static struct hashtable *rsync_xal_h = NULL;

static size_t prior_xattr_count = (size_t)-1;

/* ------------------------------------------------------------------------- */

static void rsync_xal_free(item_list *xalp)
{
	size_t i;
	rsync_xa *rxas = xalp->items;

	if (!xalp->malloced)
		return;

	for (i = 0; i < xalp->count; i++) {
		free(rxas[i].datum);
		/*free(rxas[i].name);*/
	}
	free(xalp->items);
}

void free_xattr(stat_x *sxp)
{
	if (!sxp->xattr)
		return;
	rsync_xal_free(sxp->xattr);
	free(sxp->xattr);
	sxp->xattr = NULL;
}

static int rsync_xal_compare_names(const void *x1, const void *x2)
{
	const rsync_xa *xa1 = x1;
	const rsync_xa *xa2 = x2;
	return strcmp(xa1->name, xa2->name);
}

static ssize_t get_xattr_names(const char *fname)
{
	ssize_t list_len;
	int64 arg;

	if (!namebuf) {
		namebuf_len = 1024;
		namebuf = new_array(char, namebuf_len);
	}

	while (1) {
		/* The length returned includes all the '\0' terminators. */
		list_len = sys_llistxattr(fname, namebuf, namebuf_len);
		if (list_len >= 0) {
			if ((size_t)list_len <= namebuf_len)
				break;
		} else if (errno == ENOTSUP)
			return 0;
		else if (errno != ERANGE) {
			arg = namebuf_len;
		  got_error:
			rsyserr(FERROR_XFER, errno,
				"get_xattr_names: llistxattr(%s,%s) failed",
				full_fname(fname), big_num(arg));
			return -1;
		}
		list_len = sys_llistxattr(fname, NULL, 0);
		if (list_len < 0) {
			arg = 0;
			goto got_error;
		}
		if (namebuf_len)
			free(namebuf);
		namebuf_len = list_len + 1024;
		namebuf = new_array(char, namebuf_len);
	}

	return list_len;
}

/* On entry, the *len_ptr parameter contains the size of the extra space we
 * should allocate when we create a buffer for the data.  On exit, it contains
 * the length of the datum. */
static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr, int no_missing_error)
{
	size_t datum_len = sys_lgetxattr(fname, name, NULL, 0);
	size_t extra_len = *len_ptr;
	char *ptr;

	*len_ptr = datum_len;

	if (datum_len == (size_t)-1) {
		if (errno == ENOTSUP || no_missing_error)
			return NULL;
		rsyserr(FERROR_XFER, errno,
			"get_xattr_data: lgetxattr(%s,\"%s\",0) failed",
			full_fname(fname), name);
		return NULL;
	}

	if (!datum_len && !extra_len)
		extra_len = 1; /* request non-zero amount of memory */
	if (SIZE_MAX - datum_len < extra_len)
		overflow_exit("get_xattr_data");
	ptr = new_array(char, datum_len + extra_len);

	if (datum_len) {
		size_t len = sys_lgetxattr(fname, name, ptr, datum_len);
		if (len != datum_len) {
			if (len == (size_t)-1) {
				rsyserr(FERROR_XFER, errno,
					"get_xattr_data: lgetxattr(%s,\"%s\",%ld) failed",
					full_fname(fname), name, (long)datum_len);
			} else {
				rprintf(FERROR_XFER,
					"get_xattr_data: lgetxattr(%s,\"%s\",%ld) returned %ld\n",
					full_fname(fname), name,
					(long)datum_len, (long)len);
			}
			free(ptr);
			return NULL;
		}
	}

	return ptr;
}

static int rsync_xal_get(const char *fname, item_list *xalp)
{
	ssize_t list_len, name_len;
	size_t datum_len, name_offset;
	char *name, *ptr;
#ifdef HAVE_LINUX_XATTRS
	int user_only = am_sender ? 0 : !am_root;
#endif
	rsync_xa *rxa;
	int count;

	/* This puts the name list into the "namebuf" buffer. */
	if ((list_len = get_xattr_names(fname)) < 0)
		return -1;

	for (name = namebuf; list_len > 0; name += name_len) {
		name_len = strlen(name) + 1;
		list_len -= name_len;

		if (saw_xattr_filter) {
			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
				continue;
		}
#ifdef HAVE_LINUX_XATTRS
		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
			continue;
#endif

		/* No rsync.%FOO attributes are copied w/o 2 -X options. */
		if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
			if ((am_sender && preserve_xattrs < 2)
			 || (am_root < 0
			  && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
			   || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
			   || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0)))
				continue;
		}

		datum_len = name_len; /* Pass extra size to get_xattr_data() */
		if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
			return -1;

		if (datum_len > MAX_FULL_DATUM) {
			/* For large datums, we store a flag and a checksum. */
			name_offset = 1 + MAX_XATTR_DIGEST_LEN;
			sum_init(xattr_sum_nni, checksum_seed);
			sum_update(ptr, datum_len);
			free(ptr);

			ptr = new_array(char, name_offset + name_len);
			*ptr = XSTATE_ABBREV;
			sum_end(ptr + 1);
		} else
			name_offset = datum_len;

		rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
		rxa->name = ptr + name_offset;
		memcpy(rxa->name, name, name_len);
		rxa->datum = ptr;
		rxa->name_len = name_len;
		rxa->datum_len = datum_len;
	}
	count = xalp->count;
	rxa = xalp->items;
	if (count > 1)
		qsort(rxa, count, sizeof (rsync_xa), rsync_xal_compare_names);
	for (rxa += count-1; count; count--, rxa--)
		rxa->num = count;
	return 0;
}

/* Read the xattr(s) for this filename. */
int get_xattr(const char *fname, stat_x *sxp)
{
	sxp->xattr = new(item_list);
	*sxp->xattr = empty_xattr;

	if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
		/* Everyone supports this. */
	} else if (S_ISLNK(sxp->st.st_mode)) {
#ifndef NO_SYMLINK_XATTRS
		if (!preserve_links)
#endif
			return 0;
	} else if (IS_SPECIAL(sxp->st.st_mode)) {
#ifndef NO_SPECIAL_XATTRS
		if (!preserve_specials)
#endif
			return 0;
	} else if (IS_DEVICE(sxp->st.st_mode)) {
#ifndef NO_DEVICE_XATTRS
		if (!preserve_devices)
#endif
			return 0;
	} else if (IS_MISSING_FILE(sxp->st))
		return 0;

	if (rsync_xal_get(fname, sxp->xattr) < 0) {
		free_xattr(sxp);
		return -1;
	}
	return 0;
}

int copy_xattrs(const char *source, const char *dest)
{
	ssize_t list_len, name_len;
	size_t datum_len;
	char *name, *ptr;
#ifdef HAVE_LINUX_XATTRS
	int user_only = am_sender ? 0 : am_root <= 0;
#endif

	/* This puts the name list into the "namebuf" buffer. */
	if ((list_len = get_xattr_names(source)) < 0)
		return -1;

	for (name = namebuf; list_len > 0; name += name_len) {
		name_len = strlen(name) + 1;
		list_len -= name_len;

		if (saw_xattr_filter) {
			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
				continue;
		}
#ifdef HAVE_LINUX_XATTRS
		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
			continue;
#endif

		datum_len = 0;
		if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
			return -1;
		if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
			int save_errno = errno ? errno : EINVAL;
			rsyserr(FERROR_XFER, errno,
				"copy_xattrs: lsetxattr(%s,\"%s\") failed",
				full_fname(dest), name);
			errno = save_errno;
			return -1;
		}
		free(ptr);
	}

	return 0;
}

static int64 xattr_lookup_hash(const item_list *xalp)
{
	const rsync_xa *rxas = xalp->items;
	size_t i;
	int64 key = hashlittle2(&xalp->count, sizeof xalp->count);

	for (i = 0; i < xalp->count; i++) {
		key += hashlittle2(rxas[i].name, rxas[i].name_len);
		if (rxas[i].datum_len > MAX_FULL_DATUM)
			key += hashlittle2(rxas[i].datum, xattr_sum_len);
		else
			key += hashlittle2(rxas[i].datum, rxas[i].datum_len);
	}

	return key;
}

static int find_matching_xattr(const item_list *xalp)
{
	const struct ht_int64_node *node;
	const rsync_xa_list_ref *ref;
	int64 key;

	if (rsync_xal_h == NULL)
		return -1;

	key = xattr_lookup_hash(xalp);

	node = hashtable_find(rsync_xal_h, key, NULL);
	if (node == NULL)
		return -1;

	if (node->data == NULL)
		return -1;

	for (ref = node->data; ref != NULL; ref = ref->next) {
		const rsync_xa_list *ptr = rsync_xal_l.items;
		const rsync_xa *rxas1;
		const rsync_xa *rxas2 = xalp->items;
		size_t j;

		ptr += ref->ndx;
		rxas1 = ptr->xa_items.items;

		/* Wrong number of elements? */
		if (ptr->xa_items.count != xalp->count)
			continue;
		/* any elements different? */
		for (j = 0; j < xalp->count; j++) {
			if (rxas1[j].name_len != rxas2[j].name_len
			 || rxas1[j].datum_len != rxas2[j].datum_len
			 || strcmp(rxas1[j].name, rxas2[j].name))
				break;
			if (rxas1[j].datum_len > MAX_FULL_DATUM) {
				if (memcmp(rxas1[j].datum + 1,
					   rxas2[j].datum + 1,
					   xattr_sum_len) != 0)
					break;
			} else {
				if (memcmp(rxas1[j].datum, rxas2[j].datum,
					   rxas2[j].datum_len))
					break;
			}
		}
		/* no differences found.  This is The One! */
		if (j == xalp->count)
			return ref->ndx;
	}

	return -1;
}

/* Store *xalp on the end of rsync_xal_l */
static int rsync_xal_store(item_list *xalp)
{
	struct ht_int64_node *node;
	int ndx = rsync_xal_l.count; /* pre-incremented count */
	rsync_xa_list *new_list = EXPAND_ITEM_LIST(&rsync_xal_l, rsync_xa_list, RSYNC_XAL_LIST_INITIAL);
	rsync_xa_list_ref *new_ref;
	/* Since the following call starts a new list, we know it will hold the
	 * entire initial-count, not just enough space for one new item. */
	*new_list = empty_xa_list;
	(void)EXPAND_ITEM_LIST(&new_list->xa_items, rsync_xa, xalp->count);
	memcpy(new_list->xa_items.items, xalp->items, xalp->count * sizeof (rsync_xa));
	new_list->xa_items.count = xalp->count;
	xalp->count = 0;

	new_list->ndx = ndx;
	new_list->key = xattr_lookup_hash(&new_list->xa_items);

	if (rsync_xal_h == NULL)
		rsync_xal_h = hashtable_create(512, HT_KEY64);

	new_ref = new0(rsync_xa_list_ref);
	new_ref->ndx = ndx;

	node = hashtable_find(rsync_xal_h, new_list->key, new_ref);
	if (node->data != (void*)new_ref) {
		rsync_xa_list_ref *ref = node->data;

		while (ref != NULL) {
			if (ref->next != NULL) {
				ref = ref->next;
				continue;
			}

			ref->next = new_ref;
			break;
		}
	}

	return ndx;
}

/* Send the make_xattr()-generated xattr list for this flist entry. */
int send_xattr(int f, stat_x *sxp)
{
	int ndx = find_matching_xattr(sxp->xattr);

	/* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
	write_varint(f, ndx + 1);

	if (ndx < 0) {
		rsync_xa *rxa;
		int count = sxp->xattr->count;
		write_varint(f, count);
		for (rxa = sxp->xattr->items; count--; rxa++) {
			size_t name_len = rxa->name_len;
			const char *name = rxa->name;
			/* Strip the rsync prefix from disguised namespaces. */
			if (name_len > RPRE_LEN
#ifdef HAVE_LINUX_XATTRS
			 && am_root < 0
#endif
			 && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
				name += RPRE_LEN;
				name_len -= RPRE_LEN;
			}
#ifndef HAVE_LINUX_XATTRS
			else {
				/* Put everything else in the user namespace. */
				name_len += UPRE_LEN;
			}
#endif
			write_varint(f, name_len);
			write_varint(f, rxa->datum_len);
#ifndef HAVE_LINUX_XATTRS
			if (name_len > rxa->name_len) {
				write_buf(f, USER_PREFIX, UPRE_LEN);
				name_len -= UPRE_LEN;
			}
#endif
			write_buf(f, name, name_len);
			if (rxa->datum_len > MAX_FULL_DATUM)
				write_buf(f, rxa->datum + 1, xattr_sum_len);
			else
				write_bigbuf(f, rxa->datum, rxa->datum_len);
		}
		ndx = rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
	}

	return ndx;
}

/* Return a flag indicating if we need to change a file's xattrs.  If
 * "find_all" is specified, also mark any abbreviated xattrs that we
 * need so that send_xattr_request() can tell the sender about them. */
int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
{
	const rsync_xa_list *glst = rsync_xal_l.items;
	const item_list *lst;
	rsync_xa *snd_rxa, *rec_rxa;
	int snd_cnt, rec_cnt;
	int cmp, same, xattrs_equal = 1;

	if (sxp && XATTR_READY(*sxp)) {
		rec_rxa = sxp->xattr->items;
		rec_cnt = sxp->xattr->count;
	} else {
		rec_rxa = NULL;
		rec_cnt = 0;
	}

	if (F_XATTR(file) >= 0) {
		glst += F_XATTR(file);
		lst = &glst->xa_items;
	} else
		lst = &empty_xattr;

	snd_rxa = lst->items;
	snd_cnt = lst->count;

	/* If the count of the sender's xattrs is different from our
	 * (receiver's) xattrs, the lists are not the same. */
	if (snd_cnt != rec_cnt) {
		if (!find_all)
			return 1;
		xattrs_equal = 0;
	}

	while (snd_cnt) {
		cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
		if (cmp > 0)
			same = 0;
		else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
			same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
			    && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
				      xattr_sum_len) == 0;
			/* Flag unrequested items that we need. */
			if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
				snd_rxa->datum[0] = XSTATE_TODO;
		} else {
			same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
			    && memcmp(snd_rxa->datum, rec_rxa->datum,
				      snd_rxa->datum_len) == 0;
		}
		if (!same) {
			if (!find_all)
				return 1;
			xattrs_equal = 0;
		}

		if (cmp <= 0) {
			snd_rxa++;
			snd_cnt--;
		}
		if (cmp >= 0) {
			rec_rxa++;
			rec_cnt--;
		}
	}

	if (rec_cnt)
		xattrs_equal = 0;

	return !xattrs_equal;
}

/* When called by the generator (with a NULL fname), this tells the sender
 * all the abbreviated xattr values we need.  When called by the sender
 * (with a non-NULL fname), we send all the extra xattr data it needs.
 * The generator may also call with f_out < 0 to just change all the
 * XSTATE_ABBREV states into XSTATE_DONE. */
void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
{
	const rsync_xa_list *glst = rsync_xal_l.items;
	const item_list *lst;
	int cnt, prior_req = 0;
	rsync_xa *rxa;

	glst += F_XATTR(file);
	lst = &glst->xa_items;

	for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
		if (rxa->datum_len <= MAX_FULL_DATUM)
			continue;
		switch (rxa->datum[0]) {
		case XSTATE_ABBREV:
			/* Items left abbreviated matched the sender's checksum, so
			 * the receiver will cache the local data for future use. */
			if (am_generator)
				rxa->datum[0] = XSTATE_DONE;
			continue;
		case XSTATE_TODO:
			assert(f_out >= 0);
			break;
		default:
			continue;
		}

		/* Flag that we handled this abbreviated item. */
		rxa->datum[0] = XSTATE_DONE;

		write_varint(f_out, rxa->num - prior_req);
		prior_req = rxa->num;

		if (fname) {
			size_t len = 0;
			char *ptr;

			/* Re-read the long datum. */
			if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) {
				rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname);
				write_varint(f_out, 0);
				continue;
			}

			write_varint(f_out, len); /* length might have changed! */
			write_bigbuf(f_out, ptr, len);
			free(ptr);
		}
	}

	if (f_out >= 0)
		write_byte(f_out, 0); /* end the list */
}

/* When called by the sender, read the request from the generator and mark
 * any needed xattrs with a flag that lets us know they need to be sent to
 * the receiver.  When called by the receiver, reads the sent data and
 * stores it in place of its checksum. */
int recv_xattr_request(struct file_struct *file, int f_in)
{
	const rsync_xa_list *glst = rsync_xal_l.items;
	const item_list *lst;
	char *old_datum, *name;
	rsync_xa *rxa;
	int rel_pos, cnt, num, got_xattr_data = 0;

	if (F_XATTR(file) < 0) {
		rprintf(FERROR, "recv_xattr_request: internal data error!\n");
		exit_cleanup(RERR_PROTOCOL);
	}
	glst += F_XATTR(file);
	lst = &glst->xa_items;

	cnt = lst->count;
	rxa = lst->items;
	num = 0;
	while ((rel_pos = read_varint(f_in)) != 0) {
		num += rel_pos;
		if (am_sender) {
			/* The sender-related num values are only in order on the sender.
			 * We use that order here to scan forward or backward as needed. */
			if (rel_pos < 0) {
				while (cnt < (int)lst->count && rxa->num > num) {
					rxa--;
					cnt++;
				}
			} else {
				while (cnt > 1 && rxa->num < num) {
					rxa++;
					cnt--;
				}
			}
		} else {
			int j;
			/* The receiving side has no known num order, so we just scan
			 * forward (w/wrap) and hope that the next value is near by. */
			for (j = lst->count; j > 1 && rxa->num != num; j--) {
				if (--cnt)
					rxa++;
				else {
					cnt = lst->count;
					rxa = lst->items;
				}
			}
		}
		if (!cnt || rxa->num != num) {
			rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
				who_am_i(), num, f_name(file, NULL));
			exit_cleanup(RERR_PROTOCOL);
		}
		if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
			rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
				who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
			exit_cleanup(RERR_PROTOCOL);
		}

		if (am_sender) {
			rxa->datum[0] = XSTATE_TODO;
			continue;
		}

		old_datum = rxa->datum;
		rxa->datum_len = read_varint(f_in);

		if (SIZE_MAX - rxa->name_len < rxa->datum_len)
			overflow_exit("recv_xattr_request");
		rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
		name = rxa->datum + rxa->datum_len;
		memcpy(name, rxa->name, rxa->name_len);
		rxa->name = name;
		free(old_datum);
		read_buf(f_in, rxa->datum, rxa->datum_len);
		got_xattr_data = 1;
	}

	return got_xattr_data;
}

/* ------------------------------------------------------------------------- */

/* receive and build the rsync_xattr_lists */
void receive_xattr(int f, struct file_struct *file)
{
	static item_list temp_xattr = EMPTY_ITEM_LIST;
	int count, num;
#ifdef HAVE_LINUX_XATTRS
	int need_sort = 0;
#else
	int need_sort = 1;
#endif
	int ndx = read_varint(f);

	if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
		rprintf(FERROR, "receive_xattr: xa index %d out of"
			" range for %s\n", ndx, f_name(file, NULL));
		exit_cleanup(RERR_STREAMIO);
	}

	if (ndx != 0) {
		F_XATTR(file) = ndx - 1;
		return;
	}

	if ((count = read_varint(f)) != 0) {
		(void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
		temp_xattr.count = 0;
	}

	for (num = 1; num <= count; num++) {
		char *ptr, *name;
		rsync_xa *rxa;
		size_t name_len = read_varint(f);
		size_t datum_len = read_varint(f);
		size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + (size_t)xattr_sum_len : datum_len;
		size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
		if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
			overflow_exit("receive_xattr");
		ptr = new_array(char, dget_len + extra_len + name_len);
		name = ptr + dget_len + extra_len;
		read_buf(f, name, name_len);
		if (name_len < 1 || name[name_len-1] != '\0') {
			rprintf(FERROR, "Invalid xattr name received (missing trailing \\0).\n");
			exit_cleanup(RERR_FILEIO);
		}
		if (dget_len == datum_len)
			read_buf(f, ptr, dget_len);
		else {
			*ptr = XSTATE_ABBREV;
			read_buf(f, ptr + 1, xattr_sum_len);
		}

		if (saw_xattr_filter) {
			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) {
				free(ptr);
				continue;
			}
		}
#ifdef HAVE_LINUX_XATTRS
		/* Non-root can only save the user namespace. */
		if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
			if (!am_root && !saw_xattr_filter) {
				free(ptr);
				continue;
			}
			name -= RPRE_LEN;
			name_len += RPRE_LEN;
			memcpy(name, RSYNC_PREFIX, RPRE_LEN);
			need_sort = 1;
		}
#else
		/* This OS only has a user namespace, so we either
		 * strip the user prefix, or we put a non-user
		 * namespace inside our rsync hierarchy. */
		if (HAS_PREFIX(name, USER_PREFIX)) {
			name += UPRE_LEN;
			name_len -= UPRE_LEN;
		} else if (am_root) {
			name -= RPRE_LEN;
			name_len += RPRE_LEN;
			memcpy(name, RSYNC_PREFIX, RPRE_LEN);
		} else {
			free(ptr);
			continue;
		}
#endif
		/* No rsync.%FOO attributes are copied w/o 2 -X options. */
		if (preserve_xattrs < 2 && name_len > RPRE_LEN
		 && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
			free(ptr);
			continue;
		}

		rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
		rxa->name = name;
		rxa->datum = ptr;
		rxa->name_len = name_len;
		rxa->datum_len = datum_len;
		rxa->num = num;
	}

	if (need_sort && count > 1)
		qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);

	ndx = rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */

	F_XATTR(file) = ndx;
}

/* Turn the xattr data in stat_x into cached xattr data, setting the index
 * values in the file struct. */
void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
{
	int ndx;

	if (!sxp->xattr)
		return;

	if (prior_xattr_count == (size_t)-1)
		prior_xattr_count = rsync_xal_l.count;
	ndx = find_matching_xattr(sxp->xattr);
	if (ndx < 0)
		rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */

	F_XATTR(file) = ndx;
}

void uncache_tmp_xattrs(void)
{
	if (prior_xattr_count != (size_t)-1) {
		rsync_xa_list *xa_list_item = rsync_xal_l.items;
		rsync_xa_list *xa_list_start = xa_list_item + prior_xattr_count;
		xa_list_item += rsync_xal_l.count;
		rsync_xal_l.count = prior_xattr_count;
		while (xa_list_item-- > xa_list_start) {
			struct ht_int64_node *node;
			rsync_xa_list_ref *ref;

			rsync_xal_free(&xa_list_item->xa_items);

			if (rsync_xal_h == NULL)
				continue;

			node = hashtable_find(rsync_xal_h, xa_list_item->key, NULL);
			if (node == NULL)
				continue;

			if (node->data == NULL)
				continue;

			ref = node->data;
			if (xa_list_item->ndx == ref->ndx) {
				/* xa_list_item is the first in the list. */
				node->data = ref->next;
				free(ref);
				continue;
			}

			while (1) {
				rsync_xa_list_ref *next = ref->next;
				if (next == NULL)
					break;
				if (xa_list_item->ndx == next->ndx) {
					ref->next = next->next;
					free(next);
					break;
				}
				ref = next;
			}
		}
		prior_xattr_count = (size_t)-1;
	}
}

static int rsync_xal_set(const char *fname, item_list *xalp,
			 const char *fnamecmp, stat_x *sxp)
{
	rsync_xa *rxas = xalp->items;
	ssize_t list_len;
	size_t i, len;
	char *name, *ptr, sum[MAX_XATTR_DIGEST_LEN];
#ifdef HAVE_LINUX_XATTRS
	int user_only = am_root <= 0;
#endif
	size_t name_len;
	int ret = 0;

	/* This puts the current name list into the "namebuf" buffer. */
	if ((list_len = get_xattr_names(fname)) < 0)
		return -1;

	for (i = 0; i < xalp->count; i++) {
		name = rxas[i].name;

		if (XATTR_ABBREV(rxas[i])) {
			/* See if the fnamecmp version is identical. */
			len = name_len = rxas[i].name_len;
			if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) {
			  still_abbrev:
				if (am_generator)
					continue;
				rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
					rxas[i].name, full_fname(fname));
				ret = -1;
				continue;
			}
			if (len != rxas[i].datum_len) {
				free(ptr);
				goto still_abbrev;
			}

			sum_init(xattr_sum_nni, checksum_seed);
			sum_update(ptr, len);
			sum_end(sum);
			if (memcmp(sum, rxas[i].datum + 1, xattr_sum_len) != 0) {
				free(ptr);
				goto still_abbrev;
			}

			if (fname == fnamecmp)
				; /* Value is already set when identical */
			else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
				rsyserr(FERROR_XFER, errno,
					"rsync_xal_set: lsetxattr(%s,\"%s\") failed",
					full_fname(fname), name);
				ret = -1;
			} else /* make sure caller sets mtime */
				sxp->st.st_mtime = (time_t)-1;

			if (am_generator) { /* generator items stay abbreviated */
				free(ptr);
				continue;
			}

			memcpy(ptr + len, name, name_len);
			free(rxas[i].datum);

			rxas[i].name = name = ptr + len;
			rxas[i].datum = ptr;
			continue;
		}

		if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
			rsyserr(FERROR_XFER, errno,
				"rsync_xal_set: lsetxattr(%s,\"%s\") failed",
				full_fname(fname), name);
			ret = -1;
		} else /* make sure caller sets mtime */
			sxp->st.st_mtime = (time_t)-1;
	}

	/* Remove any extraneous names. */
	for (name = namebuf; list_len > 0; name += name_len) {
		name_len = strlen(name) + 1;
		list_len -= name_len;

		if (saw_xattr_filter) {
			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
				continue;
		}
#ifdef HAVE_LINUX_XATTRS
		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
			continue;
#endif
		if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
			continue;

		for (i = 0; i < xalp->count; i++) {
			if (strcmp(name, rxas[i].name) == 0)
				break;
		}
		if (i == xalp->count) {
			if (sys_lremovexattr(fname, name) < 0) {
				rsyserr(FERROR_XFER, errno,
					"rsync_xal_set: lremovexattr(%s,\"%s\") failed",
					full_fname(fname), name);
				ret = -1;
			} else /* make sure caller sets mtime */
				sxp->st.st_mtime = (time_t)-1;
		}
	}

	return ret;
}

/* Set extended attributes on indicated filename. */
int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp, stat_x *sxp)
{
	rsync_xa_list *glst = rsync_xal_l.items;
	item_list *lst;
	int ndx, added_write_perm = 0;

	if (dry_run)
		return 1; /* FIXME: --dry-run needs to compute this value */

	if (read_only || list_only) {
		errno = EROFS;
		return -1;
	}

#ifdef NO_SPECIAL_XATTRS
	if (IS_SPECIAL(sxp->st.st_mode)) {
		errno = ENOTSUP;
		return -1;
	}
#endif
#ifdef NO_DEVICE_XATTRS
	if (IS_DEVICE(sxp->st.st_mode)) {
		errno = ENOTSUP;
		return -1;
	}
#endif
#ifdef NO_SYMLINK_XATTRS
	if (S_ISLNK(sxp->st.st_mode)) {
		errno = ENOTSUP;
		return -1;
	}
#endif

	/* If the target file lacks write permission, we try to add it
	 * temporarily so we can change the extended attributes. */
	if (!am_root
#ifdef SUPPORT_LINKS
	 && !S_ISLNK(sxp->st.st_mode)
#endif
	 && access(fname, W_OK) < 0
	 && do_chmod(fname, (sxp->st.st_mode & CHMOD_BITS) | S_IWUSR) == 0)
		added_write_perm = 1;

	ndx = F_XATTR(file);
	glst += ndx;
	lst = &glst->xa_items;
	int return_value = rsync_xal_set(fname, lst, fnamecmp, sxp);
	if (added_write_perm) /* remove the temporary write permission */
		do_chmod(fname, sxp->st.st_mode);
	return return_value;
}

#ifdef SUPPORT_ACLS
char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
{
	const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
	*len_p = 0; /* no extra data alloc needed from get_xattr_data() */
	return get_xattr_data(fname, name, len_p, 1);
}

int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len)
{
	const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
	if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
		rsyserr(FERROR_XFER, errno,
			"set_xattr_acl: lsetxattr(%s,\"%s\") failed",
			full_fname(fname), name);
		return -1;
	}
	return 0;
}

int del_def_xattr_acl(const char *fname)
{
	return sys_lremovexattr(fname, XDEF_ACL_ATTR);
}
#endif

int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
{
	unsigned int mode;
	int rdev_major, rdev_minor, uid, gid, len;
	char buf[256];

	if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
		return -1;

	if (xst)
		*xst = *fst;
	else
		xst = fst;
	if (fname) {
		fd = -1;
		len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
	} else {
		fname = "fd";
		len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
	}
	if (len >= (int)sizeof buf) {
		len = -1;
		errno = ERANGE;
	}
	if (len < 0) {
		if (errno == ENOTSUP || errno == ENOATTR)
			return -1;
		if (errno == EPERM && S_ISLNK(fst->st_mode)) {
			xst->st_uid = 0;
			xst->st_gid = 0;
			return 0;
		}
		rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
			XSTAT_ATTR, full_fname(fname));
		return -1;
	}
	buf[len] = '\0';

	if (sscanf(buf, "%o %d,%d %d:%d",
		   &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
		rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
			XSTAT_ATTR, full_fname(fname), buf);
		exit_cleanup(RERR_FILEIO);
	}

	xst->st_mode = from_wire_mode(mode);
	xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
	xst->st_uid = uid;
	xst->st_gid = gid;

	return 0;
}

int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
{
	STRUCT_STAT fst, xst;
	dev_t rdev;
	mode_t mode, fmode;

	if (dry_run)
		return 0;

	if (read_only || list_only) {
		rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s",
			XSTAT_ATTR, full_fname(fname));
		return -1;
	}

	if (x_lstat(fname, &fst, &xst) < 0) {
		rsyserr(FERROR_XFER, errno, "failed to re-stat %s",
			full_fname(fname));
		return -1;
	}

	fst.st_mode &= (_S_IFMT | CHMOD_BITS);
	fmode = new_mode & (_S_IFMT | CHMOD_BITS);

	if (IS_DEVICE(fmode)) {
		uint32 *devp = F_RDEV_P(file);
		rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
	} else
		rdev = 0;

	/* Dump the special permissions and enable full owner access. */
	mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
	     | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
	if (fst.st_mode != mode)
		do_chmod(fname, mode);
	if (!IS_DEVICE(fst.st_mode))
		fst.st_rdev = 0; /* just in case */

	if (mode == fmode && fst.st_rdev == rdev
	 && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) {
		/* xst.st_mode will be 0 if there's no current stat xattr */
		if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
			rsyserr(FERROR_XFER, errno,
				"delete of stat xattr failed for %s",
				full_fname(fname));
			return -1;
		}
		return 0;
	}

	if (xst.st_mode != fmode || xst.st_rdev != rdev
	 || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) {
		char buf[256];
		int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
			to_wire_mode(fmode),
			(int)major(rdev), (int)minor(rdev),
			F_OWNER(file), F_GROUP(file));
		if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
			if (errno == EPERM && S_ISLNK(fst.st_mode))
				return 0;
			rsyserr(FERROR_XFER, errno,
				"failed to write xattr %s for %s",
				XSTAT_ATTR, full_fname(fname));
			return -1;
		}
	}

	return 0;
}

int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
{
	int ret = do_stat(fname, fst);
	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
		xst->st_mode = 0;
	return ret;
}

int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
{
	int ret = do_lstat(fname, fst);
	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
		xst->st_mode = 0;
	return ret;
}

int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
{
	int ret = do_fstat(fd, fst);
	if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
		xst->st_mode = 0;
	return ret;
}

#endif /* SUPPORT_XATTRS */
rsync-3.2.7/zlib/0000775000000000000000000000000014324367162012331 5ustar  rootrootrsync-3.2.7/zlib/inffixed.h0000664000000000000000000001427412155261705014302 0ustar  rootroot    /* inffixed.h -- table for decoding fixed codes
     * Generated automatically by makefixed().
     */

    /* WARNING: this file should *not* be used by applications.
       It is part of the implementation of this library and is
       subject to change. Applications should only use zlib.h.
     */

    static const code lenfix[512] = {
        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
        {0,9,255}
    };

    static const code distfix[32] = {
        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
        {22,5,193},{64,5,0}
    };
rsync-3.2.7/zlib/zlib.h0000664000000000000000000025354312155261705013452 0ustar  rootroot/* zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.8, April 28th, 2013

  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu


  The data format used by the zlib library is described by RFCs (Request for
  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/

#ifndef ZLIB_H
#define ZLIB_H

#include "zconf.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ZLIB_VERSION "1.2.8"
#define ZLIB_VERNUM 0x1280
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
#define ZLIB_VER_REVISION 8
#define ZLIB_VER_SUBREVISION 0

/*
    The 'zlib' compression library provides in-memory compression and
  decompression functions, including integrity checks of the uncompressed data.
  This version of the library supports only one compression method (deflation)
  but other algorithms will be added later and will have the same stream
  interface.

    Compression can be done in a single step if the buffers are large enough,
  or can be done by repeated calls of the compression function.  In the latter
  case, the application must provide more input and/or consume the output
  (providing more output space) before each call.

    The compressed data format used by default by the in-memory functions is
  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
  around a deflate stream, which is itself documented in RFC 1951.

    The library also supports reading and writing files in gzip (.gz) format
  with an interface similar to that of stdio using the functions that start
  with "gz".  The gzip format is different from the zlib format.  gzip is a
  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.

    This library can optionally read and write gzip streams in memory as well.

    The zlib format was designed to be compact and fast for use in memory
  and on communications channels.  The gzip format was designed for single-
  file compression on file systems, has a larger header than zlib to maintain
  directory information, and uses a different, slower check method than zlib.

    The library does not install any signal handler.  The decoder checks
  the consistency of the compressed data, so the library should never crash
  even in case of corrupted input.
*/

typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void   (*free_func)  OF((voidpf opaque, voidpf address));

struct internal_state;

typedef struct z_stream_s {
    z_const Bytef *next_in;     /* next input byte */
    uInt     avail_in;  /* number of bytes available at next_in */
    uLong    total_in;  /* total number of input bytes read so far */

    Bytef    *next_out; /* next output byte should be put there */
    uInt     avail_out; /* remaining free space at next_out */
    uLong    total_out; /* total number of bytes output so far */

    z_const char *msg;  /* last error message, NULL if no error */
    struct internal_state FAR *state; /* not visible by applications */

    alloc_func zalloc;  /* used to allocate the internal state */
    free_func  zfree;   /* used to free the internal state */
    voidpf     opaque;  /* private data object passed to zalloc and zfree */

    int     data_type;  /* best guess about the data type: binary or text */
    uLong   adler;      /* adler32 value of the uncompressed data */
    uLong   reserved;   /* reserved for future use */
} z_stream;

typedef z_stream FAR *z_streamp;

/*
     gzip header information passed to and from zlib routines.  See RFC 1952
  for more details on the meanings of these fields.
*/
typedef struct gz_header_s {
    int     text;       /* true if compressed data believed to be text */
    uLong   time;       /* modification time */
    int     xflags;     /* extra flags (not used when writing a gzip file) */
    int     os;         /* operating system */
    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
    uInt    extra_max;  /* space at extra (only when reading header) */
    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
    uInt    name_max;   /* space at name (only when reading header) */
    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
    uInt    comm_max;   /* space at comment (only when reading header) */
    int     hcrc;       /* true if there was or will be a header crc */
    int     done;       /* true when done reading gzip header (not used
                           when writing a gzip file) */
} gz_header;

typedef gz_header FAR *gz_headerp;

/*
     The application must update next_in and avail_in when avail_in has dropped
   to zero.  It must update next_out and avail_out when avail_out has dropped
   to zero.  The application must initialize zalloc, zfree and opaque before
   calling the init function.  All other fields are set by the compression
   library and must not be updated by the application.

     The opaque value provided by the application will be passed as the first
   parameter for calls of zalloc and zfree.  This can be useful for custom
   memory management.  The compression library attaches no meaning to the
   opaque value.

     zalloc must return Z_NULL if there is not enough memory for the object.
   If zlib is used in a multi-threaded application, zalloc and zfree must be
   thread safe.

     On 16-bit systems, the functions zalloc and zfree must be able to allocate
   exactly 65536 bytes, but will not be required to allocate more than this if
   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
   returned by zalloc for objects of exactly 65536 bytes *must* have their
   offset normalized to zero.  The default allocation function provided by this
   library ensures this (see zutil.c).  To reduce memory requirements and avoid
   any allocation of 64K objects, at the expense of compression ratio, compile
   the library with -DMAX_WBITS=14 (see zconf.h).

     The fields total_in and total_out can be used for statistics or progress
   reports.  After compression, total_in holds the total size of the
   uncompressed data and may be saved for use in the decompressor (particularly
   if the decompressor wants to decompress everything in a single step).
*/

                        /* constants */

#define Z_NO_FLUSH      0
#define Z_PARTIAL_FLUSH 1
#define Z_SYNC_FLUSH    2
#define Z_FULL_FLUSH    3
#define Z_FINISH        4
#define Z_BLOCK         5
#define Z_TREES         6
/* Allowed flush values; see deflate() and inflate() below for details */
#define Z_INSERT_ONLY	7

#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
 * are errors, positive values are used for special but normal events.
 */

#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
/* compression levels */

#define Z_FILTERED            1
#define Z_HUFFMAN_ONLY        2
#define Z_RLE                 3
#define Z_FIXED               4
#define Z_DEFAULT_STRATEGY    0
/* compression strategy; see deflateInit2() below for details */

#define Z_BINARY   0
#define Z_TEXT     1
#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN  2
/* Possible values of the data_type field (though see inflate()) */

#define Z_DEFLATED   8
/* The deflate compression method (the only one supported in this version) */

#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */

#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */


                        /* basic functions */

ZEXTERN const char * ZEXPORT zlibVersion OF((void));
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
   If the first character differs, the library code actually used is not
   compatible with the zlib.h header file used by the application.  This check
   is automatically made by deflateInit and inflateInit.
 */

/*
ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));

     Initializes the internal stream state for compression.  The fields
   zalloc, zfree and opaque must be initialized before by the caller.  If
   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
   allocation functions.

     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
   1 gives best speed, 9 gives best compression, 0 gives no compression at all
   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
   requests a default compromise between speed and compression (currently
   equivalent to level 6).

     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if level is not a valid compression level, or
   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
   if there is no error message.  deflateInit does not perform any compression:
   this will be done by deflate().
*/


ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
/*
    deflate compresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

    The detailed semantics are as follows.  deflate performs one or both of the
  following actions:

  - Compress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in and avail_in are updated and
    processing will resume at this point for the next call of deflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  This action is forced if the parameter flush is non zero.
    Forcing flush frequently degrades the compression ratio, so this parameter
    should be set only when necessary (in interactive applications).  Some
    output may be provided even if flush is not set.

    Before the call of deflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating avail_in or avail_out accordingly; avail_out should
  never be zero before the call.  The application can consume the compressed
  output when it wants, for example when the output buffer is full (avail_out
  == 0), or after each call of deflate().  If deflate returns Z_OK and with
  zero avail_out, it must be called again after making room in the output
  buffer because there might be more output pending.

    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
  decide how much data to accumulate before producing output, in order to
  maximize compression.

    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
  flushed to the output buffer and the output is aligned on a byte boundary, so
  that the decompressor can get all input data available so far.  (In
  particular avail_in is zero after the call if enough output space has been
  provided before the call.) Flushing may degrade compression for some
  compression algorithms and so it should be used only when necessary.  This
  completes the current deflate block and follows it with an empty stored block
  that is three bits plus filler bits to the next byte, followed by four bytes
  (00 00 ff ff).

    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
  output buffer, but the output is not aligned to a byte boundary.  All of the
  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
  This completes the current deflate block and follows it with an empty fixed
  codes block that is 10 bits long.  This assures that enough bytes are output
  in order for the decompressor to finish the block before the empty fixed code
  block.

    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
  seven bits of the current block are held to be written as the next byte after
  the next deflate block is completed.  In this case, the decompressor may not
  be provided enough bits at this point in order to complete decompression of
  the data provided so far to the compressor.  It may need to wait for the next
  block to be emitted.  This is for advanced applications that need to control
  the emission of deflate blocks.

    If flush is set to Z_FULL_FLUSH, all output is flushed as with
  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
  restart from this point if previous compressed data has been damaged or if
  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
  compression.

    If deflate returns with avail_out == 0, this function must be called again
  with the same value of the flush parameter and more output space (updated
  avail_out), until the flush is complete (deflate returns with non-zero
  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
  avail_out is greater than six to avoid repeated flush markers due to
  avail_out == 0 on return.

    If the parameter flush is set to Z_FINISH, pending input is processed,
  pending output is flushed and deflate returns with Z_STREAM_END if there was
  enough output space; if deflate returns with Z_OK, this function must be
  called again with Z_FINISH and more output space (updated avail_out) but no
  more input data, until it returns with Z_STREAM_END or an error.  After
  deflate has returned Z_STREAM_END, the only possible operations on the stream
  are deflateReset or deflateEnd.

    Z_FINISH can be used immediately after deflateInit if all the compression
  is to be done in a single step.  In this case, avail_out must be at least the
  value returned by deflateBound (see below).  Then deflate is guaranteed to
  return Z_STREAM_END.  If not enough output space is provided, deflate will
  not return Z_STREAM_END, and it must be called again as described above.

    deflate() sets strm->adler to the adler32 checksum of all input read
  so far (that is, total_in bytes).

    deflate() may update strm->data_type if it can make a good guess about
  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
  binary.  This field is only for information purposes and does not affect the
  compression algorithm in any manner.

    deflate() returns Z_OK if some progress has been made (more input
  processed or more output produced), Z_STREAM_END if all input has been
  consumed and all output has been produced (only when flush is set to
  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
  fatal, and deflate() can be called again with more input and more output
  space to continue compressing.
*/


ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
   prematurely (some input or output was discarded).  In the error case, msg
   may be set but then points to a static string (which must not be
   deallocated).
*/


/*
ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));

     Initializes the internal stream state for decompression.  The fields
   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
   exact value depends on the compression method), inflateInit determines the
   compression method from the zlib header and allocates all data structures
   accordingly; otherwise the allocation will be deferred to the first call of
   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
   use default allocation functions.

     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit() does not process any header information -- that is deferred
   until inflate() is called.
*/


ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
/*
    inflate decompresses as much data as possible, and stops when the input
  buffer becomes empty or the output buffer becomes full.  It may introduce
  some output latency (reading input without producing any output) except when
  forced to flush.

  The detailed semantics are as follows.  inflate performs one or both of the
  following actions:

  - Decompress more input starting at next_in and update next_in and avail_in
    accordingly.  If not all input can be processed (because there is not
    enough room in the output buffer), next_in is updated and processing will
    resume at this point for the next call of inflate().

  - Provide more output starting at next_out and update next_out and avail_out
    accordingly.  inflate() provides as much output as possible, until there is
    no more input data or no more space in the output buffer (see below about
    the flush parameter).

    Before the call of inflate(), the application should ensure that at least
  one of the actions is possible, by providing more input and/or consuming more
  output, and updating the next_* and avail_* values accordingly.  The
  application can consume the uncompressed output when it wants, for example
  when the output buffer is full (avail_out == 0), or after each call of
  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
  called again after making room in the output buffer because there might be
  more output pending.

    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
  output as possible to the output buffer.  Z_BLOCK requests that inflate()
  stop if and when it gets to the next deflate block boundary.  When decoding
  the zlib or gzip format, this will cause inflate() to return immediately
  after the header and before the first block.  When doing a raw inflate,
  inflate() will go ahead and process the first block, and will return when it
  gets to the end of that block, or when it runs out of data.

    The Z_BLOCK option assists in appending to or combining deflate streams.
  Also to assist in this, on return inflate() will set strm->data_type to the
  number of unused bits in the last byte taken from strm->next_in, plus 64 if
  inflate() is currently decoding the last block in the deflate stream, plus
  128 if inflate() returned immediately after decoding an end-of-block code or
  decoding the complete header up to just before the first byte of the deflate
  stream.  The end-of-block will not be indicated until all of the uncompressed
  data from that block has been written to strm->next_out.  The number of
  unused bits may in general be greater than seven, except when bit 7 of
  data_type is set, in which case the number of unused bits will be less than
  eight.  data_type is set as noted here every time inflate() returns for all
  flush options, and so can be used to determine the amount of currently
  consumed input in bits.

    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
  end of each deflate block header is reached, before any actual data in that
  block is decoded.  This allows the caller to determine the length of the
  deflate block header for later use in random access within a deflate block.
  256 is added to the value of strm->data_type when inflate() returns
  immediately after reaching the end of the deflate block header.

    inflate() should normally be called until it returns Z_STREAM_END or an
  error.  However if all decompression is to be performed in a single step (a
  single call of inflate), the parameter flush should be set to Z_FINISH.  In
  this case all pending input is processed and all pending output is flushed;
  avail_out must be large enough to hold all of the uncompressed data for the
  operation to complete.  (The size of the uncompressed data may have been
  saved by the compressor for this purpose.) The use of Z_FINISH is not
  required to perform an inflation in one step.  However it may be used to
  inform inflate that a faster approach can be used for the single inflate()
  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
  stream completes, which reduces inflate's memory footprint.  If the stream
  does not complete, either because not all of the stream is provided or not
  enough output space is provided, then a sliding window will be allocated and
  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
  been used.

     In this implementation, inflate() always flushes as much output as
  possible to the output buffer, and always uses the faster approach on the
  first call.  So the effects of the flush parameter in this implementation are
  on the return value of inflate() as noted below, when inflate() returns early
  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
  memory for a sliding window when Z_FINISH is used.

     If a preset dictionary is needed after this call (see inflateSetDictionary
  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
  strm->adler to the Adler-32 checksum of all output produced so far (that is,
  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
  below.  At the end of the stream, inflate() checks that its computed adler32
  checksum is equal to that saved by the compressor and returns Z_STREAM_END
  only if the checksum is correct.

    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
  deflate data.  The header type is detected automatically, if requested when
  initializing with inflateInit2().  Any information contained in the gzip
  header is not retained, so applications that need that information should
  instead use raw inflate, see inflateInit2() below, or inflateBack() and
  perform their own processing of the gzip header and trailer.  When processing
  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
  producted so far.  The CRC-32 is checked against the gzip trailer.

    inflate() returns Z_OK if some progress has been made (more input processed
  or more output produced), Z_STREAM_END if the end of the compressed data has
  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
  corrupted (input stream not conforming to the zlib format or incorrect check
  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
  inflate() can be called again with more input and more output space to
  continue decompressing.  If Z_DATA_ERROR is returned, the application may
  then call inflateSync() to look for a good compression block if a partial
  recovery of the data is desired.
*/


ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
/*
     All dynamically allocated data structures for this stream are freed.
   This function discards any unprocessed input and does not flush any pending
   output.

     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
   was inconsistent.  In the error case, msg may be set but then points to a
   static string (which must not be deallocated).
*/


                        /* Advanced functions */

/*
    The following functions are needed only in some special applications.
*/

/*
ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
                                     int  level,
                                     int  method,
                                     int  windowBits,
                                     int  memLevel,
                                     int  strategy));

     This is another version of deflateInit with more compression options.  The
   fields next_in, zalloc, zfree and opaque must be initialized before by the
   caller.

     The method parameter is the compression method.  It must be Z_DEFLATED in
   this version of the library.

     The windowBits parameter is the base two logarithm of the window size
   (the size of the history buffer).  It should be in the range 8..15 for this
   version of the library.  Larger values of this parameter result in better
   compression at the expense of memory usage.  The default value is 15 if
   deflateInit is used instead.

     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
   determines the window size.  deflate() will then generate raw deflate data
   with no zlib header or trailer, and will not compute an adler32 check value.

     windowBits can also be greater than 15 for optional gzip encoding.  Add
   16 to windowBits to write a simple gzip header and trailer around the
   compressed data instead of a zlib wrapper.  The gzip header will have no
   file name, no extra data, no comment, no modification time (set to zero), no
   header crc, and the operating system will be set to 255 (unknown).  If a
   gzip stream is being written, strm->adler is a crc32 instead of an adler32.

     The memLevel parameter specifies how much memory should be allocated
   for the internal compression state.  memLevel=1 uses minimum memory but is
   slow and reduces compression ratio; memLevel=9 uses maximum memory for
   optimal speed.  The default value is 8.  See zconf.h for total memory usage
   as a function of windowBits and memLevel.

     The strategy parameter is used to tune the compression algorithm.  Use the
   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
   string match), or Z_RLE to limit match distances to one (run-length
   encoding).  Filtered data consists mostly of small values with a somewhat
   random distribution.  In this case, the compression algorithm is tuned to
   compress them better.  The effect of Z_FILTERED is to force more Huffman
   coding and less string matching; it is somewhat intermediate between
   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
   strategy parameter only affects the compression ratio but not the
   correctness of the compressed output even if it is not set appropriately.
   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
   decoder for special applications.

     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
   set to null if there is no error message.  deflateInit2 does not perform any
   compression: this will be done by deflate().
*/

ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength));
/*
     Initializes the compression dictionary from the given byte sequence
   without producing any compressed output.  When using the zlib format, this
   function must be called immediately after deflateInit, deflateInit2 or
   deflateReset, and before any call of deflate.  When doing raw deflate, this
   function must be called either before any call of deflate, or immediately
   after the completion of a deflate block, i.e. after all input has been
   consumed and all output has been delivered when using any of the flush
   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
   compressor and decompressor must use exactly the same dictionary (see
   inflateSetDictionary).

     The dictionary should consist of strings (byte sequences) that are likely
   to be encountered later in the data to be compressed, with the most commonly
   used strings preferably put towards the end of the dictionary.  Using a
   dictionary is most useful when the data to be compressed is short and can be
   predicted with good accuracy; the data can then be compressed better than
   with the default empty dictionary.

     Depending on the size of the compression data structures selected by
   deflateInit or deflateInit2, a part of the dictionary may in effect be
   discarded, for example if the dictionary is larger than the window size
   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
   useful should be put at the end of the dictionary, not at the front.  In
   addition, the current implementation of deflate will use at most the window
   size minus 262 bytes of the provided dictionary.

     Upon return of this function, strm->adler is set to the adler32 value
   of the dictionary; the decompressor may later use this value to determine
   which dictionary has been used by the compressor.  (The adler32 value
   applies to the whole dictionary even if only a subset of the dictionary is
   actually used by the compressor.) If a raw deflate was requested, then the
   adler32 value is not computed and strm->adler is not set.

     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent (for example if deflate has already been called for this stream
   or if not at a block boundary for raw deflate).  deflateSetDictionary does
   not perform any compression: this will be done by deflate().
*/

ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
                                    z_streamp source));
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when several compression strategies will be
   tried, for example when there are several ways of pre-processing the input
   data with a filter.  The streams that will be discarded should then be freed
   by calling deflateEnd.  Note that deflateCopy duplicates the internal
   compression state which can be quite large, so this strategy is slow and can
   consume lots of memory.

     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
/*
     This function is equivalent to deflateEnd followed by deflateInit,
   but does not free and reallocate all the internal compression state.  The
   stream will keep the same compression level and any other attributes that
   may have been set by deflateInit2.

     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
                                      int level,
                                      int strategy));
/*
     Dynamically update the compression level and compression strategy.  The
   interpretation of level and strategy is as in deflateInit2.  This can be
   used to switch between compression and straight copy of the input data, or
   to switch to a different kind of input data requiring a different strategy.
   If the compression level is changed, the input available so far is
   compressed with the old level (and may be flushed); the new level will take
   effect only at the next call of deflate().

     Before the call of deflateParams, the stream state must be set as for
   a call of deflate(), since the currently available input may have to be
   compressed and flushed.  In particular, strm->avail_out must be non-zero.

     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
   strm->avail_out was zero.
*/

ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
                                    int good_length,
                                    int max_lazy,
                                    int nice_length,
                                    int max_chain));
/*
     Fine tune deflate's internal compression parameters.  This should only be
   used by someone who understands the algorithm used by zlib's deflate for
   searching for the best matching string, and even then only by the most
   fanatic optimizer trying to squeeze out the last compressed bit for their
   specific input data.  Read the deflate.c source code for the meaning of the
   max_lazy, good_length, nice_length, and max_chain parameters.

     deflateTune() can be called after deflateInit() or deflateInit2(), and
   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
 */

ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
                                       uLong sourceLen));
/*
     deflateBound() returns an upper bound on the compressed size after
   deflation of sourceLen bytes.  It must be called after deflateInit() or
   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
   to allocate an output buffer for deflation in a single pass, and so would be
   called before deflate().  If that first deflate() call is provided the
   sourceLen input bytes, an output buffer allocated to the size returned by
   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
   to return Z_STREAM_END.  Note that it is possible for the compressed size to
   be larger than the value returned by deflateBound() if flush options other
   than Z_FINISH or Z_NO_FLUSH are used.
*/

ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
                                       unsigned *pending,
                                       int *bits));
/*
     deflatePending() returns the number of bytes and bits of output that have
   been generated, but not yet provided in the available output.  The bytes not
   provided would be due to the available output space having being consumed.
   The number of bits of output not provided are between 0 and 7, where they
   await more bits to join them in order to fill out a full byte.  If pending
   or bits are Z_NULL, then those values are not set.

     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
 */

ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
                                     int bits,
                                     int value));
/*
     deflatePrime() inserts bits in the deflate output stream.  The intent
   is that this function is used to start off the deflate output with the bits
   leftover from a previous deflate stream when appending to it.  As such, this
   function can only be used for raw deflate, and must be used before the first
   deflate() call after a deflateInit2() or deflateReset().  bits must be less
   than or equal to 16, and that many of the least significant bits of value
   will be inserted in the output.

     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
   source stream state was inconsistent.
*/

ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
                                         gz_headerp head));
/*
     deflateSetHeader() provides gzip header information for when a gzip
   stream is requested by deflateInit2().  deflateSetHeader() may be called
   after deflateInit2() or deflateReset() and before the first call of
   deflate().  The text, time, os, extra field, name, and comment information
   in the provided gz_header structure are written to the gzip header (xflag is
   ignored -- the extra flags are set according to the compression level).  The
   caller must assure that, if not Z_NULL, name and comment are terminated with
   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
   available there.  If hcrc is true, a gzip header crc is included.  Note that
   the current versions of the command-line version of gzip (up through version
   1.3.x) do not support header crc's, and will report that it is a "multi-part
   gzip file" and give up.

     If deflateSetHeader is not used, the default gzip header has text false,
   the time set to zero, and os set to 255, with no extra, name, or comment
   fields.  The gzip header is returned to the default state by deflateReset().

     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
                                     int  windowBits));

     This is another version of inflateInit with an extra parameter.  The
   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
   before by the caller.

     The windowBits parameter is the base two logarithm of the maximum window
   size (the size of the history buffer).  It should be in the range 8..15 for
   this version of the library.  The default value is 15 if inflateInit is used
   instead.  windowBits must be greater than or equal to the windowBits value
   provided to deflateInit2() while compressing, or it must be equal to 15 if
   deflateInit2() was not used.  If a compressed stream with a larger window
   size is given as input, inflate() will return with the error code
   Z_DATA_ERROR instead of trying to allocate a larger window.

     windowBits can also be zero to request that inflate use the window size in
   the zlib header of the compressed stream.

     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
   determines the window size.  inflate() will then process raw deflate data,
   not looking for a zlib or gzip header, not generating a check value, and not
   looking for any check values for comparison at the end of the stream.  This
   is for use with other formats that use the deflate compressed data format
   such as zip.  Those formats provide their own check values.  If a custom
   format is developed using the raw deflate format for compressed data, it is
   recommended that a check value such as an adler32 or a crc32 be applied to
   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
   most applications, the zlib format should be used as is.  Note that comments
   above on the use in deflateInit2() applies to the magnitude of windowBits.

     windowBits can also be greater than 15 for optional gzip decoding.  Add
   32 to windowBits to enable zlib and gzip decoding with automatic header
   detection, or add 16 to decode only the gzip format (the zlib format will
   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
   crc32 instead of an adler32.

     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
   invalid, such as a null pointer to the structure.  msg is set to null if
   there is no error message.  inflateInit2 does not perform any decompression
   apart from possibly reading the zlib header if present: actual decompression
   will be done by inflate().  (So next_in and avail_in may be modified, but
   next_out and avail_out are unused and unchanged.) The current implementation
   of inflateInit2() does not process any header information -- that is
   deferred until inflate() is called.
*/

ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
                                             const Bytef *dictionary,
                                             uInt  dictLength));
/*
     Initializes the decompression dictionary from the given uncompressed byte
   sequence.  This function must be called immediately after a call of inflate,
   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
   can be determined from the adler32 value returned by that call of inflate.
   The compressor and decompressor must use exactly the same dictionary (see
   deflateSetDictionary).  For raw inflate, this function can be called at any
   time to set the dictionary.  If the provided dictionary is smaller than the
   window and there is already data in the window, then the provided dictionary
   will amend what's there.  The application must insure that the dictionary
   that was used for compression is provided.

     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
   expected one (incorrect adler32 value).  inflateSetDictionary does not
   perform any decompression: this will be done by subsequent calls of
   inflate().
*/

ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
                                             Bytef *dictionary,
                                             uInt  *dictLength));
/*
     Returns the sliding dictionary being maintained by inflate.  dictLength is
   set to the number of bytes in the dictionary, and that many bytes are copied
   to dictionary.  dictionary must have enough space, where 32768 bytes is
   always enough.  If inflateGetDictionary() is called with dictionary equal to
   Z_NULL, then only the dictionary length is returned, and nothing is copied.
   Similary, if dictLength is Z_NULL, then it is not set.

     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
   stream state is inconsistent.
*/

ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
/*
     Skips invalid compressed data until a possible full flush point (see above
   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
   available input is skipped.  No output is provided.

     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
   All full flush points have this pattern, but not all occurrences of this
   pattern are full flush points.

     inflateSync returns Z_OK if a possible full flush point has been found,
   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
   In the success case, the application may save the current current value of
   total_in which indicates where valid compressed data was found.  In the
   error case, the application may repeatedly call inflateSync, providing more
   input each time, until success or end of the input data.
*/

ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
                                    z_streamp source));
/*
     Sets the destination stream as a complete copy of the source stream.

     This function can be useful when randomly accessing a large stream.  The
   first pass through the stream can periodically record the inflate state,
   allowing restarting inflate at those points when randomly accessing the
   stream.

     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
   destination.
*/

ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
/*
     This function is equivalent to inflateEnd followed by inflateInit,
   but does not free and reallocate all the internal decompression state.  The
   stream will keep attributes that may have been set by inflateInit2.

     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL).
*/

ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
                                      int windowBits));
/*
     This function is the same as inflateReset, but it also permits changing
   the wrap and window size requests.  The windowBits parameter is interpreted
   the same as it is for inflateInit2.

     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
   the windowBits parameter is invalid.
*/

ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
                                     int bits,
                                     int value));
/*
     This function inserts bits in the inflate input stream.  The intent is
   that this function is used to start inflating at a bit position in the
   middle of a byte.  The provided bits will be used before any bytes are used
   from next_in.  This function should only be used with raw inflate, and
   should be used before the first inflate() call after inflateInit2() or
   inflateReset().  bits must be less than or equal to 16, and that many of the
   least significant bits of value will be inserted in the input.

     If bits is negative, then the input stream bit buffer is emptied.  Then
   inflatePrime() can be called again to put bits in the buffer.  This is used
   to clear out bits leftover after feeding inflate a block description prior
   to feeding inflate codes.

     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
/*
     This function returns two values, one in the lower 16 bits of the return
   value, and the other in the remaining upper bits, obtained by shifting the
   return value down 16 bits.  If the upper value is -1 and the lower value is
   zero, then inflate() is currently decoding information outside of a block.
   If the upper value is -1 and the lower value is non-zero, then inflate is in
   the middle of a stored block, with the lower value equaling the number of
   bytes from the input remaining to copy.  If the upper value is not -1, then
   it is the number of bits back from the current bit position in the input of
   the code (literal or length/distance pair) currently being processed.  In
   that case the lower value is the number of bytes already emitted for that
   code.

     A code is being processed if inflate is waiting for more input to complete
   decoding of the code, or if it has completed decoding but is waiting for
   more output space to write the literal or match data.

     inflateMark() is used to mark locations in the input data for random
   access, which may be at bit positions, and to note those cases where the
   output of a code may span boundaries of random access blocks.  The current
   location in the input stream can be determined from avail_in and data_type
   as noted in the description for the Z_BLOCK flush parameter for inflate.

     inflateMark returns the value noted above or -1 << 16 if the provided
   source stream state was inconsistent.
*/

ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
                                         gz_headerp head));
/*
     inflateGetHeader() requests that gzip header information be stored in the
   provided gz_header structure.  inflateGetHeader() may be called after
   inflateInit2() or inflateReset(), and before the first call of inflate().
   As inflate() processes the gzip stream, head->done is zero until the header
   is completed, at which time head->done is set to one.  If a zlib stream is
   being decoded, then head->done is set to -1 to indicate that there will be
   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
   used to force inflate() to return immediately after header processing is
   complete and before any actual data is decompressed.

     The text, time, xflags, and os fields are filled in with the gzip header
   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
   contains the maximum number of bytes to write to extra.  Once done is true,
   extra_len contains the actual extra field length, and extra contains the
   extra field, or that field truncated if extra_max is less than extra_len.
   If name is not Z_NULL, then up to name_max characters are written there,
   terminated with a zero unless the length is greater than name_max.  If
   comment is not Z_NULL, then up to comm_max characters are written there,
   terminated with a zero unless the length is greater than comm_max.  When any
   of extra, name, or comment are not Z_NULL and the respective field is not
   present in the header, then that field is set to Z_NULL to signal its
   absence.  This allows the use of deflateSetHeader() with the returned
   structure to duplicate the header.  However if those fields are set to
   allocated memory, then the application will need to save those pointers
   elsewhere so that they can be eventually freed.

     If inflateGetHeader is not used, then the header information is simply
   discarded.  The header is always checked for validity, including the header
   CRC if present.  inflateReset() will reset the process to discard the header
   information.  The application would need to call inflateGetHeader() again to
   retrieve the header from the next gzip stream.

     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
   stream state was inconsistent.
*/

/*
ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
                                        unsigned char FAR *window));

     Initialize the internal stream state for decompression using inflateBack()
   calls.  The fields zalloc, zfree and opaque in strm must be initialized
   before the call.  If zalloc and zfree are Z_NULL, then the default library-
   derived memory allocation routines are used.  windowBits is the base two
   logarithm of the window size, in the range 8..15.  window is a caller
   supplied buffer of that size.  Except for special applications where it is
   assured that deflate was used with small window sizes, windowBits must be 15
   and a 32K byte window must be supplied to be able to decompress general
   deflate streams.

     See inflateBack() for the usage of these routines.

     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
   allocated, or Z_VERSION_ERROR if the version of the library does not match
   the version of the header file.
*/

typedef unsigned (*in_func) OF((void FAR *,
                                z_const unsigned char FAR * FAR *));
typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));

ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
                                    in_func in, void FAR *in_desc,
                                    out_func out, void FAR *out_desc));
/*
     inflateBack() does a raw inflate with a single call using a call-back
   interface for input and output.  This is potentially more efficient than
   inflate() for file i/o applications, in that it avoids copying between the
   output and the sliding window by simply making the window itself the output
   buffer.  inflate() can be faster on modern CPUs when used with large
   buffers.  inflateBack() trusts the application to not change the output
   buffer passed by the output function, at least until inflateBack() returns.

     inflateBackInit() must be called first to allocate the internal state
   and to initialize the state with the user-provided window buffer.
   inflateBack() may then be used multiple times to inflate a complete, raw
   deflate stream with each call.  inflateBackEnd() is then called to free the
   allocated state.

     A raw deflate stream is one with no zlib or gzip header or trailer.
   This routine would normally be used in a utility that reads zip or gzip
   files and writes out uncompressed files.  The utility would decode the
   header and process the trailer on its own, hence this routine expects only
   the raw deflate stream to decompress.  This is different from the normal
   behavior of inflate(), which expects either a zlib or gzip header and
   trailer around the deflate stream.

     inflateBack() uses two subroutines supplied by the caller that are then
   called by inflateBack() for input and output.  inflateBack() calls those
   routines until it reads a complete deflate stream and writes out all of the
   uncompressed data, or until it encounters an error.  The function's
   parameters and return types are defined above in the in_func and out_func
   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
   number of bytes of provided input, and a pointer to that input in buf.  If
   there is no input available, in() must return zero--buf is ignored in that
   case--and inflateBack() will return a buffer error.  inflateBack() will call
   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
   should return zero on success, or non-zero on failure.  If out() returns
   non-zero, inflateBack() will return with an error.  Neither in() nor out()
   are permitted to change the contents of the window provided to
   inflateBackInit(), which is also the buffer that out() uses to write from.
   The length written by out() will be at most the window size.  Any non-zero
   amount of input may be provided by in().

     For convenience, inflateBack() can be provided input on the first call by
   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
   in() will be called.  Therefore strm->next_in must be initialized before
   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
   must also be initialized, and then if strm->avail_in is not zero, input will
   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].

     The in_desc and out_desc parameters of inflateBack() is passed as the
   first parameter of in() and out() respectively when they are called.  These
   descriptors can be optionally used to pass any information that the caller-
   supplied in() and out() functions need to do their job.

     On return, inflateBack() will set strm->next_in and strm->avail_in to
   pass back any unused input that was provided by the last in() call.  The
   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
   in the deflate stream (in which case strm->msg is set to indicate the nature
   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
   In the case of Z_BUF_ERROR, an input or output error can be distinguished
   using strm->next_in which will be Z_NULL only if in() returned an error.  If
   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
   non-zero.  (in() will always be called before out(), so strm->next_in is
   assured to be defined if out() returns non-zero.) Note that inflateBack()
   cannot return Z_OK.
*/

ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
/*
     All memory allocated by inflateBackInit() is freed.

     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
   state was inconsistent.
*/

ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
/* Return flags indicating compile-time options.

    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
     1.0: size of uInt
     3.2: size of uLong
     5.4: size of voidpf (pointer)
     7.6: size of z_off_t

    Compiler, assembler, and debug options:
     8: DEBUG
     9: ASMV or ASMINF -- use ASM code
     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
     11: 0 (reserved)

    One-time table building (smaller code, but not thread-safe if true):
     12: BUILDFIXED -- build static block decoding tables when needed
     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
     14,15: 0 (reserved)

    Library content (indicates missing functionality):
     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
                          deflate code when not needed)
     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
                    and decode gzip streams (to avoid linking crc code)
     18-19: 0 (reserved)

    Operation variations (changes in library functionality):
     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
     21: FASTEST -- deflate algorithm with only one, lowest compression level
     22,23: 0 (reserved)

    The sprintf variant used by gzprintf (zero is best):
     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
     26: 0 = returns value, 1 = void -- 1 means inferred string length returned

    Remainder:
     27-31: 0 (reserved)
 */

#ifndef Z_SOLO

                        /* utility functions */

/*
     The following utility functions are implemented on top of the basic
   stream-oriented functions.  To simplify the interface, some default options
   are assumed (compression level and memory usage, standard memory allocation
   functions).  The source code of these utility functions can be modified if
   you need special options.
*/

ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
                                 const Bytef *source, uLong sourceLen));
/*
     Compresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer.
*/

ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
                                  const Bytef *source, uLong sourceLen,
                                  int level));
/*
     Compresses the source buffer into the destination buffer.  The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer.  Upon entry, destLen is the total size of the
   destination buffer, which must be at least the value returned by
   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
   compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/

ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
/*
     compressBound() returns an upper bound on the compressed size after
   compress() or compress2() on sourceLen bytes.  It would be used before a
   compress() or compress2() call to allocate the destination buffer.
*/

ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
                                   const Bytef *source, uLong sourceLen));
/*
     Decompresses the source buffer into the destination buffer.  sourceLen is
   the byte length of the source buffer.  Upon entry, destLen is the total size
   of the destination buffer, which must be large enough to hold the entire
   uncompressed data.  (The size of the uncompressed data must have been saved
   previously by the compressor and transmitted to the decompressor by some
   mechanism outside the scope of this compression library.) Upon exit, destLen
   is the actual size of the uncompressed buffer.

     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
   enough memory, Z_BUF_ERROR if there was not enough room in the output
   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
   the case where there is not enough room, uncompress() will fill the output
   buffer with the uncompressed data up to that point.
*/

                        /* gzip file access functions */

/*
     This library supports reading and writing files in gzip (.gz) format with
   an interface similar to that of stdio, using the functions that start with
   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
   wrapper, documented in RFC 1952, wrapped around a deflate stream.
*/

typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */

/*
ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));

     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
   for fixed code compression as in "wb9F".  (See the description of
   deflateInit2 for more information about the strategy parameter.)  'T' will
   request transparent writing or appending with no compression and not using
   the gzip format.

     "a" can be used instead of "w" to request that the gzip stream that will
   be written be appended to the file.  "+" will result in an error, since
   reading and writing to the same gzip file is not supported.  The addition of
   "x" when writing will create the file exclusively, which fails if the file
   already exists.  On systems that support it, the addition of "e" when
   reading or writing will set the flag to close the file on an execve() call.

     These functions, as well as gzip, will read and decode a sequence of gzip
   streams in a file.  The append function of gzopen() can be used to create
   such a file.  (Also see gzflush() for another way to do this.)  When
   appending, gzopen does not test whether the file begins with a gzip stream,
   nor does it look for the end of the gzip streams to begin appending.  gzopen
   will simply append a gzip stream to the existing file.

     gzopen can be used to read a file which is not in gzip format; in this
   case gzread will directly read from the file without decompression.  When
   reading, this will be detected automatically by looking for the magic two-
   byte gzip header.

     gzopen returns NULL if the file could not be opened, if there was
   insufficient memory to allocate the gzFile state, or if an invalid mode was
   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
   errno can be checked to determine if the reason gzopen failed was that the
   file could not be opened.
*/

ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
/*
     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
   are obtained from calls like open, dup, creat, pipe or fileno (if the file
   has been previously opened with fopen).  The mode parameter is as in gzopen.

     The next call of gzclose on the returned gzFile will also close the file
   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
   mode);.  The duplicated descriptor should be saved to avoid a leak, since
   gzdopen does not close fd if it fails.  If you are using fileno() to get the
   file descriptor from a FILE *, then you will have to use dup() to avoid
   double-close()ing the file descriptor.  Both gzclose() and fclose() will
   close the associated file descriptor, so they need to have different file
   descriptors.

     gzdopen returns NULL if there was insufficient memory to allocate the
   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
   used until the next gz* read, write, seek, or close operation, so gzdopen
   will not detect if fd is invalid (unless fd is -1).
*/

ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
/*
     Set the internal buffer size used by this library's functions.  The
   default buffer size is 8192 bytes.  This function must be called after
   gzopen() or gzdopen(), and before any other calls that read or write the
   file.  The buffer memory allocation is always deferred to the first read or
   write.  Two buffers are allocated, either both of the specified size when
   writing, or one of the specified size and the other twice that size when
   reading.  A larger buffer size of, for example, 64K or 128K bytes will
   noticeably increase the speed of decompression (reading).

     The new buffer size also affects the maximum length for gzprintf().

     gzbuffer() returns 0 on success, or -1 on failure, such as being called
   too late.
*/

ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
/*
     Dynamically update the compression level or strategy.  See the description
   of deflateInit2 for the meaning of these parameters.

     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
   opened for writing.
*/

ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
/*
     Reads the given number of uncompressed bytes from the compressed file.  If
   the input file is not in gzip format, gzread copies the given number of
   bytes into the buffer directly from the file.

     After reaching the end of a gzip stream in the input, gzread will continue
   to read, looking for another gzip stream.  Any number of gzip streams may be
   concatenated in the input file, and will all be decompressed by gzread().
   If something other than a gzip stream is encountered after a gzip stream,
   that remaining trailing garbage is ignored (and no error is returned).

     gzread can be used to read a gzip file that is being concurrently written.
   Upon reaching the end of the input, gzread will return with the available
   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
   gzclearerr can be used to clear the end of file indicator in order to permit
   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
   middle of a gzip stream.  Note that gzread does not return -1 in the event
   of an incomplete gzip stream.  This error is deferred until gzclose(), which
   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
   stream.  Alternatively, gzerror can be used before gzclose to detect this
   case.

     gzread returns the number of uncompressed bytes actually read, less than
   len for end of file, or -1 for error.
*/

ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
                                voidpc buf, unsigned len));
/*
     Writes the given number of uncompressed bytes into the compressed file.
   gzwrite returns the number of uncompressed bytes written or 0 in case of
   error.
*/

ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
     Converts, formats, and writes the arguments to the compressed file under
   control of the format string, as in fprintf.  gzprintf returns the number of
   uncompressed bytes actually written, or 0 in case of error.  The number of
   uncompressed bytes written is limited to 8191, or one less than the buffer
   size given to gzbuffer().  The caller should assure that this limit is not
   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
   nothing written.  In this case, there may also be a buffer overflow with
   unpredictable consequences, which is possible only if zlib was compiled with
   the insecure functions sprintf() or vsprintf() because the secure snprintf()
   or vsnprintf() functions were not available.  This can be determined using
   zlibCompileFlags().
*/

ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
/*
     Writes the given null-terminated string to the compressed file, excluding
   the terminating null character.

     gzputs returns the number of characters written, or -1 in case of error.
*/

ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
/*
     Reads bytes from the compressed file until len-1 characters are read, or a
   newline character is read and transferred to buf, or an end-of-file
   condition is encountered.  If any characters are read or if len == 1, the
   string is terminated with a null character.  If no characters are read due
   to an end-of-file or len < 1, then the buffer is left untouched.

     gzgets returns buf which is a null-terminated string, or it returns NULL
   for end-of-file or in case of error.  If there was an error, the contents at
   buf are indeterminate.
*/

ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
/*
     Writes c, converted to an unsigned char, into the compressed file.  gzputc
   returns the value that was written, or -1 in case of error.
*/

ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
/*
     Reads one byte from the compressed file.  gzgetc returns this byte or -1
   in case of end of file or error.  This is implemented as a macro for speed.
   As such, it does not do all of the checking the other functions do.  I.e.
   it does not check to see if file is NULL, nor whether the structure file
   points to has been clobbered or not.
*/

ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
/*
     Push one character back onto the stream to be read as the first character
   on the next read.  At least one character of push-back is allowed.
   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
   fail if c is -1, and may fail if a character has been pushed but not read
   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
   The pushed character will be discarded if the stream is repositioned with
   gzseek() or gzrewind().
*/

ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
/*
     Flushes all pending output into the compressed file.  The parameter flush
   is as in the deflate() function.  The return value is the zlib error number
   (see function gzerror below).  gzflush is only permitted when writing.

     If the flush parameter is Z_FINISH, the remaining data is written and the
   gzip stream is completed in the output.  If gzwrite() is called again, a new
   gzip stream will be started in the output.  gzread() is able to read such
   concatented gzip streams.

     gzflush should be called only when strictly necessary because it will
   degrade compression if called too often.
*/

/*
ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
                                   z_off_t offset, int whence));

     Sets the starting position for the next gzread or gzwrite on the given
   compressed file.  The offset represents a number of bytes in the
   uncompressed data stream.  The whence parameter is defined as in lseek(2);
   the value SEEK_END is not supported.

     If the file is opened for reading, this function is emulated but can be
   extremely slow.  If the file is opened for writing, only forward seeks are
   supported; gzseek then compresses a sequence of zeroes up to the new
   starting position.

     gzseek returns the resulting offset location as measured in bytes from
   the beginning of the uncompressed stream, or -1 in case of error, in
   particular if the file is opened for writing and the new starting position
   would be before the current position.
*/

ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
/*
     Rewinds the given file. This function is supported only for reading.

     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
*/

/*
ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));

     Returns the starting position for the next gzread or gzwrite on the given
   compressed file.  This position represents a number of bytes in the
   uncompressed data stream, and is zero when starting, even if appending or
   reading a gzip stream from the middle of a file using gzdopen().

     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
*/

/*
ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));

     Returns the current offset in the file being read or written.  This offset
   includes the count of bytes that precede the gzip stream, for example when
   appending or when using gzdopen() for reading.  When reading, the offset
   does not include as yet unused buffered input.  This information can be used
   for a progress indicator.  On error, gzoffset() returns -1.
*/

ZEXTERN int ZEXPORT gzeof OF((gzFile file));
/*
     Returns true (1) if the end-of-file indicator has been set while reading,
   false (0) otherwise.  Note that the end-of-file indicator is set only if the
   read tried to go past the end of the input, but came up short.  Therefore,
   just like feof(), gzeof() may return false even if there is no more data to
   read, in the event that the last read request was for the exact number of
   bytes remaining in the input file.  This will happen if the input file size
   is an exact multiple of the buffer size.

     If gzeof() returns true, then the read functions will return no more data,
   unless the end-of-file indicator is reset by gzclearerr() and the input file
   has grown since the previous end of file was detected.
*/

ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
/*
     Returns true (1) if file is being copied directly while reading, or false
   (0) if file is a gzip stream being decompressed.

     If the input file is empty, gzdirect() will return true, since the input
   does not contain a gzip stream.

     If gzdirect() is used immediately after gzopen() or gzdopen() it will
   cause buffers to be allocated to allow reading the file to determine if it
   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
   gzdirect().

     When writing, gzdirect() returns true (1) if transparent writing was
   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
   gzdirect() is not needed when writing.  Transparent writing must be
   explicitly requested, so the application already knows the answer.  When
   linking statically, using gzdirect() will include all of the zlib code for
   gzip file reading and decompression, which may not be desired.)
*/

ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
/*
     Flushes all pending output if necessary, closes the compressed file and
   deallocates the (de)compression state.  Note that once file is closed, you
   cannot call gzerror with file, since its structures have been deallocated.
   gzclose must not be called more than once on the same file, just as free
   must not be called more than once on the same allocation.

     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
   last read ended in the middle of a gzip stream, or Z_OK on success.
*/

ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
/*
     Same as gzclose(), but gzclose_r() is only for use when reading, and
   gzclose_w() is only for use when writing or appending.  The advantage to
   using these instead of gzclose() is that they avoid linking in zlib
   compression or decompression code that is not used when only reading or only
   writing respectively.  If gzclose() is used, then both compression and
   decompression code will be included the application when linking to a static
   zlib library.
*/

ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
/*
     Returns the error message for the last error which occurred on the given
   compressed file.  errnum is set to zlib error number.  If an error occurred
   in the file system and not in the compression library, errnum is set to
   Z_ERRNO and the application may consult errno to get the exact error code.

     The application must not modify the returned string.  Future calls to
   this function may invalidate the previously returned string.  If file is
   closed, then the string previously returned by gzerror will no longer be
   available.

     gzerror() should be used to distinguish errors from end-of-file for those
   functions above that do not distinguish those cases in their return values.
*/

ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
/*
     Clears the error and end-of-file flags for file.  This is analogous to the
   clearerr() function in stdio.  This is useful for continuing to read a gzip
   file that is being written concurrently.
*/

#endif /* !Z_SOLO */

                        /* checksum functions */

/*
     These functions are not related to compression but are exported
   anyway because they might be useful in applications using the compression
   library.
*/

ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
/*
     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
   return the updated checksum.  If buf is Z_NULL, this function returns the
   required initial value for the checksum.

     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
   much faster.

   Usage example:

     uLong adler = adler32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       adler = adler32(adler, buffer, length);
     }
     if (adler != original_adler) error();
*/

/*
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
                                          z_off_t len2));

     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
   that the z_off_t type (like off_t) is a signed integer.  If len2 is
   negative, the result has no meaning or utility.
*/

ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
/*
     Update a running CRC-32 with the bytes buf[0..len-1] and return the
   updated CRC-32.  If buf is Z_NULL, this function returns the required
   initial value for the crc.  Pre- and post-conditioning (one's complement) is
   performed within this function so it shouldn't be done by the application.

   Usage example:

     uLong crc = crc32(0L, Z_NULL, 0);

     while (read_buffer(buffer, length) != EOF) {
       crc = crc32(crc, buffer, length);
     }
     if (crc != original_crc) error();
*/

/*
ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));

     Combine two CRC-32 check values into one.  For two sequences of bytes,
   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
   len2.
*/


                        /* various hacks, don't look :) */

/* deflateInit and inflateInit are macros to allow checking the zlib version
 * and the compiler's view of z_stream:
 */
ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
                                     const char *version, int stream_size));
ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
                                     const char *version, int stream_size));
ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
                                      int windowBits, int memLevel,
                                      int strategy, const char *version,
                                      int stream_size));
ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
                                      const char *version, int stream_size));
ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
                                         unsigned char FAR *window,
                                         const char *version,
                                         int stream_size));
#define deflateInit(strm, level) \
        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit(strm) \
        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
#define inflateInit2(strm, windowBits) \
        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
                      (int)sizeof(z_stream))
#define inflateBackInit(strm, windowBits, window) \
        inflateBackInit_((strm), (windowBits), (window), \
                      ZLIB_VERSION, (int)sizeof(z_stream))

#ifndef Z_SOLO

/* gzgetc() macro and its supporting function and exposed data structure.  Note
 * that the real internal state is much larger than the exposed structure.
 * This abbreviated structure exposes just enough for the gzgetc() macro.  The
 * user should not mess with these exposed elements, since their names or
 * behavior could change in the future, perhaps even capriciously.  They can
 * only be used by the gzgetc() macro.  You have been warned.
 */
struct gzFile_s {
    unsigned have;
    unsigned char *next;
    z_off64_t pos;
};
ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */
#ifdef Z_PREFIX_SET
#  undef z_gzgetc
#  define z_gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#else
#  define gzgetc(g) \
          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
#endif

/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
 * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
 * both are true, the application gets the *64 functions, and the regular
 * functions are changed to 64 bits) -- in case these are set on systems
 * without large file support, _LFS64_LARGEFILE must also be true
 */
#ifdef Z_LARGE64
   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
#endif

#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
#  ifdef Z_PREFIX_SET
#    define z_gzopen z_gzopen64
#    define z_gzseek z_gzseek64
#    define z_gztell z_gztell64
#    define z_gzoffset z_gzoffset64
#    define z_adler32_combine z_adler32_combine64
#    define z_crc32_combine z_crc32_combine64
#  else
#    define gzopen gzopen64
#    define gzseek gzseek64
#    define gztell gztell64
#    define gzoffset gzoffset64
#    define adler32_combine adler32_combine64
#    define crc32_combine crc32_combine64
#  endif
#  ifndef Z_LARGE64
     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
#  endif
#else
   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
#endif

#else /* Z_SOLO */

   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));

#endif /* !Z_SOLO */

/* hack for buggy compilers */
#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
    struct internal_state {int dummy;};
#endif

/* undocumented functions */
ZEXTERN const char   * ZEXPORT zError           OF((int));
ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
#if defined(_WIN32) && !defined(Z_SOLO)
ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
                                            const char *mode));
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
                                                  const char *format,
                                                  va_list va));
#  endif
#endif

#ifdef __cplusplus
}
#endif

#endif /* ZLIB_H */
rsync-3.2.7/zlib/crc32.c0000664000000000000000000003153613443225253013414 0ustar  rootroot/* crc32.c -- compute the CRC-32 of a data stream
 * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 *
 * Thanks to Rodney Brown  for his contribution of faster
 * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
 * tables for updating the shift register in one step with three exclusive-ors
 * instead of four steps with four exclusive-ors.  This results in about a
 * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
 */

/* @(#) $Id$ */

/*
  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
  protection on the static variables used to control the first-use generation
  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
  first call get_crc_table() to initialize the tables before allowing more than
  one thread to use crc32().

  DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
 */

#ifdef MAKECRCH
#  include 
#  ifndef DYNAMIC_CRC_TABLE
#    define DYNAMIC_CRC_TABLE
#  endif /* !DYNAMIC_CRC_TABLE */
#endif /* MAKECRCH */

#include "zutil.h"      /* for STDC and FAR definitions */

#define local static

/* Definitions for doing the crc four data bytes at a time. */
#if !defined(NOBYFOUR) && defined(Z_U4)
#  define BYFOUR
#endif
#ifdef BYFOUR
   local unsigned long crc32_little OF((unsigned long,
                        const unsigned char FAR *, unsigned));
   local unsigned long crc32_big OF((unsigned long,
                        const unsigned char FAR *, unsigned));
#  define TBLS 8
#else
#  define TBLS 1
#endif /* BYFOUR */

/* Local functions for crc concatenation */
local unsigned long gf2_matrix_times OF((unsigned long *mat,
                                         unsigned long vec));
local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));


#ifdef DYNAMIC_CRC_TABLE

local volatile int crc_table_empty = 1;
local z_crc_t FAR crc_table[TBLS][256];
local void make_crc_table OF((void));
#ifdef MAKECRCH
   local void write_table OF((FILE *, const z_crc_t FAR *));
#endif /* MAKECRCH */
/*
  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.

  Polynomials over GF(2) are represented in binary, one bit per coefficient,
  with the lowest powers in the most significant bit.  Then adding polynomials
  is just exclusive-or, and multiplying a polynomial by x is a right shift by
  one.  If we call the above polynomial p, and represent a byte as the
  polynomial q, also with the lowest power in the most significant bit (so the
  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
  where a mod b means the remainder after dividing a by b.

  This calculation is done using the shift-register method of multiplying and
  taking the remainder.  The register is initialized to zero, and for each
  incoming bit, x^32 is added mod p to the register if the bit is a one (where
  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
  x (which is shifting right by one and adding x^32 mod p if the bit shifted
  out is a one).  We start with the highest power (least significant bit) of
  q and repeat for all eight bits of q.

  The first table is simply the CRC of all possible eight bit values.  This is
  all the information needed to generate CRCs on data a byte at a time for all
  combinations of CRC register values and incoming bytes.  The remaining tables
  allow for word-at-a-time CRC calculation for both big-endian and little-
  endian machines, where a word is four bytes.
*/
local void make_crc_table()
{
    z_crc_t c;
    int n, k;
    z_crc_t poly;                       /* polynomial exclusive-or pattern */
    /* terms of polynomial defining this crc (except x^32): */
    static volatile int first = 1;      /* flag to limit concurrent making */
    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};

    /* See if another task is already doing this (not thread-safe, but better
       than nothing -- significantly reduces duration of vulnerability in
       case the advice about DYNAMIC_CRC_TABLE is ignored) */
    if (first) {
        first = 0;

        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
        poly = 0;
        for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
            poly |= (z_crc_t)1 << (31 - p[n]);

        /* generate a crc for every 8-bit value */
        for (n = 0; n < 256; n++) {
            c = (z_crc_t)n;
            for (k = 0; k < 8; k++)
                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
            crc_table[0][n] = c;
        }

#ifdef BYFOUR
        /* generate crc for each value followed by one, two, and three zeros,
           and then the byte reversal of those as well as the first table */
        for (n = 0; n < 256; n++) {
            c = crc_table[0][n];
            crc_table[4][n] = ZSWAP32(c);
            for (k = 1; k < 4; k++) {
                c = crc_table[0][c & 0xff] ^ (c >> 8);
                crc_table[k][n] = c;
                crc_table[k + 4][n] = ZSWAP32(c);
            }
        }
#endif /* BYFOUR */

        crc_table_empty = 0;
    }
    else {      /* not first */
        /* wait for the other guy to finish (not efficient, but rare) */
        while (crc_table_empty)
            ;
    }

#ifdef MAKECRCH
    /* write out CRC tables to crc32.h */
    {
        FILE *out;

        out = fopen("crc32.h", "w");
        if (out == NULL) return;
        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
        fprintf(out, "local const z_crc_t FAR ");
        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
        write_table(out, crc_table[0]);
#  ifdef BYFOUR
        fprintf(out, "#ifdef BYFOUR\n");
        for (k = 1; k < 8; k++) {
            fprintf(out, "  },\n  {\n");
            write_table(out, crc_table[k]);
        }
        fprintf(out, "#endif\n");
#  endif /* BYFOUR */
        fprintf(out, "  }\n};\n");
        fclose(out);
    }
#endif /* MAKECRCH */
}

#ifdef MAKECRCH
local void write_table(out, table)
    FILE *out;
    const z_crc_t FAR *table;
{
    int n;

    for (n = 0; n < 256; n++)
        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ",
                (unsigned long)(table[n]),
                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
}
#endif /* MAKECRCH */

#else /* !DYNAMIC_CRC_TABLE */
/* ========================================================================
 * Tables of CRC-32s of all single-byte values, made by make_crc_table().
 */
#include "crc32.h"
#endif /* DYNAMIC_CRC_TABLE */

/* =========================================================================
 * This function can be used by asm versions of crc32()
 */
const z_crc_t FAR * ZEXPORT get_crc_table()
{
#ifdef DYNAMIC_CRC_TABLE
    if (crc_table_empty)
        make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
    return (const z_crc_t FAR *)crc_table;
}

/* ========================================================================= */
#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1

/* ========================================================================= */
unsigned long ZEXPORT crc32(crc, buf, len)
    unsigned long crc;
    const unsigned char FAR *buf;
    uInt len;
{
    if (buf == Z_NULL) return 0UL;

#ifdef DYNAMIC_CRC_TABLE
    if (crc_table_empty)
        make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */

#ifdef BYFOUR
    if (sizeof(void *) == sizeof(ptrdiff_t)) {
        z_crc_t endian;

        endian = 1;
        if (*((unsigned char *)(&endian)))
            return crc32_little(crc, buf, len);
        else
            return crc32_big(crc, buf, len);
    }
#endif /* BYFOUR */
    crc = crc ^ 0xffffffffUL;
    while (len >= 8) {
        DO8;
        len -= 8;
    }
    if (len) do {
        DO1;
    } while (--len);
    return crc ^ 0xffffffffUL;
}

#ifdef BYFOUR

/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4

/* ========================================================================= */
local unsigned long crc32_little(crc, buf, len)
    unsigned long crc;
    const unsigned char FAR *buf;
    unsigned len;
{
    register z_crc_t c;
    register const z_crc_t FAR *buf4;

    c = (z_crc_t)crc;
    c = ~c;
    while (len && ((ptrdiff_t)buf & 3)) {
        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
        len--;
    }

    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
    while (len >= 32) {
        DOLIT32;
        len -= 32;
    }
    while (len >= 4) {
        DOLIT4;
        len -= 4;
    }
    buf = (const unsigned char FAR *)buf4;

    if (len) do {
        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
    } while (--len);
    c = ~c;
    return (unsigned long)c;
}

/* ========================================================================= */
#define DOBIG4 c ^= *buf4++; \
        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4

/* ========================================================================= */
local unsigned long crc32_big(crc, buf, len)
    unsigned long crc;
    const unsigned char FAR *buf;
    unsigned len;
{
    register z_crc_t c;
    register const z_crc_t FAR *buf4;

    c = ZSWAP32((z_crc_t)crc);
    c = ~c;
    while (len && ((ptrdiff_t)buf & 3)) {
        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
        len--;
    }

    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
    while (len >= 32) {
        DOBIG32;
        len -= 32;
    }
    while (len >= 4) {
        DOBIG4;
        len -= 4;
    }
    buf = (const unsigned char FAR *)buf4;

    if (len) do {
        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
    } while (--len);
    c = ~c;
    return (unsigned long)(ZSWAP32(c));
}

#endif /* BYFOUR */

#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */

/* ========================================================================= */
local unsigned long gf2_matrix_times(mat, vec)
    unsigned long *mat;
    unsigned long vec;
{
    unsigned long sum;

    sum = 0;
    while (vec) {
        if (vec & 1)
            sum ^= *mat;
        vec >>= 1;
        mat++;
    }
    return sum;
}

/* ========================================================================= */
local void gf2_matrix_square(square, mat)
    unsigned long *square;
    unsigned long *mat;
{
    int n;

    for (n = 0; n < GF2_DIM; n++)
        square[n] = gf2_matrix_times(mat, mat[n]);
}

/* ========================================================================= */
local uLong crc32_combine_(crc1, crc2, len2)
    uLong crc1;
    uLong crc2;
    z_off64_t len2;
{
    int n;
    unsigned long row;
    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */

    /* degenerate case (also disallow negative lengths) */
    if (len2 <= 0)
        return crc1;

    /* put operator for one zero bit in odd */
    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */
    row = 1;
    for (n = 1; n < GF2_DIM; n++) {
        odd[n] = row;
        row <<= 1;
    }

    /* put operator for two zero bits in even */
    gf2_matrix_square(even, odd);

    /* put operator for four zero bits in odd */
    gf2_matrix_square(odd, even);

    /* apply len2 zeros to crc1 (first square will put the operator for one
       zero byte, eight zero bits, in even) */
    do {
        /* apply zeros operator for this bit of len2 */
        gf2_matrix_square(even, odd);
        if (len2 & 1)
            crc1 = gf2_matrix_times(even, crc1);
        len2 >>= 1;

        /* if no more bits set, then done */
        if (len2 == 0)
            break;

        /* another iteration of the loop with odd and even swapped */
        gf2_matrix_square(odd, even);
        if (len2 & 1)
            crc1 = gf2_matrix_times(odd, crc1);
        len2 >>= 1;

        /* if no more bits set, then done */
    } while (len2 != 0);

    /* return combined crc */
    crc1 ^= crc2;
    return crc1;
}

/* ========================================================================= */
uLong ZEXPORT crc32_combine(crc1, crc2, len2)
    uLong crc1;
    uLong crc2;
    z_off_t len2;
{
    return crc32_combine_(crc1, crc2, len2);
}

uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
    uLong crc1;
    uLong crc2;
    z_off64_t len2;
{
    return crc32_combine_(crc1, crc2, len2);
}
rsync-3.2.7/zlib/inflate.h0000664000000000000000000001445312155261705014127 0ustar  rootroot/* inflate.h -- internal inflate state definition
 * Copyright (C) 1995-2009 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* define NO_GZIP when compiling if you want to disable gzip header and
   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
   the crc code when it is not needed.  For shared libraries, gzip decoding
   should be left enabled. */
#ifndef NO_GZIP
#  define GUNZIP
#endif

#ifdef BAD /* For AIX */
#undef BAD
#endif

/* Possible inflate modes between inflate() calls */
typedef enum {
    HEAD,       /* i: waiting for magic header */
    FLAGS,      /* i: waiting for method and flags (gzip) */
    TIME,       /* i: waiting for modification time (gzip) */
    OS,         /* i: waiting for extra flags and operating system (gzip) */
    EXLEN,      /* i: waiting for extra length (gzip) */
    EXTRA,      /* i: waiting for extra bytes (gzip) */
    NAME,       /* i: waiting for end of file name (gzip) */
    COMMENT,    /* i: waiting for end of comment (gzip) */
    HCRC,       /* i: waiting for header crc (gzip) */
    DICTID,     /* i: waiting for dictionary check value */
    DICT,       /* waiting for inflateSetDictionary() call */
        TYPE,       /* i: waiting for type bits, including last-flag bit */
        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
        STORED,     /* i: waiting for stored size (length and complement) */
        COPY_,      /* i/o: same as COPY below, but only first time in */
        COPY,       /* i/o: waiting for input or output to copy stored block */
        TABLE,      /* i: waiting for dynamic block table lengths */
        LENLENS,    /* i: waiting for code length code lengths */
        CODELENS,   /* i: waiting for length/lit and distance code lengths */
            LEN_,       /* i: same as LEN below, but only first time in */
            LEN,        /* i: waiting for length/lit/eob code */
            LENEXT,     /* i: waiting for length extra bits */
            DIST,       /* i: waiting for distance code */
            DISTEXT,    /* i: waiting for distance extra bits */
            MATCH,      /* o: waiting for output space to copy string */
            LIT,        /* o: waiting for output space to write literal */
    CHECK,      /* i: waiting for 32-bit check value */
    LENGTH,     /* i: waiting for 32-bit length (gzip) */
    DONE,       /* finished check, done -- remain here until reset */
    BAD,        /* got a data error -- remain here until reset */
    MEM,        /* got an inflate() memory error -- remain here until reset */
    SYNC        /* looking for synchronization bytes to restart inflate() */
} inflate_mode;

/*
    State transitions between above modes -

    (most modes can go to BAD or MEM on error -- not shown for clarity)

    Process header:
        HEAD -> (gzip) or (zlib) or (raw)
        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
                  HCRC -> TYPE
        (zlib) -> DICTID or TYPE
        DICTID -> DICT -> TYPE
        (raw) -> TYPEDO
    Read deflate blocks:
            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
            STORED -> COPY_ -> COPY -> TYPE
            TABLE -> LENLENS -> CODELENS -> LEN_
            LEN_ -> LEN
    Read deflate codes in fixed or dynamic block:
                LEN -> LENEXT or LIT or TYPE
                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
                LIT -> LEN
    Process trailer:
        CHECK -> LENGTH -> DONE
 */

/* state maintained between inflate() calls.  Approximately 10K bytes. */
struct inflate_state {
    inflate_mode mode;          /* current inflate mode */
    int last;                   /* true if processing last block */
    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
    int havedict;               /* true if dictionary provided */
    int flags;                  /* gzip header method and flags (0 if zlib) */
    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
    unsigned long check;        /* protected copy of check value */
    unsigned long total;        /* protected copy of output count */
    gz_headerp head;            /* where to save gzip header information */
        /* sliding window */
    unsigned wbits;             /* log base 2 of requested window size */
    unsigned wsize;             /* window size or zero if not using window */
    unsigned whave;             /* valid bytes in the window */
    unsigned wnext;             /* window write index */
    unsigned char FAR *window;  /* allocated sliding window, if needed */
        /* bit accumulator */
    unsigned long hold;         /* input bit accumulator */
    unsigned bits;              /* number of bits in "in" */
        /* for string and stored block copying */
    unsigned length;            /* literal or length of data to copy */
    unsigned offset;            /* distance back to copy string from */
        /* for table and code decoding */
    unsigned extra;             /* extra bits needed */
        /* fixed and dynamic code tables */
    code const FAR *lencode;    /* starting table for length/literal codes */
    code const FAR *distcode;   /* starting table for distance codes */
    unsigned lenbits;           /* index bits for lencode */
    unsigned distbits;          /* index bits for distcode */
        /* dynamic table building */
    unsigned ncode;             /* number of code length code lengths */
    unsigned nlen;              /* number of length code lengths */
    unsigned ndist;             /* number of distance code lengths */
    unsigned have;              /* number of code lengths in lens[] */
    code FAR *next;             /* next available space in codes[] */
    unsigned short lens[320];   /* temporary storage for code lengths */
    unsigned short work[288];   /* work area for code table building */
    code codes[ENOUGH];         /* space for code tables */
    int sane;                   /* if false, allow invalid distance too far */
    int back;                   /* bits back of last unprocessed length/lit */
    unsigned was;               /* initial length of match */
};
rsync-3.2.7/zlib/inftrees.h0000664000000000000000000000556012155261705014323 0ustar  rootroot/* inftrees.h -- header to use inftrees.c
 * Copyright (C) 1995-2005, 2010 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* Structure for decoding tables.  Each entry provides either the
   information needed to do the operation requested by the code that
   indexed that table entry, or it provides a pointer to another
   table that indexes more bits of the code.  op indicates whether
   the entry is a pointer to another table, a literal, a length or
   distance, an end-of-block, or an invalid code.  For a table
   pointer, the low four bits of op is the number of index bits of
   that table.  For a length or distance, the low four bits of op
   is the number of extra bits to get after the code.  bits is
   the number of bits in this code or part of the code to drop off
   of the bit buffer.  val is the actual byte to output in the case
   of a literal, the base length or distance, or the offset from
   the current table to the next table.  Each entry is four bytes. */
typedef struct {
    unsigned char op;           /* operation, extra bits, table bits */
    unsigned char bits;         /* bits in this part of the code */
    unsigned short val;         /* offset in table or code value */
} code;

/* op values as set by inflate_table():
    00000000 - literal
    0000tttt - table link, tttt != 0 is the number of table index bits
    0001eeee - length or distance, eeee is the number of extra bits
    01100000 - end of block
    01000000 - invalid code
 */

/* Maximum size of the dynamic table.  The maximum number of code structures is
   1444, which is the sum of 852 for literal/length codes and 592 for distance
   codes.  These values were found by exhaustive searches using the program
   examples/enough.c found in the zlib distribtution.  The arguments to that
   program are the number of symbols, the initial root table size, and the
   maximum bit length of a code.  "enough 286 9 15" for literal/length codes
   returns returns 852, and "enough 30 6 15" for distance codes returns 592.
   The initial root table size (9 or 6) is found in the fifth argument of the
   inflate_table() calls in inflate.c and infback.c.  If the root table size is
   changed, then these maximum sizes would be need to be recalculated and
   updated. */
#define ENOUGH_LENS 852
#define ENOUGH_DISTS 592
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)

/* Type of code to build for inflate_table() */
typedef enum {
    CODES,
    LENS,
    DISTS
} codetype;

int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
                             unsigned codes, code FAR * FAR *table,
                             unsigned FAR *bits, unsigned short FAR *work));
rsync-3.2.7/zlib/crc32.h0000664000000000000000000007354212155261705013425 0ustar  rootroot/* crc32.h -- tables for rapid CRC calculation
 * Generated automatically by crc32.c
 */

local const z_crc_t FAR crc_table[TBLS][256] =
{
  {
    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
    0x2d02ef8dUL
#ifdef BYFOUR
  },
  {
    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
    0x9324fd72UL
  },
  {
    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
    0xbe9834edUL
  },
  {
    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
    0xde0506f1UL
  },
  {
    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
    0x8def022dUL
  },
  {
    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
    0x72fd2493UL
  },
  {
    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
    0xed3498beUL
  },
  {
    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
    0xf10605deUL
#endif
  }
};
rsync-3.2.7/zlib/dummy.in0000664000000000000000000000014606524251175014014 0ustar  rootrootThis is a dummy file to ensure that the lib directory gets created
by configure when a VPATH is used.
rsync-3.2.7/zlib/zutil.c0000664000000000000000000001706012155261705013644 0ustar  rootroot/* zutil.c -- target dependent utility functions for the compression library
 * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#include "zutil.h"
#ifndef Z_SOLO
#  include "gzguts.h"
#endif

#ifndef NO_DUMMY_DECL
struct internal_state      {int dummy;}; /* for buggy compilers */
#endif

z_const char * const z_errmsg[10] = {
"need dictionary",     /* Z_NEED_DICT       2  */
"stream end",          /* Z_STREAM_END      1  */
"",                    /* Z_OK              0  */
"file error",          /* Z_ERRNO         (-1) */
"stream error",        /* Z_STREAM_ERROR  (-2) */
"data error",          /* Z_DATA_ERROR    (-3) */
"insufficient memory", /* Z_MEM_ERROR     (-4) */
"buffer error",        /* Z_BUF_ERROR     (-5) */
"incompatible version",/* Z_VERSION_ERROR (-6) */
""};


const char * ZEXPORT zlibVersion()
{
    return ZLIB_VERSION;
}

uLong ZEXPORT zlibCompileFlags()
{
    uLong flags;

    flags = 0;
    switch ((int)(sizeof(uInt))) {
    case 2:     break;				/* CONSTANT CONDITION */
    case 4:     flags += 1;     break;		/* CONSTANT CONDITION */
    case 8:     flags += 2;     break;		/* CONSTANT CONDITION */
    default:    flags += 3;
    }
    switch ((int)(sizeof(uLong))) {
    case 2:     break;				/* CONSTANT CONDITION */
    case 4:     flags += 1 << 2;        break;	/* CONSTANT CONDITION */
    case 8:     flags += 2 << 2;        break;	/* CONSTANT CONDITION */
    default:    flags += 3 << 2;
    }
    switch ((int)(sizeof(voidpf))) {
    case 2:     break;				/* CONSTANT CONDITION */
    case 4:     flags += 1 << 4;        break;	/* CONSTANT CONDITION */
    case 8:     flags += 2 << 4;        break;	/* CONSTANT CONDITION */
    default:    flags += 3 << 4;
    }
    switch ((int)(sizeof(z_off_t))) {
    case 2:     break;				/* CONSTANT CONDITION */
    case 4:     flags += 1 << 6;        break;	/* CONSTANT CONDITION */
    case 8:     flags += 2 << 6;        break;	/* CONSTANT CONDITION */
    default:    flags += 3 << 6;
    }
#ifdef DEBUG
    flags += 1 << 8;
#endif
#if defined(ASMV) || defined(ASMINF)
    flags += 1 << 9;
#endif
#ifdef ZLIB_WINAPI
    flags += 1 << 10;
#endif
#ifdef BUILDFIXED
    flags += 1 << 12;
#endif
#ifdef DYNAMIC_CRC_TABLE
    flags += 1 << 13;
#endif
#ifdef NO_GZCOMPRESS
    flags += 1L << 16;
#endif
#ifdef NO_GZIP
    flags += 1L << 17;
#endif
#ifdef PKZIP_BUG_WORKAROUND
    flags += 1L << 20;
#endif
#ifdef FASTEST
    flags += 1L << 21;
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifdef NO_vsnprintf
    flags += 1L << 25;
#    ifdef HAS_vsprintf_void
    flags += 1L << 26;
#    endif
#  else
#    ifdef HAS_vsnprintf_void
    flags += 1L << 26;
#    endif
#  endif
#else
    flags += 1L << 24;
#  ifdef NO_snprintf
    flags += 1L << 25;
#    ifdef HAS_sprintf_void
    flags += 1L << 26;
#    endif
#  else
#    ifdef HAS_snprintf_void
    flags += 1L << 26;
#    endif
#  endif
#endif
    return flags;
}

#ifdef DEBUG

#  ifndef verbose
#    define verbose 0
#  endif
int ZLIB_INTERNAL z_verbose = verbose;

void ZLIB_INTERNAL z_error (m)
    char *m;
{
    fprintf(stderr, "%s\n", m);
    exit(1);
}
#endif

/* exported to allow conversion of error code to string for compress() and
 * uncompress()
 */
const char * ZEXPORT zError(err)
    int err;
{
    return ERR_MSG(err);
}

#if defined(_WIN32_WCE)
    /* The Microsoft C Run-Time Library for Windows CE doesn't have
     * errno.  We define it as a global variable to simplify porting.
     * Its value is always 0 and should not be used.
     */
    int errno = 0;
#endif

#ifndef HAVE_MEMCPY

void ZLIB_INTERNAL zmemcpy(dest, source, len)
    Bytef* dest;
    const Bytef* source;
    uInt  len;
{
    if (len == 0) return;
    do {
        *dest++ = *source++; /* ??? to be unrolled */
    } while (--len != 0);
}

int ZLIB_INTERNAL zmemcmp(s1, s2, len)
    const Bytef* s1;
    const Bytef* s2;
    uInt  len;
{
    uInt j;

    for (j = 0; j < len; j++) {
        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
    }
    return 0;
}

void ZLIB_INTERNAL zmemzero(dest, len)
    Bytef* dest;
    uInt  len;
{
    if (len == 0) return;
    do {
        *dest++ = 0;  /* ??? to be unrolled */
    } while (--len != 0);
}
#endif

#ifndef Z_SOLO

#ifdef SYS16BIT

#ifdef __TURBOC__
/* Turbo C in 16-bit mode */

#  define MY_ZCALLOC

/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
 * and farmalloc(64K) returns a pointer with an offset of 8, so we
 * must fix the pointer. Warning: the pointer must be put back to its
 * original form in order to free it, use zcfree().
 */

#define MAX_PTR 10
/* 10*64K = 640K */

local int next_ptr = 0;

typedef struct ptr_table_s {
    voidpf org_ptr;
    voidpf new_ptr;
} ptr_table;

local ptr_table table[MAX_PTR];
/* This table is used to remember the original form of pointers
 * to large buffers (64K). Such pointers are normalized with a zero offset.
 * Since MSDOS is not a preemptive multitasking OS, this table is not
 * protected from concurrent access. This hack doesn't work anyway on
 * a protected system like OS/2. Use Microsoft C instead.
 */

voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
{
    voidpf buf = opaque; /* just to make some compilers happy */
    ulg bsize = (ulg)items*size;

    /* If we allocate less than 65520 bytes, we assume that farmalloc
     * will return a usable pointer which doesn't have to be normalized.
     */
    if (bsize < 65520L) {
        buf = farmalloc(bsize);
        if (*(ush*)&buf != 0) return buf;
    } else {
        buf = farmalloc(bsize + 16L);
    }
    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
    table[next_ptr].org_ptr = buf;

    /* Normalize the pointer to seg:0 */
    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
    *(ush*)&buf = 0;
    table[next_ptr++].new_ptr = buf;
    return buf;
}

void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
    int n;
    if (*(ush*)&ptr != 0) { /* object < 64K */
        farfree(ptr);
        return;
    }
    /* Find the original pointer */
    for (n = 0; n < next_ptr; n++) {
        if (ptr != table[n].new_ptr) continue;

        farfree(table[n].org_ptr);
        while (++n < next_ptr) {
            table[n-1] = table[n];
        }
        next_ptr--;
        return;
    }
    ptr = opaque; /* just to make some compilers happy */
    Assert(0, "zcfree: ptr not found");
}

#endif /* __TURBOC__ */


#ifdef M_I86
/* Microsoft C in 16-bit mode */

#  define MY_ZCALLOC

#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
#  define _halloc  halloc
#  define _hfree   hfree
#endif

voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
{
    if (opaque) opaque = 0; /* to make compiler happy */
    return _halloc((long)items, size);
}

void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
    if (opaque) opaque = 0; /* to make compiler happy */
    _hfree(ptr);
}

#endif /* M_I86 */

#endif /* SYS16BIT */


#ifndef MY_ZCALLOC /* Any system without a special alloc function */

#ifndef STDC
extern voidp  malloc OF((uInt size));
extern voidp  calloc OF((uInt items, uInt size));
extern void   free   OF((voidpf ptr));
#endif

voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
    voidpf opaque;
    unsigned items;
    unsigned size;
{
    if (opaque) items += size - size; /* make compiler happy */
    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
                              (voidpf)calloc(items, size);
}

void ZLIB_INTERNAL zcfree (opaque, ptr)
    voidpf opaque;
    voidpf ptr;
{
    free(ptr);
    if (opaque) return; /* make compiler happy */
}

#endif /* MY_ZCALLOC */

#endif /* !Z_SOLO */
rsync-3.2.7/zlib/trees.h0000664000000000000000000002043012155261705013617 0ustar  rootroot/* header created automatically with -DGEN_TREES_H */

local const ct_data static_ltree[L_CODES+2] = {
{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
};

local const ct_data static_dtree[D_CODES] = {
{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
};

const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};

const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};

local const int base_length[LENGTH_CODES] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
64, 80, 96, 112, 128, 160, 192, 224, 0
};

local const int base_dist[D_CODES] = {
    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
};

rsync-3.2.7/zlib/ChangeLog0000664000000000000000000022516212155261705014107 0ustar  rootroot
                ChangeLog file for zlib

Changes in 1.2.8 (28 Apr 2013)
- Update contrib/minizip/iowin32.c for Windows RT [Vollant]
- Do not force Z_CONST for C++
- Clean up contrib/vstudio [Ro§]
- Correct spelling error in zlib.h
- Fix mixed line endings in contrib/vstudio

Changes in 1.2.7.3 (13 Apr 2013)
- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc

Changes in 1.2.7.2 (13 Apr 2013)
- Change check for a four-byte type back to hexadecimal
- Fix typo in win32/Makefile.msc
- Add casts in gzwrite.c for pointer differences

Changes in 1.2.7.1 (24 Mar 2013)
- Replace use of unsafe string functions with snprintf if available
- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink]
- Fix gzgetc undefine when Z_PREFIX set [Turk]
- Eliminate use of mktemp in Makefile (not always available)
- Fix bug in 'F' mode for gzopen()
- Add inflateGetDictionary() function
- Correct comment in deflate.h
- Use _snprintf for snprintf in Microsoft C
- On Darwin, only use /usr/bin/libtool if libtool is not Apple
- Delete "--version" file if created by "ar --version" [Richard G.]
- Fix configure check for veracity of compiler error return codes
- Fix CMake compilation of static lib for MSVC2010 x64
- Remove unused variable in infback9.c
- Fix argument checks in gzlog_compress() and gzlog_write()
- Clean up the usage of z_const and respect const usage within zlib
- Clean up examples/gzlog.[ch] comparisons of different types
- Avoid shift equal to bits in type (caused endless loop)
- Fix unintialized value bug in gzputc() introduced by const patches
- Fix memory allocation error in examples/zran.c [Nor]
- Fix bug where gzopen(), gzclose() would write an empty file
- Fix bug in gzclose() when gzwrite() runs out of memory
- Check for input buffer malloc failure in examples/gzappend.c
- Add note to contrib/blast to use binary mode in stdio
- Fix comparisons of differently signed integers in contrib/blast
- Check for invalid code length codes in contrib/puff
- Fix serious but very rare decompression bug in inftrees.c
- Update inflateBack() comments, since inflate() can be faster
- Use underscored I/O function names for WINAPI_FAMILY
- Add _tr_flush_bits to the external symbols prefixed by --zprefix
- Add contrib/vstudio/vc10 pre-build step for static only
- Quote --version-script argument in CMakeLists.txt
- Don't specify --version-script on Apple platforms in CMakeLists.txt
- Fix casting error in contrib/testzlib/testzlib.c
- Fix types in contrib/minizip to match result of get_crc_table()
- Simplify contrib/vstudio/vc10 with 'd' suffix
- Add TOP support to win32/Makefile.msc
- Suport i686 and amd64 assembler builds in CMakeLists.txt
- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
- Add vc11 and vc12 build files to contrib/vstudio
- Add gzvprintf() as an undocumented function in zlib
- Fix configure for Sun shell
- Remove runtime check in configure for four-byte integer type
- Add casts and consts to ease user conversion to C++
- Add man pages for minizip and miniunzip
- In Makefile uninstall, don't rm if preceding cd fails
- Do not return Z_BUF_ERROR if deflateParam() has nothing to write

Changes in 1.2.7 (2 May 2012)
- Replace use of memmove() with a simple copy for portability
- Test for existence of strerror
- Restore gzgetc_ for backward compatibility with 1.2.6
- Fix build with non-GNU make on Solaris
- Require gcc 4.0 or later on Mac OS X to use the hidden attribute
- Include unistd.h for Watcom C
- Use __WATCOMC__ instead of __WATCOM__
- Do not use the visibility attribute if NO_VIZ defined
- Improve the detection of no hidden visibility attribute
- Avoid using __int64 for gcc or solo compilation
- Cast to char * in gzprintf to avoid warnings [Zinser]
- Fix make_vms.com for VAX [Zinser]
- Don't use library or built-in byte swaps
- Simplify test and use of gcc hidden attribute
- Fix bug in gzclose_w() when gzwrite() fails to allocate memory
- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen()
- Fix bug in test/minigzip.c for configure --solo
- Fix contrib/vstudio project link errors [Mohanathas]
- Add ability to choose the builder in make_vms.com [Schweda]
- Add DESTDIR support to mingw32 win32/Makefile.gcc
- Fix comments in win32/Makefile.gcc for proper usage
- Allow overriding the default install locations for cmake
- Generate and install the pkg-config file with cmake
- Build both a static and a shared version of zlib with cmake
- Include version symbols for cmake builds
- If using cmake with MSVC, add the source directory to the includes
- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta]
- Move obsolete emx makefile to old [Truta]
- Allow the use of -Wundef when compiling or using zlib
- Avoid the use of the -u option with mktemp
- Improve inflate() documentation on the use of Z_FINISH
- Recognize clang as gcc
- Add gzopen_w() in Windows for wide character path names
- Rename zconf.h in CMakeLists.txt to move it out of the way
- Add source directory in CMakeLists.txt for building examples
- Look in build directory for zlib.pc in CMakeLists.txt
- Remove gzflags from zlibvc.def in vc9 and vc10
- Fix contrib/minizip compilation in the MinGW environment
- Update ./configure for Solaris, support --64 [Mooney]
- Remove -R. from Solaris shared build (possible security issue)
- Avoid race condition for parallel make (-j) running example
- Fix type mismatch between get_crc_table() and crc_table
- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler]
- Fix the path to zlib.map in CMakeLists.txt
- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe]
- Add instructions to win32/Makefile.gcc for shared install [Torri]

Changes in 1.2.6.1 (12 Feb 2012)
- Avoid the use of the Objective-C reserved name "id"
- Include io.h in gzguts.h for Microsoft compilers
- Fix problem with ./configure --prefix and gzgetc macro
- Include gz_header definition when compiling zlib solo
- Put gzflags() functionality back in zutil.c
- Avoid library header include in crc32.c for Z_SOLO
- Use name in GCC_CLASSIC as C compiler for coverage testing, if set
- Minor cleanup in contrib/minizip/zip.c [Vollant]
- Update make_vms.com [Zinser]
- Remove unnecessary gzgetc_ function
- Use optimized byte swap operations for Microsoft and GNU [Snyder]
- Fix minor typo in zlib.h comments [Rzesniowiecki]

Changes in 1.2.6 (29 Jan 2012)
- Update the Pascal interface in contrib/pascal
- Fix function numbers for gzgetc_ in zlibvc.def files
- Fix configure.ac for contrib/minizip [Schiffer]
- Fix large-entry detection in minizip on 64-bit systems [Schiffer]
- Have ./configure use the compiler return code for error indication
- Fix CMakeLists.txt for cross compilation [McClure]
- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes]
- Fix compilation of contrib/minizip on FreeBSD [Marquez]
- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath]
- Include io.h for Turbo C / Borland C on all platforms [Truta]
- Make version explicit in contrib/minizip/configure.ac [Bosmans]
- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant]
- Minor cleanup up contrib/minizip/unzip.c [Vollant]
- Fix bug when compiling minizip with C++ [Vollant]
- Protect for long name and extra fields in contrib/minizip [Vollant]
- Avoid some warnings in contrib/minizip [Vollant]
- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip
- Add missing libs to minizip linker command
- Add support for VPATH builds in contrib/minizip
- Add an --enable-demos option to contrib/minizip/configure
- Add the generation of configure.log by ./configure
- Exit when required parameters not provided to win32/Makefile.gcc
- Have gzputc return the character written instead of the argument
- Use the -m option on ldconfig for BSD systems [Tobias]
- Correct in zlib.map when deflateResetKeep was added

Changes in 1.2.5.3 (15 Jan 2012)
- Restore gzgetc function for binary compatibility
- Do not use _lseeki64 under Borland C++ [Truta]
- Update win32/Makefile.msc to build test/*.c [Truta]
- Remove old/visualc6 given CMakefile and other alternatives
- Update AS400 build files and documentation [Monnerat]
- Update win32/Makefile.gcc to build test/*.c [Truta]
- Permit stronger flushes after Z_BLOCK flushes
- Avoid extraneous empty blocks when doing empty flushes
- Permit Z_NULL arguments to deflatePending
- Allow deflatePrime() to insert bits in the middle of a stream
- Remove second empty static block for Z_PARTIAL_FLUSH
- Write out all of the available bits when using Z_BLOCK
- Insert the first two strings in the hash table after a flush

Changes in 1.2.5.2 (17 Dec 2011)
- fix ld error: unable to find version dependency 'ZLIB_1.2.5'
- use relative symlinks for shared libs
- Avoid searching past window for Z_RLE strategy
- Assure that high-water mark initialization is always applied in deflate
- Add assertions to fill_window() in deflate.c to match comments
- Update python link in README
- Correct spelling error in gzread.c
- Fix bug in gzgets() for a concatenated empty gzip stream
- Correct error in comment for gz_make()
- Change gzread() and related to ignore junk after gzip streams
- Allow gzread() and related to continue after gzclearerr()
- Allow gzrewind() and gzseek() after a premature end-of-file
- Simplify gzseek() now that raw after gzip is ignored
- Change gzgetc() to a macro for speed (~40% speedup in testing)
- Fix gzclose() to return the actual error last encountered
- Always add large file support for windows
- Include zconf.h for windows large file support
- Include zconf.h.cmakein for windows large file support
- Update zconf.h.cmakein on make distclean
- Merge vestigial vsnprintf determination from zutil.h to gzguts.h
- Clarify how gzopen() appends in zlib.h comments
- Correct documentation of gzdirect() since junk at end now ignored
- Add a transparent write mode to gzopen() when 'T' is in the mode
- Update python link in zlib man page
- Get inffixed.h and MAKEFIXED result to match
- Add a ./config --solo option to make zlib subset with no libary use
- Add undocumented inflateResetKeep() function for CAB file decoding
- Add --cover option to ./configure for gcc coverage testing
- Add #define ZLIB_CONST option to use const in the z_stream interface
- Add comment to gzdopen() in zlib.h to use dup() when using fileno()
- Note behavior of uncompress() to provide as much data as it can
- Add files in contrib/minizip to aid in building libminizip
- Split off AR options in Makefile.in and configure
- Change ON macro to Z_ARG to avoid application conflicts
- Facilitate compilation with Borland C++ for pragmas and vsnprintf
- Include io.h for Turbo C / Borland C++
- Move example.c and minigzip.c to test/
- Simplify incomplete code table filling in inflate_table()
- Remove code from inflate.c and infback.c that is impossible to execute
- Test the inflate code with full coverage
- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw)
- Add deflateResetKeep and fix inflateResetKeep to retain dictionary
- Fix gzwrite.c to accommodate reduced memory zlib compilation
- Have inflate() with Z_FINISH avoid the allocation of a window
- Do not set strm->adler when doing raw inflate
- Fix gzeof() to behave just like feof() when read is not past end of file
- Fix bug in gzread.c when end-of-file is reached
- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF
- Document gzread() capability to read concurrently written files
- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo]

Changes in 1.2.5.1 (10 Sep 2011)
- Update FAQ entry on shared builds (#13)
- Avoid symbolic argument to chmod in Makefile.in
- Fix bug and add consts in contrib/puff [Oberhumer]
- Update contrib/puff/zeros.raw test file to have all block types
- Add full coverage test for puff in contrib/puff/Makefile
- Fix static-only-build install in Makefile.in
- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno]
- Add libz.a dependency to shared in Makefile.in for parallel builds
- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out
- Replace $(...) with `...` in configure for non-bash sh [Bowler]
- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen]
- Add solaris* to Linux* in configure to allow gcc use [Groffen]
- Add *bsd* to Linux* case in configure [Bar-Lev]
- Add inffast.obj to dependencies in win32/Makefile.msc
- Correct spelling error in deflate.h [Kohler]
- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc
- Add test to configure for GNU C looking for gcc in output of $cc -v
- Add zlib.pc generation to win32/Makefile.gcc [Weigelt]
- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not
- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense
- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser)
- Make stronger test in zconf.h to include unistd.h for LFS
- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack]
- Fix zlib.h LFS support when Z_PREFIX used
- Add updated as400 support (removed from old) [Monnerat]
- Avoid deflate sensitivity to volatile input data
- Avoid division in adler32_combine for NO_DIVIDE
- Clarify the use of Z_FINISH with deflateBound() amount of space
- Set binary for output file in puff.c
- Use u4 type for crc_table to avoid conversion warnings
- Apply casts in zlib.h to avoid conversion warnings
- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
- Improve inflateSync() documentation to note indeterminancy
- Add deflatePending() function to return the amount of pending output
- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
- Add a check in configure for stdarg.h, use for gzprintf()
- Check that pointers fit in ints when gzprint() compiled old style
- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
- Add debug records in assmebler code [Londer]
- Update RFC references to use http://tools.ietf.org/html/... [Li]
- Add --archs option, use of libtool to configure for Mac OS X [Borstel]

Changes in 1.2.5 (19 Apr 2010)
- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev]
- Default to libdir as sharedlibdir in configure [Nieder]
- Update copyright dates on modified source files
- Update trees.c to be able to generate modified trees.h
- Exit configure for MinGW, suggesting win32/Makefile.gcc
- Check for NULL path in gz_open [Homurlu]

Changes in 1.2.4.5 (18 Apr 2010)
- Set sharedlibdir in configure [Torok]
- Set LDFLAGS in Makefile.in [Bar-Lev]
- Avoid mkdir objs race condition in Makefile.in [Bowler]
- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays
- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C
- Don't use hidden attribute when it is a warning generator (e.g. Solaris)

Changes in 1.2.4.4 (18 Apr 2010)
- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok]
- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty
- Try to use bash or ksh regardless of functionality of /bin/sh
- Fix configure incompatibility with NetBSD sh
- Remove attempt to run under bash or ksh since have better NetBSD fix
- Fix win32/Makefile.gcc for MinGW [Bar-Lev]
- Add diagnostic messages when using CROSS_PREFIX in configure
- Added --sharedlibdir option to configure [Weigelt]
- Use hidden visibility attribute when available [Frysinger]

Changes in 1.2.4.3 (10 Apr 2010)
- Only use CROSS_PREFIX in configure for ar and ranlib if they exist
- Use CROSS_PREFIX for nm [Bar-Lev]
- Assume _LARGEFILE64_SOURCE defined is equivalent to true
- Avoid use of undefined symbols in #if with && and ||
- Make *64 prototypes in gzguts.h consistent with functions
- Add -shared load option for MinGW in configure [Bowler]
- Move z_off64_t to public interface, use instead of off64_t
- Remove ! from shell test in configure (not portable to Solaris)
- Change +0 macro tests to -0 for possibly increased portability

Changes in 1.2.4.2 (9 Apr 2010)
- Add consistent carriage returns to readme.txt's in masmx86 and masmx64
- Really provide prototypes for *64 functions when building without LFS
- Only define unlink() in minigzip.c if unistd.h not included
- Update README to point to contrib/vstudio project files
- Move projects/vc6 to old/ and remove projects/
- Include stdlib.h in minigzip.c for setmode() definition under WinCE
- Clean up assembler builds in win32/Makefile.msc [Rowe]
- Include sys/types.h for Microsoft for off_t definition
- Fix memory leak on error in gz_open()
- Symbolize nm as $NM in configure [Weigelt]
- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt]
- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined
- Fix bug in gzeof() to take into account unused input data
- Avoid initialization of structures with variables in puff.c
- Updated win32/README-WIN32.txt [Rowe]

Changes in 1.2.4.1 (28 Mar 2010)
- Remove the use of [a-z] constructs for sed in configure [gentoo 310225]
- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech]
- Restore "for debugging" comment on sprintf() in gzlib.c
- Remove fdopen for MVS from gzguts.h
- Put new README-WIN32.txt in win32 [Rowe]
- Add check for shell to configure and invoke another shell if needed
- Fix big fat stinking bug in gzseek() on uncompressed files
- Remove vestigial F_OPEN64 define in zutil.h
- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE
- Avoid errors on non-LFS systems when applications define LFS macros
- Set EXE to ".exe" in configure for MINGW [Kahle]
- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill]
- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev]
- Add DLL install in win32/makefile.gcc [Bar-Lev]
- Allow Linux* or linux* from uname in configure [Bar-Lev]
- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev]
- Add cross-compilation prefixes to configure [Bar-Lev]
- Match type exactly in gz_load() invocation in gzread.c
- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func
- Provide prototypes for *64 functions when building zlib without LFS
- Don't use -lc when linking shared library on MinGW
- Remove errno.h check in configure and vestigial errno code in zutil.h

Changes in 1.2.4 (14 Mar 2010)
- Fix VER3 extraction in configure for no fourth subversion
- Update zlib.3, add docs to Makefile.in to make .pdf out of it
- Add zlib.3.pdf to distribution
- Don't set error code in gzerror() if passed pointer is NULL
- Apply destination directory fixes to CMakeLists.txt [Lowman]
- Move #cmakedefine's to a new zconf.in.cmakein
- Restore zconf.h for builds that don't use configure or cmake
- Add distclean to dummy Makefile for convenience
- Update and improve INDEX, README, and FAQ
- Update CMakeLists.txt for the return of zconf.h [Lowman]
- Update contrib/vstudio/vc9 and vc10 [Vollant]
- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc
- Apply license and readme changes to contrib/asm686 [Raiter]
- Check file name lengths and add -c option in minigzip.c [Li]
- Update contrib/amd64 and contrib/masmx86/ [Vollant]
- Avoid use of "eof" parameter in trees.c to not shadow library variable
- Update make_vms.com for removal of zlibdefs.h [Zinser]
- Update assembler code and vstudio projects in contrib [Vollant]
- Remove outdated assembler code contrib/masm686 and contrib/asm586
- Remove old vc7 and vc8 from contrib/vstudio
- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe]
- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open()
- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant]
- Remove *64 functions from win32/zlib.def (they're not 64-bit yet)
- Fix bug in void-returning vsprintf() case in gzwrite.c
- Fix name change from inflate.h in contrib/inflate86/inffas86.c
- Check if temporary file exists before removing in make_vms.com [Zinser]
- Fix make install and uninstall for --static option
- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta]
- Update readme.txt in contrib/masmx64 and masmx86 to assemble

Changes in 1.2.3.9 (21 Feb 2010)
- Expunge gzio.c
- Move as400 build information to old
- Fix updates in contrib/minizip and contrib/vstudio
- Add const to vsnprintf test in configure to avoid warnings [Weigelt]
- Delete zconf.h (made by configure) [Weigelt]
- Change zconf.in.h to zconf.h.in per convention [Weigelt]
- Check for NULL buf in gzgets()
- Return empty string for gzgets() with len == 1 (like fgets())
- Fix description of gzgets() in zlib.h for end-of-file, NULL return
- Update minizip to 1.1 [Vollant]
- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c
- Note in zlib.h that gzerror() should be used to distinguish from EOF
- Remove use of snprintf() from gzlib.c
- Fix bug in gzseek()
- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant]
- Fix zconf.h generation in CMakeLists.txt [Lowman]
- Improve comments in zconf.h where modified by configure

Changes in 1.2.3.8 (13 Feb 2010)
- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer]
- Use z_off64_t in gz_zero() and gz_skip() to match state->skip
- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t)
- Revert to Makefile.in from 1.2.3.6 (live with the clutter)
- Fix missing error return in gzflush(), add zlib.h note
- Add *64 functions to zlib.map [Levin]
- Fix signed/unsigned comparison in gz_comp()
- Use SFLAGS when testing shared linking in configure
- Add --64 option to ./configure to use -m64 with gcc
- Fix ./configure --help to correctly name options
- Have make fail if a test fails [Levin]
- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson]
- Remove assembler object files from contrib

Changes in 1.2.3.7 (24 Jan 2010)
- Always gzopen() with O_LARGEFILE if available
- Fix gzdirect() to work immediately after gzopen() or gzdopen()
- Make gzdirect() more precise when the state changes while reading
- Improve zlib.h documentation in many places
- Catch memory allocation failure in gz_open()
- Complete close operation if seek forward in gzclose_w() fails
- Return Z_ERRNO from gzclose_r() if close() fails
- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL
- Return zero for gzwrite() errors to match zlib.h description
- Return -1 on gzputs() error to match zlib.h description
- Add zconf.in.h to allow recovery from configure modification [Weigelt]
- Fix static library permissions in Makefile.in [Weigelt]
- Avoid warnings in configure tests that hide functionality [Weigelt]
- Add *BSD and DragonFly to Linux case in configure [gentoo 123571]
- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212]
- Avoid access of uninitialized data for first inflateReset2 call [Gomes]
- Keep object files in subdirectories to reduce the clutter somewhat
- Remove default Makefile and zlibdefs.h, add dummy Makefile
- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_
- Remove zlibdefs.h completely -- modify zconf.h instead

Changes in 1.2.3.6 (17 Jan 2010)
- Avoid void * arithmetic in gzread.c and gzwrite.c
- Make compilers happier with const char * for gz_error message
- Avoid unused parameter warning in inflate.c
- Avoid signed-unsigned comparison warning in inflate.c
- Indent #pragma's for traditional C
- Fix usage of strwinerror() in glib.c, change to gz_strwinerror()
- Correct email address in configure for system options
- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser]
- Update zlib.map [Brown]
- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok]
- Apply various fixes to CMakeLists.txt [Lowman]
- Add checks on len in gzread() and gzwrite()
- Add error message for no more room for gzungetc()
- Remove zlib version check in gzwrite()
- Defer compression of gzprintf() result until need to
- Use snprintf() in gzdopen() if available
- Remove USE_MMAP configuration determination (only used by minigzip)
- Remove examples/pigz.c (available separately)
- Update examples/gun.c to 1.6

Changes in 1.2.3.5 (8 Jan 2010)
- Add space after #if in zutil.h for some compilers
- Fix relatively harmless bug in deflate_fast() [Exarevsky]
- Fix same problem in deflate_slow()
- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown]
- Add deflate_rle() for faster Z_RLE strategy run-length encoding
- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding
- Change name of "write" variable in inffast.c to avoid library collisions
- Fix premature EOF from gzread() in gzio.c [Brown]
- Use zlib header window size if windowBits is 0 in inflateInit2()
- Remove compressBound() call in deflate.c to avoid linking compress.o
- Replace use of errno in gz* with functions, support WinCE [Alves]
- Provide alternative to perror() in minigzip.c for WinCE [Alves]
- Don't use _vsnprintf on later versions of MSVC [Lowman]
- Add CMake build script and input file [Lowman]
- Update contrib/minizip to 1.1 [Svensson, Vollant]
- Moved nintendods directory from contrib to .
- Replace gzio.c with a new set of routines with the same functionality
- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
- Update contrib/minizip to 1.1b
- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h

Changes in 1.2.3.4 (21 Dec 2009)
- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility
- Update comments in configure and Makefile.in for default --shared
- Fix test -z's in configure [Marquess]
- Build examplesh and minigzipsh when not testing
- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h
- Import LDFLAGS from the environment in configure
- Fix configure to populate SFLAGS with discovered CFLAGS options
- Adapt make_vms.com to the new Makefile.in [Zinser]
- Add zlib2ansi script for C++ compilation [Marquess]
- Add _FILE_OFFSET_BITS=64 test to make test (when applicable)
- Add AMD64 assembler code for longest match to contrib [Teterin]
- Include options from $SFLAGS when doing $LDSHARED
- Simplify 64-bit file support by introducing z_off64_t type
- Make shared object files in objs directory to work around old Sun cc
- Use only three-part version number for Darwin shared compiles
- Add rc option to ar in Makefile.in for when ./configure not run
- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4*
- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile
- Protect against _FILE_OFFSET_BITS being defined when compiling zlib
- Rename Makefile.in targets allstatic to static and allshared to shared
- Fix static and shared Makefile.in targets to be independent
- Correct error return bug in gz_open() by setting state [Brown]
- Put spaces before ;;'s in configure for better sh compatibility
- Add pigz.c (parallel implementation of gzip) to examples/
- Correct constant in crc32.c to UL [Leventhal]
- Reject negative lengths in crc32_combine()
- Add inflateReset2() function to work like inflateEnd()/inflateInit2()
- Include sys/types.h for _LARGEFILE64_SOURCE [Brown]
- Correct typo in doc/algorithm.txt [Janik]
- Fix bug in adler32_combine() [Zhu]
- Catch missing-end-of-block-code error in all inflates and in puff
    Assures that random input to inflate eventually results in an error
- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/
- Update ENOUGH and its usage to reflect discovered bounds
- Fix gzerror() error report on empty input file [Brown]
- Add ush casts in trees.c to avoid pedantic runtime errors
- Fix typo in zlib.h uncompress() description [Reiss]
- Correct inflate() comments with regard to automatic header detection
- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays)
- Put new version of gzlog (2.0) in examples with interruption recovery
- Add puff compile option to permit invalid distance-too-far streams
- Add puff TEST command options, ability to read piped input
- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but
  _LARGEFILE64_SOURCE not defined
- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart
- Fix deflateSetDictionary() to use all 32K for output consistency
- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h)
- Clear bytes after deflate lookahead to avoid use of uninitialized data
- Change a limit in inftrees.c to be more transparent to Coverity Prevent
- Update win32/zlib.def with exported symbols from zlib.h
- Correct spelling errors in zlib.h [Willem, Sobrado]
- Allow Z_BLOCK for deflate() to force a new block
- Allow negative bits in inflatePrime() to delete existing bit buffer
- Add Z_TREES flush option to inflate() to return at end of trees
- Add inflateMark() to return current state information for random access
- Add Makefile for NintendoDS to contrib [Costa]
- Add -w in configure compile tests to avoid spurious warnings [Beucler]
- Fix typos in zlib.h comments for deflateSetDictionary()
- Fix EOF detection in transparent gzread() [Maier]

Changes in 1.2.3.3 (2 October 2006)
- Make --shared the default for configure, add a --static option
- Add compile option to permit invalid distance-too-far streams
- Add inflateUndermine() function which is required to enable above
- Remove use of "this" variable name for C++ compatibility [Marquess]
- Add testing of shared library in make test, if shared library built
- Use ftello() and fseeko() if available instead of ftell() and fseek()
- Provide two versions of all functions that use the z_off_t type for
  binary compatibility -- a normal version and a 64-bit offset version,
  per the Large File Support Extension when _LARGEFILE64_SOURCE is
  defined; use the 64-bit versions by default when _FILE_OFFSET_BITS
  is defined to be 64
- Add a --uname= option to configure to perhaps help with cross-compiling

Changes in 1.2.3.2 (3 September 2006)
- Turn off silly Borland warnings [Hay]
- Use off64_t and define _LARGEFILE64_SOURCE when present
- Fix missing dependency on inffixed.h in Makefile.in
- Rig configure --shared to build both shared and static [Teredesai, Truta]
- Remove zconf.in.h and instead create a new zlibdefs.h file
- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant]
- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt]

Changes in 1.2.3.1 (16 August 2006)
- Add watcom directory with OpenWatcom make files [Daniel]
- Remove #undef of FAR in zconf.in.h for MVS [Fedtke]
- Update make_vms.com [Zinser]
- Use -fPIC for shared build in configure [Teredesai, Nicholson]
- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen]
- Use fdopen() (not _fdopen()) for Interix in zutil.h [BŠck]
- Add some FAQ entries about the contrib directory
- Update the MVS question in the FAQ
- Avoid extraneous reads after EOF in gzio.c [Brown]
- Correct spelling of "successfully" in gzio.c [Randers-Pehrson]
- Add comments to zlib.h about gzerror() usage [Brown]
- Set extra flags in gzip header in gzopen() like deflate() does
- Make configure options more compatible with double-dash conventions
  [Weigelt]
- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen]
- Fix uninstall target in Makefile.in [Truta]
- Add pkgconfig support [Weigelt]
- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt]
- Replace set_data_type() with a more accurate detect_data_type() in
  trees.c, according to the txtvsbin.txt document [Truta]
- Swap the order of #include  and #include "zlib.h" in
  gzio.c, example.c and minigzip.c [Truta]
- Shut up annoying VS2005 warnings about standard C deprecation [Rowe,
  Truta] (where?)
- Fix target "clean" from win32/Makefile.bor [Truta]
- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe]
- Update zlib www home address in win32/DLL_FAQ.txt [Truta]
- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove]
- Enable browse info in the "Debug" and "ASM Debug" configurations in
  the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta]
- Add pkgconfig support [Weigelt]
- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h,
  for use in win32/zlib1.rc [Polushin, Rowe, Truta]
- Add a document that explains the new text detection scheme to
  doc/txtvsbin.txt [Truta]
- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta]
- Move algorithm.txt into doc/ [Truta]
- Synchronize FAQ with website
- Fix compressBound(), was low for some pathological cases [Fearnley]
- Take into account wrapper variations in deflateBound()
- Set examples/zpipe.c input and output to binary mode for Windows
- Update examples/zlib_how.html with new zpipe.c (also web site)
- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems
  that gcc became pickier in 4.0)
- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain
  un-versioned, the patch adds versioning only for symbols introduced in
  zlib-1.2.0 or later.  It also declares as local those symbols which are
  not designed to be exported." [Levin]
- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure
- Do not initialize global static by default in trees.c, add a response
  NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess]
- Don't use strerror() in gzio.c under WinCE [Yakimov]
- Don't use errno.h in zutil.h under WinCE [Yakimov]
- Move arguments for AR to its usage to allow replacing ar [Marot]
- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson]
- Improve inflateInit() and inflateInit2() documentation
- Fix structure size comment in inflate.h
- Change configure help option from --h* to --help [Santos]

Changes in 1.2.3 (18 July 2005)
- Apply security vulnerability fixes to contrib/infback9 as well
- Clean up some text files (carriage returns, trailing space)
- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]

Changes in 1.2.2.4 (11 July 2005)
- Add inflatePrime() function for starting inflation at bit boundary
- Avoid some Visual C warnings in deflate.c
- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
  compile
- Fix some spelling errors in comments [Betts]
- Correct inflateInit2() error return documentation in zlib.h
- Add zran.c example of compressed data random access to examples
  directory, shows use of inflatePrime()
- Fix cast for assignments to strm->state in inflate.c and infback.c
- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
- Add cast in trees.c t avoid a warning [Oberhumer]
- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
- Update make_vms.com [Zinser]
- Initialize state->write in inflateReset() since copied in inflate_fast()
- Be more strict on incomplete code sets in inflate_table() and increase
  ENOUGH and MAXD -- this repairs a possible security vulnerability for
  invalid inflate input.  Thanks to Tavis Ormandy and Markus Oberhumer for
  discovering the vulnerability and providing test cases.
- Add ia64 support to configure for HP-UX [Smith]
- Add error return to gzread() for format or i/o error [Levin]
- Use malloc.h for OS/2 [Necasek]

Changes in 1.2.2.3 (27 May 2005)
- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
- Typecast fread() return values in gzio.c [Vollant]
- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
- Fix crc check bug in gzread() after gzungetc() [Heiner]
- Add the deflateTune() function to adjust internal compression parameters
- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
- Remove an incorrect assertion in examples/zpipe.c
- Add C++ wrapper in infback9.h [Donais]
- Fix bug in inflateCopy() when decoding fixed codes
- Note in zlib.h how much deflateSetDictionary() actually uses
- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
- Add gzdirect() function to indicate transparent reads
- Update contrib/minizip [Vollant]
- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
- Add casts in crc32.c to avoid warnings [Oberhumer]
- Add contrib/masmx64 [Vollant]
- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]

Changes in 1.2.2.2 (30 December 2004)
- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
  avoid implicit memcpy calls (portability for no-library compilation)
- Increase sprintf() buffer size in gzdopen() to allow for large numbers
- Add INFLATE_STRICT to check distances against zlib header
- Improve WinCE errno handling and comments [Chang]
- Remove comment about no gzip header processing in FAQ
- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
- Add updated make_vms.com [Coghlan], update README
- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
  fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
- Add FAQ entry and comments in deflate.c on uninitialized memory access
- Add Solaris 9 make options in configure [Gilbert]
- Allow strerror() usage in gzio.c for STDC
- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
- Use z_off_t for adler32_combine() and crc32_combine() lengths
- Make adler32() much faster for small len
- Use OS_CODE in deflate() default gzip header

Changes in 1.2.2.1 (31 October 2004)
- Allow inflateSetDictionary() call for raw inflate
- Fix inflate header crc check bug for file names and comments
- Add deflateSetHeader() and gz_header structure for custom gzip headers
- Add inflateGetheader() to retrieve gzip headers
- Add crc32_combine() and adler32_combine() functions
- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
- Use zstreamp consistently in zlib.h (inflate_back functions)
- Remove GUNZIP condition from definition of inflate_mode in inflate.h
  and in contrib/inflate86/inffast.S [Truta, Anderson]
- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
- Update projects/README.projects and projects/visualc6 [Truta]
- Update win32/DLL_FAQ.txt [Truta]
- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
- Use a new algorithm for setting strm->data_type in trees.c [Truta]
- Do not define an exit() prototype in zutil.c unless DEBUG defined
- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
- Fix Darwin build version identification [Peterson]

Changes in 1.2.2 (3 October 2004)
- Update zlib.h comments on gzip in-memory processing
- Set adler to 1 in inflateReset() to support Java test suite [Walles]
- Add contrib/dotzlib [Ravn]
- Update win32/DLL_FAQ.txt [Truta]
- Update contrib/minizip [Vollant]
- Move contrib/visual-basic.txt to old/ [Truta]
- Fix assembler builds in projects/visualc6/ [Truta]

Changes in 1.2.1.2 (9 September 2004)
- Update INDEX file
- Fix trees.c to update strm->data_type (no one ever noticed!)
- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
- Add limited multitasking protection to DYNAMIC_CRC_TABLE
- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
- Don't declare strerror() under VMS [Mozilla]
- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
- Update contrib/ada [Anisimkov]
- Update contrib/minizip [Vollant]
- Fix configure to not hardcode directories for Darwin [Peterson]
- Fix gzio.c to not return error on empty files [Brown]
- Fix indentation; update version in contrib/delphi/ZLib.pas and
  contrib/pascal/zlibpas.pas [Truta]
- Update mkasm.bat in contrib/masmx86 [Truta]
- Update contrib/untgz [Truta]
- Add projects/README.projects [Truta]
- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
- Update win32/DLL_FAQ.txt [Truta]
- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
- Remove an unnecessary assignment to curr in inftrees.c [Truta]
- Add OS/2 to exe builds in configure [Poltorak]
- Remove err dummy parameter in zlib.h [Kientzle]

Changes in 1.2.1.1 (9 January 2004)
- Update email address in README
- Several FAQ updates
- Fix a big fat bug in inftrees.c that prevented decoding valid
  dynamic blocks with only literals and no distance codes --
  Thanks to "Hot Emu" for the bug report and sample file
- Add a note to puff.c on no distance codes case.

Changes in 1.2.1 (17 November 2003)
- Remove a tab in contrib/gzappend/gzappend.c
- Update some interfaces in contrib for new zlib functions
- Update zlib version number in some contrib entries
- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
- Support shared libraries on Hurd and KFreeBSD [Brown]
- Fix error in NO_DIVIDE option of adler32.c

Changes in 1.2.0.8 (4 November 2003)
- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
- Add experimental NO_DIVIDE #define in adler32.c
    - Possibly faster on some processors (let me know if it is)
- Correct Z_BLOCK to not return on first inflate call if no wrap
- Fix strm->data_type on inflate() return to correctly indicate EOB
- Add deflatePrime() function for appending in the middle of a byte
- Add contrib/gzappend for an example of appending to a stream
- Update win32/DLL_FAQ.txt [Truta]
- Delete Turbo C comment in README [Truta]
- Improve some indentation in zconf.h [Truta]
- Fix infinite loop on bad input in configure script [Church]
- Fix gzeof() for concatenated gzip files [Johnson]
- Add example to contrib/visual-basic.txt [Michael B.]
- Add -p to mkdir's in Makefile.in [vda]
- Fix configure to properly detect presence or lack of printf functions
- Add AS400 support [Monnerat]
- Add a little Cygwin support [Wilson]

Changes in 1.2.0.7 (21 September 2003)
- Correct some debug formats in contrib/infback9
- Cast a type in a debug statement in trees.c
- Change search and replace delimiter in configure from % to # [Beebe]
- Update contrib/untgz to 0.2 with various fixes [Truta]
- Add build support for Amiga [Nikl]
- Remove some directories in old that have been updated to 1.2
- Add dylib building for Mac OS X in configure and Makefile.in
- Remove old distribution stuff from Makefile
- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
- Update links in README

Changes in 1.2.0.6 (13 September 2003)
- Minor FAQ updates
- Update contrib/minizip to 1.00 [Vollant]
- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
- Update POSTINC comment for 68060 [Nikl]
- Add contrib/infback9 with deflate64 decoding (unsupported)
- For MVS define NO_vsnprintf and undefine FAR [van Burik]
- Add pragma for fdopen on MVS [van Burik]

Changes in 1.2.0.5 (8 September 2003)
- Add OF to inflateBackEnd() declaration in zlib.h
- Remember start when using gzdopen in the middle of a file
- Use internal off_t counters in gz* functions to properly handle seeks
- Perform more rigorous check for distance-too-far in inffast.c
- Add Z_BLOCK flush option to return from inflate at block boundary
- Set strm->data_type on return from inflate
    - Indicate bits unused, if at block boundary, and if in last block
- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
- Add condition so old NO_DEFLATE define still works for compatibility
- FAQ update regarding the Windows DLL [Truta]
- INDEX update: add qnx entry, remove aix entry [Truta]
- Install zlib.3 into mandir [Wilson]
- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
- Adapt the zlib interface to the new DLL convention guidelines [Truta]
- Introduce ZLIB_WINAPI macro to allow the export of functions using
  the WINAPI calling convention, for Visual Basic [Vollant, Truta]
- Update msdos and win32 scripts and makefiles [Truta]
- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
- Add contrib/ada [Anisimkov]
- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
- Add contrib/masm686 [Truta]
- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
  [Truta, Vollant]
- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
- Remove contrib/delphi2; add a new contrib/delphi [Truta]
- Avoid inclusion of the nonstandard  in contrib/iostream,
  and fix some method prototypes [Truta]
- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
  [Truta]
- Avoid the use of backslash (\) in contrib/minizip [Vollant]
- Fix file time handling in contrib/untgz; update makefiles [Truta]
- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
  [Vollant]
- Remove contrib/vstudio/vc15_16 [Vollant]
- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
- Update README.contrib [Truta]
- Invert the assignment order of match_head and s->prev[...] in
  INSERT_STRING [Truta]
- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
  [Truta]
- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
- Fix prototype of syncsearch in inflate.c [Truta]
- Introduce ASMINF macro to be enabled when using an ASM implementation
  of inflate_fast [Truta]
- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
- Modify test_gzio in example.c to take a single file name as a
  parameter [Truta]
- Exit the example.c program if gzopen fails [Truta]
- Add type casts around strlen in example.c [Truta]
- Remove casting to sizeof in minigzip.c; give a proper type
  to the variable compared with SUFFIX_LEN [Truta]
- Update definitions of STDC and STDC99 in zconf.h [Truta]
- Synchronize zconf.h with the new Windows DLL interface [Truta]
- Use SYS16BIT instead of __32BIT__ to distinguish between
  16- and 32-bit platforms [Truta]
- Use far memory allocators in small 16-bit memory models for
  Turbo C [Truta]
- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
  zlibCompileFlags [Truta]
- Cygwin has vsnprintf [Wilson]
- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]

Changes in 1.2.0.4 (10 August 2003)
- Minor FAQ updates
- Be more strict when checking inflateInit2's windowBits parameter
- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
- Add gzip wrapper option to deflateInit2 using windowBits
- Add updated QNX rule in configure and qnx directory [Bonnefoy]
- Make inflate distance-too-far checks more rigorous
- Clean up FAR usage in inflate
- Add casting to sizeof() in gzio.c and minigzip.c

Changes in 1.2.0.3 (19 July 2003)
- Fix silly error in gzungetc() implementation [Vollant]
- Update contrib/minizip and contrib/vstudio [Vollant]
- Fix printf format in example.c
- Correct cdecl support in zconf.in.h [Anisimkov]
- Minor FAQ updates

Changes in 1.2.0.2 (13 July 2003)
- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
- Attempt to avoid warnings in crc32.c for pointer-int conversion
- Add AIX to configure, remove aix directory [Bakker]
- Add some casts to minigzip.c
- Improve checking after insecure sprintf() or vsprintf() calls
- Remove #elif's from crc32.c
- Change leave label to inf_leave in inflate.c and infback.c to avoid
  library conflicts
- Remove inflate gzip decoding by default--only enable gzip decoding by
  special request for stricter backward compatibility
- Add zlibCompileFlags() function to return compilation information
- More typecasting in deflate.c to avoid warnings
- Remove leading underscore from _Capital #defines [Truta]
- Fix configure to link shared library when testing
- Add some Windows CE target adjustments [Mai]
- Remove #define ZLIB_DLL in zconf.h [Vollant]
- Add zlib.3 [Rodgers]
- Update RFC URL in deflate.c and algorithm.txt [Mai]
- Add zlib_dll_FAQ.txt to contrib [Truta]
- Add UL to some constants [Truta]
- Update minizip and vstudio [Vollant]
- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
- Expand use of NO_DUMMY_DECL to avoid all dummy structures
- Added iostream3 to contrib [Schwardt]
- Replace rewind() with fseek() for WinCE [Truta]
- Improve setting of zlib format compression level flags
    - Report 0 for huffman and rle strategies and for level == 0 or 1
    - Report 2 only for level == 6
- Only deal with 64K limit when necessary at compile time [Truta]
- Allow TOO_FAR check to be turned off at compile time [Truta]
- Add gzclearerr() function [Souza]
- Add gzungetc() function

Changes in 1.2.0.1 (17 March 2003)
- Add Z_RLE strategy for run-length encoding [Truta]
    - When Z_RLE requested, restrict matches to distance one
    - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
- Correct FASTEST compilation to allow level == 0
- Clean up what gets compiled for FASTEST
- Incorporate changes to zconf.in.h [Vollant]
    - Refine detection of Turbo C need for dummy returns
    - Refine ZLIB_DLL compilation
    - Include additional header file on VMS for off_t typedef
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
- Add some casts in inffast.c
- Enchance comments in zlib.h on what happens if gzprintf() tries to
  write more than 4095 bytes before compression
- Remove unused state from inflateBackEnd()
- Remove exit(0) from minigzip.c, example.c
- Get rid of all those darn tabs
- Add "check" target to Makefile.in that does the same thing as "test"
- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
- Update contrib/inflate86 [Anderson]
- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
- Add msdos and win32 directories with makefiles [Truta]
- More additions and improvements to the FAQ

Changes in 1.2.0 (9 March 2003)
- New and improved inflate code
    - About 20% faster
    - Does not allocate 32K window unless and until needed
    - Automatically detects and decompresses gzip streams
    - Raw inflate no longer needs an extra dummy byte at end
    - Added inflateBack functions using a callback interface--even faster
      than inflate, useful for file utilities (gzip, zip)
    - Added inflateCopy() function to record state for random access on
      externally generated deflate streams (e.g. in gzip files)
    - More readable code (I hope)
- New and improved crc32()
    - About 50% faster, thanks to suggestions from Rodney Brown
- Add deflateBound() and compressBound() functions
- Fix memory leak in deflateInit2()
- Permit setting dictionary for raw deflate (for parallel deflate)
- Fix const declaration for gzwrite()
- Check for some malloc() failures in gzio.c
- Fix bug in gzopen() on single-byte file 0x1f
- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
  and next buffer doesn't start with 0x8b
- Fix uncompress() to return Z_DATA_ERROR on truncated input
- Free memory at end of example.c
- Remove MAX #define in trees.c (conflicted with some libraries)
- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
- Declare malloc() and free() in gzio.c if STDC not defined
- Use malloc() instead of calloc() in zutil.c if int big enough
- Define STDC for AIX
- Add aix/ with approach for compiling shared library on AIX
- Add HP-UX support for shared libraries in configure
- Add OpenUNIX support for shared libraries in configure
- Use $cc instead of gcc to build shared library
- Make prefix directory if needed when installing
- Correct Macintosh avoidance of typedef Byte in zconf.h
- Correct Turbo C memory allocation when under Linux
- Use libz.a instead of -lz in Makefile (assure use of compiled library)
- Update configure to check for snprintf or vsnprintf functions and their
  return value, warn during make if using an insecure function
- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
  is lost when library is used--resolution is to build new zconf.h
- Documentation improvements (in zlib.h):
    - Document raw deflate and inflate
    - Update RFCs URL
    - Point out that zlib and gzip formats are different
    - Note that Z_BUF_ERROR is not fatal
    - Document string limit for gzprintf() and possible buffer overflow
    - Note requirement on avail_out when flushing
    - Note permitted values of flush parameter of inflate()
- Add some FAQs (and even answers) to the FAQ
- Add contrib/inflate86/ for x86 faster inflate
- Add contrib/blast/ for PKWare Data Compression Library decompression
- Add contrib/puff/ simple inflate for deflate format description

Changes in 1.1.4 (11 March 2002)
- ZFREE was repeated on same allocation on some error conditions.
  This creates a security problem described in
  http://www.zlib.org/advisory-2002-03-11.txt
- Returned incorrect error (Z_MEM_ERROR) on some invalid data
- Avoid accesses before window for invalid distances with inflate window
  less than 32K.
- force windowBits > 8 to avoid a bug in the encoder for a window size
  of 256 bytes. (A complete fix will be available in 1.1.5).

Changes in 1.1.3 (9 July 1998)
- fix "an inflate input buffer bug that shows up on rare but persistent
  occasions" (Mark)
- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
- fix gzseek(..., SEEK_SET) in write mode
- fix crc check after a gzeek (Frank Faubert)
- fix miniunzip when the last entry in a zip file is itself a zip file
  (J Lillge)
- add contrib/asm586 and contrib/asm686 (Brian Raiter)
  See http://www.muppetlabs.com/~breadbox/software/assembly.html
- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
- added a FAQ file

- Support gzdopen on Mac with Metrowerks (Jason Linhart)
- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
- avoid some warnings with Borland C (Tom Tanner)
- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
- emulate utime() for WIN32 in contrib/untgz  (Gilles Vollant)
- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
- use libdir and includedir in Makefile.in (Tim Mooney)
- support shared libraries on OSF1 V4 (Tim Mooney)
- remove so_locations in "make clean"  (Tim Mooney)
- fix maketree.c compilation error (Glenn, Mark)
- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
- new Makefile.riscos (Rich Walker)
- initialize static descriptors in trees.c for embedded targets (Nick Smith)
- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
- fix maketree.c to allow clean compilation of inffixed.h (Mark)
- fix parameter check in deflateCopy (Gunther Nikl)
- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
- Many portability patches by Christian Spieler:
  . zutil.c, zutil.h: added "const" for zmem*
  . Make_vms.com: fixed some typos
  . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
  . msdos/Makefile.msc: remove "default rtl link library" info from obj files
  . msdos/Makefile.*: use model-dependent name for the built zlib library
  . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
     new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
- replace __far with _far for better portability (Christian Spieler, Tom Lane)
- fix test for errno.h in configure (Tim Newsham)

Changes in 1.1.2 (19 March 98)
- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
  See http://www.winimage.com/zLibDll/unzip.html
- preinitialize the inflate tables for fixed codes, to make the code
  completely thread safe (Mark)
- some simplifications and slight speed-up to the inflate code (Mark)
- fix gzeof on non-compressed files (Allan Schrum)
- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
- do not wrap extern "C" around system includes (Tom Lane)
- mention zlib binding for TCL in README (Andreas Kupries)
- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
- allow "configure --prefix $HOME" (Tim Mooney)
- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
- move Makefile.sas to amiga/Makefile.sas

Changes in 1.1.1 (27 Feb 98)
- fix macros _tr_tally_* in deflate.h for debug mode  (Glenn Randers-Pehrson)
- remove block truncation heuristic which had very marginal effect for zlib
  (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
  compression ratio on some files. This also allows inlining _tr_tally for
  matches in deflate_slow.
- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)

Changes in 1.1.0 (24 Feb 98)
- do not return STREAM_END prematurely in inflate (John Bowler)
- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
- compile with -DFASTEST to get compression code optimized for speed only
- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
  on Sun but significant on HP)

- add a pointer to experimental unzip library in README (Gilles Vollant)
- initialize variable gcc in configure (Chris Herborth)

Changes in 1.0.9 (17 Feb 1998)
- added gzputs and gzgets functions
- do not clear eof flag in gzseek (Mark Diekhans)
- fix gzseek for files in transparent mode (Mark Diekhans)
- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
- replace EXPORT with ZEXPORT to avoid conflict with other programs
- added compress2 in zconf.h, zlib.def, zlib.dnt
- new asm code from Gilles Vollant in contrib/asm386
- simplify the inflate code (Mark):
 . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
 . ZALLOC the length list in inflate_trees_fixed() instead of using stack
 . ZALLOC the value area for huft_build() instead of using stack
 . Simplify Z_FINISH check in inflate()

- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
  the declaration of FAR (Gilles VOllant)
- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
- read_buf buf parameter of type Bytef* instead of charf*
- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
- fix check for presence of directories in "make install" (Ian Willis)

Changes in 1.0.8 (27 Jan 1998)
- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
- added compress2() to allow setting the compression level
- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
- use constant arrays for the static trees in trees.c instead of computing
  them at run time (thanks to Ken Raeburn for this suggestion). To create
  trees.h, compile with GEN_TREES_H and run "make test".
- check return code of example in "make test" and display result
- pass minigzip command line options to file_compress
- simplifying code of inflateSync to avoid gcc 2.8 bug

- support CC="gcc -Wall" in configure -s (QingLong)
- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
- fix test for shared library support to avoid compiler warnings
- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
- do not use fdopen for Metrowerks on Mac (Brad Pettit))
- add checks for gzputc and gzputc in example.c
- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
- use const for the CRC table (Ken Raeburn)
- fixed "make uninstall" for shared libraries
- use Tracev instead of Trace in infblock.c
- in example.c use correct compressed length for test_sync
- suppress +vnocompatwarnings in configure for HPUX (not always supported)

Changes in 1.0.7 (20 Jan 1998)
- fix gzseek which was broken in write mode
- return error for gzseek to negative absolute position
- fix configure for Linux (Chun-Chung Chen)
- increase stack space for MSC (Tim Wegner)
- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
- define EXPORTVA for gzprintf (Gilles Vollant)
- added man page zlib.3 (Rick Rodgers)
- for contrib/untgz, fix makedir() and improve Makefile

- check gzseek in write mode in example.c
- allocate extra buffer for seeks only if gzseek is actually called
- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
- add inflateSyncPoint in zconf.h
- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def

Changes in 1.0.6 (19 Jan 1998)
- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
  gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
- Fix a deflate bug occurring only with compression level 0 (thanks to
  Andy Buckler for finding this one).
- In minigzip, pass transparently also the first byte for .Z files.
- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
- check Z_FINISH in inflate (thanks to Marc Schluper)
- Implement deflateCopy (thanks to Adam Costello)
- make static libraries by default in configure, add --shared option.
- move MSDOS or Windows specific files to directory msdos
- suppress the notion of partial flush to simplify the interface
  (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
- suppress history buffer provided by application to simplify the interface
  (this feature was not implemented anyway in 1.0.4)
- next_in and avail_in must be initialized before calling inflateInit or
  inflateInit2
- add EXPORT in all exported functions (for Windows DLL)
- added Makefile.nt (thanks to Stephen Williams)
- added the unsupported "contrib" directory:
   contrib/asm386/ by Gilles Vollant 
        386 asm code replacing longest_match().
   contrib/iostream/ by Kevin Ruland 
        A C++ I/O streams interface to the zlib gz* functions
   contrib/iostream2/  by Tyge Løvset 
        Another C++ I/O streams interface
   contrib/untgz/  by "Pedro A. Aranda Guti\irrez" 
        A very simple tar.gz file extractor using zlib
   contrib/visual-basic.txt by Carlos Rios 
        How to use compress(), uncompress() and the gz* functions from VB.
- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
  level) in minigzip (thanks to Tom Lane)

- use const for rommable constants in deflate
- added test for gzseek and gztell in example.c
- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
- add undocumented function zError to convert error code to string
  (for Tim Smithers)
- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
- Use default memcpy for Symantec MSDOS compiler.
- Add EXPORT keyword for check_func (needed for Windows DLL)
- add current directory to LD_LIBRARY_PATH for "make test"
- create also a link for libz.so.1
- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
- added -soname for Linux in configure (Chun-Chung Chen,
- assign numbers to the exported functions in zlib.def (for Windows DLL)
- add advice in zlib.h for best usage of deflateSetDictionary
- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
- allow compilation with ANSI keywords only enabled for TurboC in large model
- avoid "versionString"[0] (Borland bug)
- add NEED_DUMMY_RETURN for Borland
- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
- allow compilation with CC
- defined STDC for OS/2 (David Charlap)
- limit external names to 8 chars for MVS (Thomas Lund)
- in minigzip.c, use static buffers only for 16-bit systems
- fix suffix check for "minigzip -d foo.gz"
- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
- added makelcc.bat for lcc-win32 (Tom St Denis)
- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
- check for unistd.h in configure (for off_t)
- remove useless check parameter in inflate_blocks_free
- avoid useless assignment of s->check to itself in inflate_blocks_new
- do not flush twice in gzclose (thanks to Ken Raeburn)
- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
- work around buggy fclose on pipes for HP/UX
- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
- fix configure if CC is already equal to gcc

Changes in 1.0.5 (3 Jan 98)
- Fix inflate to terminate gracefully when fed corrupted or invalid data
- Use const for rommable constants in inflate
- Eliminate memory leaks on error conditions in inflate
- Removed some vestigial code in inflate
- Update web address in README

Changes in 1.0.4 (24 Jul 96)
- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
  bit, so the decompressor could decompress all the correct data but went
  on to attempt decompressing extra garbage data. This affected minigzip too.
- zlibVersion and gzerror return const char* (needed for DLL)
- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
- use z_error only for DEBUG (avoid problem with DLLs)

Changes in 1.0.3 (2 Jul 96)
- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
  small and medium models; this makes the library incompatible with previous
  versions for these models. (No effect in large model or on other systems.)
- return OK instead of BUF_ERROR if previous deflate call returned with
  avail_out as zero but there is nothing to do
- added memcmp for non STDC compilers
- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
- better check for 16-bit mode MSC (avoids problem with Symantec)

Changes in 1.0.2 (23 May 96)
- added Windows DLL support
- added a function zlibVersion (for the DLL support)
- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
- Bytef is define's instead of typedef'd only for Borland C
- avoid reading uninitialized memory in example.c
- mention in README that the zlib format is now RFC1950
- updated Makefile.dj2
- added algorithm.doc

Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
- fix array overlay in deflate.c which sometimes caused bad compressed data
- fix inflate bug with empty stored block
- fix MSDOS medium model which was broken in 0.99
- fix deflateParams() which could generated bad compressed data.
- Bytef is define'd instead of typedef'ed (work around Borland bug)
- added an INDEX file
- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
  Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
- speed up adler32 for modern machines without auto-increment
- added -ansi for IRIX in configure
- static_init_done in trees.c is an int
- define unlink as delete for VMS
- fix configure for QNX
- add configure branch for SCO and HPUX
- avoid many warnings (unused variables, dead assignments, etc...)
- no fdopen for BeOS
- fix the Watcom fix for 32 bit mode (define FAR as empty)
- removed redefinition of Byte for MKWERKS
- work around an MWKERKS bug (incorrect merge of all .h files)

Changes in 0.99 (27 Jan 96)
- allow preset dictionary shared between compressor and decompressor
- allow compression level 0 (no compression)
- add deflateParams in zlib.h: allow dynamic change of compression level
  and compression strategy.
- test large buffers and deflateParams in example.c
- add optional "configure" to build zlib as a shared library
- suppress Makefile.qnx, use configure instead
- fixed deflate for 64-bit systems (detected on Cray)
- fixed inflate_blocks for 64-bit systems (detected on Alpha)
- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
- always return Z_BUF_ERROR when deflate() has nothing to do
- deflateInit and inflateInit are now macros to allow version checking
- prefix all global functions and types with z_ with -DZ_PREFIX
- make falloc completely reentrant (inftrees.c)
- fixed very unlikely race condition in ct_static_init
- free in reverse order of allocation to help memory manager
- use zlib-1.0/* instead of zlib/* inside the tar.gz
- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
  -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
- allow gzread on concatenated .gz files
- deflateEnd now returns Z_DATA_ERROR if it was premature
- deflate is finally (?) fully deterministic (no matches beyond end of input)
- Document Z_SYNC_FLUSH
- add uninstall in Makefile
- Check for __cpluplus in zlib.h
- Better test in ct_align for partial flush
- avoid harmless warnings for Borland C++
- initialize hash_head in deflate.c
- avoid warning on fdopen (gzio.c) for HP cc -Aa
- include stdlib.h for STDC compilers
- include errno.h for Cray
- ignore error if ranlib doesn't exist
- call ranlib twice for NeXTSTEP
- use exec_prefix instead of prefix for libz.a
- renamed ct_* as _tr_* to avoid conflict with applications
- clear z->msg in inflateInit2 before any error return
- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
- fixed typo in zconf.h (_GNUC__ => __GNUC__)
- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
- in fcalloc, normalize pointer if size > 65520 bytes
- don't use special fcalloc for 32 bit Borland C++
- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
- use Z_BINARY instead of BINARY
- document that gzclose after gzdopen will close the file
- allow "a" as mode in gzopen.
- fix error checking in gzread
- allow skipping .gz extra-field on pipes
- added reference to Perl interface in README
- put the crc table in FAR data (I dislike more and more the medium model :)
- added get_crc_table
- added a dimension to all arrays (Borland C can't count).
- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
- guard against multiple inclusion of *.h (for precompiled header on Mac)
- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
- don't use unsized arrays to avoid silly warnings by Visual C++:
     warning C4746: 'inflate_mask' : unsized array treated as  '__far'
     (what's wrong with far data in far model?).
- define enum out of inflate_blocks_state to allow compilation with C++

Changes in 0.95 (16 Aug 95)
- fix MSDOS small and medium model (now easier to adapt to any compiler)
- inlined send_bits
- fix the final (:-) bug for deflate with flush (output was correct but
  not completely flushed in rare occasions).
- default window size is same for compression and decompression
  (it's now sufficient to set MAX_WBITS in zconf.h).
- voidp -> voidpf and voidnp -> voidp (for consistency with other
  typedefs and because voidnp was not near in large model).

Changes in 0.94 (13 Aug 95)
- support MSDOS medium model
- fix deflate with flush (could sometimes generate bad output)
- fix deflateReset (zlib header was incorrectly suppressed)
- added support for VMS
- allow a compression level in gzopen()
- gzflush now calls fflush
- For deflate with flush, flush even if no more input is provided.
- rename libgz.a as libz.a
- avoid complex expression in infcodes.c triggering Turbo C bug
- work around a problem with gcc on Alpha (in INSERT_STRING)
- don't use inline functions (problem with some gcc versions)
- allow renaming of Byte, uInt, etc... with #define.
- avoid warning about (unused) pointer before start of array in deflate.c
- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
- avoid reserved word 'new' in trees.c

Changes in 0.93 (25 June 95)
- temporarily disable inline functions
- make deflate deterministic
- give enough lookahead for PARTIAL_FLUSH
- Set binary mode for stdin/stdout in minigzip.c for OS/2
- don't even use signed char in inflate (not portable enough)
- fix inflate memory leak for segmented architectures

Changes in 0.92 (3 May 95)
- don't assume that char is signed (problem on SGI)
- Clear bit buffer when starting a stored block
- no memcpy on Pyramid
- suppressed inftest.c
- optimized fill_window, put longest_match inline for gcc
- optimized inflate on stored blocks.
- untabify all sources to simplify patches

Changes in 0.91 (2 May 95)
- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
- Document the memory requirements in zconf.h
- added "make install"
- fix sync search logic in inflateSync
- deflate(Z_FULL_FLUSH) now works even if output buffer too short
- after inflateSync, don't scare people with just "lo world"
- added support for DJGPP

Changes in 0.9 (1 May 95)
- don't assume that zalloc clears the allocated memory (the TurboC bug
  was Mark's bug after all :)
- let again gzread copy uncompressed data unchanged (was working in 0.71)
- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
- added a test of inflateSync in example.c
- moved MAX_WBITS to zconf.h because users might want to change that.
- document explicitly that zalloc(64K) on MSDOS must return a normalized
  pointer (zero offset)
- added Makefiles for Microsoft C, Turbo C, Borland C++
- faster crc32()

Changes in 0.8 (29 April 95)
- added fast inflate (inffast.c)
- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
  is incompatible with previous versions of zlib which returned Z_OK.
- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
  (actually that was not a compiler bug, see 0.81 above)
- gzread no longer reads one extra byte in certain cases
- In gzio destroy(), don't reference a freed structure
- avoid many warnings for MSDOS
- avoid the ERROR symbol which is used by MS Windows

Changes in 0.71 (14 April 95)
- Fixed more MSDOS compilation problems :( There is still a bug with
  TurboC large model.

Changes in 0.7 (14 April 95)
- Added full inflate support.
- Simplified the crc32() interface. The pre- and post-conditioning
  (one's complement) is now done inside crc32(). WARNING: this is
  incompatible with previous versions; see zlib.h for the new usage.

Changes in 0.61 (12 April 95)
- workaround for a bug in TurboC. example and minigzip now work on MSDOS.

Changes in 0.6 (11 April 95)
- added minigzip.c
- added gzdopen to reopen a file descriptor as gzFile
- added transparent reading of non-gziped files in gzread.
- fixed bug in gzread (don't read crc as data)
- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
- don't allocate big arrays in the stack (for MSDOS)
- fix some MSDOS compilation problems

Changes in 0.5:
- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
  not yet Z_FULL_FLUSH.
- support decompression but only in a single step (forced Z_FINISH)
- added opaque object for zalloc and zfree.
- added deflateReset and inflateReset
- added a variable zlib_version for consistency checking.
- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
  Added Z_FILTERED and Z_HUFFMAN_ONLY constants.

Changes in 0.4:
- avoid "zip" everywhere, use zlib instead of ziplib.
- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
  if compression method == 8.
- added adler32 and crc32
- renamed deflateOptions as deflateInit2, call one or the other but not both
- added the method parameter for deflateInit2.
- added inflateInit2
- simplied considerably deflateInit and inflateInit by not supporting
  user-provided history buffer. This is supported only in deflateInit2
  and inflateInit2.

Changes in 0.3:
- prefix all macro names with Z_
- use Z_FINISH instead of deflateEnd to finish compression.
- added Z_HUFFMAN_ONLY
- added gzerror()
rsync-3.2.7/zlib/inflate.c0000664000000000000000000015161114274347346014132 0ustar  rootroot/* inflate.c -- zlib decompression
 * Copyright (C) 1995-2012 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/*
 * Change history:
 *
 * 1.2.beta0    24 Nov 2002
 * - First version -- complete rewrite of inflate to simplify code, avoid
 *   creation of window when not needed, minimize use of window when it is
 *   needed, make inffast.c even faster, implement gzip decoding, and to
 *   improve code readability and style over the previous zlib inflate code
 *
 * 1.2.beta1    25 Nov 2002
 * - Use pointers for available input and output checking in inffast.c
 * - Remove input and output counters in inffast.c
 * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
 * - Remove unnecessary second byte pull from length extra in inffast.c
 * - Unroll direct copy to three copies per loop in inffast.c
 *
 * 1.2.beta2    4 Dec 2002
 * - Change external routine names to reduce potential conflicts
 * - Correct filename to inffixed.h for fixed tables in inflate.c
 * - Make hbuf[] unsigned char to match parameter type in inflate.c
 * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
 *   to avoid negation problem on Alphas (64 bit) in inflate.c
 *
 * 1.2.beta3    22 Dec 2002
 * - Add comments on state->bits assertion in inffast.c
 * - Add comments on op field in inftrees.h
 * - Fix bug in reuse of allocated window after inflateReset()
 * - Remove bit fields--back to byte structure for speed
 * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
 * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
 * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
 * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
 * - Use local copies of stream next and avail values, as well as local bit
 *   buffer and bit count in inflate()--for speed when inflate_fast() not used
 *
 * 1.2.beta4    1 Jan 2003
 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
 * - Move a comment on output buffer sizes from inffast.c to inflate.c
 * - Add comments in inffast.c to introduce the inflate_fast() routine
 * - Rearrange window copies in inflate_fast() for speed and simplification
 * - Unroll last copy for window match in inflate_fast()
 * - Use local copies of window variables in inflate_fast() for speed
 * - Pull out common wnext == 0 case for speed in inflate_fast()
 * - Make op and len in inflate_fast() unsigned for consistency
 * - Add FAR to lcode and dcode declarations in inflate_fast()
 * - Simplified bad distance check in inflate_fast()
 * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
 *   source file infback.c to provide a call-back interface to inflate for
 *   programs like gzip and unzip -- uses window as output buffer to avoid
 *   window copying
 *
 * 1.2.beta5    1 Jan 2003
 * - Improved inflateBack() interface to allow the caller to provide initial
 *   input in strm.
 * - Fixed stored blocks bug in inflateBack()
 *
 * 1.2.beta6    4 Jan 2003
 * - Added comments in inffast.c on effectiveness of POSTINC
 * - Typecasting all around to reduce compiler warnings
 * - Changed loops from while (1) or do {} while (1) to for (;;), again to
 *   make compilers happy
 * - Changed type of window in inflateBackInit() to unsigned char *
 *
 * 1.2.beta7    27 Jan 2003
 * - Changed many types to unsigned or unsigned short to avoid warnings
 * - Added inflateCopy() function
 *
 * 1.2.0        9 Mar 2003
 * - Changed inflateBack() interface to provide separate opaque descriptors
 *   for the in() and out() functions
 * - Changed inflateBack() argument and in_func typedef to swap the length
 *   and buffer address return values for the input function
 * - Check next_in and next_out for Z_NULL on entry to inflate()
 *
 * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
 */

#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"

#ifdef MAKEFIXED
#  ifndef BUILDFIXED
#    define BUILDFIXED
#  endif
#endif

/* function prototypes */
local void fixedtables OF((struct inflate_state FAR *state));
local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
                           unsigned copy));
#ifdef BUILDFIXED
   void makefixed OF((void));
#endif
local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
                              unsigned len));

int ZEXPORT inflateResetKeep(strm)
z_streamp strm;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    strm->total_in = strm->total_out = state->total = 0;
    strm->msg = Z_NULL;
    if (state->wrap)        /* to support ill-conceived Java test suite */
        strm->adler = state->wrap & 1;
    state->mode = HEAD;
    state->last = 0;
    state->havedict = 0;
    state->dmax = 32768U;
    state->head = Z_NULL;
    state->hold = 0;
    state->bits = 0;
    state->lencode = state->distcode = state->next = state->codes;
    state->sane = 1;
    state->back = -1;
    Tracev((stderr, "inflate: reset\n"));
    return Z_OK;
}

int ZEXPORT inflateReset(strm)
z_streamp strm;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    state->wsize = 0;
    state->whave = 0;
    state->wnext = 0;
    return inflateResetKeep(strm);
}

int ZEXPORT inflateReset2(strm, windowBits)
z_streamp strm;
int windowBits;
{
    int wrap;
    struct inflate_state FAR *state;

    /* get the state */
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;

    /* extract wrap request from windowBits parameter */
    if (windowBits < 0) {
        wrap = 0;
        windowBits = -windowBits;
    }
    else {
        wrap = (windowBits >> 4) + 1;
#ifdef GUNZIP
        if (windowBits < 48)
            windowBits &= 15;
#endif
    }

    /* set number of window bits, free window if different */
    if (windowBits && (windowBits < 8 || windowBits > 15))
        return Z_STREAM_ERROR;
    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
        ZFREE(strm, state->window);
        state->window = Z_NULL;
    }

    /* update state and reset the rest of it */
    state->wrap = wrap;
    state->wbits = (unsigned)windowBits;
    return inflateReset(strm);
}

int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
z_streamp strm;
int windowBits;
const char *version;
int stream_size;
{
    int ret;
    struct inflate_state FAR *state;

    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
        stream_size != (int)(sizeof(z_stream)))
        return Z_VERSION_ERROR;
    if (strm == Z_NULL) return Z_STREAM_ERROR;
    strm->msg = Z_NULL;                 /* in case we return an error */
    if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
        return Z_STREAM_ERROR;
#else
        strm->zalloc = zcalloc;
        strm->opaque = (voidpf)0;
#endif
    }
    if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
        return Z_STREAM_ERROR;
#else
        strm->zfree = zcfree;
#endif
    state = (struct inflate_state FAR *)
            ZALLOC(strm, 1, sizeof(struct inflate_state));
    if (state == Z_NULL) return Z_MEM_ERROR;
    Tracev((stderr, "inflate: allocated\n"));
    strm->state = (struct internal_state FAR *)state;
    state->window = Z_NULL;
    ret = inflateReset2(strm, windowBits);
    if (ret != Z_OK) {
        ZFREE(strm, state);
        strm->state = Z_NULL;
    }
    return ret;
}

int ZEXPORT inflateInit_(strm, version, stream_size)
z_streamp strm;
const char *version;
int stream_size;
{
    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
}

int ZEXPORT inflatePrime(strm, bits, value)
z_streamp strm;
int bits;
int value;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    if (bits < 0) {
        state->hold = 0;
        state->bits = 0;
        return Z_OK;
    }
    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
    value &= (1L << bits) - 1;
    state->hold += value << state->bits;
    state->bits += bits;
    return Z_OK;
}

/*
   Return state with length and distance decoding tables and index sizes set to
   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
   If BUILDFIXED is defined, then instead this routine builds the tables the
   first time it's called, and returns those tables the first time and
   thereafter.  This reduces the size of the code by about 2K bytes, in
   exchange for a little execution time.  However, BUILDFIXED should not be
   used for threaded applications, since the rewriting of the tables and virgin
   may not be thread-safe.
 */
local void fixedtables(state)
struct inflate_state FAR *state;
{
#ifdef BUILDFIXED
    static int virgin = 1;
    static code *lenfix, *distfix;
    static code fixed[544];

    /* build fixed huffman tables if first call (may not be thread safe) */
    if (virgin) {
        unsigned sym, bits;
        static code *next;

        /* literal/length table */
        sym = 0;
        while (sym < 144) state->lens[sym++] = 8;
        while (sym < 256) state->lens[sym++] = 9;
        while (sym < 280) state->lens[sym++] = 7;
        while (sym < 288) state->lens[sym++] = 8;
        next = fixed;
        lenfix = next;
        bits = 9;
        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);

        /* distance table */
        sym = 0;
        while (sym < 32) state->lens[sym++] = 5;
        distfix = next;
        bits = 5;
        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);

        /* do this just once */
        virgin = 0;
    }
#else /* !BUILDFIXED */
#   include "inffixed.h"
#endif /* BUILDFIXED */
    state->lencode = lenfix;
    state->lenbits = 9;
    state->distcode = distfix;
    state->distbits = 5;
}

#ifdef MAKEFIXED
#include 

/*
   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
   those tables to stdout, which would be piped to inffixed.h.  A small program
   can simply call makefixed to do this:

    void makefixed(void);

    int main(void)
    {
        makefixed();
        return 0;
    }

   Then that can be linked with zlib built with MAKEFIXED defined and run:

    a.out > inffixed.h
 */
void makefixed()
{
    unsigned low, size;
    struct inflate_state state;

    fixedtables(&state);
    puts("    /* inffixed.h -- table for decoding fixed codes");
    puts("     * Generated automatically by makefixed().");
    puts("     */");
    puts("");
    puts("    /* WARNING: this file should *not* be used by applications.");
    puts("       It is part of the implementation of this library and is");
    puts("       subject to change. Applications should only use zlib.h.");
    puts("     */");
    puts("");
    size = 1U << 9;
    printf("    static const code lenfix[%u] = {", size);
    low = 0;
    for (;;) {
        if ((low % 7) == 0) printf("\n        ");
        printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
               state.lencode[low].bits, state.lencode[low].val);
        if (++low == size) break;
        putchar(',');
    }
    puts("\n    };");
    size = 1U << 5;
    printf("\n    static const code distfix[%u] = {", size);
    low = 0;
    for (;;) {
        if ((low % 6) == 0) printf("\n        ");
        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
               state.distcode[low].val);
        if (++low == size) break;
        putchar(',');
    }
    puts("\n    };");
}
#endif /* MAKEFIXED */

/*
   Update the window with the last wsize (normally 32K) bytes written before
   returning.  If window does not exist yet, create it.  This is only called
   when a window is already in use, or when output has been written during this
   inflate call, but the end of the deflate stream has not been reached yet.
   It is also called to create a window for dictionary data when a dictionary
   is loaded.

   Providing output buffers larger than 32K to inflate() should provide a speed
   advantage, since only the last 32K of output is copied to the sliding window
   upon return from inflate(), and since all distances after the first 32K of
   output will fall in the output data, making match copies simpler and faster.
   The advantage may be dependent on the size of the processor's data caches.
 */
local int updatewindow(strm, end, copy)
z_streamp strm;
const Bytef *end;
unsigned copy;
{
    struct inflate_state FAR *state;
    unsigned dist;

    state = (struct inflate_state FAR *)strm->state;

    /* if it hasn't been done already, allocate space for the window */
    if (state->window == Z_NULL) {
        state->window = (unsigned char FAR *)
                        ZALLOC(strm, 1U << state->wbits,
                               sizeof(unsigned char));
        if (state->window == Z_NULL) return 1;
    }

    /* if window not in use yet, initialize */
    if (state->wsize == 0) {
        state->wsize = 1U << state->wbits;
        state->wnext = 0;
        state->whave = 0;
    }

    /* copy state->wsize or less output bytes into the circular window */
    if (copy >= state->wsize) {
        zmemcpy(state->window, end - state->wsize, state->wsize);
        state->wnext = 0;
        state->whave = state->wsize;
    }
    else {
        dist = state->wsize - state->wnext;
        if (dist > copy) dist = copy;
        zmemcpy(state->window + state->wnext, end - copy, dist);
        copy -= dist;
        if (copy) {
            zmemcpy(state->window, end - copy, copy);
            state->wnext = copy;
            state->whave = state->wsize;
        }
        else {
            state->wnext += dist;
            if (state->wnext == state->wsize) state->wnext = 0;
            if (state->whave < state->wsize) state->whave += dist;
        }
    }
    return 0;
}

/* Macros for inflate(): */

/* check function to use adler32() for zlib or crc32() for gzip */
#ifdef GUNZIP
#  define UPDATE(check, buf, len) \
    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
#else
#  define UPDATE(check, buf, len) adler32(check, buf, len)
#endif

/* check macros for header crc */
#ifdef GUNZIP
#  define CRC2(check, word) \
    do { \
        hbuf[0] = (unsigned char)(word); \
        hbuf[1] = (unsigned char)((word) >> 8); \
        check = crc32(check, hbuf, 2); \
    } while (0)

#  define CRC4(check, word) \
    do { \
        hbuf[0] = (unsigned char)(word); \
        hbuf[1] = (unsigned char)((word) >> 8); \
        hbuf[2] = (unsigned char)((word) >> 16); \
        hbuf[3] = (unsigned char)((word) >> 24); \
        check = crc32(check, hbuf, 4); \
    } while (0)
#endif

/* Load registers with state in inflate() for speed */
#define LOAD() \
    do { \
        put = strm->next_out; \
        left = strm->avail_out; \
        next = strm->next_in; \
        have = strm->avail_in; \
        hold = state->hold; \
        bits = state->bits; \
    } while (0)

/* Restore state from registers in inflate() */
#define RESTORE() \
    do { \
        strm->next_out = put; \
        strm->avail_out = left; \
        strm->next_in = next; \
        strm->avail_in = have; \
        state->hold = hold; \
        state->bits = bits; \
    } while (0)

/* Clear the input bit accumulator */
#define INITBITS() \
    do { \
        hold = 0; \
        bits = 0; \
    } while (0)

/* Get a byte of input into the bit accumulator, or return from inflate()
   if there is no input available. */
#define PULLBYTE() \
    do { \
        if (have == 0) goto inf_leave; \
        have--; \
        hold += (unsigned long)(*next++) << bits; \
        bits += 8; \
    } while (0)

/* Assure that there are at least n bits in the bit accumulator.  If there is
   not enough available input to do that, then return from inflate(). */
#define NEEDBITS(n) \
    do { \
        while (bits < (unsigned)(n)) \
            PULLBYTE(); \
    } while (0)

/* Return the low n bits of the bit accumulator (n < 16) */
#define BITS(n) \
    ((unsigned)hold & ((1U << (n)) - 1))

/* Remove n bits from the bit accumulator */
#define DROPBITS(n) \
    do { \
        hold >>= (n); \
        bits -= (unsigned)(n); \
    } while (0)

/* Remove zero to seven bits as needed to go to a byte boundary */
#define BYTEBITS() \
    do { \
        hold >>= bits & 7; \
        bits -= bits & 7; \
    } while (0)

/*
   inflate() uses a state machine to process as much input data and generate as
   much output data as possible before returning.  The state machine is
   structured roughly as follows:

    for (;;) switch (state) {
    ...
    case STATEn:
        if (not enough input data or output space to make progress)
            return;
        ... make progress ...
        state = STATEm;
        break;
    ...
    }

   so when inflate() is called again, the same case is attempted again, and
   if the appropriate resources are provided, the machine proceeds to the
   next state.  The NEEDBITS() macro is usually the way the state evaluates
   whether it can proceed or should return.  NEEDBITS() does the return if
   the requested bits are not available.  The typical use of the BITS macros
   is:

        NEEDBITS(n);
        ... do something with BITS(n) ...
        DROPBITS(n);

   where NEEDBITS(n) either returns from inflate() if there isn't enough
   input left to load n bits into the accumulator, or it continues.  BITS(n)
   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
   the low n bits off the accumulator.  INITBITS() clears the accumulator
   and sets the number of available bits to zero.  BYTEBITS() discards just
   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.

   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
   if there is no input available.  The decoding of variable length codes uses
   PULLBYTE() directly in order to pull just enough bytes to decode the next
   code, and no more.

   Some states loop until they get enough input, making sure that enough
   state information is maintained to continue the loop where it left off
   if NEEDBITS() returns in the loop.  For example, want, need, and keep
   would all have to actually be part of the saved state in case NEEDBITS()
   returns:

    case STATEw:
        while (want < need) {
            NEEDBITS(n);
            keep[want++] = BITS(n);
            DROPBITS(n);
        }
        state = STATEx;
    case STATEx:

   As shown above, if the next state is also the next case, then the break
   is omitted.

   A state may also return if there is not enough output space available to
   complete that state.  Those states are copying stored data, writing a
   literal byte, and copying a matching string.

   When returning, a "goto inf_leave" is used to update the total counters,
   update the check value, and determine whether any progress has been made
   during that inflate() call in order to return the proper return code.
   Progress is defined as a change in either strm->avail_in or strm->avail_out.
   When there is a window, goto inf_leave will update the window with the last
   output written.  If a goto inf_leave occurs in the middle of decompression
   and there is no window currently, goto inf_leave will create one and copy
   output to the window for the next call of inflate().

   In this implementation, the flush parameter of inflate() only affects the
   return code (per zlib.h).  inflate() always writes as much as possible to
   strm->next_out, given the space available and the provided input--the effect
   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
   the allocation of and copying into a sliding window until necessary, which
   provides the effect documented in zlib.h for Z_FINISH when the entire input
   stream available.  So the only thing the flush parameter actually does is:
   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
   will return Z_BUF_ERROR if it has not reached the end of the stream.
 */

int ZEXPORT inflate(strm, flush)
z_streamp strm;
int flush;
{
    struct inflate_state FAR *state;
    z_const unsigned char FAR *next;    /* next input */
    unsigned char FAR *put;     /* next output */
    unsigned have, left;        /* available input and output */
    unsigned long hold;         /* bit buffer */
    unsigned bits;              /* bits in bit buffer */
    unsigned in, out;           /* save starting available input and output */
    unsigned copy;              /* number of stored or match bytes to copy */
    unsigned char FAR *from;    /* where to copy match bytes from */
    code here;                  /* current decoding table entry */
    code last;                  /* parent table entry */
    unsigned len;               /* length to copy for repeats, bits to drop */
    int ret;                    /* return code */
#ifdef GUNZIP
    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
#endif
    static const unsigned short order[19] = /* permutation of code lengths */
        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};

    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
        (strm->next_in == Z_NULL && strm->avail_in != 0))
        return Z_STREAM_ERROR;

    state = (struct inflate_state FAR *)strm->state;
    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
    LOAD();
    in = have;
    out = left;
    ret = Z_OK;
    for (;;)
        switch (state->mode) {
        case HEAD:
            if (state->wrap == 0) {
                state->mode = TYPEDO;
                break;
            }
            NEEDBITS(16);
#ifdef GUNZIP
            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
                state->check = crc32(0L, Z_NULL, 0);
                CRC2(state->check, hold);
                INITBITS();
                state->mode = FLAGS;
                break;
            }
            state->flags = 0;           /* expect zlib header */
            if (state->head != Z_NULL)
                state->head->done = -1;
            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
#else
            if (
#endif
                ((BITS(8) << 8) + (hold >> 8)) % 31) {
                strm->msg = (char *)"incorrect header check";
                state->mode = BAD;
                break;
            }
            if (BITS(4) != Z_DEFLATED) {
                strm->msg = (char *)"unknown compression method";
                state->mode = BAD;
                break;
            }
            DROPBITS(4);
            len = BITS(4) + 8;
            if (state->wbits == 0)
                state->wbits = len;
            else if (len > state->wbits) {
                strm->msg = (char *)"invalid window size";
                state->mode = BAD;
                break;
            }
            state->dmax = 1U << len;
            Tracev((stderr, "inflate:   zlib header ok\n"));
            strm->adler = state->check = adler32(0L, Z_NULL, 0);
            state->mode = hold & 0x200 ? DICTID : TYPE;
            INITBITS();
            break;
#ifdef GUNZIP
        case FLAGS:
            NEEDBITS(16);
            state->flags = (int)(hold);
            if ((state->flags & 0xff) != Z_DEFLATED) {
                strm->msg = (char *)"unknown compression method";
                state->mode = BAD;
                break;
            }
            if (state->flags & 0xe000) {
                strm->msg = (char *)"unknown header flags set";
                state->mode = BAD;
                break;
            }
            if (state->head != Z_NULL)
                state->head->text = (int)((hold >> 8) & 1);
            if (state->flags & 0x0200) CRC2(state->check, hold);
            INITBITS();
            state->mode = TIME;
	    /* FALL THROUGH */
        case TIME:
            NEEDBITS(32);
            if (state->head != Z_NULL)
                state->head->time = hold;
            if (state->flags & 0x0200) CRC4(state->check, hold);
            INITBITS();
            state->mode = OS;
	    /* FALL THROUGH */
        case OS:
            NEEDBITS(16);
            if (state->head != Z_NULL) {
                state->head->xflags = (int)(hold & 0xff);
                state->head->os = (int)(hold >> 8);
            }
            if (state->flags & 0x0200) CRC2(state->check, hold);
            INITBITS();
            state->mode = EXLEN;
	    /* FALL THROUGH */
        case EXLEN:
            if (state->flags & 0x0400) {
                NEEDBITS(16);
                state->length = (unsigned)(hold);
                if (state->head != Z_NULL)
                    state->head->extra_len = (unsigned)hold;
                if (state->flags & 0x0200) CRC2(state->check, hold);
                INITBITS();
            }
            else if (state->head != Z_NULL)
                state->head->extra = Z_NULL;
            state->mode = EXTRA;
	    /* FALL THROUGH */
        case EXTRA:
            if (state->flags & 0x0400) {
                copy = state->length;
                if (copy > have) copy = have;
                if (copy) {
                    if (state->head != Z_NULL &&
                        state->head->extra != Z_NULL &&
                        (len = state->head->extra_len - state->length) <
                            state->head->extra_max) {
                        zmemcpy(state->head->extra + len, next,
                                len + copy > state->head->extra_max ?
                                state->head->extra_max - len : copy);
                    }
                    if (state->flags & 0x0200)
                        state->check = crc32(state->check, next, copy);
                    have -= copy;
                    next += copy;
                    state->length -= copy;
                }
                if (state->length) goto inf_leave;
            }
            state->length = 0;
            state->mode = NAME;
	    /* FALL THROUGH */
        case NAME:
            if (state->flags & 0x0800) {
                if (have == 0) goto inf_leave;
                copy = 0;
                do {
                    len = (unsigned)(next[copy++]);
                    if (state->head != Z_NULL &&
                            state->head->name != Z_NULL &&
                            state->length < state->head->name_max)
                        state->head->name[state->length++] = len;
                } while (len && copy < have);
                if (state->flags & 0x0200)
                    state->check = crc32(state->check, next, copy);
                have -= copy;
                next += copy;
                if (len) goto inf_leave;
            }
            else if (state->head != Z_NULL)
                state->head->name = Z_NULL;
            state->length = 0;
            state->mode = COMMENT;
	    /* FALL THROUGH */
        case COMMENT:
            if (state->flags & 0x1000) {
                if (have == 0) goto inf_leave;
                copy = 0;
                do {
                    len = (unsigned)(next[copy++]);
                    if (state->head != Z_NULL &&
                            state->head->comment != Z_NULL &&
                            state->length < state->head->comm_max)
                        state->head->comment[state->length++] = len;
                } while (len && copy < have);
                if (state->flags & 0x0200)
                    state->check = crc32(state->check, next, copy);
                have -= copy;
                next += copy;
                if (len) goto inf_leave;
            }
            else if (state->head != Z_NULL)
                state->head->comment = Z_NULL;
            state->mode = HCRC;
	    /* FALL THROUGH */
        case HCRC:
            if (state->flags & 0x0200) {
                NEEDBITS(16);
                if (hold != (state->check & 0xffff)) {
                    strm->msg = (char *)"header crc mismatch";
                    state->mode = BAD;
                    break;
                }
                INITBITS();
            }
            if (state->head != Z_NULL) {
                state->head->hcrc = (int)((state->flags >> 9) & 1);
                state->head->done = 1;
            }
            strm->adler = state->check = crc32(0L, Z_NULL, 0);
            state->mode = TYPE;
            break;
#endif
        case DICTID:
            NEEDBITS(32);
            strm->adler = state->check = ZSWAP32(hold);
            INITBITS();
            state->mode = DICT;
	    /* FALL THROUGH */
        case DICT:
            if (state->havedict == 0) {
                RESTORE();
                return Z_NEED_DICT;
            }
            strm->adler = state->check = adler32(0L, Z_NULL, 0);
            state->mode = TYPE;
	    /* FALL THROUGH */
        case TYPE:
            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
	    /* FALL THROUGH */
        case TYPEDO:
            if (state->last) {
                BYTEBITS();
                state->mode = CHECK;
                break;
            }
            NEEDBITS(3);
            state->last = BITS(1);
            DROPBITS(1);
            switch (BITS(2)) {
            case 0:                             /* stored block */
                Tracev((stderr, "inflate:     stored block%s\n",
                        state->last ? " (last)" : ""));
                state->mode = STORED;
                break;
            case 1:                             /* fixed block */
                fixedtables(state);
                Tracev((stderr, "inflate:     fixed codes block%s\n",
                        state->last ? " (last)" : ""));
                state->mode = LEN_;             /* decode codes */
                if (flush == Z_TREES) {
                    DROPBITS(2);
                    goto inf_leave;
                }
                break;
            case 2:                             /* dynamic block */
                Tracev((stderr, "inflate:     dynamic codes block%s\n",
                        state->last ? " (last)" : ""));
                state->mode = TABLE;
                break;
            case 3:
                strm->msg = (char *)"invalid block type";
                state->mode = BAD;
            }
            DROPBITS(2);
            break;
        case STORED:
            BYTEBITS();                         /* go to byte boundary */
            NEEDBITS(32);
            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
                strm->msg = (char *)"invalid stored block lengths";
                state->mode = BAD;
                break;
            }
            state->length = (unsigned)hold & 0xffff;
            Tracev((stderr, "inflate:       stored length %u\n",
                    state->length));
            INITBITS();
            state->mode = COPY_;
            if (flush == Z_TREES) goto inf_leave;
	    /* FALLTHROUGH */
        case COPY_:
            state->mode = COPY;
	    /* FALLTHROUGH */
        case COPY:
            copy = state->length;
            if (copy) {
                if (copy > have) copy = have;
                if (copy > left) copy = left;
                if (copy == 0) goto inf_leave;
                zmemcpy(put, next, copy);
                have -= copy;
                next += copy;
                left -= copy;
                put += copy;
                state->length -= copy;
                break;
            }
            Tracev((stderr, "inflate:       stored end\n"));
            state->mode = TYPE;
            break;
        case TABLE:
            NEEDBITS(14);
            state->nlen = BITS(5) + 257;
            DROPBITS(5);
            state->ndist = BITS(5) + 1;
            DROPBITS(5);
            state->ncode = BITS(4) + 4;
            DROPBITS(4);
#ifndef PKZIP_BUG_WORKAROUND
            if (state->nlen > 286 || state->ndist > 30) {
                strm->msg = (char *)"too many length or distance symbols";
                state->mode = BAD;
                break;
            }
#endif
            Tracev((stderr, "inflate:       table sizes ok\n"));
            state->have = 0;
            state->mode = LENLENS;
	    /* FALL THROUGH */
        case LENLENS:
            while (state->have < state->ncode) {
                NEEDBITS(3);
                state->lens[order[state->have++]] = (unsigned short)BITS(3);
                DROPBITS(3);
            }
            while (state->have < 19)
                state->lens[order[state->have++]] = 0;
            state->next = state->codes;
            state->lencode = (const code FAR *)(state->next);
            state->lenbits = 7;
            ret = inflate_table(CODES, state->lens, 19, &(state->next),
                                &(state->lenbits), state->work);
            if (ret) {
                strm->msg = (char *)"invalid code lengths set";
                state->mode = BAD;
                break;
            }
            Tracev((stderr, "inflate:       code lengths ok\n"));
            state->have = 0;
            state->mode = CODELENS;
	    /* FALL THROUGH */
        case CODELENS:
            while (state->have < state->nlen + state->ndist) {
                for (;;) {
                    here = state->lencode[BITS(state->lenbits)];
                    if ((unsigned)(here.bits) <= bits) break;
                    PULLBYTE();
                }
                if (here.val < 16) {
                    DROPBITS(here.bits);
                    state->lens[state->have++] = here.val;
                }
                else {
                    if (here.val == 16) {
                        NEEDBITS(here.bits + 2);
                        DROPBITS(here.bits);
                        if (state->have == 0) {
                            strm->msg = (char *)"invalid bit length repeat";
                            state->mode = BAD;
                            break;
                        }
                        len = state->lens[state->have - 1];
                        copy = 3 + BITS(2);
                        DROPBITS(2);
                    }
                    else if (here.val == 17) {
                        NEEDBITS(here.bits + 3);
                        DROPBITS(here.bits);
                        len = 0;
                        copy = 3 + BITS(3);
                        DROPBITS(3);
                    }
                    else {
                        NEEDBITS(here.bits + 7);
                        DROPBITS(here.bits);
                        len = 0;
                        copy = 11 + BITS(7);
                        DROPBITS(7);
                    }
                    if (state->have + copy > state->nlen + state->ndist) {
                        strm->msg = (char *)"invalid bit length repeat";
                        state->mode = BAD;
                        break;
                    }
                    while (copy--)
                        state->lens[state->have++] = (unsigned short)len;
                }
            }

            /* handle error breaks in while */
            if (state->mode == BAD) break;

            /* check for end-of-block code (better have one) */
            if (state->lens[256] == 0) {
                strm->msg = (char *)"invalid code -- missing end-of-block";
                state->mode = BAD;
                break;
            }

            /* build code tables -- note: do not change the lenbits or distbits
               values here (9 and 6) without reading the comments in inftrees.h
               concerning the ENOUGH constants, which depend on those values */
            state->next = state->codes;
            state->lencode = (const code FAR *)(state->next);
            state->lenbits = 9;
            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
                                &(state->lenbits), state->work);
            if (ret) {
                strm->msg = (char *)"invalid literal/lengths set";
                state->mode = BAD;
                break;
            }
            state->distcode = (const code FAR *)(state->next);
            state->distbits = 6;
            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
                            &(state->next), &(state->distbits), state->work);
            if (ret) {
                strm->msg = (char *)"invalid distances set";
                state->mode = BAD;
                break;
            }
            Tracev((stderr, "inflate:       codes ok\n"));
            state->mode = LEN_;
            if (flush == Z_TREES) goto inf_leave;
	    /* FALL THROUGH */
        case LEN_:
            state->mode = LEN;
	    /* FALL THROUGH */
        case LEN:
            if (have >= 6 && left >= 258) {
                RESTORE();
                inflate_fast(strm, out);
                LOAD();
                if (state->mode == TYPE)
                    state->back = -1;
                break;
            }
            state->back = 0;
            for (;;) {
                here = state->lencode[BITS(state->lenbits)];
                if ((unsigned)(here.bits) <= bits) break;
                PULLBYTE();
            }
            if (here.op && (here.op & 0xf0) == 0) {
                last = here;
                for (;;) {
                    here = state->lencode[last.val +
                            (BITS(last.bits + last.op) >> last.bits)];
                    if ((unsigned)(last.bits + here.bits) <= bits) break;
                    PULLBYTE();
                }
                DROPBITS(last.bits);
                state->back += last.bits;
            }
            DROPBITS(here.bits);
            state->back += here.bits;
            state->length = (unsigned)here.val;
            if ((int)(here.op) == 0) {
                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
                        "inflate:         literal '%c'\n" :
                        "inflate:         literal 0x%02x\n", here.val));
                state->mode = LIT;
                break;
            }
            if (here.op & 32) {
                Tracevv((stderr, "inflate:         end of block\n"));
                state->back = -1;
                state->mode = TYPE;
                break;
            }
            if (here.op & 64) {
                strm->msg = (char *)"invalid literal/length code";
                state->mode = BAD;
                break;
            }
            state->extra = (unsigned)(here.op) & 15;
            state->mode = LENEXT;
	    /* FALL THROUGH */
        case LENEXT:
            if (state->extra) {
                NEEDBITS(state->extra);
                state->length += BITS(state->extra);
                DROPBITS(state->extra);
                state->back += state->extra;
            }
            Tracevv((stderr, "inflate:         length %u\n", state->length));
            state->was = state->length;
            state->mode = DIST;
	    /* FALL THROUGH */
        case DIST:
            for (;;) {
                here = state->distcode[BITS(state->distbits)];
                if ((unsigned)(here.bits) <= bits) break;
                PULLBYTE();
            }
            if ((here.op & 0xf0) == 0) {
                last = here;
                for (;;) {
                    here = state->distcode[last.val +
                            (BITS(last.bits + last.op) >> last.bits)];
                    if ((unsigned)(last.bits + here.bits) <= bits) break;
                    PULLBYTE();
                }
                DROPBITS(last.bits);
                state->back += last.bits;
            }
            DROPBITS(here.bits);
            state->back += here.bits;
            if (here.op & 64) {
                strm->msg = (char *)"invalid distance code";
                state->mode = BAD;
                break;
            }
            state->offset = (unsigned)here.val;
            state->extra = (unsigned)(here.op) & 15;
            state->mode = DISTEXT;
	    /* FALL THROUGH */
        case DISTEXT:
            if (state->extra) {
                NEEDBITS(state->extra);
                state->offset += BITS(state->extra);
                DROPBITS(state->extra);
                state->back += state->extra;
            }
#ifdef INFLATE_STRICT
            if (state->offset > state->dmax) {
                strm->msg = (char *)"invalid distance too far back";
                state->mode = BAD;
                break;
            }
#endif
            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
            state->mode = MATCH;
	    /* FALL THROUGH */
        case MATCH:
            if (left == 0) goto inf_leave;
            copy = out - left;
            if (state->offset > copy) {         /* copy from window */
                copy = state->offset - copy;
                if (copy > state->whave) {
                    if (state->sane) {
                        strm->msg = (char *)"invalid distance too far back";
                        state->mode = BAD;
                        break;
                    }
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
                    Trace((stderr, "inflate.c too far\n"));
                    copy -= state->whave;
                    if (copy > state->length) copy = state->length;
                    if (copy > left) copy = left;
                    left -= copy;
                    state->length -= copy;
                    do {
                        *put++ = 0;
                    } while (--copy);
                    if (state->length == 0) state->mode = LEN;
                    break;
#endif
                }
                if (copy > state->wnext) {
                    copy -= state->wnext;
                    from = state->window + (state->wsize - copy);
                }
                else
                    from = state->window + (state->wnext - copy);
                if (copy > state->length) copy = state->length;
            }
            else {                              /* copy from output */
                from = put - state->offset;
                copy = state->length;
            }
            if (copy > left) copy = left;
            left -= copy;
            state->length -= copy;
            do {
                *put++ = *from++;
            } while (--copy);
            if (state->length == 0) state->mode = LEN;
            break;
        case LIT:
            if (left == 0) goto inf_leave;
            *put++ = (unsigned char)(state->length);
            left--;
            state->mode = LEN;
            break;
        case CHECK:
            if (state->wrap) {
                NEEDBITS(32);
                out -= left;
                strm->total_out += out;
                state->total += out;
                if (out)
                    strm->adler = state->check =
                        UPDATE(state->check, put - out, out);
                out = left;
                if ((
#ifdef GUNZIP
                     state->flags ? hold :
#endif
                     ZSWAP32(hold)) != state->check) {
                    strm->msg = (char *)"incorrect data check";
                    state->mode = BAD;
                    break;
                }
                INITBITS();
                Tracev((stderr, "inflate:   check matches trailer\n"));
            }
#ifdef GUNZIP
            state->mode = LENGTH;
	    /* FALL THROUGH */
        case LENGTH:
            if (state->wrap && state->flags) {
                NEEDBITS(32);
                if (hold != (state->total & 0xffffffffUL)) {
                    strm->msg = (char *)"incorrect length check";
                    state->mode = BAD;
                    break;
                }
                INITBITS();
                Tracev((stderr, "inflate:   length matches trailer\n"));
            }
#endif
            state->mode = DONE;
	    /* FALL THROUGH */
        case DONE:
            ret = Z_STREAM_END;
            goto inf_leave;
        case BAD:
            ret = Z_DATA_ERROR;
            goto inf_leave;
        case MEM:
            return Z_MEM_ERROR;
        case SYNC:
        default:
            return Z_STREAM_ERROR;
        }

    /*
       Return from inflate(), updating the total counts and the check value.
       If there was no progress during the inflate() call, return a buffer
       error.  Call updatewindow() to create and/or update the window state.
       Note: a memory error from inflate() is non-recoverable.
     */
  inf_leave:
    RESTORE();
    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
            (state->mode < CHECK || flush != Z_FINISH)))
        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
            state->mode = MEM;
            return Z_MEM_ERROR;
        }
    in -= strm->avail_in;
    out -= strm->avail_out;
    strm->total_in += in;
    strm->total_out += out;
    state->total += out;
    if (state->wrap && out)
        strm->adler = state->check =
            UPDATE(state->check, strm->next_out - out, out);
    strm->data_type = state->bits + (state->last ? 64 : 0) +
                      (state->mode == TYPE ? 128 : 0) +
                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
        ret = Z_BUF_ERROR;
    return ret;
}

int ZEXPORT inflateEnd(strm)
z_streamp strm;
{
    struct inflate_state FAR *state;
    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
        return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    if (state->window != Z_NULL) ZFREE(strm, state->window);
    ZFREE(strm, strm->state);
    strm->state = Z_NULL;
    Tracev((stderr, "inflate: end\n"));
    return Z_OK;
}

int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
z_streamp strm;
Bytef *dictionary;
uInt *dictLength;
{
    struct inflate_state FAR *state;

    /* check state */
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;

    /* copy dictionary */
    if (state->whave && dictionary != Z_NULL) {
        zmemcpy(dictionary, state->window + state->wnext,
                state->whave - state->wnext);
        zmemcpy(dictionary + state->whave - state->wnext,
                state->window, state->wnext);
    }
    if (dictLength != Z_NULL)
        *dictLength = state->whave;
    return Z_OK;
}

int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
z_streamp strm;
const Bytef *dictionary;
uInt dictLength;
{
    struct inflate_state FAR *state;
    unsigned long dictid;
    int ret;

    /* check state */
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    if (state->wrap != 0 && state->mode != DICT)
        return Z_STREAM_ERROR;

    /* check for correct dictionary identifier */
    if (state->mode == DICT) {
        dictid = adler32(0L, Z_NULL, 0);
        dictid = adler32(dictid, dictionary, dictLength);
        if (dictid != state->check)
            return Z_DATA_ERROR;
    }

    /* copy dictionary to window using updatewindow(), which will amend the
       existing dictionary if appropriate */
    ret = updatewindow(strm, dictionary + dictLength, dictLength);
    if (ret) {
        state->mode = MEM;
        return Z_MEM_ERROR;
    }
    state->havedict = 1;
    Tracev((stderr, "inflate:   dictionary set\n"));
    return Z_OK;
}

int ZEXPORT inflateGetHeader(strm, head)
z_streamp strm;
gz_headerp head;
{
    struct inflate_state FAR *state;

    /* check state */
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;

    /* save header structure */
    state->head = head;
    head->done = 0;
    return Z_OK;
}

/*
   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
   or when out of input.  When called, *have is the number of pattern bytes
   found in order so far, in 0..3.  On return *have is updated to the new
   state.  If on return *have equals four, then the pattern was found and the
   return value is how many bytes were read including the last byte of the
   pattern.  If *have is less than four, then the pattern has not been found
   yet and the return value is len.  In the latter case, syncsearch() can be
   called again with more data and the *have state.  *have is initialized to
   zero for the first call.
 */
local unsigned syncsearch(have, buf, len)
unsigned FAR *have;
const unsigned char FAR *buf;
unsigned len;
{
    unsigned got;
    unsigned next;

    got = *have;
    next = 0;
    while (next < len && got < 4) {
        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
            got++;
        else if (buf[next])
            got = 0;
        else
            got = 4 - got;
        next++;
    }
    *have = got;
    return next;
}

int ZEXPORT inflateSync(strm)
z_streamp strm;
{
    unsigned len;               /* number of bytes to look at or looked at */
    unsigned long in, out;      /* temporary to save total_in and total_out */
    unsigned char buf[4];       /* to restore bit buffer to byte string */
    struct inflate_state FAR *state;

    /* check parameters */
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;

    /* if first time, start search in bit buffer */
    if (state->mode != SYNC) {
        state->mode = SYNC;
        state->hold <<= state->bits & 7;
        state->bits -= state->bits & 7;
        len = 0;
        while (state->bits >= 8) {
            buf[len++] = (unsigned char)(state->hold);
            state->hold >>= 8;
            state->bits -= 8;
        }
        state->have = 0;
        syncsearch(&(state->have), buf, len);
    }

    /* search available input */
    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
    strm->avail_in -= len;
    strm->next_in += len;
    strm->total_in += len;

    /* return no joy or set up to restart inflate() on a new block */
    if (state->have != 4) return Z_DATA_ERROR;
    in = strm->total_in;  out = strm->total_out;
    inflateReset(strm);
    strm->total_in = in;  strm->total_out = out;
    state->mode = TYPE;
    return Z_OK;
}

/*
   Returns true if inflate is currently at the end of a block generated by
   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
   implementation to provide an additional safety check. PPP uses
   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
   block. When decompressing, PPP checks that at the end of input packet,
   inflate is waiting for these length bytes.
 */
int ZEXPORT inflateSyncPoint(strm)
z_streamp strm;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    return state->mode == STORED && state->bits == 0;
}

int ZEXPORT inflateCopy(dest, source)
z_streamp dest;
z_streamp source;
{
    struct inflate_state FAR *state;
    struct inflate_state FAR *copy;
    unsigned char FAR *window;
    unsigned wsize;

    /* check input */
    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
        return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)source->state;

    /* allocate space */
    copy = (struct inflate_state FAR *)
           ZALLOC(source, 1, sizeof(struct inflate_state));
    if (copy == Z_NULL) return Z_MEM_ERROR;
    window = Z_NULL;
    if (state->window != Z_NULL) {
        window = (unsigned char FAR *)
                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
        if (window == Z_NULL) {
            ZFREE(source, copy);
            return Z_MEM_ERROR;
        }
    }

    /* copy state */
    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
    if (state->lencode >= state->codes &&
        state->lencode <= state->codes + ENOUGH - 1) {
        copy->lencode = copy->codes + (state->lencode - state->codes);
        copy->distcode = copy->codes + (state->distcode - state->codes);
    }
    copy->next = copy->codes + (state->next - state->codes);
    if (window != Z_NULL) {
        wsize = 1U << state->wbits;
        zmemcpy(window, state->window, wsize);
    }
    copy->window = window;
    dest->state = (struct internal_state FAR *)copy;
    return Z_OK;
}

int ZEXPORT inflateUndermine(strm, subvert)
z_streamp strm;
int subvert;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
    state->sane = !subvert;
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
    return Z_OK;
#else
    state->sane = 1;
    return Z_DATA_ERROR;
#endif
}

long ZEXPORT inflateMark(strm)
z_streamp strm;
{
    struct inflate_state FAR *state;

    if (strm == Z_NULL || strm->state == Z_NULL)
        return (long)(((unsigned long)0 - 1) << 16);
    state = (struct inflate_state FAR *)strm->state;
    return (long)(((unsigned long)((long)state->back)) << 16) +
        (state->mode == COPY ? state->length :
            (state->mode == MATCH ? state->was - state->length : 0));
}
rsync-3.2.7/zlib/compress.c0000664000000000000000000000474112155261705014332 0ustar  rootroot/* compress.c -- compress a memory buffer
 * Copyright (C) 1995-2005 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#define ZLIB_INTERNAL
#include "zlib.h"

/* ===========================================================================
     Compresses the source buffer into the destination buffer. The level
   parameter has the same meaning as in deflateInit.  sourceLen is the byte
   length of the source buffer. Upon entry, destLen is the total size of the
   destination buffer, which must be at least 0.1% larger than sourceLen plus
   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.

     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
   Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
    int level;
{
    z_stream stream;
    int err;

    stream.next_in = (z_const Bytef *)source;
    stream.avail_in = (uInt)sourceLen;
#ifdef MAXSEG_64K
    /* Check for source > 64K on 16-bit machine: */
    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
#endif
    stream.next_out = dest;
    stream.avail_out = (uInt)*destLen;
    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;

    stream.zalloc = (alloc_func)0;
    stream.zfree = (free_func)0;
    stream.opaque = (voidpf)0;

    err = deflateInit(&stream, level);
    if (err != Z_OK) return err;

    err = deflate(&stream, Z_FINISH);
    if (err != Z_STREAM_END) {
        deflateEnd(&stream);
        return err == Z_OK ? Z_BUF_ERROR : err;
    }
    *destLen = stream.total_out;

    err = deflateEnd(&stream);
    return err;
}

/* ===========================================================================
 */
int ZEXPORT compress (dest, destLen, source, sourceLen)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
{
    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}

/* ===========================================================================
     If the default memLevel or windowBits for deflateInit() is changed, then
   this function needs to be updated.
 */
uLong ZEXPORT compressBound (sourceLen)
    uLong sourceLen;
{
    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
           (sourceLen >> 25) + 13;
}
rsync-3.2.7/zlib/zconf.h0000664000000000000000000003622412155261705013624 0ustar  rootroot/* zconf.h -- configuration of the zlib compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#ifndef ZCONF_H
#define ZCONF_H

/*
 * If you *really* need a unique prefix for all types and library functions,
 * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
 * Even better than compiling with -DZ_PREFIX would be to use configure to set
 * this permanently in zconf.h using "./configure --zprefix".
 */
#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
#  define Z_PREFIX_SET

/* all linked symbols */
#  define _dist_code            z__dist_code
#  define _length_code          z__length_code
#  define _tr_align             z__tr_align
#  define _tr_flush_bits        z__tr_flush_bits
#  define _tr_flush_block       z__tr_flush_block
#  define _tr_init              z__tr_init
#  define _tr_stored_block      z__tr_stored_block
#  define _tr_tally             z__tr_tally
#  define adler32               z_adler32
#  define adler32_combine       z_adler32_combine
#  define adler32_combine64     z_adler32_combine64
#  ifndef Z_SOLO
#    define compress              z_compress
#    define compress2             z_compress2
#    define compressBound         z_compressBound
#  endif
#  define crc32                 z_crc32
#  define crc32_combine         z_crc32_combine
#  define crc32_combine64       z_crc32_combine64
#  define deflate               z_deflate
#  define deflateBound          z_deflateBound
#  define deflateCopy           z_deflateCopy
#  define deflateEnd            z_deflateEnd
#  define deflateInit2_         z_deflateInit2_
#  define deflateInit_          z_deflateInit_
#  define deflateParams         z_deflateParams
#  define deflatePending        z_deflatePending
#  define deflatePrime          z_deflatePrime
#  define deflateReset          z_deflateReset
#  define deflateResetKeep      z_deflateResetKeep
#  define deflateSetDictionary  z_deflateSetDictionary
#  define deflateSetHeader      z_deflateSetHeader
#  define deflateTune           z_deflateTune
#  define deflate_copyright     z_deflate_copyright
#  define get_crc_table         z_get_crc_table
#  ifndef Z_SOLO
#    define gz_error              z_gz_error
#    define gz_intmax             z_gz_intmax
#    define gz_strwinerror        z_gz_strwinerror
#    define gzbuffer              z_gzbuffer
#    define gzclearerr            z_gzclearerr
#    define gzclose               z_gzclose
#    define gzclose_r             z_gzclose_r
#    define gzclose_w             z_gzclose_w
#    define gzdirect              z_gzdirect
#    define gzdopen               z_gzdopen
#    define gzeof                 z_gzeof
#    define gzerror               z_gzerror
#    define gzflush               z_gzflush
#    define gzgetc                z_gzgetc
#    define gzgetc_               z_gzgetc_
#    define gzgets                z_gzgets
#    define gzoffset              z_gzoffset
#    define gzoffset64            z_gzoffset64
#    define gzopen                z_gzopen
#    define gzopen64              z_gzopen64
#    ifdef _WIN32
#      define gzopen_w              z_gzopen_w
#    endif
#    define gzprintf              z_gzprintf
#    define gzvprintf             z_gzvprintf
#    define gzputc                z_gzputc
#    define gzputs                z_gzputs
#    define gzread                z_gzread
#    define gzrewind              z_gzrewind
#    define gzseek                z_gzseek
#    define gzseek64              z_gzseek64
#    define gzsetparams           z_gzsetparams
#    define gztell                z_gztell
#    define gztell64              z_gztell64
#    define gzungetc              z_gzungetc
#    define gzwrite               z_gzwrite
#  endif
#  define inflate               z_inflate
#  define inflateBack           z_inflateBack
#  define inflateBackEnd        z_inflateBackEnd
#  define inflateBackInit_      z_inflateBackInit_
#  define inflateCopy           z_inflateCopy
#  define inflateEnd            z_inflateEnd
#  define inflateGetHeader      z_inflateGetHeader
#  define inflateInit2_         z_inflateInit2_
#  define inflateInit_          z_inflateInit_
#  define inflateMark           z_inflateMark
#  define inflatePrime          z_inflatePrime
#  define inflateReset          z_inflateReset
#  define inflateReset2         z_inflateReset2
#  define inflateSetDictionary  z_inflateSetDictionary
#  define inflateGetDictionary  z_inflateGetDictionary
#  define inflateSync           z_inflateSync
#  define inflateSyncPoint      z_inflateSyncPoint
#  define inflateUndermine      z_inflateUndermine
#  define inflateResetKeep      z_inflateResetKeep
#  define inflate_copyright     z_inflate_copyright
#  define inflate_fast          z_inflate_fast
#  define inflate_table         z_inflate_table
#  ifndef Z_SOLO
#    define uncompress            z_uncompress
#  endif
#  define zError                z_zError
#  ifndef Z_SOLO
#    define zcalloc               z_zcalloc
#    define zcfree                z_zcfree
#  endif
#  define zlibCompileFlags      z_zlibCompileFlags
#  define zlibVersion           z_zlibVersion

/* all zlib typedefs in zlib.h and zconf.h */
#  define Byte                  z_Byte
#  define Bytef                 z_Bytef
#  define alloc_func            z_alloc_func
#  define charf                 z_charf
#  define free_func             z_free_func
#  ifndef Z_SOLO
#    define gzFile                z_gzFile
#  endif
#  define gz_header             z_gz_header
#  define gz_headerp            z_gz_headerp
#  define in_func               z_in_func
#  define intf                  z_intf
#  define out_func              z_out_func
#  define uInt                  z_uInt
#  define uIntf                 z_uIntf
#  define uLong                 z_uLong
#  define uLongf                z_uLongf
#  define voidp                 z_voidp
#  define voidpc                z_voidpc
#  define voidpf                z_voidpf

/* all zlib structs in zlib.h and zconf.h */
#  define gz_header_s           z_gz_header_s
#  define internal_state        z_internal_state

#endif

#if defined(__MSDOS__) && !defined(MSDOS)
#  define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
#  define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
#  define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
#  ifndef WIN32
#    define WIN32
#  endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
#    ifndef SYS16BIT
#      define SYS16BIT
#    endif
#  endif
#endif

/*
 * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
 * than 64k bytes at a time (needed on systems with 16-bit int).
 */
#ifdef SYS16BIT
#  define MAXSEG_64K
#endif
#ifdef MSDOS
#  define UNALIGNED_OK
#endif

#ifdef __STDC_VERSION__
#  ifndef STDC
#    define STDC
#  endif
#  if __STDC_VERSION__ >= 199901L
#    ifndef STDC99
#      define STDC99
#    endif
#  endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
#  define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
#  define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
#  define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
#  define STDC
#endif

#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
#  define STDC
#endif

#ifndef STDC
#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
#    define const       /* note: need a more gentle solution here */
#  endif
#endif

#if defined(ZLIB_CONST) && !defined(z_const)
#  define z_const const
#else
#  define z_const
#endif

/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
#  define NO_DUMMY_DECL
#endif

/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
#  ifdef MAXSEG_64K
#    define MAX_MEM_LEVEL 8
#  else
#    define MAX_MEM_LEVEL 9
#  endif
#endif

/* Maximum value for windowBits in deflateInit2 and inflateInit2.
 * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
 * created by gzip. (Files created by minigzip can still be extracted by
 * gzip.)
 */
#ifndef MAX_WBITS
#  define MAX_WBITS   15 /* 32K LZ77 window */
#endif

/* The memory requirements for deflate are (in bytes):
            (1 << (windowBits+2)) +  (1 << (memLevel+9))
 that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
 plus a few kilobytes for small objects. For example, if you want to reduce
 the default memory requirements from 256K to 128K, compile with
     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
 Of course this will generally degrade compression (there's no free lunch).

   The memory requirements for inflate are (in bytes) 1 << windowBits
 that is, 32K for windowBits=15 (default value) plus a few kilobytes
 for small objects.
*/

                        /* Type declarations */

#ifndef OF /* function prototypes */
#  ifdef STDC
#    define OF(args)  args
#  else
#    define OF(args)  ()
#  endif
#endif

#ifndef Z_ARG /* function prototypes for stdarg */
#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
#    define Z_ARG(args)  args
#  else
#    define Z_ARG(args)  ()
#  endif
#endif

/* The following definitions for FAR are needed only for MSDOS mixed
 * model programming (small or medium model with some far allocations).
 * This was tested only with MSC; for other MSDOS compilers you may have
 * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
 * just define FAR to be empty.
 */
#ifdef SYS16BIT
#  if defined(M_I86SM) || defined(M_I86MM)
     /* MSC small or medium model */
#    define SMALL_MEDIUM
#    ifdef _MSC_VER
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#  if (defined(__SMALL__) || defined(__MEDIUM__))
     /* Turbo C small or medium model */
#    define SMALL_MEDIUM
#    ifdef __BORLANDC__
#      define FAR _far
#    else
#      define FAR far
#    endif
#  endif
#endif

#if defined(WINDOWS) || defined(WIN32)
   /* If building or using zlib as a DLL, define ZLIB_DLL.
    * This is not mandatory, but it offers a little performance increase.
    */
#  ifdef ZLIB_DLL
#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
#      ifdef ZLIB_INTERNAL
#        define ZEXTERN extern __declspec(dllexport)
#      else
#        define ZEXTERN extern __declspec(dllimport)
#      endif
#    endif
#  endif  /* ZLIB_DLL */
   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
    * define ZLIB_WINAPI.
    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
    */
#  ifdef ZLIB_WINAPI
#    ifdef FAR
#      undef FAR
#    endif
#    include 
     /* No need for _export, use ZLIB.DEF instead. */
     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
#    define ZEXPORT WINAPI
#    ifdef WIN32
#      define ZEXPORTVA WINAPIV
#    else
#      define ZEXPORTVA FAR CDECL
#    endif
#  endif
#endif

#if defined (__BEOS__)
#  ifdef ZLIB_DLL
#    ifdef ZLIB_INTERNAL
#      define ZEXPORT   __declspec(dllexport)
#      define ZEXPORTVA __declspec(dllexport)
#    else
#      define ZEXPORT   __declspec(dllimport)
#      define ZEXPORTVA __declspec(dllimport)
#    endif
#  endif
#endif

#ifndef ZEXTERN
#  define ZEXTERN extern
#endif
#ifndef ZEXPORT
#  define ZEXPORT
#endif
#ifndef ZEXPORTVA
#  define ZEXPORTVA
#endif

#ifndef FAR
#  define FAR
#endif

#if !defined(__MACTYPES__)
typedef unsigned char  Byte;  /* 8 bits */
#endif
typedef unsigned int   uInt;  /* 16 bits or more */
typedef unsigned long  uLong; /* 32 bits or more */

#ifdef SMALL_MEDIUM
   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
#  define Bytef Byte FAR
#else
   typedef Byte  FAR Bytef;
#endif
typedef char  FAR charf;
typedef int   FAR intf;
typedef uInt  FAR uIntf;
typedef uLong FAR uLongf;

#ifdef STDC
   typedef void const *voidpc;
   typedef void FAR   *voidpf;
   typedef void       *voidp;
#else
   typedef Byte const *voidpc;
   typedef Byte FAR   *voidpf;
   typedef Byte       *voidp;
#endif

#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
#  include 
#  if (UINT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned
#  elif (ULONG_MAX == 0xffffffffUL)
#    define Z_U4 unsigned long
#  elif (USHRT_MAX == 0xffffffffUL)
#    define Z_U4 unsigned short
#  endif
#endif

#ifdef Z_U4
   typedef Z_U4 z_crc_t;
#else
   typedef unsigned long z_crc_t;
#endif

#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_UNISTD_H
#endif

#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
#  define Z_HAVE_STDARG_H
#endif

#ifdef STDC
#  ifndef Z_SOLO
#    include       /* for off_t */
#  endif
#endif

#if defined(STDC) || defined(Z_HAVE_STDARG_H)
#  ifndef Z_SOLO
#    include          /* for va_list */
#  endif
#endif

#ifdef _WIN32
#  ifndef Z_SOLO
#    include          /* for wchar_t */
#  endif
#endif

/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
 * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
 * though the former does not conform to the LFS document), but considering
 * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
 * equivalently requesting no 64-bit operations
 */
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
#  undef _LARGEFILE64_SOURCE
#endif

#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
#  define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
#    include          /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
#    ifdef VMS
#      include        /* for off_t */
#    endif
#    ifndef z_off_t
#      define z_off_t off_t
#    endif
#  endif
#endif

#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
#  define Z_LFS64
#endif

#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
#  define Z_LARGE64
#endif

#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
#  define Z_WANT64
#endif

#if !defined(SEEK_SET) && !defined(Z_SOLO)
#  define SEEK_SET        0       /* Seek from beginning of file.  */
#  define SEEK_CUR        1       /* Seek from current position.  */
#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
#endif

#ifndef z_off_t
#  define z_off_t long
#endif

#if !defined(_WIN32) && defined(Z_LARGE64)
#  define z_off64_t off64_t
#else
#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
#    define z_off64_t __int64
#  else
#    define z_off64_t z_off_t
#  endif
#endif

/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
  #pragma map(deflateInit_,"DEIN")
  #pragma map(deflateInit2_,"DEIN2")
  #pragma map(deflateEnd,"DEEND")
  #pragma map(deflateBound,"DEBND")
  #pragma map(inflateInit_,"ININ")
  #pragma map(inflateInit2_,"ININ2")
  #pragma map(inflateEnd,"INEND")
  #pragma map(inflateSync,"INSY")
  #pragma map(inflateSetDictionary,"INSEDI")
  #pragma map(compressBound,"CMBND")
  #pragma map(inflate_table,"INTABL")
  #pragma map(inflate_fast,"INFA")
  #pragma map(inflate_copyright,"INCOPY")
#endif

#endif /* ZCONF_H */
rsync-3.2.7/zlib/README.rsync0000664000000000000000000000255507447570414014361 0ustar  rootrootREAD THIS BEFORE TRYING TO DYNAMICALLY LINK RSYNC AND ZLIB!

zlib has been adapted slightly for use in rsync. Please don't bother
the zlib authors with problems related to the use of zlib in rsync as
any bugs are likely to be our fault and not theirs.

Specific changes that have been made to zlib for rsync include:

- add Z_INSERT_ONLY to allow for efficient history updating without
  actually emitting any data. This is used to compress the matched
  blocks that don't cross the wire, which gives better compression
  ratios on the literal data.

- fixed a number of minor compilation issues. (redefinition of MAX and
  other such trivial things)

- include rsync.h to ensure that we get a consistent set of includes
  for all C code in rsync and to take advantage of autoconf

As a result of the first item, the streams from rsync's version of
zlib are *not compatible* with those produced by the upstream version
of rsync.  In other words, if you link rsync against your system's
copy, it will not be able to interoperate with any other version if
the -z option is used.  (Sorry.  Sometimes standard is better than
better.)

The rsync maintainers hope to fix this problem in the future by either
merging our changes into the upstream version, or backing them out of
rsync in a way that preserves wire compatibility.  But in the meantime
this version must be maintained in parallel.

rsync-3.2.7/zlib/inffast.c0000664000000000000000000003115713443225253014131 0ustar  rootroot/* inffast.c -- fast decoding
 * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"

#ifndef ASMINF

/*
   Decode literal, length, and distance codes and write out the resulting
   literal and match bytes until either not enough input or output is
   available, an end-of-block is encountered, or a data error is encountered.
   When large enough input and output buffers are supplied to inflate(), for
   example, a 16K input buffer and a 64K output buffer, more than 95% of the
   inflate execution time is spent in this routine.

   Entry assumptions:

        state->mode == LEN
        strm->avail_in >= 6
        strm->avail_out >= 258
        start >= strm->avail_out
        state->bits < 8

   On return, state->mode is one of:

        LEN -- ran out of enough output space or enough available input
        TYPE -- reached end of block code, inflate() to interpret next block
        BAD -- error in block data

   Notes:

    - The maximum input bits used by a length/distance pair is 15 bits for the
      length code, 5 bits for the length extra, 15 bits for the distance code,
      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
      Therefore if strm->avail_in >= 6, then there is enough input to avoid
      checking for available input while decoding.

    - The maximum bytes that a single length/distance pair can output is 258
      bytes, which is the maximum length that can be coded.  inflate_fast()
      requires strm->avail_out >= 258 for each loop to avoid checking for
      output space.
 */
void ZLIB_INTERNAL inflate_fast(strm, start)
z_streamp strm;
unsigned start;         /* inflate()'s starting value for strm->avail_out */
{
    struct inflate_state FAR *state;
    z_const unsigned char FAR *in;      /* local strm->next_in */
    z_const unsigned char FAR *last;    /* have enough input while in < last */
    unsigned char FAR *out;     /* local strm->next_out */
    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
    unsigned char FAR *end;     /* while out < end, enough space available */
#ifdef INFLATE_STRICT
    unsigned dmax;              /* maximum distance from zlib header */
#endif
    unsigned wsize;             /* window size or zero if not using window */
    unsigned whave;             /* valid bytes in the window */
    unsigned wnext;             /* window write index */
    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
    unsigned long hold;         /* local strm->hold */
    unsigned bits;              /* local strm->bits */
    code const FAR *lcode;      /* local strm->lencode */
    code const FAR *dcode;      /* local strm->distcode */
    unsigned lmask;             /* mask for first level of length codes */
    unsigned dmask;             /* mask for first level of distance codes */
    code here;                  /* retrieved table entry */
    unsigned op;                /* code bits, operation, extra bits, or */
                                /*  window position, window bytes to copy */
    unsigned len;               /* match length, unused bytes */
    unsigned dist;              /* match distance */
    unsigned char FAR *from;    /* where to copy match from */

    /* copy state to local variables */
    state = (struct inflate_state FAR *)strm->state;
    in = strm->next_in;
    last = in + (strm->avail_in - 5);
    out = strm->next_out;
    beg = out - (start - strm->avail_out);
    end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT
    dmax = state->dmax;
#endif
    wsize = state->wsize;
    whave = state->whave;
    wnext = state->wnext;
    window = state->window;
    hold = state->hold;
    bits = state->bits;
    lcode = state->lencode;
    dcode = state->distcode;
    lmask = (1U << state->lenbits) - 1;
    dmask = (1U << state->distbits) - 1;

    /* decode literals and length/distances until end-of-block or not enough
       input data or output space */
    do {
        if (bits < 15) {
            hold += (unsigned long)(*in++) << bits;
            bits += 8;
            hold += (unsigned long)(*in++) << bits;
            bits += 8;
        }
        here = lcode[hold & lmask];
      dolen:
        op = (unsigned)(here.bits);
        hold >>= op;
        bits -= op;
        op = (unsigned)(here.op);
        if (op == 0) {                          /* literal */
            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
                    "inflate:         literal '%c'\n" :
                    "inflate:         literal 0x%02x\n", here.val));
            *out++ = (unsigned char)(here.val);
        }
        else if (op & 16) {                     /* length base */
            len = (unsigned)(here.val);
            op &= 15;                           /* number of extra bits */
            if (op) {
                if (bits < op) {
                    hold += (unsigned long)(*in++) << bits;
                    bits += 8;
                }
                len += (unsigned)hold & ((1U << op) - 1);
                hold >>= op;
                bits -= op;
            }
            Tracevv((stderr, "inflate:         length %u\n", len));
            if (bits < 15) {
                hold += (unsigned long)(*in++) << bits;
                bits += 8;
                hold += (unsigned long)(*in++) << bits;
                bits += 8;
            }
            here = dcode[hold & dmask];
          dodist:
            op = (unsigned)(here.bits);
            hold >>= op;
            bits -= op;
            op = (unsigned)(here.op);
            if (op & 16) {                      /* distance base */
                dist = (unsigned)(here.val);
                op &= 15;                       /* number of extra bits */
                if (bits < op) {
                    hold += (unsigned long)(*in++) << bits;
                    bits += 8;
                    if (bits < op) {
                        hold += (unsigned long)(*in++) << bits;
                        bits += 8;
                    }
                }
                dist += (unsigned)hold & ((1U << op) - 1);
#ifdef INFLATE_STRICT
                if (dist > dmax) {
                    strm->msg = (char *)"invalid distance too far back";
                    state->mode = BAD;
                    break;
                }
#endif
                hold >>= op;
                bits -= op;
                Tracevv((stderr, "inflate:         distance %u\n", dist));
                op = (unsigned)(out - beg);     /* max distance in output */
                if (dist > op) {                /* see if copy from window */
                    op = dist - op;             /* distance back in window */
                    if (op > whave) {
                        if (state->sane) {
                            strm->msg =
                                (char *)"invalid distance too far back";
                            state->mode = BAD;
                            break;
                        }
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
                        if (len <= op - whave) {
                            do {
                                *out++ = 0;
                            } while (--len);
                            continue;
                        }
                        len -= op - whave;
                        do {
                            *out++ = 0;
                        } while (--op > whave);
                        if (op == 0) {
                            from = out - dist;
                            do {
                                *out++ = *from++;
                            } while (--len);
                            continue;
                        }
#endif
                    }
                    from = window;
                    if (wnext == 0) {           /* very common case */
                        from += wsize - op;
                        if (op < len) {         /* some from window */
                            len -= op;
                            do {
                                *out++ = *from++;
                            } while (--op);
                            from = out - dist;  /* rest from output */
                        }
                    }
                    else if (wnext < op) {      /* wrap around window */
                        from += wsize + wnext - op;
                        op -= wnext;
                        if (op < len) {         /* some from end of window */
                            len -= op;
                            do {
                                *out++ = *from++;
                            } while (--op);
                            from = window;
                            if (wnext < len) {  /* some from start of window */
                                op = wnext;
                                len -= op;
                                do {
                                    *out++ = *from++;
                                } while (--op);
                                from = out - dist;      /* rest from output */
                            }
                        }
                    }
                    else {                      /* contiguous in window */
                        from += wnext - op;
                        if (op < len) {         /* some from window */
                            len -= op;
                            do {
                                *out++ = *from++;
                            } while (--op);
                            from = out - dist;  /* rest from output */
                        }
                    }
                    while (len > 2) {
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        len -= 3;
                    }
                    if (len) {
                        *out++ = *from++;
                        if (len > 1)
                            *out++ = *from++;
                    }
                }
                else {
                    from = out - dist;          /* copy direct from output */
                    do {                        /* minimum length is three */
                        *out++ = *from++;
                        *out++ = *from++;
                        *out++ = *from++;
                        len -= 3;
                    } while (len > 2);
                    if (len) {
                        *out++ = *from++;
                        if (len > 1)
                            *out++ = *from++;
                    }
                }
            }
            else if ((op & 64) == 0) {          /* 2nd level distance code */
                here = dcode[here.val + (hold & ((1U << op) - 1))];
                goto dodist;
            }
            else {
                strm->msg = (char *)"invalid distance code";
                state->mode = BAD;
                break;
            }
        }
        else if ((op & 64) == 0) {              /* 2nd level length code */
            here = lcode[here.val + (hold & ((1U << op) - 1))];
            goto dolen;
        }
        else if (op & 32) {                     /* end-of-block */
            Tracevv((stderr, "inflate:         end of block\n"));
            state->mode = TYPE;
            break;
        }
        else {
            strm->msg = (char *)"invalid literal/length code";
            state->mode = BAD;
            break;
        }
    } while (in < last && out < end);

    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
    len = bits >> 3;
    in -= len;
    bits -= len << 3;
    hold &= (1U << bits) - 1;

    /* update state and return */
    strm->next_in = in;
    strm->next_out = out;
    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
    strm->avail_out = (unsigned)(out < end ?
                                 257 + (end - out) : 257 - (out - end));
    state->hold = hold;
    state->bits = bits;
    return;
}

/*
   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
   - Using bit fields for code structure
   - Different op definition to avoid & for extra bits (do & for table bits)
   - Three separate decoding do-loops for direct, window, and wnext == 0
   - Special case for distance > 1 copies to do overlapped load and store copy
   - Explicit branch predictions (based on measured branch probabilities)
   - Deferring match copy and interspersed it with decoding subsequent codes
   - Swapping literal/length else
   - Swapping window/direct else
   - Larger unrolled copy loops (three is about right)
   - Moving len -= 3 statement into middle of loop
 */

#endif /* !ASMINF */
rsync-3.2.7/zlib/deflate.c0000664000000000000000000022105214225047132014073 0ustar  rootroot/* deflate.c -- compress data using the deflation algorithm
 * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/*
 *  ALGORITHM
 *
 *      The "deflation" process depends on being able to identify portions
 *      of the input text which are identical to earlier input (within a
 *      sliding window trailing behind the input currently being processed).
 *
 *      The most straightforward technique turns out to be the fastest for
 *      most input files: try all possible matches and select the longest.
 *      The key feature of this algorithm is that insertions into the string
 *      dictionary are very simple and thus fast, and deletions are avoided
 *      completely. Insertions are performed at each input character, whereas
 *      string matches are performed only when the previous match ends. So it
 *      is preferable to spend more time in matches to allow very fast string
 *      insertions and avoid deletions. The matching algorithm for small
 *      strings is inspired from that of Rabin & Karp. A brute force approach
 *      is used to find longer strings when a small match has been found.
 *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
 *      (by Leonid Broukhis).
 *         A previous version of this file used a more sophisticated algorithm
 *      (by Fiala and Greene) which is guaranteed to run in linear amortized
 *      time, but has a larger average cost, uses more memory and is patented.
 *      However the F&G algorithm may be faster for some highly redundant
 *      files if the parameter max_chain_length (described below) is too large.
 *
 *  ACKNOWLEDGEMENTS
 *
 *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
 *      I found it in 'freeze' written by Leonid Broukhis.
 *      Thanks to many people for bug reports and testing.
 *
 *  REFERENCES
 *
 *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
 *      Available in http://tools.ietf.org/html/rfc1951
 *
 *      A description of the Rabin and Karp algorithm is given in the book
 *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
 *
 *      Fiala,E.R., and Greene,D.H.
 *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
 *
 */

/* @(#) $Id$ */

#include "deflate.h"

#define read_buf dread_buf

const char deflate_copyright[] =
   " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
/*
  If you use the zlib library in a product, an acknowledgment is welcome
  in the documentation of your product. If for some reason you cannot
  include such an acknowledgment, I would appreciate that you keep this
  copyright string in the executable of your product.
 */

/* ===========================================================================
 *  Function prototypes.
 */
typedef enum {
    need_more,      /* block not completed, need more input or more output */
    block_done,     /* block flush performed */
    finish_started, /* finish started, need only more output at next deflate */
    finish_done     /* finish done, accept no more input or output */
} block_state;

typedef block_state (*compress_func) OF((deflate_state *s, int flush));
/* Compression function. Returns the block state after the call. */

local void fill_window    OF((deflate_state *s));
local block_state deflate_stored OF((deflate_state *s, int flush));
local block_state deflate_fast   OF((deflate_state *s, int flush));
#ifndef FASTEST
local block_state deflate_slow   OF((deflate_state *s, int flush));
#endif
local block_state deflate_rle    OF((deflate_state *s, int flush));
local block_state deflate_huff   OF((deflate_state *s, int flush));
local void lm_init        OF((deflate_state *s));
local void putShortMSB    OF((deflate_state *s, uInt b));
local void flush_pending  OF((z_streamp strm));
local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV
      void match_init OF((void)); /* asm code initialization */
      uInt longest_match  OF((deflate_state *s, IPos cur_match));
#else
local uInt longest_match  OF((deflate_state *s, IPos cur_match));
#endif

#ifdef DEBUG
local  void check_match OF((deflate_state *s, IPos start, IPos match,
                            int length));
#endif

/* ===========================================================================
 * Local data
 */

#define NIL 0
/* Tail of hash chains */

#ifndef TOO_FAR
#  define TOO_FAR 4096
#endif
/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */

/* Values for max_lazy_match, good_match and max_chain_length, depending on
 * the desired pack level (0..9). The values given below have been tuned to
 * exclude worst case performance for pathological files. Better values may be
 * found for specific files.
 */
typedef struct config_s {
   ush good_length; /* reduce lazy search above this match length */
   ush max_lazy;    /* do not perform lazy search above this match length */
   ush nice_length; /* quit search above this match length */
   ush max_chain;
   compress_func func;
} config;

#ifdef FASTEST
local const config configuration_table[2] = {
/*      good lazy nice chain */
/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
#else
local const config configuration_table[10] = {
/*      good lazy nice chain */
/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
/* 2 */ {4,    5, 16,    8, deflate_fast},
/* 3 */ {4,    6, 32,   32, deflate_fast},

/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
/* 5 */ {8,   16, 32,   32, deflate_slow},
/* 6 */ {8,   16, 128, 128, deflate_slow},
/* 7 */ {8,   32, 128, 256, deflate_slow},
/* 8 */ {32, 128, 258, 1024, deflate_slow},
/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
#endif

/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
 * meaning.
 */

#define EQUAL 0
/* result of memcmp for equal strings */

#ifndef NO_DUMMY_DECL
struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
#endif

/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))

/* ===========================================================================
 * Update a hash value with the given input byte
 * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
 *    input characters, so that a running hash key can be computed from the
 *    previous key instead of complete recalculation each time.
 */
#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask)


/* ===========================================================================
 * Insert string str in the dictionary and set match_head to the previous head
 * of the hash chain (the most recent string with same hash key). Return
 * the previous length of the hash chain.
 * If this file is compiled with -DFASTEST, the compression level is forced
 * to 1, and no hash chains are maintained.
 * IN  assertion: all calls to to INSERT_STRING are made with consecutive
 *    input characters and the first MIN_MATCH bytes of str are valid
 *    (except for the last MIN_MATCH-1 bytes of the input file).
 */
#ifdef FASTEST
#define INSERT_STRING(s, str, match_head) \
   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
    match_head = s->head[s->ins_h], \
    s->head[s->ins_h] = (Pos)(str))
#else
#define INSERT_STRING(s, str, match_head) \
   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
    s->head[s->ins_h] = (Pos)(str))
#endif

/* ===========================================================================
 * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
 * prev[] will be initialized on the fly.
 */
#define CLEAR_HASH(s) \
    s->head[s->hash_size-1] = NIL; \
    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));

/* ========================================================================= */
int ZEXPORT deflateInit_(strm, level, version, stream_size)
    z_streamp strm;
    int level;
    const char *version;
    int stream_size;
{
    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
                         Z_DEFAULT_STRATEGY, version, stream_size);
    /* To do: ignore strm->next_in if we use it as window */
}

/* ========================================================================= */
int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
                  version, stream_size)
    z_streamp strm;
    int  level;
    int  method;
    int  windowBits;
    int  memLevel;
    int  strategy;
    const char *version;
    int stream_size;
{
    deflate_state *s;
    int wrap = 1;
    static const char my_version[] = ZLIB_VERSION;

    if (version == Z_NULL || version[0] != my_version[0] ||
        stream_size != sizeof(z_stream)) {
        return Z_VERSION_ERROR;
    }
    if (strm == Z_NULL) return Z_STREAM_ERROR;

    strm->msg = Z_NULL;
    if (strm->zalloc == (alloc_func)0) {
#ifdef Z_SOLO
        return Z_STREAM_ERROR;
#else
        strm->zalloc = zcalloc;
        strm->opaque = (voidpf)0;
#endif
    }
    if (strm->zfree == (free_func)0)
#ifdef Z_SOLO
        return Z_STREAM_ERROR;
#else
        strm->zfree = zcfree;
#endif

#ifdef FASTEST
    if (level != 0) level = 1;
#else
    if (level == Z_DEFAULT_COMPRESSION) level = 6;
#endif

    if (windowBits < 0) { /* suppress zlib wrapper */
        wrap = 0;
        windowBits = -windowBits;
    }
#ifdef GZIP
    else if (windowBits > 15) {
        wrap = 2;       /* write gzip wrapper instead */
        windowBits -= 16;
    }
#endif
    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
        strategy < 0 || strategy > Z_FIXED) {
        return Z_STREAM_ERROR;
    }
    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
    if (s == Z_NULL) return Z_MEM_ERROR;
    strm->state = (struct internal_state FAR *)s;
    s->strm = strm;

    s->wrap = wrap;
    s->gzhead = Z_NULL;
    s->w_bits = windowBits;
    s->w_size = 1 << s->w_bits;
    s->w_mask = s->w_size - 1;

    s->hash_bits = memLevel + 7;
    s->hash_size = 1 << s->hash_bits;
    s->hash_mask = s->hash_size - 1;
    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);

    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));

    s->high_water = 0;      /* nothing written to s->window yet */

    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */

    /* We overlay pending_buf and sym_buf. This works since the average size
     * for length/distance pairs over any compressed block is assured to be 31
     * bits or less.
     *
     * Analysis: The longest fixed codes are a length code of 8 bits plus 5
     * extra bits, for lengths 131 to 257. The longest fixed distance codes are
     * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
     * possible fixed-codes length/distance pair is then 31 bits total.
     *
     * sym_buf starts one-fourth of the way into pending_buf. So there are
     * three bytes in sym_buf for every four bytes in pending_buf. Each symbol
     * in sym_buf is three bytes -- two for the distance and one for the
     * literal/length. As each symbol is consumed, the pointer to the next
     * sym_buf value to read moves forward three bytes. From that symbol, up to
     * 31 bits are written to pending_buf. The closest the written pending_buf
     * bits gets to the next sym_buf symbol to read is just before the last
     * code is written. At that time, 31*(n-2) bits have been written, just
     * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
     * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
     * symbols are written.) The closest the writing gets to what is unread is
     * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
     * can range from 128 to 32768.
     *
     * Therefore, at a minimum, there are 142 bits of space between what is
     * written and what is read in the overlain buffers, so the symbols cannot
     * be overwritten by the compressed data. That space is actually 139 bits,
     * due to the three-bit fixed-code block header.
     *
     * That covers the case where either Z_FIXED is specified, forcing fixed
     * codes, or when the use of fixed codes is chosen, because that choice
     * results in a smaller compressed block than dynamic codes. That latter
     * condition then assures that the above analysis also covers all dynamic
     * blocks. A dynamic-code block will only be chosen to be emitted if it has
     * fewer bits than a fixed-code block would for the same set of symbols.
     * Therefore its average symbol length is assured to be less than 31. So
     * the compressed data for a dynamic block also cannot overwrite the
     * symbols from which it is being constructed.
     */

    s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
    s->pending_buf_size = (ulg)s->lit_bufsize * 4;

    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
        s->pending_buf == Z_NULL) {
        s->status = FINISH_STATE;
        strm->msg = ERR_MSG(Z_MEM_ERROR);
        deflateEnd (strm);
        return Z_MEM_ERROR;
    }
    s->sym_buf = s->pending_buf + s->lit_bufsize;
    s->sym_end = (s->lit_bufsize - 1) * 3;
    /* We avoid equality with lit_bufsize*3 because of wraparound at 64K
     * on 16 bit machines and because stored blocks are restricted to
     * 64K-1 bytes.
     */

    s->level = level;
    s->strategy = strategy;
    s->method = (Byte)method;

    return deflateReset(strm);
}

/* ========================================================================= */
int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
    z_streamp strm;
    const Bytef *dictionary;
    uInt  dictLength;
{
    deflate_state *s;
    uInt str, n;
    int wrap;
    unsigned avail;
    z_const unsigned char *next;

    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
        return Z_STREAM_ERROR;
    s = strm->state;
    wrap = s->wrap;
    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
        return Z_STREAM_ERROR;

    /* when using zlib wrappers, compute Adler-32 for provided dictionary */
    if (wrap == 1)
        strm->adler = adler32(strm->adler, dictionary, dictLength);
    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */

    /* if dictionary would fill window, just replace the history */
    if (dictLength >= s->w_size) {
        if (wrap == 0) {            /* already empty otherwise */
            CLEAR_HASH(s);
            s->strstart = 0;
            s->block_start = 0L;
            s->insert = 0;
        }
        dictionary += dictLength - s->w_size;  /* use the tail */
        dictLength = s->w_size;
    }

    /* insert dictionary into window and hash */
    avail = strm->avail_in;
    next = strm->next_in;
    strm->avail_in = dictLength;
    strm->next_in = (z_const Bytef *)dictionary;
    fill_window(s);
    while (s->lookahead >= MIN_MATCH) {
        str = s->strstart;
        n = s->lookahead - (MIN_MATCH-1);
        do {
            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
#ifndef FASTEST
            s->prev[str & s->w_mask] = s->head[s->ins_h];
#endif
            s->head[s->ins_h] = (Pos)str;
            str++;
        } while (--n);
        s->strstart = str;
        s->lookahead = MIN_MATCH-1;
        fill_window(s);
    }
    s->strstart += s->lookahead;
    s->block_start = (long)s->strstart;
    s->insert = s->lookahead;
    s->lookahead = 0;
    s->match_length = s->prev_length = MIN_MATCH-1;
    s->match_available = 0;
    strm->next_in = next;
    strm->avail_in = avail;
    s->wrap = wrap;
    return Z_OK;
}

/* ========================================================================= */
int ZEXPORT deflateResetKeep (strm)
    z_streamp strm;
{
    deflate_state *s;

    if (strm == Z_NULL || strm->state == Z_NULL ||
        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
        return Z_STREAM_ERROR;
    }

    strm->total_in = strm->total_out = 0;
    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
    strm->data_type = Z_UNKNOWN;

    s = (deflate_state *)strm->state;
    s->pending = 0;
    s->pending_out = s->pending_buf;

    if (s->wrap < 0) {
        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
    }
    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
    strm->adler =
#ifdef GZIP
        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
#endif
        adler32(0L, Z_NULL, 0);
    s->last_flush = Z_NO_FLUSH;

    _tr_init(s);

    return Z_OK;
}

/* ========================================================================= */
int ZEXPORT deflateReset (strm)
    z_streamp strm;
{
    int ret;

    ret = deflateResetKeep(strm);
    if (ret == Z_OK)
        lm_init(strm->state);
    return ret;
}

/* ========================================================================= */
int ZEXPORT deflateSetHeader (strm, head)
    z_streamp strm;
    gz_headerp head;
{
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
    strm->state->gzhead = head;
    return Z_OK;
}

/* ========================================================================= */
int ZEXPORT deflatePending (strm, pending, bits)
    unsigned *pending;
    int *bits;
    z_streamp strm;
{
    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    if (pending != Z_NULL)
        *pending = strm->state->pending;
    if (bits != Z_NULL)
        *bits = strm->state->bi_valid;
    return Z_OK;
}

/* ========================================================================= */
int ZEXPORT deflatePrime (strm, bits, value)
    z_streamp strm;
    int bits;
    int value;
{
    deflate_state *s;
    int put;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    s = strm->state;
    if (s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
        return Z_BUF_ERROR;
    do {
        put = Buf_size - s->bi_valid;
        if (put > bits)
            put = bits;
        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
        s->bi_valid += put;
        _tr_flush_bits(s);
        value >>= put;
        bits -= put;
    } while (bits);
    return Z_OK;
}

/* ========================================================================= */
int ZEXPORT deflateParams(strm, level, strategy)
    z_streamp strm;
    int level;
    int strategy;
{
    deflate_state *s;
    compress_func func;
    int err = Z_OK;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    s = strm->state;

#ifdef FASTEST
    if (level != 0) level = 1;
#else
    if (level == Z_DEFAULT_COMPRESSION) level = 6;
#endif
    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
        return Z_STREAM_ERROR;
    }
    func = configuration_table[s->level].func;

    if ((strategy != s->strategy || func != configuration_table[level].func) &&
        strm->total_in != 0) {
        /* Flush the last buffer: */
        err = deflate(strm, Z_BLOCK);
        if (err == Z_BUF_ERROR && s->pending == 0)
            err = Z_OK;
    }
    if (s->level != level) {
        s->level = level;
        s->max_lazy_match   = configuration_table[level].max_lazy;
        s->good_match       = configuration_table[level].good_length;
        s->nice_match       = configuration_table[level].nice_length;
        s->max_chain_length = configuration_table[level].max_chain;
    }
    s->strategy = strategy;
    return err;
}

/* ========================================================================= */
int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
    z_streamp strm;
    int good_length;
    int max_lazy;
    int nice_length;
    int max_chain;
{
    deflate_state *s;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
    s = strm->state;
    s->good_match = good_length;
    s->max_lazy_match = max_lazy;
    s->nice_match = nice_length;
    s->max_chain_length = max_chain;
    return Z_OK;
}

/* =========================================================================
 * For the default windowBits of 15 and memLevel of 8, this function returns
 * a close to exact, as well as small, upper bound on the compressed size.
 * They are coded as constants here for a reason--if the #define's are
 * changed, then this function needs to be changed as well.  The return
 * value for 15 and 8 only works for those exact settings.
 *
 * For any setting other than those defaults for windowBits and memLevel,
 * the value returned is a conservative worst case for the maximum expansion
 * resulting from using fixed blocks instead of stored blocks, which deflate
 * can emit on compressed data for some combinations of the parameters.
 *
 * This function could be more sophisticated to provide closer upper bounds for
 * every combination of windowBits and memLevel.  But even the conservative
 * upper bound of about 14% expansion does not seem onerous for output buffer
 * allocation.
 */
uLong ZEXPORT deflateBound(strm, sourceLen)
    z_streamp strm;
    uLong sourceLen;
{
    deflate_state *s;
    uLong complen, wraplen;
    Bytef *str;

    /* conservative upper bound for compressed data */
    complen = sourceLen +
              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;

    /* if can't get parameters, return conservative bound plus zlib wrapper */
    if (strm == Z_NULL || strm->state == Z_NULL)
        return complen + 6;

    /* compute wrapper length */
    s = strm->state;
    switch (s->wrap) {
    case 0:                                 /* raw deflate */
        wraplen = 0;
        break;
    case 1:                                 /* zlib wrapper */
        wraplen = 6 + (s->strstart ? 4 : 0);
        break;
    case 2:                                 /* gzip wrapper */
        wraplen = 18;
        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */
            if (s->gzhead->extra != Z_NULL)
                wraplen += 2 + s->gzhead->extra_len;
            str = s->gzhead->name;
            if (str != Z_NULL)
                do {
                    wraplen++;
                } while (*str++);
            str = s->gzhead->comment;
            if (str != Z_NULL)
                do {
                    wraplen++;
                } while (*str++);
            if (s->gzhead->hcrc)
                wraplen += 2;
        }
        break;
    default:                                /* for compiler happiness */
        wraplen = 6;
    }

    /* if not default parameters, return conservative bound */
    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
        return complen + wraplen;

    /* default settings: return tight bound for that case */
    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
           (sourceLen >> 25) + 13 - 6 + wraplen;
}

/* =========================================================================
 * Put a short in the pending buffer. The 16-bit value is put in MSB order.
 * IN assertion: the stream state is correct and there is enough room in
 * pending_buf.
 */
local void putShortMSB (s, b)
    deflate_state *s;
    uInt b;
{
    put_byte(s, (Byte)(b >> 8));
    put_byte(s, (Byte)(b & 0xff));
}

/* =========================================================================
 * Flush as much pending output as possible. All deflate() output goes
 * through this function so some applications may wish to modify it
 * to avoid allocating a large strm->next_out buffer and copying into it.
 * (See also read_buf()).
 */
local void flush_pending(strm)
    z_streamp strm;
{
    unsigned len;
    deflate_state *s = strm->state;

    _tr_flush_bits(s);
    len = s->pending;
    if (len > strm->avail_out) len = strm->avail_out;
    if (len == 0) return;

    zmemcpy(strm->next_out, s->pending_out, len);
    strm->next_out  += len;
    s->pending_out  += len;
    strm->total_out += len;
    strm->avail_out  -= len;
    s->pending -= len;
    if (s->pending == 0) {
        s->pending_out = s->pending_buf;
    }
}

/* ========================================================================= */
int ZEXPORT deflate (strm, flush)
    z_streamp strm;
    int flush;
{
    int old_flush; /* value of flush param for previous deflate call */
    deflate_state *s;

    if (strm == Z_NULL || strm->state == Z_NULL ||
        (flush > Z_BLOCK && flush != Z_INSERT_ONLY) || flush < 0) {
        return Z_STREAM_ERROR;
    }
    s = strm->state;

    if (strm->next_out == Z_NULL ||
        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
        (s->status == FINISH_STATE && flush != Z_FINISH)) {
        ERR_RETURN(strm, Z_STREAM_ERROR);
    }
    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);

    s->strm = strm; /* just in case */
    old_flush = s->last_flush;
    s->last_flush = flush;

    /* Write the header */
    if (s->status == INIT_STATE) {
#ifdef GZIP
        if (s->wrap == 2) {
            strm->adler = crc32(0L, Z_NULL, 0);
            put_byte(s, 31);
            put_byte(s, 139);
            put_byte(s, 8);
            if (s->gzhead == Z_NULL) {
                put_byte(s, 0);
                put_byte(s, 0);
                put_byte(s, 0);
                put_byte(s, 0);
                put_byte(s, 0);
                put_byte(s, s->level == 9 ? 2 :
                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
                             4 : 0));
                put_byte(s, OS_CODE);
                s->status = BUSY_STATE;
            }
            else {
                put_byte(s, (s->gzhead->text ? 1 : 0) +
                            (s->gzhead->hcrc ? 2 : 0) +
                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
                            (s->gzhead->name == Z_NULL ? 0 : 8) +
                            (s->gzhead->comment == Z_NULL ? 0 : 16)
                        );
                put_byte(s, (Byte)(s->gzhead->time & 0xff));
                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
                put_byte(s, s->level == 9 ? 2 :
                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
                             4 : 0));
                put_byte(s, s->gzhead->os & 0xff);
                if (s->gzhead->extra != Z_NULL) {
                    put_byte(s, s->gzhead->extra_len & 0xff);
                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
                }
                if (s->gzhead->hcrc)
                    strm->adler = crc32(strm->adler, s->pending_buf,
                                        s->pending);
                s->gzindex = 0;
                s->status = EXTRA_STATE;
            }
        }
        else
#endif
        {
            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
            uInt level_flags;

            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
                level_flags = 0;
            else if (s->level < 6)
                level_flags = 1;
            else if (s->level == 6)
                level_flags = 2;
            else
                level_flags = 3;
            header |= (level_flags << 6);
            if (s->strstart != 0) header |= PRESET_DICT;
            header += 31 - (header % 31);

            s->status = BUSY_STATE;
            putShortMSB(s, header);

            /* Save the adler32 of the preset dictionary: */
            if (s->strstart != 0) {
                putShortMSB(s, (uInt)(strm->adler >> 16));
                putShortMSB(s, (uInt)(strm->adler & 0xffff));
            }
            strm->adler = adler32(0L, Z_NULL, 0);
        }
    }
#ifdef GZIP
    if (s->status == EXTRA_STATE) {
        if (s->gzhead->extra != Z_NULL) {
            uInt beg = s->pending;  /* start of bytes to update crc */

            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
                if (s->pending == s->pending_buf_size) {
                    if (s->gzhead->hcrc && s->pending > beg)
                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                            s->pending - beg);
                    flush_pending(strm);
                    beg = s->pending;
                    if (s->pending == s->pending_buf_size)
                        break;
                }
                put_byte(s, s->gzhead->extra[s->gzindex]);
                s->gzindex++;
            }
            if (s->gzhead->hcrc && s->pending > beg)
                strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                    s->pending - beg);
            if (s->gzindex == s->gzhead->extra_len) {
                s->gzindex = 0;
                s->status = NAME_STATE;
            }
        }
        else
            s->status = NAME_STATE;
    }
    if (s->status == NAME_STATE) {
        if (s->gzhead->name != Z_NULL) {
            uInt beg = s->pending;  /* start of bytes to update crc */
            int val;

            do {
                if (s->pending == s->pending_buf_size) {
                    if (s->gzhead->hcrc && s->pending > beg)
                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                            s->pending - beg);
                    flush_pending(strm);
                    beg = s->pending;
                    if (s->pending == s->pending_buf_size) {
                        val = 1;
                        break;
                    }
                }
                val = s->gzhead->name[s->gzindex++];
                put_byte(s, val);
            } while (val != 0);
            if (s->gzhead->hcrc && s->pending > beg)
                strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                    s->pending - beg);
            if (val == 0) {
                s->gzindex = 0;
                s->status = COMMENT_STATE;
            }
        }
        else
            s->status = COMMENT_STATE;
    }
    if (s->status == COMMENT_STATE) {
        if (s->gzhead->comment != Z_NULL) {
            uInt beg = s->pending;  /* start of bytes to update crc */
            int val;

            do {
                if (s->pending == s->pending_buf_size) {
                    if (s->gzhead->hcrc && s->pending > beg)
                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                            s->pending - beg);
                    flush_pending(strm);
                    beg = s->pending;
                    if (s->pending == s->pending_buf_size) {
                        val = 1;
                        break;
                    }
                }
                val = s->gzhead->comment[s->gzindex++];
                put_byte(s, val);
            } while (val != 0);
            if (s->gzhead->hcrc && s->pending > beg)
                strm->adler = crc32(strm->adler, s->pending_buf + beg,
                                    s->pending - beg);
            if (val == 0)
                s->status = HCRC_STATE;
        }
        else
            s->status = HCRC_STATE;
    }
    if (s->status == HCRC_STATE) {
        if (s->gzhead->hcrc) {
            if (s->pending + 2 > s->pending_buf_size)
                flush_pending(strm);
            if (s->pending + 2 <= s->pending_buf_size) {
                put_byte(s, (Byte)(strm->adler & 0xff));
                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
                strm->adler = crc32(0L, Z_NULL, 0);
                s->status = BUSY_STATE;
            }
        }
        else
            s->status = BUSY_STATE;
    }
#endif

    /* Flush as much pending output as possible */
    if (s->pending != 0) {
        flush_pending(strm);
        if (strm->avail_out == 0) {
            /* Since avail_out is 0, deflate will be called again with
             * more output space, but possibly with both pending and
             * avail_in equal to zero. There won't be anything to do,
             * but this is not an error situation so make sure we
             * return OK instead of BUF_ERROR at next call of deflate:
             */
            s->last_flush = -1;
            return Z_OK;
        }

    /* Make sure there is something to do and avoid duplicate consecutive
     * flushes. For repeated and useless calls with Z_FINISH, we keep
     * returning Z_STREAM_END instead of Z_BUF_ERROR.
     */
    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
               flush != Z_FINISH) {
        ERR_RETURN(strm, Z_BUF_ERROR);
    }

    /* User must not provide more input after the first FINISH: */
    if (s->status == FINISH_STATE && strm->avail_in != 0) {
        ERR_RETURN(strm, Z_BUF_ERROR);
    }

    /* Start a new block or continue the current one.
     */
    if (strm->avail_in != 0 || s->lookahead != 0 ||
        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
        block_state bstate;

        bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
                    (s->strategy == Z_RLE ? deflate_rle(s, flush) :
                        (*(configuration_table[s->level].func))(s, flush));

        if (bstate == finish_started || bstate == finish_done) {
            s->status = FINISH_STATE;
        }
        if (bstate == need_more || bstate == finish_started) {
            if (strm->avail_out == 0) {
                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
            }
            return Z_OK;
            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
             * of deflate should use the same flush parameter to make sure
             * that the flush is complete. So we don't have to output an
             * empty block here, this will be done at next call. This also
             * ensures that for a very small output buffer, we emit at most
             * one empty block.
             */
        }
        if (bstate == block_done) {
            if (flush == Z_PARTIAL_FLUSH) {
                _tr_align(s);
            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
                _tr_stored_block(s, (char*)0, 0L, 0);
                /* For a full flush, this empty block will be recognized
                 * as a special marker by inflate_sync().
                 */
                if (flush == Z_FULL_FLUSH) {
                    CLEAR_HASH(s);             /* forget history */
                    if (s->lookahead == 0) {
                        s->strstart = 0;
                        s->block_start = 0L;
                        s->insert = 0;
                    }
                }
            }
            flush_pending(strm);
            if (strm->avail_out == 0) {
              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
              return Z_OK;
            }
        }
    }
    Assert(strm->avail_out > 0, "bug2");

    if (flush != Z_FINISH) return Z_OK;
    if (s->wrap <= 0) return Z_STREAM_END;

    /* Write the trailer */
#ifdef GZIP
    if (s->wrap == 2) {
        put_byte(s, (Byte)(strm->adler & 0xff));
        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
        put_byte(s, (Byte)(strm->total_in & 0xff));
        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
    }
    else
#endif
    {
        putShortMSB(s, (uInt)(strm->adler >> 16));
        putShortMSB(s, (uInt)(strm->adler & 0xffff));
    }
    flush_pending(strm);
    /* If avail_out is zero, the application will call deflate again
     * to flush the rest.
     */
    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
    return s->pending != 0 ? Z_OK : Z_STREAM_END;
}

/* ========================================================================= */
int ZEXPORT deflateEnd (strm)
    z_streamp strm;
{
    int status;

    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;

    status = strm->state->status;
    if (status != INIT_STATE &&
        status != EXTRA_STATE &&
        status != NAME_STATE &&
        status != COMMENT_STATE &&
        status != HCRC_STATE &&
        status != BUSY_STATE &&
        status != FINISH_STATE) {
      return Z_STREAM_ERROR;
    }

    /* Deallocate in reverse order of allocations: */
    TRY_FREE(strm, strm->state->pending_buf);
    TRY_FREE(strm, strm->state->head);
    TRY_FREE(strm, strm->state->prev);
    TRY_FREE(strm, strm->state->window);

    ZFREE(strm, strm->state);
    strm->state = Z_NULL;

    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
}

/* =========================================================================
 * Copy the source state to the destination state.
 * To simplify the source, this is not supported for 16-bit MSDOS (which
 * doesn't have enough memory anyway to duplicate compression states).
 */
int ZEXPORT deflateCopy (dest, source)
    z_streamp dest;
    z_streamp source;
{
#ifdef MAXSEG_64K
    return Z_STREAM_ERROR;
#else
    deflate_state *ds;
    deflate_state *ss;


    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
        return Z_STREAM_ERROR;
    }

    ss = source->state;

    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));

    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
    if (ds == Z_NULL) return Z_MEM_ERROR;
    dest->state = (struct internal_state FAR *) ds;
    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
    ds->strm = dest;

    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
    ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);

    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
        ds->pending_buf == Z_NULL) {
        deflateEnd (dest);
        return Z_MEM_ERROR;
    }
    /* following zmemcpy do not work for 16-bit MSDOS */
    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);

    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
    ds->sym_buf = ds->pending_buf + ds->lit_bufsize;

    ds->l_desc.dyn_tree = ds->dyn_ltree;
    ds->d_desc.dyn_tree = ds->dyn_dtree;
    ds->bl_desc.dyn_tree = ds->bl_tree;

    return Z_OK;
#endif /* MAXSEG_64K */
}

/* ===========================================================================
 * Read a new buffer from the current input stream, update the adler32
 * and total number of bytes read.  All deflate() input goes through
 * this function so some applications may wish to modify it to avoid
 * allocating a large strm->next_in buffer and copying from it.
 * (See also flush_pending()).
 */
local int read_buf(strm, buf, size)
    z_streamp strm;
    Bytef *buf;
    unsigned size;
{
    unsigned len = strm->avail_in;

    if (len > size) len = size;
    if (len == 0) return 0;

    strm->avail_in  -= len;

    zmemcpy(buf, strm->next_in, len);
    if (strm->state->wrap == 1) {
        strm->adler = adler32(strm->adler, buf, len);
    }
#ifdef GZIP
    else if (strm->state->wrap == 2) {
        strm->adler = crc32(strm->adler, buf, len);
    }
#endif
    strm->next_in  += len;
    strm->total_in += len;

    return (int)len;
}

/* ===========================================================================
 * Initialize the "longest match" routines for a new zlib stream
 */
local void lm_init (s)
    deflate_state *s;
{
    s->window_size = (ulg)2L*s->w_size;

    CLEAR_HASH(s);

    /* Set the default configuration parameters:
     */
    s->max_lazy_match   = configuration_table[s->level].max_lazy;
    s->good_match       = configuration_table[s->level].good_length;
    s->nice_match       = configuration_table[s->level].nice_length;
    s->max_chain_length = configuration_table[s->level].max_chain;

    s->strstart = 0;
    s->block_start = 0L;
    s->lookahead = 0;
    s->insert = 0;
    s->match_length = s->prev_length = MIN_MATCH-1;
    s->match_available = 0;
    s->ins_h = 0;
#ifndef FASTEST
#ifdef ASMV
    match_init(); /* initialize the asm code */
#endif
#endif
}

#ifndef FASTEST
/* ===========================================================================
 * Set match_start to the longest match starting at the given string and
 * return its length. Matches shorter or equal to prev_length are discarded,
 * in which case the result is equal to prev_length and match_start is
 * garbage.
 * IN assertions: cur_match is the head of the hash chain for the current
 *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
 * OUT assertion: the match length is not greater than s->lookahead.
 */
#ifndef ASMV
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
 * match.S. The code will be functionally equivalent.
 */
local uInt longest_match(s, cur_match)
    deflate_state *s;
    IPos cur_match;                             /* current match */
{
    unsigned chain_length = s->max_chain_length;/* max hash chain length */
    register Bytef *scan = s->window + s->strstart; /* current string */
    register Bytef *match;                       /* matched string */
    register int len;                           /* length of current match */
    int best_len = s->prev_length;              /* best match length so far */
    int nice_match = s->nice_match;             /* stop if match long enough */
    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
        s->strstart - (IPos)MAX_DIST(s) : NIL;
    /* Stop when cur_match becomes <= limit. To simplify the code,
     * we prevent matches with the string of window index 0.
     */
    Posf *prev = s->prev;
    uInt wmask = s->w_mask;

#ifdef UNALIGNED_OK
    /* Compare two bytes at a time. Note: this is not always beneficial.
     * Try with and without -DUNALIGNED_OK to check.
     */
    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
    register ush scan_start = *(ushf*)scan;
    register ush scan_end   = *(ushf*)(scan+best_len-1);
#else
    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
    register Byte scan_end1  = scan[best_len-1];
    register Byte scan_end   = scan[best_len];
#endif

    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
     * It is easy to get rid of this optimization if necessary.
     */
    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");

    /* Do not waste too much time if we already have a good match: */
    if (s->prev_length >= s->good_match) {
        chain_length >>= 2;
    }
    /* Do not look for matches beyond the end of the input. This is necessary
     * to make deflate deterministic.
     */
    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;

    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");

    do {
        Assert(cur_match < s->strstart, "no future");
        match = s->window + cur_match;

        /* Skip to next match if the match length cannot increase
         * or if the match length is less than 2.  Note that the checks below
         * for insufficient lookahead only occur occasionally for performance
         * reasons.  Therefore uninitialized memory will be accessed, and
         * conditional jumps will be made that depend on those values.
         * However the length of the match is limited to the lookahead, so
         * the output of deflate is not affected by the uninitialized values.
         */
#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
        /* This code assumes sizeof(unsigned short) == 2. Do not use
         * UNALIGNED_OK if your compiler uses a different size.
         */
        if (*(ushf*)(match+best_len-1) != scan_end ||
            *(ushf*)match != scan_start) continue;

        /* It is not necessary to compare scan[2] and match[2] since they are
         * always equal when the other bytes match, given that the hash keys
         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
         * strstart+3, +5, ... up to strstart+257. We check for insufficient
         * lookahead only every 4th comparison; the 128th check will be made
         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
         * necessary to put more guard bytes at the end of the window, or
         * to check more often for insufficient lookahead.
         */
        Assert(scan[2] == match[2], "scan[2]?");
        scan++, match++;
        do {
        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
                 scan < strend);
        /* The funny "do {}" generates better code on most compilers */

        /* Here, scan <= window+strstart+257 */
        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
        if (*scan == *match) scan++;

        len = (MAX_MATCH - 1) - (int)(strend-scan);
        scan = strend - (MAX_MATCH-1);

#else /* UNALIGNED_OK */

        if (match[best_len]   != scan_end  ||
            match[best_len-1] != scan_end1 ||
            *match            != *scan     ||
            *++match          != scan[1])      continue;

        /* The check at best_len-1 can be removed because it will be made
         * again later. (This heuristic is not always a win.)
         * It is not necessary to compare scan[2] and match[2] since they
         * are always equal when the other bytes match, given that
         * the hash keys are equal and that HASH_BITS >= 8.
         */
        scan += 2, match++;
        Assert(*scan == *match, "match[2]?");

        /* We check for insufficient lookahead only every 8th comparison;
         * the 256th check will be made at strstart+258.
         */
        do {
        } while (*++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 *++scan == *++match && *++scan == *++match &&
                 scan < strend);

        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");

        len = MAX_MATCH - (int)(strend - scan);
        scan = strend - MAX_MATCH;

#endif /* UNALIGNED_OK */

        if (len > best_len) {
            s->match_start = cur_match;
            best_len = len;
            if (len >= nice_match) break;
#ifdef UNALIGNED_OK
            scan_end = *(ushf*)(scan+best_len-1);
#else
            scan_end1  = scan[best_len-1];
            scan_end   = scan[best_len];
#endif
        }
    } while ((cur_match = prev[cur_match & wmask]) > limit
             && --chain_length != 0);

    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
    return s->lookahead;
}
#endif /* ASMV */

#else /* FASTEST */

/* ---------------------------------------------------------------------------
 * Optimized version for FASTEST only
 */
local uInt longest_match(s, cur_match)
    deflate_state *s;
    IPos cur_match;                             /* current match */
{
    register Bytef *scan = s->window + s->strstart; /* current string */
    register Bytef *match;                       /* matched string */
    register int len;                           /* length of current match */
    register Bytef *strend = s->window + s->strstart + MAX_MATCH;

    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
     * It is easy to get rid of this optimization if necessary.
     */
    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");

    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");

    Assert(cur_match < s->strstart, "no future");

    match = s->window + cur_match;

    /* Return failure if the match length is less than 2:
     */
    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;

    /* The check at best_len-1 can be removed because it will be made
     * again later. (This heuristic is not always a win.)
     * It is not necessary to compare scan[2] and match[2] since they
     * are always equal when the other bytes match, given that
     * the hash keys are equal and that HASH_BITS >= 8.
     */
    scan += 2, match += 2;
    Assert(*scan == *match, "match[2]?");

    /* We check for insufficient lookahead only every 8th comparison;
     * the 256th check will be made at strstart+258.
     */
    do {
    } while (*++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             scan < strend);

    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");

    len = MAX_MATCH - (int)(strend - scan);

    if (len < MIN_MATCH) return MIN_MATCH - 1;

    s->match_start = cur_match;
    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
}

#endif /* FASTEST */

#ifdef DEBUG
/* ===========================================================================
 * Check that the match at match_start is indeed a match.
 */
local void check_match(s, start, match, length)
    deflate_state *s;
    IPos start, match;
    int length;
{
    /* check that the match is indeed a match */
    if (zmemcmp(s->window + match,
                s->window + start, length) != EQUAL) {
        fprintf(stderr, " start %u, match %u, length %d\n",
                start, match, length);
        do {
            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
        } while (--length != 0);
        z_error("invalid match");
    }
    if (z_verbose > 1) {
        fprintf(stderr,"\\[%d,%d]", start-match, length);
        do { putc(s->window[start++], stderr); } while (--length != 0);
    }
}
#else
#  define check_match(s, start, match, length)
#endif /* DEBUG */

/* ===========================================================================
 * Fill the window when the lookahead becomes insufficient.
 * Updates strstart and lookahead.
 *
 * IN assertion: lookahead < MIN_LOOKAHEAD
 * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
 *    At least one byte has been read, or avail_in == 0; reads are
 *    performed for at least two bytes (required for the zip translate_eol
 *    option -- not supported here).
 */
local void fill_window(s)
    deflate_state *s;
{
    register unsigned n, m;
    register Posf *p;
    unsigned more;    /* Amount of free space at the end of the window. */
    uInt wsize = s->w_size;

    Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");

    do {
        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);

        /* Deal with !@#$% 64K limit: */
        if (sizeof(int) <= 2) {
            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
                more = wsize;

            } else if (more == (unsigned)(-1)) {
                /* Very unlikely, but possible on 16 bit machine if
                 * strstart == 0 && lookahead == 1 (input done a byte at time)
                 */
                more--;
            }
        }

        /* If the window is almost full and there is insufficient lookahead,
         * move the upper half to the lower one to make room in the upper half.
         */
        if (s->strstart >= wsize+MAX_DIST(s)) {

            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
            s->match_start -= wsize;
            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
            s->block_start -= (long) wsize;

            /* Slide the hash table (could be avoided with 32 bit values
               at the expense of memory usage). We slide even when level == 0
               to keep the hash table consistent if we switch back to level > 0
               later. (Using level 0 permanently is not an optimal usage of
               zlib, so we don't care about this pathological case.)
             */
            n = s->hash_size;
            p = &s->head[n];
            do {
                m = *--p;
                *p = (Pos)(m >= wsize ? m-wsize : NIL);
            } while (--n);

            n = wsize;
#ifndef FASTEST
            p = &s->prev[n];
            do {
                m = *--p;
                *p = (Pos)(m >= wsize ? m-wsize : NIL);
                /* If n is not on any hash chain, prev[n] is garbage but
                 * its value will never be used.
                 */
            } while (--n);
#endif
            more += wsize;
        }
        if (s->strm->avail_in == 0) break;

        /* If there was no sliding:
         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
         *    more == window_size - lookahead - strstart
         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
         * => more >= window_size - 2*WSIZE + 2
         * In the BIG_MEM or MMAP case (not yet supported),
         *   window_size == input_size + MIN_LOOKAHEAD  &&
         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
         * Otherwise, window_size == 2*WSIZE so more >= 2.
         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
         */
        Assert(more >= 2, "more < 2");

        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
        s->lookahead += n;

        /* Initialize the hash value now that we have some input: */
        if (s->lookahead + s->insert >= MIN_MATCH) {
            uInt str = s->strstart - s->insert;
            s->ins_h = s->window[str];
            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
#if MIN_MATCH != 3
            Call UPDATE_HASH() MIN_MATCH-3 more times
#endif
            while (s->insert) {
                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
#ifndef FASTEST
                s->prev[str & s->w_mask] = s->head[s->ins_h];
#endif
                s->head[s->ins_h] = (Pos)str;
                str++;
                s->insert--;
                if (s->lookahead + s->insert < MIN_MATCH)
                    break;
            }
        }
        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
         * but this is not important since only literal bytes will be emitted.
         */

    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);

    /* If the WIN_INIT bytes after the end of the current data have never been
     * written, then zero those bytes in order to avoid memory check reports of
     * the use of uninitialized (or uninitialised as Julian writes) bytes by
     * the longest match routines.  Update the high water mark for the next
     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
     */
    if (s->high_water < s->window_size) {
        ulg curr = s->strstart + (ulg)(s->lookahead);
        ulg init;

        if (s->high_water < curr) {
            /* Previous high water mark below current data -- zero WIN_INIT
             * bytes or up to end of window, whichever is less.
             */
            init = s->window_size - curr;
            if (init > WIN_INIT)
                init = WIN_INIT;
            zmemzero(s->window + curr, (unsigned)init);
            s->high_water = curr + init;
        }
        else if (s->high_water < (ulg)curr + WIN_INIT) {
            /* High water mark at or above current data, but below current data
             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
             * to end of window, whichever is less.
             */
            init = (ulg)curr + WIN_INIT - s->high_water;
            if (init > s->window_size - s->high_water)
                init = s->window_size - s->high_water;
            zmemzero(s->window + s->high_water, (unsigned)init);
            s->high_water += init;
        }
    }

    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
           "not enough room for search");
}

/* ===========================================================================
 * Flush the current block, with given end-of-file flag.
 * IN assertion: strstart is set to the end of the current match.
 */
#define FLUSH_BLOCK_ONLY(s, last) { \
   _tr_flush_block(s, (s->block_start >= 0L ? \
                   (charf *)&s->window[(unsigned)s->block_start] : \
                   (charf *)Z_NULL), \
                (ulg)((long)s->strstart - s->block_start), \
                (last)); \
   s->block_start = s->strstart; \
   flush_pending(s->strm); \
   Tracev((stderr,"[FLUSH]")); \
}

/* Same but force premature exit if necessary. */
#define FLUSH_BLOCK(s, last) { \
   FLUSH_BLOCK_ONLY(s, last); \
   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
}

/* ===========================================================================
 * Copy without compression as much as possible from the input stream, return
 * the current block state.
 * This function does not insert new strings in the dictionary since
 * uncompressible data is probably not useful. This function is used
 * only for the level=0 compression option.
 * NOTE: this function should be optimized to avoid extra copying from
 * window to pending_buf.
 */
local block_state deflate_stored(s, flush)
    deflate_state *s;
    int flush;
{
    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
     * to pending_buf_size, and each stored block has a 5 byte header:
     */
    ulg max_block_size = 0xffff;
    ulg max_start;

    if (max_block_size > s->pending_buf_size - 5) {
        max_block_size = s->pending_buf_size - 5;
    }

    /* Copy as much as possible from input to output: */
    for (;;) {
        /* Fill the window as much as possible: */
        if (s->lookahead <= 1) {

            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
                   s->block_start >= (long)s->w_size, "slide too late");

            fill_window(s);
            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;

            if (s->lookahead == 0) break; /* flush the current block */
        }
        Assert(s->block_start >= 0L, "block gone");

        s->strstart += s->lookahead;
        s->lookahead = 0;

	if (flush == Z_INSERT_ONLY) {
	    s->block_start = s->strstart;
	    continue;
	}

        /* Emit a stored block if pending_buf will be full: */
        max_start = s->block_start + max_block_size;
        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
            /* strstart == 0 is possible when wraparound on 16-bit machine */
            s->lookahead = (uInt)(s->strstart - max_start);
            s->strstart = (uInt)max_start;
            FLUSH_BLOCK(s, 0);
        }
        /* Flush if we may have to slide, otherwise block_start may become
         * negative and the data will be gone:
         */
        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
            FLUSH_BLOCK(s, 0);
        }
    }
    s->insert = 0;
    if (flush == Z_INSERT_ONLY) {
	s->block_start = s->strstart;
	return need_more;
    }
    if (flush == Z_FINISH) {
        FLUSH_BLOCK(s, 1);
        return finish_done;
    }
    if ((long)s->strstart > s->block_start)
        FLUSH_BLOCK(s, 0);
    return block_done;
}

/* ===========================================================================
 * Compress as much as possible from the input stream, return the current
 * block state.
 * This function does not perform lazy evaluation of matches and inserts
 * new strings in the dictionary only for unmatched strings or for short
 * matches. It is used only for the fast compression options.
 */
local block_state deflate_fast(s, flush)
    deflate_state *s;
    int flush;
{
    IPos hash_head;       /* head of the hash chain */
    int bflush;           /* set if current block must be flushed */

    for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the next match, plus MIN_MATCH bytes to insert the
         * string following the next match.
         */
        if (s->lookahead < MIN_LOOKAHEAD) {
            fill_window(s);
            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
                return need_more;
            }
            if (s->lookahead == 0) break; /* flush the current block */
        }

        /* Insert the string window[strstart .. strstart+2] in the
         * dictionary, and set hash_head to the head of the hash chain:
         */
        hash_head = NIL;
        if (s->lookahead >= MIN_MATCH) {
            INSERT_STRING(s, s->strstart, hash_head);
        }

	if (flush == Z_INSERT_ONLY) {
	    s->strstart++;
	    s->lookahead--;
	    continue;
	}

        /* Find the longest match, discarding those <= prev_length.
         * At this point we have always match_length < MIN_MATCH
         */
        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
            /* To simplify the code, we prevent matches with the string
             * of window index 0 (in particular we have to avoid a match
             * of the string with itself at the start of the input file).
             */
            s->match_length = longest_match (s, hash_head);
            /* longest_match() sets match_start */
        }
        if (s->match_length >= MIN_MATCH) {
            check_match(s, s->strstart, s->match_start, s->match_length);

            _tr_tally_dist(s, s->strstart - s->match_start,
                           s->match_length - MIN_MATCH, bflush);

            s->lookahead -= s->match_length;

            /* Insert new strings in the hash table only if the match length
             * is not too large. This saves time but degrades compression.
             */
#ifndef FASTEST
            if (s->match_length <= s->max_insert_length &&
                s->lookahead >= MIN_MATCH) {
                s->match_length--; /* string at strstart already in table */
                do {
                    s->strstart++;
                    INSERT_STRING(s, s->strstart, hash_head);
                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
                     * always MIN_MATCH bytes ahead.
                     */
                } while (--s->match_length != 0);
                s->strstart++;
            } else
#endif
            {
                s->strstart += s->match_length;
                s->match_length = 0;
                s->ins_h = s->window[s->strstart];
                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
#if MIN_MATCH != 3
                Call UPDATE_HASH() MIN_MATCH-3 more times
#endif
                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
                 * matter since it will be recomputed at next deflate call.
                 */
            }
        } else {
            /* No match, output a literal byte */
            Tracevv((stderr,"%c", s->window[s->strstart]));
            _tr_tally_lit (s, s->window[s->strstart], bflush);
            s->lookahead--;
            s->strstart++;
        }
        if (bflush) FLUSH_BLOCK(s, 0);
    }
    if (flush == Z_INSERT_ONLY) {
	s->block_start = s->strstart;
	return need_more;
    }
    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
    if (flush == Z_FINISH) {
        FLUSH_BLOCK(s, 1);
        return finish_done;
    }
    if (s->sym_next)
        FLUSH_BLOCK(s, 0);
    return block_done;
}

#ifndef FASTEST
/* ===========================================================================
 * Same as above, but achieves better compression. We use a lazy
 * evaluation for matches: a match is finally adopted only if there is
 * no better match at the next window position.
 */
local block_state deflate_slow(s, flush)
    deflate_state *s;
    int flush;
{
    IPos hash_head;          /* head of hash chain */
    int bflush;              /* set if current block must be flushed */

    /* Process the input block. */
    for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the next match, plus MIN_MATCH bytes to insert the
         * string following the next match.
         */
        if (s->lookahead < MIN_LOOKAHEAD) {
            fill_window(s);
            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
                return need_more;
            }
            if (s->lookahead == 0) break; /* flush the current block */
        }

        /* Insert the string window[strstart .. strstart+2] in the
         * dictionary, and set hash_head to the head of the hash chain:
         */
        hash_head = NIL;
        if (s->lookahead >= MIN_MATCH) {
            INSERT_STRING(s, s->strstart, hash_head);
        }

	if (flush == Z_INSERT_ONLY) {
	    s->strstart++;
	    s->lookahead--;
	    continue;
	}

        /* Find the longest match, discarding those <= prev_length.
         */
        s->prev_length = s->match_length, s->prev_match = s->match_start;
        s->match_length = MIN_MATCH-1;

        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
            s->strstart - hash_head <= MAX_DIST(s)) {
            /* To simplify the code, we prevent matches with the string
             * of window index 0 (in particular we have to avoid a match
             * of the string with itself at the start of the input file).
             */
            s->match_length = longest_match (s, hash_head);
            /* longest_match() sets match_start */

            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
#if TOO_FAR <= 32767
                || (s->match_length == MIN_MATCH &&
                    s->strstart - s->match_start > TOO_FAR)
#endif
                )) {

                /* If prev_match is also MIN_MATCH, match_start is garbage
                 * but we will ignore the current match anyway.
                 */
                s->match_length = MIN_MATCH-1;
            }
        }
        /* If there was a match at the previous step and the current
         * match is not better, output the previous match:
         */
        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
            /* Do not insert strings in hash table beyond this. */

            check_match(s, s->strstart-1, s->prev_match, s->prev_length);

            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
                           s->prev_length - MIN_MATCH, bflush);

            /* Insert in hash table all strings up to the end of the match.
             * strstart-1 and strstart are already inserted. If there is not
             * enough lookahead, the last two strings are not inserted in
             * the hash table.
             */
            s->lookahead -= s->prev_length-1;
            s->prev_length -= 2;
            do {
                if (++s->strstart <= max_insert) {
                    INSERT_STRING(s, s->strstart, hash_head);
                }
            } while (--s->prev_length != 0);
            s->match_available = 0;
            s->match_length = MIN_MATCH-1;
            s->strstart++;

            if (bflush) FLUSH_BLOCK(s, 0);

        } else if (s->match_available) {
            /* If there was no match at the previous position, output a
             * single literal. If there was a match but the current match
             * is longer, truncate the previous match to a single literal.
             */
            Tracevv((stderr,"%c", s->window[s->strstart-1]));
            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
            if (bflush) {
                FLUSH_BLOCK_ONLY(s, 0);
            }
            s->strstart++;
            s->lookahead--;
            if (s->strm->avail_out == 0) return need_more;
        } else {
            /* There is no previous match to compare with, wait for
             * the next step to decide.
             */
            s->match_available = 1;
            s->strstart++;
            s->lookahead--;
        }
    }
    if (flush == Z_INSERT_ONLY) {
	s->block_start = s->strstart;
	return need_more;
    }
    Assert (flush != Z_NO_FLUSH, "no flush?");
    if (s->match_available) {
        Tracevv((stderr,"%c", s->window[s->strstart-1]));
        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
        s->match_available = 0;
    }
    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
    if (flush == Z_FINISH) {
        FLUSH_BLOCK(s, 1);
        return finish_done;
    }
    if (s->sym_next)
        FLUSH_BLOCK(s, 0);
    return block_done;
}
#endif /* FASTEST */

/* ===========================================================================
 * For Z_RLE, simply look for runs of bytes, generate matches only of distance
 * one.  Do not maintain a hash table.  (It will be regenerated if this run of
 * deflate switches away from Z_RLE.)
 */
local block_state deflate_rle(s, flush)
    deflate_state *s;
    int flush;
{
    int bflush;             /* set if current block must be flushed */
    uInt prev;              /* byte at distance one to match */
    Bytef *scan, *strend;   /* scan goes up to strend for length of run */

    for (;;) {
        /* Make sure that we always have enough lookahead, except
         * at the end of the input file. We need MAX_MATCH bytes
         * for the longest run, plus one for the unrolled loop.
         */
        if (s->lookahead <= MAX_MATCH) {
            fill_window(s);
            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
                return need_more;
            }
            if (s->lookahead == 0) break; /* flush the current block */
        }

        /* See how many times the previous byte repeats */
        s->match_length = 0;
        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
            scan = s->window + s->strstart - 1;
            prev = *scan;
            if (prev == *++scan && prev == *++scan && prev == *++scan) {
                strend = s->window + s->strstart + MAX_MATCH;
                do {
                } while (prev == *++scan && prev == *++scan &&
                         prev == *++scan && prev == *++scan &&
                         prev == *++scan && prev == *++scan &&
                         prev == *++scan && prev == *++scan &&
                         scan < strend);
                s->match_length = MAX_MATCH - (int)(strend - scan);
                if (s->match_length > s->lookahead)
                    s->match_length = s->lookahead;
            }
            Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
        }

        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
        if (s->match_length >= MIN_MATCH) {
            check_match(s, s->strstart, s->strstart - 1, s->match_length);

            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);

            s->lookahead -= s->match_length;
            s->strstart += s->match_length;
            s->match_length = 0;
        } else {
            /* No match, output a literal byte */
            Tracevv((stderr,"%c", s->window[s->strstart]));
            _tr_tally_lit (s, s->window[s->strstart], bflush);
            s->lookahead--;
            s->strstart++;
        }
        if (bflush) FLUSH_BLOCK(s, 0);
    }
    s->insert = 0;
    if (flush == Z_FINISH) {
        FLUSH_BLOCK(s, 1);
        return finish_done;
    }
    if (s->sym_next)
        FLUSH_BLOCK(s, 0);
    return block_done;
}

/* ===========================================================================
 * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
 * (It will be regenerated if this run of deflate switches away from Huffman.)
 */
local block_state deflate_huff(s, flush)
    deflate_state *s;
    int flush;
{
    int bflush;             /* set if current block must be flushed */

    for (;;) {
        /* Make sure that we have a literal to write. */
        if (s->lookahead == 0) {
            fill_window(s);
            if (s->lookahead == 0) {
                if (flush == Z_NO_FLUSH)
                    return need_more;
                break;      /* flush the current block */
            }
        }

        /* Output a literal byte */
        s->match_length = 0;
        Tracevv((stderr,"%c", s->window[s->strstart]));
        _tr_tally_lit (s, s->window[s->strstart], bflush);
        s->lookahead--;
        s->strstart++;
        if (bflush) FLUSH_BLOCK(s, 0);
    }
    s->insert = 0;
    if (flush == Z_FINISH) {
        FLUSH_BLOCK(s, 1);
        return finish_done;
    }
    if (s->sym_next)
        FLUSH_BLOCK(s, 0);
    return block_done;
}
rsync-3.2.7/zlib/adler32.c0000664000000000000000000001155012155261705013727 0ustar  rootroot/* adler32.c -- compute the Adler-32 checksum of a data stream
 * Copyright (C) 1995-2011 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#include "zutil.h"

#define local static

local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));

#define BASE 65521      /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */

#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
#define DO16(buf)   DO8(buf,0); DO8(buf,8);

/* use NO_DIVIDE if your processor does not do division in hardware --
   try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
   (thank you to John Reiser for pointing this out) */
#  define CHOP(a) \
    do { \
        unsigned long tmp = a >> 16; \
        a &= 0xffffUL; \
        a += (tmp << 4) - tmp; \
    } while (0)
#  define MOD28(a) \
    do { \
        CHOP(a); \
        if (a >= BASE) a -= BASE; \
    } while (0)
#  define MOD(a) \
    do { \
        CHOP(a); \
        MOD28(a); \
    } while (0)
#  define MOD63(a) \
    do { /* this assumes a is not negative */ \
        z_off64_t tmp = a >> 32; \
        a &= 0xffffffffL; \
        a += (tmp << 8) - (tmp << 5) + tmp; \
        tmp = a >> 16; \
        a &= 0xffffL; \
        a += (tmp << 4) - tmp; \
        tmp = a >> 16; \
        a &= 0xffffL; \
        a += (tmp << 4) - tmp; \
        if (a >= BASE) a -= BASE; \
    } while (0)
#else
#  define MOD(a) a %= BASE
#  define MOD28(a) a %= BASE
#  define MOD63(a) a %= BASE
#endif

/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
    uLong adler;
    const Bytef *buf;
    uInt len;
{
    unsigned long sum2;
    unsigned n;

    /* split Adler-32 into component sums */
    sum2 = (adler >> 16) & 0xffff;
    adler &= 0xffff;

    /* in case user likes doing a byte at a time, keep it fast */
    if (len == 1) {
        adler += buf[0];
        if (adler >= BASE)
            adler -= BASE;
        sum2 += adler;
        if (sum2 >= BASE)
            sum2 -= BASE;
        return adler | (sum2 << 16);
    }

    /* initial Adler-32 value (deferred check for len == 1 speed) */
    if (buf == Z_NULL)
        return 1L;

    /* in case short lengths are provided, keep it somewhat fast */
    if (len < 16) {
        while (len--) {
            adler += *buf++;
            sum2 += adler;
        }
        if (adler >= BASE)
            adler -= BASE;
        MOD28(sum2);            /* only added so many BASE's */
        return adler | (sum2 << 16);
    }

    /* do length NMAX blocks -- requires just one modulo operation */
    while (len >= NMAX) {
        len -= NMAX;
        n = NMAX / 16;          /* NMAX is divisible by 16 */
        do {
            DO16(buf);          /* 16 sums unrolled */
            buf += 16;
        } while (--n);
        MOD(adler);
        MOD(sum2);
    }

    /* do remaining bytes (less than NMAX, still just one modulo) */
    if (len) {                  /* avoid modulos if none remaining */
        while (len >= 16) {
            len -= 16;
            DO16(buf);
            buf += 16;
        }
        while (len--) {
            adler += *buf++;
            sum2 += adler;
        }
        MOD(adler);
        MOD(sum2);
    }

    /* return recombined sums */
    return adler | (sum2 << 16);
}

/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
    uLong adler1;
    uLong adler2;
    z_off64_t len2;
{
    unsigned long sum1;
    unsigned long sum2;
    unsigned rem;

    /* for negative len, return invalid adler32 as a clue for debugging */
    if (len2 < 0)
        return 0xffffffffUL;

    /* the derivation of this formula is left as an exercise for the reader */
    MOD63(len2);                /* assumes len2 >= 0 */
    rem = (unsigned)len2;
    sum1 = adler1 & 0xffff;
    sum2 = rem * sum1;
    MOD(sum2);
    sum1 += (adler2 & 0xffff) + BASE - 1;
    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
    if (sum1 >= BASE) sum1 -= BASE;
    if (sum1 >= BASE) sum1 -= BASE;
    if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
    if (sum2 >= BASE) sum2 -= BASE;
    return sum1 | (sum2 << 16);
}

/* ========================================================================= */
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
    uLong adler1;
    uLong adler2;
    z_off_t len2;
{
    return adler32_combine_(adler1, adler2, len2);
}

uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
    uLong adler1;
    uLong adler2;
    z_off64_t len2;
{
    return adler32_combine_(adler1, adler2, len2);
}
rsync-3.2.7/zlib/inftrees.c0000664000000000000000000003131513443225253014312 0ustar  rootroot/* inftrees.c -- generate Huffman trees for efficient decoding
 * Copyright (C) 1995-2013 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "zutil.h"
#include "inftrees.h"

#define MAXBITS 15

const char inflate_copyright[] =
   " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
/*
  If you use the zlib library in a product, an acknowledgment is welcome
  in the documentation of your product. If for some reason you cannot
  include such an acknowledgment, I would appreciate that you keep this
  copyright string in the executable of your product.
 */

/*
   Build a set of tables to decode the provided canonical Huffman code.
   The code lengths are lens[0..codes-1].  The result starts at *table,
   whose indices are 0..2^bits-1.  work is a writable array of at least
   lens shorts, which is used as a work area.  type is the type of code
   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
   on return points to the next available entry's address.  bits is the
   requested root table index bits, and on return it is the actual root
   table index bits.  It will differ if the request is greater than the
   longest code or if it is less than the shortest code.
 */
int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
codetype type;
unsigned short FAR *lens;
unsigned codes;
code FAR * FAR *table;
unsigned FAR *bits;
unsigned short FAR *work;
{
    unsigned len;               /* a code's length in bits */
    unsigned sym;               /* index of code symbols */
    unsigned min, max;          /* minimum and maximum code lengths */
    unsigned root;              /* number of index bits for root table */
    unsigned curr;              /* number of index bits for current table */
    unsigned drop;              /* code bits to drop for sub-table */
    int left;                   /* number of prefix codes available */
    unsigned used;              /* code entries in table used */
    unsigned huff;              /* Huffman code */
    unsigned incr;              /* for incrementing code, index */
    unsigned fill;              /* index for replicating entries */
    unsigned low;               /* low bits for current root entry */
    unsigned mask;              /* mask for low root bits */
    code here;                  /* table entry for duplication */
    code FAR *next;             /* next available space in table */
    const unsigned short FAR *base;     /* base value table to use */
    const unsigned short FAR *extra;    /* extra bits table to use */
    unsigned match;             /* use base and extra for symbol >= match */
    unsigned short count[MAXBITS+1];    /* number of codes of each length */
    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
        8193, 12289, 16385, 24577, 0, 0};
    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
        28, 28, 29, 29, 64, 64};

    /*
       Process a set of code lengths to create a canonical Huffman code.  The
       code lengths are lens[0..codes-1].  Each length corresponds to the
       symbols 0..codes-1.  The Huffman code is generated by first sorting the
       symbols by length from short to long, and retaining the symbol order
       for codes with equal lengths.  Then the code starts with all zero bits
       for the first code of the shortest length, and the codes are integer
       increments for the same length, and zeros are appended as the length
       increases.  For the deflate format, these bits are stored backwards
       from their more natural integer increment ordering, and so when the
       decoding tables are built in the large loop below, the integer codes
       are incremented backwards.

       This routine assumes, but does not check, that all of the entries in
       lens[] are in the range 0..MAXBITS.  The caller must assure this.
       1..MAXBITS is interpreted as that code length.  zero means that that
       symbol does not occur in this code.

       The codes are sorted by computing a count of codes for each length,
       creating from that a table of starting indices for each length in the
       sorted table, and then entering the symbols in order in the sorted
       table.  The sorted table is work[], with that space being provided by
       the caller.

       The length counts are used for other purposes as well, i.e. finding
       the minimum and maximum length codes, determining if there are any
       codes at all, checking for a valid set of lengths, and looking ahead
       at length counts to determine sub-table sizes when building the
       decoding tables.
     */

    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
    for (len = 0; len <= MAXBITS; len++)
        count[len] = 0;
    for (sym = 0; sym < codes; sym++)
        count[lens[sym]]++;

    /* bound code lengths, force root to be within code lengths */
    root = *bits;
    for (max = MAXBITS; max >= 1; max--)
        if (count[max] != 0) break;
    if (root > max) root = max;
    if (max == 0) {                     /* no symbols to code at all */
        here.op = (unsigned char)64;    /* invalid code marker */
        here.bits = (unsigned char)1;
        here.val = (unsigned short)0;
        *(*table)++ = here;             /* make a table to force an error */
        *(*table)++ = here;
        *bits = 1;
        return 0;     /* no symbols, but wait for decoding to report error */
    }
    for (min = 1; min < max; min++)
        if (count[min] != 0) break;
    if (root < min) root = min;

    /* check for an over-subscribed or incomplete set of lengths */
    left = 1;
    for (len = 1; len <= MAXBITS; len++) {
        left <<= 1;
        left -= count[len];
        if (left < 0) return -1;        /* over-subscribed */
    }
    if (left > 0 && (type == CODES || max != 1))
        return -1;                      /* incomplete set */

    /* generate offsets into symbol table for each length for sorting */
    offs[1] = 0;
    for (len = 1; len < MAXBITS; len++)
        offs[len + 1] = offs[len] + count[len];

    /* sort symbols by length, by symbol order within each length */
    for (sym = 0; sym < codes; sym++)
        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;

    /*
       Create and fill in decoding tables.  In this loop, the table being
       filled is at next and has curr index bits.  The code being used is huff
       with length len.  That code is converted to an index by dropping drop
       bits off of the bottom.  For codes where len is less than drop + curr,
       those top drop + curr - len bits are incremented through all values to
       fill the table with replicated entries.

       root is the number of index bits for the root table.  When len exceeds
       root, sub-tables are created pointed to by the root entry with an index
       of the low root bits of huff.  This is saved in low to check for when a
       new sub-table should be started.  drop is zero when the root table is
       being filled, and drop is root when sub-tables are being filled.

       When a new sub-table is needed, it is necessary to look ahead in the
       code lengths to determine what size sub-table is needed.  The length
       counts are used for this, and so count[] is decremented as codes are
       entered in the tables.

       used keeps track of how many table entries have been allocated from the
       provided *table space.  It is checked for LENS and DIST tables against
       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
       the initial root table size constants.  See the comments in inftrees.h
       for more information.

       sym increments through all symbols, and the loop terminates when
       all codes of length max, i.e. all codes, have been processed.  This
       routine permits incomplete codes, so another loop after this one fills
       in the rest of the decoding tables with invalid code markers.
     */

    /* set up for code type */
    switch (type) {
    case CODES:
        base = extra = work;    /* dummy value--not used */
        match = 20;
        break;
    case LENS:
        base = lbase;
        extra = lext;
        match = 257;
        break;
    default:            /* DISTS */
        base = dbase;
        extra = dext;
        match = 0;
    }

    /* initialize state for loop */
    huff = 0;                   /* starting code */
    sym = 0;                    /* starting code symbol */
    len = min;                  /* starting code length */
    next = *table;              /* current table to fill in */
    curr = root;                /* current table index bits */
    drop = 0;                   /* current bits to drop from code for index */
    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
    used = 1U << root;          /* use root table entries */
    mask = used - 1;            /* mask for comparing low */

    /* check available table space */
    if ((type == LENS && used > ENOUGH_LENS) ||
        (type == DISTS && used > ENOUGH_DISTS))
        return 1;

    /* process all codes and make table entries */
    for (;;) {
        /* create table entry */
        here.bits = (unsigned char)(len - drop);
        if (work[sym] + 1u < match) {
            here.op = (unsigned char)0;
            here.val = work[sym];
        }
        else if (work[sym] >= match) {
            here.op = (unsigned char)(extra[work[sym] - match]);
            here.val = base[work[sym] - match];
        }
        else {
            here.op = (unsigned char)(32 + 64);         /* end of block */
            here.val = 0;
        }

        /* replicate for those indices with low len bits equal to huff */
        incr = 1U << (len - drop);
        fill = 1U << curr;
        min = fill;                 /* save offset to next table */
        do {
            fill -= incr;
            next[(huff >> drop) + fill] = here;
        } while (fill != 0);

        /* backwards increment the len-bit code huff */
        incr = 1U << (len - 1);
        while (huff & incr)
            incr >>= 1;
        if (incr != 0) {
            huff &= incr - 1;
            huff += incr;
        }
        else
            huff = 0;

        /* go to next symbol, update count, len */
        sym++;
        if (--(count[len]) == 0) {
            if (len == max) break;
            len = lens[work[sym]];
        }

        /* create new sub-table if needed */
        if (len > root && (huff & mask) != low) {
            /* if first time, transition to sub-tables */
            if (drop == 0)
                drop = root;

            /* increment past last table */
            next += min;            /* here min is 1 << curr */

            /* determine length of next table */
            curr = len - drop;
            left = (int)(1 << curr);
            while (curr + drop < max) {
                left -= count[curr + drop];
                if (left <= 0) break;
                curr++;
                left <<= 1;
            }

            /* check for enough space */
            used += 1U << curr;
            if ((type == LENS && used > ENOUGH_LENS) ||
                (type == DISTS && used > ENOUGH_DISTS))
                return 1;

            /* point entry in root table to sub-table */
            low = huff & mask;
            (*table)[low].op = (unsigned char)curr;
            (*table)[low].bits = (unsigned char)root;
            (*table)[low].val = (unsigned short)(next - *table);
        }
    }

    /* fill in remaining table entry if code is incomplete (guaranteed to have
       at most one remaining entry, since if the code is incomplete, the
       maximum code length that was allowed to get this far is one bit) */
    if (huff != 0) {
        here.op = (unsigned char)64;            /* invalid code marker */
        here.bits = (unsigned char)(len - drop);
        here.val = (unsigned short)0;
        next[huff] = here;
    }

    /* set return parameters */
    *table += used;
    *bits = root;
    return 0;
}
rsync-3.2.7/zlib/trees.c0000664000000000000000000012455614225047132013624 0ustar  rootroot/* trees.c -- output deflated data using Huffman coding
 * Copyright (C) 1995-2012 Jean-loup Gailly
 * detect_data_type() function provided freely by Cosmin Truta, 2006
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/*
 *  ALGORITHM
 *
 *      The "deflation" process uses several Huffman trees. The more
 *      common source values are represented by shorter bit sequences.
 *
 *      Each code tree is stored in a compressed form which is itself
 * a Huffman encoding of the lengths of all the code strings (in
 * ascending order by source values).  The actual code strings are
 * reconstructed from the lengths in the inflate process, as described
 * in the deflate specification.
 *
 *  REFERENCES
 *
 *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
 *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
 *
 *      Storer, James A.
 *          Data Compression:  Methods and Theory, pp. 49-50.
 *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
 *
 *      Sedgewick, R.
 *          Algorithms, p290.
 *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
 */

/* @(#) $Id$ */

/* #define GEN_TREES_H */

#include "deflate.h"

#ifdef DEBUG
#  include 
#endif

/* ===========================================================================
 * Constants
 */

#define MAX_BL_BITS 7
/* Bit length codes must not exceed MAX_BL_BITS bits */

#define END_BLOCK 256
/* end of block literal code */

#define REP_3_6      16
/* repeat previous bit length 3-6 times (2 bits of repeat count) */

#define REPZ_3_10    17
/* repeat a zero length 3-10 times  (3 bits of repeat count) */

#define REPZ_11_138  18
/* repeat a zero length 11-138 times  (7 bits of repeat count) */

local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};

local const int extra_dbits[D_CODES] /* extra bits for each distance code */
   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};

local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};

local const uch bl_order[BL_CODES]
   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
/* The lengths of the bit length codes are sent in order of decreasing
 * probability, to avoid transmitting the lengths for unused bit length codes.
 */

/* ===========================================================================
 * Local data. These are initialized only once.
 */

#define DIST_CODE_LEN  512 /* see definition of array dist_code below */

#if defined(GEN_TREES_H) || !defined(STDC)
/* non ANSI compilers may not accept trees.h */

local ct_data static_ltree[L_CODES+2];
/* The static literal tree. Since the bit lengths are imposed, there is no
 * need for the L_CODES extra codes used during heap construction. However
 * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
 * below).
 */

local ct_data static_dtree[D_CODES];
/* The static distance tree. (Actually a trivial tree since all codes use
 * 5 bits.)
 */

uch _dist_code[DIST_CODE_LEN];
/* Distance codes. The first 256 values correspond to the distances
 * 3 .. 258, the last 256 values correspond to the top 8 bits of
 * the 15 bit distances.
 */

uch _length_code[MAX_MATCH-MIN_MATCH+1];
/* length code for each normalized match length (0 == MIN_MATCH) */

local int base_length[LENGTH_CODES];
/* First normalized length for each code (0 = MIN_MATCH) */

local int base_dist[D_CODES];
/* First normalized distance for each code (0 = distance of 1) */

#else
#  include "trees.h"
#endif /* GEN_TREES_H */

struct static_tree_desc_s {
    const ct_data *static_tree;  /* static tree or NULL */
    const intf *extra_bits;      /* extra bits for each code or NULL */
    int     extra_base;          /* base index for extra_bits */
    int     elems;               /* max number of elements in the tree */
    int     max_length;          /* max bit length for the codes */
};

local static_tree_desc  static_l_desc =
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};

local static_tree_desc  static_d_desc =
{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};

local static_tree_desc  static_bl_desc =
{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};

/* ===========================================================================
 * Local (static) routines in this file.
 */

local void tr_static_init OF((void));
local void init_block     OF((deflate_state *s));
local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
local void build_tree     OF((deflate_state *s, tree_desc *desc));
local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
local int  build_bl_tree  OF((deflate_state *s));
local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
                              int blcodes));
local void compress_block OF((deflate_state *s, const ct_data *ltree,
                              const ct_data *dtree));
local int  detect_data_type OF((deflate_state *s));
local unsigned bi_reverse OF((unsigned value, int length));
local void bi_windup      OF((deflate_state *s));
local void bi_flush       OF((deflate_state *s));
local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
                              int header));

#ifdef GEN_TREES_H
local void gen_trees_header OF((void));
#endif

#ifndef DEBUG
#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
   /* Send a code of the given tree. c and tree must not have side effects */

#else /* DEBUG */
#  define send_code(s, c, tree) \
     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
       send_bits(s, tree[c].Code, tree[c].Len); }
#endif

/* ===========================================================================
 * Output a short LSB first on the stream.
 * IN assertion: there is enough room in pendingBuf.
 */
#define put_short(s, w) { \
    put_byte(s, (uch)((w) & 0xff)); \
    put_byte(s, (uch)((ush)(w) >> 8)); \
}

/* ===========================================================================
 * Send a value on a given number of bits.
 * IN assertion: length <= 16 and value fits in length bits.
 */
#ifdef DEBUG
local void send_bits      OF((deflate_state *s, int value, int length));

local void send_bits(s, value, length)
    deflate_state *s;
    int value;  /* value to send */
    int length; /* number of bits */
{
    Tracevv((stderr," l %2d v %4x ", length, value));
    Assert(length > 0 && length <= 15, "invalid length");
    s->bits_sent += (ulg)length;

    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
     * unused bits in value.
     */
    if (s->bi_valid > (int)Buf_size - length) {
        s->bi_buf |= (ush)value << s->bi_valid;
        put_short(s, s->bi_buf);
        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
        s->bi_valid += length - Buf_size;
    } else {
        s->bi_buf |= (ush)value << s->bi_valid;
        s->bi_valid += length;
    }
}
#else /* !DEBUG */

#define send_bits(s, value, length) \
{ int len = length;\
  if (s->bi_valid > (int)Buf_size - len) {\
    int val = value;\
    s->bi_buf |= (ush)val << s->bi_valid;\
    put_short(s, s->bi_buf);\
    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
    s->bi_valid += len - Buf_size;\
  } else {\
    s->bi_buf |= (ush)(value) << s->bi_valid;\
    s->bi_valid += len;\
  }\
}
#endif /* DEBUG */


/* the arguments must not have side effects */

/* ===========================================================================
 * Initialize the various 'constant' tables.
 */
local void tr_static_init()
{
#if defined(GEN_TREES_H) || !defined(STDC)
    static int static_init_done = 0;
    int n;        /* iterates over tree elements */
    int bits;     /* bit counter */
    int length;   /* length value */
    int code;     /* code value */
    int dist;     /* distance index */
    ush bl_count[MAX_BITS+1];
    /* number of codes at each bit length for an optimal tree */

    if (static_init_done) return;

    /* For some embedded targets, global variables are not initialized: */
#ifdef NO_INIT_GLOBAL_POINTERS
    static_l_desc.static_tree = static_ltree;
    static_l_desc.extra_bits = extra_lbits;
    static_d_desc.static_tree = static_dtree;
    static_d_desc.extra_bits = extra_dbits;
    static_bl_desc.extra_bits = extra_blbits;
#endif

    /* Initialize the mapping length (0..255) -> length code (0..28) */
    length = 0;
    for (code = 0; code < LENGTH_CODES-1; code++) {
        base_length[code] = length;
        for (n = 0; n < (1< dist code (0..29) */
    dist = 0;
    for (code = 0 ; code < 16; code++) {
        base_dist[code] = dist;
        for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */
    for ( ; code < D_CODES; code++) {
        base_dist[code] = dist << 7;
        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
            _dist_code[256 + dist++] = (uch)code;
        }
    }
    Assert (dist == 256, "tr_static_init: 256+dist != 512");

    /* Construct the codes of the static literal tree */
    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
    n = 0;
    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
    /* Codes 286 and 287 do not exist, but we must include them in the
     * tree construction to get a canonical Huffman tree (longest code
     * all ones)
     */
    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);

    /* The static distance tree is trivial: */
    for (n = 0; n < D_CODES; n++) {
        static_dtree[n].Len = 5;
        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
    }
    static_init_done = 1;

#  ifdef GEN_TREES_H
    gen_trees_header();
#  endif
#endif /* defined(GEN_TREES_H) || !defined(STDC) */
}

/* ===========================================================================
 * Genererate the file trees.h describing the static trees.
 */
#ifdef GEN_TREES_H
#  ifndef DEBUG
#    include 
#  endif

#  define SEPARATOR(i, last, width) \
      ((i) == (last)? "\n};\n\n" :    \
       ((i) % (width) == (width)-1 ? ",\n" : ", "))

void gen_trees_header()
{
    FILE *header = fopen("trees.h", "w");
    int i;

    Assert (header != NULL, "Can't open trees.h");
    fprintf(header,
            "/* header created automatically with -DGEN_TREES_H */\n\n");

    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
    for (i = 0; i < L_CODES+2; i++) {
        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
    }

    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
    for (i = 0; i < D_CODES; i++) {
        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
    }

    fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
    for (i = 0; i < DIST_CODE_LEN; i++) {
        fprintf(header, "%2u%s", _dist_code[i],
                SEPARATOR(i, DIST_CODE_LEN-1, 20));
    }

    fprintf(header,
        "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
        fprintf(header, "%2u%s", _length_code[i],
                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
    }

    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
    for (i = 0; i < LENGTH_CODES; i++) {
        fprintf(header, "%1u%s", base_length[i],
                SEPARATOR(i, LENGTH_CODES-1, 20));
    }

    fprintf(header, "local const int base_dist[D_CODES] = {\n");
    for (i = 0; i < D_CODES; i++) {
        fprintf(header, "%5u%s", base_dist[i],
                SEPARATOR(i, D_CODES-1, 10));
    }

    fclose(header);
}
#endif /* GEN_TREES_H */

/* ===========================================================================
 * Initialize the tree data structures for a new zlib stream.
 */
void ZLIB_INTERNAL _tr_init(s)
    deflate_state *s;
{
    tr_static_init();

    s->l_desc.dyn_tree = s->dyn_ltree;
    s->l_desc.stat_desc = &static_l_desc;

    s->d_desc.dyn_tree = s->dyn_dtree;
    s->d_desc.stat_desc = &static_d_desc;

    s->bl_desc.dyn_tree = s->bl_tree;
    s->bl_desc.stat_desc = &static_bl_desc;

    s->bi_buf = 0;
    s->bi_valid = 0;
#ifdef DEBUG
    s->compressed_len = 0L;
    s->bits_sent = 0L;
#endif

    /* Initialize the first block of the first file: */
    init_block(s);
}

/* ===========================================================================
 * Initialize a new block.
 */
local void init_block(s)
    deflate_state *s;
{
    int n; /* iterates over tree elements */

    /* Initialize the trees. */
    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;

    s->dyn_ltree[END_BLOCK].Freq = 1;
    s->opt_len = s->static_len = 0L;
    s->sym_next = s->matches = 0;
}

#define SMALLEST 1
/* Index within the heap array of least frequent node in the Huffman tree */


/* ===========================================================================
 * Remove the smallest element from the heap and recreate the heap with
 * one less element. Updates heap and heap_len.
 */
#define pqremove(s, tree, top) \
{\
    top = s->heap[SMALLEST]; \
    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
    pqdownheap(s, tree, SMALLEST); \
}

/* ===========================================================================
 * Compares to subtrees, using the tree depth as tie breaker when
 * the subtrees have equal frequency. This minimizes the worst case length.
 */
#define smaller(tree, n, m, depth) \
   (tree[n].Freq < tree[m].Freq || \
   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))

/* ===========================================================================
 * Restore the heap property by moving down the tree starting at node k,
 * exchanging a node with the smallest of its two sons if necessary, stopping
 * when the heap property is re-established (each father smaller than its
 * two sons).
 */
local void pqdownheap(s, tree, k)
    deflate_state *s;
    ct_data *tree;  /* the tree to restore */
    int k;               /* node to move down */
{
    int v = s->heap[k];
    int j = k << 1;  /* left son of k */
    while (j <= s->heap_len) {
        /* Set j to the smallest of the two sons: */
        if (j < s->heap_len &&
            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
            j++;
        }
        /* Exit if v is smaller than both sons */
        if (smaller(tree, v, s->heap[j], s->depth)) break;

        /* Exchange v with the smallest son */
        s->heap[k] = s->heap[j];  k = j;

        /* And continue down the tree, setting j to the left son of k */
        j <<= 1;
    }
    s->heap[k] = v;
}

/* ===========================================================================
 * Compute the optimal bit lengths for a tree and update the total bit length
 * for the current block.
 * IN assertion: the fields freq and dad are set, heap[heap_max] and
 *    above are the tree nodes sorted by increasing frequency.
 * OUT assertions: the field len is set to the optimal bit length, the
 *     array bl_count contains the frequencies for each bit length.
 *     The length opt_len is updated; static_len is also updated if stree is
 *     not null.
 */
local void gen_bitlen(s, desc)
    deflate_state *s;
    tree_desc *desc;    /* the tree descriptor */
{
    ct_data *tree        = desc->dyn_tree;
    int max_code         = desc->max_code;
    const ct_data *stree = desc->stat_desc->static_tree;
    const intf *extra    = desc->stat_desc->extra_bits;
    int base             = desc->stat_desc->extra_base;
    int max_length       = desc->stat_desc->max_length;
    int h;              /* heap index */
    int n, m;           /* iterate over the tree elements */
    int bits;           /* bit length */
    int xbits;          /* extra bits */
    ush f;              /* frequency */
    int overflow = 0;   /* number of elements with bit length too large */

    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;

    /* In a first pass, compute the optimal bit lengths (which may
     * overflow in the case of the bit length tree).
     */
    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */

    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
        n = s->heap[h];
        bits = tree[tree[n].Dad].Len + 1;
        if (bits > max_length) bits = max_length, overflow++;
        tree[n].Len = (ush)bits;
        /* We overwrite tree[n].Dad which is no longer needed */

        if (n > max_code) continue; /* not a leaf node */

        s->bl_count[bits]++;
        xbits = 0;
        if (n >= base) xbits = extra[n-base];
        f = tree[n].Freq;
        s->opt_len += (ulg)f * (bits + xbits);
        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
    }
    if (overflow == 0) return;

    Trace((stderr,"\nbit length overflow\n"));
    /* This happens for example on obj2 and pic of the Calgary corpus */

    /* Find the first bit length which could increase: */
    do {
        bits = max_length-1;
        while (s->bl_count[bits] == 0) bits--;
        s->bl_count[bits]--;      /* move one leaf down the tree */
        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
        s->bl_count[max_length]--;
        /* The brother of the overflow item also moves one step up,
         * but this does not affect bl_count[max_length]
         */
        overflow -= 2;
    } while (overflow > 0);

    /* Now recompute all bit lengths, scanning in increasing frequency.
     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
     * lengths instead of fixing only the wrong ones. This idea is taken
     * from 'ar' written by Haruhiko Okumura.)
     */
    for (bits = max_length; bits != 0; bits--) {
        n = s->bl_count[bits];
        while (n != 0) {
            m = s->heap[--h];
            if (m > max_code) continue;
            if ((unsigned) tree[m].Len != (unsigned) bits) {
                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
                s->opt_len += ((long)bits - (long)tree[m].Len)
                              *(long)tree[m].Freq;
                tree[m].Len = (ush)bits;
            }
            n--;
        }
    }
}

/* ===========================================================================
 * Generate the codes for a given tree and bit counts (which need not be
 * optimal).
 * IN assertion: the array bl_count contains the bit length statistics for
 * the given tree and the field len is set for all tree elements.
 * OUT assertion: the field code is set for all tree elements of non
 *     zero code length.
 */
local void gen_codes (tree, max_code, bl_count)
    ct_data *tree;             /* the tree to decorate */
    int max_code;              /* largest code with non zero frequency */
    ushf *bl_count;            /* number of codes at each bit length */
{
    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
    ush code = 0;              /* running code value */
    int bits;                  /* bit index */
    int n;                     /* code index */

    /* The distribution counts are first used to generate the code values
     * without bit reversal.
     */
    for (bits = 1; bits <= MAX_BITS; bits++) {
        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
    }
    /* Check that the bit counts in bl_count are consistent. The last code
     * must be all ones.
     */
    Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree;
    const ct_data *stree  = desc->stat_desc->static_tree;
    int elems             = desc->stat_desc->elems;
    int n, m;          /* iterate over heap elements */
    int max_code = -1; /* largest code with non zero frequency */
    int node;          /* new node being created */

    /* Construct the initial heap, with least frequent element in
     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
     * heap[0] is not used.
     */
    s->heap_len = 0, s->heap_max = HEAP_SIZE;

    for (n = 0; n < elems; n++) {
        if (tree[n].Freq != 0) {
            s->heap[++(s->heap_len)] = max_code = n;
            s->depth[n] = 0;
        } else {
            tree[n].Len = 0;
        }
    }

    /* The pkzip format requires that at least one distance code exists,
     * and that at least one bit should be sent even if there is only one
     * possible code. So to avoid special checks later on we force at least
     * two codes of non zero frequency.
     */
    while (s->heap_len < 2) {
        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
        tree[node].Freq = 1;
        s->depth[node] = 0;
        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
        /* node is 0 or 1 so it does not have extra bits */
    }
    desc->max_code = max_code;

    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
     * establish sub-heaps of increasing lengths:
     */
    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);

    /* Construct the Huffman tree by repeatedly combining the least two
     * frequent nodes.
     */
    node = elems;              /* next internal node of the tree */
    do {
        pqremove(s, tree, n);  /* n = node of least frequency */
        m = s->heap[SMALLEST]; /* m = node of next least frequency */

        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
        s->heap[--(s->heap_max)] = m;

        /* Create a new node father of n and m */
        tree[node].Freq = tree[n].Freq + tree[m].Freq;
        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
                                s->depth[n] : s->depth[m]) + 1);
        tree[n].Dad = tree[m].Dad = (ush)node;
#ifdef DUMP_BL_TREE
        if (tree == s->bl_tree) {
            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
        }
#endif
        /* and insert the new node in the heap */
        s->heap[SMALLEST] = node++;
        pqdownheap(s, tree, SMALLEST);

    } while (s->heap_len >= 2);

    s->heap[--(s->heap_max)] = s->heap[SMALLEST];

    /* At this point, the fields freq and dad are set. We can now
     * generate the bit lengths.
     */
    gen_bitlen(s, (tree_desc *)desc);

    /* The field len is now set, we can generate the bit codes */
    gen_codes ((ct_data *)tree, max_code, s->bl_count);
}

/* ===========================================================================
 * Scan a literal or distance tree to determine the frequencies of the codes
 * in the bit length tree.
 */
local void scan_tree (s, tree, max_code)
    deflate_state *s;
    ct_data *tree;   /* the tree to be scanned */
    int max_code;    /* and its largest code of non zero frequency */
{
    int n;                     /* iterates over all tree elements */
    int prevlen = -1;          /* last emitted length */
    int curlen;                /* length of current code */
    int nextlen = tree[0].Len; /* length of next code */
    int count = 0;             /* repeat count of the current code */
    int max_count = 7;         /* max repeat count */
    int min_count = 4;         /* min repeat count */

    if (nextlen == 0) max_count = 138, min_count = 3;
    tree[max_code+1].Len = (ush)0xffff; /* guard */

    for (n = 0; n <= max_code; n++) {
        curlen = nextlen; nextlen = tree[n+1].Len;
        if (++count < max_count && curlen == nextlen) {
            continue;
        } else if (count < min_count) {
            s->bl_tree[curlen].Freq += count;
        } else if (curlen != 0) {
            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
            s->bl_tree[REP_3_6].Freq++;
        } else if (count <= 10) {
            s->bl_tree[REPZ_3_10].Freq++;
        } else {
            s->bl_tree[REPZ_11_138].Freq++;
        }
        count = 0; prevlen = curlen;
        if (nextlen == 0) {
            max_count = 138, min_count = 3;
        } else if (curlen == nextlen) {
            max_count = 6, min_count = 3;
        } else {
            max_count = 7, min_count = 4;
        }
    }
}

/* ===========================================================================
 * Send a literal or distance tree in compressed form, using the codes in
 * bl_tree.
 */
local void send_tree (s, tree, max_code)
    deflate_state *s;
    ct_data *tree; /* the tree to be scanned */
    int max_code;       /* and its largest code of non zero frequency */
{
    int n;                     /* iterates over all tree elements */
    int prevlen = -1;          /* last emitted length */
    int curlen;                /* length of current code */
    int nextlen = tree[0].Len; /* length of next code */
    int count = 0;             /* repeat count of the current code */
    int max_count = 7;         /* max repeat count */
    int min_count = 4;         /* min repeat count */

    /* tree[max_code+1].Len = -1; */  /* guard already set */
    if (nextlen == 0) max_count = 138, min_count = 3;

    for (n = 0; n <= max_code; n++) {
        curlen = nextlen; nextlen = tree[n+1].Len;
        if (++count < max_count && curlen == nextlen) {
            continue;
        } else if (count < min_count) {
            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);

        } else if (curlen != 0) {
            if (curlen != prevlen) {
                send_code(s, curlen, s->bl_tree); count--;
            }
            Assert(count >= 3 && count <= 6, " 3_6?");
            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);

        } else if (count <= 10) {
            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);

        } else {
            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
        }
        count = 0; prevlen = curlen;
        if (nextlen == 0) {
            max_count = 138, min_count = 3;
        } else if (curlen == nextlen) {
            max_count = 6, min_count = 3;
        } else {
            max_count = 7, min_count = 4;
        }
    }
}

/* ===========================================================================
 * Construct the Huffman tree for the bit lengths and return the index in
 * bl_order of the last bit length code to send.
 */
local int build_bl_tree(s)
    deflate_state *s;
{
    int max_blindex;  /* index of last bit length code of non zero freq */

    /* Determine the bit length frequencies for literal and distance trees */
    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);

    /* Build the bit length tree: */
    build_tree(s, (tree_desc *)(&(s->bl_desc)));
    /* opt_len now includes the length of the tree representations, except
     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
     */

    /* Determine the number of bit length codes to send. The pkzip format
     * requires that at least 4 bit length codes be sent. (appnote.txt says
     * 3 but the actual value used is 4.)
     */
    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
    }
    /* Update opt_len to include the bit length tree and counts */
    s->opt_len += 3*(max_blindex+1) + 5+5+4;
    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
            s->opt_len, s->static_len));

    return max_blindex;
}

/* ===========================================================================
 * Send the header for a block using dynamic Huffman trees: the counts, the
 * lengths of the bit length codes, the literal tree and the distance tree.
 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
 */
local void send_all_trees(s, lcodes, dcodes, blcodes)
    deflate_state *s;
    int lcodes, dcodes, blcodes; /* number of codes for each tree */
{
    int rank;                    /* index in bl_order */

    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
            "too many codes");
    Tracev((stderr, "\nbl counts: "));
    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
    send_bits(s, dcodes-1,   5);
    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
    for (rank = 0; rank < blcodes; rank++) {
        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
    }
    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));

    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));

    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
}

/* ===========================================================================
 * Send a stored block
 */
void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
    deflate_state *s;
    charf *buf;       /* input block */
    ulg stored_len;   /* length of input block */
    int last;         /* one if this is the last block for a file */
{
    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */
#ifdef DEBUG
    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
    s->compressed_len += (stored_len + 4) << 3;
#endif
    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
}

/* ===========================================================================
 * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
 */
void ZLIB_INTERNAL _tr_flush_bits(s)
    deflate_state *s;
{
    bi_flush(s);
}

/* ===========================================================================
 * Send one empty static block to give enough lookahead for inflate.
 * This takes 10 bits, of which 7 may remain in the bit buffer.
 */
void ZLIB_INTERNAL _tr_align(s)
    deflate_state *s;
{
    send_bits(s, STATIC_TREES<<1, 3);
    send_code(s, END_BLOCK, static_ltree);
#ifdef DEBUG
    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
#endif
    bi_flush(s);
}

/* ===========================================================================
 * Determine the best encoding for the current block: dynamic trees, static
 * trees or store, and output the encoded block to the zip file.
 */
void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
    deflate_state *s;
    charf *buf;       /* input block, or NULL if too old */
    ulg stored_len;   /* length of input block */
    int last;         /* one if this is the last block for a file */
{
    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
    int max_blindex = 0;  /* index of last bit length code of non zero freq */

    /* Build the Huffman trees unless a stored block is forced */
    if (s->level > 0) {

        /* Check if the file is binary or text */
        if (s->strm->data_type == Z_UNKNOWN)
            s->strm->data_type = detect_data_type(s);

        /* Construct the literal and distance trees */
        build_tree(s, (tree_desc *)(&(s->l_desc)));
        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
                s->static_len));

        build_tree(s, (tree_desc *)(&(s->d_desc)));
        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
                s->static_len));
        /* At this point, opt_len and static_len are the total bit lengths of
         * the compressed block data, excluding the tree representations.
         */

        /* Build the bit length tree for the above two trees, and get the index
         * in bl_order of the last bit length code to send.
         */
        max_blindex = build_bl_tree(s);

        /* Determine the best encoding. Compute the block lengths in bytes. */
        opt_lenb = (s->opt_len+3+7)>>3;
        static_lenb = (s->static_len+3+7)>>3;

        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
                s->sym_next / 3));

        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;

    } else {
        Assert(buf != (char*)0, "lost buf");
        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
    }

#ifdef FORCE_STORED
    if (buf != (char*)0) { /* force stored block */
#else
    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
                       /* 4: two words for the lengths */
#endif
        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
         * Otherwise we can't have processed more than WSIZE input bytes since
         * the last block flush, because compression would have been
         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
         * transform a block into a stored block.
         */
        _tr_stored_block(s, buf, stored_len, last);

#ifdef FORCE_STATIC
    } else if (static_lenb >= 0) { /* force static trees */
#else
    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
#endif
        send_bits(s, (STATIC_TREES<<1)+last, 3);
        compress_block(s, (const ct_data *)static_ltree,
                       (const ct_data *)static_dtree);
#ifdef DEBUG
        s->compressed_len += 3 + s->static_len;
#endif
    } else {
        send_bits(s, (DYN_TREES<<1)+last, 3);
        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
                       max_blindex+1);
        compress_block(s, (const ct_data *)s->dyn_ltree,
                       (const ct_data *)s->dyn_dtree);
#ifdef DEBUG
        s->compressed_len += 3 + s->opt_len;
#endif
    }
    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
    /* The above check is made mod 2^32, for files larger than 512 MB
     * and uLong implemented on 32 bits.
     */
    init_block(s);

    if (last) {
        bi_windup(s);
#ifdef DEBUG
        s->compressed_len += 7;  /* align on byte boundary */
#endif
    }
    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
           s->compressed_len-7*last));
}

/* ===========================================================================
 * Save the match info and tally the frequency counts. Return true if
 * the current block must be flushed.
 */
int ZLIB_INTERNAL _tr_tally (s, dist, lc)
    deflate_state *s;
    unsigned dist;  /* distance of matched string */
    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
{
    s->sym_buf[s->sym_next++] = dist;
    s->sym_buf[s->sym_next++] = dist >> 8;
    s->sym_buf[s->sym_next++] = lc;
    if (dist == 0) {
        /* lc is the unmatched char */
        s->dyn_ltree[lc].Freq++;
    } else {
        s->matches++;
        /* Here, lc is the match length - MIN_MATCH */
        dist--;             /* dist = match distance - 1 */
        Assert((ush)dist < (ush)MAX_DIST(s) &&
               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");

        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
        s->dyn_dtree[d_code(dist)].Freq++;
    }
    return (s->sym_next == s->sym_end);
}

/* ===========================================================================
 * Send the block data compressed using the given Huffman trees
 */
local void compress_block(s, ltree, dtree)
    deflate_state *s;
    const ct_data *ltree; /* literal tree */
    const ct_data *dtree; /* distance tree */
{
    unsigned dist;      /* distance of matched string */
    int lc;             /* match length or unmatched char (if dist == 0) */
    unsigned sx = 0;    /* running index in sym_buf */
    unsigned code;      /* the code to send */
    int extra;          /* number of extra bits to send */

    if (s->sym_next != 0) do {
        dist = s->sym_buf[sx++] & 0xff;
        dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
        lc = s->sym_buf[sx++];
        if (dist == 0) {
            send_code(s, lc, ltree); /* send a literal byte */
            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
        } else {
            /* Here, lc is the match length - MIN_MATCH */
            code = _length_code[lc];
            send_code(s, code+LITERALS+1, ltree); /* send the length code */
            extra = extra_lbits[code];
            if (extra != 0) {
                lc -= base_length[code];
                send_bits(s, lc, extra);       /* send the extra length bits */
            }
            dist--; /* dist is now the match distance - 1 */
            code = d_code(dist);
            Assert (code < D_CODES, "bad d_code");

            send_code(s, code, dtree);       /* send the distance code */
            extra = extra_dbits[code];
            if (extra != 0) {
                dist -= base_dist[code];
                send_bits(s, dist, extra);   /* send the extra distance bits */
            }
        } /* literal or match pair ? */

        /* Check that the overlay between pending_buf and sym_buf is ok: */
        Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");

    } while (sx < s->sym_next);

    send_code(s, END_BLOCK, ltree);
}

/* ===========================================================================
 * Check if the data type is TEXT or BINARY, using the following algorithm:
 * - TEXT if the two conditions below are satisfied:
 *    a) There are no non-portable control characters belonging to the
 *       "black list" (0..6, 14..25, 28..31).
 *    b) There is at least one printable character belonging to the
 *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
 * - BINARY otherwise.
 * - The following partially-portable control characters form a
 *   "gray list" that is ignored in this detection algorithm:
 *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
 * IN assertion: the fields Freq of dyn_ltree are set.
 */
local int detect_data_type(s)
    deflate_state *s;
{
    /* black_mask is the bit mask of black-listed bytes
     * set bits 0..6, 14..25, and 28..31
     * 0xf3ffc07f = binary 11110011111111111100000001111111
     */
    unsigned long black_mask = 0xf3ffc07fUL;
    int n;

    /* Check for non-textual ("black-listed") bytes. */
    for (n = 0; n <= 31; n++, black_mask >>= 1)
        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
            return Z_BINARY;

    /* Check for textual ("white-listed") bytes. */
    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
            || s->dyn_ltree[13].Freq != 0)
        return Z_TEXT;
    for (n = 32; n < LITERALS; n++)
        if (s->dyn_ltree[n].Freq != 0)
            return Z_TEXT;

    /* There are no "black-listed" or "white-listed" bytes:
     * this stream either is empty or has tolerated ("gray-listed") bytes only.
     */
    return Z_BINARY;
}

/* ===========================================================================
 * Reverse the first len bits of a code, using straightforward code (a faster
 * method would use a table)
 * IN assertion: 1 <= len <= 15
 */
local unsigned bi_reverse(code, len)
    unsigned code; /* the value to invert */
    int len;       /* its bit length */
{
    register unsigned res = 0;
    do {
        res |= code & 1;
        code >>= 1, res <<= 1;
    } while (--len > 0);
    return res >> 1;
}

/* ===========================================================================
 * Flush the bit buffer, keeping at most 7 bits in it.
 */
local void bi_flush(s)
    deflate_state *s;
{
    if (s->bi_valid == 16) {
        put_short(s, s->bi_buf);
        s->bi_buf = 0;
        s->bi_valid = 0;
    } else if (s->bi_valid >= 8) {
        put_byte(s, (Byte)s->bi_buf);
        s->bi_buf >>= 8;
        s->bi_valid -= 8;
    }
}

/* ===========================================================================
 * Flush the bit buffer and align the output on a byte boundary
 */
local void bi_windup(s)
    deflate_state *s;
{
    if (s->bi_valid > 8) {
        put_short(s, s->bi_buf);
    } else if (s->bi_valid > 0) {
        put_byte(s, (Byte)s->bi_buf);
    }
    s->bi_buf = 0;
    s->bi_valid = 0;
#ifdef DEBUG
    s->bits_sent = (s->bits_sent+7) & ~7;
#endif
}

/* ===========================================================================
 * Copy a stored block, storing first the length and its
 * one's complement if requested.
 */
local void copy_block(s, buf, len, header)
    deflate_state *s;
    charf    *buf;    /* the input data */
    unsigned len;     /* its length */
    int      header;  /* true if block header must be written */
{
    bi_windup(s);        /* align on byte boundary */

    if (header) {
        put_short(s, (ush)len);
        put_short(s, (ush)~len);
#ifdef DEBUG
        s->bits_sent += 2*16;
#endif
    }
#ifdef DEBUG
    s->bits_sent += (ulg)len<<3;
#endif
    while (len--) {
        put_byte(s, *buf++);
    }
}
rsync-3.2.7/zlib/inffast.h0000664000000000000000000000065312155261705014134 0ustar  rootroot/* inffast.h -- header to use inffast.c
 * Copyright (C) 1995-2003, 2010 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
rsync-3.2.7/zlib/README0000664000000000000000000001210112155261705013200 0ustar  rootrootZLIB DATA COMPRESSION LIBRARY

zlib 1.2.8 is a general purpose data compression library.  All the code is
thread safe.  The data format used by the zlib library is described by RFCs
(Request for Comments) 1950 to 1952 in the files
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
rfc1952 (gzip format).

All functions of the compression library are documented in the file zlib.h
(volunteer to write man pages welcome, contact zlib@gzip.org).  A usage example
of the library is given in the file test/example.c which also tests that
the library is working correctly.  Another example is given in the file
test/minigzip.c.  The compression library itself is composed of all source
files in the root directory.

To compile all files and run the test program, follow the instructions given at
the top of Makefile.in.  In short "./configure; make test", and if that goes
well, "make install" should work for most flavors of Unix.  For Windows, use
one of the special makefiles in win32/ or contrib/vstudio/ .  For VMS, use
make_vms.com.

Questions about zlib should be sent to , or to Gilles Vollant
 for the Windows DLL version.  The zlib home page is
http://zlib.net/ .  Before reporting a problem, please check this site to
verify that you have the latest version of zlib; otherwise get the latest
version and check whether the problem still exists or not.

PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.

Mark Nelson  wrote an article about zlib for the Jan.  1997
issue of Dr.  Dobb's Journal; a copy of the article is available at
http://marknelson.us/1997/01/01/zlib-engine/ .

The changes made in version 1.2.8 are documented in the file ChangeLog.

Unsupported third party contributions are provided in directory contrib/ .

zlib is available in Java using the java.util.zip package, documented at
http://java.sun.com/developer/technicalArticles/Programming/compression/ .

A Perl interface to zlib written by Paul Marquess  is available
at CPAN (Comprehensive Perl Archive Network) sites, including
http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .

A Python interface to zlib written by A.M. Kuchling  is
available in Python 1.5 and later versions, see
http://docs.python.org/library/zlib.html .

zlib is built into tcl: http://wiki.tcl.tk/4610 .

An experimental package to read and write files in .zip format, written on top
of zlib by Gilles Vollant , is available in the
contrib/minizip directory of zlib.


Notes for some targets:

- For Windows DLL versions, please see win32/DLL_FAQ.txt

- For 64-bit Irix, deflate.c must be compiled without any optimization. With
  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
  compiler flag). The compiler bug has been reported to SGI.

- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
  when compiled with cc.

- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
  necessary to get gzprintf working correctly. This is done by configure.

- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
  other compilers. Use "make test" to check your compiler.

- gzdopen is not supported on RISCOS or BEOS.

- For PalmOs, see http://palmzlib.sourceforge.net/


Acknowledgments:

  The deflate format used by zlib was defined by Phil Katz.  The deflate and
  zlib specifications were written by L.  Peter Deutsch.  Thanks to all the
  people who reported problems and suggested various improvements in zlib; they
  are too numerous to cite here.

Copyright notice:

 (C) 1995-2013 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly        Mark Adler
  jloup@gzip.org          madler@alumni.caltech.edu

If you use the zlib library in a product, we would appreciate *not* receiving
lengthy legal documents to sign.  The sources are provided for free but without
warranty of any kind.  The library has been entirely written by Jean-loup
Gailly and Mark Adler; it does not include third-party code.

If you redistribute modified sources, we would appreciate that you include in
the file ChangeLog history information documenting your changes.  Please read
the FAQ for more information on the distribution of modified source versions.
rsync-3.2.7/zlib/deflate.h0000664000000000000000000003070114225047132014077 0ustar  rootroot/* deflate.h -- internal compression state
 * Copyright (C) 1995-2012 Jean-loup Gailly
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef DEFLATE_H
#define DEFLATE_H

#include "zutil.h"

/* define NO_GZIP when compiling if you want to disable gzip header and
   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
   the crc code when it is not needed.  For shared libraries, gzip encoding
   should be left enabled. */
#ifndef NO_GZIP
#  define GZIP
#endif

/* ===========================================================================
 * Internal compression state.
 */

#define LENGTH_CODES 29
/* number of length codes, not counting the special END_BLOCK code */

#define LITERALS  256
/* number of literal bytes 0..255 */

#define L_CODES (LITERALS+1+LENGTH_CODES)
/* number of Literal or Length codes, including the END_BLOCK code */

#define D_CODES   30
/* number of distance codes */

#define BL_CODES  19
/* number of codes used to transfer the bit lengths */

#define HEAP_SIZE (2*L_CODES+1)
/* maximum heap size */

#define MAX_BITS 15
/* All codes must not exceed MAX_BITS bits */

#define Buf_size 16
/* size of bit buffer in bi_buf */

#define INIT_STATE    42
#define EXTRA_STATE   69
#define NAME_STATE    73
#define COMMENT_STATE 91
#define HCRC_STATE   103
#define BUSY_STATE   113
#define FINISH_STATE 666
/* Stream status */


/* Data structure describing a single value and its code string. */
typedef struct ct_data_s {
    union {
        ush  freq;       /* frequency count */
        ush  code;       /* bit string */
    } fc;
    union {
        ush  dad;        /* father node in Huffman tree */
        ush  len;        /* length of bit string */
    } dl;
} FAR ct_data;

#define Freq fc.freq
#define Code fc.code
#define Dad  dl.dad
#define Len  dl.len

typedef struct static_tree_desc_s  static_tree_desc;

typedef struct tree_desc_s {
    ct_data *dyn_tree;           /* the dynamic tree */
    int     max_code;            /* largest code with non zero frequency */
    static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;

typedef ush Pos;
typedef Pos FAR Posf;
typedef unsigned IPos;

/* A Pos is an index in the character window. We use short instead of int to
 * save space in the various tables. IPos is used only for parameter passing.
 */

typedef struct internal_state {
    z_streamp strm;      /* pointer back to this zlib stream */
    int   status;        /* as the name implies */
    Bytef *pending_buf;  /* output still pending */
    ulg   pending_buf_size; /* size of pending_buf */
    Bytef *pending_out;  /* next pending byte to output to the stream */
    uInt   pending;      /* nb of bytes in the pending buffer */
    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
    gz_headerp  gzhead;  /* gzip header information to write */
    uInt   gzindex;      /* where in extra, name, or comment */
    Byte  method;        /* can only be DEFLATED */
    int   last_flush;    /* value of flush param for previous deflate call */

                /* used by deflate.c: */

    uInt  w_size;        /* LZ77 window size (32K by default) */
    uInt  w_bits;        /* log2(w_size)  (8..16) */
    uInt  w_mask;        /* w_size - 1 */

    Bytef *window;
    /* Sliding window. Input bytes are read into the second half of the window,
     * and move to the first half later to keep a dictionary of at least wSize
     * bytes. With this organization, matches are limited to a distance of
     * wSize-MAX_MATCH bytes, but this ensures that IO is always
     * performed with a length multiple of the block size. Also, it limits
     * the window size to 64K, which is quite useful on MSDOS.
     * To do: use the user input buffer as sliding window.
     */

    ulg window_size;
    /* Actual size of window: 2*wSize, except when the user input buffer
     * is directly used as sliding window.
     */

    Posf *prev;
    /* Link to older string with same hash index. To limit the size of this
     * array to 64K, this link is maintained only for the last 32K strings.
     * An index in this array is thus a window index modulo 32K.
     */

    Posf *head; /* Heads of the hash chains or NIL. */

    uInt  ins_h;          /* hash index of string to be inserted */
    uInt  hash_size;      /* number of elements in hash table */
    uInt  hash_bits;      /* log2(hash_size) */
    uInt  hash_mask;      /* hash_size-1 */

    uInt  hash_shift;
    /* Number of bits by which ins_h must be shifted at each input
     * step. It must be such that after MIN_MATCH steps, the oldest
     * byte no longer takes part in the hash key, that is:
     *   hash_shift * MIN_MATCH >= hash_bits
     */

    long block_start;
    /* Window position at the beginning of the current output block. Gets
     * negative when the window is moved backwards.
     */

    uInt match_length;           /* length of best match */
    IPos prev_match;             /* previous match */
    int match_available;         /* set if previous match exists */
    uInt strstart;               /* start of string to insert */
    uInt match_start;            /* start of matching string */
    uInt lookahead;              /* number of valid bytes ahead in window */

    uInt prev_length;
    /* Length of the best match at previous step. Matches not greater than this
     * are discarded. This is used in the lazy match evaluation.
     */

    uInt max_chain_length;
    /* To speed up deflation, hash chains are never searched beyond this
     * length.  A higher limit improves compression ratio but degrades the
     * speed.
     */

    uInt max_lazy_match;
    /* Attempt to find a better match only when the current match is strictly
     * smaller than this value. This mechanism is used only for compression
     * levels >= 4.
     */
#   define max_insert_length  max_lazy_match
    /* Insert new strings in the hash table only if the match length is not
     * greater than this length. This saves time but degrades compression.
     * max_insert_length is used only for compression levels <= 3.
     */

    int level;    /* compression level (1..9) */
    int strategy; /* favor or force Huffman coding*/

    uInt good_match;
    /* Use a faster search when the previous match is longer than this */

    int nice_match; /* Stop searching when current match exceeds this */

                /* used by trees.c: */
    /* Didn't use ct_data typedef below to suppress compiler warning */
    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */

    struct tree_desc_s l_desc;               /* desc. for literal tree */
    struct tree_desc_s d_desc;               /* desc. for distance tree */
    struct tree_desc_s bl_desc;              /* desc. for bit length tree */

    ush bl_count[MAX_BITS+1];
    /* number of codes at each bit length for an optimal tree */

    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
    int heap_len;               /* number of elements in the heap */
    int heap_max;               /* element of largest frequency */
    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
     * The same heap array is used to build all trees.
     */

    uch depth[2*L_CODES+1];
    /* Depth of each subtree used as tie breaker for trees of equal frequency
     */

    uchf *sym_buf;        /* buffer for distances and literals/lengths */

    uInt  lit_bufsize;
    /* Size of match buffer for literals/lengths.  There are 4 reasons for
     * limiting lit_bufsize to 64K:
     *   - frequencies can be kept in 16 bit counters
     *   - if compression is not successful for the first block, all input
     *     data is still in the window so we can still emit a stored block even
     *     when input comes from standard input.  (This can also be done for
     *     all blocks if lit_bufsize is not greater than 32K.)
     *   - if compression is not successful for a file smaller than 64K, we can
     *     even emit a stored file instead of a stored block (saving 5 bytes).
     *     This is applicable only for zip (not gzip or zlib).
     *   - creating new Huffman trees less frequently may not provide fast
     *     adaptation to changes in the input data statistics. (Take for
     *     example a binary file with poorly compressible code followed by
     *     a highly compressible string table.) Smaller buffer sizes give
     *     fast adaptation but have of course the overhead of transmitting
     *     trees more frequently.
     *   - I can't count above 4
     */

    uInt sym_next;      /* running index in sym_buf */
    uInt sym_end;       /* symbol table full when sym_next reaches this */

    ulg opt_len;        /* bit length of current block with optimal trees */
    ulg static_len;     /* bit length of current block with static trees */
    uInt matches;       /* number of string matches in current block */
    uInt insert;        /* bytes at end of window left to insert */

#ifdef DEBUG
    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
#endif

    ush bi_buf;
    /* Output buffer. bits are inserted starting at the bottom (least
     * significant bits).
     */
    int bi_valid;
    /* Number of valid bits in bi_buf.  All bits above the last valid bit
     * are always zero.
     */

    ulg high_water;
    /* High water mark offset in window for initialized bytes -- bytes above
     * this are set to zero in order to avoid memory check warnings when
     * longest match routines access bytes past the input.  This is then
     * updated to the new high water mark.
     */

} FAR deflate_state;

/* Output a byte on the stream.
 * IN assertion: there is enough room in pending_buf.
 */
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}


#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
/* Minimum amount of lookahead, except at the end of the input file.
 * See deflate.c for comments about the MIN_MATCH+1.
 */

#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
/* In order to simplify the code, particularly on 16 bit machines, match
 * distances are limited to MAX_DIST instead of WSIZE.
 */

#define WIN_INIT MAX_MATCH
/* Number of bytes after end of data in window to initialize in order to avoid
   memory checker errors from longest match routines */

        /* in trees.c */
void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
                        ulg stored_len, int last));
void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
                        ulg stored_len, int last));

#define d_code(dist) \
   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
/* Mapping from a distance to a distance code. dist is the distance - 1 and
 * must not have side effects. _dist_code[256] and _dist_code[257] are never
 * used.
 */

#ifndef DEBUG
/* Inline versions of _tr_tally for speed: */

#if defined(GEN_TREES_H) || !defined(STDC)
  extern uch ZLIB_INTERNAL _length_code[];
  extern uch ZLIB_INTERNAL _dist_code[];
#else
  extern const uch ZLIB_INTERNAL _length_code[];
  extern const uch ZLIB_INTERNAL _dist_code[];
#endif

# define _tr_tally_lit(s, c, flush) \
  { uch cc = (c); \
    s->sym_buf[s->sym_next++] = 0; \
    s->sym_buf[s->sym_next++] = 0; \
    s->sym_buf[s->sym_next++] = cc; \
    s->dyn_ltree[cc].Freq++; \
    flush = (s->sym_next == s->sym_end); \
   }
# define _tr_tally_dist(s, distance, length, flush) \
  { uch len = (length); \
    ush dist = (distance); \
    s->sym_buf[s->sym_next++] = dist; \
    s->sym_buf[s->sym_next++] = dist >> 8; \
    s->sym_buf[s->sym_next++] = len; \
    dist--; \
    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
    s->dyn_dtree[d_code(dist)].Freq++; \
    flush = (s->sym_next == s->sym_end); \
  }
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
              flush = _tr_tally(s, distance, length)
#endif

#endif /* DEFLATE_H */
rsync-3.2.7/zlib/zutil.h0000664000000000000000000001505712155261705013655 0ustar  rootroot/* zutil.h -- internal interface and configuration of the compression library
 * Copyright (C) 1995-2013 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* WARNING: this file should *not* be used by applications. It is
   part of the implementation of the compression library and is
   subject to change. Applications should only use zlib.h.
 */

/* @(#) $Id$ */

#ifndef ZUTIL_H
#define ZUTIL_H

#define ZLIB_INTERNAL
#include "../rsync.h"
#include "zlib.h"

#if 0
#if defined(STDC) && !defined(Z_SOLO)
#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
#    include 
#  endif
#  include 
#  include 
#endif
#endif

#ifdef Z_SOLO
   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

typedef unsigned char  uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long  ulg;

extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */

#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]

#define ERR_RETURN(strm,err) \
  return (strm->msg = ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */

        /* common constants */

#ifndef DEF_WBITS
#  define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */

#if MAX_MEM_LEVEL >= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif
/* default memLevel */

#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES    2
/* The three kinds of block type */

#define MIN_MATCH  3
#define MAX_MATCH  258
/* The minimum and maximum match lengths */

#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */

        /* target dependencies */

#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
#  define OS_CODE  0x00
#  ifndef Z_SOLO
#    if defined(__TURBOC__) || defined(__BORLANDC__)
#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
         /* Allow compilation with ANSI keywords only enabled */
         void _Cdecl farfree( void *block );
         void *_Cdecl farmalloc( unsigned long nbytes );
#      else
#        include 
#      endif
#    else /* MSC or DJGPP */
#      include 
#    endif
#  endif
#endif

#ifdef AMIGA
#  define OS_CODE  0x01
#endif

#if defined(VAXC) || defined(VMS)
#  define OS_CODE  0x02
#  define F_OPEN(name, mode) \
     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif

#if defined(ATARI) || defined(atarist)
#  define OS_CODE  0x05
#endif

#ifdef OS2
#  define OS_CODE  0x06
#  if defined(M_I86) && !defined(Z_SOLO)
#    include 
#  endif
#endif

#if defined(MACOS) || defined(TARGET_OS_MAC)
#  define OS_CODE  0x07
#  ifndef Z_SOLO
#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
#      include  /* for fdopen */
#    else
#      ifndef fdopen
#        define fdopen(fd,mode) NULL /* No fdopen() */
#      endif
#    endif
#  endif
#endif

#ifdef TOPS20
#  define OS_CODE  0x0a
#endif

#ifdef WIN32
#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
#    define OS_CODE  0x0b
#  endif
#endif

#ifdef __50SERIES /* Prime/PRIMOS */
#  define OS_CODE  0x0f
#endif

#if defined(_BEOS_) || defined(RISCOS)
#  define fdopen(fd,mode) NULL /* No fdopen() */
#endif

#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
#  if defined(_WIN32_WCE)
#    define fdopen(fd,mode) NULL /* No fdopen() */
#    ifndef _PTRDIFF_T_DEFINED
       typedef int ptrdiff_t;
#      define _PTRDIFF_T_DEFINED
#    endif
#  else
#    define fdopen(fd,type)  _fdopen(fd,type)
#  endif
#endif

#if defined(__BORLANDC__) && !defined(MSDOS)
  #pragma warn -8004
  #pragma warn -8008
  #pragma warn -8066
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
#endif

        /* common defaults */

#ifndef OS_CODE
#  define OS_CODE  0x03  /* assume Unix */
#endif

#ifndef F_OPEN
#  define F_OPEN(name, mode) fopen((name), (mode))
#endif

         /* functions */

#if defined(pyr) || defined(Z_SOLO)
#  define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
 /* Use our own functions for small and medium model with MSC <= 5.0.
  * You may have to use the same strategy for Borland C (untested).
  * The __SC__ check is for Symantec.
  */
#  define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
#  define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
#    define zmemcpy _fmemcpy
#    define zmemcmp _fmemcmp
#    define zmemzero(dest, len) _fmemset(dest, 0, len)
#  else
#    define zmemcpy memcpy
#    define zmemcmp memcmp
#    define zmemzero(dest, len) memset(dest, 0, len)
#  endif
#else
   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
#endif

/* Diagnostic functions */
#ifdef DEBUG
#  include 
   extern int ZLIB_INTERNAL z_verbose;
   extern void ZLIB_INTERNAL z_error OF((char *m));
#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
#  define Assert(cond,msg)
#  define Trace(x)
#  define Tracev(x)
#  define Tracevv(x)
#  define Tracec(c,x)
#  define Tracecv(c,x)
#endif

#ifndef Z_SOLO
   voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
                                    unsigned size));
   void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));
#endif

#define ZALLOC(strm, items, size) \
           (*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}

/* Reverse the bytes in a 32-bit value */
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))

#endif /* ZUTIL_H */
rsync-3.2.7/zlib/gzguts.h0000664000000000000000000001463012155261705014025 0ustar  rootroot/* gzguts.h -- zlib internal header definitions for gz* operations
 * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#ifdef _LARGEFILE64_SOURCE
#  ifndef _LARGEFILE_SOURCE
#    define _LARGEFILE_SOURCE 1
#  endif
#  ifdef _FILE_OFFSET_BITS
#    undef _FILE_OFFSET_BITS
#  endif
#endif

#ifdef HAVE_HIDDEN
#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
#  define ZLIB_INTERNAL
#endif

#include 
#include "zlib.h"
#ifdef STDC
#  include 
#  include 
#  include 
#endif
#include 

#ifdef _WIN32
#  include 
#endif

#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
#  include 
#endif

#ifdef WINAPI_FAMILY
#  define open _open
#  define read _read
#  define write _write
#  define close _close
#endif

#ifdef NO_DEFLATE       /* for compatibility with old definition */
#  define NO_GZCOMPRESS
#endif

#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
#  ifndef HAVE_VSNPRINTF
#    define HAVE_VSNPRINTF
#  endif
#endif

#if defined(__CYGWIN__)
#  ifndef HAVE_VSNPRINTF
#    define HAVE_VSNPRINTF
#  endif
#endif

#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
#  ifndef HAVE_VSNPRINTF
#    define HAVE_VSNPRINTF
#  endif
#endif

#ifndef HAVE_VSNPRINTF
#  ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
   but for now we just assume it doesn't. */
#    define NO_vsnprintf
#  endif
#  ifdef __TURBOC__
#    define NO_vsnprintf
#  endif
#  ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
#         define vsnprintf _vsnprintf
#      endif
#    endif
#  endif
#  ifdef __SASC
#    define NO_vsnprintf
#  endif
#  ifdef VMS
#    define NO_vsnprintf
#  endif
#  ifdef __OS400__
#    define NO_vsnprintf
#  endif
#  ifdef __MVS__
#    define NO_vsnprintf
#  endif
#endif

/* unlike snprintf (which is required in C99, yet still not supported by
   Microsoft more than a decade later!), _snprintf does not guarantee null
   termination of the result -- however this is only used in gzlib.c where
   the result is assured to fit in the space provided */
#ifdef _MSC_VER
#  define snprintf _snprintf
#endif

#ifndef local
#  define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */

/* gz* functions always use library allocation functions */
#ifndef STDC
  extern voidp  malloc OF((uInt size));
  extern void   free   OF((voidpf ptr));
#endif

/* get errno and strerror definition */
#if defined UNDER_CE
#  include 
#  define zstrerror() gz_strwinerror((DWORD)GetLastError())
#else
#  ifndef NO_STRERROR
#    include 
#    define zstrerror() strerror(errno)
#  else
#    define zstrerror() "stdio error (consult errno)"
#  endif
#endif

/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
    ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
    ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
    ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
    ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
#endif

/* default memLevel */
#if MAX_MEM_LEVEL >= 8
#  define DEF_MEM_LEVEL 8
#else
#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
#endif

/* default i/o buffer size -- double this for output when reading (this and
   twice this must be able to fit in an unsigned type) */
#define GZBUFSIZE 8192

/* gzip modes, also provide a little integrity check on the passed structure */
#define GZ_NONE 0
#define GZ_READ 7247
#define GZ_WRITE 31153
#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */

/* values for gz_state how */
#define LOOK 0      /* look for a gzip header */
#define COPY 1      /* copy input directly */
#define GZIP 2      /* decompress a gzip stream */

/* internal gzip file state data structure */
typedef struct {
        /* exposed contents for gzgetc() macro */
    struct gzFile_s x;      /* "x" for exposed */
                            /* x.have: number of bytes available at x.next */
                            /* x.next: next output data to deliver or write */
                            /* x.pos: current position in uncompressed data */
        /* used for both reading and writing */
    int mode;               /* see gzip modes above */
    int fd;                 /* file descriptor */
    char *path;             /* path or fd for error messages */
    unsigned size;          /* buffer size, zero if not allocated yet */
    unsigned want;          /* requested buffer size, default is GZBUFSIZE */
    unsigned char *in;      /* input buffer */
    unsigned char *out;     /* output buffer (double-sized when reading) */
    int direct;             /* 0 if processing gzip, 1 if transparent */
        /* just for reading */
    int how;                /* 0: get header, 1: copy, 2: decompress */
    z_off64_t start;        /* where the gzip data started, for rewinding */
    int eof;                /* true if end of input file reached */
    int past;               /* true if read requested past end */
        /* just for writing */
    int level;              /* compression level */
    int strategy;           /* compression strategy */
        /* seek request */
    z_off64_t skip;         /* amount to skip (already rewound if backwards) */
    int seek;               /* true if seek request pending */
        /* error information */
    int err;                /* error code */
    char *msg;              /* error message */
        /* zlib inflate or deflate stream */
    z_stream strm;          /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;

/* shared functions */
void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
#if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
#endif

/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
   value -- needed when comparing unsigned to z_off64_t, which is signed
   (possible z_off64_t types off_t, off64_t, and long are all signed) */
#ifdef INT_MAX
#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
#else
unsigned ZLIB_INTERNAL gz_intmax OF((void));
#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#endif
rsync-3.2.7/.cirrus.yml0000664000000000000000000000147314306717433013506 0ustar  rootrootfreebsd_task:
  name: FreeBSD
  freebsd_instance:
    image_family: freebsd-13-1
  env:
    PATH: /usr/local/bin:$PATH
  prep_script:
    - dd if=/dev/zero of=/tmp/zpool bs=1M count=1024
    - zpool create -m `pwd`/testtmp zpool /tmp/zpool
    - pkg install -y bash autotools m4 xxhash zstd liblz4 wget
    - wget -O git-version.h https://gist.githubusercontent.com/WayneD/c11243fa374fc64d4e42f2855c8e3827/raw/rsync-git-version.h
  configure_script:
    - CPPFLAGS=-I/usr/local/include/ LDFLAGS=-L/usr/local/lib/ ./configure --disable-md2man
  make_script:
    - make
  install_script:
    - make install
  info_script:
    - rsync --version
  test_script:
    - RSYNC_EXPECT_SKIPPED=acls-default,acls,crtimes,protected-regular make check
  ssl_file_list_script:
    - rsync-ssl --no-motd download.samba.org::rsyncftp/ || true
rsync-3.2.7/rsyncd.conf.5.html0000664000000000000000000021471114324367163014657 0ustar  rootroot
rsyncd.conf(5) manpage




NAME

rsyncd.conf -⁠ configuration file for rsync in daemon mode

SYNOPSIS

rsyncd.conf

The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rsyncd.conf.5.

DESCRIPTION

The rsyncd.conf file is the runtime configuration file for rsync when run as an rsync daemon.

The rsyncd.conf file controls authentication, access, logging and available modules.

FILE FORMAT

The file consists of modules and parameters. A module begins with the name of the module in square brackets and continues until the next module begins. Modules contain parameters of the form name = value.

The file is line-based -⁠-⁠ that is, each newline-terminated line represents either a comment, a module name or a parameter.

Only the first equals sign in a parameter is significant. Whitespace before or after the first equals sign is discarded. Leading, trailing and internal whitespace in module and parameter names is irrelevant. Leading and trailing whitespace in a parameter value is discarded. Internal whitespace within a parameter value is retained verbatim.

Any line beginning with a hash (#) is ignored, as are lines containing only whitespace. (If a hash occurs after anything other than leading whitespace, it is considered a part of the line's content.)

Any line ending in a \ is "continued" on the next line in the customary UNIX fashion.

The values following the equals sign in parameters are all either a string (no quotes needed) or a boolean, which may be given as yes/no, 0/1 or true/false. Case is not significant in boolean values, but is preserved in string values.

LAUNCHING THE RSYNC DAEMON

The rsync daemon is launched by specifying the --daemon option to rsync.

The daemon must run with root privileges if you wish to use chroot, to bind to a port numbered under 1024 (as is the default 873), or to set file ownership. Otherwise, it must just have permission to read and write the appropriate data, log, and lock files.

You can launch it either via inetd, as a stand-alone daemon, or from an rsync client via a remote shell. If run as a stand-alone daemon then just run the command "rsync --daemon" from a suitable startup script.

When run via inetd you should add a line like this to /etc/services:

rsync           873/tcp

and a single line something like this to /etc/inetd.conf:

rsync   stream  tcp     nowait  root   /usr/bin/rsync rsyncd --daemon

Replace "/usr/bin/rsync" with the path to where you have rsync installed on your system. You will then need to send inetd a HUP signal to tell it to reread its config file.

Note that you should not send the rsync daemon a HUP signal to force it to reread the rsyncd.conf file. The file is re-read on each client connection.

GLOBAL PARAMETERS

The first parameters in the file (before a [module] header) are the global parameters. Rsync also allows for the use of a "[global]" module name to indicate the start of one or more global-parameter sections (the name must be lower case).

You may also include any module parameters in the global part of the config file in which case the supplied value will override the default for that parameter.

You may use references to environment variables in the values of parameters. String parameters will have %VAR% references expanded as late as possible (when the string is first used in the program), allowing for the use of variables that rsync sets at connection time, such as RSYNC_USER_NAME. Non-string parameters (such as true/false settings) are expanded when read from the config file. If a variable does not exist in the environment, or if a sequence of characters is not a valid reference (such as an un-paired percent sign), the raw characters are passed through unchanged. This helps with backward compatibility and safety (e.g. expanding a non-existent %VAR% to an empty string in a path could result in a very unsafe path). The safest way to insert a literal % into a value is to use %%.

motd file

This parameter allows you to specify a "message of the day" (MOTD) to display to clients on each connect. This usually contains site information and any legal notices. The default is no MOTD file. This can be overridden by the --dparam=motdfile=FILE command-line option when starting the daemon.

pid file

This parameter tells the rsync daemon to write its process ID to that file. The rsync keeps the file locked so that it can know when it is safe to overwrite an existing file.

The filename can be overridden by the --dparam=pidfile=FILE command-line option when starting the daemon.

port

You can override the default port the daemon will listen on by specifying this value (defaults to 873). This is ignored if the daemon is being run by inetd, and is superseded by the --port command-line option.

address

You can override the default IP address the daemon will listen on by specifying this value. This is ignored if the daemon is being run by inetd, and is superseded by the --address command-line option.

socket options

This parameter can provide endless fun for people who like to tune their systems to the utmost degree. You can set all sorts of socket options which may make transfers faster (or slower!). Read the manpage for the setsockopt() system call for details on some of the options you may be able to set. By default no special socket options are set. These settings can also be specified via the --sockopts command-line option.

listen backlog

You can override the default backlog value when the daemon listens for connections. It defaults to 5.

MODULE PARAMETERS

After the global parameters you should define a number of modules, each module exports a directory tree as a symbolic name. Modules are exported by specifying a module name in square brackets [module] followed by the parameters for that module. The module name cannot contain a slash or a closing square bracket. If the name contains whitespace, each internal sequence of whitespace will be changed into a single space, while leading or trailing whitespace will be discarded. Also, the name cannot be "global" as that exact name indicates that global parameters follow (see above).

As with GLOBAL PARAMETERS, you may use references to environment variables in the values of parameters. See the GLOBAL PARAMETERS section for more details.

comment

This parameter specifies a description string that is displayed next to the module name when clients obtain a list of available modules. The default is no comment.

path

This parameter specifies the directory in the daemon's filesystem to make available in this module. You must specify this parameter for each module in rsyncd.conf.

If the value contains a "/./" element then the path will be divided at that point into a chroot dir and an inner-chroot subdir. If use chroot is set to false, though, the extraneous dot dir is just cleaned out of the path. An example of this idiom is:

path = /var/rsync/./module1

This will (when chrooting) chroot to "/var/rsync" and set the inside-chroot path to "/module1".

You may base the path's value off of an environment variable by surrounding the variable name with percent signs. You can even reference a variable that is set by rsync when the user connects. For example, this would use the authorizing user's name in the path:

path = /home/%RSYNC_USER_NAME%

It is fine if the path includes internal spaces -⁠-⁠ they will be retained verbatim (which means that you shouldn't try to escape them). If your final directory has a trailing space (and this is somehow not something you wish to fix), append a trailing slash to the path to avoid losing the trailing whitespace.

use chroot

If "use chroot" is true, the rsync daemon will chroot to the "path" before starting the file transfer with the client. This has the advantage of extra protection against possible implementation security holes, but it has the disadvantages of requiring super-user privileges, of not being able to follow symbolic links that are either absolute or outside of the new root path, and of complicating the preservation of users and groups by name (see below).

If use chroot is not set, it defaults to trying to enable a chroot but allows the daemon to continue (after logging a warning) if it fails. The one exception to this is when a module's path has a "/./" chroot divider in it -⁠-⁠ this causes an unset value to be treated as true for that module.

Prior to rsync 3.2.7, the default value was "true". The new "unset" default makes it easier to setup an rsync daemon as a non-root user or to run a daemon on a system where chroot fails. Explicitly setting the value to "true" in rsyncd.conf will always require the chroot to succeed.

It is also possible to specify a dot-dir in the module's "path" to indicate that you want to chdir to the earlier part of the path and then serve files from inside the latter part of the path (with sanitizing and default symlink munging). This can be useful if you need some library dirs inside the chroot (typically for uid & gid lookups) but don't want to put the lib dir into the top of the served path (even though they can be hidden with an exclude directive). However, a better choice for a modern rsync setup is to use a name converter" and try to avoid inner lib dirs altogether. See also the daemon chroot parameter, which causes rsync to chroot into its own chroot area before doing any path-related chrooting.

If the daemon is serving the "/" dir (either directly or due to being chrooted to the module's path), rsync does not do any path sanitizing or (default) munging.

When it has to limit access to a particular subdir (either due to chroot being disabled or having an inside-chroot path set), rsync will munge symlinks (by default) and sanitize paths. Those that dislike munged symlinks (and really, really trust their users to not break out of the subdir) can disable the symlink munging via the "munge symlinks" parameter.

When rsync is sanitizing paths, it trims ".." path elements from args that it believes would escape the module hierarchy. It also substitutes leading slashes in absolute paths with the module's path (so that options such as --backup-dir & --compare-dest interpret an absolute path as rooted in the module's "path" dir).

When a chroot is in effect and the "name converter" parameter is not set, the "numeric ids" parameter will default to being enabled (disabling name lookups). This means that if you manually setup name-lookup libraries in your chroot (instead of using a name converter) that you need to explicitly set numeric ids = false for rsync to do name lookups.

If you copy library resources into the module's chroot area, you should protect them through your OS's normal user/group or ACL settings (to prevent the rsync module's user from being able to change them), and then hide them from the user's view via "exclude" (see how in the discussion of that parameter). However, it's easier and safer to setup a name converter.

daemon chroot

This parameter specifies a path to which the daemon will chroot before beginning communication with clients. Module paths (and any "use chroot" settings) will then be related to this one. This lets you choose if you want the whole daemon to be chrooted (with this setting), just the transfers to be chrooted (with "use chroot"), or both. Keep in mind that the "daemon chroot" area may need various OS/lib/etc files installed to allow the daemon to function. By default the daemon runs without any chrooting.

proxy protocol

When this parameter is enabled, all incoming connections must start with a V1 or V2 proxy protocol header. If the header is not found, the connection is closed.

Setting this to true requires a proxy server to forward source IP information to rsync, allowing you to log proper IP/host info and make use of client-oriented IP restrictions. The default of false means that the IP information comes directly from the socket's metadata. If rsync is not behind a proxy, this should be disabled.

CAUTION: using this option can be dangerous if you do not ensure that only the proxy is allowed to connect to the rsync port. If any non-proxied connections are allowed through, the client will be able to use a modified rsync to spoof any remote IP address that they desire. You can lock this down using something like iptables -uid-owner root rules (for strict localhost access), various firewall rules, or you can require password authorization so that any spoofing by users will not grant extra access.

This setting is global. If you need some modules to require this and not others, then you will need to setup multiple rsync daemon processes on different ports.

name converter

This parameter lets you specify a program that will be run by the rsync daemon to do user & group conversions between names & ids. This script is started prior to any chroot being setup, and runs as the daemon user (not the transfer user). You can specify a fully qualified pathname or a program name that is on the $PATH.

The program can be used to do normal user & group lookups without having to put any extra files into the chroot area of the module or you can do customized conversions.

The nameconvert program has access to all of the environment variables that are described in the section on pre-xfer exec. This is useful if you want to customize the conversion using information about the module and/or the copy request.

There is a sample python script in the support dir named "nameconvert" that implements the normal user & group lookups. Feel free to customize it or just use it as documentation to implement your own.

numeric ids

Enabling this parameter disables the mapping of users and groups by name for the current daemon module. This prevents the daemon from trying to load any user/group-related files or libraries. This enabling makes the transfer behave as if the client had passed the --numeric-ids command-line option. By default, this parameter is enabled for chroot modules and disabled for non-chroot modules. Also keep in mind that uid/gid preservation requires the module to be running as root (see "uid") or for "fake super" to be configured.

A chroot-enabled module should not have this parameter set to false unless you're using a "name converter" program or you've taken steps to ensure that the module has the necessary resources it needs to translate names and that it is not possible for a user to change those resources.

This parameter tells rsync to modify all symlinks in the same way as the (non-daemon-affecting) --munge-links command-line option (using a method described below). This should help protect your files from user trickery when your daemon module is writable. The default is disabled when "use chroot" is on with an inside-chroot path of "/", OR if "daemon chroot" is on, otherwise it is enabled.

If you disable this parameter on a daemon that is not read-only, there are tricks that a user can play with uploaded symlinks to access daemon-excluded items (if your module has any), and, if "use chroot" is off, rsync can even be tricked into showing or changing data that is outside the module's path (as access-permissions allow).

The way rsync disables the use of symlinks is to prefix each one with the string "/rsyncd-munged/". This prevents the links from being used as long as that directory does not exist. When this parameter is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory. When using the "munge symlinks" parameter in a chroot area that has an inside-chroot path of "/", you should add "/rsyncd-munged/" to the exclude setting for the module so that a user can't try to create it.

Note: rsync makes no attempt to verify that any pre-existing symlinks in the module's hierarchy are as safe as you want them to be (unless, of course, it just copied in the whole hierarchy). If you setup an rsync daemon on a new area or locally add symlinks, you can manually protect your symlinks from being abused by prefixing "/rsyncd-munged/" to the start of every symlink's value. There is a perl script in the support directory of the source code named "munge-symlinks" that can be used to add or remove this prefix from your symlinks.

When this parameter is disabled on a writable module and "use chroot" is off (or the inside-chroot path is not "/"), incoming symlinks will be modified to drop a leading slash and to remove ".." path elements that rsync believes will allow a symlink to escape the module's hierarchy. There are tricky ways to work around this, though, so you had better trust your users if you choose this combination of parameters.

charset

This specifies the name of the character set in which the module's filenames are stored. If the client uses an --iconv option, the daemon will use the value of the "charset" parameter regardless of the character set the client actually passed. This allows the daemon to support charset conversion in a chroot module without extra files in the chroot area, and also ensures that name-translation is done in a consistent manner. If the "charset" parameter is not set, the --iconv option is refused, just as if "iconv" had been specified via "refuse options".

If you wish to force users to always use --iconv for a particular module, add "no-iconv" to the "refuse options" parameter. Keep in mind that this will restrict access to your module to very new rsync clients.

max connections

This parameter allows you to specify the maximum number of simultaneous connections you will allow. Any clients connecting when the maximum has been reached will receive a message telling them to try later. The default is 0, which means no limit. A negative value disables the module. See also the "lock file" parameter.

log file

When the "log file" parameter is set to a non-empty string, the rsync daemon will log messages to the indicated file rather than using syslog. This is particularly useful on systems (such as AIX) where syslog() doesn't work for chrooted programs. The file is opened before chroot() is called, allowing it to be placed outside the transfer. If this value is set on a per-module basis instead of globally, the global log will still contain any authorization failures or config-file error messages.

If the daemon fails to open the specified file, it will fall back to using syslog and output an error about the failure. (Note that the failure to open the specified log file used to be a fatal error.)

This setting can be overridden by using the --log-file=FILE or --dparam=logfile=FILE command-line options. The former overrides all the log-file parameters of the daemon and all module settings. The latter sets the daemon's log file and the default for all the modules, which still allows modules to override the default setting.

syslog facility

This parameter allows you to specify the syslog facility name to use when logging messages from the rsync daemon. You may use any standard syslog facility name which is defined on your system. Common names are auth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, syslog, user, uucp, local0, local1, local2, local3, local4, local5, local6 and local7. The default is daemon. This setting has no effect if the "log file" setting is a non-empty string (either set in the per-modules settings, or inherited from the global settings).

syslog tag

This parameter allows you to specify the syslog tag to use when logging messages from the rsync daemon. The default is "rsyncd". This setting has no effect if the "log file" setting is a non-empty string (either set in the per-modules settings, or inherited from the global settings).

For example, if you wanted each authenticated user's name to be included in the syslog tag, you could do something like this:

syslog tag = rsyncd.%RSYNC_USER_NAME%
max verbosity

This parameter allows you to control the maximum amount of verbose information that you'll allow the daemon to generate (since the information goes into the log file). The default is 1, which allows the client to request one level of verbosity.

This also affects the user's ability to request higher levels of --info and --debug logging. If the max value is 2, then no info and/or debug value that is higher than what would be set by -vv will be honored by the daemon in its logging. To see how high of a verbosity level you need to accept for a particular info/debug level, refer to rsync --info=help and rsync --debug=help. For instance, it takes max-verbosity 4 to be able to output debug TIME2 and FLIST3.

lock file

This parameter specifies the file to use to support the "max connections" parameter. The rsync daemon uses record locking on this file to ensure that the max connections limit is not exceeded for the modules sharing the lock file. The default is /var/run/rsyncd.lock.

read only

This parameter determines whether clients will be able to upload files or not. If "read only" is true then any attempted uploads will fail. If "read only" is false then uploads will be possible if file permissions on the daemon side allow them. The default is for all modules to be read only.

Note that "auth users" can override this setting on a per-user basis.

write only

This parameter determines whether clients will be able to download files or not. If "write only" is true then any attempted downloads will fail. If "write only" is false then downloads will be possible if file permissions on the daemon side allow them. The default is for this parameter to be disabled.

Helpful hint: you probably want to specify "refuse options = delete" for a write-only module.

open noatime

When set to True, this parameter tells the rsync daemon to open files with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred. If your OS does not support the O_NOATIME flag then rsync will silently ignore this option. Note also that some filesystems are mounted to avoid updating the atime on read access even without the O_NOATIME flag being set.

When set to False, this parameters ensures that files on the server are not opened with O_NOATIME.

When set to Unset (the default) the user controls the setting via --open-noatime.

list

This parameter determines whether this module is listed when the client asks for a listing of available modules. In addition, if this is false, the daemon will pretend the module does not exist when a client denied by "hosts allow" or "hosts deny" attempts to access it. Realize that if "reverse lookup" is disabled globally but enabled for the module, the resulting reverse lookup to a potentially client-controlled DNS server may still reveal to the client that it hit an existing module. The default is for modules to be listable.

uid

This parameter specifies the user name or user ID that file transfers to and from that module should take place as when the daemon was run as root. In combination with the "gid" parameter this determines what file permissions are available. The default when run by a super-user is to switch to the system's "nobody" user. The default for a non-super-user is to not try to change the user. See also the "gid" parameter.

The RSYNC_USER_NAME environment variable may be used to request that rsync run as the authorizing user. For example, if you want a rsync to run as the same user that was received for the rsync authentication, this setup is useful:

uid = %RSYNC_USER_NAME%
gid = *
gid

This parameter specifies one or more group names/IDs that will be used when accessing the module. The first one will be the default group, and any extra ones be set as supplemental groups. You may also specify a "*" as the first gid in the list, which will be replaced by all the normal groups for the transfer's user (see "uid"). The default when run by a super-user is to switch to your OS's "nobody" (or perhaps "nogroup") group with no other supplementary groups. The default for a non-super-user is to not change any group attributes (and indeed, your OS may not allow a non-super-user to try to change their group settings).

The specified list is normally split into tokens based on spaces and commas. However, if the list starts with a comma, then the list is only split on commas, which allows a group name to contain a space. In either case any leading and/or trailing whitespace is removed from the tokens and empty tokens are ignored.

daemon uid

This parameter specifies a uid under which the daemon will run. The daemon usually runs as user root, and when this is left unset the user is left unchanged. See also the "uid" parameter.

daemon gid

This parameter specifies a gid under which the daemon will run. The daemon usually runs as group root, and when this is left unset, the group is left unchanged. See also the "gid" parameter.

fake super

Setting "fake super = yes" for a module causes the daemon side to behave as if the --fake-super command-line option had been specified. This allows the full attributes of a file to be stored without having to have the daemon actually running as root.

filter

The daemon has its own filter chain that determines what files it will let the client access. This chain is not sent to the client and is independent of any filters the client may have specified. Files excluded by the daemon filter chain (daemon-excluded files) are treated as non-existent if the client tries to pull them, are skipped with an error message if the client tries to push them (triggering exit code 23), and are never deleted from the module. You can use daemon filters to prevent clients from downloading or tampering with private administrative files, such as files you may add to support uid/gid name translations.

The daemon filter chain is built from the "filter", "include from", "include", "exclude from", and "exclude" parameters, in that order of priority. Anchored patterns are anchored at the root of the module. To prevent access to an entire subtree, for example, "/secret", you must exclude everything in the subtree; the easiest way to do this is with a triple-star pattern like "/secret/***".

The "filter" parameter takes a space-separated list of daemon filter rules, though it is smart enough to know not to split a token at an internal space in a rule (e.g. "- /foo - /bar" is parsed as two rules). You may specify one or more merge-file rules using the normal syntax. Only one "filter" parameter can apply to a given module in the config file, so put all the rules you want in a single parameter. Note that per-directory merge-file rules do not provide as much protection as global rules, but they can be used to make --delete work better during a client download operation if the per-dir merge files are included in the transfer and the client requests that they be used.

exclude

This parameter takes a space-separated list of daemon exclude patterns. As with the client --exclude option, patterns can be qualified with "- " or "+ " to explicitly indicate exclude/include. Only one "exclude" parameter can apply to a given module. See the "filter" parameter for a description of how excluded files affect the daemon.

include

Use an "include" to override the effects of the "exclude" parameter. Only one "include" parameter can apply to a given module. See the "filter" parameter for a description of how excluded files affect the daemon.

exclude from

This parameter specifies the name of a file on the daemon that contains daemon exclude patterns, one per line. Only one "exclude from" parameter can apply to a given module; if you have multiple exclude-from files, you can specify them as a merge file in the "filter" parameter. See the "filter" parameter for a description of how excluded files affect the daemon.

include from

Analogue of "exclude from" for a file of daemon include patterns. Only one "include from" parameter can apply to a given module. See the "filter" parameter for a description of how excluded files affect the daemon.

incoming chmod

This parameter allows you to specify a set of comma-separated chmod strings that will affect the permissions of all incoming files (files that are being received by the daemon). These changes happen after all other permission calculations, and this will even override destination-default and/or existing permissions when the client does not specify --perms. See the description of the --chmod rsync option and the chmod(1) manpage for information on the format of this string.

outgoing chmod

This parameter allows you to specify a set of comma-separated chmod strings that will affect the permissions of all outgoing files (files that are being sent out from the daemon). These changes happen first, making the sent permissions appear to be different than those stored in the filesystem itself. For instance, you could disable group write permissions on the server while having it appear to be on to the clients. See the description of the --chmod rsync option and the chmod(1) manpage for information on the format of this string.

auth users

This parameter specifies a comma and/or space-separated list of authorization rules. In its simplest form, you list the usernames that will be allowed to connect to this module. The usernames do not need to exist on the local system. The rules may contain shell wildcard characters that will be matched against the username provided by the client for authentication. If "auth users" is set then the client will be challenged to supply a username and password to connect to the module. A challenge response authentication protocol is used for this exchange. The plain text usernames and passwords are stored in the file specified by the "secrets file" parameter. The default is for all users to be able to connect without a password (this is called "anonymous rsync").

In addition to username matching, you can specify groupname matching via a '@' prefix. When using groupname matching, the authenticating username must be a real user on the system, or it will be assumed to be a member of no groups. For example, specifying "@rsync" will match the authenticating user if the named user is a member of the rsync group.

Finally, options may be specified after a colon (:). The options allow you to "deny" a user or a group, set the access to "ro" (read-only), or set the access to "rw" (read/write). Setting an auth-rule-specific ro/rw setting overrides the module's "read only" setting.

Be sure to put the rules in the order you want them to be matched, because the checking stops at the first matching user or group, and that is the only auth that is checked. For example:

auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam

In the above rule, user joe will be denied access no matter what. Any user that is in the group "guest" is also denied access. The user "admin" gets access in read/write mode, but only if the admin user is not in group "guest" (because the admin user-matching rule would never be reached if the user is in group "guest"). Any other user who is in group "rsync" will get read-only access. Finally, users susan, joe, and sam get the ro/rw setting of the module, but only if the user didn't match an earlier group-matching rule.

If you need to specify a user or group name with a space in it, start your list with a comma to indicate that the list should only be split on commas (though leading and trailing whitespace will also be removed, and empty entries are just ignored). For example:

auth users = , joe:deny, @Some Group:deny, admin:rw, @RO Group:ro

See the description of the secrets file for how you can have per-user passwords as well as per-group passwords. It also explains how a user can authenticate using their user password or (when applicable) a group password, depending on what rule is being authenticated.

See also the section entitled "USING RSYNC-DAEMON FEATURES VIA A REMOTE SHELL CONNECTION" in rsync(1) for information on how handle an rsyncd.conf-level username that differs from the remote-shell-level username when using a remote shell to connect to an rsync daemon.

secrets file

This parameter specifies the name of a file that contains the username:password and/or @groupname:password pairs used for authenticating this module. This file is only consulted if the "auth users" parameter is specified. The file is line-based and contains one name:password pair per line. Any line has a hash (#) as the very first character on the line is considered a comment and is skipped. The passwords can contain any characters but be warned that many operating systems limit the length of passwords that can be typed at the client end, so you may find that passwords longer than 8 characters don't work.

The use of group-specific lines are only relevant when the module is being authorized using a matching "@groupname" rule. When that happens, the user can be authorized via either their "username:password" line or the "@groupname:password" line for the group that triggered the authentication.

It is up to you what kind of password entries you want to include, either users, groups, or both. The use of group rules in "auth users" does not require that you specify a group password if you do not want to use shared passwords.

There is no default for the "secrets file" parameter, you must choose a name (such as /etc/rsyncd.secrets). The file must normally not be readable by "other"; see "strict modes". If the file is not found or is rejected, no logins for an "auth users" module will be possible.

strict modes

This parameter determines whether or not the permissions on the secrets file will be checked. If "strict modes" is true, then the secrets file must not be readable by any user ID other than the one that the rsync daemon is running under. If "strict modes" is false, the check is not performed. The default is true. This parameter was added to accommodate rsync running on the Windows operating system.

hosts allow

This parameter allows you to specify a list of comma- and/or whitespace-separated patterns that are matched against a connecting client's hostname and IP address. If none of the patterns match, then the connection is rejected.

Each pattern can be in one of six forms:

  • a dotted decimal IPv4 address of the form a.b.c.d, or an IPv6 address of the form a:b:c::d:e:f. In this case the incoming machine's IP address must match exactly.
  • an address/mask in the form ipaddr/n where ipaddr is the IP address and n is the number of one bits in the netmask. All IP addresses which match the masked IP address will be allowed in.
  • an address/mask in the form ipaddr/maskaddr where ipaddr is the IP address and maskaddr is the netmask in dotted decimal notation for IPv4, or similar for IPv6, e.g. ffff:ffff:ffff:ffff:: instead of /64. All IP addresses which match the masked IP address will be allowed in.
  • a hostname pattern using wildcards. If the hostname of the connecting IP (as determined by a reverse lookup) matches the wildcarded name (using the same rules as normal Unix filename matching), the client is allowed in. This only works if "reverse lookup" is enabled (the default).
  • a hostname. A plain hostname is matched against the reverse DNS of the connecting IP (if "reverse lookup" is enabled), and/or the IP of the given hostname is matched against the connecting IP (if "forward lookup" is enabled, as it is by default). Any match will be allowed in.
  • an '@' followed by a netgroup name, which will match if the reverse DNS of the connecting IP is in the specified netgroup.

Note IPv6 link-local addresses can have a scope in the address specification:

fe80::1%link1
fe80::%link1/64
fe80::%link1/ffff:ffff:ffff:ffff::

You can also combine "hosts allow" with "hosts deny" as a way to add exceptions to your deny list. When both parameters are specified, the "hosts allow" parameter is checked first and a match results in the client being able to connect. A non-allowed host is then matched against the "hosts deny" list to see if it should be rejected. A host that does not match either list is allowed to connect.

The default is no "hosts allow" parameter, which means all hosts can connect.

hosts deny

This parameter allows you to specify a list of comma- and/or whitespace-separated patterns that are matched against a connecting clients hostname and IP address. If the pattern matches then the connection is rejected. See the "hosts allow" parameter for more information.

The default is no "hosts deny" parameter, which means all hosts can connect.

reverse lookup

Controls whether the daemon performs a reverse lookup on the client's IP address to determine its hostname, which is used for "hosts allow" & "hosts deny" checks and the "%h" log escape. This is enabled by default, but you may wish to disable it to save time if you know the lookup will not return a useful result, in which case the daemon will use the name "UNDETERMINED" instead.

If this parameter is enabled globally (even by default), rsync performs the lookup as soon as a client connects, so disabling it for a module will not avoid the lookup. Thus, you probably want to disable it globally and then enable it for modules that need the information.

forward lookup

Controls whether the daemon performs a forward lookup on any hostname specified in an hosts allow/deny setting. By default this is enabled, allowing the use of an explicit hostname that would not be returned by reverse DNS of the connecting IP.

ignore errors

This parameter tells rsyncd to ignore I/O errors on the daemon when deciding whether to run the delete phase of the transfer. Normally rsync skips the --delete step if any I/O errors have occurred in order to prevent disastrous deletion due to a temporary resource shortage or other I/O error. In some cases this test is counter productive so you can use this parameter to turn off this behavior.

ignore nonreadable

This tells the rsync daemon to completely ignore files that are not readable by the user. This is useful for public archives that may have some non-readable files among the directories, and the sysadmin doesn't want those files to be seen at all.

transfer logging

This parameter enables per-file logging of downloads and uploads in a format somewhat similar to that used by ftp daemons. The daemon always logs the transfer at the end, so if a transfer is aborted, no mention will be made in the log file.

If you want to customize the log lines, see the "log format" parameter.

log format

This parameter allows you to specify the format used for logging file transfers when transfer logging is enabled. The format is a text string containing embedded single-character escape sequences prefixed with a percent (%) character. An optional numeric field width may also be specified between the percent and the escape letter (e.g. "%-50n %8l %07p"). In addition, one or more apostrophes may be specified prior to a numerical escape to indicate that the numerical value should be made more human-readable. The 3 supported levels are the same as for the --human-readable command-line option, though the default is for human-readability to be off. Each added apostrophe increases the level (e.g. "%''l %'b %f").

The default log format is "%o %h [%a] %m (%u) %f %l", and a "%t [%p] " is always prefixed when using the "log file" parameter. (A perl script that will summarize this default log format is included in the rsync source code distribution in the "support" subdirectory: rsyncstats.)

The single-character escapes that are understood are as follows:

  • %a the remote IP address (only available for a daemon)
  • %b the number of bytes actually transferred
  • %B the permission bits of the file (e.g. rwxrwxrwt)
  • %c the total size of the block checksums received for the basis file (only when sending)
  • %C the full-file checksum if it is known for the file. For older rsync protocols/versions, the checksum was salted, and is thus not a useful value (and is not displayed when that is the case). For the checksum to output for a file, either the --checksum option must be in-effect or the file must have been transferred without a salted checksum being used. See the --checksum-choice option for a way to choose the algorithm.
  • %f the filename (long form on sender; no trailing "/")
  • %G the gid of the file (decimal) or "DEFAULT"
  • %h the remote host name (only available for a daemon)
  • %i an itemized list of what is being updated
  • %l the length of the file in bytes
  • %L the string " -> SYMLINK", " => HARDLINK", or "" (where SYMLINK or HARDLINK is a filename)
  • %m the module name
  • %M the last-modified time of the file
  • %n the filename (short form; trailing "/" on dir)
  • %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period)
  • %p the process ID of this rsync session
  • %P the module path
  • %t the current date time
  • %u the authenticated username or an empty string
  • %U the uid of the file (decimal)

For a list of what the characters mean that are output by "%i", see the --itemize-changes option in the rsync manpage.

Note that some of the logged output changes when talking with older rsync versions. For instance, deleted files were only output as verbose messages prior to rsync 2.6.4.

timeout

This parameter allows you to override the clients choice for I/O timeout for this module. Using this parameter you can ensure that rsync won't wait on a dead client forever. The timeout is specified in seconds. A value of zero means no timeout and is the default. A good choice for anonymous rsync daemons may be 600 (giving a 10 minute timeout).

refuse options

This parameter allows you to specify a space-separated list of rsync command-line options that will be refused by your rsync daemon. You may specify the full option name, its one-letter abbreviation, or a wild-card string that matches multiple options. Beginning in 3.2.0, you can also negate a match term by starting it with a "!".

When an option is refused, the daemon prints an error message and exits.

For example, this would refuse --checksum (-c) and all the various delete options:

refuse options = c delete

The reason the above refuses all delete options is that the options imply --delete, and implied options are refused just like explicit options.

The use of a negated match allows you to fine-tune your refusals after a wild-card, such as this:

refuse options = delete-* !delete-during

Negated matching can also turn your list of refused options into a list of accepted options. To do this, begin the list with a "*" (to refuse all options) and then specify one or more negated matches to accept. For example:

refuse options = * !a !v !compress*

Don't worry that the "*" will refuse certain vital options such as --dry-run, --server, --no-iconv, --seclude-args, etc. These important options are not matched by wild-card, so they must be overridden by their exact name. For instance, if you're forcing iconv transfers you could use something like this:

refuse options = * no-iconv !a !v

As an additional aid (beginning in 3.2.0), refusing (or "!refusing") the "a" or "archive" option also affects all the options that the --archive option implies (-rdlptgoD), but only if the option is matched explicitly (not using a wildcard). If you want to do something tricky, you can use "archive*" to avoid this side-effect, but keep in mind that no normal rsync client ever sends the actual archive option to the server.

As an additional safety feature, the refusal of "delete" also refuses remove-source-files when the daemon is the sender; if you want the latter without the former, instead refuse "delete-*" as that refuses all the delete modes without affecting --remove-source-files. (Keep in mind that the client's --delete option typically results in --delete-during.)

When un-refusing delete options, you should either specify "!delete*" (to accept all delete options) or specify a limited set that includes "delete", such as:

refuse options = * !a !delete !delete-during

... whereas this accepts any delete option except --delete-after:

refuse options = * !a !delete* delete-after

A note on refusing "compress": it may be better to set the "dont compress" daemon parameter to "*" and ensure that RSYNC_COMPRESS_LIST=zlib is set in the environment of the daemon in order to disable compression silently instead of returning an error that forces the client to remove the -z option.

If you are un-refusing the compress option, you may want to match "!compress*" if you also want to allow the --compress-level option.

Note that the "copy-devices" & "write-devices" options are refused by default, but they can be explicitly accepted with "!copy-devices" and/or "!write-devices". The options "log-file" and "log-file-format" are forcibly refused and cannot be accepted.

Here are all the options that are not matched by wild-cards:

  • --server: Required for rsync to even work.
  • --rsh, -e: Required to convey compatibility flags to the server.
  • --out-format: This is required to convey output behavior to a remote receiver. While rsync passes the older alias --log-format for compatibility reasons, this options should not be confused with --log-file-format.
  • --sender: Use "write only" parameter instead of refusing this.
  • --dry-run, -n: Who would want to disable this?
  • --seclude-args, -s: Is the oldest arg-protection method.
  • --from0, -0: Makes it easier to accept/refuse --files-from without affecting this helpful modifier.
  • --iconv: This is auto-disabled based on "charset" parameter.
  • --no-iconv: Most transfers use this option.
  • --checksum-seed: Is a fairly rare, safe option.
  • --write-devices: Is non-wild but also auto-disabled.
dont compress

NOTE: This parameter currently has no effect except in one instance: if it is set to "*" then it minimizes or disables compression for all files (for those that don't want to refuse the --compress option completely).

This parameter allows you to select filenames based on wildcard patterns that should not be compressed when pulling files from the daemon (no analogous parameter exists to govern the pushing of files to a daemon). Compression can be expensive in terms of CPU usage, so it is usually good to not try to compress files that won't compress well, such as already compressed files.

The "dont compress" parameter takes a space-separated list of case-insensitive wildcard patterns. Any source filename matching one of the patterns will be compressed as little as possible during the transfer. If the compression algorithm has an "off" level, then no compression occurs for those files. If an algorithms has the ability to change the level in mid-stream, it will be minimized to reduce the CPU usage as much as possible.

See the --skip-compress parameter in the rsync(1) manpage for the list of file suffixes that are skipped by default if this parameter is not set.

early exec, pre-xfer exec, post-xfer exec

You may specify a command to be run in the early stages of the connection, or right before and/or after the transfer. If the early exec or pre-xfer exec command returns an error code, the transfer is aborted before it begins. Any output from the pre-xfer exec command on stdout (up to several KB) will be displayed to the user when aborting, but is not displayed if the script returns success. The other programs cannot send any text to the user. All output except for the pre-xfer exec stdout goes to the corresponding daemon's stdout/stderr, which is typically discarded. See the --no-detatch option for a way to see the daemon's output, which can assist with debugging.

Note that the early exec command runs before any part of the transfer request is known except for the module name. This helper script can be used to setup a disk mount or decrypt some data into a module dir, but you may need to use lock file and max connections to avoid concurrency issues. If the client rsync specified the --early-input=FILE option, it can send up to about 5K of data to the stdin of the early script. The stdin will otherwise be empty.

Note that the post-xfer exec command is still run even if one of the other scripts returns an error code. The pre-xfer exec command will not be run, however, if the early exec command fails.

The following environment variables will be set, though some are specific to the pre-xfer or the post-xfer environment:

  • RSYNC_MODULE_NAME: The name of the module being accessed.
  • RSYNC_MODULE_PATH: The path configured for the module.
  • RSYNC_HOST_ADDR: The accessing host's IP address.
  • RSYNC_HOST_NAME: The accessing host's name.
  • RSYNC_USER_NAME: The accessing user's name (empty if no user).
  • RSYNC_PID: A unique number for this transfer.
  • RSYNC_REQUEST: (pre-xfer only) The module/path info specified by the user. Note that the user can specify multiple source files, so the request can be something like "mod/path1 mod/path2", etc.
  • RSYNC_ARG#: (pre-xfer only) The pre-request arguments are set in these numbered values. RSYNC_ARG0 is always "rsyncd", followed by the options that were used in RSYNC_ARG1, and so on. There will be a value of "." indicating that the options are done and the path args are beginning -⁠-⁠ these contain similar information to RSYNC_REQUEST, but with values separated and the module name stripped off.
  • RSYNC_EXIT_STATUS: (post-xfer only) the server side's exit value. This will be 0 for a successful run, a positive value for an error that the server generated, or a -⁠1 if rsync failed to exit properly. Note that an error that occurs on the client side does not currently get sent to the server side, so this is not the final exit status for the whole transfer.
  • RSYNC_RAW_STATUS: (post-xfer only) the raw exit value from waitpid().

Even though the commands can be associated with a particular module, they are run using the permissions of the user that started the daemon (not the module's uid/gid setting) without any chroot restrictions.

These settings honor 2 environment variables: use RSYNC_SHELL to set a shell to use when running the command (which otherwise uses your system() call's default shell), and use RSYNC_NO_XFER_EXEC to disable both options completely.

CONFIG DIRECTIVES

There are currently two config directives available that allow a config file to incorporate the contents of other files: &include and &merge. Both allow a reference to either a file or a directory. They differ in how segregated the file's contents are considered to be.

The &include directive treats each file as more distinct, with each one inheriting the defaults of the parent file, starting the parameter parsing as globals/defaults, and leaving the defaults unchanged for the parsing of the rest of the parent file.

The &merge directive, on the other hand, treats the file's contents as if it were simply inserted in place of the directive, and thus it can set parameters in a module started in another file, can affect the defaults for other files, etc.

When an &include or &merge directive refers to a directory, it will read in all the *.conf or *.inc files (respectively) that are contained inside that directory (without any recursive scanning), with the files sorted into alpha order. So, if you have a directory named "rsyncd.d" with the files "foo.conf", "bar.conf", and "baz.conf" inside it, this directive:

&include /path/rsyncd.d

would be the same as this set of directives:

&include /path/rsyncd.d/bar.conf
&include /path/rsyncd.d/baz.conf
&include /path/rsyncd.d/foo.conf

except that it adjusts as files are added and removed from the directory.

The advantage of the &include directive is that you can define one or more modules in a separate file without worrying about unintended side-effects between the self-contained module files.

The advantage of the &merge directive is that you can load config snippets that can be included into multiple module definitions, and you can also set global values that will affect connections (such as motd file), or globals that will affect other include files.

For example, this is a useful /etc/rsyncd.conf file:

port = 873
log file = /var/log/rsync.log
pid file = /var/lock/rsync.lock

&merge /etc/rsyncd.d
&include /etc/rsyncd.d

This would merge any /etc/rsyncd.d/*.inc files (for global values that should stay in effect), and then include any /etc/rsyncd.d/*.conf files (defining modules without any global-value cross-talk).

AUTHENTICATION STRENGTH

The authentication protocol used in rsync is a 128 bit MD4 based challenge response system. This is fairly weak protection, though (with at least one brute-force hash-finding algorithm publicly available), so if you want really top-quality security, then I recommend that you run rsync over ssh. (Yes, a future version of rsync will switch over to a stronger hashing method.)

Also note that the rsync daemon protocol does not currently provide any encryption of the data that is transferred over the connection. Only authentication is provided. Use ssh as the transport if you want encryption.

You can also make use of SSL/TLS encryption if you put rsync behind an SSL proxy.

SSL/TLS Daemon Setup

When setting up an rsync daemon for access via SSL/TLS, you will need to configure a TCP proxy (such as haproxy or nginx) as the front-end that handles the encryption.

  • You should limit the access to the backend-rsyncd port to only allow the proxy to connect. If it is on the same host as the proxy, then configuring it to only listen on localhost is a good idea.
  • You should consider turning on the proxy protocol rsync-daemon parameter if your proxy supports sending that information. The examples below assume that this is enabled.

An example haproxy setup is as follows:

frontend fe_rsync-ssl
   bind :::874 ssl crt /etc/letsencrypt/example.com/combined.pem
   mode tcp
   use_backend be_rsync

backend be_rsync
   mode tcp
   server local-rsync 127.0.0.1:873 check send-proxy

An example nginx proxy setup is as follows:

stream {
   server {
       listen 874 ssl;
       listen [::]:874 ssl;

       ssl_certificate /etc/letsencrypt/example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/example.com/privkey.pem;

       proxy_pass localhost:873;
       proxy_protocol on; # Requires rsyncd.conf "proxy protocol = true"
       proxy_timeout 1m;
       proxy_connect_timeout 5s;
   }
}

DAEMON CONFIG EXAMPLES

A simple rsyncd.conf file that allow anonymous rsync to a ftp area at /home/ftp would be:

[ftp]
        path = /home/ftp
        comment = ftp export area

A more sophisticated example would be:

uid = nobody
gid = nobody
use chroot = yes
max connections = 4
syslog facility = local5
pid file = /var/run/rsyncd.pid

[ftp]
        path = /var/ftp/./pub
        comment = whole ftp area (approx 6.1 GB)

[sambaftp]
        path = /var/ftp/./pub/samba
        comment = Samba ftp area (approx 300 MB)

[rsyncftp]
        path = /var/ftp/./pub/rsync
        comment = rsync ftp area (approx 6 MB)

[sambawww]
        path = /public_html/samba
        comment = Samba WWW pages (approx 240 MB)

[cvs]
        path = /data/cvs
        comment = CVS repository (requires authentication)
        auth users = tridge, susan
        secrets file = /etc/rsyncd.secrets

The /etc/rsyncd.secrets file would look something like this:

tridge:mypass
susan:herpass

FILES

/etc/rsyncd.conf or rsyncd.conf

SEE ALSO

rsync(1), rsync-ssl(1)

BUGS

Please report bugs! The rsync bug tracking system is online at https://rsync.samba.org/.

VERSION

This manpage is current for version 3.2.7 of rsync.

CREDITS

Rsync is distributed under the GNU General Public License. See the file COPYING for details.

An rsync web site is available at https://rsync.samba.org/ and its github project is https://github.com/WayneD/rsync.

THANKS

Thanks to Warren Stanley for his original idea and patch for the rsync daemon. Thanks to Karsten Thygesen for his many suggestions and documentation!

AUTHOR

Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. It is currently maintained by Wayne Davison.

Mailing lists for support and development are available at https://lists.samba.org/.

20 Oct 2022

rsync-3.2.7/params.c0000664000000000000000000005245513675270555013042 0ustar rootroot/* This modules is based on the params.c module from Samba, written by Karl Auer and much modified by Christopher Hertel. */ /* * 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. */ /* -------------------------------------------------------------------------- ** * * Module name: params * * -------------------------------------------------------------------------- ** * * This module performs lexical analysis and initial parsing of a * Windows-like parameter file. It recognizes and handles four token * types: section-name, parameter-name, parameter-value, and * end-of-file. Comments and line continuation are handled * internally. * * The entry point to the module is function pm_process(). This * function opens the source file, calls the Parse() function to parse * the input, and then closes the file when either the EOF is reached * or a fatal error is encountered. * * A sample parameter file might look like this: * * [section one] * parameter one = value string * parameter two = another value * [section two] * new parameter = some value or t'other * * The parameter file is divided into sections by section headers: * section names enclosed in square brackets (eg. [section one]). * Each section contains parameter lines, each of which consist of a * parameter name and value delimited by an equal sign. Roughly, the * syntax is: * * :== {
} EOF * *
:==
{ } * *
:== '[' NAME ']' * * :== NAME '=' VALUE '\n' * * Blank lines and comment lines are ignored. Comment lines are lines * beginning with either a semicolon (';') or a pound sign ('#'). * * All whitespace in section names and parameter names is compressed * to single spaces. Leading and trailing whitespace is stripped from * both names and values. * * Only the first equals sign in a parameter line is significant. * Parameter values may contain equals signs, square brackets and * semicolons. Internal whitespace is retained in parameter values, * with the exception of the '\r' character, which is stripped for * historic reasons. Parameter names may not start with a left square * bracket, an equal sign, a pound sign, or a semicolon, because these * are used to identify other tokens. * * -------------------------------------------------------------------------- ** */ #include "rsync.h" #include "ifuncs.h" #include "itypes.h" /* -------------------------------------------------------------------------- ** * Constants... */ #define BUFR_INC 1024 /* -------------------------------------------------------------------------- ** * Variables... * * bufr - pointer to a global buffer. This is probably a kludge, * but it was the nicest kludge I could think of (for now). * bSize - The size of the global buffer . */ static char *bufr = NULL; static int bSize = 0; static BOOL (*the_sfunc)(char *); static BOOL (*the_pfunc)(char *, char *); /* -------------------------------------------------------------------------- ** * Functions... */ static int EatWhitespace( FILE *InFile ) /* ------------------------------------------------------------------------ ** * Scan past whitespace (see ctype(3C)) and return the first non-whitespace * character, or newline, or EOF. * * Input: InFile - Input source. * * Output: The next non-whitespace character in the input stream. * * Notes: Because the config files use a line-oriented grammar, we * explicitly exclude the newline character from the list of * whitespace characters. * - Note that both EOF (-1) and the nul character ('\0') are * considered end-of-file markers. * * ------------------------------------------------------------------------ ** */ { int c; for( c = getc( InFile ); isspace( c ) && ('\n' != c); c = getc( InFile ) ) ; return( c ); } /* EatWhitespace */ static int EatComment( FILE *InFile ) /* ------------------------------------------------------------------------ ** * Scan to the end of a comment. * * Input: InFile - Input source. * * Output: The character that marks the end of the comment. Normally, * this will be a newline, but it *might* be an EOF. * * Notes: Because the config files use a line-oriented grammar, we * explicitly exclude the newline character from the list of * whitespace characters. * - Note that both EOF (-1) and the nul character ('\0') are * considered end-of-file markers. * * ------------------------------------------------------------------------ ** */ { int c; for( c = getc( InFile ); ('\n'!=c) && (EOF!=c) && (c>0); c = getc( InFile ) ) ; return( c ); } /* EatComment */ static int Continuation( char *line, int pos ) /* ------------------------------------------------------------------------ ** * Scan backwards within a string to discover if the last non-whitespace * character is a line-continuation character ('\\'). * * Input: line - A pointer to a buffer containing the string to be * scanned. * pos - This is taken to be the offset of the end of the * string. This position is *not* scanned. * * Output: The offset of the '\\' character if it was found, or -1 to * indicate that it was not. * * ------------------------------------------------------------------------ ** */ { pos--; while( pos >= 0 && isSpace(line + pos) ) pos--; return( ((pos >= 0) && ('\\' == line[pos])) ? pos : -1 ); } /* Continuation */ static BOOL Section( FILE *InFile, BOOL (*sfunc)(char *) ) /* ------------------------------------------------------------------------ ** * Scan a section name, and pass the name to function sfunc(). * * Input: InFile - Input source. * sfunc - Pointer to the function to be called if the section * name is successfully read. * * Output: True if the section name was read and True was returned from * . False if failed or if a lexical error was * encountered. * * ------------------------------------------------------------------------ ** */ { int c; int i; int end; char *func = "params.c:Section() -"; i = 0; /* is the offset of the next free byte in bufr[] and */ end = 0; /* is the current "end of string" offset. In most */ /* cases these will be the same, but if the last */ /* character written to bufr[] is a space, then */ /* will be one less than . */ c = EatWhitespace( InFile ); /* We've already got the '['. Scan */ /* past initial white space. */ while( (EOF != c) && (c > 0) ) { /* Check that the buffer is big enough for the next character. */ if( i > (bSize - 2) ) { bSize += BUFR_INC; bufr = realloc_array( bufr, char, bSize ); } /* Handle a single character. */ switch( c ) { case ']': /* Found the closing bracket. */ bufr[end] = '\0'; if( 0 == end ) /* Don't allow an empty name. */ { rprintf(FLOG, "%s Empty section name in config file.\n", func ); return( False ); } if( !sfunc( bufr ) ) /* Got a valid name. Deal with it. */ return( False ); (void)EatComment( InFile ); /* Finish off the line. */ return( True ); case '\n': /* Got newline before closing ']'. */ i = Continuation( bufr, i ); /* Check for line continuation. */ if( i < 0 ) { bufr[end] = '\0'; rprintf(FLOG, "%s Badly formed line in config file: %s\n", func, bufr ); return( False ); } end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); c = getc( InFile ); /* Continue with next line. */ break; default: /* All else are a valid name chars. */ if( isspace( c ) ) /* One space per whitespace region. */ { bufr[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else /* All others copy verbatim. */ { bufr[i++] = c; end = i; c = getc( InFile ); } } } /* We arrive here if we've met the EOF before the closing bracket. */ rprintf(FLOG, "%s Unexpected EOF in the config file: %s\n", func, bufr ); return( False ); } /* Section */ static BOOL Parameter( FILE *InFile, BOOL (*pfunc)(char *, char *), int c ) /* ------------------------------------------------------------------------ ** * Scan a parameter name and value, and pass these two fields to pfunc(). * * Input: InFile - The input source. * pfunc - A pointer to the function that will be called to * process the parameter, once it has been scanned. * c - The first character of the parameter name, which * would have been read by Parse(). Unlike a comment * line or a section header, there is no lead-in * character that can be discarded. * * Output: True if the parameter name and value were scanned and processed * successfully, else False. * * Notes: This function is in two parts. The first loop scans the * parameter name. Internal whitespace is compressed, and an * equal sign (=) terminates the token. Leading and trailing * whitespace is discarded. The second loop scans the parameter * value. When both have been successfully identified, they are * passed to pfunc() for processing. * * ------------------------------------------------------------------------ ** */ { int i = 0; /* Position within bufr. */ int end = 0; /* bufr[end] is current end-of-string. */ int vstart = 0; /* Starting position of the parameter value. */ char *func = "params.c:Parameter() -"; /* Read the parameter name. */ while( 0 == vstart ) /* Loop until we've found the start of the value. */ { if( i > (bSize - 2) ) /* Ensure there's space for next char. */ { bSize += BUFR_INC; bufr = realloc_array( bufr, char, bSize ); } switch( c ) { case '=': /* Equal sign marks end of param name. */ if( 0 == end ) /* Don't allow an empty name. */ { rprintf(FLOG, "%s Invalid parameter name in config file.\n", func ); return( False ); } bufr[end++] = '\0'; /* Mark end of string & advance. */ i = vstart = end; /* New string starts here. */ c = EatWhitespace(InFile); break; case '\n': /* Find continuation char, else error. */ i = Continuation( bufr, i ); if( i < 0 ) { bufr[end] = '\0'; rprintf(FLOG, "%s Ignoring badly formed line in config file: %s\n", func, bufr ); return( True ); } end = ( (i > 0) && (' ' == bufr[i - 1]) ) ? (i - 1) : (i); c = getc( InFile ); /* Read past eoln. */ break; case '\0': /* Shouldn't have EOF within param name. */ case EOF: bufr[i] = '\0'; rprintf(FLOG, "%s Unexpected end-of-file at: %s\n", func, bufr ); return( True ); case ' ': case '\t': /* A directive divides at the first space or tab. */ if (*bufr == '&') { bufr[end++] = '\0'; i = vstart = end; c = EatWhitespace(InFile); if (c == '=') c = EatWhitespace(InFile); break; } /* FALL THROUGH */ default: if( isspace( c ) ) /* One ' ' per whitespace region. */ { bufr[end] = ' '; i = end + 1; c = EatWhitespace( InFile ); } else /* All others verbatim. */ { bufr[i++] = c; end = i; c = getc( InFile ); } } } /* Now parse the value. */ while( (EOF !=c) && (c > 0) ) { if( i > (bSize - 2) ) /* Make sure there's enough room. */ { bSize += BUFR_INC; bufr = realloc_array( bufr, char, bSize ); } switch( c ) { case '\r': /* Explicitly remove '\r' because the older */ c = getc( InFile ); /* version called fgets_slash() which also */ break; /* removes them. */ case '\n': /* Marks end of value unless there's a '\'. */ i = Continuation( bufr, i ); if( i < 0 ) c = 0; else { for( end = i; end >= 0 && isSpace(bufr + end); end-- ) ; c = getc( InFile ); } break; default: /* All others verbatim. Note that spaces do */ bufr[i++] = c; /* not advance . This allows trimming */ if( !isspace( c ) ) /* of whitespace at the end of the line. */ end = i; c = getc( InFile ); break; } } bufr[end] = '\0'; /* End of value. */ return( pfunc( bufr, &bufr[vstart] ) ); /* Pass name & value to pfunc(). */ } /* Parameter */ static int name_cmp(const void *n1, const void *n2) { return strcmp(*(char * const *)n1, *(char * const *)n2); } static int include_config(char *include, int manage_globals) { STRUCT_STAT sb; char *match = manage_globals ? "*.conf" : "*.inc"; int ret; if (do_stat(include, &sb) < 0) { rsyserr(FLOG, errno, "unable to stat config file \"%s\"", include); return 0; } if (S_ISREG(sb.st_mode)) { if (manage_globals && the_sfunc) the_sfunc("]push"); ret = pm_process(include, the_sfunc, the_pfunc); if (manage_globals && the_sfunc) the_sfunc("]pop"); } else if (S_ISDIR(sb.st_mode)) { char buf[MAXPATHLEN], **bpp; item_list conf_list; struct dirent *di; size_t j; DIR *d; if (!(d = opendir(include))) { rsyserr(FLOG, errno, "unable to open config dir \"%s\"", include); return 0; } memset(&conf_list, 0, sizeof conf_list); while ((di = readdir(d)) != NULL) { char *dname = d_name(di); if (!wildmatch(match, dname)) continue; bpp = EXPAND_ITEM_LIST(&conf_list, char *, 32); pathjoin(buf, sizeof buf, include, dname); *bpp = strdup(buf); } closedir(d); if (!(bpp = conf_list.items)) return 1; if (conf_list.count > 1) qsort(bpp, conf_list.count, sizeof (char *), name_cmp); for (j = 0, ret = 1; j < conf_list.count; j++) { if (manage_globals && the_sfunc) the_sfunc(j == 0 ? "]push" : "]reset"); if ((ret = pm_process(bpp[j], the_sfunc, the_pfunc)) != 1) break; } if (manage_globals && the_sfunc) the_sfunc("]pop"); for (j = 0; j < conf_list.count; j++) free(bpp[j]); free(bpp); } else ret = 0; return ret; } static int parse_directives(char *name, char *val) { if (strcasecmp(name, "&include") == 0) return include_config(val, 1); if (strcasecmp(name, "&merge") == 0) return include_config(val, 0); rprintf(FLOG, "Unknown directive: %s.\n", name); return 0; } static int Parse( FILE *InFile, BOOL (*sfunc)(char *), BOOL (*pfunc)(char *, char *) ) /* ------------------------------------------------------------------------ ** * Scan & parse the input. * * Input: InFile - Input source. * sfunc - Function to be called when a section name is scanned. * See Section(). * pfunc - Function to be called when a parameter is scanned. * See Parameter(). * * Output: 1 if the file was successfully scanned, 2 if the file was * scanned until a section header with no section function, else 0. * * Notes: The input can be viewed in terms of 'lines'. There are four * types of lines: * Blank - May contain whitespace, otherwise empty. * Comment - First non-whitespace character is a ';' or '#'. * The remainder of the line is ignored. * Section - First non-whitespace character is a '['. * Parameter - The default case. * * ------------------------------------------------------------------------ ** */ { int c; c = EatWhitespace( InFile ); while( (EOF != c) && (c > 0) ) { switch( c ) { case '\n': /* Blank line. */ c = EatWhitespace( InFile ); break; case ';': /* Comment line. */ case '#': c = EatComment( InFile ); break; case '[': /* Section Header. */ if (!sfunc) return 2; if( !Section( InFile, sfunc ) ) return 0; c = EatWhitespace( InFile ); break; case '\\': /* Bogus backslash. */ c = EatWhitespace( InFile ); break; case '&': /* Handle directives */ the_sfunc = sfunc; the_pfunc = pfunc; c = Parameter( InFile, parse_directives, c ); if (c != 1) return c; c = EatWhitespace( InFile ); break; default: /* Parameter line. */ if( !Parameter( InFile, pfunc, c ) ) return 0; c = EatWhitespace( InFile ); break; } } return 1; } /* Parse */ static FILE *OpenConfFile( char *FileName ) /* ------------------------------------------------------------------------ ** * Open a config file. * * Input: FileName - The pathname of the config file to be opened. * * Output: A pointer of type (FILE *) to the opened file, or NULL if the * file could not be opened. * * ------------------------------------------------------------------------ ** */ { FILE *OpenedFile; char *func = "params.c:OpenConfFile() -"; if( NULL == FileName || 0 == *FileName ) { rprintf(FLOG, "%s No config filename specified.\n", func); return( NULL ); } OpenedFile = fopen( FileName, "r" ); if( NULL == OpenedFile ) { rsyserr(FLOG, errno, "unable to open config file \"%s\"", FileName); } return( OpenedFile ); } /* OpenConfFile */ int pm_process( char *FileName, BOOL (*sfunc)(char *), BOOL (*pfunc)(char *, char *) ) /* ------------------------------------------------------------------------ ** * Process the named parameter file. * * Input: FileName - The pathname of the parameter file to be opened. * sfunc - A pointer to a function that will be called when * a section name is discovered. * pfunc - A pointer to a function that will be called when * a parameter name and value are discovered. * * Output: 1 if the file was successfully parsed, 2 if parsing ended at a * section header w/o a section function, else 0. * * ------------------------------------------------------------------------ ** */ { int result; FILE *InFile; char *func = "params.c:pm_process() -"; InFile = OpenConfFile( FileName ); /* Open the config file. */ if( NULL == InFile ) return( False ); if( NULL != bufr ) /* If we already have a buffer */ result = Parse( InFile, sfunc, pfunc ); /* (recursive call), then just */ /* use it. */ else /* If we don't have a buffer */ { /* allocate one, then parse, */ bSize = BUFR_INC; /* then free. */ bufr = new_array( char, bSize ); result = Parse( InFile, sfunc, pfunc ); free( bufr ); bufr = NULL; bSize = 0; } fclose(InFile); if( !result ) /* Generic failure. */ { rprintf(FLOG, "%s Failed. Error returned from params.c:parse().\n", func); return 0; } return result; } /* pm_process */ /* -------------------------------------------------------------------------- */ rsync-3.2.7/progress.c0000664000000000000000000001452014170671375013406 0ustar rootroot/* * Routines to output progress information during a file transfer. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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 "inums.h" extern int am_server; extern int flist_eof; extern int quiet; extern int need_unsorted_flist; extern int output_needs_newline; extern int stdout_format_has_i; extern struct stats stats; extern struct file_list *cur_flist; BOOL want_progress_now = False; #define PROGRESS_HISTORY_SECS 5 #ifdef GETPGRP_VOID #define GETPGRP_ARG #else #define GETPGRP_ARG 0 #endif struct progress_history { struct timeval time; OFF_T ofs; }; static struct progress_history ph_start; static struct progress_history ph_list[PROGRESS_HISTORY_SECS]; static int newest_hpos, oldest_hpos; static int current_file_index; static unsigned long msdiff(struct timeval *t1, struct timeval *t2) { return (t2->tv_sec - t1->tv_sec) * 1000L + (t2->tv_usec - t1->tv_usec) / 1000; } /** * @param ofs Current position in file * @param size Total size of file * @param is_last True if this is the last time progress will be * printed for this file, so we should output a newline. (Not * necessarily the same as all bytes being received.) **/ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_last) { char rembuf[64], eol[128]; const char *units; unsigned long diff; double rate, remain; int pct; if (is_last) { int len = snprintf(eol, sizeof eol, " (xfr#%d, %s-chk=%d/%d)\n", stats.xferred_files, flist_eof ? "to" : "ir", stats.num_files - current_file_index - 1, stats.num_files); if (INFO_GTE(PROGRESS, 2)) { static int last_len = 0; /* Drop \n and pad with spaces if line got shorter. */ if (last_len < --len) last_len = len; eol[last_len] = '\0'; while (last_len > len) eol[--last_len] = ' '; is_last = 0; } /* Compute stats based on the starting info. */ if (!ph_start.time.tv_sec || !(diff = msdiff(&ph_start.time, now))) diff = 1; rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0; /* Switch to total time taken for our last update. */ remain = (double) diff / 1000.0; } else { strlcpy(eol, " ", sizeof eol); /* Compute stats based on recent progress. */ if (!(diff = msdiff(&ph_list[oldest_hpos].time, now))) diff = 1; rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 / diff / 1024.0; remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0; } if (rate > 1024*1024) { rate /= 1024.0 * 1024.0; units = "GB/s"; } else if (rate > 1024) { rate /= 1024.0; units = "MB/s"; } else { units = "kB/s"; } if (remain < 0 || remain > 9999.0 * 3600.0) strlcpy(rembuf, " ??:??:??", sizeof rembuf); else { snprintf(rembuf, sizeof rembuf, "%4u:%02u:%02u", (unsigned int) (remain / 3600.0), (unsigned int) (remain / 60.0) % 60, (unsigned int) remain % 60); } output_needs_newline = 0; pct = ofs == size ? 100 : (int) (100.0 * ofs / size); rprintf(FCLIENT, "\r%15s %3d%% %7.2f%s %s%s", human_num(ofs), pct, rate, units, rembuf, eol); if (!is_last && !quiet) { output_needs_newline = 1; rflush(FCLIENT); } } void progress_init(void) { if (!am_server && !INFO_GTE(PROGRESS, 1)) { struct timeval now; gettimeofday(&now, NULL); ph_start.time.tv_sec = now.tv_sec; ph_start.time.tv_usec = now.tv_usec; } } void set_current_file_index(struct file_struct *file, int ndx) { if (!file) current_file_index = cur_flist->used + cur_flist->ndx_start - 1; else if (need_unsorted_flist) current_file_index = flist_find(cur_flist, file) + cur_flist->ndx_start; else current_file_index = ndx; current_file_index -= cur_flist->flist_num; } void instant_progress(const char *fname) { /* We only get here if want_progress_now is True */ if (!stdout_format_has_i && !INFO_GTE(NAME, 1)) rprintf(FINFO, "%s\n", fname); end_progress(0); want_progress_now = False; } void end_progress(OFF_T size) { if (!am_server) { struct timeval now; gettimeofday(&now, NULL); if (INFO_GTE(PROGRESS, 2) || want_progress_now) { rprint_progress(stats.total_transferred_size, stats.total_size, &now, True); } else { rprint_progress(size, size, &now, True); memset(&ph_start, 0, sizeof ph_start); } } } void show_progress(OFF_T ofs, OFF_T size) { struct timeval now; #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP static pid_t pgrp = -1; pid_t tc_pgrp; #endif if (am_server) return; #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP if (pgrp == -1) pgrp = getpgrp(GETPGRP_ARG); #endif gettimeofday(&now, NULL); if (INFO_GTE(PROGRESS, 2)) { ofs = stats.total_transferred_size - size + ofs; size = stats.total_size; } if (!ph_start.time.tv_sec) { int i; /* Try to guess the real starting time when the sender started * to send us data by using the time we last received some data * in the last file (if it was recent enough). */ if (msdiff(&ph_list[newest_hpos].time, &now) <= 1500) { ph_start.time = ph_list[newest_hpos].time; ph_start.ofs = 0; } else { ph_start.time.tv_sec = now.tv_sec; ph_start.time.tv_usec = now.tv_usec; ph_start.ofs = ofs; } for (i = 0; i < PROGRESS_HISTORY_SECS; i++) ph_list[i] = ph_start; } else { if (msdiff(&ph_list[newest_hpos].time, &now) < 1000) return; newest_hpos = oldest_hpos; oldest_hpos = (oldest_hpos + 1) % PROGRESS_HISTORY_SECS; ph_list[newest_hpos].time.tv_sec = now.tv_sec; ph_list[newest_hpos].time.tv_usec = now.tv_usec; ph_list[newest_hpos].ofs = ofs; } #if defined HAVE_GETPGRP && defined HAVE_TCGETPGRP tc_pgrp = tcgetpgrp(STDOUT_FILENO); if (tc_pgrp != pgrp && tc_pgrp != -1) return; #endif rprint_progress(ofs, size, &now, False); } rsync-3.2.7/wildtest.c0000664000000000000000000001277713443220465013405 0ustar rootroot/* * Test suite for the wildmatch code. * * Copyright (C) 2003-2019 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. */ /*#define COMPARE_WITH_FNMATCH*/ #define WILD_TEST_ITERATIONS #include "lib/wildmatch.c" #include #ifdef COMPARE_WITH_FNMATCH #include int fnmatch_errors = 0; #endif int wildmatch_errors = 0; typedef char bool; int output_iterations = 0; int explode_mod = 0; int empties_mod = 0; int empty_at_start = 0; int empty_at_end = 0; static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"iterations", 'i', POPT_ARG_NONE, &output_iterations, 0, 0, 0}, {"empties", 'e', POPT_ARG_STRING, 0, 'e', 0, 0}, {"explode", 'x', POPT_ARG_INT, &explode_mod, 0, 0, 0}, {0,0,0,0, 0, 0, 0} }; /* match just at the start of string (anchored tests) */ static void run_test(int line, bool matches, #ifdef COMPARE_WITH_FNMATCH bool same_as_fnmatch, #endif const char *text, const char *pattern) { bool matched; #ifdef COMPARE_WITH_FNMATCH bool fn_matched; int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME; #endif if (explode_mod) { char buf[MAXPATHLEN*2], *texts[MAXPATHLEN]; int pos = 0, cnt = 0, ndx = 0, len = strlen(text); if (empty_at_start) texts[ndx++] = ""; /* An empty string must turn into at least one empty array item. */ while (1) { texts[ndx] = buf + ndx * (explode_mod + 1); strlcpy(texts[ndx++], text + pos, explode_mod + 1); if (pos + explode_mod >= len) break; pos += explode_mod; if (!(++cnt % empties_mod)) texts[ndx++] = ""; } if (empty_at_end) texts[ndx++] = ""; texts[ndx] = NULL; matched = wildmatch_array(pattern, (const char**)texts, 0); } else matched = wildmatch(pattern, text); #ifdef COMPARE_WITH_FNMATCH fn_matched = !fnmatch(pattern, text, flags); #endif if (matched != matches) { printf("wildmatch failure on line %d:\n %s\n %s\n expected %s match\n", line, text, pattern, matches? "a" : "NO"); wildmatch_errors++; } #ifdef COMPARE_WITH_FNMATCH if (fn_matched != (matches ^ !same_as_fnmatch)) { printf("fnmatch disagreement on line %d:\n %s\n %s\n expected %s match\n", line, text, pattern, matches ^ !same_as_fnmatch? "a" : "NO"); fnmatch_errors++; } #endif if (output_iterations) { printf("%d: \"%s\" iterations = %d\n", line, pattern, wildmatch_iteration_count); } } int main(int argc, char **argv) { char buf[2048], *s, *string[2], *end[2]; const char *arg; FILE *fp; int opt, line, i, flag[2]; poptContext pc = poptGetContext("wildtest", argc, (const char**)argv, long_options, 0); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case 'e': arg = poptGetOptArg(pc); empties_mod = atoi(arg); if (strchr(arg, 's')) empty_at_start = 1; if (strchr(arg, 'e')) empty_at_end = 1; if (!explode_mod) explode_mod = 1024; break; default: fprintf(stderr, "%s: %s\n", poptBadOption(pc, POPT_BADOPTION_NOALIAS), poptStrerror(opt)); exit(1); } } if (explode_mod && !empties_mod) empties_mod = 1024; argv = (char**)poptGetArgs(pc); if (!argv || argv[1]) { fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n"); exit(1); } if ((fp = fopen(*argv, "r")) == NULL) { fprintf(stderr, "Unable to open %s\n", *argv); exit(1); } line = 0; while (fgets(buf, sizeof buf, fp)) { line++; if (*buf == '#' || *buf == '\n') continue; for (s = buf, i = 0; i <= 1; i++) { if (*s == '1') flag[i] = 1; else if (*s == '0') flag[i] = 0; else flag[i] = -1; if (*++s != ' ' && *s != '\t') flag[i] = -1; if (flag[i] < 0) { fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s", line, *argv, buf); exit(1); } while (*++s == ' ' || *s == '\t') {} } for (i = 0; i <= 1; i++) { if (*s == '\'' || *s == '"' || *s == '`') { char quote = *s++; string[i] = s; while (*s && *s != quote) s++; if (!*s) { fprintf(stderr, "Unmatched quote on line %d of %s:\n%s", line, *argv, buf); exit(1); } end[i] = s; } else { if (!*s || *s == '\n') { fprintf(stderr, "Not enough strings on line %d of %s:\n%s", line, *argv, buf); exit(1); } string[i] = s; while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {} end[i] = s; } while (*++s == ' ' || *s == '\t') {} } *end[0] = *end[1] = '\0'; run_test(line, flag[0], #ifdef COMPARE_WITH_FNMATCH flag[1], #endif string[0], string[1]); } if (!wildmatch_errors) fputs("No", stdout); else printf("%d", wildmatch_errors); printf(" wildmatch error%s found.\n", wildmatch_errors == 1? "" : "s"); #ifdef COMPARE_WITH_FNMATCH if (!fnmatch_errors) fputs("No", stdout); else printf("%d", fnmatch_errors); printf(" fnmatch error%s found.\n", fnmatch_errors == 1? "" : "s"); #endif return 0; } rsync-3.2.7/SECURITY.md0000664000000000000000000000047113724011540013151 0ustar rootroot# Security Policy ## Supported Versions Only the current release of the software is actively supported. If you need help backporting fixes into an older release, feel free to ask. ## Reporting a Vulnerability Email your vulnerability information to rsync's maintainer: Wayne Davison rsync-3.2.7/latest-year.h0000664000000000000000000000003314164430617013766 0ustar rootroot#define LATEST_YEAR "2022" rsync-3.2.7/rsync.1.md0000664000000000000000000072131014323055442013206 0ustar rootroot## NAME rsync - a fast, versatile, remote (and local) file-copying tool ## SYNOPSIS ``` Local: rsync [OPTION...] SRC... [DEST] Access via remote shell: Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST:DEST Access via rsync daemon: Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST] rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST::DEST rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST) ``` Usages with just one SRC arg and no DEST arg will list the source files instead of copying. The online version of this manpage (that includes cross-linking of topics) is available at . ## DESCRIPTION Rsync is a fast and extraordinarily versatile file copying tool. It can copy locally, to/from another host over any remote shell, or to/from a remote rsync daemon. It offers a large number of options that control every aspect of its behavior and permit very flexible specification of the set of files to be copied. It is famous for its delta-transfer algorithm, which reduces the amount of data sent over the network by sending only the differences between the source files and the existing files in the destination. Rsync is widely used for backups and mirroring and as an improved copy command for everyday use. Rsync finds files that need to be transferred using a "quick check" algorithm (by default) that looks for files that have changed in size or in last-modified time. Any changes in the other preserved attributes (as requested by options) are made on the destination file directly when the quick check indicates that the file's data does not need to be updated. Some of the additional features of rsync are: - support for copying links, devices, owners, groups, and permissions - exclude and exclude-from options similar to GNU tar - a CVS exclude mode for ignoring the same files that CVS would ignore - can use any transparent remote shell, including ssh or rsh - does not require super-user privileges - pipelining of file transfers to minimize latency costs - support for anonymous or authenticated rsync daemons (ideal for mirroring) ## GENERAL Rsync copies files either to or from a remote host, or locally on the current host (it does not support copying files between two remote hosts). There are two different ways for rsync to contact a remote system: using a remote-shell program as the transport (such as ssh or rsh) or contacting an rsync daemon directly via TCP. The remote-shell transport is used whenever the source or destination path contains a single colon (:) separator after a host specification. Contacting an rsync daemon directly happens when the source or destination path contains a double colon (::) separator after a host specification, OR when an rsync:// URL is specified (see also the [USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION](#) section for an exception to this latter rule). As a special case, if a single source arg is specified without a destination, the files are listed in an output format similar to "`ls -l`". As expected, if neither the source or destination path specify a remote host, the copy occurs locally (see also the [`--list-only`](#opt) option). Rsync refers to the local side as the client and the remote side as the server. Don't confuse server with an rsync daemon. A daemon is always a server, but a server can be either a daemon or a remote-shell spawned process. ## SETUP See the file README.md for installation instructions. Once installed, you can use rsync to any machine that you can access via a remote shell (as well as some that you can access using the rsync daemon-mode protocol). For remote transfers, a modern rsync uses ssh for its communications, but it may have been configured to use a different remote shell by default, such as rsh or remsh. You can also specify any remote shell you like, either by using the [`-e`](#opt) command line option, or by setting the [`RSYNC_RSH`](#) environment variable. Note that rsync must be installed on both the source and destination machines. ## USAGE You use rsync in the same way you use rcp. You must specify a source and a destination, one of which may be remote. Perhaps the best way to explain the syntax is with some examples: > rsync -t *.c foo:src/ This would transfer all files matching the pattern `*.c` from the current directory to the directory src on the machine foo. If any of the files already exist on the remote system then the rsync remote-update protocol is used to update the file by sending only the differences in the data. Note that the expansion of wildcards on the command-line (`*.c`) into a list of files is handled by the shell before it runs rsync and not by rsync itself (exactly the same as all other Posix-style programs). > rsync -avz foo:src/bar /data/tmp This would recursively transfer all files from the directory src/bar on the machine foo into the /data/tmp/bar directory on the local machine. The files are transferred in archive mode, which ensures that symbolic links, devices, attributes, permissions, ownerships, etc. are preserved in the transfer. Additionally, compression will be used to reduce the size of data portions of the transfer. > rsync -avz foo:src/bar/ /data/tmp A trailing slash on the source changes this behavior to avoid creating an additional directory level at the destination. You can think of a trailing / on a source as meaning "copy the contents of this directory" as opposed to "copy the directory by name", but in both cases the attributes of the containing directory are transferred to the containing directory on the destination. In other words, each of the following commands copies the files in the same way, including their setting of the attributes of /dest/foo: > rsync -av /src/foo /dest > rsync -av /src/foo/ /dest/foo Note also that host and module references don't require a trailing slash to copy the contents of the default directory. For example, both of these copy the remote directory's contents into "/dest": > rsync -av host: /dest > rsync -av host::module /dest You can also use rsync in local-only mode, where both the source and destination don't have a ':' in the name. In this case it behaves like an improved copy command. Finally, you can list all the (listable) modules available from a particular rsync daemon by leaving off the module name: > rsync somehost.mydomain.com:: ## COPYING TO A DIFFERENT NAME When you want to copy a directory to a different name, use a trailing slash on the source directory to put the contents of the directory into any destination directory you like: > rsync -ai foo/ bar/ Rsync also has the ability to customize a destination file's name when copying a single item. The rules for this are: - The transfer list must consist of a single item (either a file or an empty directory) - The final element of the destination path must not exist as a directory - The destination path must not have been specified with a trailing slash Under those circumstances, rsync will set the name of the destination's single item to the last element of the destination path. Keep in mind that it is best to only use this idiom when copying a file and use the above trailing-slash idiom when copying a directory. The following example copies the `foo.c` file as `bar.c` in the `save` dir (assuming that `bar.c` isn't a directory): > rsync -ai src/foo.c save/bar.c The single-item copy rule might accidentally bite you if you unknowingly copy a single item and specify a destination dir that doesn't exist (without using a trailing slash). For example, if `src/*.c` matches one file and `save/dir` doesn't exist, this will confuse you by naming the destination file `save/dir`: > rsync -ai src/*.c save/dir To prevent such an accident, either make sure the destination dir exists or specify the destination path with a trailing slash: > rsync -ai src/*.c save/dir/ ## SORTED TRANSFER ORDER Rsync always sorts the specified filenames into its internal transfer list. This handles the merging together of the contents of identically named directories, makes it easy to remove duplicate filenames. It can, however, confuse someone when the files are transferred in a different order than what was given on the command-line. If you need a particular file to be transferred prior to another, either separate the files into different rsync calls, or consider using [`--delay-updates`](#opt) (which doesn't affect the sorted transfer order, but does make the final file-updating phase happen much more rapidly). ## MULTI-HOST SECURITY Rsync takes steps to ensure that the file requests that are shared in a transfer are protected against various security issues. Most of the potential problems arise on the receiving side where rsync takes steps to ensure that the list of files being transferred remains within the bounds of what was requested. Toward this end, rsync 3.1.2 and later have aborted when a file list contains an absolute or relative path that tries to escape out of the top of the transfer. Also, beginning with version 3.2.5, rsync does two more safety checks of the file list to (1) ensure that no extra source arguments were added into the transfer other than those that the client requested and (2) ensure that the file list obeys the exclude rules that were sent to the sender. For those that don't yet have a 3.2.5 client rsync (or those that want to be extra careful), it is safest to do a copy into a dedicated destination directory for the remote files when you don't trust the remote host. For example, instead of doing an rsync copy into your home directory: > rsync -aiv host1:dir1 ~ Dedicate a "host1-files" dir to the remote content: > rsync -aiv host1:dir1 ~/host1-files See the [`--trust-sender`](#opt) option for additional details. CAUTION: it is not particularly safe to use rsync to copy files from a case-preserving filesystem to a case-ignoring filesystem. If you must perform such a copy, you should either disable symlinks via `--no-links` or enable the munging of symlinks via [`--munge-links`](#opt) (and make sure you use the right local or remote option). This will prevent rsync from doing potentially dangerous things if a symlink name overlaps with a file or directory. It does not, however, ensure that you get a full copy of all the files (since that may not be possible when the names overlap). A potentially better solution is to list all the source files and create a safe list of filenames that you pass to the [`--files-from`](#opt) option. Any files that conflict in name would need to be copied to different destination directories using more than one copy. While a copy of a case-ignoring filesystem to a case-ignoring filesystem can work out fairly well, if no `--delete-during` or `--delete-before` option is active, rsync can potentially update an existing file on the receiveing side without noticing that the upper-/lower-case of the filename should be changed to match the sender. ## ADVANCED USAGE The syntax for requesting multiple files from a remote host is done by specifying additional remote-host args in the same style as the first, or with the hostname omitted. For instance, all these work: > rsync -aiv host:file1 :file2 host:file{3,4} /dest/ > rsync -aiv host::modname/file{1,2} host::modname/extra /dest/ > rsync -aiv host::modname/first ::extra-file{1,2} /dest/ Note that a daemon connection only supports accessing one module per copy command, so if the start of a follow-up path doesn't begin with the modname of the first path, it is assumed to be a path in the module (such as the extra-file1 & extra-file2 that are grabbed above). Really old versions of rsync (2.6.9 and before) only allowed specifying one remote-source arg, so some people have instead relied on the remote-shell performing space splitting to break up an arg into multiple paths. Such unintuitive behavior is no longer supported by default (though you can request it, as described below). Starting in 3.2.4, filenames are passed to a remote shell in such a way as to preserve the characters you give it. Thus, if you ask for a file with spaces in the name, that's what the remote rsync looks for: > rsync -aiv host:'a simple file.pdf' /dest/ If you use scripts that have been written to manually apply extra quoting to the remote rsync args (or to require remote arg splitting), you can ask rsync to let your script handle the extra escaping. This is done by either adding the [`--old-args`](#opt) option to the rsync runs in the script (which requires a new rsync) or exporting [RSYNC_OLD_ARGS](#)=1 and [RSYNC_PROTECT_ARGS](#)=0 (which works with old or new rsync versions). ## CONNECTING TO AN RSYNC DAEMON It is also possible to use rsync without a remote shell as the transport. In this case you will directly connect to a remote rsync daemon, typically using TCP port 873. (This obviously requires the daemon to be running on the remote system, so refer to the [STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS](#) section below for information on that.) Using rsync in this way is the same as using it with a remote shell except that: - Use either double-colon syntax or rsync:// URL syntax instead of the single-colon (remote shell) syntax. - The first element of the "path" is actually a module name. - Additional remote source args can use an abbreviated syntax that omits the hostname and/or the module name, as discussed in [ADVANCED USAGE](#). - The remote daemon may print a "message of the day" when you connect. - If you specify only the host (with no module or path) then a list of accessible modules on the daemon is output. - If you specify a remote source path but no destination, a listing of the matching files on the remote daemon is output. - The [`--rsh`](#opt) (`-e`) option must be omitted to avoid changing the connection style from using a socket connection to [USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION](#). An example that copies all the files in a remote module named "src": > rsync -av host::src /dest Some modules on the remote daemon may require authentication. If so, you will receive a password prompt when you connect. You can avoid the password prompt by setting the environment variable [`RSYNC_PASSWORD`](#) to the password you want to use or using the [`--password-file`](#opt) option. This may be useful when scripting rsync. WARNING: On some systems environment variables are visible to all users. On those systems using [`--password-file`](#opt) is recommended. You may establish the connection via a web proxy by setting the environment variable [`RSYNC_PROXY`](#) to a hostname:port pair pointing to your web proxy. Note that your web proxy's configuration must support proxy connections to port 873. You may also establish a daemon connection using a program as a proxy by setting the environment variable [`RSYNC_CONNECT_PROG`](#) to the commands you wish to run in place of making a direct socket connection. The string may contain the escape "%H" to represent the hostname specified in the rsync command (so use "%%" if you need a single "%" in your string). For example: > export RSYNC_CONNECT_PROG='ssh proxyhost nc %H 873' > rsync -av targethost1::module/src/ /dest/ > rsync -av rsync://targethost2/module/src/ /dest/ The command specified above uses ssh to run nc (netcat) on a proxyhost, which forwards all data to port 873 (the rsync daemon) on the targethost (%H). Note also that if the [`RSYNC_SHELL`](#) environment variable is set, that program will be used to run the `RSYNC_CONNECT_PROG` command instead of using the default shell of the **system()** call. ## USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION It is sometimes useful to use various features of an rsync daemon (such as named modules) without actually allowing any new socket connections into a system (other than what is already required to allow remote-shell access). Rsync supports connecting to a host using a remote shell and then spawning a single-use "daemon" server that expects to read its config file in the home dir of the remote user. This can be useful if you want to encrypt a daemon-style transfer's data, but since the daemon is started up fresh by the remote user, you may not be able to use features such as chroot or change the uid used by the daemon. (For another way to encrypt a daemon transfer, consider using ssh to tunnel a local port to a remote machine and configure a normal rsync daemon on that remote host to only allow connections from "localhost".) From the user's perspective, a daemon transfer via a remote-shell connection uses nearly the same command-line syntax as a normal rsync-daemon transfer, with the only exception being that you must explicitly set the remote shell program on the command-line with the [`--rsh=COMMAND`](#opt) option. (Setting the RSYNC_RSH in the environment will not turn on this functionality.) For example: > rsync -av --rsh=ssh host::module /dest If you need to specify a different remote-shell user, keep in mind that the user@ prefix in front of the host is specifying the rsync-user value (for a module that requires user-based authentication). This means that you must give the '-l user' option to ssh when specifying the remote-shell, as in this example that uses the short version of the [`--rsh`](#opt) option: > rsync -av -e "ssh -l ssh-user" rsync-user@host::module /dest The "ssh-user" will be used at the ssh level; the "rsync-user" will be used to log-in to the "module". In this setup, the daemon is started by the ssh command that is accessing the system (which can be forced via the `~/.ssh/authorized_keys` file, if desired). However, when accessing a daemon directly, it needs to be started beforehand. ## STARTING AN RSYNC DAEMON TO ACCEPT CONNECTIONS In order to connect to an rsync daemon, the remote system needs to have a daemon already running (or it needs to have configured something like inetd to spawn an rsync daemon for incoming connections on a particular port). For full information on how to start a daemon that will handling incoming socket connections, see the [**rsyncd.conf**(5)](rsyncd.conf.5) manpage -- that is the config file for the daemon, and it contains the full details for how to run the daemon (including stand-alone and inetd configurations). If you're using one of the remote-shell transports for the transfer, there is no need to manually start an rsync daemon. ## EXAMPLES Here are some examples of how rsync can be used. To backup a home directory, which consists of large MS Word files and mail folders, a per-user cron job can be used that runs this each day: > rsync -aiz . bkhost:backup/joe/ To move some files from a remote host to the local host, you could run: > rsync -aiv --remove-source-files rhost:/tmp/{file1,file2}.c ~/src/ ## OPTION SUMMARY Here is a short summary of the options available in rsync. Each option also has its own detailed description later in this manpage. [comment]: # (help-rsync.h) [comment]: # (Keep these short enough that they'll be under 80 chars when indented by 7 chars.) ``` --verbose, -v increase verbosity --info=FLAGS fine-grained informational verbosity --debug=FLAGS fine-grained debug verbosity --stderr=e|a|c change stderr output mode (default: errors) --quiet, -q suppress non-error messages --no-motd suppress daemon-mode MOTD --checksum, -c skip based on checksum, not mod-time & size --archive, -a archive mode is -rlptgoD (no -A,-X,-U,-N,-H) --no-OPTION turn off an implied OPTION (e.g. --no-D) --recursive, -r recurse into directories --relative, -R use relative path names --no-implied-dirs don't send implied dirs with --relative --backup, -b make backups (see --suffix & --backup-dir) --backup-dir=DIR make backups into hierarchy based in DIR --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) --update, -u skip files that are newer on the receiver --inplace update destination files in-place --append append data onto shorter files --append-verify --append w/old data in file checksum --dirs, -d transfer directories without recursing --old-dirs, --old-d works like --dirs when talking to old rsync --mkpath create destination's missing path components --links, -l copy symlinks as symlinks --copy-links, -L transform symlink into referent file/dir --copy-unsafe-links only "unsafe" symlinks are transformed --safe-links ignore symlinks that point outside the tree --munge-links munge symlinks to make them safe & unusable --copy-dirlinks, -k transform symlink to dir into referent dir --keep-dirlinks, -K treat symlinked dir on receiver as dir --hard-links, -H preserve hard links --perms, -p preserve permissions --executability, -E preserve executability --chmod=CHMOD affect file and/or directory permissions --acls, -A preserve ACLs (implies --perms) --xattrs, -X preserve extended attributes --owner, -o preserve owner (super-user only) --group, -g preserve group --devices preserve device files (super-user only) --copy-devices copy device contents as a regular file --write-devices write to devices as files (implies --inplace) --specials preserve special files -D same as --devices --specials --times, -t preserve modification times --atimes, -U preserve access (use) times --open-noatime avoid changing the atime on opened files --crtimes, -N preserve create times (newness) --omit-dir-times, -O omit directories from --times --omit-link-times, -J omit symlinks from --times --super receiver attempts super-user activities --fake-super store/recover privileged attrs using xattrs --sparse, -S turn sequences of nulls into sparse blocks --preallocate allocate dest files before writing them --dry-run, -n perform a trial run with no changes made --whole-file, -W copy files whole (w/o delta-xfer algorithm) --checksum-choice=STR choose the checksum algorithm (aka --cc) --one-file-system, -x don't cross filesystem boundaries --block-size=SIZE, -B force a fixed checksum block-size --rsh=COMMAND, -e specify the remote shell to use --rsync-path=PROGRAM specify the rsync to run on remote machine --existing skip creating new files on receiver --ignore-existing skip updating files that exist on receiver --remove-source-files sender removes synchronized files (non-dir) --del an alias for --delete-during --delete delete extraneous files from dest dirs --delete-before receiver deletes before xfer, not during --delete-during receiver deletes during the transfer --delete-delay find deletions during, delete after --delete-after receiver deletes after transfer, not during --delete-excluded also delete excluded files from dest dirs --ignore-missing-args ignore missing source args without error --delete-missing-args delete missing source args from destination --ignore-errors delete even if there are I/O errors --force force deletion of dirs even if not empty --max-delete=NUM don't delete more than NUM files --max-size=SIZE don't transfer any file larger than SIZE --min-size=SIZE don't transfer any file smaller than SIZE --max-alloc=SIZE change a limit relating to memory alloc --partial keep partially transferred files --partial-dir=DIR put a partially transferred file into DIR --delay-updates put all updated files into place at end --prune-empty-dirs, -m prune empty directory chains from file-list --numeric-ids don't map uid/gid values by user/group name --usermap=STRING custom username mapping --groupmap=STRING custom groupname mapping --chown=USER:GROUP simple username/groupname mapping --timeout=SECONDS set I/O timeout in seconds --contimeout=SECONDS set daemon connection timeout in seconds --ignore-times, -I don't skip files that match size and time --size-only skip files that match in size --modify-window=NUM, -@ set the accuracy for mod-time comparisons --temp-dir=DIR, -T create temporary files in directory DIR --fuzzy, -y find similar file for basis if no dest file --compare-dest=DIR also compare destination files relative to DIR --copy-dest=DIR ... and include copies of unchanged files --link-dest=DIR hardlink to files in DIR when unchanged --compress, -z compress file data during the transfer --compress-choice=STR choose the compression algorithm (aka --zc) --compress-level=NUM explicitly set compression level (aka --zl) --skip-compress=LIST skip compressing files with suffix in LIST --cvs-exclude, -C auto-ignore files in the same way CVS does --filter=RULE, -f add a file-filtering RULE -F same as --filter='dir-merge /.rsync-filter' repeated: --filter='- .rsync-filter' --exclude=PATTERN exclude files matching PATTERN --exclude-from=FILE read exclude patterns from FILE --include=PATTERN don't exclude files matching PATTERN --include-from=FILE read include patterns from FILE --files-from=FILE read list of source-file names from FILE --from0, -0 all *-from/filter files are delimited by 0s --old-args disable the modern arg-protection idiom --secluded-args, -s use the protocol to safely send the args --trust-sender trust the remote sender's file list --copy-as=USER[:GROUP] specify user & optional group for the copy --address=ADDRESS bind address for outgoing socket to daemon --port=PORT specify double-colon alternate port number --sockopts=OPTIONS specify custom TCP options --blocking-io use blocking I/O for the remote shell --outbuf=N|L|B set out buffering to None, Line, or Block --stats give some file-transfer stats --8-bit-output, -8 leave high-bit chars unescaped in output --human-readable, -h output numbers in a human-readable format --progress show progress during transfer -P same as --partial --progress --itemize-changes, -i output a change-summary for all updates --remote-option=OPT, -M send OPTION to the remote side only --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 --password-file=FILE read daemon-access password from FILE --early-input=FILE use FILE for daemon's early exec input --list-only list the files instead of copying them --bwlimit=RATE limit socket I/O bandwidth --stop-after=MINS Stop rsync after MINS minutes have elapsed --stop-at=y-m-dTh:m Stop rsync at the specified point in time --fsync fsync every written file --write-batch=FILE write a batched update to FILE --only-write-batch=FILE like --write-batch but w/o updating dest --read-batch=FILE read a batched update from FILE --protocol=NUM force an older protocol version to be used --iconv=CONVERT_SPEC request charset conversion of filenames --checksum-seed=NUM set block/file checksum seed (advanced) --ipv4, -4 prefer IPv4 --ipv6, -6 prefer IPv6 --version, -V print the version + other info and exit --help, -h (*) show this help (* -h is help only on its own) ``` Rsync can also be run as a daemon, in which case the following options are accepted: [comment]: # (help-rsyncd.h) ``` --daemon run as an rsync daemon --address=ADDRESS bind to the specified address --bwlimit=RATE limit socket I/O bandwidth --config=FILE specify alternate rsyncd.conf file --dparam=OVERRIDE, -M override global daemon config parameter --no-detach do not detach from the parent --port=PORT listen on alternate port number --log-file=FILE override the "log file" setting --log-file-format=FMT override the "log format" setting --sockopts=OPTIONS specify custom TCP options --verbose, -v increase verbosity --ipv4, -4 prefer IPv4 --ipv6, -6 prefer IPv6 --help, -h show this help (when used with --daemon) ``` ## OPTIONS Rsync accepts both long (double-dash + word) and short (single-dash + letter) options. The full list of the available options are described below. If an option can be specified in more than one way, the choices are comma-separated. Some options only have a long variant, not a short. If the option takes a parameter, the parameter is only listed after the long variant, even though it must also be specified for the short. When specifying a parameter, you can either use the form `--option=param`, `--option param`, `-o=param`, `-o param`, or `-oparam` (the latter choices assume that your option has a short variant). The parameter may need to be quoted in some manner for it to survive the shell's command-line parsing. Also keep in mind that a leading tilde (`~`) in a pathname is substituted by your shell, so make sure that you separate the option name from the pathname using a space if you want the local shell to expand it. [comment]: # (Some markup below uses a literal non-breakable space when a backtick string) [comment]: # (needs to contain a space since markdown strips spaces from the start/end) [comment]: # (An OL starting at 0 is converted into a DL by the parser.) 0. `--help` Print a short help page describing the options available in rsync and exit. You can also use `-h` for `--help` when it is used without any other options (since it normally means [`--human-readable`](#opt)). 0. `--version`, `-V` Print the rsync version plus other info and exit. When repeated, the information is output is a JSON format that is still fairly readable (client side only). The output includes a list of compiled-in capabilities, a list of optimizations, the default list of checksum algorithms, the default list of compression algorithms, the default list of daemon auth digests, a link to the rsync web site, and a few other items. 0. `--verbose`, `-v` This option increases the amount of information you are given during the transfer. By default, rsync works silently. A single `-v` will give you information about what files are being transferred and a brief summary at the end. Two `-v` options will give you information on what files are being skipped and slightly more information at the end. More than two `-v` options should only be used if you are debugging rsync. The end-of-run summary tells you the number of bytes sent to the remote rsync (which is the receiving side on a local copy), the number of bytes received from the remote host, and the average bytes per second of the transferred data computed over the entire length of the rsync run. The second line shows the total size (in bytes), which is the sum of all the file sizes that rsync considered transferring. It also shows a "speedup" value, which is a ratio of the total file size divided by the sum of the sent and received bytes (which is really just a feel-good bigger-is-better number). Note that these byte values can be made more (or less) human-readable by using the [`--human-readable`](#opt) (or `--no-human-readable`) options. In a modern rsync, the `-v` option is equivalent to the setting of groups of [`--info`](#opt) and [`--debug`](#opt) options. You can choose to use these newer options in addition to, or in place of using `--verbose`, as any fine-grained settings override the implied settings of `-v`. Both [`--info`](#opt) and [`--debug`](#opt) have a way to ask for help that tells you exactly what flags are set for each increase in verbosity. However, do keep in mind that a daemon's "`max verbosity`" setting will limit how high of a level the various individual flags can be set on the daemon side. For instance, if the max is 2, then any info and/or debug flag that is set to a higher value than what would be set by `-vv` will be downgraded to the `-vv` level in the daemon's logging. 0. `--info=FLAGS` This option lets you have fine-grained control over the information output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use `--info=help` to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples: > rsync -a --info=progress2 src/ dest/ > rsync -avv --info=stats2,misc1,flist0 src/ dest/ Note that `--info=name`'s output is affected by the [`--out-format`](#opt) and [`--itemize-changes`](#opt) (`-i`) options. See those options for more information on what is output and when. This option was added to 3.1.0, so an older rsync on the server side might reject your attempts at fine-grained control (if one or more flags needed to be send to the server and the server was too old to understand them). See also the "`max verbosity`" caveat above when dealing with a daemon. 0. `--debug=FLAGS` This option lets you have fine-grained control over the debug output you want to see. An individual flag name may be followed by a level number, with 0 meaning to silence that output, 1 being the default output level, and higher numbers increasing the output of that flag (for those that support higher levels). Use `--debug=help` to see all the available flag names, what they output, and what flag names are added for each increase in the verbose level. Some examples: > rsync -avvv --debug=none src/ dest/ > rsync -avA --del --debug=del2,acl src/ dest/ Note that some debug messages will only be output when the [`--stderr=all`](#opt) option is specified, especially those pertaining to I/O and buffer debugging. Beginning in 3.2.0, this option is no longer auto-forwarded to the server side in order to allow you to specify different debug values for each side of the transfer, as well as to specify a new debug option that is only present in one of the rsync versions. If you want to duplicate the same option on both sides, using brace expansion is an easy way to save you some typing. This works in zsh and bash: > rsync -aiv {-M,}--debug=del2 src/ dest/ 0. `--stderr=errors|all|client` This option controls which processes output to stderr and if info messages are also changed to stderr. The mode strings can be abbreviated, so feel free to use a single letter value. The 3 possible choices are: - `errors` - (the default) causes all the rsync processes to send an error directly to stderr, even if the process is on the remote side of the transfer. Info messages are sent to the client side via the protocol stream. If stderr is not available (i.e. when directly connecting with a daemon via a socket) errors fall back to being sent via the protocol stream. - `all` - causes all rsync messages (info and error) to get written directly to stderr from all (possible) processes. This causes stderr to become line-buffered (instead of raw) and eliminates the ability to divide up the info and error messages by file handle. For those doing debugging or using several levels of verbosity, this option can help to avoid clogging up the transfer stream (which should prevent any chance of a deadlock bug hanging things up). It also allows [`--debug`](#opt) to enable some extra I/O related messages. - `client` - causes all rsync messages to be sent to the client side via the protocol stream. One client process outputs all messages, with errors on stderr and info messages on stdout. This **was** the default in older rsync versions, but can cause error delays when a lot of transfer data is ahead of the messages. If you're pushing files to an older rsync, you may want to use `--stderr=all` since that idiom has been around for several releases. This option was added in rsync 3.2.3. This version also began the forwarding of a non-default setting to the remote side, though rsync uses the backward-compatible options `--msgs2stderr` and `--no-msgs2stderr` to represent the `all` and `client` settings, respectively. A newer rsync will continue to accept these older option names to maintain compatibility. 0. `--quiet`, `-q` This option decreases the amount of information you are given during the transfer, notably suppressing information messages from the remote server. This option is useful when invoking rsync from cron. 0. `--no-motd` This option affects the information that is output by the client at the start of a daemon transfer. This suppresses the message-of-the-day (MOTD) text, but it also affects the list of modules that the daemon sends in response to the "rsync host::" request (due to a limitation in the rsync protocol), so omit this option if you want to request the list of modules from the daemon. 0. `--ignore-times`, `-I` Normally rsync will skip any files that are already the same size and have the same modification timestamp. This option turns off this "quick check" behavior, causing all files to be updated. This option can be confusing compared to [`--ignore-existing`](#opt) and [`--ignore-non-existing`](#opt) in that that they cause rsync to transfer fewer files, while this option causes rsync to transfer more files. 0. `--size-only` This modifies rsync's "quick check" algorithm for finding files that need to be transferred, changing it from the default of transferring files with either a changed size or a changed last-modified time to just looking for files that have changed in size. This is useful when starting to use rsync after using another mirroring system which may not preserve timestamps exactly. 0. `--modify-window=NUM`, `-@` When comparing two timestamps, rsync treats the timestamps as being equal if they differ by no more than the modify-window value. The default is 0, which matches just integer seconds. If you specify a negative value (and the receiver is at least version 3.1.3) then nanoseconds will also be taken into account. Specifying 1 is useful for copies to/from MS Windows FAT filesystems, because FAT represents times with a 2-second resolution (allowing times to differ from the original by up to 1 second). If you want all your transfers to default to comparing nanoseconds, you can create a `~/.popt` file and put these lines in it: > rsync alias -a -a@-1 > rsync alias -t -t@-1 With that as the default, you'd need to specify `--modify-window=0` (aka `-@0`) to override it and ignore nanoseconds, e.g. if you're copying between ext3 and ext4, or if the receiving rsync is older than 3.1.3. 0. `--checksum`, `-c` This changes the way rsync checks if the files have been changed and are in need of a transfer. Without this option, rsync uses a "quick check" that (by default) checks if each file's size and time of last modification match between the sender and receiver. This option changes this to compare a 128-bit checksum for each file that has a matching size. Generating the checksums means that both sides will expend a lot of disk I/O reading all the data in the files in the transfer, so this can slow things down significantly (and this is prior to any reading that will be done to transfer changed files) The sending side generates its checksums while it is doing the file-system scan that builds the list of the available files. The receiver generates its checksums when it is scanning for changed files, and will checksum any file that has the same size as the corresponding sender's file: files with either a changed size or a changed checksum are selected for transfer. Note that rsync always verifies that each _transferred_ file was correctly reconstructed on the receiving side by checking a whole-file checksum that is generated as the file is transferred, but that automatic after-the-transfer verification has nothing to do with this option's before-the-transfer "Does this file need to be updated?" check. The checksum used is auto-negotiated between the client and the server, but can be overridden using either the [`--checksum-choice`](#opt) (`--cc`) option or an environment variable that is discussed in that option's section. 0. `--archive`, `-a` This is equivalent to `-rlptgoD`. It is a quick way of saying you want recursion and want to preserve almost everything. Be aware that it does **not** include preserving ACLs (`-A`), xattrs (`-X`), atimes (`-U`), crtimes (`-N`), nor the finding and preserving of hardlinks (`-H`). The only exception to the above equivalence is when [`--files-from`](#opt) is specified, in which case [`-r`](#opt) is not implied. 0. `--no-OPTION` You may turn off one or more implied options by prefixing the option name with "no-". Not all positive options have a negated opposite, but a lot do, including those that can be used to disable an implied option (e.g. `--no-D`, `--no-perms`) or have different defaults in various circumstances (e.g. [`--no-whole-file`](#opt), `--no-blocking-io`, `--no-dirs`). Every valid negated option accepts both the short and the long option name after the "no-" prefix (e.g. `--no-R` is the same as `--no-relative`). As an example, if you want to use [`--archive`](#opt) (`-a`) but don't want [`--owner`](#opt) (`-o`), instead of converting `-a` into `-rlptgD`, you can specify `-a --no-o` (aka `--archive --no-owner`). The order of the options is important: if you specify `--no-r -a`, the `-r` option would end up being turned on, the opposite of `-a --no-r`. Note also that the side-effects of the [`--files-from`](#opt) option are NOT positional, as it affects the default state of several options and slightly changes the meaning of [`-a`](#opt) (see the [`--files-from`](#opt) option for more details). 0. `--recursive`, `-r` This tells rsync to copy directories recursively. See also [`--dirs`](#opt) (`-d`) for an option that allows the scanning of a single directory. See the [`--inc-recursive`](#opt) option for a discussion of the incremental recursion for creating the list of files to transfer. 0. `--inc-recursive`, `--i-r` This option explicitly enables on incremental recursion when scanning for files, which is enabled by default when using the [`--recursive`](#opt) option and both sides of the transfer are running rsync 3.0.0 or newer. Incremental recursion uses much less memory than non-incremental, while also beginning the transfer more quickly (since it doesn't need to scan the entire transfer hierarchy before it starts transferring files). If no recursion is enabled in the source files, this option has no effect. Some options require rsync to know the full file list, so these options disable the incremental recursion mode. These include: - [`--delete-before`](#opt) (the old default of [`--delete`](#opt)) - [`--delete-after`](#opt) - [`--prune-empty-dirs`](#opt) - [`--delay-updates`](#opt) In order to make [`--delete`](#opt) compatible with incremental recursion, rsync 3.0.0 made [`--delete-during`](#opt) the default delete mode (which was first added in 2.6.4). One side-effect of incremental recursion is that any missing sub-directories inside a recursively-scanned directory are (by default) created prior to recursing into the sub-dirs. This earlier creation point (compared to a non-incremental recursion) allows rsync to then set the modify time of the finished directory right away (without having to delay that until a bunch of recursive copying has finished). However, these early directories don't yet have their completed mode, mtime, or ownership set -- they have more restrictive rights until the subdirectory's copying actually begins. This early-creation idiom can be avoided by using the [`--omit-dir-times`](#opt) option. Incremental recursion can be disabled using the [`--no-inc-recursive`](#opt) (`--no-i-r`) option. 0. `--no-inc-recursive`, `--no-i-r` Disables the new incremental recursion algorithm of the [`--recursive`](#opt) option. This makes rsync scan the full file list before it begins to transfer files. See [`--inc-recursive`](#opt) for more info. 0. `--relative`, `-R` Use relative paths. This means that the full path names specified on the command line are sent to the server rather than just the last parts of the filenames. This is particularly useful when you want to send several different directories at the same time. For example, if you used this command: > rsync -av /foo/bar/baz.c remote:/tmp/ would create a file named baz.c in /tmp/ on the remote machine. If instead you used > rsync -avR /foo/bar/baz.c remote:/tmp/ then a file named /tmp/foo/bar/baz.c would be created on the remote machine, preserving its full path. These extra path elements are called "implied directories" (i.e. the "foo" and the "foo/bar" directories in the above example). Beginning with rsync 3.0.0, rsync always sends these implied directories as real directories in the file list, even if a path element is really a symlink on the sending side. This prevents some really unexpected behaviors when copying the full path of a file that you didn't realize had a symlink in its path. If you want to duplicate a server-side symlink, include both the symlink via its path, and referent directory via its real path. If you're dealing with an older rsync on the sending side, you may need to use the [`--no-implied-dirs`](#opt) option. It is also possible to limit the amount of path information that is sent as implied directories for each path you specify. With a modern rsync on the sending side (beginning with 2.6.7), you can insert a dot and a slash into the source path, like this: > rsync -avR /foo/./bar/baz.c remote:/tmp/ That would create /tmp/bar/baz.c on the remote machine. (Note that the dot must be followed by a slash, so "/foo/." would not be abbreviated.) For older rsync versions, you would need to use a chdir to limit the source path. For example, when pushing files: > (cd /foo; rsync -avR bar/baz.c remote:/tmp/) (Note that the parens put the two commands into a sub-shell, so that the "cd" command doesn't remain in effect for future commands.) If you're pulling files from an older rsync, use this idiom (but only for a non-daemon transfer): > rsync -avR --rsync-path="cd /foo; rsync" \ > remote:bar/baz.c /tmp/ 0. `--no-implied-dirs` This option affects the default behavior of the [`--relative`](#opt) option. When it is specified, the attributes of the implied directories from the source names are not included in the transfer. This means that the corresponding path elements on the destination system are left unchanged if they exist, and any missing implied directories are created with default attributes. This even allows these implied path elements to have big differences, such as being a symlink to a directory on the receiving side. For instance, if a command-line arg or a files-from entry told rsync to transfer the file "path/foo/file", the directories "path" and "path/foo" are implied when [`--relative`](#opt) is used. If "path/foo" is a symlink to "bar" on the destination system, the receiving rsync would ordinarily delete "path/foo", recreate it as a directory, and receive the file into the new directory. With `--no-implied-dirs`, the receiving rsync updates "path/foo/file" using the existing path elements, which means that the file ends up being created in "path/bar". Another way to accomplish this link preservation is to use the [`--keep-dirlinks`](#opt) option (which will also affect symlinks to directories in the rest of the transfer). When pulling files from an rsync older than 3.0.0, you may need to use this option if the sending side has a symlink in the path you request and you wish the implied directories to be transferred as normal directories. 0. `--backup`, `-b` With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the [`--backup-dir`](#opt) and [`--suffix`](#opt) options. If you don't specify [`--backup-dir`](#opt): 1. the [`--omit-dir-times`](#opt) option will be forced on 2. the use of [`--delete`](#opt) (without [`--delete-excluded`](#opt)), causes rsync to add a "protect" [filter-rule](#FILTER_RULES) for the backup suffix to the end of all your existing filters that looks like this: `-f "P *~"`. This rule prevents previously backed-up files from being deleted. Note that if you are supplying your own filter rules, you may need to manually insert your own exclude/protect rule somewhere higher up in the list so that it has a high enough priority to be effective (e.g. if your rules specify a trailing inclusion/exclusion of `*`, the auto-added rule would never be reached). 0. `--backup-dir=DIR` This implies the [`--backup`](#opt) option, and tells rsync to store all backups in the specified directory on the receiving side. This can be used for incremental backups. You can additionally specify a backup suffix using the [`--suffix`](#opt) option (otherwise the files backed up in the specified directory will keep their original filenames). Note that if you specify a relative path, the backup directory will be relative to the destination directory, so you probably want to specify either an absolute path or a path that starts with "../". If an rsync daemon is the receiver, the backup dir cannot go outside the module's path hierarchy, so take extra care not to delete it or copy into it. 0. `--suffix=SUFFIX` This option allows you to override the default backup suffix used with the [`--backup`](#opt) (`-b`) option. The default suffix is a `~` if no [`--backup-dir`](#opt) was specified, otherwise it is an empty string. 0. `--update`, `-u` This forces rsync to skip any files which exist on the destination and have a modified time that is newer than the source file. (If an existing destination file has a modification time equal to the source file's, it will be updated if the sizes are different.) Note that this does not affect the copying of dirs, symlinks, or other special files. Also, a difference of file format between the sender and receiver is always considered to be important enough for an update, no matter what date is on the objects. In other words, if the source has a directory where the destination has a file, the transfer would occur regardless of the timestamps. This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any exclude side effects. A caution for those that choose to combine [`--inplace`](#opt) with `--update`: an interrupted transfer will leave behind a partial file on the receiving side that has a very recent modified time, so re-running the transfer will probably **not** continue the interrupted file. As such, it is usually best to avoid combining this with[ `--inplace`](#opt) unless you have implemented manual steps to handle any interrupted in-progress files. 0. `--inplace` This option changes how rsync transfers a file when its data needs to be updated: instead of the default method of creating a new copy of the file and moving it into place when it is complete, rsync instead writes the updated data directly to the destination file. This has several effects: - Hard links are not broken. This means the new data will be visible through other hard links to the destination file. Moreover, attempts to copy differing source files onto a multiply-linked destination file will result in a "tug of war" with the destination data changing back and forth. - In-use binaries cannot be updated (either the OS will prevent this from happening, or binaries that attempt to swap-in their data will misbehave or crash). - The file's data will be in an inconsistent state during the transfer and will be left that way if the transfer is interrupted or if an update fails. - A file that rsync cannot write to cannot be updated. While a super user can update any file, a normal user needs to be granted write permission for the open of the file for writing to be successful. - The efficiency of rsync's delta-transfer algorithm may be reduced if some data in the destination file is overwritten before it can be copied to a position later in the file. This does not apply if you use [`--backup`](#opt), since rsync is smart enough to use the backup file as the basis file for the transfer. WARNING: you should not use this option to update files that are being accessed by others, so be careful when choosing to use this for a copy. This option is useful for transferring large files with block-based changes or appended data, and also on systems that are disk bound, not network bound. It can also help keep a copy-on-write filesystem snapshot from diverging the entire contents of a file that only has minor changes. The option implies [`--partial`](#opt) (since an interrupted transfer does not delete the file), but conflicts with [`--partial-dir`](#opt) and [`--delay-updates`](#opt). Prior to rsync 2.6.4 `--inplace` was also incompatible with [`--compare-dest`](#opt) and [`--link-dest`](#opt). 0. `--append` This special copy mode only works to efficiently update files that are known to be growing larger where any existing content on the receiving side is also known to be the same as the content on the sender. The use of `--append` **can be dangerous** if you aren't 100% sure that all the files in the transfer are shared, growing files. You should thus use filter rules to ensure that you weed out any files that do not fit this criteria. Rsync updates these growing file in-place without verifying any of the existing content in the file (it only verifies the content that it is appending). Rsync skips any files that exist on the receiving side that are not shorter than the associated file on the sending side (which means that new files are transferred). It also skips any files whose size on the sending side gets shorter during the send negotiations (rsync warns about a "diminished" file when this happens). This does not interfere with the updating of a file's non-content attributes (e.g. permissions, ownership, etc.) when the file does not need to be transferred, nor does it affect the updating of any directories or non-regular files. 0. `--append-verify` This special copy mode works like [`--append`](#opt) except that all the data in the file is included in the checksum verification (making it less efficient but also potentially safer). This option **can be dangerous** if you aren't 100% sure that all the files in the transfer are shared, growing files. See the [`--append`](#opt) option for more details. Note: prior to rsync 3.0.0, the [`--append`](#opt) option worked like `--append-verify`, so if you are interacting with an older rsync (or the transfer is using a protocol prior to 30), specifying either append option will initiate an `--append-verify` transfer. 0. `--dirs`, `-d` Tell the sending side to include any directories that are encountered. Unlike [`--recursive`](#opt), a directory's contents are not copied unless the directory name specified is "." or ends with a trailing slash (e.g. ".", "dir/.", "dir/", etc.). Without this option or the [`--recursive`](#opt) option, rsync will skip all directories it encounters (and output a message to that effect for each one). If you specify both `--dirs` and [`--recursive`](#opt), `--recursive` takes precedence. The `--dirs` option is implied by the [`--files-from`](#opt) option or the [`--list-only`](#opt) option (including an implied [`--list-only`](#opt) usage) if [`--recursive`](#opt) wasn't specified (so that directories are seen in the listing). Specify `--no-dirs` (or `--no-d`) if you want to turn this off. There is also a backward-compatibility helper option, `--old-dirs` (`--old-d`) that tells rsync to use a hack of `-r --exclude='/*/*'` to get an older rsync to list a single directory without recursing. 0. `--mkpath` Create all missing path components of the destination path. By default, rsync allows only the final component of the destination path to not exist, which is an attempt to help you to validate your destination path. With this option, rsync creates all the missing destination-path components, just as if `mkdir -p $DEST_PATH` had been run on the receiving side. When specifying a destination path, including a trailing slash ensures that the whole path is treated as directory names to be created, even when the file list has a single item. See the [COPYING TO A DIFFERENT NAME](#) section for full details on how rsync decides if a final destination-path component should be created as a directory or not. If you would like the newly-created destination dirs to match the dirs on the sending side, you should be using [`--relative`](#opt) (`-R`) instead of `--mkpath`. For instance, the following two commands result in the same destination tree, but only the second command ensures that the "some/extra/path" components match the dirs on the sending side: > rsync -ai --mkpath host:some/extra/path/*.c some/extra/path/ > rsync -aiR host:some/extra/path/*.c ./ 0. `--links`, `-l` Add symlinks to the transferred files instead of noisily ignoring them with a "non-regular file" warning for each symlink encountered. You can alternately silence the warning by specifying [`--info=nonreg0`](#opt). The default handling of symlinks is to recreate each symlink's unchanged value on the receiving side. See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--copy-links`, `-L` The sender transforms each symlink encountered in the transfer into the referent item, following the symlink chain to the file or directory that it references. If a symlink chain is broken, an error is output and the file is dropped from the transfer. This option supersedes any other options that affect symlinks in the transfer, since there are no symlinks left in the transfer. This option does not change the handling of existing symlinks on the receiving side, unlike versions of rsync prior to 2.6.3 which had the side-effect of telling the receiving side to also follow symlinks. A modern rsync won't forward this option to a remote receiver (since only the sender needs to know about it), so this caveat should only affect someone using an rsync client older than 2.6.7 (which is when `-L` stopped being forwarded to the receiver). See the [`--keep-dirlinks`](#opt) (`-K`) if you need a symlink to a directory to be treated as a real directory on the receiving side. See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--copy-unsafe-links` This tells rsync to copy the referent of symbolic links that point outside the copied tree. Absolute symlinks are also treated like ordinary files, and so are any symlinks in the source path itself when [`--relative`](#opt) is used. Note that the cut-off point is the top of the transfer, which is the part of the path that rsync isn't mentioning in the verbose output. If you copy "/src/subdir" to "/dest/" then the "subdir" directory is a name inside the transfer tree, not the top of the transfer (which is /src) so it is legal for created relative symlinks to refer to other names inside the /src and /dest directories. If you instead copy "/src/subdir/" (with a trailing slash) to "/dest/subdir" that would not allow symlinks to any files outside of "subdir". Note that safe symlinks are only copied if [`--links`](#opt) was also specified or implied. The `--copy-unsafe-links` option has no extra effect when combined with [`--copy-links`](#opt). See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--safe-links` This tells the receiving rsync to ignore any symbolic links in the transfer which point outside the copied tree. All absolute symlinks are also ignored. Since this ignoring is happening on the receiving side, it will still be effective even when the sending side has munged symlinks (when it is using [`--munge-links`](#opt)). It also affects deletions, since the file being present in the transfer prevents any matching file on the receiver from being deleted when the symlink is deemed to be unsafe and is skipped. This option must be combined with [`--links`](#opt) (or [`--archive`](#opt)) to have any symlinks in the transfer to conditionally ignore. Its effect is superseded by [`--copy-unsafe-links`](#opt). Using this option in conjunction with [`--relative`](#opt) may give unexpected results. See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--munge-links` This option affects just one side of the transfer and tells rsync to munge symlink values when it is receiving files or unmunge symlink values when it is sending files. The munged values make the symlinks unusable on disk but allows the original contents of the symlinks to be recovered. The server-side rsync often enables this option without the client's knowledge, such as in an rsync daemon's configuration file or by an option given to the rrsync (restricted rsync) script. When specified on the client side, specify the option normally if it is the client side that has/needs the munged symlinks, or use `-M--munge-links` to give the option to the server when it has/needs the munged symlinks. Note that on a local transfer, the client is the sender, so specifying the option directly unmunges symlinks while specifying it as a remote option munges symlinks. This option has no effect when sent to a daemon via [`--remote-option`](#opt) because the daemon configures whether it wants munged symlinks via its "`munge symlinks`" parameter. The symlink value is munged/unmunged once it is in the transfer, so any option that transforms symlinks into non-symlinks occurs prior to the munging/unmunging **except** for [`--safe-links`](#opt), which is a choice that the receiver makes, so it bases its decision on the munged/unmunged value. This does mean that if a receiver has munging enabled, that using [`--safe-links`](#opt) will cause all symlinks to be ignored (since they are all absolute). The method that rsync uses to munge the symlinks is to prefix each one's value with the string "/rsyncd-munged/". This prevents the links from being used as long as the directory does not exist. When this option is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory (though it only checks at startup). See also the "munge-symlinks" python script in the support directory of the source code for a way to munge/unmunge one or more symlinks in-place. 0. `--copy-dirlinks`, `-k` This option causes the sending side to treat a symlink to a directory as though it were a real directory. This is useful if you don't want symlinks to non-directories to be affected, as they would be using [`--copy-links`](#opt). Without this option, if the sending side has replaced a directory with a symlink to a directory, the receiving side will delete anything that is in the way of the new symlink, including a directory hierarchy (as long as [`--force`](#opt) or [`--delete`](#opt) is in effect). See also [`--keep-dirlinks`](#opt) for an analogous option for the receiving side. `--copy-dirlinks` applies to all symlinks to directories in the source. If you want to follow only a few specified symlinks, a trick you can use is to pass them as additional source args with a trailing slash, using [`--relative`](#opt) to make the paths match up right. For example: > rsync -r --relative src/./ src/./follow-me/ dest/ This works because rsync calls **lstat**(2) on the source arg as given, and the trailing slash makes **lstat**(2) follow the symlink, giving rise to a directory in the file-list which overrides the symlink found during the scan of "src/./". See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--keep-dirlinks`, `-K` This option causes the receiving side to treat a symlink to a directory as though it were a real directory, but only if it matches a real directory from the sender. Without this option, the receiver's symlink would be deleted and replaced with a real directory. For example, suppose you transfer a directory "foo" that contains a file "file", but "foo" is a symlink to directory "bar" on the receiver. Without `--keep-dirlinks`, the receiver deletes symlink "foo", recreates it as a directory, and receives the file into the new directory. With `--keep-dirlinks`, the receiver keeps the symlink and "file" ends up in "bar". One note of caution: if you use `--keep-dirlinks`, you must trust all the symlinks in the copy or enable the [`--munge-links`](#opt) option on the receiving side! If it is possible for an untrusted user to create their own symlink to any real directory, the user could then (on a subsequent copy) replace the symlink with a real directory and affect the content of whatever directory the symlink references. For backup copies, you are better off using something like a bind mount instead of a symlink to modify your receiving hierarchy. See also [`--copy-dirlinks`](#opt) for an analogous option for the sending side. See the [SYMBOLIC LINKS](#) section for multi-option info. 0. `--hard-links`, `-H` This tells rsync to look for hard-linked files in the source and link together the corresponding files on the destination. Without this option, hard-linked files in the source are treated as though they were separate files. This option does NOT necessarily ensure that the pattern of hard links on the destination exactly matches that on the source. Cases in which the destination may end up with extra hard links include the following: - If the destination contains extraneous hard-links (more linking than what is present in the source file list), the copying algorithm will not break them explicitly. However, if one or more of the paths have content differences, the normal file-update process will break those extra links (unless you are using the [`--inplace`](#opt) option). - If you specify a [`--link-dest`](#opt) directory that contains hard links, the linking of the destination files against the [`--link-dest`](#opt) files can cause some paths in the destination to become linked together due to the [`--link-dest`](#opt) associations. Note that rsync can only detect hard links between files that are inside the transfer set. If rsync updates a file that has extra hard-link connections to files outside the transfer, that linkage will be broken. If you are tempted to use the [`--inplace`](#opt) option to avoid this breakage, be very careful that you know how your files are being updated so that you are certain that no unintended changes happen due to lingering hard links (and see the [`--inplace`](#opt) option for more caveats). If incremental recursion is active (see [`--inc-recursive`](#opt)), rsync may transfer a missing hard-linked file before it finds that another link for that contents exists elsewhere in the hierarchy. This does not affect the accuracy of the transfer (i.e. which files are hard-linked together), just its efficiency (i.e. copying the data for a new, early copy of a hard-linked file that could have been found later in the transfer in another member of the hard-linked set of files). One way to avoid this inefficiency is to disable incremental recursion using the [`--no-inc-recursive`](#opt) option. 0. `--perms`, `-p` This option causes the receiving rsync to set the destination permissions to be the same as the source permissions. (See also the [`--chmod`](#opt) option for a way to modify what rsync considers to be the source permissions.) When this option is _off_, permissions are set as follows: - Existing files (including updated files) retain their existing permissions, though the [`--executability`](#opt) option might change just the execute permission for the file. - New files get their "normal" permission bits set to the source file's permissions masked with the receiving directory's default permissions (either the receiving process's umask, or the permissions specified via the destination directory's default ACL), and their special permission bits disabled except in the case where a new directory inherits a setgid bit from its parent directory. Thus, when `--perms` and [`--executability`](#opt) are both disabled, rsync's behavior is the same as that of other file-copy utilities, such as **cp**(1) and **tar**(1). In summary: to give destination files (both old and new) the source permissions, use `--perms`. To give new files the destination-default permissions (while leaving existing files unchanged), make sure that the `--perms` option is off and use [`--chmod=ugo=rwX`](#opt) (which ensures that all non-masked bits get enabled). If you'd care to make this latter behavior easier to type, you could define a popt alias for it, such as putting this line in the file `~/.popt` (the following defines the `-Z` option, and includes `--no-g` to use the default group of the destination dir): > rsync alias -Z --no-p --no-g --chmod=ugo=rwX You could then use this new option in a command such as this one: > rsync -avZ src/ dest/ (Caveat: make sure that `-a` does not follow `-Z`, or it will re-enable the two `--no-*` options mentioned above.) The preservation of the destination's setgid bit on newly-created directories when `--perms` is off was added in rsync 2.6.7. Older rsync versions erroneously preserved the three special permission bits for newly-created files when `--perms` was off, while overriding the destination's setgid bit setting on a newly-created directory. Default ACL observance was added to the ACL patch for rsync 2.6.7, so older (or non-ACL-enabled) rsyncs use the umask even if default ACLs are present. (Keep in mind that it is the version of the receiving rsync that affects these behaviors.) 0. `--executability`, `-E` This option causes rsync to preserve the executability (or non-executability) of regular files when [`--perms`](#opt) is not enabled. A regular file is considered to be executable if at least one 'x' is turned on in its permissions. When an existing destination file's executability differs from that of the corresponding source file, rsync modifies the destination file's permissions as follows: - To make a file non-executable, rsync turns off all its 'x' permissions. - To make a file executable, rsync turns on each 'x' permission that has a corresponding 'r' permission enabled. If [`--perms`](#opt) is enabled, this option is ignored. 0. `--acls`, `-A` This option causes rsync to update the destination ACLs to be the same as the source ACLs. The option also implies [`--perms`](#opt). The source and destination systems must have compatible ACL entries for this option to work properly. See the [`--fake-super`](#opt) option for a way to backup and restore ACLs that are not compatible. 0. `--xattrs`, `-X` This option causes rsync to update the destination extended attributes to be the same as the source ones. For systems that support extended-attribute namespaces, a copy being done by a super-user copies all namespaces except system.\*. A normal user only copies the user.\* namespace. To be able to backup and restore non-user namespaces as a normal user, see the [`--fake-super`](#opt) option. The above name filtering can be overridden by using one or more filter options with the **x** modifier. When you specify an xattr-affecting filter rule, rsync requires that you do your own system/user filtering, as well as any additional filtering for what xattr names are copied and what names are allowed to be deleted. For example, to skip the system namespace, you could specify: > --filter='-x system.*' To skip all namespaces except the user namespace, you could specify a negated-user match: > --filter='-x! user.*' To prevent any attributes from being deleted, you could specify a receiver-only rule that excludes all names: > --filter='-xr *' Note that the `-X` option does not copy rsync's special xattr values (e.g. those used by [`--fake-super`](#opt)) unless you repeat the option (e.g. `-XX`). This "copy all xattrs" mode cannot be used with [`--fake-super`](#opt). 0. `--chmod=CHMOD` This option tells rsync to apply one or more comma-separated "chmod" modes to the permission of the files in the transfer. The resulting value is treated as though it were the permissions that the sending side supplied for the file, which means that this option can seem to have no effect on existing files if [`--perms`](#opt) is not enabled. In addition to the normal parsing rules specified in the **chmod**(1) manpage, you can specify an item that should only apply to a directory by prefixing it with a 'D', or specify an item that should only apply to a file by prefixing it with a 'F'. For example, the following will ensure that all directories get marked set-gid, that no files are other-writable, that both are user-writable and group-writable, and that both have consistent executability across all bits: > --chmod=Dg+s,ug+w,Fo-w,+X Using octal mode numbers is also allowed: > --chmod=D2775,F664 It is also legal to specify multiple `--chmod` options, as each additional option is just appended to the list of changes to make. See the [`--perms`](#opt) and [`--executability`](#opt) options for how the resulting permission value can be applied to the files in the transfer. 0. `--owner`, `-o` This option causes rsync to set the owner of the destination file to be the same as the source file, but only if the receiving rsync is being run as the super-user (see also the [`--super`](#opt) and [`--fake-super`](#opt) options). Without this option, the owner of new and/or transferred files are set to the invoking user on the receiving side. The preservation of ownership will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the [`--numeric-ids`](#opt) option for a full discussion). 0. `--group`, `-g` This option causes rsync to set the group of the destination file to be the same as the source file. If the receiving program is not running as the super-user (or if `--no-super` was specified), only groups that the invoking user on the receiving side is a member of will be preserved. Without this option, the group is set to the default group of the invoking user on the receiving side. The preservation of group information will associate matching names by default, but may fall back to using the ID number in some circumstances (see also the [`--numeric-ids`](#opt) option for a full discussion). 0. `--devices` This option causes rsync to transfer character and block device files to the remote system to recreate these devices. If the receiving rsync is not being run as the super-user, rsync silently skips creating the device files (see also the [`--super`](#opt) and [`--fake-super`](#opt) options). By default, rsync generates a "non-regular file" warning for each device file encountered when this option is not set. You can silence the warning by specifying [`--info=nonreg0`](#opt). 0. `--specials` This option causes rsync to transfer special files, such as named sockets and fifos. If the receiving rsync is not being run as the super-user, rsync silently skips creating the special files (see also the [`--super`](#opt) and [`--fake-super`](#opt) options). By default, rsync generates a "non-regular file" warning for each special file encountered when this option is not set. You can silence the warning by specifying [`--info=nonreg0`](#opt). 0. `-D` The `-D` option is equivalent to "[`--devices`](#opt) [`--specials`](#opt)". 0. `--copy-devices` This tells rsync to treat a device on the sending side as a regular file, allowing it to be copied to a normal destination file (or another device if `--write-devices` was also specified). This option is refused by default by an rsync daemon. 0. `--write-devices` This tells rsync to treat a device on the receiving side as a regular file, allowing the writing of file data into a device. This option implies the [`--inplace`](#opt) option. Be careful using this, as you should know what devices are present on the receiving side of the transfer, especially when running rsync as root. This option is refused by default by an rsync daemon. 0. `--times`, `-t` This tells rsync to transfer modification times along with the files and update them on the remote system. Note that if this option is not used, the optimization that excludes files that have not been modified cannot be effective; in other words, a missing `-t` (or [`-a`](#opt)) will cause the next transfer to behave as if it used [`--ignore-times`](#opt) (`-I`), causing all files to be updated (though rsync's delta-transfer algorithm will make the update fairly efficient if the files haven't actually changed, you're much better off using `-t`). A modern rsync that is using transfer protocol 30 or 31 conveys a modify time using up to 8-bytes. If rsync is forced to speak an older protocol (perhaps due to the remote rsync being older than 3.0.0) a modify time is conveyed using 4-bytes. Prior to 3.2.7, these shorter values could convey a date range of 13-Dec-1901 to 19-Jan-2038. Beginning with 3.2.7, these 4-byte values now convey a date range of 1-Jan-1970 to 7-Feb-2106. If you have files dated older than 1970, make sure your rsync executables are upgraded so that the full range of dates can be conveyed. 0. `--atimes`, `-U` This tells rsync to set the access (use) times of the destination files to the same value as the source files. If repeated, it also sets the [`--open-noatime`](#opt) option, which can help you to make the sending and receiving systems have the same access times on the transferred files without needing to run rsync an extra time after a file is transferred. Note that some older rsync versions (prior to 3.2.0) may have been built with a pre-release `--atimes` patch that does not imply [`--open-noatime`](#opt) when this option is repeated. 0. `--open-noatime` This tells rsync to open files with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred. If your OS does not support the O_NOATIME flag then rsync will silently ignore this option. Note also that some filesystems are mounted to avoid updating the atime on read access even without the O_NOATIME flag being set. 0. `--crtimes`, `-N,` This tells rsync to set the create times (newness) of the destination files to the same value as the source files. 0. `--omit-dir-times`, `-O` This tells rsync to omit directories when it is preserving modification, access, and create times. If NFS is sharing the directories on the receiving side, it is a good idea to use `-O`. This option is inferred if you use [`--backup`](#opt) without [`--backup-dir`](#opt). This option also has the side-effect of avoiding early creation of missing sub-directories when incremental recursion is enabled, as discussed in the [`--inc-recursive`](#opt) section. 0. `--omit-link-times`, `-J` This tells rsync to omit symlinks when it is preserving modification, access, and create times. 0. `--super` This tells the receiving side to attempt super-user activities even if the receiving rsync wasn't run by the super-user. These activities include: preserving users via the [`--owner`](#opt) option, preserving all groups (not just the current user's groups) via the [`--group`](#opt) option, and copying devices via the [`--devices`](#opt) option. This is useful for systems that allow such activities without being the super-user, and also for ensuring that you will get errors if the receiving side isn't being run as the super-user. To turn off super-user activities, the super-user can use `--no-super`. 0. `--fake-super` When this option is enabled, rsync simulates super-user activities by saving/restoring the privileged attributes via special extended attributes that are attached to each file (as needed). This includes the file's owner and group (if it is not the default), the file's device info (device & special files are created as empty text files), and any permission bits that we won't allow to be set on the real file (e.g. the real file gets u-s,g-s,o-t for safety) or that would limit the owner's access (since the real super-user can always access/change a file, the files we create can always be accessed/changed by the creating user). This option also handles ACLs (if [`--acls`](#opt) was specified) and non-user extended attributes (if [`--xattrs`](#opt) was specified). This is a good way to backup data without using a super-user, and to store ACLs from incompatible systems. The `--fake-super` option only affects the side where the option is used. To affect the remote side of a remote-shell connection, use the [`--remote-option`](#opt) (`-M`) option: > rsync -av -M--fake-super /src/ host:/dest/ 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 `-M--fake-super`. If you wish a local copy to enable this option just for the source files, combine `--fake-super` with `-M--super`. This option is overridden by both [`--super`](#opt) and `--no-super`. See also the [`fake super`](rsyncd.conf.5#fake_super) setting in the daemon's rsyncd.conf file. 0. `--sparse`, `-S` Try to handle sparse files efficiently so they take up less space on the destination. If combined with [`--inplace`](#opt) the file created might not end up with sparse blocks with some combinations of kernel version and/or filesystem type. If [`--whole-file`](#opt) is in effect (e.g. for a local copy) then it will always work because rsync truncates the file prior to writing out the updated version. Note that versions of rsync older than 3.1.3 will reject the combination of `--sparse` and [`--inplace`](#opt). 0. `--preallocate` This tells the receiver to allocate each destination file to its eventual size before writing data to the file. Rsync will only use the real filesystem-level preallocation support provided by Linux's **fallocate**(2) system call or Cygwin's **posix_fallocate**(3), not the slow glibc implementation that writes a null byte into each block. Without this option, larger files may not be entirely contiguous on the filesystem, but with this option rsync will probably copy more slowly. If the destination is not an extent-supporting filesystem (such as ext4, xfs, NTFS, etc.), this option may have no positive effect at all. If combined with [`--sparse`](#opt), the file will only have sparse blocks (as opposed to allocated sequences of null bytes) if the kernel version and filesystem type support creating holes in the allocated data. 0. `--dry-run`, `-n` This makes rsync perform a trial run that doesn't make any changes (and produces mostly the same output as a real run). It is most commonly used in combination with the [`--verbose`](#opt) (`-v`) and/or [`--itemize-changes`](#opt) (`-i`) options to see what an rsync command is going to do before one actually runs it. The output of [`--itemize-changes`](#opt) is supposed to be exactly the same on a dry run and a subsequent real run (barring intentional trickery and system call failures); if it isn't, that's a bug. Other output should be mostly unchanged, but may differ in some areas. Notably, a dry run does not send the actual data for file transfers, so [`--progress`](#opt) has no effect, the "bytes sent", "bytes received", "literal data", and "matched data" statistics are too small, and the "speedup" value is equivalent to a run where no file transfers were needed. 0. `--whole-file`, `-W` This option disables rsync's delta-transfer algorithm, which causes all transferred files to be sent whole. The transfer may be faster if this option is used when the bandwidth between the source and destination machines is higher than the bandwidth to disk (especially when the "disk" is actually a networked filesystem). This is the default when both the source and destination are specified as local paths, but only if no batch-writing option is in effect. 0. `--no-whole-file`, `--no-W` Disable whole-file updating when it is enabled by default for a local transfer. This usually slows rsync down, but it can be useful if you are trying to minimize the writes to the destination file (if combined with [`--inplace`](#opt)) or for testing the checksum-based update algorithm. See also the [`--whole-file`](#opt) option. 0. `--checksum-choice=STR`, `--cc=STR` This option overrides the checksum algorithms. If one algorithm name is specified, it is used for both the transfer checksums and (assuming [`--checksum`](#opt) is specified) the pre-transfer checksums. If two comma-separated names are supplied, the first name affects the transfer checksums, and the second name affects the pre-transfer checksums (`-c`). The checksum options that you may be able to use are: - `auto` (the default automatic choice) - `xxh128` - `xxh3` - `xxh64` (aka `xxhash`) - `md5` - `md4` - `sha1` - `none` Run `rsync --version` to see the default checksum list compiled into your version (which may differ from the list above). If "none" is specified for the first (or only) name, the [`--whole-file`](#opt) option is forced on and no checksum verification is performed on the transferred data. If "none" is specified for the second (or only) name, the [`--checksum`](#opt) option cannot be used. The "auto" option is the default, where rsync bases its algorithm choice on a negotiation between the client and the server as follows: When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common checksum choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, a value is chosen based on the protocol version (which chooses between MD5 and various flavors of MD4 based on protocol age). The default order can be customized by setting the environment variable [`RSYNC_CHECKSUM_LIST`](#) to a space-separated list of acceptable checksum names. If the string contains a "`&`" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default checksum list is used. This method does not allow you to specify the transfer checksum separately from the pre-transfer checksum, and it discards "auto" and all unknown checksum names. A list with only invalid names results in a failed negotiation. The use of the `--checksum-choice` option overrides this environment list. 0. `--one-file-system`, `-x` This tells rsync to avoid crossing a filesystem boundary when recursing. This does not limit the user's ability to specify items to copy from multiple filesystems, just rsync's recursion through the hierarchy of each directory that the user specified, and also the analogous recursion on the receiving side during deletion. Also keep in mind that rsync treats a "bind" mount to the same device as being on the same filesystem. If this option is repeated, rsync omits all mount-point directories from the copy. Otherwise, it includes an empty directory at each mount-point it encounters (using the attributes of the mounted directory because those of the underlying mount-point directory are inaccessible). If rsync has been told to collapse symlinks (via [`--copy-links`](#opt) or [`--copy-unsafe-links`](#opt)), a symlink to a directory on another device is treated like a mount-point. Symlinks to non-directories are unaffected by this option. 0. `--ignore-non-existing`, `--existing` This tells rsync to skip creating files (including directories) that do not exist yet on the destination. If this option is combined with the [`--ignore-existing`](#opt) option, no files will be updated (which can be useful if all you want to do is delete extraneous files). This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any exclude side effects. 0. `--ignore-existing` This tells rsync to skip updating files that already exist on the destination (this does _not_ ignore existing directories, or nothing would get done). See also [`--ignore-non-existing`](#opt). This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any exclude side effects. This option can be useful for those doing backups using the [`--link-dest`](#opt) option when they need to continue a backup run that got interrupted. Since a [`--link-dest`](#opt) run is copied into a new directory hierarchy (when it is used properly), using [`--ignore-existing` will ensure that the already-handled files don't get tweaked (which avoids a change in permissions on the hard-linked files). This does mean that this option is only looking at the existing files in the destination hierarchy itself. When [`--info=skip2`](#opt) is used rsync will output "FILENAME exists (INFO)" messages where the INFO indicates one of "type change", "sum change" (requires [`-c`](#opt)), "file change" (based on the quick check), "attr change", or "uptodate". Using [`--info=skip1`](#opt) (which is also implied by 2 [`-v`](#opt) options) outputs the exists message without the INFO suffix. 0. `--remove-source-files` This tells rsync to remove from the sending side the files (meaning non-directories) that are a part of the transfer and have been successfully duplicated on the receiving side. Note that you should only use this option on source files that are quiescent. If you are using this to move files that show up in a particular directory over to another host, make sure that the finished files get renamed into the source directory, not directly written into it, so that rsync can't possibly transfer a file that is not yet fully written. If you can't first write the files into a different directory, you should use a naming idiom that lets rsync avoid transferring files that are not yet finished (e.g. name the file "foo.new" when it is written, rename it to "foo" when it is done, and then use the option [`--exclude='*.new'`](#opt) for the rsync transfer). Starting with 3.1.0, rsync will skip the sender-side removal (and output an error) if the file's size or modify time has not stayed unchanged. Starting with 3.2.6, a local rsync copy will ensure that the sender does not remove a file the receiver just verified, such as when the user accidentally makes the source and destination directory the same path. 0. `--delete` This tells rsync to delete extraneous files from the receiving side (ones that aren't on the sending side), but only for the directories that are being synchronized. You must have asked rsync to send the whole directory (e.g. "`dir`" or "`dir/`") without using a wildcard for the directory's contents (e.g. "`dir/*`") since the wildcard is expanded by the shell and rsync thus gets a request to transfer individual files, not the files' parent directory. Files that are excluded from the transfer are also excluded from being deleted unless you use the [`--delete-excluded`](#opt) option or mark the rules as only matching on the sending side (see the include/exclude modifiers in the [FILTER RULES](#) section). Prior to rsync 2.6.7, this option would have no effect unless [`--recursive`](#opt) was enabled. Beginning with 2.6.7, deletions will also occur when [`--dirs`](#opt) (`-d`) is enabled, but only for directories whose contents are being copied. This option can be dangerous if used incorrectly! It is a very good idea to first try a run using the [`--dry-run`](#opt) (`-n`) option to see what files are going to be deleted. If the sending side detects any I/O errors, then the deletion of any files at the destination will be automatically disabled. This is to prevent temporary filesystem failures (such as NFS errors) on the sending side from causing a massive deletion of files on the destination. You can override this with the [`--ignore-errors`](#opt) option. The `--delete` option may be combined with one of the --delete-WHEN options without conflict, as well as [`--delete-excluded`](#opt). However, if none of the `--delete-WHEN` options are specified, rsync will choose the [`--delete-during`](#opt) algorithm when talking to rsync 3.0.0 or newer, or the [`--delete-before`](#opt) algorithm when talking to an older rsync. See also [`--delete-delay`](#opt) and [`--delete-after`](#opt). 0. `--delete-before` Request that the file-deletions on the receiving side be done before the transfer starts. See [`--delete`](#opt) (which is implied) for more details on file-deletion. Deleting before the transfer is helpful if the filesystem is tight for space and removing extraneous files would help to make the transfer possible. However, it does introduce a delay before the start of the transfer, and this delay might cause the transfer to timeout (if [`--timeout`](#opt) was specified). It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see [`--recursive`](#opt)). 0. `--delete-during`, `--del` Request that the file-deletions on the receiving side be done incrementally as the transfer happens. The per-directory delete scan is done right before each directory is checked for updates, so it behaves like a more efficient [`--delete-before`](#opt), including doing the deletions prior to any per-directory filter files being updated. This option was first added in rsync version 2.6.4. See [`--delete`](#opt) (which is implied) for more details on file-deletion. 0. `--delete-delay` Request that the file-deletions on the receiving side be computed during the transfer (like [`--delete-during`](#opt)), and then removed after the transfer completes. This is useful when combined with [`--delay-updates`](#opt) and/or [`--fuzzy`](#opt), and is more efficient than using [`--delete-after`](#opt) (but can behave differently, since [`--delete-after`](#opt) computes the deletions in a separate pass after all updates are done). If the number of removed files overflows an internal buffer, a temporary file will be created on the receiving side to hold the names (it is removed while open, so you shouldn't see it during the transfer). If the creation of the temporary file fails, rsync will try to fall back to using [`--delete-after`](#opt) (which it cannot do if [`--recursive`](#opt) is doing an incremental scan). See [`--delete`](#opt) (which is implied) for more details on file-deletion. 0. `--delete-after` Request that the file-deletions on the receiving side be done after the transfer has completed. This is useful if you are sending new per-directory merge files as a part of the transfer and you want their exclusions to take effect for the delete phase of the current transfer. It also forces rsync to use the old, non-incremental recursion algorithm that requires rsync to scan all the files in the transfer into memory at once (see [`--recursive`](#opt)). See [`--delete`](#opt) (which is implied) for more details on file-deletion. See also the [`--delete-delay`](#opt) option that might be a faster choice for those that just want the deletions to occur at the end of the transfer. 0. `--delete-excluded` This option turns any unqualified exclude/include rules into server-side rules that do not affect the receiver's deletions. By default, an exclude or include has both a server-side effect (to "hide" and "show" files when building the server's file list) and a receiver-side effect (to "protect" and "risk" files when deletions are occurring). Any rule that has no modifier to specify what sides it is executed on will be instead treated as if it were a server-side rule only, avoiding any "protect" effects of the rules. A rule can still apply to both sides even with this option specified if the rule is given both the sender & receiver modifier letters (e.g., `-f'-sr foo'`). Receiver-side protect/risk rules can also be explicitly specified to limit the deletions. This saves you from having to edit a bunch of `-f'- foo'` rules into `-f'-s foo'` (aka `-f'H foo'`) rules (not to mention the corresponding includes). See the [FILTER RULES](#) section for more information. See [`--delete`](#opt) (which is implied) for more details on deletion. 0. `--ignore-missing-args` When rsync is first processing the explicitly requested source files (e.g. command-line arguments or [`--files-from`](#opt) entries), it is normally an error if the file cannot be found. This option suppresses that error, and does not try to transfer the file. This does not affect subsequent vanished-file errors if a file was initially found to be present and later is no longer there. 0. `--delete-missing-args` This option takes the behavior of the (implied) [`--ignore-missing-args`](#opt) option a step farther: each missing arg will become a deletion request of the corresponding destination file on the receiving side (should it exist). If the destination file is a non-empty directory, it will only be successfully deleted if [`--force`](#opt) or [`--delete`](#opt) are in effect. Other than that, this option is independent of any other type of delete processing. The missing source files are represented by special file-list entries which display as a "`*missing`" entry in the [`--list-only`](#opt) output. 0. `--ignore-errors` Tells [`--delete`](#opt) to go ahead and delete files even when there are I/O errors. 0. `--force` This option tells rsync to delete a non-empty directory when it is to be replaced by a non-directory. This is only relevant if deletions are not active (see [`--delete`](#opt) for details). Note for older rsync versions: `--force` used to still be required when using [`--delete-after`](#opt), and it used to be non-functional unless the [`--recursive`](#opt) option was also enabled. 0. `--max-delete=NUM` This tells rsync not to delete more than NUM files or directories. If that limit is exceeded, all further deletions are skipped through the end of the transfer. At the end, rsync outputs a warning (including a count of the skipped deletions) and exits with an error code of 25 (unless some more important error condition also occurred). Beginning with version 3.0.0, you may specify `--max-delete=0` to be warned about any extraneous files in the destination without removing any of them. Older clients interpreted this as "unlimited", so if you don't know what version the client is, you can use the less obvious `--max-delete=-1` as a backward-compatible way to specify that no deletions be allowed (though really old versions didn't warn when the limit was exceeded). 0. `--max-size=SIZE` This tells rsync to avoid transferring any file that is larger than the specified SIZE. A numeric value can be suffixed with a string to indicate the numeric units or left unqualified to specify bytes. Feel free to use a fractional value along with the units, such as `--max-size=1.5m`. This option is a [TRANSFER RULE](#TRANSFER_RULES), so don't expect any exclude side effects. The first letter of a units string can be `B` (bytes), `K` (kilo), `M` (mega), `G` (giga), `T` (tera), or `P` (peta). If the string is a single char or has "ib" added to it (e.g. "G" or "GiB") then the units are multiples of 1024. If you use a two-letter suffix that ends with a "B" (e.g. "kb") then you get units that are multiples of 1000. The string's letters can be any mix of upper and lower-case that you want to use. Finally, if the string ends with either "+1" or "-1", it is offset by one byte in the indicated direction. The largest possible value is usually `8192P-1`. Examples: `--max-size=1.5mb-1` is 1499999 bytes, and `--max-size=2g+1` is 2147483649 bytes. Note that rsync versions prior to 3.1.0 did not allow `--max-size=0`. 0. `--min-size=SIZE` This tells rsync to avoid transferring any file that is smaller than the specified SIZE, which can help in not transferring small, junk files. See the [`--max-size`](#opt) option for a description of SIZE and other info. Note that rsync versions prior to 3.1.0 did not allow `--min-size=0`. 0. `--max-alloc=SIZE` By default rsync limits an individual malloc/realloc to about 1GB in size. For most people this limit works just fine and prevents a protocol error causing rsync to request massive amounts of memory. However, if you have many millions of files in a transfer, a large amount of server memory, and you don't want to split up your transfer into multiple parts, you can increase the per-allocation limit to something larger and rsync will consume more memory. Keep in mind that this is not a limit on the total size of allocated memory. It is a sanity-check value for each individual allocation. See the [`--max-size`](#opt) option for a description of how SIZE can be specified. The default suffix if none is given is bytes. Beginning in 3.2.3, a value of 0 specifies no limit. You can set a default value using the environment variable [`RSYNC_MAX_ALLOC`](#) using the same SIZE values as supported by this option. If the remote rsync doesn't understand the `--max-alloc` option, you can override an environmental value by specifying `--max-alloc=1g`, which will make rsync avoid sending the option to the remote side (because "1G" is the default). 0. `--block-size=SIZE`, `-B` This forces the block size used in rsync's delta-transfer algorithm to a fixed value. It is normally selected based on the size of each file being updated. See the technical report for details. Beginning in 3.2.3 the SIZE can be specified with a suffix as detailed in the [`--max-size`](#opt) option. Older versions only accepted a byte count. 0. `--rsh=COMMAND`, `-e` This option allows you to choose an alternative remote shell program to use for communication between the local and remote copies of rsync. Typically, rsync is configured to use ssh by default, but you may prefer to use rsh on a local network. If this option is used with `[user@]host::module/path`, then the remote shell _COMMAND_ will be used to run an rsync daemon on the remote host, and all data will be transmitted through that remote shell connection, rather than through a direct socket connection to a running rsync daemon on the remote host. See the [USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION](#) section above. Beginning with rsync 3.2.0, the [`RSYNC_PORT`](#) environment variable will be set when a daemon connection is being made via a remote-shell connection. It is set to 0 if the default daemon port is being assumed, or it is set to the value of the rsync port that was specified via either the [`--port`](#opt) option or a non-empty port value in an `rsync://` URL. This allows the script to discern if a non-default port is being requested, allowing for things such as an SSL or stunnel helper script to connect to a default or alternate port. Command-line arguments are permitted in COMMAND provided that COMMAND is presented to rsync as a single argument. You must use spaces (not tabs or other whitespace) to separate the command and args from each other, and you can use single- and/or double-quotes to preserve spaces in an argument (but not backslashes). Note that doubling a single-quote inside a single-quoted string gives you a single-quote; likewise for double-quotes (though you need to pay attention to which quotes your shell is parsing and which quotes rsync is parsing). Some examples: > -e 'ssh -p 2234' > -e 'ssh -o "ProxyCommand nohup ssh firewall nc -w1 %h %p"' (Note that ssh users can alternately customize site-specific connect options in their .ssh/config file.) You can also choose the remote shell program using the [`RSYNC_RSH`](#) environment variable, which accepts the same range of values as `-e`. See also the [`--blocking-io`](#opt) option which is affected by this option. 0. `--rsync-path=PROGRAM` Use this to specify what program is to be run on the remote machine to start-up rsync. Often used when rsync is not in the default remote-shell's path (e.g. `--rsync-path=/usr/local/bin/rsync`). Note that PROGRAM is run with the help of a shell, so it can be any program, script, or command sequence you'd care to run, so long as it does not corrupt the standard-in & standard-out that rsync is using to communicate. One tricky example is to set a different default directory on the remote machine for use with the [`--relative`](#opt) option. For instance: > rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/ 0. `--remote-option=OPTION`, `-M` This option is used for more advanced situations where you want certain effects to be limited to one side of the transfer only. For instance, if you want to pass [`--log-file=FILE`](#opt) and [`--fake-super`](#opt) to the remote system, specify it like this: > rsync -av -M --log-file=foo -M--fake-super src/ dest/ If you want to have an option affect only the local side of a transfer when it normally affects both sides, send its negation to the remote side. Like this: > rsync -av -x -M--no-x src/ dest/ Be cautious using this, as it is possible to toggle an option that will cause rsync to have a different idea about what data to expect next over the socket, and that will make it fail in a cryptic fashion. Note that you should use a separate `-M` option for each remote option you want to pass. On older rsync versions, the presence of any spaces in the remote-option arg could cause it to be split into separate remote args, but this requires the use of [`--old-args`](#opt) in a modern rsync. When performing a local transfer, the "local" side is the sender and the "remote" side is the receiver. Note some versions of the popt option-parsing library have a bug in them that prevents you from using an adjacent arg with an equal in it next to a short option letter (e.g. `-M--log-file=/tmp/foo`). If this bug affects your version of popt, you can use the version of popt that is included with rsync. 0. `--cvs-exclude`, `-C` 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 a file should be ignored. The exclude list is initialized to exclude the following items (these initial items are marked as perishable -- see the [FILTER RULES](#) section): [comment]: # (This list gets used for the default-cvsignore.h file.) > `RCS` > `SCCS` > `CVS` > `CVS.adm` > `RCSLOG` > `cvslog.*` > `tags` > `TAGS` > `.make.state` > `.nse_depinfo` > `*~` > `#*` > `.#*` > `,*` > `_$*` > `*$` > `*.old` > `*.bak` > `*.BAK` > `*.orig` > `*.rej` > `.del-*` > `*.a` > `*.olb` > `*.o` > `*.obj` > `*.so` > `*.exe` > `*.Z` > `*.elc` > `*.ln` > `core` > `.svn/` > `.git/` > `.hg/` > `.bzr/` then, files listed in a $HOME/.cvsignore are added to the list and any files listed in the CVSIGNORE environment variable (all cvsignore names are delimited by whitespace). Finally, any file is ignored if it is in the same directory as a .cvsignore file and matches one of the patterns listed therein. Unlike rsync's filter/exclude files, these patterns are split on whitespace. See the **cvs**(1) manual for more information. If you're combining `-C` with your own [`--filter`](#opt) rules, you should note that these CVS excludes are appended at the end of your own rules, regardless of where the `-C` was placed on the command-line. This makes them a lower priority than any rules you specified explicitly. If you want to control where these CVS excludes get inserted into your filter rules, you should omit the `-C` as a command-line option and use a combination of [`--filter=:C`](#opt) and [`--filter=-C`](#opt) (either on your command-line or by putting the ":C" and "-C" rules into a filter file with your other rules). The first option turns on the per-directory scanning for the .cvsignore file. The second option does a one-time import of the CVS excludes mentioned above. 0. `--filter=RULE`, `-f` This option allows you to add rules to selectively exclude certain files from the list of files to be transferred. This is most useful in combination with a recursive transfer. You may use as many `--filter` options on the command line as you like to build up the list of files to exclude. If the filter contains whitespace, be sure to quote it so that the shell gives the rule to rsync as a single argument. The text below also mentions that you can use an underscore to replace the space that separates a rule from its arg. See the [FILTER RULES](#) section for detailed information on this option. 0. `-F` The `-F` option is a shorthand for adding two [`--filter`](#opt) rules to your command. The first time it is used is a shorthand for this rule: > --filter='dir-merge /.rsync-filter' This tells rsync to look for per-directory .rsync-filter files that have been sprinkled through the hierarchy and use their rules to filter the files in the transfer. If `-F` is repeated, it is a shorthand for this rule: > --filter='exclude .rsync-filter' This filters out the .rsync-filter files themselves from the transfer. See the [FILTER RULES](#) section for detailed information on how these options work. 0. `--exclude=PATTERN` This option is a simplified form of the [`--filter`](#opt) option that specifies an exclude rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying `-f'- PATTERN'`. See the [FILTER RULES](#) section for detailed information on this option. 0. `--exclude-from=FILE` This option is related to the [`--exclude`](#opt) option, but it specifies a FILE that contains exclude patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with '`;`' or '`#`' (filename rules that contain those characters are unaffected). If a line begins with "`- `" (dash, space) or "`+ `" (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an exclude. If a line consists of just "`!`", then the current filter rules are cleared before adding any further rules. If _FILE_ is '`-`', the list will be read from standard input. 0. `--include=PATTERN` This option is a simplified form of the [`--filter`](#opt) option that specifies an include rule and does not allow the full rule-parsing syntax of normal filter rules. This is equivalent to specifying `-f'+ PATTERN'`. See the [FILTER RULES](#) section for detailed information on this option. 0. `--include-from=FILE` This option is related to the [`--include`](#opt) option, but it specifies a FILE that contains include patterns (one per line). Blank lines in the file are ignored, as are whole-line comments that start with '`;`' or '`#`' (filename rules that contain those characters are unaffected). If a line begins with "`- `" (dash, space) or "`+ `" (plus, space), then the type of rule is being explicitly specified as an exclude or an include (respectively). Any rules without such a prefix are taken to be an include. If a line consists of just "`!`", then the current filter rules are cleared before adding any further rules. If _FILE_ is '`-`', the list will be read from standard input. 0. `--files-from=FILE` Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or '`-`' for standard input). It also tweaks the default behavior of rsync to make transferring just the specified files and directories easier: - The [`--relative`](#opt) (`-R`) option is implied, which preserves the path information that is specified for each item in the file (use `--no-relative` or `--no-R` if you want to turn that off). - The [`--dirs`](#opt) (`-d`) option is implied, which will create directories specified in the list on the destination rather than noisily skipping them (use `--no-dirs` or `--no-d` if you want to turn that off). - The [`--archive`](#opt) (`-a`) option's behavior does not imply [`--recursive`](#opt) (`-r`), so specify it explicitly, if you want it. - These side-effects change the default state of rsync, so the position of the `--files-from` option on the command-line has no bearing on how other options are parsed (e.g. [`-a`](#opt) works the same before or after `--files-from`, as does `--no-R` and all other options). The filenames that are read from the FILE are all relative to the source dir -- any leading slashes are removed and no ".." references are allowed to go higher than the source dir. For example, take this command: > rsync -a --files-from=/tmp/foo /usr remote:/backup If /tmp/foo contains the string "bin" (or even "/bin"), the /usr/bin directory will be created as /backup/bin on the remote host. If it contains "bin/" (note the trailing slash), the immediate contents of the directory would also be sent (without needing to be explicitly mentioned in the file -- this began in version 2.6.4). In both cases, if the [`-r`](#opt) option was enabled, that dir's entire hierarchy would also be transferred (keep in mind that [`-r`](#opt) needs to be specified explicitly with `--files-from`, since it is not implied by [`-a`](#opt). Also note that the effect of the (enabled by default) [`-r`](#opt) option is to duplicate only the path info that is read from the file -- it does not force the duplication of the source-spec path (/usr in this case). In addition, the `--files-from` file can be read from the remote host instead of the local host if you specify a "host:" in front of the file (the host must match one end of the transfer). As a short-cut, you can specify just a prefix of ":" to mean "use the remote end of the transfer". For example: > rsync -a --files-from=:/path/file-list src:/ /tmp/copy This would copy all the files specified in the /path/file-list file that was located on the remote "src" host. If the [`--iconv`](#opt) and [`--secluded-args`](#opt) options are specified and the `--files-from` filenames are being sent from one host to another, the filenames will be translated from the sending host's charset to the receiving host's charset. NOTE: sorting the list of files in the `--files-from` input helps rsync to be more efficient, as it will avoid re-visiting the path elements that are shared between adjacent entries. If the input is not sorted, some path elements (implied directories) may end up being scanned multiple times, and rsync will eventually unduplicate them after they get turned into file-list elements. 0. `--from0`, `-0` This tells rsync that the rules/filenames it reads from a file are terminated by a null ('\\0') character, not a NL, CR, or CR+LF. This affects [`--exclude-from`](#opt), [`--include-from`](#opt), [`--files-from`](#opt), and any merged files specified in a [`--filter`](#opt) rule. It does not affect [`--cvs-exclude`](#opt) (since all names read from a .cvsignore file are split on whitespace). 0. `--old-args` This option tells rsync to stop trying to protect the arg values on the remote side from unintended word-splitting or other misinterpretation. It also allows the client to treat an empty arg as a "." instead of generating an error. The default in a modern rsync is for "shell-active" characters (including spaces) to be backslash-escaped in the args that are sent to the remote shell. The wildcard characters `*`, `?`, `[`, & `]` are not escaped in filename args (allowing them to expand into multiple filenames) while being protected in option args, such as [`--usermap`](#opt). If you have a script that wants to use old-style arg splitting in its filenames, specify this option once. If the remote shell has a problem with any backslash escapes at all, specify this option twice. You may also control this setting via the [`RSYNC_OLD_ARGS`](#) environment variable. If it has the value "1", rsync will default to a single-option setting. If it has the value "2" (or more), rsync will default to a repeated-option setting. If it is "0", you'll get the default escaping behavior. The environment is always overridden by manually specified positive or negative options (the negative is `--no-old-args`). Note that this option also disables the extra safety check added in 3.2.5 that ensures that a remote sender isn't including extra top-level items in the file-list that you didn't request. This side-effect is necessary because we can't know for sure what names to expect when the remote shell is interpreting the args. This option conflicts with the [`--secluded-args`](#opt) option. 0. `--secluded-args`, `-s` This option sends all filenames and most options to the remote rsync via the protocol (not the remote shell command line) which avoids letting the remote shell modify them. Wildcards are expanded on the remote host by rsync instead of a shell. This is similar to the default backslash-escaping of args that was added in 3.2.4 (see [`--old-args`](#opt)) in that it prevents things like space splitting and unwanted special-character side-effects. However, it has the drawbacks of being incompatible with older rsync versions (prior to 3.0.0) and of being refused by restricted shells that want to be able to inspect all the option values for safety. This option is useful for those times that you need the argument's character set to be converted for the remote host, if the remote shell is incompatible with the default backslash-escpaing method, or there is some other reason that you want the majority of the options and arguments to bypass the command-line of the remote shell. If you combine this option with [`--iconv`](#opt), the args related to the remote side will be translated from the local to the remote character-set. The translation happens before wild-cards are expanded. See also the [`--files-from`](#opt) option. You may also control this setting via the [`RSYNC_PROTECT_ARGS`](#) environment variable. If it has a non-zero value, this setting will be enabled by default, otherwise it will be disabled by default. Either state is overridden by a manually specified positive or negative version of this option (note that `--no-s` and `--no-secluded-args` are the negative versions). This environment variable is also superseded by a non-zero [`RSYNC_OLD_ARGS`](#) export. This option conflicts with the [`--old-args`](#opt) option. This option used to be called `--protect-args` (before 3.2.6) and that older name can still be used (though specifying it as `-s` is always the easiest and most compatible choice). 0. `--trust-sender` This option disables two extra validation checks that a local client performs on the file list generated by a remote sender. This option should only be used if you trust the sender to not put something malicious in the file list (something that could possibly be done via a modified rsync, a modified shell, or some other similar manipulation). Normally, the rsync client (as of version 3.2.5) runs two extra validation checks when pulling files from a remote rsync: - It verifies that additional arg items didn't get added at the top of the transfer. - It verifies that none of the items in the file list are names that should have been excluded (if filter rules were specified). Note that various options can turn off one or both of these checks if the option interferes with the validation. For instance: - Using a per-directory filter file reads filter rules that only the server knows about, so the filter checking is disabled. - Using the [`--old-args`](#opt) option allows the sender to manipulate the requested args, so the arg checking is disabled. - Reading the files-from list from the server side means that the client doesn't know the arg list, so the arg checking is disabled. - Using [`--read-batch`](#opt) disables both checks since the batch file's contents will have been verified when it was created. This option may help an under-powered client server if the extra pattern matching is slowing things down on a huge transfer. It can also be used to work around a currently-unknown bug in the verification logic for a transfer from a trusted sender. When using this option it is a good idea to specify a dedicated destination directory, as discussed in the [MULTI-HOST SECURITY](#) section. 0. `--copy-as=USER[:GROUP]` This option instructs rsync to use the USER and (if specified after a colon) the GROUP for the copy operations. This only works if the user that is running rsync has the ability to change users. If the group is not specified then the user's default groups are used. This option can help to reduce the risk of an rsync being run as root into or out of a directory that might have live changes happening to it and you want to make sure that root-level read or write actions of system files are not possible. While you could alternatively run all of rsync as the specified user, sometimes you need the root-level host-access credentials to be used, so this allows rsync to drop root for the copying part of the operation after the remote-shell or daemon connection is established. The option only affects one side of the transfer unless the transfer is local, in which case it affects both sides. Use the [`--remote-option`](#opt) to affect the remote side, such as `-M--copy-as=joe`. For a local transfer, the lsh (or lsh.sh) support file provides a local-shell helper script that can be used to allow a "localhost:" or "lh:" host-spec to be specified without needing to setup any remote shells, allowing you to specify remote options that affect the side of the transfer that is using the host-spec (and using hostname "lh" avoids the overriding of the remote directory to the user's home dir). For example, the following rsync writes the local files as user "joe": > sudo rsync -aiv --copy-as=joe host1:backups/joe/ /home/joe/ This makes all files owned by user "joe", limits the groups to those that are available to that user, and makes it impossible for the joe user to do a timed exploit of the path to induce a change to a file that the joe user has no permissions to change. The following command does a local copy into the "dest/" dir as user "joe" (assuming you've installed support/lsh into a dir on your $PATH): > sudo rsync -aive lsh -M--copy-as=joe src/ lh:dest/ 0. `--temp-dir=DIR`, `-T` This option instructs rsync to use DIR as a scratch directory when creating temporary copies of the files transferred on the receiving side. The default behavior is to create each temporary file in the same directory as the associated destination file. Beginning with rsync 3.1.1, the temp-file names inside the specified DIR will not be prefixed with an extra dot (though they will still have a random suffix added). This option is most often used when the receiving disk partition does not have enough free space to hold a copy of the largest file in the transfer. In this case (i.e. when the scratch directory is on a different disk partition), rsync will not be able to rename each received temporary file over the top of the associated destination file, but instead must copy it into place. Rsync does this by copying the file over the top of the destination file, which means that the destination file will contain truncated data during this copy. If this were not done this way (even if the destination file were first removed, the data locally copied to a temporary file in the destination directory, and then renamed into place) it would be possible for the old file to continue taking up disk space (if someone had it open), and thus there might not be enough room to fit the new version on the disk at the same time. If you are using this option for reasons other than a shortage of disk space, you may wish to combine it with the [`--delay-updates`](#opt) option, which will ensure that all copied files get put into subdirectories in the destination hierarchy, awaiting the end of the transfer. If you don't have enough room to duplicate all the arriving files on the destination partition, another way to tell rsync that you aren't overly concerned about disk space is to use the [`--partial-dir`](#opt) option with a relative path; because this tells rsync that it is OK to stash off a copy of a single file in a subdir in the destination hierarchy, rsync will use the partial-dir as a staging area to bring over the copied file, and then rename it into place from there. (Specifying a [`--partial-dir`](#opt) with an absolute path does not have this side-effect.) 0. `--fuzzy`, `-y` This option tells rsync that it should look for a basis file for any destination file that is missing. The current algorithm looks in the same directory as the destination file for either a file that has an identical size and modified-time, or a similarly-named file. If found, rsync uses the fuzzy basis file to try to speed up the transfer. If the option is repeated, the fuzzy scan will also be done in any matching alternate destination directories that are specified via [`--compare-dest`](#opt), [`--copy-dest`](#opt), or [`--link-dest`](#opt). Note that the use of the [`--delete`](#opt) option might get rid of any potential fuzzy-match files, so either use [`--delete-after`](#opt) or specify some filename exclusions if you need to prevent this. 0. `--compare-dest=DIR` This option instructs rsync to use _DIR_ on the destination machine as an additional hierarchy to compare destination files against doing transfers (if the files are missing in the destination directory). If a file is found in _DIR_ that is identical to the sender's file, the file will NOT be transferred to the destination directory. This is useful for creating a sparse backup of just files that have changed from an earlier backup. This option is typically used to copy into an empty (or newly created) directory. Beginning in version 2.6.4, multiple `--compare-dest` directories may be provided, which will cause rsync to search the list in the order specified for an exact match. If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the _DIRs_ will be selected to try to speed up the transfer. If _DIR_ is a relative path, it is relative to the destination directory. See also [`--copy-dest`](#opt) and [`--link-dest`](#opt). NOTE: beginning with version 3.1.0, rsync will remove a file from a non-empty destination hierarchy if an exact match is found in one of the compare-dest hierarchies (making the end result more closely match a fresh copy). 0. `--copy-dest=DIR` This option behaves like [`--compare-dest`](#opt), but rsync will also copy unchanged files found in _DIR_ to the destination directory using a local copy. This is useful for doing transfers to a new destination while leaving existing files intact, and then doing a flash-cutover when all files have been successfully transferred. Multiple `--copy-dest` directories may be provided, which will cause rsync to search the list in the order specified for an unchanged file. If a match is not found, a basis file from one of the _DIRs_ will be selected to try to speed up the transfer. If _DIR_ is a relative path, it is relative to the destination directory. See also [`--compare-dest`](#opt) and [`--link-dest`](#opt). 0. `--link-dest=DIR` This option behaves like [`--copy-dest`](#opt), but unchanged files are hard linked from _DIR_ to the destination directory. The files must be identical in all preserved attributes (e.g. permissions, possibly ownership) in order for the files to be linked together. An example: > rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/ If files aren't linking, double-check their attributes. Also check if some attributes are getting forced outside of rsync's control, such a mount option that squishes root to a single user, or mounts a removable drive with generic ownership (such as OS X's "Ignore ownership on this volume" option). Beginning in version 2.6.4, multiple `--link-dest` directories may be provided, which will cause rsync to search the list in the order specified for an exact match (there is a limit of 20 such directories). If a match is found that differs only in attributes, a local copy is made and the attributes updated. If a match is not found, a basis file from one of the _DIRs_ will be selected to try to speed up the transfer. This option works best when copying into an empty destination hierarchy, as existing files may get their attributes tweaked, and that can affect alternate destination files via hard-links. Also, itemizing of changes can get a bit muddled. Note that prior to version 3.1.0, an alternate-directory exact match would never be found (nor linked into the destination) when a destination file already exists. Note that if you combine this option with [`--ignore-times`](#opt), rsync will not link any files together because it only links identical files together as a substitute for transferring the file, never as an additional check after the file is updated. If _DIR_ is a relative path, it is relative to the destination directory. See also [`--compare-dest`](#opt) and [`--copy-dest`](#opt). Note that rsync versions prior to 2.6.1 had a bug that could prevent `--link-dest` from working properly for a non-super-user when [`--owner`](#opt) (`-o`) was specified (or implied). You can work-around this bug by avoiding the `-o` option (or using `--no-o`) when sending to an old rsync. 0. `--compress`, `-z` With this option, rsync compresses the file data as it is sent to the destination machine, which reduces the amount of data being transmitted -- something that is useful over a slow connection. Rsync supports multiple compression methods and will choose one for you unless you force the choice using the [`--compress-choice`](#opt) (`--zc`) option. Run `rsync --version` to see the default compress list compiled into your version. When both sides of the transfer are at least 3.2.0, rsync chooses the first algorithm in the client's list of choices that is also in the server's list of choices. If no common compress choice is found, rsync exits with an error. If the remote rsync is too old to support checksum negotiation, its list is assumed to be "zlib". The default order can be customized by setting the environment variable [`RSYNC_COMPRESS_LIST`](#) to a space-separated list of acceptable compression names. If the string contains a "`&`" character, it is separated into the "client string & server string", otherwise the same string applies to both. If the string (or string portion) contains no non-whitespace characters, the default compress list is used. Any unknown compression names are discarded from the list, but a list with only invalid names results in a failed negotiation. There are some older rsync versions that were configured to reject a `-z` option and require the use of `-zz` because their compression library was not compatible with the default zlib compression method. You can usually ignore this weirdness unless the rsync server complains and tells you to specify `-zz`. 0. `--compress-choice=STR`, `--zc=STR` This option can be used to override the automatic negotiation of the compression algorithm that occurs when [`--compress`](#opt) is used. The option implies [`--compress`](#opt) unless "none" was specified, which instead implies `--no-compress`. The compression options that you may be able to use are: - `zstd` - `lz4` - `zlibx` - `zlib` - `none` Run `rsync --version` to see the default compress list compiled into your version (which may differ from the list above). Note that if you see an error about an option named `--old-compress` or `--new-compress`, this is rsync trying to send the `--compress-choice=zlib` or `--compress-choice=zlibx` option in a backward-compatible manner that more rsync versions understand. This error indicates that the older rsync version on the server will not allow you to force the compression type. Note that the "zlibx" compression algorithm is just the "zlib" algorithm with matched data excluded from the compression stream (to try to make it more compatible with an external zlib implementation). 0. `--compress-level=NUM`, `--zl=NUM` Explicitly set the compression level to use (see [`--compress`](#opt), `-z`) instead of letting it default. The [`--compress`](#opt) option is implied as long as the level chosen is not a "don't compress" level for the compression algorithm that is in effect (e.g. zlib compression treats level 0 as "off"). The level values vary depending on the checksum in effect. Because rsync will negotiate a checksum choice by default (when the remote rsync is new enough), it can be good to combine this option with a [`--compress-choice`](#opt) (`--zc`) option unless you're sure of the choice in effect. For example: > rsync -aiv --zc=zstd --zl=22 host:src/ dest/ For zlib & zlibx compression the valid values are from 1 to 9 with 6 being the default. Specifying `--zl=0` turns compression off, and specifying `--zl=-1` chooses the default level of 6. For zstd compression the valid values are from -131072 to 22 with 3 being the default. Specifying 0 chooses the default of 3. For lz4 compression there are no levels, so the value is always 0. If you specify a too-large or too-small value, the number is silently limited to a valid value. This allows you to specify something like `--zl=999999999` and be assured that you'll end up with the maximum compression level no matter what algorithm was chosen. If you want to know the compression level that is in effect, specify [`--debug=nstr`](#opt) to see the "negotiated string" results. This will report something like "`Client compress: zstd (level 3)`" (along with the checksum choice in effect). 0. `--skip-compress=LIST` **NOTE:** no compression method currently supports per-file compression changes, so this option has no effect. Override the list of file suffixes that will be compressed as little as possible. Rsync sets the compression level on a per-file basis based on the file's suffix. If the compression algorithm has an "off" level, then no compression occurs for those files. Other algorithms that support changing the streaming level on-the-fly will have the level minimized to reduces the CPU usage as much as possible for a matching file. The **LIST** should be one or more file suffixes (without the dot) separated by slashes (`/`). You may specify an empty string to indicate that no files should be skipped. Simple character-class matching is supported: each must consist of a list of letters inside the square brackets (e.g. no special classes, such as "[:alpha:]", are supported, and '-' has no special meaning). The characters asterisk (`*`) and question-mark (`?`) have no special meaning. Here's an example that specifies 6 suffixes to skip (since 1 of the 5 rules matches 2 suffixes): > --skip-compress=gz/jpg/mp[34]/7z/bz2 The default file suffixes in the skip-compress list in this version of rsync are: [comment]: # (This list gets used for the default-dont-compress.h file.) > 3g2 > 3gp > 7z > aac > ace > apk > avi > bz2 > deb > dmg > ear > f4v > flac > flv > gpg > gz > iso > jar > jpeg > jpg > lrz > lz > lz4 > lzma > lzo > m1a > m1v > m2a > m2ts > m2v > m4a > m4b > m4p > m4r > m4v > mka > mkv > mov > mp1 > mp2 > mp3 > mp4 > mpa > mpeg > mpg > mpv > mts > odb > odf > odg > odi > odm > odp > ods > odt > oga > ogg > ogm > ogv > ogx > opus > otg > oth > otp > ots > ott > oxt > png > qt > rar > rpm > rz > rzip > spx > squashfs > sxc > sxd > sxg > sxm > sxw > sz > tbz > tbz2 > tgz > tlz > ts > txz > tzo > vob > war > webm > webp > xz > z > zip > zst This list will be replaced by your `--skip-compress` list in all but one situation: a copy from a daemon rsync will add your skipped suffixes to its list of non-compressing files (and its list may be configured to a different default). 0. `--numeric-ids` With this option rsync will transfer numeric group and user IDs rather than using user and group names and mapping them at both ends. By default rsync will use the username and groupname to determine what ownership to give files. The special uid 0 and the special group 0 are never mapped via user/group names even if the `--numeric-ids` option is not specified. If a user or group has no name on the source system or it has no match on the destination system, then the numeric ID from the source system is used instead. See also the [`use chroot`](rsyncd.conf.5#use_chroot) setting in the rsyncd.conf manpage for some comments on how the chroot setting affects rsync's ability to look up the names of the users and groups and what you can do about it. 0. `--usermap=STRING`, `--groupmap=STRING` These options allow you to specify users and groups that should be mapped to other values by the receiving side. The **STRING** is one or more **FROM**:**TO** pairs of values separated by commas. Any matching **FROM** value from the sender is replaced with a **TO** value from the receiver. You may specify usernames or user IDs for the **FROM** and **TO** values, and the **FROM** value may also be a wild-card string, which will be matched against the sender's names (wild-cards do NOT match against ID numbers, though see below for why a '`*`' matches everything). You may instead specify a range of ID numbers via an inclusive range: LOW-HIGH. For example: > --usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr The first match in the list is the one that is used. You should specify all your user mappings using a single `--usermap` option, and/or all your group mappings using a single `--groupmap` option. Note that the sender's name for the 0 user and group are not transmitted to the receiver, so you should either match these values using a 0, or use the names in effect on the receiving side (typically "root"). All other **FROM** names match those in use on the sending side. All **TO** names match those in use on the receiving side. Any IDs that do not have a name on the sending side are treated as having an empty name for the purpose of matching. This allows them to be matched via a "`*`" or using an empty name. For instance: > --usermap=:nobody --groupmap=*:nobody When the [`--numeric-ids`](#opt) option is used, the sender does not send any names, so all the IDs are treated as having an empty name. This means that you will need to specify numeric **FROM** values if you want to map these nameless IDs to different values. For the `--usermap` option to work, the receiver will need to be running as a super-user (see also the [`--super`](#opt) and [`--fake-super`](#opt) options). For the `--groupmap` option to work, the receiver will need to have permissions to set that group. Starting with rsync 3.2.4, the `--usermap` option implies the [`--owner`](#opt) (`-o`) option while the `--groupmap` option implies the [`--group`](#opt) (`-g`) option (since rsync needs to have those options enabled for the mapping options to work). An older rsync client may need to use [`-s`](#opt) to avoid a complaint about wildcard characters, but a modern rsync handles this automatically. 0. `--chown=USER:GROUP` This option forces all files to be owned by USER with group GROUP. This is a simpler interface than using [`--usermap`](#opt) & [`--groupmap`](#opt) directly, but it is implemented using those options internally so they cannot be mixed. If either the USER or GROUP is empty, no mapping for the omitted user/group will occur. If GROUP is empty, the trailing colon may be omitted, but if USER is empty, a leading colon must be supplied. If you specify "`--chown=foo:bar`", this is exactly the same as specifying "`--usermap=*:foo --groupmap=*:bar`", only easier (and with the same implied [`--owner`](#opt) and/or [`--group`](#opt) options). An older rsync client may need to use [`-s`](#opt) to avoid a complaint about wildcard characters, but a modern rsync handles this automatically. 0. `--timeout=SECONDS` This option allows you to set a maximum I/O timeout in seconds. If no data is transferred for the specified time then rsync will exit. The default is 0, which means no timeout. 0. `--contimeout=SECONDS` This option allows you to set the amount of time that rsync will wait for its connection to an rsync daemon to succeed. If the timeout is reached, rsync exits with an error. 0. `--address=ADDRESS` By default rsync will bind to the wildcard address when connecting to an rsync daemon. The `--address` option allows you to specify a specific IP address (or hostname) to bind to. See also [the daemon version of the `--address` option](#dopt--address). 0. `--port=PORT` This specifies an alternate TCP port number to use rather than the default of 873. This is only needed if you are using the double-colon (::) syntax to connect with an rsync daemon (since the URL syntax has a way to specify the port as a part of the URL). See also [the daemon version of the `--port` option](#dopt--port). 0. `--sockopts=OPTIONS` This option can provide endless fun for people who like to tune their systems to the utmost degree. You can set all sorts of socket options which may make transfers faster (or slower!). Read the manpage for the `setsockopt()` system call for details on some of the options you may be able to set. By default no special socket options are set. This only affects direct socket connections to a remote rsync daemon. See also [the daemon version of the `--sockopts` option](#dopt--sockopts). 0. `--blocking-io` This tells rsync to use blocking I/O when launching a remote shell transport. If the remote shell is either rsh or remsh, rsync defaults to using blocking I/O, otherwise it defaults to using non-blocking I/O. (Note that ssh prefers non-blocking I/O.) 0. `--outbuf=MODE` This sets the output buffering mode. The mode can be None (aka Unbuffered), Line, or Block (aka Full). You may specify as little as a single letter for the mode, and use upper or lower case. The main use of this option is to change Full buffering to Line buffering when rsync's output is going to a file or pipe. 0. `--itemize-changes`, `-i` Requests a simple itemized list of the changes that are being made to each file, including attribute changes. This is exactly the same as specifying [`--out-format='%i %n%L'`](#opt). If you repeat the option, unchanged files will also be output, but only if the receiving rsync is at least version 2.6.7 (you can use `-vv` with older versions of rsync, but that also turns on the output of other verbose messages). The "%i" escape has a cryptic output that is 11 letters long. The general format is like the string `YXcstpoguax`, where **Y** is replaced by the type of update being done, **X** is replaced by the file-type, and the other letters represent attributes that may be output if they are being modified. The update types that replace the **Y** are as follows: - A `<` means that a file is being transferred to the remote host (sent). - A `>` means that a file is being transferred to the local host (received). - A `c` means that a local change/creation is occurring for the item (such as the creation of a directory or the changing of a symlink, etc.). - A `h` means that the item is a hard link to another item (requires [`--hard-links`](#opt)). - A `.` means that the item is not being updated (though it might have attributes that are being modified). - A `*` means that the rest of the itemized-output area contains a message (e.g. "deleting"). The file-types that replace the **X** are: `f` for a file, a `d` for a directory, an `L` for a symlink, a `D` for a device, and a `S` for a special file (e.g. named sockets and fifos). The other letters in the string indicate if some attributes of the file have changed, as follows: - "`.`" - the attribute is unchanged. - "`+`" - the file is newly created. - "` `" - all the attributes are unchanged (all dots turn to spaces). - "`?`" - the change is unknown (when the remote rsync is old). - A letter indicates an attribute is being updated. The attribute that is associated with each letter is as follows: - A `c` means either that a regular file has a different checksum (requires [`--checksum`](#opt)) or that a symlink, device, or special file has a changed value. Note that if you are sending files to an rsync prior to 3.0.1, this change flag will be present only for checksum-differing regular files. - A `s` means the size of a regular file is different and will be updated by the file transfer. - A `t` means the modification time is different and is being updated to the sender's value (requires [`--times`](#opt)). An alternate value of `T` means that the modification time will be set to the transfer time, which happens when a file/symlink/device is updated without [`--times`](#opt) and when a symlink is changed and the receiver can't set its time. (Note: when using an rsync 3.0.0 client, you might see the `s` flag combined with `t` instead of the proper `T` flag for this time-setting failure.) - A `p` means the permissions are different and are being updated to the sender's value (requires [`--perms`](#opt)). - An `o` means the owner is different and is being updated to the sender's value (requires [`--owner`](#opt) and super-user privileges). - A `g` means the group is different and is being updated to the sender's value (requires [`--group`](#opt) and the authority to set the group). - A `u`|`n`|`b` indicates the following information: - `u` means the access (use) time is different and is being updated to the sender's value (requires [`--atimes`](#opt)) - `n` means the create time (newness) is different and is being updated to the sender's value (requires [`--crtimes`](#opt)) - `b` means that both the access and create times are being updated - The `a` means that the ACL information is being changed. - The `x` means that the extended attribute information is being changed. One other output is possible: when deleting files, the "%i" will output the string "`*deleting`" for each item that is being removed (assuming that you are talking to a recent enough rsync that it logs deletions instead of outputting them as a verbose message). 0. `--out-format=FORMAT` This allows you to specify exactly what the rsync client outputs to the user on a per-update basis. The format is a text string containing embedded single-character escape sequences prefixed with a percent (%) character. A default format of "%n%L" is assumed if either [`--info=name`](#opt) or [`-v`](#opt) is specified (this tells you just the name of the file and, if the item is a link, where it points). For a full list of the possible escape characters, see the [`log format`](rsyncd.conf.5#log_format) setting in the rsyncd.conf manpage. Specifying the `--out-format` option implies the [`--info=name`](#opt) option, which will mention each file, dir, etc. that gets updated in a significant way (a transferred file, a recreated symlink/device, or a touched directory). In addition, if the itemize-changes escape (%i) is included in the string (e.g. if the [`--itemize-changes`](#opt) option was used), the logging of names increases to mention any item that is changed in any way (as long as the receiving side is at least 2.6.4). See the [`--itemize-changes`](#opt) option for a description of the output of "%i". Rsync will output the out-format string prior to a file's transfer unless one of the transfer-statistic escapes is requested, in which case the logging is done at the end of the file's transfer. When this late logging is in effect and [`--progress`](#opt) is also specified, rsync will also output the name of the file being transferred prior to its progress information (followed, of course, by the out-format output). 0. `--log-file=FILE` This option causes rsync to log what it is doing to a file. This is similar to the logging that a daemon does, but can be requested for the client side and/or the server side of a non-daemon transfer. If specified as a client option, transfer logging will be enabled with a default format of "%i %n%L". See the [`--log-file-format`](#opt) option if you wish to override this. Here's an example command that requests the remote side to log what is happening: > rsync -av --remote-option=--log-file=/tmp/rlog src/ dest/ This is very useful if you need to debug why a connection is closing unexpectedly. See also [the daemon version of the `--log-file` option](#dopt--log-file). 0. `--log-file-format=FORMAT` This allows you to specify exactly what per-update logging is put into the file specified by the [`--log-file`](#opt) option (which must also be specified for this option to have any effect). If you specify an empty string, updated files will not be mentioned in the log file. For a list of the possible escape characters, see the [`log format`](rsyncd.conf.5#log_format) setting in the rsyncd.conf manpage. The default FORMAT used if [`--log-file`](#opt) is specified and this option is not is '%i %n%L'. See also [the daemon version of the `--log-file-format` option](#dopt--log-file-format). 0. `--stats` This tells rsync to print a verbose set of statistics on the file transfer, allowing you to tell how effective rsync's delta-transfer algorithm is for your data. This option is equivalent to [`--info=stats2`](#opt) if combined with 0 or 1 [`-v`](#opt) options, or [`--info=stats3`](#opt) if combined with 2 or more [`-v`](#opt) options. The current statistics are as follows: - `Number of files` is the count of all "files" (in the generic sense), which includes directories, symlinks, etc. The total count will be followed by a list of counts by filetype (if the total is non-zero). For example: "(reg: 5, dir: 3, link: 2, dev: 1, special: 1)" lists the totals for regular files, directories, symlinks, devices, and special files. If any of value is 0, it is completely omitted from the list. - `Number of created files` is the count of how many "files" (generic sense) were created (as opposed to updated). The total count will be followed by a list of counts by filetype (if the total is non-zero). - `Number of deleted files` is the count of how many "files" (generic sense) were deleted. The total count will be followed by a list of counts by filetype (if the total is non-zero). Note that this line is only output if deletions are in effect, and only if protocol 31 is being used (the default for rsync 3.1.x). - `Number of regular files transferred` is the count of normal files that were updated via rsync's delta-transfer algorithm, which does not include dirs, symlinks, etc. Note that rsync 3.1.0 added the word "regular" into this heading. - `Total file size` is the total sum of all file sizes in the transfer. This does not count any size for directories or special files, but does include the size of symlinks. - `Total transferred file size` is the total sum of all files sizes for just the transferred files. - `Literal data` is how much unmatched file-update data we had to send to the receiver for it to recreate the updated files. - `Matched data` is how much data the receiver got locally when recreating the updated files. - `File list size` is how big the file-list data was when the sender sent it to the receiver. This is smaller than the in-memory size for the file list due to some compressing of duplicated data when rsync sends the list. - `File list generation time` is the number of seconds that the sender spent creating the file list. This requires a modern rsync on the sending side for this to be present. - `File list transfer time` is the number of seconds that the sender spent sending the file list to the receiver. - `Total bytes sent` is the count of all the bytes that rsync sent from the client side to the server side. - `Total bytes received` is the count of all non-message bytes that rsync received by the client side from the server side. "Non-message" bytes means that we don't count the bytes for a verbose message that the server sent to us, which makes the stats more consistent. 0. `--8-bit-output`, `-8` This tells rsync to leave all high-bit characters unescaped in the output instead of trying to test them to see if they're valid in the current locale and escaping the invalid ones. All control characters (but never tabs) are always escaped, regardless of this option's setting. The escape idiom that started in 2.6.7 is to output a literal backslash (`\`) and a hash (`#`), followed by exactly 3 octal digits. For example, a newline would output as "`\#012`". A literal backslash that is in a filename is not escaped unless it is followed by a hash and 3 digits (0-9). 0. `--human-readable`, `-h` Output numbers in a more human-readable format. There are 3 possible levels: 1. output numbers with a separator between each set of 3 digits (either a comma or a period, depending on if the decimal point is represented by a period or a comma). 2. output numbers in units of 1000 (with a character suffix for larger units -- see below). 3. output numbers in units of 1024. The default is human-readable level 1. Each `-h` option increases the level by one. You can take the level down to 0 (to output numbers as pure digits) by specifying the `--no-human-readable` (`--no-h`) option. The unit letters that are appended in levels 2 and 3 are: `K` (kilo), `M` (mega), `G` (giga), `T` (tera), or `P` (peta). For example, a 1234567-byte file would output as 1.23M in level-2 (assuming that a period is your local decimal point). Backward compatibility note: versions of rsync prior to 3.1.0 do not support human-readable level 1, and they default to level 0. Thus, specifying one or two `-h` options will behave in a comparable manner in old and new versions as long as you didn't specify a `--no-h` option prior to one or more `-h` options. See the [`--list-only`](#opt) option for one difference. 0. `--partial` By default, rsync will delete any partially transferred file if the transfer is interrupted. In some circumstances it is more desirable to keep partially transferred files. Using the `--partial` option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster. 0. `--partial-dir=DIR` This option modifies the behavior of the [`--partial`](#opt) option while also implying that it be enabled. This enhanced partial-file method puts any partially transferred files into the specified _DIR_ instead of writing the partial file out to the destination file. On the next transfer, rsync will use a file found in this dir as data to speed up the resumption of the transfer and then delete it after it has served its purpose. Note that if [`--whole-file`](#opt) is specified (or implied), any partial-dir files that are found for a file that is being updated will simply be removed (since rsync is sending files without using rsync's delta-transfer algorithm). Rsync will create the _DIR_ if it is missing, but just the last dir -- not the whole path. This makes it easy to use a relative path (such as "`--partial-dir=.rsync-partial`") to have rsync create the partial-directory in the destination file's directory when it is needed, and then remove it again when the partial file is deleted. Note that this directory removal is only done for a relative pathname, as it is expected that an absolute path is to a directory that is reserved for partial-dir work. If the partial-dir value is not an absolute path, rsync will add an exclude rule at the end of all your existing excludes. This will prevent the sending of any partial-dir files that may exist on the sending side, and will also prevent the untimely deletion of partial-dir items on the receiving side. An example: the above `--partial-dir` option would add the equivalent of this "perishable" exclude at the end of any other filter rules: `-f '-p .rsync-partial/'` If you are supplying your own exclude rules, you may need to add your own exclude/hide/protect rule for the partial-dir because: 1. the auto-added rule may be ineffective at the end of your other rules, or 2. you may wish to override rsync's exclude choice. For instance, if you want to make rsync clean-up any left-over partial-dirs that may be lying around, you should specify [`--delete-after`](#opt) and add a "risk" filter rule, e.g. `-f 'R .rsync-partial/'`. Avoid using [`--delete-before`](#opt) or [`--delete-during`](#opt) unless you don't need rsync to use any of the left-over partial-dir data during the current run. IMPORTANT: the `--partial-dir` should not be writable by other users or it is a security risk! E.g. AVOID "/tmp"! You can also set the partial-dir value the [`RSYNC_PARTIAL_DIR`](#) environment variable. Setting this in the environment does not force [`--partial`](#opt) to be enabled, but rather it affects where partial files go when [`--partial`](#opt) is specified. For instance, instead of using `--partial-dir=.rsync-tmp` along with [`--progress`](#opt), you could set [`RSYNC_PARTIAL_DIR=.rsync-tmp`](#) in your environment and then use the [`-P`](#opt) option to turn on the use of the .rsync-tmp dir for partial transfers. The only times that the [`--partial`](#opt) option does not look for this environment value are: 1. when [`--inplace`](#opt) was specified (since [`--inplace`](#opt) conflicts with `--partial-dir`), and 2. when [`--delay-updates`](#opt) was specified (see below). When a modern rsync resumes the transfer of a file in the partial-dir, that partial file is now updated in-place instead of creating yet another tmp-file copy (so it maxes out at dest + tmp instead of dest + partial + tmp). This requires both ends of the transfer to be at least version 3.2.0. For the purposes of the daemon-config's "`refuse options`" setting, `--partial-dir` does _not_ imply [`--partial`](#opt). This is so that a refusal of the [`--partial`](#opt) option can be used to disallow the overwriting of destination files with a partial transfer, while still allowing the safer idiom provided by `--partial-dir`. 0. `--delay-updates` This option puts the temporary file from each updated file into a holding directory until the end of the transfer, at which time all the files are renamed into place in rapid succession. This attempts to make the updating of the files a little more atomic. By default the files are placed into a directory named `.~tmp~` in each file's destination directory, but if you've specified the [`--partial-dir`](#opt) option, that directory will be used instead. See the comments in the [`--partial-dir`](#opt) section for a discussion of how this `.~tmp~` dir will be excluded from the transfer, and what you can do if you want rsync to cleanup old `.~tmp~` dirs that might be lying around. Conflicts with [`--inplace`](#opt) and [`--append`](#opt). This option implies [`--no-inc-recursive`](#opt) since it needs the full file list in memory in order to be able to iterate over it at the end. This option uses more memory on the receiving side (one bit per file transferred) and also requires enough free disk space on the receiving side to hold an additional copy of all the updated files. Note also that you should not use an absolute path to [`--partial-dir`](#opt) unless: 1. there is no chance of any of the files in the transfer having the same name (since all the updated files will be put into a single directory if the path is absolute), and 2. there are no mount points in the hierarchy (since the delayed updates will fail if they can't be renamed into place). See also the "atomic-rsync" python script in the "support" subdir for an update algorithm that is even more atomic (it uses [`--link-dest`](#opt) and a parallel hierarchy of files). 0. `--prune-empty-dirs`, `-m` This option tells the receiving rsync to get rid of empty directories from the file-list, including nested directories that have no non-directory children. This is useful for avoiding the creation of a bunch of useless directories when the sending rsync is recursively scanning a hierarchy of files using include/exclude/filter rules. This option can still leave empty directories on the receiving side if you make use of [TRANSFER_RULES](#). Because the file-list is actually being pruned, this option also affects what directories get deleted when a delete is active. However, keep in mind that excluded files and directories can prevent existing items from being deleted due to an exclude both hiding source files and protecting destination files. See the perishable filter-rule option for how to avoid this. You can prevent the pruning of certain empty directories from the file-list by using a global "protect" filter. For instance, this option would ensure that the directory "emptydir" was kept in the file-list: > --filter 'protect emptydir/' Here's an example that copies all .pdf files in a hierarchy, only creating the necessary destination directories to hold the .pdf files, and ensures that any superfluous files and directories in the destination are removed (note the hide filter of non-directories being used instead of an exclude): > rsync -avm --del --include='*.pdf' -f 'hide,! */' src/ dest If you didn't want to remove superfluous destination files, the more time-honored options of `--include='*/' --exclude='*'` would work fine in place of the hide-filter (if that is more natural to you). 0. `--progress` This option tells rsync to print information showing the progress of the transfer. This gives a bored user something to watch. With a modern rsync this is the same as specifying [`--info=flist2,name,progress`](#opt), but any user-supplied settings for those info flags takes precedence (e.g. [`--info=flist0 --progress`](#opt)). While rsync is transferring a regular file, it updates a progress line that looks like this: > 782448 63% 110.64kB/s 0:00:04 In this example, the receiver has reconstructed 782448 bytes or 63% of the sender's file, which is being reconstructed at a rate of 110.64 kilobytes per second, and the transfer will finish in 4 seconds if the current rate is maintained until the end. These statistics can be misleading if rsync's delta-transfer algorithm is in use. For example, if the sender's file consists of the basis file followed by additional data, the reported rate will probably drop dramatically when the receiver gets to the literal data, and the transfer will probably take much longer to finish than the receiver estimated as it was finishing the matched part of the file. When the file transfer finishes, rsync replaces the progress line with a summary line that looks like this: > 1,238,099 100% 146.38kB/s 0:00:08 (xfr#5, to-chk=169/396) In this example, the file was 1,238,099 bytes long in total, the average rate of transfer for the whole file was 146.38 kilobytes per second over the 8 seconds that it took to complete, it was the 5th transfer of a regular file during the current rsync session, and there are 169 more files for the receiver to check (to see if they are up-to-date or not) remaining out of the 396 total files in the file-list. In an incremental recursion scan, rsync won't know the total number of files in the file-list until it reaches the ends of the scan, but since it starts to transfer files during the scan, it will display a line with the text "ir-chk" (for incremental recursion check) instead of "to-chk" until the point that it knows the full size of the list, at which point it will switch to using "to-chk". Thus, seeing "ir-chk" lets you know that the total count of files in the file list is still going to increase (and each time it does, the count of files left to check will increase by the number of the files added to the list). 0. `-P` The `-P` option is equivalent to "[`--partial`](#opt) [`--progress`](#opt)". Its purpose is to make it much easier to specify these two options for a long transfer that may be interrupted. There is also a [`--info=progress2`](#opt) option that outputs statistics based on the whole transfer, rather than individual files. Use this flag without outputting a filename (e.g. avoid `-v` or specify [`--info=name0`](#opt)) if you want to see how the transfer is doing without scrolling the screen with a lot of names. (You don't need to specify the [`--progress`](#opt) option in order to use [`--info=progress2`](#opt).) Finally, you can get an instant progress report by sending rsync a signal of either SIGINFO or SIGVTALRM. On BSD systems, a SIGINFO is generated by typing a Ctrl+T (Linux doesn't currently support a SIGINFO signal). When the client-side process receives one of those signals, it sets a flag to output a single progress report which is output when the current file transfer finishes (so it may take a little time if a big file is being handled when the signal arrives). A filename is output (if needed) followed by the [`--info=progress2`](#opt) format of progress info. If you don't know which of the 3 rsync processes is the client process, it's OK to signal all of them (since the non-client processes ignore the signal). CAUTION: sending SIGVTALRM to an older rsync (pre-3.2.0) will kill it. 0. `--password-file=FILE` This option allows you to provide a password for accessing an rsync daemon via a file or via standard input if **FILE** is `-`. The file should contain just the password on the first line (all other lines are ignored). Rsync will exit with an error if **FILE** is world readable or if a root-run rsync command finds a non-root-owned file. This option does not supply a password to a remote shell transport such as ssh; to learn how to do that, consult the remote shell's documentation. When accessing an rsync daemon using a remote shell as the transport, this option only comes into effect after the remote shell finishes its authentication (i.e. if you have also specified a password in the daemon's config file). 0. `--early-input=FILE` This option allows rsync to send up to 5K of data to the "early exec" script on its stdin. One possible use of this data is to give the script a secret that can be used to mount an encrypted filesystem (which you should unmount in the the "post-xfer exec" script). The daemon must be at least version 3.2.1. 0. `--list-only` This option will cause the source files to be listed instead of transferred. This option is inferred if there is a single source arg and no destination specified, so its main uses are: 1. to turn a copy command that includes a destination arg into a file-listing command, or 2. to be able to specify more than one source arg. Note: be sure to include the destination. CAUTION: keep in mind that a source arg with a wild-card is expanded by the shell into multiple args, so it is never safe to try to specify a single wild-card arg to try to infer this option. A safe example is: > rsync -av --list-only foo* dest/ This option always uses an output format that looks similar to this: > drwxrwxr-x 4,096 2022/09/30 12:53:11 support > -rw-rw-r-- 80 2005/01/11 10:37:37 support/Makefile The only option that affects this output style is (as of 3.1.0) the [`--human-readable`](#opt) (`-h`) option. The default is to output sizes as byte counts with digit separators (in a 14-character-width column). Specifying at least one `-h` option makes the sizes output with unit suffixes. If you want old-style bytecount sizes without digit separators (and an 11-character-width column) use `--no-h`. Compatibility note: when requesting a remote listing of files from an rsync that is version 2.6.3 or older, you may encounter an error if you ask for a non-recursive listing. This is because a file listing implies the [`--dirs`](#opt) option w/o [`--recursive`](#opt), and older rsyncs don't have that option. To avoid this problem, either specify the `--no-dirs` option (if you don't need to expand a directory's content), or turn on recursion and exclude the content of subdirectories: `-r --exclude='/*/*'`. 0. `--bwlimit=RATE` This option allows you to specify the maximum transfer rate for the data sent over the socket, specified in units per second. The RATE value can be suffixed with a string to indicate a size multiplier, and may be a fractional value (e.g. `--bwlimit=1.5m`). If no suffix is specified, the value will be assumed to be in units of 1024 bytes (as if "K" or "KiB" had been appended). See the [`--max-size`](#opt) option for a description of all the available suffixes. A value of 0 specifies no limit. For backward-compatibility reasons, the rate limit will be rounded to the nearest KiB unit, so no rate smaller than 1024 bytes per second is possible. Rsync writes data over the socket in blocks, and this option both limits the size of the blocks that rsync writes, and tries to keep the average transfer rate at the requested limit. Some burstiness may be seen where rsync writes out a block of data and then sleeps to bring the average rate into compliance. Due to the internal buffering of data, the [`--progress`](#opt) option may not be an accurate reflection on how fast the data is being sent. This is because some files can show up as being rapidly sent when the data is quickly buffered, while other can show up as very slow when the flushing of the output buffer occurs. This may be fixed in a future version. See also [the daemon version of the `--bwlimit` option](#dopt--bwlimit). 0. `--stop-after=MINS`, (`--time-limit=MINS`) This option tells rsync to stop copying when the specified number of minutes has elapsed. For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using [`--remote-option`](#opt) (`-M`), should the need arise. The `--time-limit` version of this option is deprecated. 0. `--stop-at=y-m-dTh:m` This option tells rsync to stop copying when the specified point in time has been reached. The date & time can be fully specified in a numeric format of year-month-dayThour:minute (e.g. 2000-12-31T23:59) in the local timezone. You may choose to separate the date numbers using slashes instead of dashes. The value can also be abbreviated in a variety of ways, such as specifying a 2-digit year and/or leaving off various values. In all cases, the value will be taken to be the next possible point in time where the supplied information matches. If the value specifies the current time or a past time, rsync exits with an error. For example, "1-30" specifies the next January 30th (at midnight local time), "14:00" specifies the next 2 P.M., "1" specifies the next 1st of the month at midnight, "31" specifies the next month where we can stop on its 31st day, and ":59" specifies the next 59th minute after the hour. For maximal flexibility, rsync does not communicate this option to the remote rsync since it is usually enough that one side of the connection quits as specified. This allows the option's use even when only one side of the connection supports it. You can tell the remote side about the time limit using [`--remote-option`](#opt) (`-M`), should the need arise. Do keep in mind that the remote host may have a different default timezone than your local host. 0. `--fsync` Cause the receiving side to fsync each finished file. This may slow down the transfer, but can help to provide peace of mind when updating critical files. 0. `--write-batch=FILE` Record a file that can later be applied to another identical destination with [`--read-batch`](#opt). See the "BATCH MODE" section for details, and also the [`--only-write-batch`](#opt) option. This option overrides the negotiated checksum & compress lists and always negotiates a choice based on old-school md5/md4/zlib choices. If you want a more modern choice, use the [`--checksum-choice`](#opt) (`--cc`) and/or [`--compress-choice`](#opt) (`--zc`) options. 0. `--only-write-batch=FILE` Works like [`--write-batch`](#opt), except that no updates are made on the destination system when creating the batch. This lets you transport the changes to the destination system via some other means and then apply the changes via [`--read-batch`](#opt). Note that you can feel free to write the batch directly to some portable media: if this media fills to capacity before the end of the transfer, you can just apply that partial transfer to the destination and repeat the whole process to get the rest of the changes (as long as you don't mind a partially updated destination system while the multi-update cycle is happening). Also note that you only save bandwidth when pushing changes to a remote system because this allows the batched data to be diverted from the sender into the batch file without having to flow over the wire to the receiver (when pulling, the sender is remote, and thus can't write the batch). 0. `--read-batch=FILE` Apply all of the changes stored in FILE, a file previously generated by [`--write-batch`](#opt). If _FILE_ is `-`, the batch data will be read from standard input. See the "BATCH MODE" section for details. 0. `--protocol=NUM` Force an older protocol version to be used. This is useful for creating a batch file that is compatible with an older version of rsync. For instance, if rsync 2.6.4 is being used with the [`--write-batch`](#opt) option, but rsync 2.6.3 is what will be used to run the [`--read-batch`](#opt) option, you should use "--protocol=28" when creating the batch file to force the older protocol version to be used in the batch file (assuming you can't upgrade the rsync on the reading system). 0. `--iconv=CONVERT_SPEC` Rsync can convert filenames between character sets using this option. Using a CONVERT_SPEC of "." tells rsync to look up the default character-set via the locale setting. Alternately, you can fully specify what conversion to do by giving a local and a remote charset separated by a comma in the order `--iconv=LOCAL,REMOTE`, e.g. `--iconv=utf8,iso88591`. This order ensures that the option will stay the same whether you're pushing or pulling files. Finally, you can specify either `--no-iconv` or a CONVERT_SPEC of "-" to turn off any conversion. The default setting of this option is site-specific, and can also be affected via the [`RSYNC_ICONV`](#) environment variable. For a list of what charset names your local iconv library supports, you can run "`iconv --list`". If you specify the [`--secluded-args`](#opt) (`-s`) option, rsync will translate the filenames you specify on the command-line that are being sent to the remote host. See also the [`--files-from`](#opt) option. Note that rsync does not do any conversion of names in filter files (including include/exclude files). It is up to you to ensure that you're specifying matching rules that can match on both sides of the transfer. For instance, you can specify extra include/exclude rules if there are filename differences on the two sides that need to be accounted for. When you pass an `--iconv` option to an rsync daemon that allows it, the daemon uses the charset specified in its "charset" configuration parameter regardless of the remote charset you actually pass. Thus, you may feel free to specify just the local charset for a daemon transfer (e.g. `--iconv=utf8`). 0. `--ipv4`, `-4` or `--ipv6`, `-6` Tells rsync to prefer IPv4/IPv6 when creating sockets or running ssh. This affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an rsync daemon, as well as the forwarding of the `-4` or `-6` option to ssh when rsync can deduce that ssh is being used as the remote shell. For other remote shells you'll need to specify the "`--rsh SHELL -4`" option directly (or whatever IPv4/IPv6 hint options it uses). See also [the daemon version of these options](#dopt--ipv4). If rsync was compiled without support for IPv6, the `--ipv6` option will have no effect. The `rsync --version` output will contain "`no IPv6`" if is the case. 0. `--checksum-seed=NUM` Set the checksum seed to the integer NUM. This 4 byte checksum seed is included in each block and MD4 file checksum calculation (the more modern MD5 file checksums don't use a seed). By default the checksum seed is generated by the server and defaults to the current **time**(). This option is used to set a specific checksum seed, which is useful for applications that want repeatable block checksums, or in the case where the user wants a more random checksum seed. Setting NUM to 0 causes rsync to use the default of **time**() for checksum seed. ## DAEMON OPTIONS The options allowed when starting an rsync daemon are as follows: 0. `--daemon` This tells rsync that it is to run as a daemon. The daemon you start running may be accessed using an rsync client using the `host::module` or `rsync://host/module/` syntax. If standard input is a socket then rsync will assume that it is being run via inetd, otherwise it will detach from the current terminal and become a background daemon. The daemon will read the config file (rsyncd.conf) on each connect made by a client and respond to requests accordingly. See the [**rsyncd.conf**(5)](rsyncd.conf.5) manpage for more details. 0. `--address=ADDRESS` By default rsync will bind to the wildcard address when run as a daemon with the `--daemon` option. The `--address` option allows you to specify a specific IP address (or hostname) to bind to. This makes virtual hosting possible in conjunction with the `--config` option. See also the [address](rsyncd.conf.5#address) global option in the rsyncd.conf manpage and the [client version of the `--address` option](#opt--address). 0. `--bwlimit=RATE` This option allows you to specify the maximum transfer rate for the data the daemon sends over the socket. The client can still specify a smaller `--bwlimit` value, but no larger value will be allowed. See the [client version of the `--bwlimit` option](#opt--bwlimit) for some extra details. 0. `--config=FILE` This specifies an alternate config file than the default. This is only relevant when [`--daemon`](#dopt) is specified. The default is /etc/rsyncd.conf unless the daemon is running over a remote shell program and the remote user is not the super-user; in that case the default is rsyncd.conf in the current directory (typically $HOME). 0. `--dparam=OVERRIDE`, `-M` This option can be used to set a daemon-config parameter when starting up rsync in daemon mode. It is equivalent to adding the parameter at the end of the global settings prior to the first module's definition. The parameter names can be specified without spaces, if you so desire. For instance: > rsync --daemon -M pidfile=/path/rsync.pid 0. `--no-detach` When running as a daemon, this option instructs rsync to not detach itself and become a background process. This option is required when running as a service on Cygwin, and may also be useful when rsync is supervised by a program such as `daemontools` or AIX's `System Resource Controller`. `--no-detach` is also recommended when rsync is run under a debugger. This option has no effect if rsync is run from inetd or sshd. 0. `--port=PORT` This specifies an alternate TCP port number for the daemon to listen on rather than the default of 873. See also [the client version of the `--port` option](#opt--port) and the [port](rsyncd.conf.5#port) global setting in the rsyncd.conf manpage. 0. `--log-file=FILE` This option tells the rsync daemon to use the given log-file name instead of using the "`log file`" setting in the config file. See also [the client version of the `--log-file` option](#opt--log-file). 0. `--log-file-format=FORMAT` This option tells the rsync daemon to use the given FORMAT string instead of using the "`log format`" setting in the config file. It also enables "`transfer logging`" unless the string is empty, in which case transfer logging is turned off. See also [the client version of the `--log-file-format` option](#opt--log-file-format). 0. `--sockopts` This overrides the [`socket options`](rsyncd.conf.5#socket_options) setting in the rsyncd.conf file and has the same syntax. See also [the client version of the `--sockopts` option](#opt--sockopts). 0. `--verbose`, `-v` This option increases the amount of information the daemon logs during its startup phase. After the client connects, the daemon's verbosity level will be controlled by the options that the client used and the "`max verbosity`" setting in the module's config section. See also [the client version of the `--verbose` option](#opt--verbose). 0. `--ipv4`, `-4` or `--ipv6`, `-6` Tells rsync to prefer IPv4/IPv6 when creating the incoming sockets that the rsync daemon will use to listen for connections. One of these options may be required in older versions of Linux to work around an IPv6 bug in the kernel (if you see an "address already in use" error when nothing else is using the port, try specifying `--ipv6` or `--ipv4` when starting the daemon). See also [the client version of these options](#opt--ipv4). If rsync was compiled without support for IPv6, the `--ipv6` option will have no effect. The `rsync --version` output will contain "`no IPv6`" if is the case. 0. `--help`, `-h` When specified after `--daemon`, print a short help page describing the options available for starting an rsync daemon. ## FILTER RULES The filter rules allow for custom control of several aspects of how files are handled: - Control which files the sending side puts into the file list that describes the transfer hierarchy - Control which files the receiving side protects from deletion when the file is not in the sender's file list - Control which extended attribute names are skipped when copying xattrs The rules are either directly specified via option arguments or they can be read in from one or more files. The filter-rule files can even be a part of the hierarchy of files being copied, affecting different parts of the tree in different ways. ### SIMPLE INCLUDE/EXCLUDE RULES We will first cover the basics of how include & exclude rules affect what files are transferred, ignoring any deletion side-effects. Filter rules mainly affect the contents of directories that rsync is "recursing" into, but they can also affect a top-level item in the transfer that was specified as a argument. The default for any unmatched file/dir is for it to be included in the transfer, which puts the file/dir into the sender's file list. The use of an exclude rule causes one or more matching files/dirs to be left out of the sender's file list. An include rule can be used to limit the effect of an exclude rule that is matching too many files. The order of the rules is important because the first rule that matches is the one that takes effect. Thus, if an early rule excludes a file, no include rule that comes after it can have any effect. This means that you must place any include overrides somewhere prior to the exclude that it is intended to limit. When a directory is excluded, all its contents and sub-contents are also excluded. The sender doesn't scan through any of it at all, which can save a lot of time when skipping large unneeded sub-trees. It is also important to understand that the include/exclude rules are applied to every file and directory that the sender is recursing into. Thus, if you want a particular deep file to be included, you have to make sure that none of the directories that must be traversed on the way down to that file are excluded or else the file will never be discovered to be included. As an example, if the directory "`a/path`" was given as a transfer argument and you want to ensure that the file "`a/path/down/deep/wanted.txt`" is a part of the transfer, then the sender must not exclude the directories "`a/path`", "`a/path/down`", or "`a/path/down/deep`" as it makes it way scanning through the file tree. When you are working on the rules, it can be helpful to ask rsync to tell you what is being excluded/included and why. Specifying `--debug=FILTER` or (when pulling files) `-M--debug=FILTER` turns on level 1 of the FILTER debug information that will output a message any time that a file or directory is included or excluded and which rule it matched. Beginning in 3.2.4 it will also warn if a filter rule has trailing whitespace, since an exclude of "foo " (with a trailing space) will not exclude a file named "foo". Exclude and include rules can specify wildcard [PATTERN MATCHING RULES](#) (similar to shell wildcards) that allow you to match things like a file suffix or a portion of a filename. A rule can be limited to only affecting a directory by putting a trailing slash onto the filename. ### SIMPLE INCLUDE/EXCLUDE EXAMPLE With the following file tree created on the sending side: > mkdir x/ > touch x/file.txt > mkdir x/y/ > touch x/y/file.txt > touch x/y/zzz.txt > mkdir x/z/ > touch x/z/file.txt Then the following rsync command will transfer the file "`x/y/file.txt`" and the directories needed to hold it, resulting in the path "`/tmp/x/y/file.txt`" existing on the remote host: > rsync -ai -f'+ x/' -f'+ x/y/' -f'+ x/y/file.txt' -f'- *' x host:/tmp/ Aside: this copy could also have been accomplished using the [`-R`](#opt) option (though the 2 commands behave differently if deletions are enabled): > rsync -aiR x/y/file.txt host:/tmp/ The following command does not need an include of the "x" directory because it is not a part of the transfer (note the traililng slash). Running this command would copy just "`/tmp/x/file.txt`" because the "y" and "z" dirs get excluded: > rsync -ai -f'+ file.txt' -f'- *' x/ host:/tmp/x/ This command would omit the zzz.txt file while copying "x" and everything else it contains: > rsync -ai -f'- zzz.txt' x host:/tmp/ ### FILTER RULES WHEN DELETING By default the include & exclude filter rules affect both the sender (as it creates its file list) and the receiver (as it creates its file lists for calculating deletions). If no delete option is in effect, the receiver skips creating the delete-related file lists. This two-sided default can be manually overridden so that you are only specifying sender rules or receiver rules, as described in the [FILTER RULES IN DEPTH](#) section. When deleting, an exclude protects a file from being removed on the receiving side while an include overrides that protection (putting the file at risk of deletion). The default is for a file to be at risk -- its safety depends on it matching a corresponding file from the sender. An example of the two-sided exclude effect can be illustrated by the copying of a C development directory between 2 systems. When doing a touch-up copy, you might want to skip copying the built executable and the `.o` files (sender hide) so that the receiving side can build their own and not lose any object files that are already correct (receiver protect). For instance: > rsync -ai --del -f'- *.o' -f'- cmd' src host:/dest/ Note that using `-f'-p *.o'` is even better than `-f'- *.o'` if there is a chance that the directory structure may have changed. The "p" modifier is discussed in [FILTER RULE MODIFIERS](#). One final note, if your shell doesn't mind unexpanded wildcards, you could simplify the typing of the filter options by using an underscore in place of the space and leaving off the quotes. For instance, `-f -_*.o -f -_cmd` (and similar) could be used instead of the filter options above. ### FILTER RULES IN DEPTH Rsync supports old-style include/exclude rules and new-style filter rules. The older rules are specified using [`--include`](#opt) and [`--exclude`](#opt) as well as the [`--include-from`](#opt) and [`--exclude-from`](#opt). These are limited in behavior but they don't require a "-" or "+" prefix. An old-style exclude rule is turned into a "`- name`" filter rule (with no modifiers) and an old-style include rule is turned into a "`+ name`" filter rule (with no modifiers). Rsync builds an ordered list of filter rules as specified on the command-line and/or read-in from files. New style filter rules have the following syntax: > RULE [PATTERN_OR_FILENAME] > RULE,MODIFIERS [PATTERN_OR_FILENAME] You have your choice of using either short or long RULE names, as described below. If you use a short-named rule, the ',' separating the RULE from the MODIFIERS is optional. The PATTERN or FILENAME that follows (when present) must come after either a single space or an underscore (\_). Any additional spaces and/or underscores are considered to be a part of the pattern name. Here are the available rule prefixes: 0. `exclude, '-'` specifies an exclude pattern that (by default) is both a `hide` and a `protect`. 0. `include, '+'` specifies an include pattern that (by default) is both a `show` and a `risk`. 0. `merge, '.'` specifies a merge-file on the client side to read for more rules. 0. `dir-merge, ':'` specifies a per-directory merge-file. Using this kind of filter rule requires that you trust the sending side's filter checking, so it has the side-effect mentioned under the [`--trust-sender`](#opt) option. 0. `hide, 'H'` specifies a pattern for hiding files from the transfer. Equivalent to a sender-only exclude, so `-f'H foo'` could also be specified as `-f'-s foo'`. 0. `show, 'S'` files that match the pattern are not hidden. Equivalent to a sender-only include, so `-f'S foo'` could also be specified as `-f'+s foo'`. 0. `protect, 'P'` specifies a pattern for protecting files from deletion. Equivalent to a receiver-only exclude, so `-f'P foo'` could also be specified as `-f'-r foo'`. 0. `risk, 'R'` files that match the pattern are not protected. Equivalent to a receiver-only include, so `-f'R foo'` could also be specified as `-f'+r foo'`. 0. `clear, '!'` clears the current include/exclude list (takes no arg) When rules are being read from a file (using merge or dir-merge), empty lines are ignored, as are whole-line comments that start with a '`#`' (filename rules that contain a hash character are unaffected). Note also that the [`--filter`](#opt), [`--include`](#opt), and [`--exclude`](#opt) options take one rule/pattern each. To add multiple ones, you can repeat the options on the command-line, use the merge-file syntax of the [`--filter`](#opt) option, or the [`--include-from`](#opt) / [`--exclude-from`](#opt) options. ### PATTERN MATCHING RULES Most of the rules mentioned above take an argument that specifies what the rule should match. If rsync is recursing through a directory hierarchy, keep in mind that each pattern is matched against the name of every directory in the descent path as rsync finds the filenames to send. The matching rules for the pattern argument take several forms: - If a pattern contains a `/` (not counting a trailing slash) or a "`**`" (which can match a slash), then the pattern is matched against the full pathname, including any leading directories within the transfer. If the pattern doesn't contain a (non-trailing) `/` or a "`**`", then it is matched only against the final component of the filename or pathname. For example, `foo` means that the final path component must be "foo" while `foo/bar` would match the last 2 elements of the path (as long as both elements are within the transfer). - A pattern that ends with a `/` only matches a directory, not a regular file, symlink, or device. - A pattern that starts with a `/` is anchored to the start of the transfer path instead of the end. For example, `/foo/**` or `/foo/bar/**` match only leading elements in the path. If the rule is read from a per-directory filter file, the transfer path being matched will begin at the level of the filter file instead of the top of the transfer. See the section on [ANCHORING INCLUDE/EXCLUDE PATTERNS](#) for a full discussion of how to specify a pattern that matches at the root of the transfer. Rsync chooses between doing a simple string match and wildcard matching by checking if the pattern contains one of these three wildcard characters: '`*`', '`?`', and '`[`' : - a '`?`' matches any single character except a slash (`/`). - a '`*`' matches zero or more non-slash characters. - a '`**`' matches zero or more characters, including slashes. - a '`[`' introduces a character class, such as `[a-z]` or `[[:alpha:]]`, that must match one character. - a trailing `***` in the pattern is a shorthand that allows you to match a directory and all its contents using a single rule. For example, specifying "`dir_name/***`" will match both the "dir_name" directory (as if "`dir_name/`" had been specified) and everything in the directory (as if "`dir_name/**`" had been specified). - a backslash can be used to escape a wildcard character, but it is only interpreted as an escape character if at least one wildcard character is present in the match pattern. For instance, the pattern "`foo\bar`" matches that single backslash literally, while the pattern "`foo\bar*`" would need to be changed to "`foo\\bar*`" to avoid the "`\b`" becoming just "b". Here are some examples of exclude/include matching: - Option `-f'- *.o'` would exclude all filenames ending with `.o` - Option `-f'- /foo'` would exclude a file (or directory) named foo in the transfer-root directory - Option `-f'- foo/'` would exclude any directory named foo - Option `-f'- foo/*/bar'` would exclude any file/dir named bar which is at two levels below a directory named foo (if foo is in the transfer) - Option `-f'- /foo/**/bar'` would exclude any file/dir named bar that was two or more levels below a top-level directory named foo (note that /foo/bar is **not** excluded by this) - Options `-f'+ */' -f'+ *.c' -f'- *'` would include all directories and .c source files but nothing else - Options `-f'+ foo/' -f'+ foo/bar.c' -f'- *'` would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "`- *`") ### FILTER RULE MODIFIERS The following modifiers are accepted after an include (+) or exclude (-) rule: - A `/` specifies that the include/exclude rule should be matched against the absolute pathname of the current item. For example, `-f'-/ /etc/passwd'` would exclude the passwd file any time the transfer was sending files from the "/etc" directory, and "-/ subdir/foo" would always exclude "foo" when it is in a dir named "subdir", even if "foo" is at the root of the current transfer. - A `!` specifies that the include/exclude should take effect if the pattern fails to match. For instance, `-f'-! */'` would exclude all non-directories. - A `C` is used to indicate that all the global CVS-exclude rules should be inserted as excludes in place of the "-C". No arg should follow. - An `s` is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it affects what files are put into the sender's file list. The default is for a rule to affect both sides unless [`--delete-excluded`](#opt) was specified, in which case default rules become sender-side only. See also the hide (H) and show (S) rules, which are an alternate way to specify sending-side includes/excludes. - An `r` is used to indicate that the rule applies to the receiving side. When a rule affects the receiving side, it prevents files from being deleted. See the `s` modifier for more info. See also the protect (P) and risk (R) rules, which are an alternate way to specify receiver-side includes/excludes. - A `p` indicates that a rule is perishable, meaning that it is ignored in directories that are being deleted. For instance, the [`--cvs-exclude`](#opt) (`-C`) option's default rules that exclude things like "CVS" and "`*.o`" are marked as perishable, and will not prevent a directory that was removed on the source from being deleted on the destination. - An `x` indicates that a rule affects xattr names in xattr copy/delete operations (and is thus ignored when matching file/dir names). If no xattr-matching rules are specified, a default xattr filtering rule is used (see the [`--xattrs`](#opt) option). ### MERGE-FILE FILTER RULES You can merge whole files into your filter rules by specifying either a merge (.) or a dir-merge (:) filter rule (as introduced in the [FILTER RULES](#) section above). There are two kinds of merged files -- single-instance ('.') and per-directory (':'). A single-instance merge file is read one time, and its rules are incorporated into the filter list in the place of the "." rule. For per-directory merge files, rsync will scan every directory that it traverses for the named file, merging its contents when the file exists into the current list of inherited rules. These per-directory rule files must be created on the sending side because it is the sending side that is being scanned for the available files to transfer. These rule files may also need to be transferred to the receiving side if you want them to affect what files don't get deleted (see [PER-DIRECTORY RULES AND DELETE](#) below). Some examples: > merge /etc/rsync/default.rules > . /etc/rsync/default.rules > dir-merge .per-dir-filter > dir-merge,n- .non-inherited-per-dir-excludes > :n- .non-inherited-per-dir-excludes The following modifiers are accepted after a merge or dir-merge rule: - A `-` specifies that the file should consist of only exclude patterns, with no other rule-parsing except for in-file comments. - A `+` specifies that the file should consist of only include patterns, with no other rule-parsing except for in-file comments. - A `C` is a way to specify that the file should be read in a CVS-compatible manner. This turns on 'n', 'w', and '-', but also allows the list-clearing token (!) to be specified. If no filename is provided, ".cvsignore" is assumed. - A `e` will exclude the merge-file name from the transfer; e.g. "dir-merge,e .rules" is like "dir-merge .rules" and "- .rules". - An `n` specifies that the rules are not inherited by subdirectories. - A `w` specifies that the rules are word-split on whitespace instead of the normal line-splitting. This also turns off comments. Note: the space that separates the prefix from the rule is treated specially, so "- foo + bar" is parsed as two rules (assuming that prefix-parsing wasn't also disabled). - You may also specify any of the modifiers for the "+" or "-" rules (above) in order to have the rules that are read in from the file default to having that modifier set (except for the `!` modifier, which would not be useful). For instance, "merge,-/ .excl" would treat the contents of .excl as absolute-path excludes, while "dir-merge,s .filt" and ":sC" would each make all their per-directory rules apply only on the sending side. If the merge rule specifies sides to affect (via the `s` or `r` modifier or both), then the rules in the file must not specify sides (via a modifier or a rule prefix such as `hide`). Per-directory rules are inherited in all subdirectories of the directory where the merge-file was found unless the 'n' modifier was used. Each subdirectory's rules are prefixed to the inherited per-directory rules from its parents, which gives the newest rules a higher priority than the inherited rules. The entire set of dir-merge rules are grouped together in the spot where the merge-file was specified, so it is possible to override dir-merge rules via a rule that got specified earlier in the list of global rules. When the list-clearing rule ("!") is read from a per-directory file, it only clears the inherited rules for the current merge file. Another way to prevent a single rule from a dir-merge file from being inherited is to anchor it with a leading slash. Anchored rules in a per-directory merge-file are relative to the merge-file's directory, so a pattern "/foo" would only match the file "foo" in the directory where the dir-merge filter file was found. Here's an example filter file which you'd specify via `--filter=". file":` > merge /home/user/.global-filter > - *.gz > dir-merge .rules > + *.[ch] > - *.o > - foo* This will merge the contents of the /home/user/.global-filter file at the start of the list and also turns the ".rules" filename into a per-directory filter file. All rules read in prior to the start of the directory scan follow the global anchoring rules (i.e. a leading slash matches at the root of the transfer). If a per-directory merge-file is specified with a path that is a parent directory of the first transfer directory, rsync will scan all the parent dirs from that starting point to the transfer directory for the indicated per-directory file. For instance, here is a common filter (see [`-F`](#opt)): > --filter=': /.rsync-filter' That rule tells rsync to scan for the file .rsync-filter in all directories from the root down through the parent directory of the transfer prior to the start of the normal directory scan of the file in the directories that are sent as a part of the transfer. (Note: for an rsync daemon, the root is always the same as the module's "path".) Some examples of this pre-scanning for per-directory files: > rsync -avF /src/path/ /dest/dir > rsync -av --filter=': ../../.rsync-filter' /src/path/ /dest/dir > rsync -av --filter=': .rsync-filter' /src/path/ /dest/dir The first two commands above will look for ".rsync-filter" in "/" and "/src" before the normal scan begins looking for the file in "/src/path" and its subdirectories. The last command avoids the parent-dir scan and only looks for the ".rsync-filter" files in each directory that is a part of the transfer. If you want to include the contents of a ".cvsignore" in your patterns, you should use the rule ":C", which creates a dir-merge of the .cvsignore file, but parsed in a CVS-compatible manner. You can use this to affect where the [`--cvs-exclude`](#opt) (`-C`) option's inclusion of the per-directory .cvsignore file gets placed into your rules by putting the ":C" wherever you like in your filter rules. Without this, rsync would add the dir-merge rule for the .cvsignore file at the end of all your other rules (giving it a lower priority than your command-line rules). For example: > ``` > cat < + foo.o > :C > - *.old > EOT > rsync -avC --include=foo.o -f :C --exclude='*.old' a/ b > ``` Both of the above rsync commands are identical. Each one will merge all the per-directory .cvsignore rules in the middle of the list rather than at the end. This allows their dir-specific rules to supersede the rules that follow the :C instead of being subservient to all your rules. To affect the other CVS exclude rules (i.e. the default list of exclusions, the contents of $HOME/.cvsignore, and the value of $CVSIGNORE) you should omit the `-C` command-line option and instead insert a "-C" rule into your filter rules; e.g. "`--filter=-C`". ### LIST-CLEARING FILTER RULE You can clear the current include/exclude list by using the "!" filter rule (as introduced in the [FILTER RULES](#) section above). The "current" list is either the global list of rules (if the rule is encountered while parsing the filter options) or a set of per-directory rules (which are inherited in their own sub-list, so a subdirectory can use this to clear out the parent's rules). ### ANCHORING INCLUDE/EXCLUDE PATTERNS As mentioned earlier, global include/exclude patterns are anchored at the "root of the transfer" (as opposed to per-directory patterns, which are anchored at the merge-file's directory). If you think of the transfer as a subtree of names that are being sent from sender to receiver, the transfer-root is where the tree starts to be duplicated in the destination directory. This root governs where patterns that start with a / match. Because the matching is relative to the transfer-root, changing the trailing slash on a source path or changing your use of the [`--relative`](#opt) option affects the path you need to use in your matching (in addition to changing how much of the file tree is duplicated on the destination host). The following examples demonstrate this. Let's say that we want to match two source files, one with an absolute path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz". Here is how the various command choices differ for a 2-source transfer: > ``` > Example cmd: rsync -a /home/me /home/you /dest > +/- pattern: /me/foo/bar > +/- pattern: /you/bar/baz > Target file: /dest/me/foo/bar > Target file: /dest/you/bar/baz > ``` > ``` > Example cmd: rsync -a /home/me/ /home/you/ /dest > +/- pattern: /foo/bar (note missing "me") > +/- pattern: /bar/baz (note missing "you") > Target file: /dest/foo/bar > Target file: /dest/bar/baz > ``` > ``` > Example cmd: rsync -a --relative /home/me/ /home/you /dest > +/- pattern: /home/me/foo/bar (note full path) > +/- pattern: /home/you/bar/baz (ditto) > Target file: /dest/home/me/foo/bar > Target file: /dest/home/you/bar/baz > ``` > ``` > Example cmd: cd /home; rsync -a --relative me/foo you/ /dest > +/- pattern: /me/foo/bar (starts at specified path) > +/- pattern: /you/bar/baz (ditto) > Target file: /dest/me/foo/bar > Target file: /dest/you/bar/baz > ``` The easiest way to see what name you should filter is to just look at the output when using [`--verbose`](#opt) and put a / in front of the name (use the `--dry-run` option if you're not yet ready to copy any files). ### PER-DIRECTORY RULES AND DELETE Without a delete option, per-directory rules are only relevant on the sending side, so you can feel free to exclude the merge files themselves without affecting the transfer. To make this easy, the 'e' modifier adds this exclude for you, as seen in these two equivalent commands: > rsync -av --filter=': .excl' --exclude=.excl host:src/dir /dest > rsync -av --filter=':e .excl' host:src/dir /dest However, if you want to do a delete on the receiving side AND you want some files to be excluded from being deleted, you'll need to be sure that the receiving side knows what files to exclude. The easiest way is to include the per-directory merge files in the transfer and use [`--delete-after`](#opt), because this ensures that the receiving side gets all the same exclude rules as the sending side before it tries to delete anything: > rsync -avF --delete-after host:src/dir /dest However, if the merge files are not a part of the transfer, you'll need to either specify some global exclude rules (i.e. specified on the command line), or you'll need to maintain your own per-directory merge files on the receiving side. An example of the first is this (assume that the remote .rules files exclude themselves): > rsync -av --filter=': .rules' --filter='. /my/extra.rules' > --delete host:src/dir /dest In the above example the extra.rules file can affect both sides of the transfer, but (on the sending side) the rules are subservient to the rules merged from the .rules files because they were specified after the per-directory merge rule. In one final example, the remote side is excluding the .rsync-filter files from the transfer, but we want to use our own .rsync-filter files to control what gets deleted on the receiving side. To do this we must specifically exclude the per-directory merge files (so that they don't get deleted) and then put rules into the local files to control what else should not get deleted. Like one of these commands: > ``` > rsync -av --filter=':e /.rsync-filter' --delete \ > host:src/dir /dest > rsync -avFF --delete host:src/dir /dest > ``` ## TRANSFER RULES In addition to the [FILTER RULES](#) that affect the recursive file scans that generate the file list on the sending and (when deleting) receiving sides, there are transfer rules. These rules affect which files the generator decides need to be transferred without the side effects of an exclude filter rule. Transfer rules affect only files and never directories. Because a transfer rule does not affect what goes into the sender's (and receiver's) file list, it cannot have any effect on which files get deleted on the receiving side. For example, if the file "foo" is present in the sender's list but its size is such that it is omitted due to a transfer rule, the receiving side does not request the file. However, its presence in the file list means that a delete pass will not remove a matching file named "foo" on the receiving side. On the other hand, a server-side exclude (hide) of the file "foo" leaves the file out of the server's file list, and absent a receiver-side exclude (protect) the receiver will remove a matching file named "foo" if deletions are requested. Given that the files are still in the sender's file list, the [`--prune-empty-dirs`](#opt) option will not judge a directory as being empty even if it contains only files that the transfer rules omitted. Similarly, a transfer rule does not have any extra effect on which files are deleted on the receiving side, so setting a maximum file size for the transfer does not prevent big files from being deleted. Examples of transfer rules include the default "quick check" algorithm (which compares size & modify time), the [`--update`](#opt) option, the [`--max-size`](#opt) option, the [`--ignore-non-existing`](#opt) option, and a few others. ## BATCH MODE Batch mode can be used to apply the same set of updates to many identical systems. Suppose one has a tree which is replicated on a number of hosts. Now suppose some changes have been made to this source tree and those changes need to be propagated to the other hosts. In order to do this using batch mode, rsync is run with the write-batch option to apply the changes made to the source tree to one of the destination trees. The write-batch option causes the rsync client to store in a "batch file" all the information needed to repeat this operation against other, identical destination trees. Generating the batch file once saves having to perform the file status, checksum, and data block generation more than once when updating multiple destination trees. Multicast transport protocols can be used to transfer the batch update files in parallel to many hosts at once, instead of sending the same data to every host individually. To apply the recorded changes to another destination tree, run rsync with the read-batch option, specifying the name of the same batch file, and the destination tree. Rsync updates the destination tree using the information stored in the batch file. For your convenience, a script file is also created when the write-batch option is used: it will be named the same as the batch file with ".sh" appended. This script file contains a command-line suitable for updating a destination tree using the associated batch file. It can be executed using a Bourne (or Bourne-like) shell, optionally passing in an alternate destination tree pathname which is then used instead of the original destination path. This is useful when the destination tree path on the current host differs from the one used to create the batch file. Examples: > $ rsync --write-batch=foo -a host:/source/dir/ /adest/dir/ > $ scp foo* remote: > $ ssh remote ./foo.sh /bdest/dir/ > $ rsync --write-batch=foo -a /source/dir/ /adest/dir/ > $ ssh remote rsync --read-batch=- -a /bdest/dir/ ssh remotehost /bin/true > out.dat then look at out.dat. If everything is working correctly then out.dat should be a zero length file. If you are getting the above error from rsync then you will probably find that out.dat contains some text or data. Look at the contents and try to work out what is producing it. The most common cause is incorrectly configured shell startup scripts (such as .cshrc or .profile) that contain output statements for non-interactive logins. If you are having trouble debugging filter patterns, then try specifying the `-vv` option. At this level of verbosity rsync will show why each individual file is included or excluded. ## EXIT VALUES - **0** - Success - **1** - Syntax or usage error - **2** - Protocol incompatibility - **3** - Errors selecting input/output files, dirs - **4** - Requested action not supported. Either: - an attempt was made to manipulate 64-bit files on a platform that cannot support them - an option was specified that is supported by the client and not by the server - **5** - Error starting client-server protocol - **6** - Daemon unable to append to log-file - **10** - Error in socket I/O - **11** - Error in file I/O - **12** - Error in rsync protocol data stream - **13** - Errors with program diagnostics - **14** - Error in IPC code - **20** - Received SIGUSR1 or SIGINT - **21** - Some error returned by **waitpid()** - **22** - Error allocating core memory buffers - **23** - Partial transfer due to error - **24** - Partial transfer due to vanished source files - **25** - The --max-delete limit stopped deletions - **30** - Timeout in data send/receive - **35** - Timeout waiting for daemon connection ## ENVIRONMENT VARIABLES 0. `CVSIGNORE` The CVSIGNORE environment variable supplements any ignore patterns in .cvsignore files. See the [`--cvs-exclude`](#opt) option for more details. 0. `RSYNC_ICONV` Specify a default [`--iconv`](#opt) setting using this environment variable. First supported in 3.0.0. 0. `RSYNC_OLD_ARGS` Specify a "1" if you want the [`--old-args`](#opt) option to be enabled by default, a "2" (or more) if you want it to be enabled in the repeated-option state, or a "0" to make sure that it is disabled by default. When this environment variable is set to a non-zero value, it supersedes the [`RSYNC_PROTECT_ARGS`](#) variable. This variable is ignored if [`--old-args`](#opt), `--no-old-args`, or [`--secluded-args`](#opt) is specified on the command line. First supported in 3.2.4. 0. `RSYNC_PROTECT_ARGS` Specify a non-zero numeric value if you want the [`--secluded-args`](#opt) option to be enabled by default, or a zero value to make sure that it is disabled by default. This variable is ignored if [`--secluded-args`](#opt), `--no-secluded-args`, or [`--old-args`](#opt) is specified on the command line. First supported in 3.1.0. Starting in 3.2.4, this variable is ignored if [`RSYNC_OLD_ARGS`](#) is set to a non-zero value. 0. `RSYNC_RSH` This environment variable allows you to override the default shell used as the transport for rsync. Command line options are permitted after the command name, just as in the [`--rsh`](#opt) (`-e`) option. 0. `RSYNC_PROXY` This environment variable allows you to redirect your rsync client to use a web proxy when connecting to an rsync daemon. You should set `RSYNC_PROXY` to a hostname:port pair. 0. `RSYNC_PASSWORD` This environment variable allows you to set the password for an rsync **daemon** connection, which avoids the password prompt. Note that this does **not** supply a password to a remote shell transport such as ssh (consult its documentation for how to do that). 0. `USER` or `LOGNAME` The USER or LOGNAME environment variables are used to determine the default username sent to an rsync daemon. If neither is set, the username defaults to "nobody". If both are set, `USER` takes precedence. 0. `RSYNC_PARTIAL_DIR` This environment variable specifies the directory to use for a [`--partial`](#opt) transfer without implying that partial transfers be enabled. See the [`--partial-dir`](#opt) option for full details. 0. `RSYNC_COMPRESS_LIST` This environment variable allows you to customize the negotiation of the compression algorithm by specifying an alternate order or a reduced list of names. Use the command `rsync --version` to see the available compression names. See the [`--compress`](#opt) option for full details. 0. `RSYNC_CHECKSUM_LIST` This environment variable allows you to customize the negotiation of the checksum algorithm by specifying an alternate order or a reduced list of names. Use the command `rsync --version` to see the available checksum names. See the [`--checksum-choice`](#opt) option for full details. 0. `RSYNC_MAX_ALLOC` This environment variable sets an allocation maximum as if you had used the [`--max-alloc`](#opt) option. 0. `RSYNC_PORT` This environment variable is not read by rsync, but is instead set in its sub-environment when rsync is running the remote shell in combination with a daemon connection. This allows a script such as [`rsync-ssl`](rsync-ssl.1) to be able to know the port number that the user specified on the command line. 0. `HOME` This environment variable is used to find the user's default .cvsignore file. 0. `RSYNC_CONNECT_PROG` This environment variable is mainly used in debug setups to set the program to use when making a daemon connection. See [CONNECTING TO AN RSYNC DAEMON](#) for full details. 0. `RSYNC_SHELL` This environment variable is mainly used in debug setups to set the program to use to run the program specified by [`RSYNC_CONNECT_PROG`](#). See [CONNECTING TO AN RSYNC DAEMON](#) for full details. ## FILES /etc/rsyncd.conf or rsyncd.conf ## SEE ALSO [**rsync-ssl**(1)](rsync-ssl.1), [**rsyncd.conf**(5)](rsyncd.conf.5), [**rrsync**(1)](rrsync.1) ## BUGS - Times are transferred as \*nix time_t values. - When transferring to FAT filesystems rsync may re-sync unmodified files. See the comments on the [`--modify-window`](#opt) option. - File permissions, devices, etc. are transferred as native numerical values. - See also the comments on the [`--delete`](#opt) option. Please report bugs! See the web site at . ## VERSION This manpage is current for version @VERSION@ of rsync. ## INTERNAL OPTIONS The options `--server` and `--sender` are used internally by rsync, and should never be typed by a user under normal circumstances. Some awareness of these options may be needed in certain scenarios, such as when setting up a login that can only run an rsync command. For instance, the support directory of the rsync distribution has an example script named rrsync (for restricted rsync) that can be used with a restricted ssh login. ## CREDITS Rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. An rsync web site is available at . The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page. The rsync github project is . We would be delighted to hear from you if you like this program. Please contact the mailing-list at . This program uses the excellent zlib compression library written by Jean-loup Gailly and Mark Adler. ## THANKS Special thanks go out to: John Van Essen, Matt McCutchen, Wesley W. Terpstra, David Dykstra, Jos Backus, Sebastian Krahmer, Martin Pool, and our gone-but-not-forgotten compadre, J.W. Schultz. Thanks also to Richard Brent, Brendan Mackay, Bill Waite, Stephen Rothwell and David Bell. I've probably missed some people, my apologies if I have. ## AUTHOR Rsync was originally written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. It is currently maintained by Wayne Davison. Mailing lists for support and development are available at . rsync-3.2.7/prepare-source0000775000000000000000000000330114217634073014247 0ustar rootroot#!/bin/sh # Either use autoconf and autoheader to create configure.sh and config.h.in # or (optionally) fetch the latest development versions of generated files. # # Specify one action or more than one to provide a fall-back: # # build build the config files [the default w/no arg] # fetch fetch the latest dev autoconfig files # fetchgen fetch all the latest dev generated files (including manpages) # fetchSRC fetch the latest dev source files [NON-GENERATED FILES] # # The script stops after the first successful action. dir=`dirname $0` if test x"$dir" = x; then dir=. fi if test "$dir" = '.'; then branch=`packaging/prep-auto-dir` || exit 1 if test x"$branch" != x; then cd build || exit 1 dir=.. fi fi if test "$dir" != '.'; then for lnk in configure.ac m4; do if test ! -h $lnk; then rm -f $lnk # Just in case ln -s "$dir/$lnk" $lnk fi done for fn in configure.sh config.h.in aclocal.m4; do test ! -f $fn && test -f "$dir/$fn" && cp -p "$dir/$fn" $fn done fi if test $# = 0; then set -- build fi for action in "${@}"; do case "$action" in build|make) make -f "$dir/prepare-source.mak" ;; fetch|fetchgen) if test "$action" = fetchgen; then match='*' else match='[ca]*' fi $dir/rsync-ssl -iipc --no-motd "rsync://download.samba.org/rsyncftp/generated-files/$match" ./ test $? != 0 && continue sleep 1 # The following files need to be newer than aclocal.m4 touch configure.sh config.h.in ;; fetchSRC) ./rsync-ssl -iipr --no-motd --exclude=/.git/ rsync://download.samba.org/ftp/pub/unpacked/rsync/ . ;; *) echo "Unknown action: $action" exit 1 ;; esac if test $? = 0; then exit fi done exit 1 rsync-3.2.7/sender.c0000664000000000000000000002747414300464433013024 0ustar rootroot/* * Routines only used by the sending process. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2022 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 "inums.h" extern int do_xfers; extern int am_server; extern int am_daemon; extern int local_server; extern int inc_recurse; extern int log_before_transfer; extern int stdout_format_has_i; extern int logfile_format_has_i; extern int want_xattr_optim; extern int csum_length; extern int append_mode; extern int copy_links; extern int io_error; extern int flist_eof; extern int whole_file; extern int allowed_lull; extern int copy_devices; extern int preserve_xattrs; extern int protocol_version; extern int remove_source_files; extern int updating_basis_file; extern int make_backups; extern int inplace; extern int inplace_partial; extern int batch_fd; extern int write_batch; extern int file_old_total; extern BOOL want_progress_now; extern struct stats stats; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern char num_dev_ino_buf[4 + 8 + 8]; BOOL extra_flist_sending_enabled; /** * @file * * The sender gets checksums from the generator, calculates deltas, * and transmits them to the receiver. The sender process runs on the * machine holding the source files. **/ /** * Receive the checksums for a buffer **/ static struct sum_struct *receive_sums(int f) { struct sum_struct *s = new(struct sum_struct); int lull_mod = protocol_version >= 31 ? 0 : allowed_lull * 5; OFF_T offset = 0; int32 i; read_sum_head(f, s); s->sums = NULL; if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "count=%s n=%ld rem=%ld\n", big_num(s->count), (long)s->blength, (long)s->remainder); } if (append_mode > 0) { s->flength = (OFF_T)s->count * s->blength; if (s->remainder) s->flength -= s->blength - s->remainder; return s; } if (s->count == 0) return(s); s->sums = new_array(struct sum_buf, s->count); for (i = 0; i < s->count; i++) { s->sums[i].sum1 = read_int(f); read_buf(f, s->sums[i].sum2, s->s2length); s->sums[i].offset = offset; s->sums[i].flags = 0; if (i == s->count-1 && s->remainder != 0) s->sums[i].len = s->remainder; else s->sums[i].len = s->blength; offset += s->sums[i].len; if (lull_mod && !(i % lull_mod)) maybe_send_keepalive(time(NULL), True); if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "chunk[%d] len=%d offset=%s sum1=%08x\n", i, s->sums[i].len, big_num(s->sums[i].offset), s->sums[i].sum1); } } s->flength = offset; return s; } void successful_send(int ndx) { char fname[MAXPATHLEN]; char *failed_op; struct file_struct *file; struct file_list *flist; STRUCT_STAT st; if (!remove_source_files) return; flist = flist_for_ndx(ndx, "successful_send"); file = flist->files[ndx - flist->ndx_start]; if (!change_pathname(file, NULL, 0)) return; f_name(file, fname); if ((copy_links ? do_stat(fname, &st) : do_lstat(fname, &st)) < 0) { failed_op = "re-lstat"; goto failed; } if (local_server && (int64)st.st_dev == IVAL64(num_dev_ino_buf, 4) && (int64)st.st_ino == IVAL64(num_dev_ino_buf, 4 + 8)) { rprintf(FERROR_XFER, "ERROR: Skipping sender remove of destination file: %s\n", fname); return; } if (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime #ifdef ST_MTIME_NSEC || (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file)) #endif ) { rprintf(FERROR_XFER, "ERROR: Skipping sender remove for changed file: %s\n", fname); return; } if (do_unlink(fname) < 0) { failed_op = "remove"; failed: if (errno == ENOENT) rprintf(FINFO, "sender file already removed: %s\n", fname); else rsyserr(FERROR_XFER, errno, "sender failed to %s %s", failed_op, fname); } else { if (INFO_GTE(REMOVE, 1)) rprintf(FINFO, "sender removed %s\n", fname); } } static void write_ndx_and_attrs(int f_out, int ndx, int iflags, const char *fname, struct file_struct *file, uchar fnamecmp_type, char *buf, int len) { write_ndx(f_out, ndx); if (protocol_version < 29) return; write_shortint(f_out, iflags); if (iflags & ITEM_BASIS_TYPE_FOLLOWS) write_byte(f_out, fnamecmp_type); if (iflags & ITEM_XNAME_FOLLOWS) write_vstring(f_out, buf, len); #ifdef SUPPORT_XATTRS if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) send_xattr_request(fname, file, f_out); #endif } void send_files(int f_in, int f_out) { int fd = -1; struct sum_struct *s; struct map_struct *mbuf = NULL; STRUCT_STAT st; char fname[MAXPATHLEN], xname[MAXPATHLEN]; const char *path, *slash; uchar fnamecmp_type; int iflags, xlen; struct file_struct *file; int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1; int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i; enum logcode log_code = log_before_transfer ? FLOG : FINFO; int f_xfer = write_batch < 0 ? batch_fd : f_out; int save_io_error = io_error; int ndx, j; if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "send_files starting\n"); if (whole_file < 0) whole_file = 0; progress_init(); while (1) { if (inc_recurse) { send_extra_file_list(f_out, MIN_FILECNT_LOOKAHEAD); extra_flist_sending_enabled = !flist_eof; } /* This call also sets cur_flist. */ ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type, xname, &xlen); extra_flist_sending_enabled = False; if (ndx == NDX_DONE) { if (!am_server && cur_flist) { set_current_file_index(NULL, 0); if (INFO_GTE(PROGRESS, 2)) end_progress(0); } if (inc_recurse && first_flist) { file_old_total -= first_flist->used; flist_free(first_flist); if (first_flist) { if (first_flist == cur_flist) file_old_total = cur_flist->used; write_ndx(f_out, NDX_DONE); continue; } } if (++phase > max_phase) break; if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "send_files phase=%d\n", phase); write_ndx(f_out, NDX_DONE); continue; } if (inc_recurse) send_extra_file_list(f_out, MIN_FILECNT_LOOKAHEAD); if (ndx - cur_flist->ndx_start >= 0) file = cur_flist->files[ndx - cur_flist->ndx_start]; else file = dir_flist->files[cur_flist->parent_ndx]; if (F_PATHNAME(file)) { path = F_PATHNAME(file); slash = "/"; } else { path = slash = ""; } if (!change_pathname(file, NULL, 0)) continue; f_name(file, fname); if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname); #ifdef SUPPORT_XATTRS if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))) recv_xattr_request(file, f_in); #endif if (!(iflags & ITEM_TRANSFER)) { maybe_log_item(file, iflags, itemizing, xname); write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen); if (iflags & ITEM_IS_NEW) { stats.created_files++; if (S_ISREG(file->mode)) { /* Nothing further to count. */ } else if (S_ISDIR(file->mode)) stats.created_dirs++; #ifdef SUPPORT_LINKS else if (S_ISLNK(file->mode)) stats.created_symlinks++; #endif else if (IS_DEVICE(file->mode)) stats.created_devices++; else stats.created_specials++; } continue; } if (phase == 2) { rprintf(FERROR, "got transfer request in phase 2 [%s]\n", who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (file->flags & FLAG_FILE_SENT) { if (csum_length == SHORT_SUM_LENGTH) { /* For inplace: redo phase turns off the backup * flag so that we do a regular inplace send. */ make_backups = -make_backups; append_mode = -append_mode; csum_length = SUM_LENGTH; } } else { if (csum_length != SHORT_SUM_LENGTH) { make_backups = -make_backups; append_mode = -append_mode; csum_length = SHORT_SUM_LENGTH; } if (iflags & ITEM_IS_NEW) stats.created_files++; } updating_basis_file = (inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR) || (inplace && (protocol_version >= 29 ? fnamecmp_type == FNAMECMP_FNAME : make_backups <= 0)); if (!am_server) set_current_file_index(file, ndx); stats.xferred_files++; stats.total_transferred_size += F_LENGTH(file); remember_initial_stats(); if (!do_xfers) { /* log the transfer */ log_item(FCLIENT, file, iflags, NULL); write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen); continue; } if (!(s = receive_sums(f_in))) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "receive_sums failed\n"); exit_cleanup(RERR_PROTOCOL); } fd = do_open(fname, O_RDONLY, 0); if (fd == -1) { if (errno == ENOENT) { enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING; io_error |= IOERR_VANISHED; rprintf(c, "file has vanished: %s\n", full_fname(fname)); } else { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "send_files failed to open %s", full_fname(fname)); } free_sums(s); if (protocol_version >= 30) send_msg_int(MSG_NO_SEND, ndx); continue; } /* map the local file */ if (do_fstat(fd, &st) != 0) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "fstat failed"); free_sums(s); close(fd); exit_cleanup(RERR_FILEIO); } if (IS_DEVICE(st.st_mode)) { if (!copy_devices) { rprintf(FERROR, "attempt to copy device contents without --copy-devices\n"); exit_cleanup(RERR_PROTOCOL); } if (st.st_size == 0) st.st_size = get_device_size(fd, fname); } if (append_mode > 0 && st.st_size < F_LENGTH(file)) { rprintf(FWARNING, "skipped diminished file: %s\n", full_fname(fname)); free_sums(s); close(fd); if (protocol_version >= 30) send_msg_int(MSG_NO_SEND, ndx); continue; } if (st.st_size) { int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE); mbuf = map_file(fd, st.st_size, read_size, s->blength); } else mbuf = NULL; if (DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "send_files mapped %s%s%s of size %s\n", path,slash,fname, big_num(st.st_size)); } write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen); write_sum_head(f_xfer, s); if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO, "calling match_sums %s%s%s\n", path,slash,fname); if (log_before_transfer) log_item(FCLIENT, file, iflags, NULL); else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1)) rprintf(FCLIENT, "%s\n", fname); set_compression(fname); match_sums(f_xfer, s, mbuf, st.st_size); if (INFO_GTE(PROGRESS, 1)) end_progress(st.st_size); else if (want_progress_now) instant_progress(fname); log_item(log_code, file, iflags, NULL); if (mbuf) { j = unmap_file(mbuf); if (j) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, j, "read errors mapping %s", full_fname(fname)); } } close(fd); free_sums(s); if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "sender finished %s%s%s\n", path,slash,fname); /* Flag that we actually sent this entry. */ file->flags |= FLAG_FILE_SENT; } if (make_backups < 0) make_backups = -make_backups; if (io_error != save_io_error && protocol_version >= 30) send_msg_int(MSG_IO_ERROR, io_error); if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "send files finished\n"); match_report(); write_ndx(f_out, NDX_DONE); } rsync-3.2.7/rounding.c0000664000000000000000000000227013672767223013372 0ustar rootroot/* * A pre-compilation helper program to aid in the creation of rounding.h. * * Copyright (C) 2007-2020 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" #define ARRAY_LEN (EXTRA_ROUNDING+1) #define SIZEOF(x) ((long int)sizeof (x)) struct test { union file_extras extras[ARRAY_LEN]; int64 test; }; #define ACTUAL_SIZE SIZEOF(struct test) #define EXPECTED_SIZE (SIZEOF(union file_extras) * ARRAY_LEN + SIZEOF(int64)) int main(UNUSED(int argc), UNUSED(char *argv[])) { static int test_array[1 - 2 * (ACTUAL_SIZE != EXPECTED_SIZE)]; test_array[0] = 0; return 0; } rsync-3.2.7/configure0000775000000000000000000000123113676252421013275 0ustar rootroot#!/bin/sh -e # This configure script ensures that the configure.sh script exists, and # if not, it tries to fetch rsync's generated files or build them. We # then transfer control to the configure.sh script to do the real work. dir=`dirname $0` if test x"$dir" = x; then dir=. fi if test "$dir" = '.'; then branch=`packaging/prep-auto-dir` || exit 1 if test x"$branch" != x; then cd build || exit 1 dir=.. fi fi if test ! -f configure.sh; then if ! "$dir/prepare-source" build; then echo 'Failed to build configure.sh and/or config.h.in -- giving up.' >&2 rm -f configure.sh exit 1 fi fi exec ./configure.sh --srcdir="$dir" "${@}" rsync-3.2.7/maybe-make-man0000775000000000000000000000150114162465417014077 0ustar rootroot#!/bin/sh if [ $# != 1 ]; then echo "Usage: $0 NAME.NUM.md" 1>&2 exit 1 fi inname="$1" srcdir=`dirname "$0"` flagfile="$srcdir/.md2man-works" if [ ! -f "$flagfile" ]; then # We test our smallest manpage just to see if the python setup works. if "$srcdir/md-convert" --test "$srcdir/rsync-ssl.1.md" >/dev/null 2>&1; then touch $flagfile else outname=`echo "$inname" | sed 's/\.md$//'` if [ -f "$outname" ]; then exit 0 elif [ -f "$srcdir/$outname" ]; then echo "Copying $srcdir/$outname" cp -p "$srcdir/$outname" . exit 0 else echo "ERROR: $outname cannot be created." if [ -f "$HOME/build_farm/build_test.fns" ]; then exit 0 # No exit errorno to avoid a build failure in the samba build farm else exit 1 fi fi fi fi "$srcdir/md-convert" "$srcdir/$inname" rsync-3.2.7/popt/0000775000000000000000000000000014324367162012353 5ustar rootrootrsync-3.2.7/popt/popt.h0000664000000000000000000003767211364621666013530 0ustar rootroot/** \file popt/popt.h * \ingroup popt */ /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #ifndef H_POPT #define H_POPT #include /* for FILE * */ #define POPT_OPTION_DEPTH 10 /** \ingroup popt * \name Arg type identifiers */ /*@{*/ #define POPT_ARG_NONE 0 /*!< no arg */ #define POPT_ARG_STRING 1 /*!< arg will be saved as string */ #define POPT_ARG_INT 2 /*!< arg will be converted to int */ #define POPT_ARG_LONG 3 /*!< arg will be converted to long */ #define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */ #define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be set first in table; arg points to callback, descrip points to callback data to pass */ #define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain for this table and any included tables; arg points to the domain string */ #define POPT_ARG_VAL 7 /*!< arg should take value val */ #define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */ #define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */ #define POPT_ARG_MASK 0x0000FFFF /*@}*/ /** \ingroup popt * \name Arg modifiers */ /*@{*/ #define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */ #define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */ #define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */ #define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */ #define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */ #define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */ #define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */ #define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */ #define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */ #define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */ #define POPT_ARGFLAG_LOGICALOPS \ (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR) #define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR) /*!< set arg bit(s) */ #define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND) /*!< clear arg bit(s) */ #define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */ /*@}*/ /** \ingroup popt * \name Callback modifiers */ /*@{*/ #define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */ #define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */ #define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line, not the subtable */ #define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */ #define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */ /*@}*/ /** \ingroup popt * \name Error return values */ /*@{*/ #define POPT_ERROR_NOARG -10 /*!< missing argument */ #define POPT_ERROR_BADOPT -11 /*!< unknown option */ #define POPT_ERROR_UNWANTEDARG -12 /*!< option does not take an argument */ #define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */ #define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */ #define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */ #define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */ #define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */ #define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */ #define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */ #define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */ /*@}*/ /** \ingroup popt * \name poptBadOption() flags */ /*@{*/ #define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */ /*@}*/ /** \ingroup popt * \name poptGetContext() flags */ /*@{*/ #define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */ #define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */ #define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */ #define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */ /*@}*/ /** \ingroup popt */ struct poptOption { /*@observer@*/ /*@null@*/ const char * longName; /*!< may be NULL */ char shortName; /*!< may be NUL */ int argInfo; /*@shared@*/ /*@null@*/ void * arg; /*!< depends on argInfo */ int val; /*!< 0 means don't return, just update flag */ /*@observer@*/ /*@null@*/ const char * descrip; /*!< description for autohelp -- may be NULL */ /*@observer@*/ /*@null@*/ const char * argDescrip; /*!< argument description for autohelp */ }; /** \ingroup popt * A popt alias argument for poptAddAlias(). */ struct poptAlias { /*@owned@*/ /*@null@*/ const char * longName; /*!< may be NULL */ char shortName; /*!< may be NUL */ int argc; /*@owned@*/ const char ** argv; /*!< must be free()able */ }; /** \ingroup popt * A popt alias or exec argument for poptAddItem(). */ /*@-exporttype@*/ typedef struct poptItem_s { struct poptOption option; /*!< alias/exec name(s) and description. */ int argc; /*!< (alias) no. of args. */ /*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */ } * poptItem; /*@=exporttype@*/ /** \ingroup popt * \name Auto-generated help/usage */ /*@{*/ /** * Empty table marker to enable displaying popt alias/exec options. */ /*@-exportvar@*/ /*@unchecked@*/ /*@observer@*/ extern struct poptOption poptAliasOptions[]; /*@=exportvar@*/ #define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ 0, "Options implemented via popt alias/exec:", NULL }, /** * Auto help table options. */ /*@-exportvar@*/ /*@unchecked@*/ /*@observer@*/ extern struct poptOption poptHelpOptions[]; /*@=exportvar@*/ /*@-exportvar@*/ /*@unchecked@*/ /*@observer@*/ extern struct poptOption * poptHelpOptionsI18N; /*@=exportvar@*/ #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ 0, "Help options:", NULL }, #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL } /*@}*/ /** \ingroup popt */ /*@-exporttype@*/ typedef /*@abstract@*/ struct poptContext_s * poptContext; /*@=exporttype@*/ /** \ingroup popt */ #ifndef __cplusplus /*@-exporttype -typeuse@*/ typedef struct poptOption * poptOption; /*@=exporttype =typeuse@*/ #endif /*@-exportconst@*/ enum poptCallbackReason { POPT_CALLBACK_REASON_PRE = 0, POPT_CALLBACK_REASON_POST = 1, POPT_CALLBACK_REASON_OPTION = 2 }; /*@=exportconst@*/ #ifdef __cplusplus extern "C" { #endif /*@-type@*/ /** \ingroup popt * Table callback prototype. * @param con context * @param reason reason for callback * @param opt option that triggered callback * @param arg @todo Document. * @param data @todo Document. */ typedef void (*poptCallbackType) (poptContext con, enum poptCallbackReason reason, /*@null@*/ const struct poptOption * opt, /*@null@*/ const char * arg, /*@null@*/ const void * data) /*@globals internalState @*/ /*@modifies internalState @*/; /** \ingroup popt * Initialize popt context. * @param name context name (usually argv[0] program name) * @param argc no. of arguments * @param argv argument array * @param options address of popt option table * @param flags or'd POPT_CONTEXT_* bits * @return initialized popt context */ /*@only@*/ /*@null@*/ poptContext poptGetContext( /*@dependent@*/ /*@keep@*/ const char * name, int argc, /*@dependent@*/ /*@keep@*/ const char ** argv, /*@dependent@*/ /*@keep@*/ const struct poptOption * options, int flags) /*@*/; /** \ingroup popt * Reinitialize popt context. * @param con context */ /*@unused@*/ void poptResetContext(/*@null@*/poptContext con) /*@modifies con @*/; /** \ingroup popt * Return value of next option found. * @param con context * @return next option val, -1 on last item, POPT_ERROR_* on error */ int poptGetNextOpt(/*@null@*/poptContext con) /*@globals fileSystem, internalState @*/ /*@modifies con, fileSystem, internalState @*/; /** \ingroup popt * Return next option argument (if any). * @param con context * @return option argument, NULL if no argument is available */ /*@observer@*/ /*@null@*/ /*@unused@*/ const char * poptGetOptArg(/*@null@*/poptContext con) /*@modifies con @*/; /** \ingroup popt * Return next argument. * @param con context * @return next argument, NULL if no argument is available */ /*@observer@*/ /*@null@*/ /*@unused@*/ const char * poptGetArg(/*@null@*/poptContext con) /*@modifies con @*/; /** \ingroup popt * Peek at current argument. * @param con context * @return current argument, NULL if no argument is available */ /*@observer@*/ /*@null@*/ /*@unused@*/ const char * poptPeekArg(/*@null@*/poptContext con) /*@*/; /** \ingroup popt * Return remaining arguments. * @param con context * @return argument array, NULL terminated */ /*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con) /*@modifies con @*/; /** \ingroup popt * Return the option which caused the most recent error. * @param con context * @param flags * @return offending option */ /*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags) /*@*/; /** \ingroup popt * Destroy context. * @param con context * @return NULL always */ /*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con) /*@modifies con @*/; /** \ingroup popt * Add arguments to context. * @param con context * @param argv argument array, NULL terminated * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure */ /*@unused@*/ int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv) /*@modifies con @*/; /** \ingroup popt * Add alias to context. * @todo Pass alias by reference, not value. * @deprecated Use poptAddItem instead. * @param con context * @param alias alias to add * @param flags (unused) * @return 0 on success */ /*@unused@*/ int poptAddAlias(poptContext con, struct poptAlias alias, int flags) /*@modifies con @*/; /** \ingroup popt * Add alias/exec item to context. * @param con context * @param newItem alias/exec item to add * @param flags 0 for alias, 1 for exec * @return 0 on success */ int poptAddItem(poptContext con, poptItem newItem, int flags) /*@modifies con @*/; /** \ingroup popt * Read configuration file. * @param con context * @param fn file name to read * @return 0 on success, POPT_ERROR_ERRNO on failure */ int poptReadConfigFile(poptContext con, const char * fn) /*@globals errno, fileSystem, internalState @*/ /*@modifies con->execs, con->numExecs, errno, fileSystem, internalState @*/; /** \ingroup popt * Read default configuration from /etc/popt and $HOME/.popt. * @param con context * @param useEnv (unused) * @return 0 on success, POPT_ERROR_ERRNO on failure */ /*@unused@*/ int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) /*@globals fileSystem, internalState @*/ /*@modifies con->execs, con->numExecs, fileSystem, internalState @*/; /** \ingroup popt * Duplicate an argument array. * @note: The argument array is malloc'd as a single area, so only argv must * be free'd. * * @param argc no. of arguments * @param argv argument array * @retval argcPtr address of returned no. of arguments * @retval argvPtr address of returned argument array * @return 0 on success, POPT_ERROR_NOARG on failure */ int poptDupArgv(int argc, /*@null@*/ const char **argv, /*@null@*/ /*@out@*/ int * argcPtr, /*@null@*/ /*@out@*/ const char *** argvPtr) /*@modifies *argcPtr, *argvPtr @*/; /** \ingroup popt * Parse a string into an argument array. * The parse allows ', ", and \ quoting, but ' is treated the same as " and * both may include \ quotes. * @note: The argument array is malloc'd as a single area, so only argv must * be free'd. * * @param s string to parse * @retval argcPtr address of returned no. of arguments * @retval argvPtr address of returned argument array */ int poptParseArgvString(const char * s, /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr) /*@modifies *argcPtr, *argvPtr @*/; /** \ingroup popt * Parses an input configuration file and returns an string that is a * command line. For use with popt. You must free the return value when done. * * Given the file: \verbatim # this line is ignored # this one too aaa bbb ccc bla=bla this_is = fdsafdas bad_line= reall bad line reall bad line = again 5555= 55555 test = with lots of spaces \endverbatim * * The result is: \verbatim --aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces" \endverbatim * * Passing this to poptParseArgvString() yields an argv of: \verbatim '--aaa' '--bbb' '--ccc' '--bla=bla' '--this_is=fdsafdas' '--5555=55555' '--test=with lots of spaces' \endverbatim * * @bug NULL is returned if file line is too long. * @bug Silently ignores invalid lines. * * @param fp file handle to read * @param *argstrp return string of options (malloc'd) * @param flags unused * @return 0 on success * @see poptParseArgvString */ /*@-fcnuse@*/ int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags) /*@globals fileSystem @*/ /*@modifies *fp, *argstrp, fileSystem @*/; /*@=fcnuse@*/ /** \ingroup popt * Return formatted error string for popt failure. * @param error popt error * @return error string */ /*@observer@*/ const char * poptStrerror(const int error) /*@*/; /** \ingroup popt * Limit search for executables. * @param con context * @param path single path to search for executables * @param allowAbsolute absolute paths only? */ /*@unused@*/ void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) /*@modifies con @*/; /** \ingroup popt * Print detailed description of options. * @param con context * @param fp ouput file handle * @param flags (unused) */ void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/; /** \ingroup popt * Print terse description of options. * @param con context * @param fp ouput file handle * @param flags (unused) */ void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/; /** \ingroup popt * Provide text to replace default "[OPTION...]" in help/usage output. * @param con context * @param text replacement text */ /*@-fcnuse@*/ void poptSetOtherOptionHelp(poptContext con, const char * text) /*@modifies con @*/; /*@=fcnuse@*/ /** \ingroup popt * Return argv[0] from context. * @param con context * @return argv[0] */ /*@-fcnuse@*/ /*@observer@*/ const char * poptGetInvocationName(poptContext con) /*@*/; /*@=fcnuse@*/ /** \ingroup popt * Shuffle argv pointers to remove stripped args, returns new argc. * @param con context * @param argc no. of args * @param argv arg vector * @return new argc */ /*@-fcnuse@*/ int poptStrippedArgv(poptContext con, int argc, char ** argv) /*@modifies *argv @*/; /*@=fcnuse@*/ /** * Save a long, performing logical operation with value. * @warning Alignment check may be too strict on certain platorms. * @param arg integer pointer, aligned on int boundary. * @param argInfo logical operation (see POPT_ARGFLAG_*) * @param aLong value to use * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION */ /*@-incondefs@*/ /*@unused@*/ int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong) /*@modifies *arg @*/ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; /*@=incondefs@*/ /** * Save an integer, performing logical operation with value. * @warning Alignment check may be too strict on certain platorms. * @param arg integer pointer, aligned on int boundary. * @param argInfo logical operation (see POPT_ARGFLAG_*) * @param aLong value to use * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION */ /*@-incondefs@*/ /*@unused@*/ int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) /*@modifies *arg @*/ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; /*@=incondefs@*/ /*@=type@*/ #ifdef __cplusplus } #endif #endif rsync-3.2.7/popt/popthelp.c0000664000000000000000000005411110764561320014350 0ustar rootroot/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /** \ingroup popt * \file popt/popthelp.c */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" /*#define POPT_WCHAR_HACK*/ #ifdef POPT_WCHAR_HACK #include /* for mbsrtowcs */ /*@access mbstate_t @*/ #endif #include "poptint.h" /*@access poptContext@*/ /** * Display arguments. * @param con context * @param foo (unused) * @param key option(s) * @param arg (unused) * @param data (unused) */ static void displayArgs(poptContext con, /*@unused@*/ UNUSED(enum poptCallbackReason foo), struct poptOption * key, /*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data)) /*@globals fileSystem@*/ /*@modifies fileSystem@*/ { if (key->shortName == '?') poptPrintHelp(con, stdout, 0); else poptPrintUsage(con, stdout, 0); exit(0); } #ifdef NOTYET /*@unchecked@*/ static int show_option_defaults = 0; #endif /** * Empty table marker to enable displaying popt alias/exec options. */ /*@observer@*/ /*@unchecked@*/ struct poptOption poptAliasOptions[] = { POPT_TABLEEND }; /** * Auto help table options. */ /*@-castfcnptr@*/ /*@observer@*/ /*@unchecked@*/ struct poptOption poptHelpOptions[] = { { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, POPT_TABLEEND } ; /*@observer@*/ /*@unchecked@*/ static struct poptOption poptHelpOptions2[] = { /*@-readonlytrans@*/ { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL}, /*@=readonlytrans@*/ { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, #ifdef NOTYET { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, N_("Display option defaults in message"), NULL }, #endif POPT_TABLEEND } ; /*@observer@*/ /*@unchecked@*/ struct poptOption * poptHelpOptionsI18N = poptHelpOptions2; /*@=castfcnptr@*/ /** * @param table option(s) */ /*@observer@*/ /*@null@*/ static const char * getTableTranslationDomain(/*@null@*/ const struct poptOption *table) /*@*/ { const struct poptOption *opt; if (table != NULL) for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->argInfo == POPT_ARG_INTL_DOMAIN) return opt->arg; } return NULL; } /** * @param opt option(s) * @param translation_domain translation domain */ /*@observer@*/ /*@null@*/ static const char * getArgDescrip(const struct poptOption * opt, /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ /*@null@*/ UNUSED(const char * translation_domain)) /*@=paramuse@*/ /*@*/ { if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2)) if (opt->argDescrip) return POPT_(opt->argDescrip); if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); switch (opt->argInfo & POPT_ARG_MASK) { /*case POPT_ARG_NONE: return POPT_("NONE");*/ /* impossible */ #ifdef DYING case POPT_ARG_VAL: return POPT_("VAL"); #else case POPT_ARG_VAL: return NULL; #endif case POPT_ARG_INT: return POPT_("INT"); case POPT_ARG_LONG: return POPT_("LONG"); case POPT_ARG_STRING: return POPT_("STRING"); case POPT_ARG_FLOAT: return POPT_("FLOAT"); case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); default: return POPT_("ARG"); } } /** * Display default value for an option. * @param lineLength display positions remaining * @param opt option(s) * @param translation_domain translation domain * @return */ static /*@only@*/ /*@null@*/ char * singleOptionDefaultValue(size_t lineLength, const struct poptOption * opt, /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ /*@null@*/ UNUSED(const char * translation_domain)) /*@=paramuse@*/ /*@*/ { const char * defstr = D_(translation_domain, "default"); size_t limit, bufsize = 4*lineLength + 1; char * le = malloc(bufsize); char * l = le; if (le == NULL) return NULL; /* XXX can't happen */ /*@-boundswrite@*/ *le++ = '('; le += strlcpy(le, defstr, bufsize - 3); *le++ = ':'; *le++ = ' '; limit = bufsize - (le - l) - 1; /* -1 for closing paren */ if (opt->arg) /* XXX programmer error */ switch (opt->argInfo & POPT_ARG_MASK) { case POPT_ARG_VAL: case POPT_ARG_INT: { long aLong = *((int *)opt->arg); le += snprintf(le, limit, "%ld", aLong); } break; case POPT_ARG_LONG: { long aLong = *((long *)opt->arg); le += snprintf(le, limit, "%ld", aLong); } break; case POPT_ARG_FLOAT: { double aDouble = *((float *)opt->arg); le += snprintf(le, limit, "%g", aDouble); } break; case POPT_ARG_DOUBLE: { double aDouble = *((double *)opt->arg); le += snprintf(le, limit, "%g", aDouble); } break; case POPT_ARG_STRING: { const char * s = *(const char **)opt->arg; if (s == NULL) { le += strlcpy(le, "null", limit); } else { size_t len; limit -= 2; /* make room for quotes */ *le++ = '"'; len = strlcpy(le, s, limit); if (len >= limit) { le += limit - 3 - 1; *le++ = '.'; *le++ = '.'; *le++ = '.'; } else le += len; *le++ = '"'; } } break; case POPT_ARG_NONE: default: l = _free(l); return NULL; /*@notreached@*/ break; } *le++ = ')'; *le = '\0'; /*@=boundswrite@*/ return l; } /** * Display help text for an option. * @param fp output file handle * @param maxLeftCol largest argument display width * @param opt option(s) * @param translation_domain translation domain */ static void singleOptionHelp(FILE * fp, size_t maxLeftCol, const struct poptOption * opt, /*@null@*/ UNUSED(const char * translation_domain)) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { size_t indentLength = maxLeftCol + 5; size_t lineLength = 79 - indentLength; const char * help = D_(translation_domain, opt->descrip); const char * argDescrip = getArgDescrip(opt, translation_domain); size_t helpLength; char * defs = NULL; char * left; size_t lelen, limit; size_t nb = maxLeftCol + 1; int displaypad = 0; /* Make sure there's more than enough room in target buffer. */ if (opt->longName) nb += strlen(opt->longName); if (argDescrip) nb += strlen(argDescrip); /*@-boundswrite@*/ left = malloc(nb); if (left == NULL) return; /* XXX can't happen */ left[0] = '\0'; left[maxLeftCol] = '\0'; if (opt->longName && opt->shortName) snprintf(left, nb, "-%c, %s%s", opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), opt->longName); else if (opt->shortName != '\0') snprintf(left, nb, "-%c", opt->shortName); else if (opt->longName) snprintf(left, nb, "%s%s", ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), opt->longName); if (!*left) goto out; if (argDescrip) { char * le = left + strlen(left); if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) *le++ = '['; /* Choose type of output */ /*@-branchstate@*/ if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { defs = singleOptionDefaultValue(lineLength, opt, translation_domain); if (defs) { size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs); char * t = malloc(bufsize); if (t) { snprintf(t, bufsize, "%s %s", help ? help : "", defs); defs = _free(defs); } defs = t; } } /*@=branchstate@*/ if (opt->argDescrip == NULL) { switch (opt->argInfo & POPT_ARG_MASK) { case POPT_ARG_NONE: break; case POPT_ARG_VAL: #ifdef NOTNOW /* XXX pug ugly nerdy output */ { long aLong = opt->val; int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); int negate = (opt->argInfo & POPT_ARGFLAG_NOT); /* Don't bother displaying typical values */ if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) break; *le++ = '['; switch (ops) { case POPT_ARGFLAG_OR: *le++ = '|'; /*@innerbreak@*/ break; case POPT_ARGFLAG_AND: *le++ = '&'; /*@innerbreak@*/ break; case POPT_ARGFLAG_XOR: *le++ = '^'; /*@innerbreak@*/ break; default: /*@innerbreak@*/ break; } *le++ = (opt->longName != NULL ? '=' : ' '); if (negate) *le++ = '~'; /*@-formatconst@*/ limit = nb - (le - left); lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong); le += lelen >= limit ? limit - 1 : lelen; /*@=formatconst@*/ *le++ = ']'; } #endif break; case POPT_ARG_INT: case POPT_ARG_LONG: case POPT_ARG_FLOAT: case POPT_ARG_DOUBLE: case POPT_ARG_STRING: *le++ = (opt->longName != NULL ? '=' : ' '); limit = nb - (le - left); lelen = strlcpy(le, argDescrip, limit); le += lelen >= limit ? limit - 1 : lelen; break; default: break; } } else { *le++ = '='; limit = nb - (le - left); lelen = strlcpy(le, argDescrip, limit); if (lelen >= limit) lelen = limit - 1; le += lelen; #ifdef POPT_WCHAR_HACK { const char * scopy = argDescrip; mbstate_t t; size_t n; memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ /* Determine number of characters. */ n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); displaypad = (int) (lelen-n); } #endif } if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) *le++ = ']'; *le = '\0'; } /*@=boundswrite@*/ if (help) fprintf(fp," %-*s ", (int)maxLeftCol+displaypad, left); else { fprintf(fp," %s\n", left); goto out; } left = _free(left); /*@-branchstate@*/ if (defs) { help = defs; defs = NULL; } /*@=branchstate@*/ helpLength = strlen(help); /*@-boundsread@*/ while (helpLength > lineLength) { const char * ch; char format[16]; ch = help + lineLength - 1; while (ch > help && !isSpace(ch)) ch--; if (ch == help) break; /* give up */ while (ch > (help + 1) && isSpace(ch)) ch--; ch++; snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength); /*@-formatconst@*/ fprintf(fp, format, help, " "); /*@=formatconst@*/ help = ch; while (isSpace(help) && *help) help++; helpLength = strlen(help); } /*@=boundsread@*/ if (helpLength) fprintf(fp, "%s\n", help); out: /*@-dependenttrans@*/ defs = _free(defs); /*@=dependenttrans@*/ left = _free(left); } /** * Find display width for longest argument string. * @param opt option(s) * @param translation_domain translation domain * @return display width */ static size_t maxArgWidth(const struct poptOption * opt, /*@null@*/ UNUSED(const char * translation_domain)) /*@*/ { size_t max = 0; size_t len = 0; const char * s; if (opt != NULL) while (opt->longName || opt->shortName || opt->arg) { if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { if (opt->arg) /* XXX program error */ len = maxArgWidth(opt->arg, translation_domain); if (len > max) max = len; } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { len = sizeof(" ")-1; if (opt->shortName != '\0') len += sizeof("-X")-1; if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; if (opt->longName) { len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? sizeof("-")-1 : sizeof("--")-1); len += strlen(opt->longName); } s = getArgDescrip(opt, translation_domain); #ifdef POPT_WCHAR_HACK /* XXX Calculate no. of display characters. */ if (s) { const char * scopy = s; mbstate_t t; size_t n; /*@-boundswrite@*/ memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ /*@=boundswrite@*/ /* Determine number of characters. */ n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); len += sizeof("=")-1 + n; } #else if (s) len += sizeof("=")-1 + strlen(s); #endif if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; if (len > max) max = len; } opt++; } return max; } /** * Display popt alias and exec help. * @param fp output file handle * @param items alias/exec array * @param nitems no. of alias/exec entries * @param left largest argument display width * @param translation_domain translation domain */ static void itemHelp(FILE * fp, /*@null@*/ poptItem items, int nitems, size_t left, /*@null@*/ UNUSED(const char * translation_domain)) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { poptItem item; int i; if (items != NULL) for (i = 0, item = items; i < nitems; i++, item++) { const struct poptOption * opt; opt = &item->option; if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) singleOptionHelp(fp, left, opt, translation_domain); } } /** * Display help text for a table of options. * @param con context * @param fp output file handle * @param table option(s) * @param left largest argument display width * @param translation_domain translation domain */ static void singleTableHelp(poptContext con, FILE * fp, /*@null@*/ const struct poptOption * table, size_t left, /*@null@*/ UNUSED(const char * translation_domain)) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { const struct poptOption * opt; const char *sub_transdom; if (table == poptAliasOptions) { itemHelp(fp, con->aliases, con->numAliases, left, NULL); itemHelp(fp, con->execs, con->numExecs, left, NULL); return; } if (table != NULL) for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) singleOptionHelp(fp, left, opt, translation_domain); } if (table != NULL) for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) continue; sub_transdom = getTableTranslationDomain(opt->arg); if (sub_transdom == NULL) sub_transdom = translation_domain; if (opt->descrip) fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); singleTableHelp(con, fp, opt->arg, left, sub_transdom); } } /** * @param con context * @param fp output file handle */ static int showHelpIntro(poptContext con, FILE * fp) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { int len = 6; const char * fn; fprintf(fp, POPT_("Usage:")); if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { /*@-boundsread@*/ /*@-nullderef -type@*/ /* LCL: wazzup? */ fn = con->optionStack->argv[0]; /*@=nullderef =type@*/ /*@=boundsread@*/ if (fn == NULL) return len; if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; fprintf(fp, " %s", fn); len += strlen(fn) + 1; } return len; } void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) { size_t leftColWidth; (void) showHelpIntro(con, fp); if (con->otherHelp) fprintf(fp, " %s\n", con->otherHelp); else fprintf(fp, " %s\n", POPT_("[OPTION...]")); leftColWidth = maxArgWidth(con->options, NULL); singleTableHelp(con, fp, con->options, leftColWidth, NULL); } /** * Display usage text for an option. * @param fp output file handle * @param cursor current display position * @param opt option(s) * @param translation_domain translation domain */ static size_t singleOptionUsage(FILE * fp, size_t cursor, const struct poptOption * opt, /*@null@*/ const char *translation_domain) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { size_t len = 4; char shortStr[2] = { '\0', '\0' }; const char * item = shortStr; const char * argDescrip = getArgDescrip(opt, translation_domain); if (opt->shortName != '\0' && opt->longName != NULL) { len += 2; if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; len += strlen(opt->longName); } else if (opt->shortName != '\0') { len++; shortStr[0] = opt->shortName; shortStr[1] = '\0'; } else if (opt->longName) { len += strlen(opt->longName); if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; item = opt->longName; } if (len == 4) return cursor; #ifdef POPT_WCHAR_HACK /* XXX Calculate no. of display characters. */ if (argDescrip) { const char * scopy = argDescrip; mbstate_t t; size_t n; /*@-boundswrite@*/ memset ((void *)&t, '\0', sizeof (t)); /* In initial state. */ /*@=boundswrite@*/ /* Determine number of characters. */ n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t); len += sizeof("=")-1 + n; } #else if (argDescrip) len += sizeof("=")-1 + strlen(argDescrip); #endif if ((cursor + len) > 79) { fprintf(fp, "\n "); cursor = 7; } if (opt->longName && opt->shortName) { fprintf(fp, " [-%c|-%s%s%s%s]", opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), opt->longName, (argDescrip ? " " : ""), (argDescrip ? argDescrip : "")); } else { fprintf(fp, " [-%s%s%s%s]", ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), item, (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), (argDescrip ? argDescrip : "")); } return cursor + len + 1; } /** * Display popt alias and exec usage. * @param fp output file handle * @param cursor current display position * @param item alias/exec array * @param nitems no. of ara/exec entries * @param translation_domain translation domain */ static size_t itemUsage(FILE * fp, size_t cursor, /*@null@*/ poptItem item, int nitems, /*@null@*/ UNUSED(const char * translation_domain)) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { int i; /*@-branchstate@*/ /* FIX: W2DO? */ if (item != NULL) for (i = 0; i < nitems; i++, item++) { const struct poptOption * opt; opt = &item->option; if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { translation_domain = (const char *)opt->arg; } else if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { cursor = singleOptionUsage(fp, cursor, opt, translation_domain); } } /*@=branchstate@*/ return cursor; } /** * Keep track of option tables already processed. */ typedef struct poptDone_s { int nopts; int maxopts; const void ** opts; } * poptDone; /** * Display usage text for a table of options. * @param con context * @param fp output file handle * @param cursor current display position * @param opt option(s) * @param translation_domain translation domain * @param done tables already processed * @return */ static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor, /*@null@*/ const struct poptOption * opt, /*@null@*/ UNUSED(const char * translation_domain), /*@null@*/ poptDone done) /*@globals fileSystem @*/ /*@modifies *fp, done, fileSystem @*/ { /*@-branchstate@*/ /* FIX: W2DO? */ if (opt != NULL) for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { translation_domain = (const char *)opt->arg; } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { if (done) { int i = 0; for (i = 0; i < done->nopts; i++) { /*@-boundsread@*/ const void * that = done->opts[i]; /*@=boundsread@*/ if (that == NULL || that != opt->arg) /*@innercontinue@*/ continue; /*@innerbreak@*/ break; } /* Skip if this table has already been processed. */ if (opt->arg == NULL || i < done->nopts) continue; /*@-boundswrite@*/ if (done->nopts < done->maxopts) done->opts[done->nopts++] = (const void *) opt->arg; /*@=boundswrite@*/ } cursor = singleTableUsage(con, fp, cursor, opt->arg, translation_domain, done); } else if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { cursor = singleOptionUsage(fp, cursor, opt, translation_domain); } } /*@=branchstate@*/ return cursor; } /** * Return concatenated short options for display. * @todo Sub-tables should be recursed. * @param opt option(s) * @param fp output file handle * @retval str concatenation of short options * @return length of display string */ static int showShortOptions(const struct poptOption * opt, FILE * fp, /*@null@*/ char * str) /*@globals fileSystem @*/ /*@modifies *str, *fp, fileSystem @*/ /*@requires maxRead(str) >= 0 @*/ { /* bufsize larger then the ascii set, lazy alloca on top level call. */ char * s = (str != NULL ? str : memset(alloca(300), 0, 300)); int len = 0; if (s == NULL) return 0; /*@-boundswrite@*/ if (opt != NULL) for (; (opt->longName || opt->shortName || opt->arg); opt++) { if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) s[strlen(s)] = opt->shortName; else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) if (opt->arg) /* XXX program error */ len = showShortOptions(opt->arg, fp, s); } /*@=boundswrite@*/ /* On return to top level, print the short options, return print length. */ if (s == str && *s != '\0') { fprintf(fp, " [-%s]", s); len = strlen(s) + sizeof(" [-]")-1; } return len; } void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags)) { poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); size_t cursor; done->nopts = 0; done->maxopts = 64; cursor = done->maxopts * sizeof(*done->opts); /*@-boundswrite@*/ done->opts = memset(alloca(cursor), 0, cursor); /*@-keeptrans@*/ done->opts[done->nopts++] = (const void *) con->options; /*@=keeptrans@*/ /*@=boundswrite@*/ cursor = showHelpIntro(con, fp); cursor += showShortOptions(con->options, fp, NULL); cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); if (con->otherHelp) { cursor += strlen(con->otherHelp) + 1; if (cursor > 79) fprintf(fp, "\n "); fprintf(fp, " %s", con->otherHelp); } fprintf(fp, "\n"); } void poptSetOtherOptionHelp(poptContext con, const char * text) { con->otherHelp = _free(con->otherHelp); con->otherHelp = xstrdup(text); } rsync-3.2.7/popt/dummy.in0000664000000000000000000000000007347620345014026 0ustar rootrootrsync-3.2.7/popt/popt.c0000664000000000000000000010517313664325154013511 0ustar rootroot/** \ingroup popt * \file popt/popt.c */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist */ #undef MYDEBUG #include "system.h" #if HAVE_FLOAT_H #include #endif #include #include "findme.h" #include "poptint.h" #ifndef DBL_EPSILON #define DBL_EPSILON 2.2204460492503131e-16 #endif #ifdef MYDEBUG /*@unchecked@*/ int _popt_debug = 0; #endif #if !defined(HAVE_STRERROR) && !defined(__LCLINT__) static char * strerror(int errno) { extern int sys_nerr; extern char * sys_errlist[]; if ((0 <= errno) && (errno < sys_nerr)) return sys_errlist[errno]; else return POPT_("unknown errno"); } #endif #ifdef MYDEBUG /*@unused@*/ static void prtcon(const char *msg, poptContext con) { if (msg) fprintf(stderr, "%s", msg); fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", con, con->os, (con->os->nextCharArg ? con->os->nextCharArg : ""), (con->os->nextArg ? con->os->nextArg : ""), con->os->next, (con->os->argv && con->os->argv[con->os->next] ? con->os->argv[con->os->next] : "")); } #endif void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) { con->execPath = _free(con->execPath); con->execPath = xstrdup(path); con->execAbsolute = allowAbsolute; /*@-nullstate@*/ /* LCL: con->execPath not NULL */ return; /*@=nullstate@*/ } static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) /*@globals internalState@*/ /*@modifies internalState@*/ { if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->arg == NULL) continue; /* XXX program error. */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg; /*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; /*@=branchstate@*/ /* Recurse on included sub-tables. */ invokeCallbacksPRE(con, arg); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && (opt->argInfo & POPT_CBFLAG_PRE)) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)opt->arg; /*@=castfcnptr@*/ /* Perform callback. */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); /*@=noeffectuncon @*/ } } } static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) /*@globals internalState@*/ /*@modifies internalState@*/ { if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if (opt->arg == NULL) continue; /* XXX program error. */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg; /*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; /*@=branchstate@*/ /* Recurse on included sub-tables. */ invokeCallbacksPOST(con, arg); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && (opt->argInfo & POPT_CBFLAG_POST)) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)opt->arg; /*@=castfcnptr@*/ /* Perform callback. */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); /*@=noeffectuncon @*/ } } } static void invokeCallbacksOPTION(poptContext con, const struct poptOption * opt, const struct poptOption * myOpt, /*@null@*/ const void * myData, int shorty) /*@globals internalState@*/ /*@modifies internalState@*/ { const struct poptOption * cbopt = NULL; if (opt != NULL) for (; opt->longName || opt->shortName || opt->arg; opt++) { if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { void * arg = opt->arg; /*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; /*@=branchstate@*/ /* Recurse on included sub-tables. */ if (opt->arg != NULL) /* XXX program error */ invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { /* Save callback info. */ cbopt = opt; } else if (cbopt != NULL && ((myOpt->shortName && opt->shortName && shorty && myOpt->shortName == opt->shortName) || (myOpt->longName && opt->longName && /*@-nullpass@*/ /* LCL: opt->longName != NULL */ !strcmp(myOpt->longName, opt->longName))) /*@=nullpass@*/ ) { /*@-castfcnptr@*/ poptCallbackType cb = (poptCallbackType)cbopt->arg; /*@=castfcnptr@*/ const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); /* Perform callback. */ if (cb != NULL) { /* XXX program error */ /*@-noeffectuncon @*/ cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, con->os->nextArg, cbData); /*@=noeffectuncon @*/ } /* Terminate (unless explcitly continuing). */ if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) return; } } } poptContext poptGetContext(const char * name, int argc, const char ** argv, const struct poptOption * options, int flags) { poptContext con = malloc(sizeof(*con)); if (con == NULL) return NULL; /* XXX can't happen */ memset(con, 0, sizeof(*con)); con->os = con->optionStack; con->os->argc = argc; /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->os->argv = argv; /*@=dependenttrans =assignexpose@*/ con->os->argb = NULL; if (!(flags & POPT_CONTEXT_KEEP_FIRST)) con->os->next = 1; /* skip argv[0] */ con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->options = options; /*@=dependenttrans =assignexpose@*/ con->aliases = NULL; con->numAliases = 0; con->flags = flags; con->execs = NULL; con->numExecs = 0; con->finalArgvAlloced = argc * 2; con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) ); con->execAbsolute = 1; con->arg_strip = NULL; if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) con->flags |= POPT_CONTEXT_POSIXMEHARDER; if (name) { size_t bufsize = strlen(name) + 1; char * t = malloc(bufsize); if (t) { strlcpy(t, name, bufsize); con->appName = t; } } /*@-internalglobs@*/ invokeCallbacksPRE(con, con->options); /*@=internalglobs@*/ return con; } static void cleanOSE(/*@special@*/ struct optionStackEntry *os) /*@uses os @*/ /*@releases os->nextArg, os->argv, os->argb @*/ /*@modifies os @*/ { os->nextArg = _free(os->nextArg); os->argv = _free(os->argv); os->argb = PBM_FREE(os->argb); } /*@-boundswrite@*/ void poptResetContext(poptContext con) { int i; if (con == NULL) return; while (con->os > con->optionStack) { cleanOSE(con->os--); } con->os->argb = PBM_FREE(con->os->argb); con->os->currAlias = NULL; con->os->nextCharArg = NULL; con->os->nextArg = NULL; con->os->next = 1; /* skip argv[0] */ con->numLeftovers = 0; con->nextLeftover = 0; con->restLeftover = 0; con->doExec = NULL; if (con->finalArgv != NULL) for (i = 0; i < con->finalArgvCount; i++) { /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ con->finalArgv[i] = _free(con->finalArgv[i]); /*@=unqualifiedtrans@*/ } con->finalArgvCount = 0; con->arg_strip = PBM_FREE(con->arg_strip); /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ return; /*@=nullstate@*/ } /*@=boundswrite@*/ /* Only one of longName, shortName should be set, not both. */ /*@-boundswrite@*/ static int handleExec(/*@special@*/ poptContext con, /*@null@*/ const char * longName, char shortName) /*@uses con->execs, con->numExecs, con->flags, con->doExec, con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ /*@modifies con @*/ { poptItem item; int i; if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ return 0; for (i = con->numExecs - 1; i >= 0; i--) { item = con->execs + i; if (longName && !(item->option.longName && !strcmp(longName, item->option.longName))) continue; else if (shortName != item->option.shortName) continue; break; } if (i < 0) return 0; if (con->flags & POPT_CONTEXT_NO_EXEC) return 1; if (con->doExec == NULL) { con->doExec = con->execs + i; return 1; } /* We already have an exec to do; remember this option for next time 'round */ if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { con->finalArgvAlloced += 10; con->finalArgv = realloc(con->finalArgv, sizeof(*con->finalArgv) * con->finalArgvAlloced); } i = con->finalArgvCount++; if (con->finalArgv != NULL) /* XXX can't happen */ { size_t bufsize = (longName ? strlen(longName) : 0) + 3; char *s = malloc(bufsize); if (s != NULL) { /* XXX can't happen */ if (longName) snprintf(s, bufsize, "--%s", longName); else snprintf(s, bufsize, "-%c", shortName); con->finalArgv[i] = s; } else con->finalArgv[i] = NULL; } /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ return 1; /*@=nullstate@*/ } /*@=boundswrite@*/ /* Only one of longName, shortName may be set at a time */ static int handleAlias(/*@special@*/ poptContext con, /*@null@*/ const char * longName, char shortName, /*@exposed@*/ /*@null@*/ const char * nextCharArg) /*@uses con->aliases, con->numAliases, con->optionStack, con->os, con->os->currAlias, con->os->currAlias->option.longName @*/ /*@modifies con @*/ { poptItem item = con->os->currAlias; int rc; int i; if (item) { if (longName && (item->option.longName && !strcmp(longName, item->option.longName))) return 0; if (shortName && shortName == item->option.shortName) return 0; } if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ return 0; for (i = con->numAliases - 1; i >= 0; i--) { item = con->aliases + i; if (longName && !(item->option.longName && !strcmp(longName, item->option.longName))) continue; else if (shortName != item->option.shortName) continue; break; } if (i < 0) return 0; if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) return POPT_ERROR_OPTSTOODEEP; /*@-boundsread@*/ if (nextCharArg && *nextCharArg) con->os->nextCharArg = nextCharArg; /*@=boundsread@*/ con->os++; con->os->next = 0; con->os->stuffed = 0; con->os->nextArg = NULL; con->os->nextCharArg = NULL; con->os->currAlias = con->aliases + i; rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, &con->os->argc, &con->os->argv); con->os->argb = NULL; return (rc ? rc : 1); } /*@-bounds -boundswrite @*/ static int execCommand(poptContext con) /*@globals internalState @*/ /*@modifies internalState @*/ { poptItem item = con->doExec; const char ** argv; int argc = 0; if (item == NULL) /*XXX can't happen*/ return POPT_ERROR_NOARG; if (item->argv == NULL || item->argc < 1 || (!con->execAbsolute && strchr(item->argv[0], '/'))) return POPT_ERROR_NOARG; argv = malloc(sizeof(*argv) * (6 + item->argc + con->numLeftovers + con->finalArgvCount)); if (argv == NULL) return POPT_ERROR_MALLOC; if (!strchr(item->argv[0], '/') && con->execPath != NULL) { size_t bufsize = strlen(con->execPath) + strlen(item->argv[0]) + sizeof "/"; char *s = alloca(bufsize); snprintf(s, bufsize, "%s/%s", con->execPath, item->argv[0]); argv[argc] = s; } else argv[argc] = findProgramPath(item->argv[0]); if (argv[argc++] == NULL) return POPT_ERROR_NOARG; if (item->argc > 1) { memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); argc += (item->argc - 1); } if (con->finalArgv != NULL && con->finalArgvCount > 0) { memcpy(argv + argc, con->finalArgv, sizeof(*argv) * con->finalArgvCount); argc += con->finalArgvCount; } if (con->leftovers != NULL && con->numLeftovers > 0) { memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); argc += con->numLeftovers; } argv[argc] = NULL; { #ifdef __hpux int rc = setresgid(getgid(), getgid(),-1); if (rc) return POPT_ERROR_ERRNO; rc = setresuid(getuid(), getuid(),-1); if (rc) return POPT_ERROR_ERRNO; #else /* * XXX " ... on BSD systems setuid() should be preferred over setreuid()" * XXX sez' Timur Bakeyev * XXX from Norbert Warmuth */ #if defined(HAVE_SETUID) int rc = setgid(getgid()); if (rc) return POPT_ERROR_ERRNO; rc = setuid(getuid()); if (rc) return POPT_ERROR_ERRNO; #elif defined (HAVE_SETREUID) int rc = setregid(getgid(), getgid()); if (rc) return POPT_ERROR_ERRNO; rc = setreuid(getuid(), getuid()); if (rc) return POPT_ERROR_ERRNO; #else ; /* Can't drop privileges */ #endif #endif } if (argv[0] == NULL) return POPT_ERROR_NOARG; #ifdef MYDEBUG if (_popt_debug) { const char ** avp; fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); for (avp = argv; *avp; avp++) fprintf(stderr, " '%s'", *avp); fprintf(stderr, "\n"); } #endif execvp(argv[0], (char *const *)argv); return POPT_ERROR_ERRNO; } /*@=bounds =boundswrite @*/ /*@-boundswrite@*/ /*@observer@*/ /*@null@*/ static const struct poptOption * findOption(const struct poptOption * opt, /*@null@*/ const char * longName, char shortName, /*@null@*/ /*@out@*/ poptCallbackType * callback, /*@null@*/ /*@out@*/ const void ** callbackData, int singleDash) /*@modifies *callback, *callbackData */ { const struct poptOption * cb = NULL; /* This happens when a single - is given */ if (singleDash && !shortName && (longName && *longName == '\0')) shortName = '-'; for (; opt->longName || opt->shortName || opt->arg; opt++) { if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { const struct poptOption * opt2; void * arg = opt->arg; /*@-branchstate@*/ /* XXX sick hack to preserve pretense of ABI. */ if (arg == poptHelpOptions) arg = poptHelpOptionsI18N; /*@=branchstate@*/ /* Recurse on included sub-tables. */ if (arg == NULL) continue; /* XXX program error */ opt2 = findOption(arg, longName, shortName, callback, callbackData, singleDash); if (opt2 == NULL) continue; /* Sub-table data will be inheirited if no data yet. */ if (!(callback && *callback)) return opt2; if (!(callbackData && *callbackData == NULL)) return opt2; /*@-observertrans -dependenttrans @*/ *callbackData = opt->descrip; /*@=observertrans =dependenttrans @*/ return opt2; } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) { cb = opt; } else if (longName && opt->longName && (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) && /*@-nullpass@*/ /* LCL: opt->longName != NULL */ !strcmp(longName, opt->longName)) /*@=nullpass@*/ { break; } else if (shortName && shortName == opt->shortName) { break; } } if (!opt->longName && !opt->shortName) return NULL; /*@-modobserver -mods @*/ if (callback) *callback = NULL; if (callbackData) *callbackData = NULL; if (cb) { if (callback) /*@-castfcnptr@*/ *callback = (poptCallbackType)cb->arg; /*@=castfcnptr@*/ if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) { if (callbackData) /*@-observertrans@*/ /* FIX: typedef double indirection. */ *callbackData = cb->descrip; /*@=observertrans@*/ } } /*@=modobserver =mods @*/ return opt; } /*@=boundswrite@*/ static const char * findNextArg(/*@special@*/ poptContext con, unsigned argx, int delete_arg) /*@uses con->optionStack, con->os, con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ /*@modifies con @*/ { struct optionStackEntry * os = con->os; const char * arg; do { int i; arg = NULL; while (os->next == os->argc && os > con->optionStack) os--; if (os->next == os->argc && os == con->optionStack) break; if (os->argv != NULL) for (i = os->next; i < os->argc; i++) { /*@-sizeoftype@*/ if (os->argb && PBM_ISSET(i, os->argb)) /*@innercontinue@*/ continue; if (*os->argv[i] == '-') /*@innercontinue@*/ continue; if (--argx > 0) /*@innercontinue@*/ continue; arg = os->argv[i]; if (delete_arg) { if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); if (os->argb != NULL) /* XXX can't happen */ PBM_SET(i, os->argb); } /*@innerbreak@*/ break; /*@=sizeoftype@*/ } if (os > con->optionStack) os--; } while (arg == NULL); return arg; } /*@-boundswrite@*/ static /*@only@*/ /*@null@*/ const char * expandNextArg(/*@special@*/ poptContext con, const char * s) /*@uses con->optionStack, con->os, con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ /*@modifies con @*/ { const char * a = NULL; size_t alen, pos; char *t, *te; size_t tn = strlen(s) + 1; char c; te = t = malloc(tn);; if (t == NULL) return NULL; /* XXX can't happen */ while ((c = *s++) != '\0') { switch (c) { #if 0 /* XXX can't do this */ case '\\': /* escape */ c = *s++; /*@switchbreak@*/ break; #endif case '!': if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) /*@switchbreak@*/ break; /* XXX Make sure that findNextArg deletes only next arg. */ if (a == NULL) { if ((a = findNextArg(con, 1, 1)) == NULL) /*@switchbreak@*/ break; } s += 3; alen = strlen(a); tn += alen; pos = te - t; t = realloc(t, tn); te = t + pos; memcpy(te, a, alen+1); te += alen; continue; /*@notreached@*/ /*@switchbreak@*/ break; default: /*@switchbreak@*/ break; } *te++ = c; } *te = '\0'; t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */ return t; } /*@=boundswrite@*/ static void poptStripArg(/*@special@*/ poptContext con, int which) /*@uses con->arg_strip, con->optionStack @*/ /*@defines con->arg_strip @*/ /*@modifies con @*/ { /*@-sizeoftype@*/ if (con->arg_strip == NULL) con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); if (con->arg_strip != NULL) /* XXX can't happen */ PBM_SET(which, con->arg_strip); /*@=sizeoftype@*/ /*@-compdef@*/ /* LCL: con->arg_strip udefined? */ return; /*@=compdef@*/ } int poptSaveLong(long * arg, int argInfo, long aLong) { /* XXX Check alignment, may fail on funky platforms. */ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) return POPT_ERROR_NULLARG; if (argInfo & POPT_ARGFLAG_NOT) aLong = ~aLong; switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { case 0: *arg = aLong; break; case POPT_ARGFLAG_OR: *arg |= aLong; break; case POPT_ARGFLAG_AND: *arg &= aLong; break; case POPT_ARGFLAG_XOR: *arg ^= aLong; break; default: return POPT_ERROR_BADOPERATION; /*@notreached@*/ break; } return 0; } int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) { /* XXX Check alignment, may fail on funky platforms. */ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) return POPT_ERROR_NULLARG; if (argInfo & POPT_ARGFLAG_NOT) aLong = ~aLong; switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { case 0: *arg = aLong; break; case POPT_ARGFLAG_OR: *arg |= aLong; break; case POPT_ARGFLAG_AND: *arg &= aLong; break; case POPT_ARGFLAG_XOR: *arg ^= aLong; break; default: return POPT_ERROR_BADOPERATION; /*@notreached@*/ break; } return 0; } /*@-boundswrite@*/ /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ int poptGetNextOpt(poptContext con) { const struct poptOption * opt = NULL; int done = 0; if (con == NULL) return -1; while (!done) { const char * origOptString = NULL; poptCallbackType cb = NULL; const void * cbData = NULL; const char * longArg = NULL; int canstrip = 0; int shorty = 0; while (!con->os->nextCharArg && con->os->next == con->os->argc && con->os > con->optionStack) { cleanOSE(con->os--); } if (!con->os->nextCharArg && con->os->next == con->os->argc) { /*@-internalglobs@*/ invokeCallbacksPOST(con, con->options); /*@=internalglobs@*/ if (con->doExec) return execCommand(con); return -1; } /* Process next long option */ if (!con->os->nextCharArg) { char * localOptString, * optString; int thisopt; /*@-sizeoftype@*/ if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { con->os->next++; continue; } /*@=sizeoftype@*/ thisopt = con->os->next; if (con->os->argv != NULL) /* XXX can't happen */ origOptString = con->os->argv[con->os->next++]; if (origOptString == NULL) /* XXX can't happen */ return POPT_ERROR_BADOPT; if (con->restLeftover || *origOptString != '-') { if (con->flags & POPT_CONTEXT_POSIXMEHARDER) con->restLeftover = 1; if (con->flags & POPT_CONTEXT_ARG_OPTS) { con->os->nextArg = xstrdup(origOptString); return 0; } if (con->leftovers != NULL) /* XXX can't happen */ con->leftovers[con->numLeftovers++] = origOptString; continue; } /* Make a copy we can hack at */ { size_t bufsize = strlen(origOptString) + 1; localOptString = optString = alloca(bufsize); if (optString == NULL) /* XXX can't happen */ return POPT_ERROR_BADOPT; strlcpy(optString, origOptString, bufsize); } if (optString[0] == '\0') return POPT_ERROR_BADOPT; if (optString[1] == '-' && !optString[2]) { con->restLeftover = 1; continue; } else { char *oe; int singleDash; optString++; if (*optString == '-') singleDash = 0, optString++; else singleDash = 1; /* XXX aliases with arg substitution need "--alias=arg" */ if (handleAlias(con, optString, '\0', NULL)) continue; if (handleExec(con, optString, '\0')) continue; /* Check for "--long=arg" option. */ for (oe = optString; *oe && *oe != '='; oe++) {}; if (*oe == '=') { *oe++ = '\0'; /* XXX longArg is mapped back to persistent storage. */ longArg = origOptString + (oe - localOptString); } else oe = NULL; opt = findOption(con->options, optString, '\0', &cb, &cbData, singleDash); if (!opt && !singleDash) return POPT_ERROR_BADOPT; if (!opt && oe) oe[-1] = '='; /* restore overwritten '=' */ } if (!opt) { con->os->nextCharArg = origOptString + 1; longArg = NULL; } else { if (con->os == con->optionStack && opt->argInfo & POPT_ARGFLAG_STRIP) { canstrip = 1; poptStripArg(con, thisopt); } shorty = 0; } } /* Process next short option */ /*@-branchstate@*/ /* FIX: W2DO? */ if (con->os->nextCharArg) { origOptString = con->os->nextCharArg; con->os->nextCharArg = NULL; if (handleAlias(con, NULL, *origOptString, origOptString + 1)) continue; if (handleExec(con, NULL, *origOptString)) { /* Restore rest of short options for further processing */ origOptString++; if (*origOptString != '\0') con->os->nextCharArg = origOptString; continue; } opt = findOption(con->options, NULL, *origOptString, &cb, &cbData, 0); if (!opt) return POPT_ERROR_BADOPT; shorty = 1; origOptString++; if (*origOptString != '\0') con->os->nextCharArg = origOptString; } /*@=branchstate@*/ if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE || (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) { if (longArg || (con->os->nextCharArg && con->os->nextCharArg[0] == '=')) return POPT_ERROR_UNWANTEDARG; if (opt->arg) { long val = (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL ? opt->val : 1; if (poptSaveInt((int *)opt->arg, opt->argInfo, val)) return POPT_ERROR_BADOPERATION; } } else { con->os->nextArg = _free(con->os->nextArg); /*@-usedef@*/ /* FIX: W2DO? */ if (longArg) { /*@=usedef@*/ longArg = expandNextArg(con, longArg); con->os->nextArg = longArg; } else if (con->os->nextCharArg) { longArg = expandNextArg(con, con->os->nextCharArg + (con->os->nextCharArg[0] == '=')); con->os->nextArg = longArg; con->os->nextCharArg = NULL; } else { while (con->os->next == con->os->argc && con->os > con->optionStack) { cleanOSE(con->os--); } if (con->os->next == con->os->argc) { if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL)) /*@-compdef@*/ /* FIX: con->os->argv not defined */ return POPT_ERROR_NOARG; /*@=compdef@*/ con->os->nextArg = NULL; } else { /* * Make sure this isn't part of a short arg or the * result of an alias expansion. */ if (con->os == con->optionStack && (opt->argInfo & POPT_ARGFLAG_STRIP) && canstrip) { poptStripArg(con, con->os->next); } if (con->os->argv != NULL) { /* XXX can't happen */ /* XXX watchout: subtle side-effects live here. */ longArg = con->os->argv[con->os->next++]; longArg = expandNextArg(con, longArg); con->os->nextArg = longArg; } } } longArg = NULL; if (opt->arg) { switch (opt->argInfo & POPT_ARG_MASK) { case POPT_ARG_STRING: /* XXX memory leak, hard to plug */ *((const char **) opt->arg) = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL; /*@switchbreak@*/ break; case POPT_ARG_INT: case POPT_ARG_LONG: { long aLong = 0; char *end; if (con->os->nextArg) { aLong = strtol(con->os->nextArg, &end, 0); if (!(end && *end == '\0')) return POPT_ERROR_BADNUMBER; } if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) { if (aLong == LONG_MIN || aLong == LONG_MAX) return POPT_ERROR_OVERFLOW; if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong)) return POPT_ERROR_BADOPERATION; } else { if (aLong > INT_MAX || aLong < INT_MIN) return POPT_ERROR_OVERFLOW; if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong)) return POPT_ERROR_BADOPERATION; } } /*@switchbreak@*/ break; case POPT_ARG_FLOAT: case POPT_ARG_DOUBLE: { double aDouble = 0.0; char *end; if (con->os->nextArg) { /*@-mods@*/ int saveerrno = errno; errno = 0; aDouble = strtod(con->os->nextArg, &end); if (errno == ERANGE) return POPT_ERROR_OVERFLOW; errno = saveerrno; /*@=mods@*/ if (*end != '\0') return POPT_ERROR_BADNUMBER; } if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) { *((double *) opt->arg) = aDouble; } else { #define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) return POPT_ERROR_OVERFLOW; if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON) return POPT_ERROR_OVERFLOW; *((float *) opt->arg) = aDouble; } } /*@switchbreak@*/ break; default: fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"), (opt->argInfo & POPT_ARG_MASK)); exit(EXIT_FAILURE); /*@notreached@*/ /*@switchbreak@*/ break; } } } if (cb) { /*@-internalglobs@*/ invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); /*@=internalglobs@*/ } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) done = 1; if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { con->finalArgvAlloced += 10; con->finalArgv = realloc(con->finalArgv, sizeof(*con->finalArgv) * con->finalArgvAlloced); } if (con->finalArgv != NULL) { ssize_t bufsize = (opt->longName ? strlen(opt->longName) : 0) + 3; char *s = malloc(bufsize); if (s != NULL) { /* XXX can't happen */ if (opt->longName) snprintf(s, bufsize, "%s%s", ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), opt->longName); else snprintf(s, bufsize, "-%c", opt->shortName); con->finalArgv[con->finalArgvCount++] = s; } else con->finalArgv[con->finalArgvCount++] = NULL; } if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) /*@-ifempty@*/ ; /*@=ifempty@*/ else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) /*@-ifempty@*/ ; /*@=ifempty@*/ else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { if (con->finalArgv != NULL && con->os->nextArg) con->finalArgv[con->finalArgvCount++] = /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */ xstrdup(con->os->nextArg); /*@=nullpass@*/ } } return (opt ? opt->val : -1); /* XXX can't happen */ } /*@=boundswrite@*/ const char * poptGetOptArg(poptContext con) { const char * ret = NULL; /*@-branchstate@*/ if (con) { ret = con->os->nextArg; con->os->nextArg = NULL; } /*@=branchstate@*/ return ret; } const char * poptGetArg(poptContext con) { const char * ret = NULL; if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) ret = con->leftovers[con->nextLeftover++]; return ret; } const char * poptPeekArg(poptContext con) { const char * ret = NULL; if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) ret = con->leftovers[con->nextLeftover]; return ret; } /*@-boundswrite@*/ const char ** poptGetArgs(poptContext con) { if (con == NULL || con->leftovers == NULL || con->numLeftovers == con->nextLeftover) return NULL; /* some apps like [like RPM ;-) ] need this NULL terminated */ con->leftovers[con->numLeftovers] = NULL; /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ return (con->leftovers + con->nextLeftover); /*@=nullret =nullstate @*/ } /*@=boundswrite@*/ poptContext poptFreeContext(poptContext con) { poptItem item; int i; if (con == NULL) return con; poptResetContext(con); con->os->argb = _free(con->os->argb); if (con->aliases != NULL) for (i = 0; i < con->numAliases; i++) { item = con->aliases + i; /*@-modobserver -observertrans -dependenttrans@*/ item->option.longName = _free(item->option.longName); item->option.descrip = _free(item->option.descrip); item->option.argDescrip = _free(item->option.argDescrip); /*@=modobserver =observertrans =dependenttrans@*/ item->argv = _free(item->argv); } con->aliases = _free(con->aliases); if (con->execs != NULL) for (i = 0; i < con->numExecs; i++) { item = con->execs + i; /*@-modobserver -observertrans -dependenttrans@*/ item->option.longName = _free(item->option.longName); item->option.descrip = _free(item->option.descrip); item->option.argDescrip = _free(item->option.argDescrip); /*@=modobserver =observertrans =dependenttrans@*/ item->argv = _free(item->argv); } con->execs = _free(con->execs); con->leftovers = _free(con->leftovers); con->finalArgv = _free(con->finalArgv); con->appName = _free(con->appName); con->otherHelp = _free(con->otherHelp); con->execPath = _free(con->execPath); con->arg_strip = PBM_FREE(con->arg_strip); con = _free(con); return con; } int poptAddAlias(poptContext con, struct poptAlias alias, /*@unused@*/ UNUSED(int flags)) { poptItem item = (poptItem) alloca(sizeof(*item)); memset(item, 0, sizeof(*item)); item->option.longName = alias.longName; item->option.shortName = alias.shortName; item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; item->option.arg = 0; item->option.val = 0; item->option.descrip = NULL; item->option.argDescrip = NULL; item->argc = alias.argc; item->argv = alias.argv; return poptAddItem(con, item, 0); } /*@-boundswrite@*/ /*@-mustmod@*/ /* LCL: con not modified? */ int poptAddItem(poptContext con, poptItem newItem, int flags) { poptItem * items, item; int * nitems; switch (flags) { case 1: items = &con->execs; nitems = &con->numExecs; break; case 0: items = &con->aliases; nitems = &con->numAliases; break; default: return 1; /*@notreached@*/ break; } *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); if ((*items) == NULL) return 1; item = (*items) + (*nitems); item->option.longName = (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL); item->option.shortName = newItem->option.shortName; item->option.argInfo = newItem->option.argInfo; item->option.arg = newItem->option.arg; item->option.val = newItem->option.val; item->option.descrip = (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL); item->option.argDescrip = (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); item->argc = newItem->argc; item->argv = newItem->argv; (*nitems)++; return 0; } /*@=mustmod@*/ /*@=boundswrite@*/ const char * poptBadOption(poptContext con, int flags) { struct optionStackEntry * os = NULL; if (con != NULL) os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; /*@-nullderef@*/ /* LCL: os->argv != NULL */ return (os && os->argv ? os->argv[os->next - 1] : NULL); /*@=nullderef@*/ } const char * poptStrerror(const int error) { switch (error) { case POPT_ERROR_NOARG: return POPT_("missing argument"); case POPT_ERROR_UNWANTEDARG: return POPT_("option does not take an argument"); case POPT_ERROR_BADOPT: return POPT_("unknown option"); case POPT_ERROR_BADOPERATION: return POPT_("mutually exclusive logical operations requested"); case POPT_ERROR_NULLARG: return POPT_("opt->arg should not be NULL"); case POPT_ERROR_OPTSTOODEEP: return POPT_("aliases nested too deeply"); case POPT_ERROR_BADQUOTE: return POPT_("error in parameter quoting"); case POPT_ERROR_BADNUMBER: return POPT_("invalid numeric value"); case POPT_ERROR_OVERFLOW: return POPT_("number too large or too small"); case POPT_ERROR_MALLOC: return POPT_("memory allocation failed"); case POPT_ERROR_ERRNO: return strerror(errno); default: return POPT_("unknown error"); } } int poptStuffArgs(poptContext con, const char ** argv) { int argc; int rc; if ((con->os - con->optionStack) == POPT_OPTION_DEPTH) return POPT_ERROR_OPTSTOODEEP; for (argc = 0; argv[argc]; argc++) {}; con->os++; con->os->next = 0; con->os->nextArg = NULL; con->os->nextCharArg = NULL; con->os->currAlias = NULL; rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); con->os->argb = NULL; con->os->stuffed = 1; return rc; } const char * poptGetInvocationName(poptContext con) { return (con->os->argv ? con->os->argv[0] : ""); } /*@-boundswrite@*/ int poptStrippedArgv(poptContext con, int argc, char ** argv) { int numargs = argc; int j = 1; int i; /*@-sizeoftype@*/ if (con->arg_strip) for (i = 1; i < argc; i++) { if (PBM_ISSET(i, con->arg_strip)) numargs--; } for (i = 1; i < argc; i++) { if (con->arg_strip && PBM_ISSET(i, con->arg_strip)) continue; argv[j] = (j < numargs) ? argv[i] : NULL; j++; } /*@=sizeoftype@*/ return numargs; } /*@=boundswrite@*/ rsync-3.2.7/popt/poptconfig.c0000664000000000000000000001075210524507416014670 0ustar rootroot/** \ingroup popt * \file popt/poptconfig.c */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "poptint.h" /*@access poptContext @*/ /*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */ static void configLine(poptContext con, char * line) /*@modifies con @*/ { size_t nameLength; const char * entryType; const char * opt; poptItem item = (poptItem) alloca(sizeof(*item)); int i, j; if (con->appName == NULL) return; nameLength = strlen(con->appName); /*@-boundswrite@*/ memset(item, 0, sizeof(*item)); if (strncmp(line, con->appName, nameLength)) return; line += nameLength; if (*line == '\0' || !isSpace(line)) return; while (*line != '\0' && isSpace(line)) line++; entryType = line; while (*line == '\0' || !isSpace(line)) line++; *line++ = '\0'; while (*line != '\0' && isSpace(line)) line++; if (*line == '\0') return; opt = line; while (*line == '\0' || !isSpace(line)) line++; *line++ = '\0'; while (*line != '\0' && isSpace(line)) line++; if (*line == '\0') return; /*@-temptrans@*/ /* FIX: line alias is saved */ if (opt[0] == '-' && opt[1] == '-') item->option.longName = opt + 2; else if (opt[0] == '-' && opt[2] == '\0') item->option.shortName = opt[1]; /*@=temptrans@*/ if (poptParseArgvString(line, &item->argc, &item->argv)) return; /*@-modobserver@*/ item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; for (i = 0, j = 0; i < item->argc; i++, j++) { const char * f; if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) { f = item->argv[i] + sizeof("--POPTdesc="); if (f[0] == '$' && f[1] == '"') f++; item->option.descrip = f; item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; j--; } else if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) { f = item->argv[i] + sizeof("--POPTargs="); if (f[0] == '$' && f[1] == '"') f++; item->option.argDescrip = f; item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; item->option.argInfo |= POPT_ARG_STRING; j--; } else if (j != i) item->argv[j] = item->argv[i]; } if (j != i) { item->argv[j] = NULL; item->argc = j; } /*@=modobserver@*/ /*@=boundswrite@*/ /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */ if (!strcmp(entryType, "alias")) (void) poptAddItem(con, item, 0); else if (!strcmp(entryType, "exec")) (void) poptAddItem(con, item, 1); /*@=nullstate@*/ } /*@=compmempass@*/ int poptReadConfigFile(poptContext con, const char * fn) { const char * file, * chptr, * end; char * buf; /*@dependent@*/ char * dst; int fd, rc; off_t fileLength; fd = open(fn, O_RDONLY); if (fd < 0) return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO); fileLength = lseek(fd, 0, SEEK_END); if (fileLength == -1 || lseek(fd, 0, 0) == -1) { rc = errno; (void) close(fd); errno = rc; return POPT_ERROR_ERRNO; } file = alloca(fileLength + 1); if (read(fd, (char *)file, fileLength) != fileLength) { rc = errno; (void) close(fd); errno = rc; return POPT_ERROR_ERRNO; } if (close(fd) == -1) return POPT_ERROR_ERRNO; /*@-boundswrite@*/ dst = buf = alloca(fileLength + 1); chptr = file; end = (file + fileLength); /*@-infloops@*/ /* LCL: can't detect chptr++ */ while (chptr < end) { switch (*chptr) { case '\n': *dst = '\0'; dst = buf; while (*dst && isSpace(dst)) dst++; if (*dst && *dst != '#') configLine(con, dst); chptr++; /*@switchbreak@*/ break; case '\\': *dst++ = *chptr++; if (chptr < end) { if (*chptr == '\n') dst--, chptr++; /* \ at the end of a line does not insert a \n */ else *dst++ = *chptr++; } /*@switchbreak@*/ break; default: *dst++ = *chptr++; /*@switchbreak@*/ break; } } /*@=infloops@*/ /*@=boundswrite@*/ return 0; } int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv)) { char * fn, * home; int rc; if (con->appName == NULL) return 0; rc = poptReadConfigFile(con, "/etc/popt"); if (rc) return rc; if ((home = getenv("HOME"))) { size_t bufsize = strlen(home) + 20; fn = alloca(bufsize); if (fn == NULL) return 0; snprintf(fn, bufsize, "%s/.popt", home); rc = poptReadConfigFile(con, fn); if (rc) return rc; } return 0; } rsync-3.2.7/popt/poptint.h0000664000000000000000000000550010524507416014215 0ustar rootroot/** \ingroup popt * \file popt/poptint.h */ /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #ifndef H_POPTINT #define H_POPTINT /** * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. * @param p memory to free * @retval NULL always */ /*@unused@*/ static inline /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * p) /*@modifies p @*/ { if (p != NULL) free((void *)p); return NULL; } static inline int isSpace(const char *ptr) { return isspace(*(unsigned char *)ptr); } /* Bit mask macros. */ /*@-exporttype -redef @*/ typedef unsigned int __pbm_bits; /*@=exporttype =redef @*/ #define __PBM_NBITS (8 * sizeof (__pbm_bits)) #define __PBM_IX(d) ((d) / __PBM_NBITS) #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS)) /*@-exporttype -redef @*/ typedef struct { __pbm_bits bits[1]; } pbm_set; /*@=exporttype =redef @*/ #define __PBM_BITS(set) ((set)->bits) #define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits)) #define PBM_FREE(s) _free(s); #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d)) #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d)) #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0) struct optionStackEntry { int argc; /*@only@*/ /*@null@*/ const char ** argv; /*@only@*/ /*@null@*/ pbm_set * argb; int next; /*@only@*/ /*@null@*/ const char * nextArg; /*@observer@*/ /*@null@*/ const char * nextCharArg; /*@dependent@*/ /*@null@*/ poptItem currAlias; int stuffed; }; struct poptContext_s { struct optionStackEntry optionStack[POPT_OPTION_DEPTH]; /*@dependent@*/ struct optionStackEntry * os; /*@owned@*/ /*@null@*/ const char ** leftovers; int numLeftovers; int nextLeftover; /*@keep@*/ const struct poptOption * options; int restLeftover; /*@only@*/ /*@null@*/ const char * appName; /*@only@*/ /*@null@*/ poptItem aliases; int numAliases; int flags; /*@owned@*/ /*@null@*/ poptItem execs; int numExecs; /*@only@*/ /*@null@*/ const char ** finalArgv; int finalArgvCount; int finalArgvAlloced; /*@dependent@*/ /*@null@*/ poptItem doExec; /*@only@*/ const char * execPath; int execAbsolute; /*@only@*/ /*@relnull@*/ const char * otherHelp; /*@null@*/ pbm_set * arg_strip; }; #ifdef HAVE_LIBINTL_H #include #endif #if defined(HAVE_GETTEXT) && !defined(__LCLINT__) #define _(foo) gettext(foo) #else #define _(foo) foo #endif #if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__) #define D_(dom, str) dgettext(dom, str) #define POPT_(foo) D_("popt", foo) #else #define D_(dom, str) str #define POPT_(foo) foo #endif #define N_(foo) foo #endif rsync-3.2.7/popt/README.rsync0000664000000000000000000000044607520563471014375 0ustar rootrootThis is a perfectly ordinary copy of libpopt. It is only used on platforms that do not have a sufficiently up-to-date copy of their own. If you build rsync on a platform which has popt, this directory should not be used. (You can control that using the --with-included-popt configure flag.) rsync-3.2.7/popt/findme.h0000664000000000000000000000077007520563471013773 0ustar rootroot/** \ingroup popt * \file popt/findme.h */ /* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #ifndef H_FINDME #define H_FINDME /** * Return absolute path to executable by searching PATH. * @param argv0 name of executable * @return (malloc'd) absolute path to executable (or NULL) */ /*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0) /*@*/; #endif rsync-3.2.7/popt/poptparse.c0000664000000000000000000001233710764561320014536 0ustar rootroot/** \ingroup popt * \file popt/poptparse.c */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "poptint.h" #define POPT_ARGV_ARRAY_GROW_DELTA 5 /*@-boundswrite@*/ int poptDupArgv(int argc, const char **argv, int * argcPtr, const char *** argvPtr) { size_t nb = (argc + 1) * sizeof(*argv); const char ** argv2; char * dst; int i; if (argc <= 0 || argv == NULL) /* XXX can't happen */ return POPT_ERROR_NOARG; for (i = 0; i < argc; i++) { if (argv[i] == NULL) return POPT_ERROR_NOARG; nb += strlen(argv[i]) + 1; } dst = malloc(nb); if (dst == NULL) /* XXX can't happen */ return POPT_ERROR_MALLOC; argv2 = (void *) dst; dst += (argc + 1) * sizeof(*argv); /*@-branchstate@*/ for (i = 0; i < argc; i++) { argv2[i] = dst; dst += strlcpy(dst, argv[i], nb) + 1; } /*@=branchstate@*/ argv2[argc] = NULL; if (argvPtr) { *argvPtr = argv2; } else { free(argv2); argv2 = NULL; } if (argcPtr) *argcPtr = argc; return 0; } /*@=boundswrite@*/ /*@-bounds@*/ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) { const char * src; char quote = '\0'; int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; const char ** argv = malloc(sizeof(*argv) * argvAlloced); int argc = 0; int buflen = strlen(s) + 1; char * buf = memset(alloca(buflen), 0, buflen); int rc = POPT_ERROR_MALLOC; if (argv == NULL) return rc; argv[argc] = buf; for (src = s; *src != '\0'; src++) { if (quote == *src) { quote = '\0'; } else if (quote != '\0') { if (*src == '\\') { src++; if (!*src) { rc = POPT_ERROR_BADQUOTE; goto exit; } if (*src != quote) *buf++ = '\\'; } *buf++ = *src; } else if (isSpace(src)) { if (*argv[argc] != '\0') { buf++, argc++; if (argc == argvAlloced) { argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; argv = realloc(argv, sizeof(*argv) * argvAlloced); if (argv == NULL) goto exit; } argv[argc] = buf; } } else switch (*src) { case '"': case '\'': quote = *src; /*@switchbreak@*/ break; case '\\': src++; if (!*src) { rc = POPT_ERROR_BADQUOTE; goto exit; } /*@fallthrough@*/ default: *buf++ = *src; /*@switchbreak@*/ break; } } if (strlen(argv[argc])) { argc++, buf++; } rc = poptDupArgv(argc, argv, argcPtr, argvPtr); exit: if (argv) free(argv); return rc; } /*@=bounds@*/ /* still in the dev stage. * return values, perhaps 1== file erro * 2== line to long * 3== umm.... more? */ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ UNUSED(int flags)) { char line[999]; char * argstr; char * p; char * q; char * x; int t; int argvlen = 0; size_t maxlinelen = sizeof(line); size_t linelen; int maxargvlen = 480; int linenum = 0; *argstrp = NULL; /* | this_is = our_line * p q x */ if (fp == NULL) return POPT_ERROR_NULLARG; argstr = calloc(maxargvlen, sizeof(*argstr)); if (argstr == NULL) return POPT_ERROR_MALLOC; while (fgets(line, (int)maxlinelen, fp) != NULL) { linenum++; p = line; /* loop until first non-space char or EOL */ while( *p != '\0' && isSpace(p) ) p++; linelen = strlen(p); if (linelen >= maxlinelen-1) { free(argstr); return POPT_ERROR_OVERFLOW; /* XXX line too long */ } if (*p == '\0' || *p == '\n') continue; /* line is empty */ if (*p == '#') continue; /* comment line */ q = p; while (*q != '\0' && (!isSpace(q)) && *q != '=') q++; if (isSpace(q)) { /* a space after the name, find next non space */ *q++='\0'; while( *q != '\0' && isSpace(q) ) q++; } if (*q == '\0') { /* single command line option (ie, no name=val, just name) */ q[-1] = '\0'; /* kill off newline from fgets() call */ argvlen += (t = q - p) + (sizeof(" --")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; argstr = realloc(argstr, maxargvlen); if (argstr == NULL) return POPT_ERROR_MALLOC; } strlcat(argstr, " --", maxargvlen); strlcat(argstr, p, maxargvlen); continue; } if (*q != '=') continue; /* XXX for now, silently ignore bogus line */ /* *q is an equal sign. */ *q++ = '\0'; /* find next non-space letter of value */ while (*q != '\0' && isSpace(q)) q++; if (*q == '\0') continue; /* XXX silently ignore missing value */ /* now, loop and strip all ending whitespace */ x = p + linelen; while (isSpace(--x)) *x = 0; /* null out last char if space (including fgets() NL) */ /* rest of line accept */ t = x - p; argvlen += t + (sizeof("' --='")-1); if (argvlen >= maxargvlen) { maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; argstr = realloc(argstr, maxargvlen); if (argstr == NULL) return POPT_ERROR_MALLOC; } strlcat(argstr, " --", maxargvlen); strlcat(argstr, p, maxargvlen); strlcat(argstr, "=\"", maxargvlen); strlcat(argstr, q, maxargvlen); strlcat(argstr, "\"", maxargvlen); } *argstrp = argstr; return 0; } rsync-3.2.7/popt/findme.c0000664000000000000000000000242410524476423013762 0ustar rootroot/** \ingroup popt * \file popt/findme.c */ /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "findme.h" const char * findProgramPath(const char * argv0) { char * path = getenv("PATH"); char * pathbuf; char * start, * chptr; char * buf; size_t bufsize; if (argv0 == NULL) return NULL; /* XXX can't happen */ /* If there is a / in the argv[0], it has to be an absolute path */ if (strchr(argv0, '/')) return xstrdup(argv0); if (path == NULL) return NULL; bufsize = strlen(path) + 1; start = pathbuf = alloca(bufsize); if (pathbuf == NULL) return NULL; /* XXX can't happen */ strlcpy(pathbuf, path, bufsize); bufsize += sizeof "/" - 1 + strlen(argv0); buf = malloc(bufsize); if (buf == NULL) return NULL; /* XXX can't happen */ chptr = NULL; /*@-branchstate@*/ do { if ((chptr = strchr(start, ':'))) *chptr = '\0'; snprintf(buf, bufsize, "%s/%s", start, argv0); if (!access(buf, X_OK)) return buf; if (chptr) start = chptr + 1; else start = NULL; } while (start && *start); /*@=branchstate@*/ free(buf); return NULL; } rsync-3.2.7/popt/COPYING0000664000000000000000000000237507245607446013423 0ustar rootrootCopyright (c) 1998 Red Hat Software Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. rsync-3.2.7/popt/README0000664000000000000000000000152607520563471013240 0ustar rootrootThis is the popt command line option parsing library. While it is similiar to getopt(3), it contains a number of enhancements, including: 1) popt is fully reentrant 2) popt can parse arbitrary argv[] style arrays while getopt(2) makes this quite difficult 3) popt allows users to alias command line arguments 4) popt provides convience functions for parsing strings into argv[] style arrays popt is used by rpm, the Red Hat install program, and many other Red Hat utilities, all of which provide excellent examples of how to use popt. Complete documentation on popt is available in popt.ps (included in this tarball), which is excerpted with permission from the book "Linux Application Development" by Michael K. Johnson and Erik Troan (availble from Addison Wesley in May, 1998). Comments on popt should be addressed to ewt@redhat.com. rsync-3.2.7/popt/system.h0000664000000000000000000000521113700546512014042 0ustar rootroot#ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined (__GLIBC__) && defined(__LCLINT__) /*@-declundef@*/ /*@unchecked@*/ extern __const __int32_t *__ctype_tolower; /*@unchecked@*/ extern __const __int32_t *__ctype_toupper; /*@=declundef@*/ #endif #ifdef __TANDEM # include #endif #include #include #include #include #if HAVE_MCHECK_H #include #endif #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifndef __GNUC__ #define __attribute__(x) #endif #ifdef __NeXT /* access macros are not declared in non posix mode in unistd.h - don't try to use posix on NeXTstep 3.3 ! */ #include #endif #if defined(__LCLINT__) /*@-declundef -incondefs @*/ /* LCL: missing annotation */ /*@only@*/ /*@out@*/ void * alloca (size_t __size) /*@ensures MaxSet(result) == (__size - 1) @*/ /*@*/; /*@=declundef =incondefs @*/ #endif /* AIX requires this to be the first thing in the file. */ #ifndef __GNUC__ # if HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifdef HAVE_ALLOCA # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca(size_t size); # endif # else # ifdef alloca # undef alloca # endif # define alloca(sz) malloc(sz) /* Kludge this for now */ # endif # endif # endif #elif !defined(alloca) #define alloca __builtin_alloca #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *d, const char *s, size_t bufsize); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *d, const char *s, size_t bufsize); #endif #if HAVE_MCHECK_H && defined(__GNUC__) static inline char * xstrdup(const char *s) { size_t memsize = strlen(s) + 1; char *ptr = malloc(memsize); if (!ptr) { fprintf(stderr, "virtual memory exhausted.\n"); exit(EXIT_FAILURE); } strlcpy(ptr, s, memsize); return ptr; } #else #define xstrdup(_str) strdup(_str) #endif /* HAVE_MCHECK_H && defined(__GNUC__) */ #if HAVE___SECURE_GETENV && !defined(__LCLINT__) #define getenv(_s) __secure_getenv(_s) #endif #if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF #define snprintf rsync_snprintf int snprintf(char *str,size_t count,const char *fmt,...); #endif #define UNUSED(x) x __attribute__((__unused__)) #define PACKAGE "rsync" #include "popt.h" rsync-3.2.7/popt/CHANGES0000664000000000000000000000244107520563471013350 0ustar rootroot1.5 -> 1.6 - add ability to perform callbacks for every, not just first, match. 1.3 -> 1.5 - heavy dose of const's - poptParseArgvString() now NULL terminates the list 1.2.3 -> 1.3 - added support for single - - misc bug fixes - portability improvements 1.2.2 -> 1.2.3 - fixed memset() in help message generation (Dale Hawkins) - added extern "C" stuff to popt.h for C++ compilers (Dale Hawkins) - const'ified poptParseArgvString (Jeff Garzik) 1.2.1 -> 1.2.2 - fixed bug in chaind alias happens which seems to have only affected --triggers in rpm - added POPT_ARG_VAL - popt.3 installed by default 1.2 -> 1.2.1 - added POPT_ARG_INTL_DOMAIN (Elliot Lee) - updated Makefile's to be more GNUish (Elliot Lee) 1.1 -> 1.2 - added popt.3 man page (Robert Lynch) - don't use mmap anymore (its lack of portability isn't worth the trouble) - added test script - added support for exec - removed support for *_POPT_ALIASES env variable -- it was a bad idea - reorganized into multiple source files - added automatic help generation, POPT_AUTOHELP - added table callbacks - added table inclusion - updated man page for new features - added test scripts 1.0 -> 1.1 - moved to autoconf (Fred Fish) - added STRERROR replacement (Norbert Warmuth) - added const keywords (Bruce Perens) rsync-3.2.7/wildtest.txt0000664000000000000000000001021110351415543013755 0ustar rootroot# Input is in the following format (all items white-space separated): # # The first two items are 1 or 0 indicating if the wildmat call is expected to # succeed and if fnmatch works the same way as wildmat, respectively. After # that is a text string for the match, and a pattern string. Strings can be # quoted (if desired) in either double or single quotes, as well as backticks. # # MATCH FNMATCH_SAME "text to match" 'pattern to use' # Basic wildmat features 1 1 foo foo 0 1 foo bar 1 1 '' "" 1 1 foo ??? 0 1 foo ?? 1 1 foo * 1 1 foo f* 0 1 foo *f 1 1 foo *foo* 1 1 foobar *ob*a*r* 1 1 aaaaaaabababab *ab 1 1 foo* foo\* 0 1 foobar foo\*bar 1 1 f\oo f\\oo 1 1 ball *[al]? 0 1 ten [ten] 1 1 ten **[!te] 0 1 ten **[!ten] 1 1 ten t[a-g]n 0 1 ten t[!a-g]n 1 1 ton t[!a-g]n 1 1 ton t[^a-g]n 1 1 a]b a[]]b 1 1 a-b a[]-]b 1 1 a]b a[]-]b 0 1 aab a[]-]b 1 1 aab a[]a-]b 1 1 ] ] # Extended slash-matching features 0 1 foo/baz/bar foo*bar 1 1 foo/baz/bar foo**bar 0 1 foo/bar foo?bar 0 1 foo/bar foo[/]bar 0 1 foo/bar f[^eiu][^eiu][^eiu][^eiu][^eiu]r 1 1 foo-bar f[^eiu][^eiu][^eiu][^eiu][^eiu]r 0 1 foo **/foo 1 1 /foo **/foo 1 1 bar/baz/foo **/foo 0 1 bar/baz/foo */foo 0 0 foo/bar/baz **/bar* 1 1 deep/foo/bar/baz **/bar/* 0 1 deep/foo/bar/baz/ **/bar/* 1 1 deep/foo/bar/baz/ **/bar/** 0 1 deep/foo/bar **/bar/* 1 1 deep/foo/bar/ **/bar/** 1 1 foo/bar/baz **/bar** 1 1 foo/bar/baz/x */bar/** 0 0 deep/foo/bar/baz/x */bar/** 1 1 deep/foo/bar/baz/x **/bar/*/* # Various additional tests 0 1 acrt a[c-c]st 1 1 acrt a[c-c]rt 0 1 ] [!]-] 1 1 a [!]-] 0 1 '' \ 0 1 \ \ 0 1 /\ */\ 1 1 /\ */\\ 1 1 foo foo 1 1 @foo @foo 0 1 foo @foo 1 1 [ab] \[ab] 1 1 [ab] [[]ab] 1 1 [ab] [[:]ab] 0 1 [ab] [[::]ab] 1 1 [ab] [[:digit]ab] 1 1 [ab] [\[:]ab] 1 1 ?a?b \??\?b 1 1 abc \a\b\c 0 1 foo '' 1 1 foo/bar/baz/to **/t[o] # Character class tests 1 1 a1B [[:alpha:]][[:digit:]][[:upper:]] 0 1 a [[:digit:][:upper:][:space:]] 1 1 A [[:digit:][:upper:][:space:]] 1 1 1 [[:digit:][:upper:][:space:]] 0 1 1 [[:digit:][:upper:][:spaci:]] 1 1 ' ' [[:digit:][:upper:][:space:]] 0 1 . [[:digit:][:upper:][:space:]] 1 1 . [[:digit:][:punct:][:space:]] 1 1 5 [[:xdigit:]] 1 1 f [[:xdigit:]] 1 1 D [[:xdigit:]] 1 1 _ [[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] #1 1 … [^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] 1 1  [^[:alnum:][:alpha:][:blank:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]] 1 1 . [^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]] 1 1 5 [a-c[:digit:]x-z] 1 1 b [a-c[:digit:]x-z] 1 1 y [a-c[:digit:]x-z] 0 1 q [a-c[:digit:]x-z] # Additional tests, including some malformed wildmats 1 1 ] [\\-^] 0 1 [ [\\-^] 1 1 - [\-_] 1 1 ] [\]] 0 1 \] [\]] 0 1 \ [\]] 0 1 ab a[]b 0 1 a[]b a[]b 0 1 ab[ ab[ 0 1 ab [! 0 1 ab [- 1 1 - [-] 0 1 - [a- 0 1 - [!a- 1 1 - [--A] 1 1 5 [--A] 1 1 ' ' '[ --]' 1 1 $ '[ --]' 1 1 - '[ --]' 0 1 0 '[ --]' 1 1 - [---] 1 1 - [------] 0 1 j [a-e-n] 1 1 - [a-e-n] 1 1 a [!------] 0 1 [ []-a] 1 1 ^ []-a] 0 1 ^ [!]-a] 1 1 [ [!]-a] 1 1 ^ [a^bc] 1 1 -b] [a-]b] 0 1 \ [\] 1 1 \ [\\] 0 1 \ [!\\] 1 1 G [A-\\] 0 1 aaabbb b*a 0 1 aabcaa *ba* 1 1 , [,] 1 1 , [\\,] 1 1 \ [\\,] 1 1 - [,-.] 0 1 + [,-.] 0 1 -.] [,-.] 1 1 2 [\1-\3] 1 1 3 [\1-\3] 0 1 4 [\1-\3] 1 1 \ [[-\]] 1 1 [ [[-\]] 1 1 ] [[-\]] 0 1 - [[-\]] # Test recursion and the abort code (use "wildtest -i" to see iteration counts) 1 1 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-* 0 1 -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-* 0 1 -adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-* 1 1 /adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1 /*/*/*/*/*/*/12/*/*/*/m/*/*/* 0 1 /adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1 /*/*/*/*/*/*/12/*/*/*/m/*/*/* 1 1 abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt **/*a*b*g*n*t 0 1 abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz **/*a*b*g*n*t rsync-3.2.7/aclocal.m40000664000000000000000000000140614324135367013232 0ustar rootroot# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_include([../m4/have_type.m4]) m4_include([../m4/header_major_fixed.m4]) m4_include([../m4/socklen_t.m4]) rsync-3.2.7/io.h0000664000000000000000000000241413443220465012145 0ustar rootroot/* * Copyright (C) 2007-2019 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. */ extern int protocol_version; static inline int32 read_varint30(int f) { if (protocol_version < 30) return read_int(f); return read_varint(f); } static inline int64 read_varlong30(int f, uchar min_bytes) { if (protocol_version < 30) return read_longint(f); return read_varlong(f, min_bytes); } static inline void write_varint30(int f, int32 x) { if (protocol_version < 30) write_int(f, x); else write_varint(f, x); } static inline void write_varlong30(int f, int64 x, uchar min_bytes) { if (protocol_version < 30) write_longint(f, x); else write_varlong(f, x, min_bytes); } rsync-3.2.7/shconfig.in0000775000000000000000000000055011636172346013525 0ustar rootroot#! /bin/sh # config.sh.in # This file is processed by config.status to produce config.status, # containing autoconf-determined values needed by the test scripts. ECHO_T="@ECHO_T@" ECHO_N="@ECHO_N@" ECHO_C="@ECHO_C@" HOST_OS="@host_os@" SHELL_PATH="@SHELL_PATH@" FAKEROOT_PATH="@FAKEROOT_PATH@" export ECHO_T ECHO_N ECHO_C HOST_OS SHELL_PATH FAKEROOT_PATH rsync-3.2.7/generator.c0000664000000000000000000020530514310656342013524 0ustar rootroot/* * Routines that are exclusive to the generator process. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2022 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 "inums.h" #include "ifuncs.h" extern int dry_run; extern int do_xfers; extern int stdout_format_has_i; extern int logfile_format_has_i; extern int am_root; extern int am_server; extern int am_daemon; extern int inc_recurse; extern int relative_paths; extern int implied_dirs; extern int keep_dirlinks; extern int write_devices; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; extern int preserve_specials; extern int preserve_hard_links; extern int preserve_executability; extern int preserve_perms; extern int preserve_mtimes; extern int omit_dir_times; extern int omit_link_times; extern int delete_mode; extern int delete_before; extern int delete_during; extern int delete_after; extern int missing_args; extern int msgdone_cnt; extern int ignore_errors; extern int remove_source_files; extern int delay_updates; extern int update_only; extern int human_readable; extern int ignore_existing; extern int ignore_non_existing; extern int want_xattr_optim; extern int modify_window; extern int inplace; extern int append_mode; extern int make_backups; extern int csum_length; extern int ignore_times; extern int size_only; extern OFF_T max_size; extern OFF_T min_size; extern int io_error; extern int flist_eof; extern int allowed_lull; extern int sock_f_out; extern int protocol_version; extern int file_total; extern int fuzzy_basis; extern int always_checksum; extern int flist_csum_len; extern char *partial_dir; extern int alt_dest_type; extern int whole_file; extern int list_only; extern int read_batch; extern int write_batch; extern int safe_symlinks; extern int32 block_size; extern int unsort_ndx; extern int max_delete; extern int force_delete; extern int one_file_system; extern int skipped_deletes; extern dev_t filesystem_dev; extern mode_t orig_umask; extern uid_t our_uid; extern char *tmpdir; extern char *basis_dir[MAX_BASIS_DIRS+1]; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern filter_rule_list filter_list, daemon_filter_list; int maybe_ATTRS_REPORT = 0; int maybe_ATTRS_ACCURATE_TIME = 0; static dev_t dev_zero; static int deldelay_size = 0, deldelay_cnt = 0; static char *deldelay_buf = NULL; static int deldelay_fd = -1; static int loopchk_limit; static int dir_tweaking; static int symlink_timeset_failed_flags; static int need_retouch_dir_times; static int need_retouch_dir_perms; static const char *solo_file = NULL; /* Forward declarations. */ #ifdef SUPPORT_HARD_LINKS static void handle_skipped_hlink(struct file_struct *file, int itemizing, enum logcode code, int f_out); #endif #define EARLY_DELAY_DONE_MSG() (!delay_updates) #define EARLY_DELETE_DONE_MSG() (!(delete_during == 2 || delete_after)) static int start_delete_delay_temp(void) { char fnametmp[MAXPATHLEN]; int save_dry_run = dry_run; dry_run = 0; if (!get_tmpname(fnametmp, "deldelay", False) || (deldelay_fd = do_mkstemp(fnametmp, 0600)) < 0) { rprintf(FINFO, "NOTE: Unable to create delete-delay temp file%s.\n", inc_recurse ? "" : " -- switching to --delete-after"); delete_during = 0; delete_after = !inc_recurse; dry_run = save_dry_run; return 0; } unlink(fnametmp); dry_run = save_dry_run; return 1; } static int flush_delete_delay(void) { if (deldelay_fd < 0 && !start_delete_delay_temp()) return 0; if (write(deldelay_fd, deldelay_buf, deldelay_cnt) != deldelay_cnt) { rsyserr(FERROR, errno, "flush of delete-delay buffer"); delete_during = 0; delete_after = !inc_recurse; close(deldelay_fd); return 0; } deldelay_cnt = 0; return 1; } static int remember_delete(struct file_struct *file, const char *fname, int flags) { int len; if (deldelay_cnt == deldelay_size && !flush_delete_delay()) return 0; if (flags & DEL_NO_UID_WRITE) deldelay_buf[deldelay_cnt++] = '!'; while (1) { len = snprintf(deldelay_buf + deldelay_cnt, deldelay_size - deldelay_cnt, "%x %s%c", (int)file->mode, fname, '\0'); if ((deldelay_cnt += len) <= deldelay_size) break; deldelay_cnt -= len; if (!flush_delete_delay()) return 0; } return 1; } static int read_delay_line(char *buf, int *flags_p) { static int read_pos = 0; unsigned int mode; int j, len; char *bp, *past_space; while (1) { for (j = read_pos; j < deldelay_cnt && deldelay_buf[j]; j++) {} if (j < deldelay_cnt) break; if (deldelay_fd < 0) { if (j > read_pos) goto invalid_data; return -1; } deldelay_cnt -= read_pos; if (deldelay_cnt == deldelay_size) goto invalid_data; if (deldelay_cnt && read_pos) { memmove(deldelay_buf, deldelay_buf + read_pos, deldelay_cnt); } len = read(deldelay_fd, deldelay_buf + deldelay_cnt, deldelay_size - deldelay_cnt); if (len == 0) { if (deldelay_cnt) { rprintf(FERROR, "ERROR: unexpected EOF in delete-delay file.\n"); } return -1; } if (len < 0) { rsyserr(FERROR, errno, "reading delete-delay file"); return -1; } deldelay_cnt += len; read_pos = 0; } bp = deldelay_buf + read_pos; if (*bp == '!') { bp++; *flags_p = DEL_NO_UID_WRITE; } else *flags_p = 0; if (sscanf(bp, "%x ", &mode) != 1) { invalid_data: rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n"); return -1; } past_space = strchr(bp, ' ') + 1; len = j - read_pos - (past_space - bp) + 1; /* count the '\0' */ read_pos = j + 1; if (len > MAXPATHLEN) { rprintf(FERROR, "ERROR: filename too long in delete-delay file.\n"); return -1; } /* The caller needs the name in a MAXPATHLEN buffer, so we copy it * instead of returning a pointer to our buffer. */ memcpy(buf, past_space, len); return mode; } static void do_delayed_deletions(char *delbuf) { int mode, flags; if (deldelay_fd >= 0) { if (deldelay_cnt && !flush_delete_delay()) return; lseek(deldelay_fd, 0, 0); } while ((mode = read_delay_line(delbuf, &flags)) >= 0) delete_item(delbuf, mode, flags | DEL_RECURSE); if (deldelay_fd >= 0) close(deldelay_fd); } /* This function is used to implement per-directory deletion, and is used by * all the --delete-WHEN options. Note that the fbuf pointer must point to a * MAXPATHLEN buffer with the name of the directory in it (the functions we * call will append names onto the end, but the old dir value will be restored * on exit). */ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t fs_dev) { static int already_warned = 0; static struct hashtable *dev_tbl; struct file_list *dirlist; char delbuf[MAXPATHLEN]; int dlen, i; if (!fbuf) { change_local_filter_dir(NULL, 0, 0); return; } if (DEBUG_GTE(DEL, 2)) rprintf(FINFO, "delete_in_dir(%s)\n", fbuf); if (allowed_lull) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); if (io_error & IOERR_GENERAL && !ignore_errors) { if (already_warned) return; rprintf(FINFO, "IO error encountered -- skipping file deletion\n"); already_warned = 1; return; } dlen = strlen(fbuf); change_local_filter_dir(fbuf, dlen, F_DEPTH(file)); if (one_file_system) { if (!dev_tbl) dev_tbl = hashtable_create(16, HT_KEY64); if (file->flags & FLAG_TOP_DIR) { hashtable_find(dev_tbl, fs_dev+1, ""); filesystem_dev = fs_dev; } else if (filesystem_dev != fs_dev) { if (!hashtable_find(dev_tbl, fs_dev+1, NULL)) return; filesystem_dev = fs_dev; /* it's a prior top-dir dev */ } } dirlist = get_dirlist(fbuf, dlen, 0); /* If an item in dirlist is not found in flist, delete it * from the filesystem. */ for (i = dirlist->used; i--; ) { struct file_struct *fp = dirlist->files[i]; if (!F_IS_ACTIVE(fp)) continue; if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { if (INFO_GTE(MOUNT, 1)) rprintf(FINFO, "cannot delete mount point: %s\n", f_name(fp, NULL)); continue; } /* Here we want to match regardless of file type. Replacement * of a file with one of another type is handled separately by * a delete_item call with a DEL_MAKE_ROOM flag. */ if (flist_find_ignore_dirness(cur_flist, fp) < 0) { int flags = DEL_RECURSE; if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) flags |= DEL_NO_UID_WRITE; f_name(fp, delbuf); if (delete_during == 2) { if (!remember_delete(fp, delbuf, flags)) break; } else delete_item(delbuf, fp->mode, flags); } } flist_free(dirlist); } /* This deletes any files on the receiving side that are not present on the * sending side. This is used by --delete-before and --delete-after. */ static void do_delete_pass(void) { char fbuf[MAXPATHLEN]; STRUCT_STAT st; int j; /* dry_run is incremented when the destination doesn't exist yet. */ if (dry_run > 1 || list_only) return; for (j = 0; j < cur_flist->used; j++) { struct file_struct *file = cur_flist->sorted[j]; if (!F_IS_ACTIVE(file)) continue; f_name(file, fbuf); if (!(file->flags & FLAG_CONTENT_DIR)) { change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file)); continue; } if (DEBUG_GTE(DEL, 1) && file->flags & FLAG_TOP_DIR) rprintf(FINFO, "deleting in %s\n", fbuf); if (link_stat(fbuf, &st, keep_dirlinks) < 0 || !S_ISDIR(st.st_mode)) continue; delete_in_dir(fbuf, file, st.st_dev); } delete_in_dir(NULL, NULL, dev_zero); if (INFO_GTE(FLIST, 2) && !am_server) rprintf(FINFO, " \r"); } static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file) { #ifdef ST_MTIME_NSEC return !same_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC_or_0(file)); #else return !same_time(stp->st_mtime, 0, file->modtime, 0); #endif } static inline int any_time_differs(stat_x *sxp, struct file_struct *file, UNUSED(const char *fname)) { int differs = mtime_differs(&sxp->st, file); #ifdef SUPPORT_CRTIMES if (!differs && crtimes_ndx) { if (sxp->crtime == 0) sxp->crtime = get_create_time(fname, &sxp->st); differs = !same_time(sxp->crtime, 0, F_CRTIME(file), 0); } #endif return differs; } static inline int perms_differ(struct file_struct *file, stat_x *sxp) { if (preserve_perms) return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS); if (preserve_executability) return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0); return 0; } static inline int ownership_differs(struct file_struct *file, stat_x *sxp) { if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file)) return 1; if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) return 1; return 0; } #ifdef SUPPORT_ACLS static inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp) { if (preserve_acls) { if (!ACL_READY(*sxp)) get_acl(fname, sxp); if (set_acl(NULL, file, sxp, file->mode)) return 1; } return 0; } #endif #ifdef SUPPORT_XATTRS static inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp) { if (preserve_xattrs) { if (!XATTR_READY(*sxp)) get_xattr(fname, sxp); if (xattr_diff(file, sxp, 0)) return 1; } return 0; } #endif int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp) { if (S_ISLNK(file->mode)) { #ifdef CAN_SET_SYMLINK_TIMES if (preserve_mtimes && !omit_link_times && any_time_differs(sxp, file, fname)) return 0; #endif #ifdef CAN_CHMOD_SYMLINK if (perms_differ(file, sxp)) return 0; #endif #ifdef CAN_CHOWN_SYMLINK if (ownership_differs(file, sxp)) return 0; #endif #if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */ if (acls_differ(fname, file, sxp)) return 0; #endif #if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS if (xattrs_differ(fname, file, sxp)) return 0; #endif } else { if (preserve_mtimes && any_time_differs(sxp, file, fname)) return 0; if (perms_differ(file, sxp)) return 0; if (ownership_differs(file, sxp)) return 0; #ifdef SUPPORT_ACLS if (acls_differ(fname, file, sxp)) return 0; #endif #ifdef SUPPORT_XATTRS if (xattrs_differ(fname, file, sxp)) return 0; #endif } return 1; } void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret, stat_x *sxp, int32 iflags, uchar fnamecmp_type, const char *xname) { if (statret >= 0) { /* A from-dest-dir statret can == 1! */ int keep_time = !preserve_mtimes ? 0 : S_ISDIR(file->mode) ? !omit_dir_times : S_ISLNK(file->mode) ? !omit_link_times : 1; if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size) iflags |= ITEM_REPORT_SIZE; if (file->flags & FLAG_TIME_FAILED) { /* symlinks only */ if (iflags & ITEM_LOCAL_CHANGE) iflags |= symlink_timeset_failed_flags; } else if (keep_time ? mtime_differs(&sxp->st, file) : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) iflags |= ITEM_REPORT_TIME; if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode) && !same_time(F_ATIME(file), 0, sxp->st.st_atime, 0)) iflags |= ITEM_REPORT_ATIME; #ifdef SUPPORT_CRTIMES if (crtimes_ndx) { if (sxp->crtime == 0) sxp->crtime = get_create_time(fnamecmp, &sxp->st); if (!same_time(sxp->crtime, 0, F_CRTIME(file), 0)) iflags |= ITEM_REPORT_CRTIME; } #endif #ifndef CAN_CHMOD_SYMLINK if (S_ISLNK(file->mode)) { ; } else #endif if (preserve_perms) { if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS)) iflags |= ITEM_REPORT_PERMS; } else if (preserve_executability && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0))) iflags |= ITEM_REPORT_PERMS; if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid) iflags |= ITEM_REPORT_OWNER; if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) iflags |= ITEM_REPORT_GROUP; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { if (!ACL_READY(*sxp)) get_acl(fnamecmp, sxp); if (set_acl(NULL, file, sxp, file->mode)) iflags |= ITEM_REPORT_ACL; } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { if (!XATTR_READY(*sxp)) get_xattr(fnamecmp, sxp); if (xattr_diff(file, sxp, 1)) iflags |= ITEM_REPORT_XATTR; } #endif } else { #ifdef SUPPORT_XATTRS if (preserve_xattrs && xattr_diff(file, NULL, 1)) iflags |= ITEM_REPORT_XATTR; #endif iflags |= ITEM_IS_NEW; } iflags &= 0xffff; if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || INFO_GTE(NAME, 2) || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) { if (protocol_version >= 29) { if (ndx >= 0) write_ndx(sock_f_out, ndx); write_shortint(sock_f_out, iflags); if (iflags & ITEM_BASIS_TYPE_FOLLOWS) write_byte(sock_f_out, fnamecmp_type); if (iflags & ITEM_XNAME_FOLLOWS) write_vstring(sock_f_out, xname, strlen(xname)); #ifdef SUPPORT_XATTRS if (preserve_xattrs && do_xfers && iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) { int fd = iflags & ITEM_REPORT_XATTR && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)) ? sock_f_out : -1; send_xattr_request(NULL, file, fd); } #endif } else if (ndx >= 0) { enum logcode code = logfile_format_has_i ? FINFO : FCLIENT; log_item(code, file, iflags, xname); } } } static enum filetype get_file_type(mode_t mode) { if (S_ISREG(mode)) return FT_REG; if (S_ISLNK(mode)) return FT_SYMLINK; if (S_ISDIR(mode)) return FT_DIR; if (IS_SPECIAL(mode)) return FT_SPECIAL; if (IS_DEVICE(mode)) return FT_DEVICE; return FT_UNSUPPORTED; } /* Perform our quick-check heuristic for determining if a file is unchanged. */ int quick_check_ok(enum filetype ftype, const char *fn, struct file_struct *file, STRUCT_STAT *st) { switch (ftype) { case FT_REG: if (st->st_size != F_LENGTH(file)) return 0; /* If always_checksum is set then we use the checksum instead * of the file mtime to determine whether to sync. */ if (always_checksum > 0) { char sum[MAX_DIGEST_LEN]; file_checksum(fn, st, sum); return memcmp(sum, F_SUM(file), flist_csum_len) == 0; } if (size_only > 0) return 1; if (ignore_times) return 0; if (mtime_differs(st, file)) return 0; break; case FT_DIR: break; case FT_SYMLINK: { #ifdef SUPPORT_LINKS char lnk[MAXPATHLEN]; int len = do_readlink(fn, lnk, MAXPATHLEN-1); if (len <= 0) return 0; lnk[len] = '\0'; if (strcmp(lnk, F_SYMLINK(file)) != 0) return 0; break; #else return -1; #endif } case FT_SPECIAL: if (!BITS_EQUAL(file->mode, st->st_mode, _S_IFMT)) return 0; break; case FT_DEVICE: { uint32 *devp = F_RDEV_P(file); if (st->st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp))) return 0; break; } case FT_UNSUPPORTED: return -1; } return 1; } /* * set (initialize) the size entries in the per-file sum_struct * calculating dynamic block and checksum sizes. * * This is only called from generate_and_send_sums() but is a separate * function to encapsulate the logic. * * The block size is a rounded square root of file length. * * The checksum size is determined according to: * blocksum_bits = BLOCKSUM_BIAS + 2*log2(file_len) - log2(block_len) * provided by Donovan Baarda which gives a probability of rsync * algorithm corrupting data and falling back using the whole md4 * checksums. * * This might be made one of several selectable heuristics. */ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len) { int32 blength; int s2length; int64 l; if (len < 0) { /* The file length overflowed our int64 var, so we can't process this file. */ sum->count = -1; /* indicate overflow error */ return; } if (block_size) blength = block_size; else if (len <= BLOCK_SIZE * BLOCK_SIZE) blength = BLOCK_SIZE; else { int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE; int32 c; int cnt; for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {} if (c < 0 || c >= max_blength) blength = max_blength; else { blength = 0; do { blength |= c; if (len < (int64)blength * blength) blength &= ~c; c >>= 1; } while (c >= 8); /* round to multiple of 8 */ blength = MAX(blength, BLOCK_SIZE); } } if (protocol_version < 27) { s2length = csum_length; } else if (csum_length == SUM_LENGTH) { s2length = SUM_LENGTH; } else { int32 c; int b = BLOCKSUM_BIAS; for (l = len; l >>= 1; b += 2) {} for (c = blength; (c >>= 1) && b; b--) {} /* add a bit, subtract rollsum, round up. */ s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */ s2length = MAX(s2length, csum_length); s2length = MIN(s2length, SUM_LENGTH); } sum->flength = len; sum->blength = blength; sum->s2length = s2length; sum->remainder = (int32)(len % blength); sum->count = (int32)(l = (len / blength) + (sum->remainder != 0)); if ((int64)sum->count != l) sum->count = -1; if (sum->count && DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "count=%s rem=%ld blength=%ld s2length=%d flength=%s\n", big_num(sum->count), (long)sum->remainder, (long)sum->blength, sum->s2length, big_num(sum->flength)); } } /* * Generate and send a stream of signatures/checksums that describe a buffer * * Generate approximately one checksum every block_len bytes. */ static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy) { int32 i; struct map_struct *mapbuf; struct sum_struct sum; OFF_T offset = 0; sum_sizes_sqroot(&sum, len); if (sum.count < 0) return -1; write_sum_head(f_out, &sum); if (append_mode > 0 && f_copy < 0) return 0; if (len > 0) mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength); else mapbuf = NULL; for (i = 0; i < sum.count; i++) { int32 n1 = (int32)MIN(len, (OFF_T)sum.blength); char *map = map_ptr(mapbuf, offset, n1); char sum2[SUM_LENGTH]; uint32 sum1; len -= n1; offset += n1; if (f_copy >= 0) { full_write(f_copy, map, n1); if (append_mode > 0) continue; } sum1 = get_checksum1(map, n1); get_checksum2(map, n1, sum2); if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "chunk[%s] offset=%s len=%ld sum1=%08lx\n", big_num(i), big_num(offset - n1), (long)n1, (unsigned long)sum1); } write_int(f_out, sum1); write_buf(f_out, sum2, sum.s2length); } if (mapbuf) unmap_file(mapbuf); return 0; } /* Try to find a filename in the same dir as "fname" with a similar name. */ static struct file_struct *find_fuzzy(struct file_struct *file, struct file_list *dirlist_array[], uchar *fnamecmp_type_ptr) { int fname_len, fname_suf_len; const char *fname_suf, *fname = file->basename; uint32 lowest_dist = 25 << 16; /* ignore a distance greater than 25 */ int i, j; struct file_struct *lowest_fp = NULL; fname_len = strlen(fname); fname_suf = find_filename_suffix(fname, fname_len, &fname_suf_len); /* Try to find an exact size+mtime match first. */ for (i = 0; i < fuzzy_basis; i++) { struct file_list *dirlist = dirlist_array[i]; if (!dirlist) continue; for (j = 0; j < dirlist->used; j++) { struct file_struct *fp = dirlist->files[j]; if (!F_IS_ACTIVE(fp)) continue; if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT) continue; if (F_LENGTH(fp) == F_LENGTH(file) && same_time(fp->modtime, 0, file->modtime, 0)) { if (DEBUG_GTE(FUZZY, 2)) rprintf(FINFO, "fuzzy size/modtime match for %s\n", f_name(fp, NULL)); *fnamecmp_type_ptr = FNAMECMP_FUZZY + i; return fp; } } } for (i = 0; i < fuzzy_basis; i++) { struct file_list *dirlist = dirlist_array[i]; if (!dirlist) continue; for (j = 0; j < dirlist->used; j++) { struct file_struct *fp = dirlist->files[j]; const char *suf, *name; int len, suf_len; uint32 dist; if (!F_IS_ACTIVE(fp)) continue; if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT) continue; name = fp->basename; len = strlen(name); suf = find_filename_suffix(name, len, &suf_len); dist = fuzzy_distance(name, len, fname, fname_len, lowest_dist); /* Add some extra weight to how well the suffixes match unless we've already disqualified * this file based on a heuristic. */ if (dist < 0xFFFF0000U) { dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len, 0xFFFF0000U) * 10; } if (DEBUG_GTE(FUZZY, 2)) { rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n", f_name(fp, NULL), (int)(dist>>16), (int)(dist&0xFFFF)); } if (dist <= lowest_dist) { lowest_dist = dist; lowest_fp = fp; *fnamecmp_type_ptr = FNAMECMP_FUZZY + i; } } } return lowest_fp; } /* Copy a file found in our --copy-dest handling. */ static int copy_altdest_file(const char *src, const char *dest, struct file_struct *file) { char buf[MAXPATHLEN]; const char *copy_to, *partialptr; int save_preserve_xattrs = preserve_xattrs; int ok, fd_w; if (inplace) { /* Let copy_file open the destination in place. */ fd_w = -1; copy_to = dest; } else { fd_w = open_tmpfile(buf, dest, file); if (fd_w < 0) return -1; copy_to = buf; } cleanup_set(copy_to, NULL, NULL, -1, -1); if (copy_file(src, copy_to, fd_w, file->mode) < 0) { if (INFO_GTE(COPY, 1)) { rsyserr(FINFO, errno, "copy_file %s => %s", full_fname(src), copy_to); } /* Try to clean up. */ unlink(copy_to); cleanup_disable(); return -1; } partialptr = partial_dir ? partial_dir_fname(dest) : NULL; preserve_xattrs = 0; /* xattrs were copied with file */ ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0); preserve_xattrs = save_preserve_xattrs; cleanup_disable(); return ok ? 0 : -1; } /* This is only called for regular files. We return -2 if we've finished * handling the file, -1 if no dest-linking occurred, or a non-negative * value if we found an alternate basis file. If we're called with the * find_exact_for_existing flag, the destination file already exists, so * we only try to find an exact alt-dest match. In this case, the returns * are only -2 & -1 (both as above). */ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, char *cmpbuf, stat_x *sxp, int find_exact_for_existing, int itemizing, enum logcode code) { STRUCT_STAT real_st = sxp->st; int best_match = -1; int match_level = 0; int j = 0; do { pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode)) continue; if (match_level == 0) { best_match = j; match_level = 1; } if (!quick_check_ok(FT_REG, cmpbuf, file, &sxp->st)) continue; if (match_level == 1) { best_match = j; match_level = 2; } if (unchanged_attrs(cmpbuf, file, sxp)) { best_match = j; match_level = 3; break; } free_stat_x(sxp); } while (basis_dir[++j] != NULL); if (!match_level) goto got_nothing_for_ya; if (j != best_match) { j = best_match; pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) goto got_nothing_for_ya; } if (match_level == 3 && alt_dest_type != COPY_DEST) { if (find_exact_for_existing) { if (alt_dest_type == LINK_DEST && real_st.st_dev == sxp->st.st_dev && real_st.st_ino == sxp->st.st_ino) return -1; if (do_unlink(fname) < 0 && errno != ENOENT) goto got_nothing_for_ya; } #ifdef SUPPORT_HARD_LINKS if (alt_dest_type == LINK_DEST) { if (!hard_link_one(file, fname, cmpbuf, 1)) goto try_a_copy; if (atimes_ndx) set_file_attrs(fname, file, sxp, NULL, 0); if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j); if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) { itemize(cmpbuf, file, ndx, 1, sxp, ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, ""); } } else #endif { if (itemizing) itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL); } if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); return -2; } if (find_exact_for_existing) goto got_nothing_for_ya; if (match_level >= 2) { #ifdef SUPPORT_HARD_LINKS try_a_copy: /* Copy the file locally. */ #endif if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0) { if (find_exact_for_existing) /* Can get here via hard-link failure */ goto got_nothing_for_ya; return -1; } if (itemizing) itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL); if (maybe_ATTRS_REPORT && ((!itemizing && INFO_GTE(NAME, 1) && match_level == 2) || (INFO_GTE(NAME, 2) && match_level == 3))) { code = match_level == 3 ? FCLIENT : FINFO; rprintf(code, "%s%s\n", fname, match_level == 3 ? " is uptodate" : ""); } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, -1); #endif return -2; } return FNAMECMP_BASIS_DIR_LOW + j; got_nothing_for_ya: sxp->st = real_st; return -1; } /* This is only called for non-regular files. We return -2 if we've finished * handling the file, or -1 if no dest-linking occurred, or a non-negative * value if we found an alternate basis file. */ static int try_dests_non(struct file_struct *file, char *fname, int ndx, char *cmpbuf, stat_x *sxp, int itemizing, enum logcode code) { int best_match = -1; int match_level = 0; enum filetype ftype = get_file_type(file->mode); int j = 0; #ifndef SUPPORT_LINKS if (ftype == FT_SYMLINK) return -1; #endif if (ftype == FT_REG || ftype == FT_UNSUPPORTED) { rprintf(FERROR, "internal: try_dests_non() called with invalid mode (%o)\n", (int)file->mode); exit_cleanup(RERR_UNSUPPORTED); } do { pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) continue; if (ftype != get_file_type(sxp->st.st_mode)) continue; if (match_level < 1) { match_level = 1; best_match = j; } if (!quick_check_ok(ftype, cmpbuf, file, &sxp->st)) continue; if (match_level < 2) { match_level = 2; best_match = j; } if (unchanged_attrs(cmpbuf, file, sxp)) { match_level = 3; best_match = j; break; } } while (basis_dir[++j] != NULL); if (!match_level) return -1; if (j != best_match) { j = best_match; pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) return -1; } if (match_level == 3) { #ifdef SUPPORT_HARD_LINKS if (alt_dest_type == LINK_DEST #ifndef CAN_HARDLINK_SYMLINK && !S_ISLNK(file->mode) #endif #ifndef CAN_HARDLINK_SPECIAL && !IS_SPECIAL(file->mode) && !IS_DEVICE(file->mode) #endif && !S_ISDIR(file->mode)) { if (do_link(cmpbuf, fname) < 0) { rsyserr(FERROR_XFER, errno, "failed to hard-link %s with %s", cmpbuf, fname); return j; } if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1); } else #endif match_level = 2; if (itemizing && stdout_format_has_i && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) { int chg = alt_dest_type == COMPARE_DEST && ftype != FT_DIR ? 0 : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0); char *lp = match_level == 3 ? "" : NULL; itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp); } if (INFO_GTE(NAME, 2) && maybe_ATTRS_REPORT) { rprintf(FCLIENT, "%s%s is uptodate\n", fname, ftype == FT_DIR ? "/" : ""); } return -2; } return j; } static void list_file_entry(struct file_struct *f) { char permbuf[PERMSTRING_SIZE]; const char *mtime_str = timestring(f->modtime); int size_width = human_readable ? 14 : 11; int mtime_width = 1 + strlen(mtime_str); int atime_width = atimes_ndx ? mtime_width : 0; int crtime_width = crtimes_ndx ? mtime_width : 0; if (!F_IS_ACTIVE(f)) { /* this can happen if duplicate names were removed */ return; } /* TODO: indicate '+' if the entry has an ACL. */ if (missing_args == 2 && f->mode == 0) { rprintf(FINFO, "%-*s %s\n", 10 + 1 + size_width + mtime_width + atime_width + crtime_width, "*missing", f_name(f, NULL)); } else { const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : ""; const char *crtime_str = crtimes_ndx ? timestring(F_CRTIME(f)) : ""; const char *arrow, *lnk; permstring(permbuf, f->mode); #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(f->mode)) { arrow = " -> "; lnk = F_SYMLINK(f); } else #endif arrow = lnk = ""; rprintf(FINFO, "%s %*s %s%*s%*s %s%s%s\n", permbuf, size_width, human_num(F_LENGTH(f)), timestring(f->modtime), atime_width, atime_str, crtime_width, crtime_str, f_name(f, NULL), arrow, lnk); } } static int phase = 0; static int dflt_perms; static int implied_dirs_are_missing; /* Helper for recv_generator's skip_dir and dry_missing_dir tests. */ static BOOL is_below(struct file_struct *file, struct file_struct *subtree) { return F_DEPTH(file) > F_DEPTH(subtree) && (!implied_dirs_are_missing || f_name_has_prefix(file, subtree)); } /* Acts on the indicated item in cur_flist whose name is fname. If a dir, * make sure it exists, and has the right permissions/timestamp info. For * all other non-regular files (symlinks, etc.) we create them here. For * regular files that have changed, we try to find a basis file and then * start sending checksums. The ndx is the file's unique index value. * * The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets * passed to delete_item(), which can use it during a recursive delete.) * * Note that f_out is set to -1 when doing final directory-permission and * modification-time repair. */ static void recv_generator(char *fname, struct file_struct *file, int ndx, int itemizing, enum logcode code, int f_out) { static const char *parent_dirname = ""; static struct file_struct *prior_dir_file = NULL; /* Missing dir not created due to --dry-run; will still be scanned. */ static struct file_struct *dry_missing_dir = NULL; /* Missing dir whose contents are skipped altogether due to * --ignore-non-existing, daemon exclude, or mkdir failure. */ static struct file_struct *skip_dir = NULL; static struct file_list *fuzzy_dirlist[MAX_BASIS_DIRS+1]; static int need_fuzzy_dirlist = 0; struct file_struct *fuzzy_file = NULL; int fd = -1, f_copy = -1; stat_x sx, real_sx; STRUCT_STAT partial_st; struct file_struct *back_file = NULL; int statret, real_ret, stat_errno; char *fnamecmp, *partialptr, *backupptr = NULL; char fnamecmpbuf[MAXPATHLEN]; uchar fnamecmp_type; int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0; enum filetype stype, ftype = get_file_type(file->mode); int is_dir = ftype != FT_DIR ? 0 : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1 : 1; if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "recv_generator(%s,%d)\n", fname, ndx); if (list_only) { if (is_dir < 0 || (is_dir && !implied_dirs && file->flags & FLAG_IMPLIED_DIR)) return; list_file_entry(file); return; } maybe_ATTRS_ACCURATE_TIME = always_checksum ? ATTRS_ACCURATE_TIME : 0; if (skip_dir) { if (is_below(file, skip_dir)) { if (is_dir) file->flags |= FLAG_MISSING_DIR; #ifdef SUPPORT_HARD_LINKS else if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif return; } skip_dir = NULL; } init_stat_x(&sx); if (daemon_filter_list.head && (*fname != '.' || fname[1])) { if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) { if (is_dir < 0) return; #ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif rprintf(FERROR_XFER, "ERROR: daemon refused to receive %s \"%s\"\n", is_dir ? "directory" : "file", fname); if (is_dir) goto skipping_dir_contents; return; } } if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) { int i; parent_is_dry_missing: for (i = 0; i < fuzzy_basis; i++) { if (fuzzy_dirlist[i]) { flist_free(fuzzy_dirlist[i]); fuzzy_dirlist[i] = NULL; } } parent_dirname = ""; statret = -1; stat_errno = ENOENT; } else { const char *dn = file->dirname ? file->dirname : "."; dry_missing_dir = NULL; if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { /* Each parent dir must be in the file list or the flist data is bad. * Optimization: most of the time the parent dir will be the last dir * this function was asked to process in the file list. */ if (!inc_recurse && (*dn != '.' || dn[1]) /* Avoid an issue with --relative and the "." dir. */ && (!prior_dir_file || strcmp(dn, f_name(prior_dir_file, NULL)) != 0)) { int ok = 0, j = flist_find_name(cur_flist, dn, -1); if (j >= 0) { struct file_struct *f = cur_flist->sorted[j]; if (S_ISDIR(f->mode) || (missing_args == 2 && !file->mode && !f->mode)) ok = 1; } /* The --delete-missing-args option can actually put invalid entries into * the file list, so if that option was specified, we'll just complain about * it and allow it. */ if (!ok && missing_args == 2 && file->mode == 0 && j < 0) rprintf(FERROR, "WARNING: parent dir is absent in the file list: %s\n", dn); else if (!ok) { rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n", dn, file->basename); exit_cleanup(RERR_PROTOCOL); } } if (relative_paths && !implied_dirs && file->mode != 0 && do_stat(dn, &sx.st) < 0) { if (dry_run) goto parent_is_dry_missing; if (make_path(fname, MKP_DROP_NAME | MKP_SKIP_SLASH) < 0) { rsyserr(FERROR_XFER, errno, "recv_generator: mkdir %s failed", full_fname(dn)); } } if (fuzzy_basis) { int i; for (i = 0; i < fuzzy_basis; i++) { if (fuzzy_dirlist[i]) { flist_free(fuzzy_dirlist[i]); fuzzy_dirlist[i] = NULL; } } need_fuzzy_dirlist = 1; } #ifdef SUPPORT_ACLS if (!preserve_perms) dflt_perms = default_perms_for_dir(dn); #endif } parent_dirname = dn; statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); stat_errno = errno; } if (missing_args == 2 && file->mode == 0) { if (filter_list.head && check_filter(&filter_list, FINFO, fname, is_dir) < 0) return; if (statret == 0) delete_item(fname, sx.st.st_mode, del_opts); return; } if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) { if (is_dir) { if (is_dir < 0) return; skip_dir = file; file->flags |= FLAG_MISSING_DIR; } #ifdef SUPPORT_HARD_LINKS else if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif if (INFO_GTE(SKIP, 1)) { rprintf(FINFO, "not creating new %s \"%s\"\n", is_dir ? "directory" : "file", fname); } return; } if (statret == 0 && !(sx.st.st_mode & S_IWUSR) && !am_root && sx.st.st_uid == our_uid) del_opts |= DEL_NO_UID_WRITE; if (statret == 0) stype = get_file_type(sx.st.st_mode); else stype = FT_UNSUPPORTED; if (ignore_existing > 0 && statret == 0 && (!is_dir || stype != FT_DIR)) { if (INFO_GTE(SKIP, 1) && is_dir >= 0) { const char *suf = ""; if (INFO_GTE(SKIP, 2)) { if (ftype != stype) suf = " (type change)"; else if (!quick_check_ok(ftype, fname, file, &sx.st)) suf = always_checksum ? " (sum change)" : " (file change)"; else if (!unchanged_attrs(fname, file, &sx)) suf = " (attr change)"; else suf = " (uptodate)"; } rprintf(FINFO, "%s exists%s\n", fname, suf); } #ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif goto cleanup; } fnamecmp = fname; if (is_dir) { mode_t added_perms; if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR) goto cleanup; if (am_root < 0) { /* For --fake-super, the dir must be useable by the copying * user, just like it would be for root. */ added_perms = S_IRUSR|S_IWUSR|S_IXUSR; } else added_perms = 0; if (is_dir < 0) { if (!preserve_mtimes || omit_dir_times) goto cleanup; /* In inc_recurse mode we want to make sure any missing * directories get created while we're still processing * the parent dir (which allows us to touch the parent * dir's mtime right away). We will handle the dir in * full later (right before we handle its contents). */ if (statret == 0 && (stype == FT_DIR || delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0)) goto cleanup; /* Any errors get reported later. */ if (do_mkdir(fname, (file->mode|added_perms) & 0700) == 0) file->flags |= FLAG_DIR_CREATED; goto cleanup; } /* The file to be received is a directory, so we need * to prepare appropriately. If there is already a * file of that name and it is *not* a directory, then * we need to delete it. If it doesn't exist, then * (perhaps recursively) create it. */ if (statret == 0 && stype != FT_DIR) { if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_DIR) != 0) goto skipping_dir_contents; statret = -1; } if (dry_run && statret != 0) { if (!dry_missing_dir) dry_missing_dir = file; file->flags |= FLAG_MISSING_DIR; } init_stat_x(&real_sx); real_sx.st = sx.st; real_ret = statret; if (file->flags & FLAG_DIR_CREATED) statret = -1; if (!preserve_perms) { /* See comment in non-dir code below. */ file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, statret == 0); } if (statret != 0 && basis_dir[0] != NULL) { int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code); if (j == -2) { itemizing = 0; code = FNONE; statret = 1; } else if (j >= 0) { statret = 1; fnamecmp = fnamecmpbuf; } } if (itemizing && f_out != -1) { itemize(fnamecmp, file, ndx, statret, &sx, statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL); } if (real_ret != 0 && do_mkdir(fname,file->mode|added_perms) < 0 && errno != EEXIST) { if (!relative_paths || errno != ENOENT || make_path(fname, MKP_DROP_NAME | MKP_SKIP_SLASH) < 0 || (do_mkdir(fname, file->mode|added_perms) < 0 && errno != EEXIST)) { rsyserr(FERROR_XFER, errno, "recv_generator: mkdir %s failed", full_fname(fname)); skipping_dir_contents: rprintf(FERROR, "*** Skipping any contents from this failed directory ***\n"); skip_dir = file; file->flags |= FLAG_MISSING_DIR; 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 both * readable and writable permissions during the time we are * putting files within them. This is then restored to the * former permissions after the transfer is done. */ #ifdef HAVE_CHMOD if (!am_root && (file->mode & S_IRWXU) != S_IRWXU && dir_tweaking) { mode_t mode = file->mode | S_IRWXU; if (do_chmod(fname, mode) < 0) { rsyserr(FERROR_XFER, errno, "failed to modify permissions on %s", full_fname(fname)); } need_retouch_dir_perms = 1; } #endif if (real_ret != 0 && one_file_system) real_sx.st.st_dev = filesystem_dev; if (inc_recurse) { if (one_file_system) { uint32 *devp = F_DIR_DEV_P(file); DEV_MAJOR(devp) = major(real_sx.st.st_dev); DEV_MINOR(devp) = minor(real_sx.st.st_dev); } } else if (delete_during && f_out != -1 && !phase && !(file->flags & FLAG_MISSING_DIR)) { if (file->flags & FLAG_CONTENT_DIR) delete_in_dir(fname, file, real_sx.st.st_dev); else change_local_filter_dir(fname, strlen(fname), F_DEPTH(file)); } prior_dir_file = file; goto cleanup; } /* If we're not preserving permissions, change the file-list's * mode based on the local permissions and some heuristics. */ if (!preserve_perms) { int exists = statret == 0 && stype != FT_DIR; file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms, exists); } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_HLINK_NOT_FIRST(file) && hard_link_check(file, ndx, fname, statret, &sx, itemizing, code)) goto cleanup; #endif if (preserve_links && ftype == FT_SYMLINK) { #ifdef SUPPORT_LINKS const char *sl = F_SYMLINK(file); if (safe_symlinks && unsafe_symlink(sl, fname)) { if (INFO_GTE(NAME, 1)) { if (solo_file) { /* fname contains the destination path, but we * want to report the source path. */ fname = f_name(file, NULL); } rprintf(FINFO, "ignoring unsafe symlink \"%s\" -> \"%s\"\n", fname, sl); } goto cleanup; } if (statret == 0) { if (stype == FT_SYMLINK && quick_check_ok(stype, fname, file, &sx.st)) { /* The link is pointing to the right place. */ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1); #endif if (remove_source_files == 1) goto return_with_success; goto cleanup; } } else if (basis_dir[0] != NULL) { int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code); if (j == -2) { #ifndef CAN_HARDLINK_SYMLINK if (alt_dest_type == LINK_DEST) { /* Resort to --copy-dest behavior. */ } else #endif if (alt_dest_type != COPY_DEST) goto cleanup; itemizing = 0; code = FNONE; } else if (j >= 0) { statret = 1; fnamecmp = fnamecmpbuf; } } if (atomic_create(file, fname, sl, NULL, MAKEDEV(0, 0), &sx, statret == 0 ? DEL_FOR_SYMLINK : 0)) { set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { if (statret == 0 && stype != FT_SYMLINK) statret = -1; itemize(fnamecmp, file, ndx, statret, &sx, ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL); } if (code != FNONE && INFO_GTE(NAME, 1)) rprintf(code, "%s -> %s\n", fname, sl); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1); #endif /* This does not check remove_source_files == 1 * because this is one of the items that the old * --remove-sent-files option would remove. */ if (remove_source_files) goto return_with_success; } #endif goto cleanup; } if ((am_root && preserve_devices && ftype == FT_DEVICE) || (preserve_specials && ftype == FT_SPECIAL)) { dev_t rdev; int del_for_flag; if (ftype == FT_DEVICE) { uint32 *devp = F_RDEV_P(file); rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); del_for_flag = DEL_FOR_DEVICE; } else { rdev = 0; del_for_flag = DEL_FOR_SPECIAL; } if (statret == 0) { if (ftype != stype) statret = -1; else if (quick_check_ok(ftype, fname, file, &sx.st)) { /* The device or special file is identical. */ set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1); #endif if (remove_source_files == 1) goto return_with_success; goto cleanup; } } else if (basis_dir[0] != NULL) { int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx, itemizing, code); if (j == -2) { #ifndef CAN_HARDLINK_SPECIAL if (alt_dest_type == LINK_DEST) { /* Resort to --copy-dest behavior. */ } else #endif if (alt_dest_type != COPY_DEST) goto cleanup; itemizing = 0; code = FNONE; } else if (j >= 0) { statret = 1; fnamecmp = fnamecmpbuf; } } if (DEBUG_GTE(GENR, 1)) { rprintf(FINFO, "mknod(%s, 0%o, [%ld,%ld])\n", fname, (int)file->mode, (long)major(rdev), (long)minor(rdev)); } if (atomic_create(file, fname, NULL, NULL, rdev, &sx, del_for_flag)) { set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { itemize(fnamecmp, file, ndx, statret, &sx, ITEM_LOCAL_CHANGE|ITEM_REPORT_CHANGE, 0, NULL); } if (code != FNONE && INFO_GTE(NAME, 1)) rprintf(code, "%s\n", fname); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1); #endif if (remove_source_files == 1) goto return_with_success; } goto cleanup; } if (ftype != FT_REG) { if (INFO_GTE(NONREG, 1)) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname); } goto cleanup; } if (max_size >= 0 && F_LENGTH(file) > max_size) { if (INFO_GTE(SKIP, 1)) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "%s is over max-size\n", fname); } goto cleanup; } if (min_size >= 0 && F_LENGTH(file) < min_size) { if (INFO_GTE(SKIP, 1)) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "%s is under min-size\n", fname); } goto cleanup; } if (update_only > 0 && statret == 0 && file->modtime - sx.st.st_mtime < modify_window) { if (INFO_GTE(SKIP, 1)) rprintf(FINFO, "%s is newer\n", fname); #ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif goto cleanup; } fnamecmp_type = FNAMECMP_FNAME; if (statret == 0 && !(stype == FT_REG || (write_devices && stype == FT_DEVICE))) { if (delete_item(fname, sx.st.st_mode, del_opts | DEL_FOR_FILE) != 0) goto cleanup; statret = -1; stat_errno = ENOENT; } if (basis_dir[0] != NULL && (statret != 0 || alt_dest_type != COPY_DEST)) { int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx, statret == 0, itemizing, code); if (j == -2) { if (remove_source_files == 1) goto return_with_success; goto cleanup; } if (j >= 0) { fnamecmp = fnamecmpbuf; fnamecmp_type = j; statret = 0; } } init_stat_x(&real_sx); real_sx.st = sx.st; /* Don't copy xattr/acl pointers, as they would free wrong. */ real_ret = statret; if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL && link_stat(partialptr, &partial_st, 0) == 0 && S_ISREG(partial_st.st_mode)) { if (statret != 0) goto prepare_to_open; } else partialptr = NULL; if (statret != 0 && fuzzy_basis) { if (need_fuzzy_dirlist) { const char *dn = file->dirname ? file->dirname : "."; int i; strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf); for (i = 0; i < fuzzy_basis; i++) { if (i && pathjoin(fnamecmpbuf, MAXPATHLEN, basis_dir[i-1], dn) >= MAXPATHLEN) continue; fuzzy_dirlist[i] = get_dirlist(fnamecmpbuf, -1, GDL_IGNORE_FILTER_RULES | GDL_PERHAPS_DIR); if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) { flist_free(fuzzy_dirlist[i]); fuzzy_dirlist[i] = NULL; } } need_fuzzy_dirlist = 0; } /* Sets fnamecmp_type to FNAMECMP_FUZZY or above. */ fuzzy_file = find_fuzzy(file, fuzzy_dirlist, &fnamecmp_type); if (fuzzy_file) { f_name(fuzzy_file, fnamecmpbuf); if (DEBUG_GTE(FUZZY, 1)) { rprintf(FINFO, "fuzzy basis selected for %s: %s\n", fname, fnamecmpbuf); } sx.st.st_size = F_LENGTH(fuzzy_file); statret = 0; fnamecmp = fnamecmpbuf; } } if (statret != 0) { #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_HLINK_NOT_LAST(file)) { cur_flist->in_progress++; goto cleanup; } #endif if (stat_errno == ENOENT) goto notify_others; rsyserr(FERROR_XFER, stat_errno, "recv_generator: failed to stat %s", full_fname(fname)); goto cleanup; } if (write_devices && IS_DEVICE(sx.st.st_mode) && sx.st.st_size == 0) { /* This early open into fd skips the regular open below. */ if ((fd = do_open(fnamecmp, O_RDONLY, 0)) >= 0) real_sx.st.st_size = sx.st.st_size = get_device_size(fd, fnamecmp); } if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH) ; else if (fnamecmp_type >= FNAMECMP_FUZZY) ; else if (quick_check_ok(FT_REG, fnamecmp, file, &sx.st)) { if (partialptr) { do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); } set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT | maybe_ATTRS_ACCURATE_TIME); if (itemizing) itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1); #endif if (remove_source_files != 1) goto cleanup; return_with_success: if (!dry_run) send_msg_success(fname, ndx); goto cleanup; } if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) { #ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif goto cleanup; } prepare_to_open: if (partialptr) { sx.st = partial_st; fnamecmp = partialptr; fnamecmp_type = FNAMECMP_PARTIAL_DIR; statret = 0; } if (!do_xfers) goto notify_others; if (read_batch || whole_file) { if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { if (!(backupptr = get_backup_name(fname))) goto cleanup; if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) goto pretend_missing; if (copy_file(fname, backupptr, -1, back_file->mode) < 0) { unmake_file(back_file); back_file = NULL; goto cleanup; } } goto notify_others; } if (fuzzy_dirlist[0]) { int j = flist_find(fuzzy_dirlist[0], file); if (j >= 0) /* don't use changing file as future fuzzy basis */ fuzzy_dirlist[0]->files[j]->flags |= FLAG_FILE_SENT; } /* open the file */ if (fd < 0 && (fd = do_open(fnamecmp, O_RDONLY, 0)) < 0) { rsyserr(FERROR, errno, "failed to open %s, continuing", full_fname(fnamecmp)); pretend_missing: /* pretend the file didn't exist */ #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_HLINK_NOT_LAST(file)) { cur_flist->in_progress++; goto cleanup; } #endif statret = real_ret = -1; goto notify_others; } if (inplace && make_backups > 0 && fnamecmp_type == FNAMECMP_FNAME) { if (!(backupptr = get_backup_name(fname))) { goto cleanup; } if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) { goto pretend_missing; } if (robust_unlink(backupptr) && errno != ENOENT) { rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(backupptr)); unmake_file(back_file); back_file = NULL; goto cleanup; } if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) { rsyserr(FERROR_XFER, errno, "open %s", full_fname(backupptr)); unmake_file(back_file); back_file = NULL; goto cleanup; } fnamecmp_type = FNAMECMP_BACKUP; } if (DEBUG_GTE(DELTASUM, 3)) { rprintf(FINFO, "gen mapped %s of size %s\n", fnamecmp, big_num(sx.st.st_size)); } if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO, "generating and sending sums for %d\n", ndx); notify_others: if (remove_source_files && !delay_updates && !phase && !dry_run) increment_active_files(ndx, itemizing, code); if (inc_recurse && (!dry_run || write_batch < 0)) cur_flist->in_progress++; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) file->flags |= FLAG_FILE_SENT; #endif write_ndx(f_out, ndx); if (itemizing) { int iflags = ITEM_TRANSFER; if (always_checksum > 0) iflags |= ITEM_REPORT_CHANGE; if (fnamecmp_type != FNAMECMP_FNAME) iflags |= ITEM_BASIS_TYPE_FOLLOWS; if (fnamecmp_type >= FNAMECMP_FUZZY) iflags |= ITEM_XNAME_FOLLOWS; itemize(fnamecmp, file, -1, real_ret, &real_sx, iflags, fnamecmp_type, fuzzy_file ? fuzzy_file->basename : NULL); free_stat_x(&real_sx); } if (!do_xfers) { #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sx.st, itemizing, code, -1); #endif goto cleanup; } if (read_batch) goto cleanup; if (statret != 0 || whole_file) write_sum_head(f_out, NULL); else if (sx.st.st_size <= 0) { write_sum_head(f_out, NULL); } else { if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) { rprintf(FWARNING, "WARNING: file is too large for checksum sending: %s\n", fnamecmp); write_sum_head(f_out, NULL); } } cleanup: if (fd >= 0) close(fd); if (back_file) { int save_preserve_xattrs = preserve_xattrs; if (f_copy >= 0) close(f_copy); #ifdef SUPPORT_XATTRS if (preserve_xattrs) { copy_xattrs(fname, backupptr); preserve_xattrs = 0; } #endif set_file_attrs(backupptr, back_file, NULL, NULL, 0); preserve_xattrs = save_preserve_xattrs; if (INFO_GTE(BACKUP, 1)) { rprintf(FINFO, "backed up %s to %s\n", fname, backupptr); } unmake_file(back_file); } free_stat_x(&sx); } /* If we are replacing an existing hard link, symlink, device, or special file, * create a temp-name item and rename it into place. A symlimk specifies slnk, * a hard link specifies hlnk, otherwise we create a device based on rdev. * Specify 0 for the del_for_flag if there is not a file to replace. This * returns 1 on success and 0 on failure. */ int atomic_create(struct file_struct *file, char *fname, const char *slnk, const char *hlnk, dev_t rdev, stat_x *sxp, int del_for_flag) { char tmpname[MAXPATHLEN]; const char *create_name; int skip_atomic, dir_in_the_way = del_for_flag && S_ISDIR(sxp->st.st_mode); if (!del_for_flag || dir_in_the_way || tmpdir || !get_tmpname(tmpname, fname, True)) skip_atomic = 1; else skip_atomic = 0; if (del_for_flag) { if (make_backups > 0 && !dir_in_the_way) { if (!make_backup(fname, skip_atomic)) return 0; } else if (skip_atomic) { int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0; if (delete_item(fname, sxp->st.st_mode, del_opts | del_for_flag) != 0) return 0; } } create_name = skip_atomic ? fname : tmpname; if (slnk) { #ifdef SUPPORT_LINKS if (do_symlink(slnk, create_name) < 0) { rsyserr(FERROR_XFER, errno, "symlink %s -> \"%s\" failed", full_fname(create_name), slnk); return 0; } #else return 0; #endif } else if (hlnk) { #ifdef SUPPORT_HARD_LINKS if (!hard_link_one(file, create_name, hlnk, 0)) return 0; #else return 0; #endif } else { if (do_mknod(create_name, file->mode, rdev) < 0) { rsyserr(FERROR_XFER, errno, "mknod %s failed", full_fname(create_name)); return 0; } } if (!skip_atomic) { if (do_rename(tmpname, fname) < 0) { rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\" failed", full_fname(tmpname), full_fname(fname)); do_unlink(tmpname); return 0; } } return 1; } #ifdef SUPPORT_HARD_LINKS static void handle_skipped_hlink(struct file_struct *file, int itemizing, enum logcode code, int f_out) { char fbuf[MAXPATHLEN]; int new_last_ndx; struct file_list *save_flist = cur_flist; /* If we skip the last item in a chain of links and there was a * prior non-skipped hard-link waiting to finish, finish it now. */ if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0) return; file = cur_flist->files[new_last_ndx - cur_flist->ndx_start]; cur_flist->in_progress--; /* undo prior increment */ f_name(file, fbuf); recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out); cur_flist = save_flist; } #endif static void touch_up_dirs(struct file_list *flist, int ndx) { static int counter = 0; struct file_struct *file; char *fname; BOOL fix_dir_perms; int i, start, end; if (ndx < 0) { start = 0; end = flist->used - 1; } else start = end = ndx; /* Fix any directory permissions that were modified during the * transfer and/or re-set any tweaked modified-time values. */ for (i = start; i <= end; i++, counter++) { file = flist->files[i]; if (!F_IS_ACTIVE(file)) continue; if (!S_ISDIR(file->mode) || (!implied_dirs && file->flags & FLAG_IMPLIED_DIR)) continue; if (DEBUG_GTE(TIME, 2)) { fname = f_name(file, NULL); rprintf(FINFO, "touch_up_dirs: %s (%d)\n", NS(fname), i); } /* Be sure not to retouch permissions with --fake-super. */ fix_dir_perms = !am_root && !(file->mode & S_IWUSR); if (file->flags & FLAG_MISSING_DIR || !(need_retouch_dir_times || fix_dir_perms)) continue; fname = f_name(file, NULL); if (fix_dir_perms) do_chmod(fname, file->mode); if (need_retouch_dir_times) { STRUCT_STAT st; if (link_stat(fname, &st, 0) == 0 && mtime_differs(&st, file)) { st.st_mtime = file->modtime; #ifdef ST_MTIME_NSEC st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file); #endif set_times(fname, &st); } } if (counter >= loopchk_limit) { if (allowed_lull) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); else maybe_flush_socket(0); counter = 0; } } } void check_for_finished_files(int itemizing, enum logcode code, int check_redo) { struct file_struct *file; struct file_list *flist; char fbuf[MAXPATHLEN]; int ndx; while (1) { #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && (ndx = get_hlink_num()) != -1) { int send_failed = (ndx == -2); if (send_failed) ndx = get_hlink_num(); flist = flist_for_ndx(ndx, "check_for_finished_files.1"); file = flist->files[ndx - flist->ndx_start]; assert(file->flags & FLAG_HLINKED); if (send_failed) handle_skipped_hlink(file, itemizing, code, sock_f_out); else finish_hard_link(file, f_name(file, fbuf), ndx, NULL, itemizing, code, -1); flist->in_progress--; continue; } #endif if (check_redo && (ndx = get_redo_num()) != -1) { OFF_T save_max_size = max_size; OFF_T save_min_size = min_size; csum_length = SUM_LENGTH; max_size = -1; min_size = -1; ignore_existing = -ignore_existing; ignore_non_existing = -ignore_non_existing; update_only = -update_only; always_checksum = -always_checksum; size_only = -size_only; append_mode = -append_mode; make_backups = -make_backups; /* avoid dup backup w/inplace */ ignore_times++; flist = cur_flist; cur_flist = flist_for_ndx(ndx, "check_for_finished_files.2"); file = cur_flist->files[ndx - cur_flist->ndx_start]; if (solo_file) strlcpy(fbuf, solo_file, sizeof fbuf); else f_name(file, fbuf); recv_generator(fbuf, file, ndx, itemizing, code, sock_f_out); cur_flist->to_redo--; cur_flist = flist; csum_length = SHORT_SUM_LENGTH; max_size = save_max_size; min_size = save_min_size; ignore_existing = -ignore_existing; ignore_non_existing = -ignore_non_existing; update_only = -update_only; always_checksum = -always_checksum; size_only = -size_only; append_mode = -append_mode; make_backups = -make_backups; ignore_times--; continue; } if (cur_flist == first_flist) break; /* We only get here if inc_recurse is enabled. */ if (first_flist->in_progress || first_flist->to_redo) break; write_ndx(sock_f_out, NDX_DONE); if (!read_batch && !flist_eof) { int old_total = 0; for (flist = first_flist; flist != cur_flist; flist = flist->next) old_total += flist->used; maybe_flush_socket(!flist_eof && file_total - old_total < MIN_FILECNT_LOOKAHEAD/2); } if (delete_during == 2 || !dir_tweaking) { /* Skip directory touch-up. */ } else if (first_flist->parent_ndx >= 0) touch_up_dirs(dir_flist, first_flist->parent_ndx); flist_free(first_flist); /* updates first_flist */ } } void generate_files(int f_out, const char *local_name) { int i, ndx, next_loopchk = 0; char fbuf[MAXPATHLEN]; int itemizing; enum logcode code; int save_info_flist = info_levels[INFO_FLIST]; int save_info_progress = info_levels[INFO_PROGRESS]; if (protocol_version >= 29) { itemizing = 1; maybe_ATTRS_REPORT = stdout_format_has_i ? 0 : ATTRS_REPORT; code = logfile_format_has_i ? FNONE : FLOG; } else if (am_daemon) { itemizing = logfile_format_has_i && do_xfers; maybe_ATTRS_REPORT = ATTRS_REPORT; code = itemizing || !do_xfers ? FCLIENT : FINFO; } else if (!am_server) { itemizing = stdout_format_has_i; maybe_ATTRS_REPORT = stdout_format_has_i ? 0 : ATTRS_REPORT; code = itemizing ? FNONE : FINFO; } else { itemizing = 0; maybe_ATTRS_REPORT = ATTRS_REPORT; code = FINFO; } solo_file = local_name; dir_tweaking = !(list_only || solo_file || dry_run); need_retouch_dir_times = preserve_mtimes && !omit_dir_times; loopchk_limit = allowed_lull ? allowed_lull * 5 : 200; symlink_timeset_failed_flags = ITEM_REPORT_TIME | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0); implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30; if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "generator starting pid=%d\n", (int)getpid()); if (delete_before && !solo_file && cur_flist->used > 0) do_delete_pass(); if (delete_during == 2) { deldelay_size = BIGPATHBUFLEN * 4; deldelay_buf = new_array(char, deldelay_size); } info_levels[INFO_FLIST] = info_levels[INFO_PROGRESS] = 0; if (append_mode > 0 || whole_file < 0) whole_file = 0; if (DEBUG_GTE(FLIST, 1)) { rprintf(FINFO, "delta-transmission %s\n", whole_file ? "disabled for local transfer or --whole-file" : "enabled"); } dflt_perms = (ACCESSPERMS & ~orig_umask); do { #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && inc_recurse) { while (!flist_eof && file_total < MIN_FILECNT_LOOKAHEAD/2) wait_for_receiver(); } #endif if (inc_recurse && cur_flist->parent_ndx >= 0) { struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx]; if (solo_file) strlcpy(fbuf, solo_file, sizeof fbuf); else f_name(fp, fbuf); ndx = cur_flist->ndx_start - 1; recv_generator(fbuf, fp, ndx, itemizing, code, f_out); if (delete_during && dry_run < 2 && !list_only && !(fp->flags & FLAG_MISSING_DIR)) { if (fp->flags & FLAG_CONTENT_DIR) { dev_t dirdev; if (one_file_system) { uint32 *devp = F_DIR_DEV_P(fp); dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); } else dirdev = MAKEDEV(0, 0); delete_in_dir(fbuf, fp, dirdev); } else change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(fp)); } } for (i = cur_flist->low; i <= cur_flist->high; i++) { struct file_struct *file = cur_flist->sorted[i]; if (!F_IS_ACTIVE(file)) continue; if (unsort_ndx) ndx = F_NDX(file); else ndx = i + cur_flist->ndx_start; if (solo_file) strlcpy(fbuf, solo_file, sizeof fbuf); else f_name(file, fbuf); recv_generator(fbuf, file, ndx, itemizing, code, f_out); check_for_finished_files(itemizing, code, 0); if (i + cur_flist->ndx_start >= next_loopchk) { if (allowed_lull) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); else maybe_flush_socket(0); next_loopchk += loopchk_limit; } } if (!inc_recurse) { write_ndx(f_out, NDX_DONE); break; } while (1) { check_for_finished_files(itemizing, code, 1); if (cur_flist->next || flist_eof) break; wait_for_receiver(); } } while ((cur_flist = cur_flist->next) != NULL); if (delete_during) delete_in_dir(NULL, NULL, dev_zero); phase++; if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "generate_files phase=%d\n", phase); while (1) { check_for_finished_files(itemizing, code, 1); if (msgdone_cnt) break; wait_for_receiver(); } phase++; if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "generate_files phase=%d\n", phase); write_ndx(f_out, NDX_DONE); /* Reduce round-trip lag-time for a useless delay-updates phase. */ if (protocol_version >= 29 && EARLY_DELAY_DONE_MSG()) write_ndx(f_out, NDX_DONE); if (protocol_version >= 31 && EARLY_DELETE_DONE_MSG()) { if ((INFO_GTE(STATS, 2) && (delete_mode || force_delete)) || read_batch) write_del_stats(f_out); if (EARLY_DELAY_DONE_MSG()) /* Can't send this before delay */ write_ndx(f_out, NDX_DONE); } /* Read MSG_DONE for the redo phase (and any prior messages). */ while (1) { check_for_finished_files(itemizing, code, 0); if (msgdone_cnt > 1) break; wait_for_receiver(); } if (protocol_version >= 29) { phase++; if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "generate_files phase=%d\n", phase); if (!EARLY_DELAY_DONE_MSG()) { write_ndx(f_out, NDX_DONE); if (protocol_version >= 31 && EARLY_DELETE_DONE_MSG()) write_ndx(f_out, NDX_DONE); } /* Read MSG_DONE for delay-updates phase & prior messages. */ while (msgdone_cnt == 2) wait_for_receiver(); } info_levels[INFO_FLIST] = save_info_flist; info_levels[INFO_PROGRESS] = save_info_progress; if (delete_during == 2) do_delayed_deletions(fbuf); if (delete_after && !solo_file && file_total > 0) do_delete_pass(); if (max_delete >= 0 && skipped_deletes) { rprintf(FWARNING, "Deletions stopped due to --max-delete limit (%d skipped)\n", skipped_deletes); io_error |= IOERR_DEL_LIMIT; } if (protocol_version >= 31) { if (!EARLY_DELETE_DONE_MSG()) { if (INFO_GTE(STATS, 2) || read_batch) write_del_stats(f_out); write_ndx(f_out, NDX_DONE); } /* Read MSG_DONE for late-delete phase & prior messages. */ while (msgdone_cnt == 3) wait_for_receiver(); } if ((need_retouch_dir_perms || need_retouch_dir_times) && dir_tweaking && (!inc_recurse || delete_during == 2)) touch_up_dirs(dir_flist, -1); if (DEBUG_GTE(GENR, 1)) rprintf(FINFO, "generate_files finished\n"); } rsync-3.2.7/daemon-parm.txt0000664000000000000000000000306614312263340014325 0ustar rootrootGlobals: ================================================================ STRING bind_address|address NULL STRING daemon_chroot NULL STRING daemon_gid NULL STRING daemon_uid NULL STRING motd_file NULL STRING pid_file NULL STRING socket_options NULL INTEGER listen_backlog 5 INTEGER rsync_port|port 0 BOOL proxy_protocol False Locals: ================================================================= STRING auth_users NULL STRING charset NULL STRING comment NULL STRING dont_compress DEFAULT_DONT_COMPRESS STRING early_exec NULL STRING exclude NULL STRING exclude_from NULL STRING filter NULL STRING gid NULL STRING hosts_allow NULL STRING hosts_deny NULL STRING include NULL STRING include_from NULL STRING incoming_chmod NULL STRING lock_file DEFAULT_LOCK_FILE STRING log_file NULL STRING log_format "%o %h [%a] %m (%u) %f %l" STRING name NULL STRING name_converter NULL STRING outgoing_chmod NULL STRING post-xfer_exec NULL STRING pre-xfer_exec NULL STRING refuse_options NULL STRING secrets_file NULL STRING syslog_tag "rsyncd" STRING uid NULL PATH path NULL PATH temp_dir NULL INTEGER max_connections 0 INTEGER max_verbosity 1 INTEGER timeout 0 ENUM syslog_facility LOG_DAEMON BOOL fake_super False BOOL forward_lookup True BOOL ignore_errors False BOOL ignore_nonreadable False BOOL list True BOOL read_only True BOOL reverse_lookup True BOOL strict_modes True BOOL transfer_logging False BOOL write_only False BOOL3 munge_symlinks Unset BOOL3 numeric_ids Unset BOOL3 open_noatime Unset BOOL3 use_chroot Unset rsync-3.2.7/configure.sh0000775000000000000000000132043314324367162013717 0ustar rootroot#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for rsync. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://rsync.samba.org/bug-tracking.html about your $0: system, including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='rsync' PACKAGE_TARNAME='rsync' PACKAGE_VERSION='' PACKAGE_STRING='rsync' PACKAGE_BUGREPORT='https://rsync.samba.org/bug-tracking.html' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_unique_file="byteorder.h" ac_config_libobj_dir=lib ac_subst_vars='LTLIBOBJS MAKE_MAN GEN_RRSYNC MAKE_RRSYNC_1 MAKE_RRSYNC BUILD_ZLIB BUILD_POPT CC_SHOBJ_FLAG OBJ_RESTORE OBJ_SAVE ALLOCA LIBOBJS ROLL_ASM MD5_ASM NOEXECSTACK ROLL_SIMD FAKEROOT_PATH SHELL_PATH HAVE_REMSH with_rrsync PYTHON3 PERL MKDIR_P INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM EGREP GREP AWK ac_ct_CXX CXXFLAGS CXX CPP host_os host_vendor host_cpu host build_os build_vendor build_cpu build OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug enable_profile enable_md2man enable_maintainer_mode with_openssl_conf with_rrsync with_included_popt with_included_zlib with_secluded_args with_rsync_path with_rsyncd_conf with_rsh with_nobody_user with_nobody_group enable_roll_simd enable_largefile enable_ipv6 enable_locale enable_openssl enable_md5_asm enable_roll_asm enable_xxhash enable_zstd enable_lz4 enable_iconv_open enable_iconv enable_acl_support enable_xattr_support ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures rsync to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/rsync] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of rsync:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-debug disable to omit debugging symbols and features --enable-profile enable to turn on CPU profiling --disable-md2man disable to omit manpage creation --enable-maintainer-mode enable to turn on extra debug features --enable-roll-simd enable/disable to control rolling-checksum SIMD optimizations (requires c++) --disable-largefile omit support for large files --disable-ipv6 disable to omit ipv6 support --disable-locale disable to omit locale features --disable-openssl disable to omit openssl crypto library --enable-md5-asm enable/disable to control MD5 ASM optimizations --enable-roll-asm enable/disable to control rolling-checksum ASM optimizations (requires --enable-roll-simd) --disable-xxhash disable to omit xxhash checksums --disable-zstd disable to omit zstd compression --disable-lz4 disable to omit LZ4 compression --disable-iconv-open disable to avoid all use of iconv_open() --disable-iconv disable to omit the --iconv option --disable-acl-support disable to omit ACL support --disable-xattr-support disable to omit extended attributes Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-openssl-conf=PATH set default OPENSSL_CONF path for rsync --with-rrsync also install the rrsync script and its manpage --with-included-popt use bundled popt library, not from system --with-included-zlib use bundled zlib library, not from system --with-secluded-args make --secluded-args option the default --with-rsync-path=PATH set default --rsync-path to PATH (default: rsync) --with-rsyncd-conf=PATH set configuration file for rsync server to PATH (default: /etc/rsyncd.conf) --with-rsh=CMD set remote shell command to CMD (default: ssh) --with-nobody-user=USER set the default unprivileged user (default nobody) --with-nobody-group=GROUP set the default unprivileged group (default nobody or nogroup) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF rsync configure generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_run LINENO # ------------------------ # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid; break else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=$ac_mid; break else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else $as_nop ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval (void) { return $2; } static unsigned long int ulongval (void) { return $2; } #include #include int main (void) { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : echo >>conftest.val; read $3 &5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main (void) { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" else $as_nop eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$4 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by rsync $as_me, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Test code for whether the C++ compiler supports C++98 (global declarations) ac_cxx_conftest_cxx98_globals=' // Does the compiler advertise C++98 conformance? #if !defined __cplusplus || __cplusplus < 199711L # error "Compiler does not advertise C++98 conformance" #endif // These inclusions are to reject old compilers that // lack the unsuffixed header files. #include #include // and are *not* freestanding headers in C++98. extern void assert (int); namespace std { extern int strcmp (const char *, const char *); } // Namespaces, exceptions, and templates were all added after "C++ 2.0". using std::exception; using std::strcmp; namespace { void test_exception_syntax() { try { throw "test"; } catch (const char *s) { // Extra parentheses suppress a warning when building autoconf itself, // due to lint rules shared with more typical C programs. assert (!(strcmp) (s, "test")); } } template struct test_template { T const val; explicit test_template(T t) : val(t) {} template T add(U u) { return static_cast(u) + val; } }; } // anonymous namespace ' # Test code for whether the C++ compiler supports C++98 (body of main) ac_cxx_conftest_cxx98_main=' assert (argc); assert (! argv[0]); { test_exception_syntax (); test_template tt (2.0); assert (tt.add (4) == 6.0); assert (true && !false); } ' # Test code for whether the C++ compiler supports C++11 (global declarations) ac_cxx_conftest_cxx11_globals=' // Does the compiler advertise C++ 2011 conformance? #if !defined __cplusplus || __cplusplus < 201103L # error "Compiler does not advertise C++11 conformance" #endif namespace cxx11test { constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; // for testing lambda expressions template Ret eval(Fn f, Ret v) { return f(v); } // for testing variadic templates and trailing return types template auto sum(V first) -> V { return first; } template auto sum(V first, Args... rest) -> V { return first + sum(rest...); } } ' # Test code for whether the C++ compiler supports C++11 (body of main) ac_cxx_conftest_cxx11_main=' { // Test auto and decltype auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; int total = 0; for (auto i = a3; *i; ++i) { total += *i; } decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (auto &x : array) { x += 23; } } { // Test lambda expressions using cxx11test::eval; assert (eval ([](int x) { return x*2; }, 21) == 42); double d = 2.0; assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); assert (d == 5.0); assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); assert (d == 5.0); } { // Test use of variadic templates using cxx11test::sum; auto a = sum(1); auto b = sum(1, 2); auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets test_template<::test_template> v(test_template(12)); } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ' # Test code for whether the C compiler supports C++11 (complete). ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} ${ac_cxx_conftest_cxx11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} ${ac_cxx_conftest_cxx11_main} return ok; } " # Test code for whether the C compiler supports C++98 (complete). ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} return ok; } " as_fn_append ac_header_c_list " utime.h utime_h HAVE_UTIME_H" # Auxiliary files required by this configure script. ac_aux_files="install-sh config.guess config.sub" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO" then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`printf "%s\n" "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 printf %s "checking for $ac_hdr that defines DIR... " >&6; } if eval test \${$as_ac_Header+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main (void) { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$as_ac_Header=yes" else $as_nop eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char opendir (); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else $as_nop ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 printf %s "checking for library containing opendir... " >&6; } if test ${ac_cv_search_opendir+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char opendir (); int main (void) { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_opendir+y} then : break fi done if test ${ac_cv_search_opendir+y} then : else $as_nop ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 printf "%s\n" "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test ${ac_cv_header_sys_wait_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main (void) { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_sys_wait_h=yes else $as_nop ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/fcntl.h" "ac_cv_header_sys_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes then : printf "%s\n" "#define HAVE_FCNTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/unistd.h" "ac_cv_header_sys_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_sys_unistd_h" = xyes then : printf "%s\n" "#define HAVE_SYS_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default" if test "x$ac_cv_header_utime_h" = xyes then : printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "compat.h" "ac_cv_header_compat_h" "$ac_includes_default" if test "x$ac_cv_header_compat_h" = xyes then : printf "%s\n" "#define HAVE_COMPAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "ctype.h" "ac_cv_header_ctype_h" "$ac_includes_default" if test "x$ac_cv_header_ctype_h" = xyes then : printf "%s\n" "#define HAVE_CTYPE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = xyes then : printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_stat_h" = xyes then : printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_filio_h" = xyes then : printf "%s\n" "#define HAVE_SYS_FILIO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes then : printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/mode.h" "ac_cv_header_sys_mode_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mode_h" = xyes then : printf "%s\n" "#define HAVE_SYS_MODE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default" if test "x$ac_cv_header_grp_h" = xyes then : printf "%s\n" "#define HAVE_GRP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" if test "x$ac_cv_header_sys_un_h" = xyes then : printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/attr.h" "ac_cv_header_sys_attr_h" "$ac_includes_default" if test "x$ac_cv_header_sys_attr_h" = xyes then : printf "%s\n" "#define HAVE_SYS_ATTR_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_inet_h" = xyes then : printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "arpa/nameser.h" "ac_cv_header_arpa_nameser_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_nameser_h" = xyes then : printf "%s\n" "#define HAVE_ARPA_NAMESER_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes then : printf "%s\n" "#define HAVE_LOCALE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" if test "x$ac_cv_header_malloc_h" = xyes then : printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = xyes then : printf "%s\n" "#define HAVE_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" if test "x$ac_cv_header_iconv_h" = xyes then : printf "%s\n" "#define HAVE_ICONV_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "libcharset.h" "ac_cv_header_libcharset_h" "$ac_includes_default" if test "x$ac_cv_header_libcharset_h" = xyes then : printf "%s\n" "#define HAVE_LIBCHARSET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "langinfo.h" "ac_cv_header_langinfo_h" "$ac_includes_default" if test "x$ac_cv_header_langinfo_h" = xyes then : printf "%s\n" "#define HAVE_LANGINFO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "mcheck.h" "ac_cv_header_mcheck_h" "$ac_includes_default" if test "x$ac_cv_header_mcheck_h" = xyes then : printf "%s\n" "#define HAVE_MCHECK_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/acl.h" "ac_cv_header_sys_acl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_acl_h" = xyes then : printf "%s\n" "#define HAVE_SYS_ACL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "acl/libacl.h" "ac_cv_header_acl_libacl_h" "$ac_includes_default" if test "x$ac_cv_header_acl_libacl_h" = xyes then : printf "%s\n" "#define HAVE_ACL_LIBACL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default" if test "x$ac_cv_header_attr_xattr_h" = xyes then : printf "%s\n" "#define HAVE_ATTR_XATTR_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" if test "x$ac_cv_header_sys_xattr_h" = xyes then : printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/extattr.h" "ac_cv_header_sys_extattr_h" "$ac_includes_default" if test "x$ac_cv_header_sys_extattr_h" = xyes then : printf "%s\n" "#define HAVE_SYS_EXTATTR_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "dl.h" "ac_cv_header_dl_h" "$ac_includes_default" if test "x$ac_cv_header_dl_h" = xyes then : printf "%s\n" "#define HAVE_DL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "popt.h" "ac_cv_header_popt_h" "$ac_includes_default" if test "x$ac_cv_header_popt_h" = xyes then : printf "%s\n" "#define HAVE_POPT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "popt/popt.h" "ac_cv_header_popt_popt_h" "$ac_includes_default" if test "x$ac_cv_header_popt_popt_h" = xyes then : printf "%s\n" "#define HAVE_POPT_POPT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "linux/falloc.h" "ac_cv_header_linux_falloc_h" "$ac_includes_default" if test "x$ac_cv_header_linux_falloc_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_FALLOC_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in_systm.h" "ac_cv_header_netinet_in_systm_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_in_systm_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_SYSTM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netgroup.h" "ac_cv_header_netgroup_h" "$ac_includes_default" if test "x$ac_cv_header_netgroup_h" = xyes then : printf "%s\n" "#define HAVE_NETGROUP_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes then : printf "%s\n" "#define HAVE_ZLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "xxhash.h" "ac_cv_header_xxhash_h" "$ac_includes_default" if test "x$ac_cv_header_xxhash_h" = xyes then : printf "%s\n" "#define HAVE_XXHASH_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/md4.h" "ac_cv_header_openssl_md4_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_md4_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_MD4_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "openssl/md5.h" "ac_cv_header_openssl_md5_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_md5_h" = xyes then : printf "%s\n" "#define HAVE_OPENSSL_MD5_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "zstd.h" "ac_cv_header_zstd_h" "$ac_includes_default" if test "x$ac_cv_header_zstd_h" = xyes then : printf "%s\n" "#define HAVE_ZSTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "lz4.h" "ac_cv_header_lz4_h" "$ac_includes_default" if test "x$ac_cv_header_lz4_h" = xyes then : printf "%s\n" "#define HAVE_LZ4_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/file.h" "ac_cv_header_sys_file_h" "$ac_includes_default" if test "x$ac_cv_header_sys_file_h" = xyes then : printf "%s\n" "#define HAVE_SYS_FILE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "bsd/string.h" "ac_cv_header_bsd_string_h" "$ac_includes_default" if test "x$ac_cv_header_bsd_string_h" = xyes then : printf "%s\n" "#define HAVE_BSD_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/ip.h" "ac_cv_header_netinet_ip_h" "#include " if test "x$ac_cv_header_netinet_ip_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IP_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 printf %s "checking whether sys/types.h defines makedev... " >&6; } if test ${ac_cv_header_sys_types_h_makedev+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { return makedev(0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : if grep sys/sysmacros.h conftest.err >/dev/null; then ac_cv_header_sys_types_h_makedev=no else ac_cv_header_sys_types_h_makedev=yes fi else $as_nop ac_cv_header_sys_types_h_makedev=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 printf "%s\n" "$ac_cv_header_sys_types_h_makedev" >&6; } if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mkdev_h" = xyes then : printf "%s\n" "#define MAJOR_IN_MKDEV 1" >>confdefs.h fi if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" if test "x$ac_cv_header_sys_sysmacros_h" = xyes then : printf "%s\n" "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h fi fi fi ac_config_headers="$ac_config_headers config.h" PACKAGE_VERSION=`sed -n 's/.*RSYNC_VERSION.*"\(.*\)".*/\1/p' <$srcdir/version.h` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configuring rsync $PACKAGE_VERSION" >&5 printf "%s\n" "$as_me: Configuring rsync $PACKAGE_VERSION" >&6;} LDFLAGS=${LDFLAGS-""} # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # We must decide this before testing the compiler. # Please allow this to default to yes, so that your users have more # chance of getting a useful stack trace if problems occur. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to include debugging symbols" >&5 printf %s "checking whether to include debugging symbols... " >&6; } # Check whether --enable-debug was given. if test ${enable_debug+y} then : enableval=$enable_debug; fi if test x"$enable_debug" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ac_cv_prog_cc_g=no else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # leave ac_cv_prog_cc_g alone; AC_PROG_CC will try to include -g if it can fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 printf "%s\n" "$CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 printf "%s\n" "$ac_ct_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_prog_cxx_stdcxx=no if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } if test ${ac_cv_prog_cxx_11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx11_program _ACEOF for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx11" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_prog_cxx_stdcxx=cxx11 fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } if test ${ac_cv_prog_cxx_98+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx98_program _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx98" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cxx_cxx98" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx98" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 ac_prog_cxx_stdcxx=cxx98 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PERL+y} then : printf %s "(cached) " >&6 else $as_nop case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 printf "%s\n" "$PERL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "python3", so it can be a program name with args. set dummy python3; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PYTHON3+y} then : printf %s "(cached) " >&6 else $as_nop case $PYTHON3 in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON3="$PYTHON3" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON3="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON3=$ac_cv_path_PYTHON3 if test -n "$PYTHON3"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PYTHON3" >&5 printf "%s\n" "$PYTHON3" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h if test x"$ac_cv_prog_cc_stdc" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: rsync requires an ANSI C compiler and you do not seem to have one" >&5 printf "%s\n" "$as_me: WARNING: rsync requires an ANSI C compiler and you do not seem to have one" >&2;} fi no_lib='' err_msg='' nl=' ' # Check whether --enable-profile was given. if test ${enable_profile+y} then : enableval=$enable_profile; fi if test x"$enable_profile" = x"yes"; then CFLAGS="$CFLAGS -pg" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if md2man can create manpages" >&5 printf %s "checking if md2man can create manpages... " >&6; } if test x"$ac_cv_path_PYTHON3" = x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no - python3 not found" >&5 printf "%s\n" "no - python3 not found" >&6; } md2man_works=no else md2man_out=`"$srcdir/md2man" --test "$srcdir/rsync-ssl.1.md" 2>&1` if test $? = 0; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } md2man_works=yes else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } md2man_works=no echo "$md2man_out" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we require man-page building" >&5 printf %s "checking if we require man-page building... " >&6; } # Check whether --enable-md2man was given. if test ${enable_md2man+y} then : enableval=$enable_md2man; fi if test x"$enable_md2man" != x"no"; then if test -f "$srcdir/rsync.1"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: optional" >&5 printf "%s\n" "optional" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: required" >&5 printf "%s\n" "required" >&6; } if test x"$md2man_works" = x"no"; then err_msg="$err_msg$nl- You need python3 and either the cmarkgfm OR commonmark python3 lib in order" err_msg="$err_msg$nl to build manpages based on the git source (manpages are included in the" err_msg="$err_msg$nl official release tar files)." no_lib="$no_lib md2man" fi fi MAKE_MAN=man else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Specifically, this turns on panic_action handling. # Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; fi if test x"$enable_maintainer_mode" = x"yes"; then CFLAGS="$CFLAGS -DMAINTAINER_MODE" fi # This is needed for our included version of popt. Kind of silly, but # I don't want our version too far out of sync. CFLAGS="$CFLAGS -DHAVE_CONFIG_H" # If GCC, turn on warnings. if test x"$GCC" = x"yes"; then CFLAGS="$CFLAGS -Wall -W" fi # Check whether --with-openssl-conf was given. if test ${with_openssl_conf+y} then : withval=$with_openssl_conf; fi case "$with_openssl_conf" in *^-/a-zA-Z0-9.,=@+_*) as_fn_error $? "Invalid path given to --with-openssl-conf" "$LINENO" 5 ;; /*) CFLAGS="$CFLAGS -DSET_OPENSSL_CONF=$with_openssl_conf" ;; no|'') ;; yes) as_fn_error $? "No path given to --with-openssl-conf" "$LINENO" 5 ;; *) as_fn_error $? "Non absolute path given to --with-openssl-conf" "$LINENO" 5 ;; esac # Check whether --with-rrsync was given. if test ${with_rrsync+y} then : withval=$with_rrsync; fi if test x"$with_rrsync" != x"yes"; then with_rrsync=no else MAKE_RRSYNC='rrsync' MAKE_RRSYNC_1='rrsync.1' GEN_RRSYNC='rrsync.1 rrsync.1.html' fi # Check whether --with-included-popt was given. if test ${with_included_popt+y} then : withval=$with_included_popt; fi # Check whether --with-included-zlib was given. if test ${with_included_zlib+y} then : withval=$with_included_zlib; fi # Check whether --with-secluded-args was given. if test ${with_secluded_args+y} then : withval=$with_secluded_args; fi if test x"$with_secluded_args" = x"yes"; then printf "%s\n" "#define RSYNC_USE_SECLUDED_ARGS 1" >>confdefs.h fi # Check whether --with-rsync-path was given. if test ${with_rsync_path+y} then : withval=$with_rsync_path; RSYNC_PATH="$with_rsync_path" else $as_nop RSYNC_PATH="rsync" fi printf "%s\n" "#define RSYNC_PATH \"$RSYNC_PATH\"" >>confdefs.h # Check whether --with-rsyncd-conf was given. if test ${with_rsyncd_conf+y} then : withval=$with_rsyncd_conf; if test ! -z "$with_rsyncd_conf" ; then case $with_rsyncd_conf in yes|no) RSYNCD_SYSCONF="/etc/rsyncd.conf" ;; /*) RSYNCD_SYSCONF="$with_rsyncd_conf" ;; *) as_fn_error $? "You must specify an absolute path to --with-rsyncd-conf=PATH" "$LINENO" 5 ;; esac else RSYNCD_SYSCONF="/etc/rsyncd.conf" fi else $as_nop RSYNCD_SYSCONF="/etc/rsyncd.conf" fi printf "%s\n" "#define RSYNCD_SYSCONF \"$RSYNCD_SYSCONF\"" >>confdefs.h # Check whether --with-rsh was given. if test ${with_rsh+y} then : withval=$with_rsh; fi # Extract the first word of "remsh", so it can be a program name with args. set dummy remsh; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_HAVE_REMSH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$HAVE_REMSH"; then ac_cv_prog_HAVE_REMSH="$HAVE_REMSH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_REMSH="1" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_HAVE_REMSH" && ac_cv_prog_HAVE_REMSH="0" fi fi HAVE_REMSH=$ac_cv_prog_HAVE_REMSH if test -n "$HAVE_REMSH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_REMSH" >&5 printf "%s\n" "$HAVE_REMSH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test x$HAVE_REMSH = x1; then printf "%s\n" "#define HAVE_REMSH 1" >>confdefs.h fi if test x"$with_rsh" != x; then RSYNC_RSH="$with_rsh" else RSYNC_RSH="ssh" fi printf "%s\n" "#define RSYNC_RSH \"$RSYNC_RSH\"" >>confdefs.h # Some programs on solaris are only found in /usr/xpg4/bin (or work better than others versions). # Extract the first word of "sh", so it can be a program name with args. set dummy sh; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_SHELL_PATH+y} then : printf %s "(cached) " >&6 else $as_nop case $SHELL_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_SHELL_PATH="$SHELL_PATH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /usr/xpg4/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_SHELL_PATH="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_SHELL_PATH" && ac_cv_path_SHELL_PATH="/bin/sh" ;; esac fi SHELL_PATH=$ac_cv_path_SHELL_PATH if test -n "$SHELL_PATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SHELL_PATH" >&5 printf "%s\n" "$SHELL_PATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "fakeroot", so it can be a program name with args. set dummy fakeroot; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_FAKEROOT_PATH+y} then : printf %s "(cached) " >&6 else $as_nop case $FAKEROOT_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_FAKEROOT_PATH="$FAKEROOT_PATH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /usr/xpg4/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_FAKEROOT_PATH="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_FAKEROOT_PATH" && ac_cv_path_FAKEROOT_PATH="/usr/bin/fakeroot" ;; esac fi FAKEROOT_PATH=$ac_cv_path_FAKEROOT_PATH if test -n "$FAKEROOT_PATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FAKEROOT_PATH" >&5 printf "%s\n" "$FAKEROOT_PATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Check whether --with-nobody-user was given. if test ${with_nobody_user+y} then : withval=$with_nobody_user; NOBODY_USER="$with_nobody_user" else $as_nop NOBODY_USER="nobody" fi # Check whether --with-nobody-group was given. if test ${with_nobody_group+y} then : withval=$with_nobody_group; NOBODY_GROUP="$with_nobody_group" fi if test x"$with_nobody_group" = x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the group for user \"nobody\"" >&5 printf %s "checking the group for user \"nobody\"... " >&6; } if grep '^nobody:' /etc/group >/dev/null 2>&1; then NOBODY_GROUP=nobody elif grep '^nogroup:' /etc/group >/dev/null 2>&1; then NOBODY_GROUP=nogroup else NOBODY_GROUP=nobody # test for others? fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NOBODY_GROUP" >&5 printf "%s\n" "$NOBODY_GROUP" >&6; } fi printf "%s\n" "#define NOBODY_USER \"$NOBODY_USER\"" >>confdefs.h printf "%s\n" "#define NOBODY_GROUP \"$NOBODY_GROUP\"" >>confdefs.h # rolling-checksum SIMD optimizations ROLL_SIMD= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable rolling-checksum SIMD optimizations" >&5 printf %s "checking whether to enable rolling-checksum SIMD optimizations... " >&6; } # Check whether --enable-roll-simd was given. if test ${enable_roll_simd+y} then : enableval=$enable_roll_simd; fi # Clag is crashing with -g -O2, so we'll get rid of -g for now. CXXFLAGS=`echo "$CXXFLAGS" | sed 's/-g //'` if test x"$enable_roll_simd" = x""; then case "$host_os" in *linux*) ;; *) enable_roll_simd=no ;; esac fi if test x"$enable_roll_simd" != x"no"; then # For x86-64 SIMD, g++ >=5 or clang++ >=7 is required if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test x"$host" = x"$build"; then if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if HAVE_STDLIB_H #include #endif #include __attribute__ ((target("default"))) int test_ssse3(int x) { return x; } __attribute__ ((target("default"))) int test_sse2(int x) { return x; } __attribute__ ((target("default"))) int test_avx2(int x) { return x; } __attribute__ ((target("ssse3"))) int test_ssse3(int x) { return x; } __attribute__ ((target("sse2"))) int test_sse2(int x) { return x; } __attribute__ ((target("avx2"))) int test_avx2(int x) { return x; } typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(1))); __attribute__ ((target("default"))) void more_testing(char* buf, int len) { } __attribute__ ((target("ssse3"))) void more_testing(char* buf, int len) { int i; for (i = 0; i < (len-32); i+=32) { __m128i in8_1, in8_2; in8_1 = _mm_lddqu_si128((__m128i_u*)&buf[i]); in8_2 = _mm_lddqu_si128((__m128i_u*)&buf[i + 16]); } } int main (void) { if (test_ssse3(42) != 42 || test_sse2(42) != 42 || test_avx2(42) != 42) exit(1); ; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO" then : CXX_OK=yes else $as_nop CXX_OK=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if HAVE_STDLIB_H #include #endif #include __attribute__ ((target("default"))) int test_ssse3(int x) { return x; } __attribute__ ((target("default"))) int test_sse2(int x) { return x; } __attribute__ ((target("default"))) int test_avx2(int x) { return x; } __attribute__ ((target("ssse3"))) int test_ssse3(int x) { return x; } __attribute__ ((target("sse2"))) int test_sse2(int x) { return x; } __attribute__ ((target("avx2"))) int test_avx2(int x) { return x; } typedef long long __m128i_u __attribute__((__vector_size__(16), __may_alias__, __aligned__(1))); typedef long long __m256i_u __attribute__((__vector_size__(32), __may_alias__, __aligned__(1))); __attribute__ ((target("default"))) void more_testing(char* buf, int len) { } __attribute__ ((target("ssse3"))) void more_testing(char* buf, int len) { int i; for (i = 0; i < (len-32); i+=32) { __m128i in8_1, in8_2; in8_1 = _mm_lddqu_si128((__m128i_u*)&buf[i]); in8_2 = _mm_lddqu_si128((__m128i_u*)&buf[i + 16]); } } int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : CXX_OK=yes else $as_nop CXX_OK=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x"$CXX_OK" = x"yes"; then # AC_MSG_RESULT() is called below. ROLL_SIMD="$host_cpu" elif test x"$enable_roll_simd" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: error" >&5 printf "%s\n" "error" >&6; } as_fn_error $? "The rolling-checksum SIMD compilation test failed. Omit --enable-roll-simd to continue without it." "$LINENO" 5 fi elif test x"$enable_roll_simd" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unavailable" >&5 printf "%s\n" "unavailable" >&6; } as_fn_error $? "The rolling-checksum SIMD optimizations are currently x86_64|amd64 only. Omit --enable-roll-simd to continue without it." "$LINENO" 5 fi fi if test x"$ROLL_SIMD" != x""; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($ROLL_SIMD)" >&5 printf "%s\n" "yes ($ROLL_SIMD)" >&6; } printf "%s\n" "#define USE_ROLL_SIMD 1" >>confdefs.h ROLL_SIMD='$(ROLL_SIMD_'"$ROLL_SIMD)" # We only use c++ for its target attribute dispatching, disable unneeded bulky features CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" # Apple often has "g++" as a symlink for clang. Try to find out the truth. CXX_VERSION=`$CXX --version 2>/dev/null | head -n 2` case "$CXX_VERSION" in *clang*) CXXFLAGS="$CXXFLAGS -fno-slp-vectorize" ;; # avoid a performance hit esac else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if assembler accepts noexecstack" >&5 printf %s "checking if assembler accepts noexecstack... " >&6; } OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wa,--noexecstack" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : NOEXECSTACK='-Wa,--noexecstack' ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop NOEXECSTACK='' ; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$OLD_CFLAGS" # arrgh. libc in some old debian version screwed up the largefile # stuff, getting byte range locking wrong { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken largefile support" >&5 printf %s "checking for broken largefile support... " >&6; } if test ${rsync_cv_HAVE_BROKEN_LARGEFILE+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_HAVE_BROKEN_LARGEFILE=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 $ac_includes_default #ifdef HAVE_FCNTL_H # include #elif defined HAVE_SYS_FCNTL_H # include #endif #ifdef HAVE_SYS_WAIT_H #include #endif int main(void) { struct flock lock; int status; char tpl[32] = "/tmp/locktest.XXXXXX"; int fd = mkstemp(tpl); if (fd < 0) { strcpy(tpl, "conftest.dat"); fd = open(tpl, O_CREAT|O_RDWR, 0600); } lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 1; lock.l_pid = 0; fcntl(fd,F_SETLK,&lock); if (fork() == 0) { lock.l_start = 1; _exit(fcntl(fd,F_SETLK,&lock) == 0); } wait(&status); unlink(tpl); return WEXITSTATUS(status); } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_HAVE_BROKEN_LARGEFILE=yes else $as_nop rsync_cv_HAVE_BROKEN_LARGEFILE=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_BROKEN_LARGEFILE" >&5 printf "%s\n" "$rsync_cv_HAVE_BROKEN_LARGEFILE" >&6; } if test x"$rsync_cv_HAVE_BROKEN_LARGEFILE" != x"yes"; then # Check whether --enable-largefile was given. if test ${enable_largefile+y} then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 printf %s "checking for special C compiler options needed for large files... " >&6; } if test ${ac_cv_sys_largefile_CC+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : break fi rm -f core conftest.err conftest.$ac_objext conftest.beam CC="$CC -n32" if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test ${ac_cv_sys_file_offset_bits+y} then : printf %s "(cached) " >&6 else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } if test ${ac_cv_sys_large_files+y} then : printf %s "(cached) " >&6 else $as_nop while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 printf "%s\n" "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h ;; esac rm -rf conftest* fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ipv6" >&5 printf %s "checking whether to enable ipv6... " >&6; } # Check whether --enable-ipv6 was given. if test ${enable_ipv6+y} then : enableval=$enable_ipv6; case "$enableval" in no) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define INET6 1" >>confdefs.h ;; esac else $as_nop if test "$cross_compiling" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* AF_INET6 availability check */ #include #include #include main() { if (socket(AF_INET6, SOCK_STREAM, 0) < 0) exit(1); else exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define INET6 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi # Check whether --enable-locale was given. if test ${enable_locale+y} then : enableval=$enable_locale; fi if test x"$enable_locale" != x"no"; then printf "%s\n" "#define CONFIG_LOCALE 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to call shutdown on all sockets" >&5 printf %s "checking whether to call shutdown on all sockets... " >&6; } case $host_os in *cygwin* ) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define SHUTDOWN_ALL_SOCKETS 1" >>confdefs.h ;; * ) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; };; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable use of openssl crypto library" >&5 printf %s "checking whether to enable use of openssl crypto library... " >&6; } # Check whether --enable-openssl was given. if test ${enable_openssl+y} then : enableval=$enable_openssl; fi if test x"$enable_openssl" != x"no"; then if test x"$ac_cv_header_openssl_md4_h" = x"yes" && test x"$ac_cv_header_openssl_md5_h" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing MD5_Init" >&5 printf %s "checking for library containing MD5_Init... " >&6; } if test ${ac_cv_search_MD5_Init+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char MD5_Init (); int main (void) { return MD5_Init (); ; return 0; } _ACEOF for ac_lib in '' crypto do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_MD5_Init=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_MD5_Init+y} then : break fi done if test ${ac_cv_search_MD5_Init+y} then : else $as_nop ac_cv_search_MD5_Init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_MD5_Init" >&5 printf "%s\n" "$ac_cv_search_MD5_Init" >&6; } ac_res=$ac_cv_search_MD5_Init if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define USE_OPENSSL 1" >>confdefs.h enable_openssl=yes else $as_nop err_msg="$err_msg$nl- Failed to find MD5_Init function in openssl crypto lib."; no_lib="$no_lib openssl" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } err_msg="$err_msg$nl- Failed to find openssl/md4.h and openssl/md5.h for openssl crypto lib support." no_lib="$no_lib openssl" fi if test x"$enable_md5_asm" != x"yes"; then enable_md5_asm=no fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi MD5_ASM= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable MD5 ASM optimizations" >&5 printf %s "checking whether to enable MD5 ASM optimizations... " >&6; } # Check whether --enable-md5-asm was given. if test ${enable_md5_asm+y} then : enableval=$enable_md5_asm; fi if test x"$enable_md5_asm" = x""; then case "$host_os" in *linux*) ;; *) enable_md5_asm=no ;; esac fi if test x"$enable_md5_asm" != x"no"; then if test x"$host_cpu" = x"x86_64" || test x"$host_cpu" = x"amd64"; then MD5_ASM="$host_cpu" elif test x"$enable_md5_asm" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unavailable" >&5 printf "%s\n" "unavailable" >&6; } as_fn_error $? "The ASM optimizations are currently x86_64|amd64 only. Omit --enable-md5-asm to continue without it." "$LINENO" 5 fi fi if test x"$MD5_ASM" != x""; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($MD5_ASM)" >&5 printf "%s\n" "yes ($MD5_ASM)" >&6; } printf "%s\n" "#define USE_MD5_ASM 1" >>confdefs.h MD5_ASM='$(MD5_ASM_'"$MD5_ASM)" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ROLL_ASM= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable rolling-checksum ASM optimizations" >&5 printf %s "checking whether to enable rolling-checksum ASM optimizations... " >&6; } # Check whether --enable-roll-asm was given. if test ${enable_roll_asm+y} then : enableval=$enable_roll_asm; fi if test x"$ROLL_SIMD" = x""; then enable_roll_asm=no fi if test x"$enable_roll_asm" = x"yes"; then ROLL_ASM="$host_cpu" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($ROLL_ASM)" >&5 printf "%s\n" "yes ($ROLL_ASM)" >&6; } printf "%s\n" "#define USE_ROLL_ASM 1" >>confdefs.h ROLL_ASM='$(ROLL_ASM_'"$ROLL_ASM)" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable xxhash checksum support" >&5 printf %s "checking whether to enable xxhash checksum support... " >&6; } # Check whether --enable-xxhash was given. if test ${enable_xxhash+y} then : enableval=$enable_xxhash; fi if test x"$enable_xxhash" != x"no"; then if test x"$ac_cv_header_xxhash_h" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing XXH64_createState" >&5 printf %s "checking for library containing XXH64_createState... " >&6; } if test ${ac_cv_search_XXH64_createState+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char XXH64_createState (); int main (void) { return XXH64_createState (); ; return 0; } _ACEOF for ac_lib in '' xxhash do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_XXH64_createState=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_XXH64_createState+y} then : break fi done if test ${ac_cv_search_XXH64_createState+y} then : else $as_nop ac_cv_search_XXH64_createState=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_XXH64_createState" >&5 printf "%s\n" "$ac_cv_search_XXH64_createState" >&6; } ac_res=$ac_cv_search_XXH64_createState if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define SUPPORT_XXHASH 1" >>confdefs.h else $as_nop err_msg="$err_msg$nl- Failed to find XXH64_createState function in xxhash lib."; no_lib="$no_lib xxhash" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } err_msg="$err_msg$nl- Failed to find xxhash.h for xxhash checksum support."; no_lib="$no_lib xxhash" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable zstd compression" >&5 printf %s "checking whether to enable zstd compression... " >&6; } # Check whether --enable-zstd was given. if test ${enable_zstd+y} then : enableval=$enable_zstd; fi if test x"$enable_zstd" != x"no"; then if test x"$ac_cv_header_zstd_h" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing ZSTD_minCLevel" >&5 printf %s "checking for library containing ZSTD_minCLevel... " >&6; } if test ${ac_cv_search_ZSTD_minCLevel+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char ZSTD_minCLevel (); int main (void) { return ZSTD_minCLevel (); ; return 0; } _ACEOF for ac_lib in '' zstd do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_ZSTD_minCLevel=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_ZSTD_minCLevel+y} then : break fi done if test ${ac_cv_search_ZSTD_minCLevel+y} then : else $as_nop ac_cv_search_ZSTD_minCLevel=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ZSTD_minCLevel" >&5 printf "%s\n" "$ac_cv_search_ZSTD_minCLevel" >&6; } ac_res=$ac_cv_search_ZSTD_minCLevel if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define SUPPORT_ZSTD 1" >>confdefs.h else $as_nop err_msg="$err_msg$nl- Failed to find ZSTD_minCLevel function in zstd lib."; no_lib="$no_lib zstd" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } err_msg="$err_msg$nl- Failed to find zstd.h for zstd compression support."; no_lib="$no_lib zstd" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable LZ4 compression" >&5 printf %s "checking whether to enable LZ4 compression... " >&6; } # Check whether --enable-lz4 was given. if test ${enable_lz4+y} then : enableval=$enable_lz4; fi if test x"$enable_lz4" != x"no"; then if test x"$ac_cv_header_lz4_h" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing LZ4_compress_default" >&5 printf %s "checking for library containing LZ4_compress_default... " >&6; } if test ${ac_cv_search_LZ4_compress_default+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char LZ4_compress_default (); int main (void) { return LZ4_compress_default (); ; return 0; } _ACEOF for ac_lib in '' lz4 do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_LZ4_compress_default=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_LZ4_compress_default+y} then : break fi done if test ${ac_cv_search_LZ4_compress_default+y} then : else $as_nop ac_cv_search_LZ4_compress_default=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_LZ4_compress_default" >&5 printf "%s\n" "$ac_cv_search_LZ4_compress_default" >&6; } ac_res=$ac_cv_search_LZ4_compress_default if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define SUPPORT_LZ4 1" >>confdefs.h else $as_nop err_msg="$err_msg$nl- Failed to find LZ4_compress_default function in lz4 lib."; no_lib="$no_lib lz4" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } err_msg="$err_msg$nl- Failed to find lz4.h for lz4 compression support." no_lib="$no_lib lz4" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test x"$no_lib" != x; then echo "" echo "Configure found the following issues:" echo "$err_msg" echo "" echo "See the INSTALL file for hints on how to install the missing libraries and/or" echo "how to generate (or fetch) manpages:" echo " https://github.com/WayneD/rsync/blob/master/INSTALL.md" echo "" echo "To disable one or more features, the relevant configure options are:" for lib in $no_lib; do echo " --disable-$lib" done echo "" as_fn_error $? "Aborting configure run" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if makedev takes 3 args" >&5 printf %s "checking if makedev takes 3 args... " >&6; } if test ${rsync_cv_MAKEDEV_TAKES_3_ARGS+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_MAKEDEV_TAKES_3_ARGS=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef MAJOR_IN_MKDEV #include # if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__) # define makedev mkdev # endif #elif defined MAJOR_IN_SYSMACROS #include #endif int main(void) { dev_t dev = makedev(0, 5, 7); if (major(dev) != 5 || minor(dev) != 7) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_MAKEDEV_TAKES_3_ARGS=yes else $as_nop rsync_cv_MAKEDEV_TAKES_3_ARGS=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MAKEDEV_TAKES_3_ARGS" >&5 printf "%s\n" "$rsync_cv_MAKEDEV_TAKES_3_ARGS" >&6; } if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then printf "%s\n" "#define MAKEDEV_TAKES_3_ARGS 1" >>confdefs.h fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 printf %s "checking size of int... " >&6; } if test ${ac_cv_sizeof_int+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_int" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 printf "%s\n" "$ac_cv_sizeof_int" >&6; } printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 printf %s "checking size of long... " >&6; } if test ${ac_cv_sizeof_long+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_long" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 printf "%s\n" "$ac_cv_sizeof_long" >&6; } printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 printf %s "checking size of long long... " >&6; } if test ${ac_cv_sizeof_long_long+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_long_long" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 printf %s "checking size of short... " >&6; } if test ${ac_cv_sizeof_short+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_short" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 printf "%s\n" "$ac_cv_sizeof_short" >&6; } printf "%s\n" "#define SIZEOF_SHORT $ac_cv_sizeof_short" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int16_t" >&5 printf %s "checking size of int16_t... " >&6; } if test ${ac_cv_sizeof_int16_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int16_t))" "ac_cv_sizeof_int16_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_int16_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int16_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int16_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int16_t" >&5 printf "%s\n" "$ac_cv_sizeof_int16_t" >&6; } printf "%s\n" "#define SIZEOF_INT16_T $ac_cv_sizeof_int16_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of uint16_t" >&5 printf %s "checking size of uint16_t... " >&6; } if test ${ac_cv_sizeof_uint16_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint16_t))" "ac_cv_sizeof_uint16_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_uint16_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (uint16_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint16_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint16_t" >&5 printf "%s\n" "$ac_cv_sizeof_uint16_t" >&6; } printf "%s\n" "#define SIZEOF_UINT16_T $ac_cv_sizeof_uint16_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int32_t" >&5 printf %s "checking size of int32_t... " >&6; } if test ${ac_cv_sizeof_int32_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int32_t))" "ac_cv_sizeof_int32_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_int32_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int32_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int32_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int32_t" >&5 printf "%s\n" "$ac_cv_sizeof_int32_t" >&6; } printf "%s\n" "#define SIZEOF_INT32_T $ac_cv_sizeof_int32_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of uint32_t" >&5 printf %s "checking size of uint32_t... " >&6; } if test ${ac_cv_sizeof_uint32_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint32_t))" "ac_cv_sizeof_uint32_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_uint32_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (uint32_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_uint32_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint32_t" >&5 printf "%s\n" "$ac_cv_sizeof_uint32_t" >&6; } printf "%s\n" "#define SIZEOF_UINT32_T $ac_cv_sizeof_uint32_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int64_t" >&5 printf %s "checking size of int64_t... " >&6; } if test ${ac_cv_sizeof_int64_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int64_t))" "ac_cv_sizeof_int64_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_int64_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int64_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int64_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int64_t" >&5 printf "%s\n" "$ac_cv_sizeof_int64_t" >&6; } printf "%s\n" "#define SIZEOF_INT64_T $ac_cv_sizeof_int64_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 printf %s "checking size of off_t... " >&6; } if test ${ac_cv_sizeof_off_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_off_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 printf "%s\n" "$ac_cv_sizeof_off_t" >&6; } printf "%s\n" "#define SIZEOF_OFF_T $ac_cv_sizeof_off_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of off64_t" >&5 printf %s "checking size of off64_t... " >&6; } if test ${ac_cv_sizeof_off64_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off64_t))" "ac_cv_sizeof_off64_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_off64_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (off64_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_off64_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off64_t" >&5 printf "%s\n" "$ac_cv_sizeof_off64_t" >&6; } printf "%s\n" "#define SIZEOF_OFF64_T $ac_cv_sizeof_off64_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 printf %s "checking size of time_t... " >&6; } if test ${ac_cv_sizeof_time_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_time_t" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (time_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_time_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 printf "%s\n" "$ac_cv_sizeof_time_t" >&6; } printf "%s\n" "#define SIZEOF_TIME_T $ac_cv_sizeof_time_t" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of char*" >&5 printf %s "checking size of char*... " >&6; } if test ${ac_cv_sizeof_charp+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char*))" "ac_cv_sizeof_charp" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_charp" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (char*) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_charp=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_charp" >&5 printf "%s\n" "$ac_cv_sizeof_charp" >&6; } printf "%s\n" "#define SIZEOF_CHARP $ac_cv_sizeof_charp" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo (void) {return 0; } $ac_kw foo_t foo (void) {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 printf "%s\n" "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5 printf %s "checking for long double with more range or precision than double... " >&6; } if test ${ac_cv_type_long_double_wider+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include long double const a[] = { 0.0L, DBL_MIN, DBL_MAX, DBL_EPSILON, LDBL_MIN, LDBL_MAX, LDBL_EPSILON }; long double f (long double x) { return ((x + (unsigned long int) 10) * (-1 / x) + a[0] + (x ? f (x) : 'c')); } int main (void) { static int test_array [1 - 2 * !((0 < ((DBL_MAX_EXP < LDBL_MAX_EXP) + (DBL_MANT_DIG < LDBL_MANT_DIG) - (LDBL_MAX_EXP < DBL_MAX_EXP) - (LDBL_MANT_DIG < DBL_MANT_DIG))) && (int) LDBL_EPSILON == 0 )]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_type_long_double_wider=yes else $as_nop ac_cv_type_long_double_wider=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double_wider" >&5 printf "%s\n" "$ac_cv_type_long_double_wider" >&6; } if test $ac_cv_type_long_double_wider = yes; then printf "%s\n" "#define HAVE_LONG_DOUBLE_WIDER 1" >>confdefs.h fi ac_cv_c_long_double=$ac_cv_type_long_double_wider if test $ac_cv_c_long_double = yes; then printf "%s\n" "#define HAVE_LONG_DOUBLE 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 printf %s "checking for uid_t in sys/types.h... " >&6; } if test ${ac_cv_type_uid_t+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1 then : ac_cv_type_uid_t=yes else $as_nop ac_cv_type_uid_t=no fi rm -rf conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 printf "%s\n" "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then printf "%s\n" "#define uid_t int" >>confdefs.h printf "%s\n" "#define gid_t int" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes then : printf "%s\n" "#define HAVE_MODE_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" if test "x$ac_cv_type_off_t" = xyes then : printf "%s\n" "#define HAVE_OFF_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : printf "%s\n" "#define HAVE_SIZE_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes then : printf "%s\n" "#define HAVE_PID_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "id_t" "ac_cv_type_id_t" "$ac_includes_default" if test "x$ac_cv_type_id_t" = xyes then : printf "%s\n" "#define HAVE_ID_T 1" >>confdefs.h fi if test "$cross_compiling" = no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5 printf %s "checking type of array argument to getgroups... " >&6; } if test ${ac_cv_type_getgroups+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_type_getgroups=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Mike Rendell for this test. */ $ac_includes_default #define NGID 256 #undef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) int main (void) { gid_t gidset[NGID]; int i, n; union { gid_t gval; long int lval; } val; val.lval = -1; for (i = 0; i < NGID; i++) gidset[i] = val.gval; n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, gidset); /* Exit non-zero if getgroups seems to require an array of ints. This happens when gid_t is short int but getgroups modifies an array of ints. */ return n > 0 && gidset[n] != val.gval; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_type_getgroups=gid_t else $as_nop ac_cv_type_getgroups=int fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_type_getgroups = cross; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1 then : ac_cv_type_getgroups=gid_t else $as_nop ac_cv_type_getgroups=int fi rm -rf conftest* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5 printf "%s\n" "$ac_cv_type_getgroups" >&6; } printf "%s\n" "#define GETGROUPS_T $ac_cv_type_getgroups" >>confdefs.h else printf "%s\n" "#define GETGROUPS_T gid_t" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif " if test "x$ac_cv_member_struct_stat_st_rdev" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_RDEV 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif " if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec.tv_nsec" "ac_cv_member_struct_stat_st_mtimespec_tv_nsec" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif " if test "x$ac_cv_member_struct_stat_st_mtimespec_tv_nsec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_UNISTD_H #include #endif " if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include #include " if test "x$ac_cv_type_socklen_t" = xyes then : else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5 printf %s "checking for socklen_t equivalent... " >&6; } if test ${rsync_cv_socklen_t_equiv+y} then : printf %s "(cached) " >&6 else $as_nop # Systems have either "struct sockaddr *" or # "void *" as the second argument to getpeername rsync_cv_socklen_t_equiv= for arg2 in "struct sockaddr" void; do for t in int size_t unsigned long "unsigned long"; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int getpeername (int, $arg2 *, $t *); int main (void) { $t len; getpeername(0,0,&len); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_socklen_t_equiv="$t" break fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done done if test "x$rsync_cv_socklen_t_equiv" = x; then as_fn_error $? "Cannot find a type to use in place of socklen_t" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_socklen_t_equiv" >&5 printf "%s\n" "$rsync_cv_socklen_t_equiv" >&6; } printf "%s\n" "#define socklen_t $rsync_cv_socklen_t_equiv" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for errno in errno.h" >&5 printf %s "checking for errno in errno.h... " >&6; } if test ${rsync_cv_errno+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int i = errno ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_errno=yes else $as_nop rsync_cv_have_errno_decl=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_errno" >&5 printf "%s\n" "$rsync_cv_errno" >&6; } if test x"$rsync_cv_errno" = x"yes"; then printf "%s\n" "#define HAVE_ERRNO_DECL 1" >>confdefs.h fi # The following test taken from the cvs sources # If we can't find connect, try looking in -lsocket, -lnsl, and -linet. # These need checks to be before checks for any other functions that # might be in the same libraries. # The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has # libsocket.so which has a bad implementation of gethostbyname (it # only looks in /etc/hosts), so we only look for -lsocket if we need # it. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes then : printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl_s" >&5 printf %s "checking for printf in -lnsl_s... " >&6; } if test ${ac_cv_lib_nsl_s_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl_s $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_s_printf=yes else $as_nop ac_cv_lib_nsl_s_printf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_s_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_s_printf" >&6; } if test "x$ac_cv_lib_nsl_s_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL_S 1" >>confdefs.h LIBS="-lnsl_s $LIBS" fi ;; esac case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl" >&5 printf %s "checking for printf in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_printf=yes else $as_nop ac_cv_lib_nsl_printf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_printf" >&6; } if test "x$ac_cv_lib_nsl_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL 1" >>confdefs.h LIBS="-lnsl $LIBS" fi ;; esac case "$LIBS" in *-lsocket*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 printf %s "checking for connect in -lsocket... " >&6; } if test ${ac_cv_lib_socket_connect+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_connect=yes else $as_nop ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 printf "%s\n" "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes then : printf "%s\n" "#define HAVE_LIBSOCKET 1" >>confdefs.h LIBS="-lsocket $LIBS" fi ;; esac case "$LIBS" in *-linet*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -linet" >&5 printf %s "checking for connect in -linet... " >&6; } if test ${ac_cv_lib_inet_connect+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_inet_connect=yes else $as_nop ac_cv_lib_inet_connect=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_connect" >&5 printf "%s\n" "$ac_cv_lib_inet_connect" >&6; } if test "x$ac_cv_lib_inet_connect" = xyes then : printf "%s\n" "#define HAVE_LIBINET 1" >>confdefs.h LIBS="-linet $LIBS" fi ;; esac if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inet_ntop" >&5 printf %s "checking for library containing inet_ntop... " >&6; } if test ${ac_cv_search_inet_ntop+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntop (); int main (void) { return inet_ntop (); ; return 0; } _ACEOF for ac_lib in '' resolv do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_inet_ntop=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_inet_ntop+y} then : break fi done if test ${ac_cv_search_inet_ntop+y} then : else $as_nop ac_cv_search_inet_ntop=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_ntop" >&5 printf "%s\n" "$ac_cv_search_inet_ntop" >&6; } ac_res=$ac_cv_search_inet_ntop if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # For OS X, Solaris, HP-UX, etc.: figure out if -liconv is needed. We'll # accept either iconv_open or libiconv_open, since some include files map # the former to the latter. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing iconv_open" >&5 printf %s "checking for library containing iconv_open... " >&6; } if test ${ac_cv_search_iconv_open+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char iconv_open (); int main (void) { return iconv_open (); ; return 0; } _ACEOF for ac_lib in '' iconv do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_iconv_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_iconv_open+y} then : break fi done if test ${ac_cv_search_iconv_open+y} then : else $as_nop ac_cv_search_iconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_iconv_open" >&5 printf "%s\n" "$ac_cv_search_iconv_open" >&6; } ac_res=$ac_cv_search_iconv_open if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing libiconv_open" >&5 printf %s "checking for library containing libiconv_open... " >&6; } if test ${ac_cv_search_libiconv_open+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char libiconv_open (); int main (void) { return libiconv_open (); ; return 0; } _ACEOF for ac_lib in '' iconv do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_libiconv_open=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_libiconv_open+y} then : break fi done if test ${ac_cv_search_libiconv_open+y} then : else $as_nop ac_cv_search_libiconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_libiconv_open" >&5 printf "%s\n" "$ac_cv_search_libiconv_open" >&6; } ac_res=$ac_cv_search_libiconv_open if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 printf %s "checking for iconv declaration... " >&6; } if test ${am_cv_proto_iconv+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_STDLIB_H #include #endif #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : am_cv_proto_iconv_arg1="" else $as_nop am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" fi am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed 's/( /(/'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- }$am_cv_proto_iconv" >&5 printf "%s\n" "${ac_t:- }$am_cv_proto_iconv" >&6; } printf "%s\n" "#define ICONV_CONST $am_cv_proto_iconv_arg1" >>confdefs.h ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" if test "x$ac_cv_func_inet_ntop" = xyes then : printf "%s\n" "#define HAVE_INET_NTOP 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" inet_ntop.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_ntop.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "inet_pton" "ac_cv_func_inet_pton" if test "x$ac_cv_func_inet_pton" = xyes then : printf "%s\n" "#define HAVE_INET_PTON 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" inet_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" ;; esac fi cv=`echo "struct addrinfo" | sed 'y%./+- %__p__%'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct addrinfo" >&5 printf %s "checking for struct addrinfo... " >&6; } if eval test \${ac_cv_type_$cv+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main (void) { struct addrinfo foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "ac_cv_type_$cv=yes" else $as_nop eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 printf "%s\n" "$ac_foo" >&6; } if test "$ac_foo" = yes; then ac_tr_hdr=HAVE_`echo struct addrinfo | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'` if false; then ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "$ac_includes_default" if test "x$ac_cv_type_struct_addrinfo" = xyes then : printf "%s\n" "#define HAVE_STRUCT_ADDRINFO 1" >>confdefs.h fi fi printf "%s\n" "#define $ac_tr_hdr 1" >>confdefs.h fi cv=`echo "struct sockaddr_storage" | sed 'y%./+- %__p__%'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5 printf %s "checking for struct sockaddr_storage... " >&6; } if eval test \${ac_cv_type_$cv+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif int main (void) { struct sockaddr_storage foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "ac_cv_type_$cv=yes" else $as_nop eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 printf "%s\n" "$ac_foo" >&6; } if test "$ac_foo" = yes; then ac_tr_hdr=HAVE_`echo struct sockaddr_storage | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'` if false; then ac_fn_c_check_type "$LINENO" "struct sockaddr_storage" "ac_cv_type_struct_sockaddr_storage" "$ac_includes_default" if test "x$ac_cv_type_struct_sockaddr_storage" = xyes then : printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_STORAGE 1" >>confdefs.h fi fi printf "%s\n" "#define $ac_tr_hdr 1" >>confdefs.h fi # Irix 6.5 has getaddrinfo but not the corresponding defines, so use # builtin getaddrinfo if one of the defines don't exist { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether defines needed by getaddrinfo exist" >&5 printf %s "checking whether defines needed by getaddrinfo exist... " >&6; } if test ${rsync_cv_HAVE_GETADDR_DEFINES+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef AI_PASSIVE yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1 then : rsync_cv_HAVE_GETADDR_DEFINES=yes else $as_nop rsync_cv_HAVE_GETADDR_DEFINES=no fi rm -rf conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_GETADDR_DEFINES" >&5 printf "%s\n" "$rsync_cv_HAVE_GETADDR_DEFINES" >&6; } if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" && test x"$ac_cv_type_struct_addrinfo" = x"yes" then : # Tru64 UNIX has getaddrinfo() but has it renamed in libc as # something else so we must include to get the # redefinition. for ac_func in getaddrinfo do : ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" if test "x$ac_cv_func_getaddrinfo" = xyes then : printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo by including " >&5 printf %s "checking for getaddrinfo by including ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include int main (void) { getaddrinfo(NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } case " $LIBOBJS " in *" getaddrinfo.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi done else $as_nop case " $LIBOBJS " in *" getaddrinfo.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext" ;; esac fi ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes then : printf "%s\n" "#define HAVE_SOCKADDR_LEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in" "sin_len" "ac_cv_member_struct_sockaddr_in_sin_len" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = xyes then : printf "%s\n" "#define HAVE_SOCKADDR_IN_LEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include " if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes then : printf "%s\n" "#define HAVE_SOCKADDR_UN_LEN 1" >>confdefs.h fi ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_scope_id" "ac_cv_member_struct_sockaddr_in6_sin6_scope_id" " #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #include " if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes then : printf "%s\n" "#define HAVE_SOCKADDR_IN6_SCOPE_ID 1" >>confdefs.h fi cv=`echo "struct stat64" | sed 'y%./+- %__p__%'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 printf %s "checking for struct stat64... " >&6; } if eval test \${ac_cv_type_$cv+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif int main (void) { struct stat64 foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "ac_cv_type_$cv=yes" else $as_nop eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 printf "%s\n" "$ac_foo" >&6; } if test "$ac_foo" = yes; then ac_tr_hdr=HAVE_`echo struct stat64 | sed 'y%abcdefghijklmnopqrstuvwxyz./- %ABCDEFGHIJKLMNOPQRSTUVWXYZ____%'` if false; then ac_fn_c_check_type "$LINENO" "struct stat64" "ac_cv_type_struct_stat64" "$ac_includes_default" if test "x$ac_cv_type_struct_stat64" = xyes then : printf "%s\n" "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi fi printf "%s\n" "#define $ac_tr_hdr 1" >>confdefs.h fi # if we can't find strcasecmp, look in -lresolv (for Unixware at least) # ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = xyes then : printf "%s\n" "#define HAVE_STRCASECMP 1" >>confdefs.h fi if test x"$ac_cv_func_strcasecmp" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lresolv" >&5 printf %s "checking for strcasecmp in -lresolv... " >&6; } if test ${ac_cv_lib_resolv_strcasecmp+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char strcasecmp (); int main (void) { return strcasecmp (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_resolv_strcasecmp=yes else $as_nop ac_cv_lib_resolv_strcasecmp=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_strcasecmp" >&5 printf "%s\n" "$ac_cv_lib_resolv_strcasecmp" >&6; } if test "x$ac_cv_lib_resolv_strcasecmp" = xyes then : printf "%s\n" "#define HAVE_LIBRESOLV 1" >>confdefs.h LIBS="-lresolv $LIBS" fi fi ac_fn_c_check_func "$LINENO" "aclsort" "ac_cv_func_aclsort" if test "x$ac_cv_func_aclsort" = xyes then : printf "%s\n" "#define HAVE_ACLSORT 1" >>confdefs.h fi if test x"$ac_cv_func_aclsort" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for aclsort in -lsec" >&5 printf %s "checking for aclsort in -lsec... " >&6; } if test ${ac_cv_lib_sec_aclsort+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsec $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char aclsort (); int main (void) { return aclsort (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_sec_aclsort=yes else $as_nop ac_cv_lib_sec_aclsort=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sec_aclsort" >&5 printf "%s\n" "$ac_cv_lib_sec_aclsort" >&6; } if test "x$ac_cv_lib_sec_aclsort" = xyes then : printf "%s\n" "#define HAVE_LIBSEC 1" >>confdefs.h LIBS="-lsec $LIBS" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5 printf %s "checking whether utime accepts a null argument... " >&6; } if test ${ac_cv_func_utime_null+y} then : printf %s "(cached) " >&6 else $as_nop rm -f conftest.data; >conftest.data # Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. if test "$cross_compiling" = yes then : ac_cv_func_utime_null='guessing yes' else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_UTIME_H # include #endif int main (void) { struct stat s, t; return ! (stat ("conftest.data", &s) == 0 && utime ("conftest.data", 0) == 0 && stat ("conftest.data", &t) == 0 && t.st_mtime >= s.st_mtime && t.st_mtime - s.st_mtime < 120); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_utime_null=yes else $as_nop ac_cv_func_utime_null=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5 printf "%s\n" "$ac_cv_func_utime_null" >&6; } if test "x$ac_cv_func_utime_null" != xno; then ac_cv_func_utime_null=yes printf "%s\n" "#define HAVE_UTIME_NULL 1" >>confdefs.h fi rm -f conftest.data ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : else $as_nop printf "%s\n" "#define size_t unsigned int" >>confdefs.h fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 printf %s "checking for working alloca.h... " >&6; } if test ${ac_cv_working_alloca_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_working_alloca_h=yes else $as_nop ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 printf "%s\n" "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then printf "%s\n" "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 printf %s "checking for alloca... " >&6; } if test ${ac_cv_func_alloca_works+y} then : printf %s "(cached) " >&6 else $as_nop if test $ac_cv_working_alloca_h = yes; then ac_cv_func_alloca_works=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef alloca # ifdef __GNUC__ # define alloca __builtin_alloca # elif defined _MSC_VER # include # define alloca _alloca # else # ifdef __cplusplus extern "C" # endif void *alloca (size_t); # endif #endif int main (void) { char *p = (char *) alloca (1); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_func_alloca_works=yes else $as_nop ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 printf "%s\n" "$ac_cv_func_alloca_works" >&6; } fi if test $ac_cv_func_alloca_works = yes; then printf "%s\n" "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=\${LIBOBJDIR}alloca.$ac_objext printf "%s\n" "#define C_ALLOCA 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 printf %s "checking stack direction for C alloca... " >&6; } if test ${ac_cv_c_stack_direction+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_c_stack_direction=0 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int find_stack_direction (int *addr, int depth) { int dir, dummy = 0; if (! addr) addr = &dummy; *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; dir = depth ? find_stack_direction (addr, depth - 1) : 0; return dir + dummy; } int main (int argc, char **argv) { return find_stack_direction (0, argc + !argv + 20) < 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_stack_direction=1 else $as_nop ac_cv_c_stack_direction=-1 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 printf "%s\n" "$ac_cv_c_stack_direction" >&6; } printf "%s\n" "#define STACK_DIRECTION $ac_cv_c_stack_direction" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "waitpid" "ac_cv_func_waitpid" if test "x$ac_cv_func_waitpid" = xyes then : printf "%s\n" "#define HAVE_WAITPID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wait4" "ac_cv_func_wait4" if test "x$ac_cv_func_wait4" = xyes then : printf "%s\n" "#define HAVE_WAIT4 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "chown" "ac_cv_func_chown" if test "x$ac_cv_func_chown" = xyes then : printf "%s\n" "#define HAVE_CHOWN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "chmod" "ac_cv_func_chmod" if test "x$ac_cv_func_chmod" = xyes then : printf "%s\n" "#define HAVE_CHMOD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lchmod" "ac_cv_func_lchmod" if test "x$ac_cv_func_lchmod" = xyes then : printf "%s\n" "#define HAVE_LCHMOD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mknod" "ac_cv_func_mknod" if test "x$ac_cv_func_mknod" = xyes then : printf "%s\n" "#define HAVE_MKNOD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkfifo" "ac_cv_func_mkfifo" if test "x$ac_cv_func_mkfifo" = xyes then : printf "%s\n" "#define HAVE_MKFIFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "fchmod" "ac_cv_func_fchmod" if test "x$ac_cv_func_fchmod" = xyes then : printf "%s\n" "#define HAVE_FCHMOD 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "fstat" "ac_cv_func_fstat" if test "x$ac_cv_func_fstat" = xyes then : printf "%s\n" "#define HAVE_FSTAT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "ftruncate" "ac_cv_func_ftruncate" if test "x$ac_cv_func_ftruncate" = xyes then : printf "%s\n" "#define HAVE_FTRUNCATE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strchr" "ac_cv_func_strchr" if test "x$ac_cv_func_strchr" = xyes then : printf "%s\n" "#define HAVE_STRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "readlink" "ac_cv_func_readlink" if test "x$ac_cv_func_readlink" = xyes then : printf "%s\n" "#define HAVE_READLINK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "link" "ac_cv_func_link" if test "x$ac_cv_func_link" = xyes then : printf "%s\n" "#define HAVE_LINK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "utime" "ac_cv_func_utime" if test "x$ac_cv_func_utime" = xyes then : printf "%s\n" "#define HAVE_UTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" if test "x$ac_cv_func_utimes" = xyes then : printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lutimes" "ac_cv_func_lutimes" if test "x$ac_cv_func_lutimes" = xyes then : printf "%s\n" "#define HAVE_LUTIMES 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime" if test "x$ac_cv_func_strftime" = xyes then : printf "%s\n" "#define HAVE_STRFTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" if test "x$ac_cv_func_chflags" = xyes then : printf "%s\n" "#define HAVE_CHFLAGS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getattrlist" "ac_cv_func_getattrlist" if test "x$ac_cv_func_getattrlist" = xyes then : printf "%s\n" "#define HAVE_GETATTRLIST 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mktime" "ac_cv_func_mktime" if test "x$ac_cv_func_mktime" = xyes then : printf "%s\n" "#define HAVE_MKTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "innetgr" "ac_cv_func_innetgr" if test "x$ac_cv_func_innetgr" = xyes then : printf "%s\n" "#define HAVE_INNETGR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "linkat" "ac_cv_func_linkat" if test "x$ac_cv_func_linkat" = xyes then : printf "%s\n" "#define HAVE_LINKAT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memmove" "ac_cv_func_memmove" if test "x$ac_cv_func_memmove" = xyes then : printf "%s\n" "#define HAVE_MEMMOVE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lchown" "ac_cv_func_lchown" if test "x$ac_cv_func_lchown" = xyes then : printf "%s\n" "#define HAVE_LCHOWN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = xyes then : printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf" if test "x$ac_cv_func_vasprintf" = xyes then : printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = xyes then : printf "%s\n" "#define HAVE_ASPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid" if test "x$ac_cv_func_setsid" = xyes then : printf "%s\n" "#define HAVE_SETSID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strpbrk" "ac_cv_func_strpbrk" if test "x$ac_cv_func_strpbrk" = xyes then : printf "%s\n" "#define HAVE_STRPBRK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" if test "x$ac_cv_func_strlcat" = xyes then : printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : printf "%s\n" "#define HAVE_STRLCPY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtol" "ac_cv_func_strtol" if test "x$ac_cv_func_strtol" = xyes then : printf "%s\n" "#define HAVE_STRTOL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mallinfo" "ac_cv_func_mallinfo" if test "x$ac_cv_func_mallinfo" = xyes then : printf "%s\n" "#define HAVE_MALLINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mallinfo2" "ac_cv_func_mallinfo2" if test "x$ac_cv_func_mallinfo2" = xyes then : printf "%s\n" "#define HAVE_MALLINFO2 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups" if test "x$ac_cv_func_getgroups" = xyes then : printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setgroups" "ac_cv_func_setgroups" if test "x$ac_cv_func_setgroups" = xyes then : printf "%s\n" "#define HAVE_SETGROUPS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid" if test "x$ac_cv_func_geteuid" = xyes then : printf "%s\n" "#define HAVE_GETEUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getegid" "ac_cv_func_getegid" if test "x$ac_cv_func_getegid" = xyes then : printf "%s\n" "#define HAVE_GETEGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" if test "x$ac_cv_func_setlocale" = xyes then : printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setmode" "ac_cv_func_setmode" if test "x$ac_cv_func_setmode" = xyes then : printf "%s\n" "#define HAVE_SETMODE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "open64" "ac_cv_func_open64" if test "x$ac_cv_func_open64" = xyes then : printf "%s\n" "#define HAVE_OPEN64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "#define HAVE_LSEEK64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkstemp64" "ac_cv_func_mkstemp64" if test "x$ac_cv_func_mkstemp64" = xyes then : printf "%s\n" "#define HAVE_MKSTEMP64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mtrace" "ac_cv_func_mtrace" if test "x$ac_cv_func_mtrace" = xyes then : printf "%s\n" "#define HAVE_MTRACE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "va_copy" "ac_cv_func_va_copy" if test "x$ac_cv_func_va_copy" = xyes then : printf "%s\n" "#define HAVE_VA_COPY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "__va_copy" "ac_cv_func___va_copy" if test "x$ac_cv_func___va_copy" = xyes then : printf "%s\n" "#define HAVE___VA_COPY 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid" if test "x$ac_cv_func_seteuid" = xyes then : printf "%s\n" "#define HAVE_SETEUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strerror" "ac_cv_func_strerror" if test "x$ac_cv_func_strerror" = xyes then : printf "%s\n" "#define HAVE_STRERROR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "putenv" "ac_cv_func_putenv" if test "x$ac_cv_func_putenv" = xyes then : printf "%s\n" "#define HAVE_PUTENV 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "iconv_open" "ac_cv_func_iconv_open" if test "x$ac_cv_func_iconv_open" = xyes then : printf "%s\n" "#define HAVE_ICONV_OPEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "locale_charset" "ac_cv_func_locale_charset" if test "x$ac_cv_func_locale_charset" = xyes then : printf "%s\n" "#define HAVE_LOCALE_CHARSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getxattr" "ac_cv_func_getxattr" if test "x$ac_cv_func_getxattr" = xyes then : printf "%s\n" "#define HAVE_GETXATTR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "extattr_get_link" "ac_cv_func_extattr_get_link" if test "x$ac_cv_func_extattr_get_link" = xyes then : printf "%s\n" "#define HAVE_EXTATTR_GET_LINK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction" if test "x$ac_cv_func_sigaction" = xyes then : printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sigprocmask" "ac_cv_func_sigprocmask" if test "x$ac_cv_func_sigprocmask" = xyes then : printf "%s\n" "#define HAVE_SIGPROCMASK 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setattrlist" "ac_cv_func_setattrlist" if test "x$ac_cv_func_setattrlist" = xyes then : printf "%s\n" "#define HAVE_SETATTRLIST 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist" if test "x$ac_cv_func_getgrouplist" = xyes then : printf "%s\n" "#define HAVE_GETGROUPLIST 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups" if test "x$ac_cv_func_initgroups" = xyes then : printf "%s\n" "#define HAVE_INITGROUPS 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "utimensat" "ac_cv_func_utimensat" if test "x$ac_cv_func_utimensat" = xyes then : printf "%s\n" "#define HAVE_UTIMENSAT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate" if test "x$ac_cv_func_posix_fallocate" = xyes then : printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "attropen" "ac_cv_func_attropen" if test "x$ac_cv_func_attropen" = xyes then : printf "%s\n" "#define HAVE_ATTROPEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setvbuf" "ac_cv_func_setvbuf" if test "x$ac_cv_func_setvbuf" = xyes then : printf "%s\n" "#define HAVE_SETVBUF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" if test "x$ac_cv_func_nanosleep" = xyes then : printf "%s\n" "#define HAVE_NANOSLEEP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep" if test "x$ac_cv_func_usleep" = xyes then : printf "%s\n" "#define HAVE_USLEEP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setenv" "ac_cv_func_setenv" if test "x$ac_cv_func_setenv" = xyes then : printf "%s\n" "#define HAVE_SETENV 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv" if test "x$ac_cv_func_unsetenv" = xyes then : printf "%s\n" "#define HAVE_UNSETENV 1" >>confdefs.h fi if test x"$ac_cv_func_iconv_open" != x"yes"; then ac_fn_c_check_func "$LINENO" "libiconv_open" "ac_cv_func_libiconv_open" if test "x$ac_cv_func_libiconv_open" = xyes then : ac_cv_func_iconv_open=yes; printf "%s\n" "#define HAVE_ICONV_OPEN 1" >>confdefs.h fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for useable fallocate" >&5 printf %s "checking for useable fallocate... " >&6; } if test ${rsync_cv_have_fallocate+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_SYS_TYPES_H #include #endif int main (void) { fallocate(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : rsync_cv_have_fallocate=yes else $as_nop rsync_cv_have_fallocate=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_have_fallocate" >&5 printf "%s\n" "$rsync_cv_have_fallocate" >&6; } if test x"$rsync_cv_have_fallocate" = x"yes"; then printf "%s\n" "#define HAVE_FALLOCATE 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FALLOC_FL_PUNCH_HOLE" >&5 printf %s "checking for FALLOC_FL_PUNCH_HOLE... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE 1 #include #ifndef FALLOC_FL_PUNCH_HOLE #error FALLOC_FL_PUNCH_HOLE is missing #endif _ACEOF if ac_fn_c_try_cpp "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_FALLOC_FL_PUNCH_HOLE 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f conftest.err conftest.i conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FALLOC_FL_ZERO_RANGE" >&5 printf %s "checking for FALLOC_FL_ZERO_RANGE... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE 1 #include #ifndef FALLOC_FL_ZERO_RANGE #error FALLOC_FL_ZERO_RANGE is missing #endif _ACEOF if ac_fn_c_try_cpp "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_FALLOC_FL_ZERO_RANGE 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f conftest.err conftest.i conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SYS_fallocate" >&5 printf %s "checking for SYS_fallocate... " >&6; } if test ${rsync_cv_have_sys_fallocate+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif int main (void) { syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_have_sys_fallocate=yes else $as_nop rsync_cv_have_sys_fallocate=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_have_sys_fallocate" >&5 printf "%s\n" "$rsync_cv_have_sys_fallocate" >&6; } if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then printf "%s\n" "#define HAVE_SYS_FALLOCATE 1" >>confdefs.h fi if test x"$ac_cv_func_posix_fallocate" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_fallocate is efficient" >&5 printf %s "checking whether posix_fallocate is efficient... " >&6; } case $host_os in *cygwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_EFFICIENT_POSIX_FALLOCATE 1" >>confdefs.h ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi ac_fn_c_check_func "$LINENO" "getpgrp" "ac_cv_func_getpgrp" if test "x$ac_cv_func_getpgrp" = xyes then : printf "%s\n" "#define HAVE_GETPGRP 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp" if test "x$ac_cv_func_tcgetpgrp" = xyes then : printf "%s\n" "#define HAVE_TCGETPGRP 1" >>confdefs.h fi if test $ac_cv_func_getpgrp = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getpgrp requires zero arguments" >&5 printf %s "checking whether getpgrp requires zero arguments... " >&6; } if test ${ac_cv_func_getpgrp_void+y} then : printf %s "(cached) " >&6 else $as_nop # Use it with a single arg. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { getpgrp (0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_func_getpgrp_void=no else $as_nop ac_cv_func_getpgrp_void=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpgrp_void" >&5 printf "%s\n" "$ac_cv_func_getpgrp_void" >&6; } if test $ac_cv_func_getpgrp_void = yes; then printf "%s\n" "#define GETPGRP_VOID 1" >>confdefs.h fi fi # Check whether --enable-iconv-open was given. if test ${enable_iconv_open+y} then : enableval=$enable_iconv_open; else $as_nop enable_iconv_open=$ac_cv_func_iconv_open fi if test x"$enable_iconv_open" != x"no"; then printf "%s\n" "#define USE_ICONV_OPEN 1" >>confdefs.h fi # Check whether --enable-iconv was given. if test ${enable_iconv+y} then : enableval=$enable_iconv; else $as_nop enable_iconv=$enable_iconv_open fi if test x"$enable_iconv" != x"no"; then if test x"$enable_iconv" = x"yes"; then printf "%s\n" "#define ICONV_OPTION NULL" >>confdefs.h else printf "%s\n" "#define ICONV_OPTION \"$enable_iconv\"" >>confdefs.h fi printf "%s\n" "#define UTF8_CHARSET \"UTF-8\"" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether chown() modifies symlinks" >&5 printf %s "checking whether chown() modifies symlinks... " >&6; } if test ${rsync_cv_chown_modifies_symlink+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_chown_modifies_symlink=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif #include #include int main(void) { char const *dangling_symlink = "conftest.dangle"; unlink(dangling_symlink); if (symlink("conftest.no-such", dangling_symlink) < 0) abort(); if (chown(dangling_symlink, getuid(), getgid()) < 0 && errno == ENOENT) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_chown_modifies_symlink=yes else $as_nop rsync_cv_chown_modifies_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_chown_modifies_symlink" >&5 printf "%s\n" "$rsync_cv_chown_modifies_symlink" >&6; } if test $rsync_cv_chown_modifies_symlink = yes; then printf "%s\n" "#define CHOWN_MODIFIES_SYMLINK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether link() can hard-link symlinks" >&5 printf %s "checking whether link() can hard-link symlinks... " >&6; } if test ${rsync_cv_can_hardlink_symlink+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_can_hardlink_symlink=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_FCNTL_H # include #elif defined HAVE_SYS_FCNTL_H # include #endif #if HAVE_UNISTD_H # include #endif #include #include #define FILENAME "conftest.dangle" int main(void) { unlink(FILENAME); if (symlink("conftest.no-such", FILENAME) < 0) abort(); unlink(FILENAME "2"); #ifdef HAVE_LINKAT if (linkat(AT_FDCWD, FILENAME, AT_FDCWD, FILENAME "2", 0) < 0) return 1; #else if (link(FILENAME, FILENAME "2") < 0) return 1; #endif return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_can_hardlink_symlink=yes else $as_nop rsync_cv_can_hardlink_symlink=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_can_hardlink_symlink" >&5 printf "%s\n" "$rsync_cv_can_hardlink_symlink" >&6; } if test $rsync_cv_can_hardlink_symlink = yes; then printf "%s\n" "#define CAN_HARDLINK_SYMLINK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether link() can hard-link special files" >&5 printf %s "checking whether link() can hard-link special files... " >&6; } if test ${rsync_cv_can_hardlink_special+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_can_hardlink_special=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include #include #define FILENAME "conftest.fifi" int main(void) { unlink(FILENAME); if (mkfifo(FILENAME, 0777) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_can_hardlink_special=yes else $as_nop rsync_cv_can_hardlink_special=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_can_hardlink_special" >&5 printf "%s\n" "$rsync_cv_can_hardlink_special" >&6; } if test $rsync_cv_can_hardlink_special = yes; then printf "%s\n" "#define CAN_HARDLINK_SPECIAL 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working socketpair" >&5 printf %s "checking for working socketpair... " >&6; } if test ${rsync_cv_HAVE_SOCKETPAIR+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_HAVE_SOCKETPAIR=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif int main(void) { int fd[2]; return (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_HAVE_SOCKETPAIR=yes else $as_nop rsync_cv_HAVE_SOCKETPAIR=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_SOCKETPAIR" >&5 printf "%s\n" "$rsync_cv_HAVE_SOCKETPAIR" >&6; } if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then printf "%s\n" "#define HAVE_SOCKETPAIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "getpass" "ac_cv_func_getpass" if test "x$ac_cv_func_getpass" = xyes then : printf "%s\n" "#define HAVE_GETPASS 1" >>confdefs.h else $as_nop case " $LIBOBJS " in *" getpass.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getpass.$ac_objext" ;; esac fi if test x"$with_included_popt" != x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for poptGetContext in -lpopt" >&5 printf %s "checking for poptGetContext in -lpopt... " >&6; } if test ${ac_cv_lib_popt_poptGetContext+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpopt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char poptGetContext (); int main (void) { return poptGetContext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_popt_poptGetContext=yes else $as_nop ac_cv_lib_popt_poptGetContext=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_popt_poptGetContext" >&5 printf "%s\n" "$ac_cv_lib_popt_poptGetContext" >&6; } if test "x$ac_cv_lib_popt_poptGetContext" = xyes then : printf "%s\n" "#define HAVE_LIBPOPT 1" >>confdefs.h LIBS="-lpopt $LIBS" else $as_nop with_included_popt=yes fi fi if test x"$ac_cv_header_popt_popt_h" = x"yes"; then # If the system has /usr/include/popt/popt.h, we enable the # included popt because an attempt to "#include " # would use our included header file anyway (due to -I.), and # might conflict with the system popt. with_included_popt=yes elif test x"$ac_cv_header_popt_h" != x"yes"; then with_included_popt=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use included libpopt" >&5 printf %s "checking whether to use included libpopt... " >&6; } if test x"$with_included_popt" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $srcdir/popt" >&5 printf "%s\n" "$srcdir/popt" >&6; } BUILD_POPT='$(popt_OBJS)' CFLAGS="-I$srcdir/popt $CFLAGS" if test x"$ALLOCA" != x then # this can be removed when/if we add an included alloca.c; # see autoconf documentation on AC_FUNC_ALLOCA { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&5 printf "%s\n" "$as_me: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&2;} fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # We default to using our zlib unless --with-included-zlib=no is given. if test x"$with_included_zlib" != x"no"; then with_included_zlib=yes elif test x"$ac_cv_header_zlib_h" != x"yes"; then with_included_zlib=yes fi if test x"$with_included_zlib" != x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for deflateParams in -lz" >&5 printf %s "checking for deflateParams in -lz... " >&6; } if test ${ac_cv_lib_z_deflateParams+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char deflateParams (); int main (void) { return deflateParams (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_z_deflateParams=yes else $as_nop ac_cv_lib_z_deflateParams=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflateParams" >&5 printf "%s\n" "$ac_cv_lib_z_deflateParams" >&6; } if test "x$ac_cv_lib_z_deflateParams" = xyes then : printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h LIBS="-lz $LIBS" else $as_nop with_included_zlib=yes fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use included zlib" >&5 printf %s "checking whether to use included zlib... " >&6; } if test x"$with_included_zlib" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $srcdir/zlib" >&5 printf "%s\n" "$srcdir/zlib" >&6; } BUILD_ZLIB='$(zlib_OBJS)' CFLAGS="-I$srcdir/zlib $CFLAGS" else printf "%s\n" "#define EXTERNAL_ZLIB 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unsigned char" >&5 printf %s "checking for unsigned char... " >&6; } if test ${rsync_cv_SIGNED_CHAR_OK+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { signed char *s = (signed char *)"" ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_SIGNED_CHAR_OK=yes else $as_nop rsync_cv_SIGNED_CHAR_OK=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_SIGNED_CHAR_OK" >&5 printf "%s\n" "$rsync_cv_SIGNED_CHAR_OK" >&6; } if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then printf "%s\n" "#define SIGNED_CHAR_OK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken readdir" >&5 printf %s "checking for broken readdir... " >&6; } if test ${rsync_cv_HAVE_BROKEN_READDIR+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_HAVE_BROKEN_READDIR=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #include int main(void) { struct dirent *di; DIR *d = opendir("."); di = readdir(d); if (di && di->d_name[-2] == '.' && di->d_name[-1] == 0 && di->d_name[0] == 0) return 0; return 1;} _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_HAVE_BROKEN_READDIR=yes else $as_nop rsync_cv_HAVE_BROKEN_READDIR=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_BROKEN_READDIR" >&5 printf "%s\n" "$rsync_cv_HAVE_BROKEN_READDIR" >&6; } if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then printf "%s\n" "#define HAVE_BROKEN_READDIR 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for utimbuf" >&5 printf %s "checking for utimbuf... " >&6; } if test ${rsync_cv_HAVE_STRUCT_UTIMBUF+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #include int main (void) { struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_HAVE_STRUCT_UTIMBUF=yes else $as_nop rsync_cv_HAVE_STRUCT_UTIMBUF=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_STRUCT_UTIMBUF" >&5 printf "%s\n" "$rsync_cv_HAVE_STRUCT_UTIMBUF" >&6; } if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then printf "%s\n" "#define HAVE_STRUCT_UTIMBUF 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if gettimeofday takes tz argument" >&5 printf %s "checking if gettimeofday takes tz argument... " >&6; } if test ${rsync_cv_HAVE_GETTIMEOFDAY_TZ+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_UNISTD_H #include #endif int main (void) { struct timeval tv; return gettimeofday(&tv, NULL); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes else $as_nop rsync_cv_HAVE_GETTIMEOFDAY_TZ=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&5 printf "%s\n" "$rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&6; } if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then printf "%s\n" "#define HAVE_GETTIMEOFDAY_TZ 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C99 vsnprintf" >&5 printf %s "checking for C99 vsnprintf... " >&6; } if test ${rsync_cv_HAVE_C99_VSNPRINTF+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_HAVE_C99_VSNPRINTF=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #include #include #if HAVE_STDLIB_H #include #endif #include void foo(const char *format, ...) { va_list ap; int len; static char buf[] = "12345678901234567890"; va_start(ap, format); len = vsnprintf(0, 0, format, ap); va_end(ap); if (len != 5) exit(1); if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1); } int main(void) { foo("hello"); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_HAVE_C99_VSNPRINTF=yes else $as_nop rsync_cv_HAVE_C99_VSNPRINTF=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_C99_VSNPRINTF" >&5 printf "%s\n" "$rsync_cv_HAVE_C99_VSNPRINTF" >&6; } if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then printf "%s\n" "#define HAVE_C99_VSNPRINTF 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for secure mkstemp" >&5 printf %s "checking for secure mkstemp... " >&6; } if test ${rsync_cv_HAVE_SECURE_MKSTEMP+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_HAVE_SECURE_MKSTEMP=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef HAVE_SYS_TYPES_H #include #endif #include #ifdef HAVE_UNISTD_H #include #endif int main(void) { struct stat st; char tpl[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); if (fd == -1) return 1; unlink(tpl); if (fstat(fd, &st) != 0) return 1; if ((st.st_mode & 0777) != 0600) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_HAVE_SECURE_MKSTEMP=yes else $as_nop rsync_cv_HAVE_SECURE_MKSTEMP=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_SECURE_MKSTEMP" >&5 printf "%s\n" "$rsync_cv_HAVE_SECURE_MKSTEMP" >&6; } if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then case $host_os in hpux*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Skipping broken HP-UX mkstemp() -- using mktemp() instead" >&5 printf "%s\n" "$as_me: WARNING: Skipping broken HP-UX mkstemp() -- using mktemp() instead" >&2;} ;; *) printf "%s\n" "#define HAVE_SECURE_MKSTEMP 1" >>confdefs.h ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if mknod creates FIFOs" >&5 printf %s "checking if mknod creates FIFOs... " >&6; } if test ${rsync_cv_MKNOD_CREATES_FIFOS+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_MKNOD_CREATES_FIFOS=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #if HAVE_UNISTD_H # include #endif int main(void) { int rc, ec; char *fn = "fifo-test"; unlink(fn); rc = mknod(fn,S_IFIFO,0600); ec = errno; unlink(fn); if (rc) {printf("(%d %d) ",rc,ec); return ec;} return 0;} _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_MKNOD_CREATES_FIFOS=yes else $as_nop rsync_cv_MKNOD_CREATES_FIFOS=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MKNOD_CREATES_FIFOS" >&5 printf "%s\n" "$rsync_cv_MKNOD_CREATES_FIFOS" >&6; } if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then printf "%s\n" "#define MKNOD_CREATES_FIFOS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if mknod creates sockets" >&5 printf %s "checking if mknod creates sockets... " >&6; } if test ${rsync_cv_MKNOD_CREATES_SOCKETS+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : rsync_cv_MKNOD_CREATES_SOCKETS=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #if HAVE_UNISTD_H # include #endif int main(void) { int rc, ec; char *fn = "sock-test"; unlink(fn); rc = mknod(fn,S_IFSOCK,0600); ec = errno; unlink(fn); if (rc) {printf("(%d %d) ",rc,ec); return ec;} return 0;} _ACEOF if ac_fn_c_try_run "$LINENO" then : rsync_cv_MKNOD_CREATES_SOCKETS=yes else $as_nop rsync_cv_MKNOD_CREATES_SOCKETS=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MKNOD_CREATES_SOCKETS" >&5 printf "%s\n" "$rsync_cv_MKNOD_CREATES_SOCKETS" >&6; } if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then printf "%s\n" "#define MKNOD_CREATES_SOCKETS 1" >>confdefs.h fi # # The following test was mostly taken from the tcl/tk plus patches # { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -c -o works" >&5 printf %s "checking whether -c -o works... " >&6; } if test ${rsync_cv_DASHC_WORKS_WITH_DASHO+y} then : printf %s "(cached) " >&6 else $as_nop rm -rf conftest* cat > conftest.$ac_ext <&5 printf "%s\n" "$rsync_cv_DASHC_WORKS_WITH_DASHO" >&6; } if test x"$rsync_cv_DASHC_WORKS_WITH_DASHO" = x"yes"; then OBJ_SAVE="#" OBJ_RESTORE="#" CC_SHOBJ_FLAG='-o $@' else OBJ_SAVE=' @b=`basename $@ .o`;rm -f $$b.o.sav;if test -f $$b.o; then mv $$b.o $$b.o.sav;fi;' OBJ_RESTORE=' @b=`basename $@ .o`;if test "$$b.o" != "$@"; then mv $$b.o $@; if test -f $$b.o.sav; then mv $$b.o.sav $$b.o; fi; fi' CC_SHOBJ_FLAG="" fi ac_fn_c_check_func "$LINENO" "_acl" "ac_cv_func__acl" if test "x$ac_cv_func__acl" = xyes then : printf "%s\n" "#define HAVE__ACL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "__acl" "ac_cv_func___acl" if test "x$ac_cv_func___acl" = xyes then : printf "%s\n" "#define HAVE___ACL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "_facl" "ac_cv_func__facl" if test "x$ac_cv_func__facl" = xyes then : printf "%s\n" "#define HAVE__FACL 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "__facl" "ac_cv_func___facl" if test "x$ac_cv_func___facl" = xyes then : printf "%s\n" "#define HAVE___FACL 1" >>confdefs.h fi ################################################# # check for ACL support { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support ACLs" >&5 printf %s "checking whether to support ACLs... " >&6; } # Check whether --enable-acl-support was given. if test ${enable_acl_support+y} then : enableval=$enable_acl_support; fi if test x"$enable_acl_support" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else case "$host_os" in *sysv5*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using UnixWare ACLs" >&5 printf "%s\n" "Using UnixWare ACLs" >&6; } printf "%s\n" "#define HAVE_UNIXWARE_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; solaris*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using solaris ACLs" >&5 printf "%s\n" "Using solaris ACLs" >&6; } printf "%s\n" "#define HAVE_SOLARIS_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; *irix*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using IRIX ACLs" >&5 printf "%s\n" "Using IRIX ACLs" >&6; } printf "%s\n" "#define HAVE_IRIX_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; *aix*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using AIX ACLs" >&5 printf "%s\n" "Using AIX ACLs" >&6; } printf "%s\n" "#define HAVE_AIX_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; *osf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using Tru64 ACLs" >&5 printf "%s\n" "Using Tru64 ACLs" >&6; } printf "%s\n" "#define HAVE_TRU64_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h LIBS="$LIBS -lpacl" ;; darwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using OS X ACLs" >&5 printf "%s\n" "Using OS X ACLs" >&6; } printf "%s\n" "#define HAVE_OSX_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; *hpux*|*nsk*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using HPUX ACLs" >&5 printf "%s\n" "Using HPUX ACLs" >&6; } printf "%s\n" "#define HAVE_HPUX_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: running tests:" >&5 printf "%s\n" "running tests:" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lacl" >&5 printf %s "checking for acl_get_file in -lacl... " >&6; } if test ${ac_cv_lib_acl_acl_get_file+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lacl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char acl_get_file (); int main (void) { return acl_get_file (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_acl_acl_get_file=yes else $as_nop ac_cv_lib_acl_acl_get_file=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_acl_acl_get_file" >&5 printf "%s\n" "$ac_cv_lib_acl_acl_get_file" >&6; } if test "x$ac_cv_lib_acl_acl_get_file" = xyes then : printf "%s\n" "#define HAVE_LIBACL 1" >>confdefs.h LIBS="-lacl $LIBS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ACL support" >&5 printf %s "checking for ACL support... " >&6; } if test ${samba_cv_HAVE_POSIX_ACLS+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_ACL_H #include #endif int main (void) { acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : samba_cv_HAVE_POSIX_ACLS=yes else $as_nop samba_cv_HAVE_POSIX_ACLS=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_POSIX_ACLS" >&5 printf "%s\n" "$samba_cv_HAVE_POSIX_ACLS" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ACL test results" >&5 printf %s "checking ACL test results... " >&6; } if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using posix ACLs" >&5 printf "%s\n" "Using posix ACLs" >&6; } printf "%s\n" "#define HAVE_POSIX_ACLS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_ACLS 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for acl_get_perm_np" >&5 printf %s "checking for acl_get_perm_np... " >&6; } if test ${samba_cv_HAVE_ACL_GET_PERM_NP+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_ACL_H #include #endif int main (void) { acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : samba_cv_HAVE_ACL_GET_PERM_NP=yes else $as_nop samba_cv_HAVE_ACL_GET_PERM_NP=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_ACL_GET_PERM_NP" >&5 printf "%s\n" "$samba_cv_HAVE_ACL_GET_PERM_NP" >&6; } if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then printf "%s\n" "#define HAVE_ACL_GET_PERM_NP 1" >>confdefs.h fi else if test x"$enable_acl_support" = x"yes"; then as_fn_error $? "Failed to find ACL support" "$LINENO" 5 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: No ACL support found" >&5 printf "%s\n" "No ACL support found" >&6; } fi fi ;; esac fi ################################################# # check for extended attribute support { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support extended attributes" >&5 printf %s "checking whether to support extended attributes... " >&6; } # Check whether --enable-xattr-support was given. if test ${enable_xattr_support+y} then : enableval=$enable_xattr_support; else $as_nop case "$ac_cv_func_getxattr$ac_cv_func_extattr_get_link$ac_cv_func_attropen" in *yes*) enable_xattr_support=maybe ;; *) enable_xattr_support=no ;; esac fi if test x"$enable_xattr_support" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else case "$host_os" in *linux*|*netbsd*|*cygwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using Linux xattrs" >&5 printf "%s\n" "Using Linux xattrs" >&6; } printf "%s\n" "#define HAVE_LINUX_XATTRS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_XATTRS 1" >>confdefs.h printf "%s\n" "#define NO_SYMLINK_USER_XATTRS 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getxattr in -lattr" >&5 printf %s "checking for getxattr in -lattr... " >&6; } if test ${ac_cv_lib_attr_getxattr+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lattr $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char getxattr (); int main (void) { return getxattr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_attr_getxattr=yes else $as_nop ac_cv_lib_attr_getxattr=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_getxattr" >&5 printf "%s\n" "$ac_cv_lib_attr_getxattr" >&6; } if test "x$ac_cv_lib_attr_getxattr" = xyes then : printf "%s\n" "#define HAVE_LIBATTR 1" >>confdefs.h LIBS="-lattr $LIBS" fi ;; darwin*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using OS X xattrs" >&5 printf "%s\n" "Using OS X xattrs" >&6; } printf "%s\n" "#define HAVE_OSX_XATTRS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_XATTRS 1" >>confdefs.h printf "%s\n" "#define NO_DEVICE_XATTRS 1" >>confdefs.h printf "%s\n" "#define NO_SPECIAL_XATTRS 1" >>confdefs.h ;; freebsd*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using FreeBSD extattrs" >&5 printf "%s\n" "Using FreeBSD extattrs" >&6; } printf "%s\n" "#define HAVE_FREEBSD_XATTRS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_XATTRS 1" >>confdefs.h ;; solaris*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using Solaris xattrs" >&5 printf "%s\n" "Using Solaris xattrs" >&6; } printf "%s\n" "#define HAVE_SOLARIS_XATTRS 1" >>confdefs.h printf "%s\n" "#define SUPPORT_XATTRS 1" >>confdefs.h printf "%s\n" "#define NO_SYMLINK_XATTRS 1" >>confdefs.h ;; *) if test x"$enable_xattr_support" = x"yes"; then as_fn_error $? "Failed to find extended attribute support" "$LINENO" 5 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: No extended attribute support found" >&5 printf "%s\n" "No extended attribute support found" >&6; } fi ;; esac fi if test x"$enable_acl_support" = x"no" || test x"$enable_xattr_support" = x"no" || test x"$enable_iconv" = x"no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-parameter" >&5 printf %s "checking whether $CC supports -Wno-unused-parameter... " >&6; } OLD_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wno-unused-parameter" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { printf("hello\n"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : rsync_warn_flag=yes else $as_nop rsync_warn_flag=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $rsync_warn_flag" >&5 printf "%s\n" "$rsync_warn_flag" >&6; } if test x"$rsync_warn_flag" = x"no"; then CFLAGS="$OLD_CFLAGS" fi fi case "$CC" in ' checker'*|checker*) printf "%s\n" "#define FORCE_FD_ZERO_MEMSET 1" >>confdefs.h ;; esac ac_config_files="$ac_config_files Makefile lib/dummy zlib/dummy popt/dummy shconfig" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by rsync $as_me, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ rsync config.status configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "lib/dummy") CONFIG_FILES="$CONFIG_FILES lib/dummy" ;; "zlib/dummy") CONFIG_FILES="$CONFIG_FILES zlib/dummy" ;; "popt/dummy") CONFIG_FILES="$CONFIG_FILES popt/dummy" ;; "shconfig") CONFIG_FILES="$CONFIG_FILES shconfig" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5 printf "%s\n" "" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: rsync $PACKAGE_VERSION configuration successful" >&5 printf "%s\n" " rsync $PACKAGE_VERSION configuration successful" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5 printf "%s\n" "" >&6; } rsync-3.2.7/rsyncsh.txt0000664000000000000000000000247307343363462013633 0ustar rootrootrsyncsh Copyright (C) 2001 by Martin Pool This is a quick hack to build an interactive shell around rsync, the same way we have the ftp, lftp and ncftp programs for the FTP protocol. The key application for this is connecting to a public rsync server, such as rsync.kernel.org, change down through and list directories, and finally pull down the file you want. rsync is somewhat ill-at-ease as an interactive operation, since every network connection is used to carry out exactly one operation. rsync kind of "forks across the network" passing the options and filenames to operate upon, and the connection is closed when the transfer is complete. (This might be fixed in the future, either by adapting the current protocol to allow chained operations over a single socket, or by writing a new protocol that better supports interactive use.) So, rsyncsh runs a new rsync command and opens a new socket for every (network-based) command you type. This has two consequences. Firstly, there is more command latency than is really desirable. More seriously, if the connection cannot be done automatically, because for example it uses SSH with a password, then you will need to enter the password every time. We might even fix this in the future, though, by having a way to automatically feed the password to SSH if it's entered once. rsync-3.2.7/rsync-ssl.1.md0000664000000000000000000001113114253733546014010 0ustar rootroot## NAME rsync-ssl - a helper script for connecting to an ssl rsync daemon ## SYNOPSIS ``` rsync-ssl [--type=SSL_TYPE] RSYNC_ARGS ``` The online version of this manpage (that includes cross-linking of topics) is available at . ## DESCRIPTION The rsync-ssl script helps you to run an rsync copy to/from an rsync daemon that requires ssl connections. The script requires that you specify an rsync-daemon arg in the style of either `hostname::` (with 2 colons) or `rsync://hostname/`. The default port used for connecting is 874 (one higher than the normal 873) unless overridden in the environment. You can specify an overriding port via `--port` or by including it in the normal spot in the URL format, though both of those require your rsync version to be at least 3.2.0. ## OPTIONS If the **first** arg is a `--type=SSL_TYPE` option, the script will only use that particular program to open an ssl connection instead of trying to find an openssl or stunnel executable via a simple heuristic (assuming that the `RSYNC_SSL_TYPE` environment variable is not set as well -- see below). This option must specify one of `openssl` or `stunnel`. The equal sign is required for this particular option. All the other options are passed through to the rsync command, so consult the **rsync**(1) manpage for more information on how it works. ## ENVIRONMENT VARIABLES The ssl helper scripts are affected by the following environment variables: 0. `RSYNC_SSL_TYPE` Specifies the program type that should be used to open the ssl connection. It must be one of `openssl` or `stunnel`. The `--type=SSL_TYPE` option overrides this, when specified. 0. `RSYNC_SSL_PORT` If specified, the value is the port number that is used as the default when the user does not specify a port in their rsync command. When not specified, the default port number is 874. (Note that older rsync versions (prior to 3.2.0) did not communicate an overriding port number value to the helper script.) 0. `RSYNC_SSL_CERT` If specified, the value is a filename that contains a certificate to use for the connection. 0. `RSYNC_SSL_KEY` If specified, the value is a filename that contains a key for the provided certificate to use for the connection. 0. `RSYNC_SSL_CA_CERT` If specified, the value is a filename that contains a certificate authority certificate that is used to validate the connection. 0. `RSYNC_SSL_OPENSSL` Specifies the openssl executable to run when the connection type is set to openssl. If unspecified, the $PATH is searched for "openssl". 0. `RSYNC_SSL_GNUTLS` Specifies the gnutls-cli executable to run when the connection type is set to gnutls. If unspecified, the $PATH is searched for "gnutls-cli". 0. `RSYNC_SSL_STUNNEL` Specifies the stunnel executable to run when the connection type is set to stunnel. If unspecified, the $PATH is searched first for "stunnel4" and then for "stunnel". ## EXAMPLES > rsync-ssl -aiv example.com::mod/ dest > rsync-ssl --type=openssl -aiv example.com::mod/ dest > rsync-ssl -aiv --port 9874 example.com::mod/ dest > rsync-ssl -aiv rsync://example.com:9874/mod/ dest ## THE SERVER SIDE For help setting up an SSL/TLS supporting rsync, see the [instructions in rsyncd.conf](rsyncd.conf.5#SSL_TLS_Daemon_Setup). ## SEE ALSO [**rsync**(1)](rsync.1), [**rsyncd.conf**(5)](rsyncd.conf.5) ## CAVEATS Note that using an stunnel connection requires at least version 4 of stunnel, which should be the case on modern systems. Also, it does not verify a connection against the CA certificate collection, so it only encrypts the connection without any cert validation unless you have specified the certificate environment options. This script also supports a `--type=gnutls` option, but at the time of this release the gnutls-cli command was dropping output, making it unusable. If that bug has been fixed in your version, feel free to put gnutls into an exported RSYNC_SSL_TYPE environment variable to make its use the default. ## BUGS Please report bugs! See the web site at . ## VERSION This manpage is current for version @VERSION@ of rsync. ## CREDITS Rsync is distributed under the GNU General Public License. See the file [COPYING](COPYING) for details. A web site is available at . The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page. ## AUTHOR This manpage was written by Wayne Davison. Mailing lists for support and development are available at . rsync-3.2.7/cleanup.c0000664000000000000000000001716613702777121013176 0ustar rootroot/* * End-of-run cleanup routines. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2020 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" extern int dry_run; extern int am_server; extern int am_daemon; extern int am_receiver; extern int am_sender; extern int io_error; extern int keep_partial; extern int got_xfer_error; extern int protocol_version; extern int output_needs_newline; extern char *partial_dir; extern char *logfile_name; int called_from_signal_handler = 0; BOOL shutting_down = False; BOOL flush_ok_after_signal = False; #ifdef HAVE_SIGACTION static struct sigaction sigact; #endif /** * Close all open sockets and files, allowing a (somewhat) graceful * shutdown() of socket connections. This eliminates the abortive * TCP RST sent by a Winsock-based system when the close() occurs. **/ void close_all(void) { #ifdef SHUTDOWN_ALL_SOCKETS int max_fd; int fd; int ret; STRUCT_STAT st; max_fd = sysconf(_SC_OPEN_MAX) - 1; for (fd = max_fd; fd >= 0; fd--) { if ((ret = do_fstat(fd, &st)) == 0) { if (is_a_socket(fd)) ret = shutdown(fd, 2); ret = close(fd); } } #endif } /** * @file cleanup.c * * Code for handling interrupted transfers. Depending on the @c * --partial option, we may either delete the temporary file, or go * ahead and overwrite the destination. This second behaviour only * occurs if we've sent literal data and therefore hopefully made * progress on the transfer. **/ /** * Set to True once literal data has been sent across the link for the * current file. (????) * * Handling the cleanup when a transfer is interrupted is tricky when * --partial is selected. We need to ensure that the partial file is * kept if any real data has been transferred. **/ int cleanup_got_literal = 0; static const char *cleanup_fname; static const char *cleanup_new_fname; static struct file_struct *cleanup_file; static int cleanup_fd_r = -1, cleanup_fd_w = -1; static pid_t cleanup_pid = 0; pid_t cleanup_child_pid = -1; /** * Eventually calls exit(), passing @p code, therefore does not return. * * @param code one of the RERR_* codes from errcode.h. **/ NORETURN void _exit_cleanup(int code, const char *file, int line) { static int switch_step = 0; static int exit_code = 0, exit_line = 0; static const char *exit_file = NULL; static int first_code = 0; SIGACTION(SIGUSR1, SIG_IGN); SIGACTION(SIGUSR2, SIG_IGN); if (!exit_code) { /* Preserve first error exit info when recursing. */ exit_code = code; exit_file = file; exit_line = line < 0 ? -line : line; } /* If this is the exit at the end of the run, the server side * should not attempt to output a message (see log_exit()). */ if (am_server && code == 0) am_server = 2; /* Some of our actions might cause a recursive call back here, so we * keep track of where we are in the cleanup and never repeat a step. */ switch (switch_step) { #include "case_N.h" /* case 0: */ switch_step++; first_code = code; if (output_needs_newline) { fputc('\n', stdout); output_needs_newline = 0; } if (DEBUG_GTE(EXIT, 2)) { rprintf(FINFO, "[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n", who_am_i(), code, src_file(file), line); } #include "case_N.h" switch_step++; if (cleanup_child_pid != -1) { int status; int pid = wait_process(cleanup_child_pid, &status, WNOHANG); if (pid == cleanup_child_pid) { status = WEXITSTATUS(status); if (status > exit_code) exit_code = status; } } #include "case_N.h" switch_step++; if (cleanup_got_literal && (cleanup_fname || cleanup_fd_w != -1)) { if (cleanup_fd_r != -1) { close(cleanup_fd_r); cleanup_fd_r = -1; } if (cleanup_fd_w != -1) { flush_write_file(cleanup_fd_w); close(cleanup_fd_w); cleanup_fd_w = -1; } if (cleanup_fname && cleanup_new_fname && keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) { int tweak_modtime = 0; const char *fname = cleanup_fname; cleanup_fname = NULL; if (!partial_dir) { /* We don't want to leave a partial file with a modern time or it * could be skipped via --update. Setting the time to something * really old also helps it to stand out as unfinished in an ls. */ tweak_modtime = 1; cleanup_file->modtime = 0; } finish_transfer(cleanup_new_fname, fname, NULL, NULL, cleanup_file, tweak_modtime, !partial_dir); } } #include "case_N.h" switch_step++; if (flush_ok_after_signal) { flush_ok_after_signal = False; if (code == RERR_SIGNAL) io_flush(FULL_FLUSH); } if (!exit_code && !code) io_flush(FULL_FLUSH); #include "case_N.h" switch_step++; if (cleanup_fname) do_unlink(cleanup_fname); if (exit_code) kill_all(SIGUSR1); if (cleanup_pid && cleanup_pid == getpid()) { char *pidf = lp_pid_file(); if (pidf && *pidf) unlink(lp_pid_file()); } if (exit_code == 0) { if (code) exit_code = code; if (io_error & IOERR_DEL_LIMIT) exit_code = RERR_DEL_LIMIT; if (io_error & IOERR_VANISHED) exit_code = RERR_VANISHED; if (io_error & IOERR_GENERAL || got_xfer_error) exit_code = RERR_PARTIAL; } /* If line < 0, this exit is after a MSG_ERROR_EXIT event, so * we don't want to output a duplicate error. */ if ((exit_code && line > 0) || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) { log_exit(exit_code, exit_file, exit_line); } #include "case_N.h" switch_step++; if (DEBUG_GTE(EXIT, 1)) { rprintf(FINFO, "[%s] _exit_cleanup(code=%d, file=%s, line=%d): " "about to call exit(%d)%s\n", who_am_i(), first_code, exit_file, exit_line, exit_code, dry_run ? " (DRY RUN)" : ""); } #include "case_N.h" switch_step++; if (exit_code && exit_code != RERR_SOCKETIO && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1 && exit_code != RERR_TIMEOUT && !shutting_down) { if (protocol_version >= 31 || am_receiver) { if (line > 0) { if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n", who_am_i(), exit_code); } send_msg_int(MSG_ERROR_EXIT, exit_code); } if (!am_sender) io_flush(MSG_FLUSH); /* Be sure to send all messages */ noop_io_until_death(); } else if (!am_sender) io_flush(MSG_FLUSH); /* Be sure to send all messages */ } #include "case_N.h" switch_step++; if (am_server && exit_code) msleep(100); close_all(); /* FALLTHROUGH */ default: break; } if (called_from_signal_handler) _exit(exit_code); exit(exit_code); } void cleanup_disable(void) { cleanup_fname = cleanup_new_fname = NULL; cleanup_fd_r = cleanup_fd_w = -1; cleanup_got_literal = 0; } void cleanup_set(const char *fnametmp, const char *fname, struct file_struct *file, int fd_r, int fd_w) { cleanup_fname = fnametmp; cleanup_new_fname = fname; /* can be NULL on a partial-dir failure */ cleanup_file = file; cleanup_fd_r = fd_r; cleanup_fd_w = fd_w; } void cleanup_set_pid(pid_t pid) { cleanup_pid = pid; } rsync-3.2.7/acls.c0000664000000000000000000007360614307412432012463 0ustar rootroot/* * Handle passing Access Control Lists between systems. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2006-2022 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 "lib/sysacls.h" #ifdef SUPPORT_ACLS extern int dry_run; extern int am_root; extern int read_only; extern int list_only; extern int orig_umask; extern int numeric_ids; extern int inc_recurse; extern int preserve_devices; extern int preserve_specials; /* Flags used to indicate what items are being transmitted for an entry. */ #define XMIT_USER_OBJ (1<<0) #define XMIT_GROUP_OBJ (1<<1) #define XMIT_MASK_OBJ (1<<2) #define XMIT_OTHER_OBJ (1<<3) #define XMIT_NAME_LIST (1<<4) #define NO_ENTRY ((uchar)0x80) /* Default value of a NON-name-list entry. */ #define NAME_IS_USER (1u<<31) /* Bit used only on a name-list entry. */ /* When we send the access bits over the wire, we shift them 2 bits to the * left and use the lower 2 bits as flags (relevant only to a name entry). * This makes the protocol more efficient than sending a value that would * be likely to have its highest bits set. */ #define XFLAG_NAME_FOLLOWS 0x0001u #define XFLAG_NAME_IS_USER 0x0002u /* === ACL structures === */ typedef struct { id_t id; uint32 access; } id_access; typedef struct { id_access *idas; int count; } ida_entries; typedef struct { char *name; uchar len; } idname; typedef struct rsync_acl { ida_entries names; /* These will be NO_ENTRY if there's no such entry. */ uchar user_obj; uchar group_obj; uchar mask_obj; uchar other_obj; } rsync_acl; typedef struct { rsync_acl racl; SMB_ACL_T sacl; } acl_duo; static const rsync_acl empty_rsync_acl = { {NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY }; static item_list access_acl_list = EMPTY_ITEM_LIST; static item_list default_acl_list = EMPTY_ITEM_LIST; static size_t prior_access_count = (size_t)-1; static size_t prior_default_count = (size_t)-1; /* === Calculations on ACL types === */ static const char *str_acl_type(SMB_ACL_TYPE_T type) { switch (type) { case SMB_ACL_TYPE_ACCESS: #ifdef HAVE_OSX_ACLS return "ACL_TYPE_EXTENDED"; #else return "ACL_TYPE_ACCESS"; #endif case SMB_ACL_TYPE_DEFAULT: return "ACL_TYPE_DEFAULT"; default: break; } return "unknown ACL type!"; } static int calc_sacl_entries(const rsync_acl *racl) { /* A System ACL always gets user/group/other permission entries. */ return racl->names.count #ifdef ACLS_NEED_MASK + 1 #else + (racl->mask_obj != NO_ENTRY) #endif + 3; } /* Extracts and returns the permission bits from the ACL. This cannot be * called on an rsync_acl that has NO_ENTRY in any spot but the mask. */ static int rsync_acl_get_perms(const rsync_acl *racl) { return (racl->user_obj << 6) + ((racl->mask_obj != NO_ENTRY ? racl->mask_obj : racl->group_obj) << 3) + racl->other_obj; } /* Removes the permission-bit entries from the ACL because these * can be reconstructed from the file's mode. */ static void rsync_acl_strip_perms(stat_x *sxp) { rsync_acl *racl = sxp->acc_acl; racl->user_obj = NO_ENTRY; if (racl->mask_obj == NO_ENTRY) racl->group_obj = NO_ENTRY; else { int group_perms = (sxp->st.st_mode >> 3) & 7; if (racl->group_obj == group_perms) racl->group_obj = NO_ENTRY; #ifndef HAVE_SOLARIS_ACLS if (racl->names.count != 0 && racl->mask_obj == group_perms) racl->mask_obj = NO_ENTRY; #endif } racl->other_obj = NO_ENTRY; } /* Given an empty rsync_acl, fake up the permission bits. */ static void rsync_acl_fake_perms(rsync_acl *racl, mode_t mode) { racl->user_obj = (mode >> 6) & 7; racl->group_obj = (mode >> 3) & 7; racl->other_obj = mode & 7; } /* === Rsync ACL functions === */ static rsync_acl *create_racl(void) { rsync_acl *racl = new(rsync_acl); *racl = empty_rsync_acl; return racl; } static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2) { id_access *ida1, *ida2; int count = ial1->count; if (count != ial2->count) return False; ida1 = ial1->idas; ida2 = ial2->idas; for (; count--; ida1++, ida2++) { if (ida1->access != ida2->access || ida1->id != ida2->id) return False; } return True; } static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2) { return racl1->user_obj == racl2->user_obj && racl1->group_obj == racl2->group_obj && racl1->mask_obj == racl2->mask_obj && racl1->other_obj == racl2->other_obj && ida_entries_equal(&racl1->names, &racl2->names); } /* Are the extended (non-permission-bit) entries equal? If so, the rest of * the ACL will be handled by the normal mode-preservation code. This is * only meaningful for access ACLs! Note: the 1st arg is a fully-populated * rsync_acl, but the 2nd parameter can be a condensed rsync_acl, which means * that it might have several of its permission objects set to NO_ENTRY. */ static BOOL rsync_acl_equal_enough(const rsync_acl *racl1, const rsync_acl *racl2, mode_t m) { if ((racl1->mask_obj ^ racl2->mask_obj) & NO_ENTRY) return False; /* One has a mask and the other doesn't */ /* When there's a mask, the group_obj becomes an extended entry. */ if (racl1->mask_obj != NO_ENTRY) { /* A condensed rsync_acl with a mask can only have no * group_obj when it was identical to the mask. This * means that it was also identical to the group attrs * from the mode. */ if (racl2->group_obj == NO_ENTRY) { if (racl1->group_obj != ((m >> 3) & 7)) return False; } else if (racl1->group_obj != racl2->group_obj) return False; } return ida_entries_equal(&racl1->names, &racl2->names); } static void rsync_acl_free(rsync_acl *racl) { if (racl->names.idas) free(racl->names.idas); *racl = empty_rsync_acl; } void free_acl(stat_x *sxp) { if (sxp->acc_acl) { rsync_acl_free(sxp->acc_acl); free(sxp->acc_acl); sxp->acc_acl = NULL; } if (sxp->def_acl) { rsync_acl_free(sxp->def_acl); free(sxp->def_acl); sxp->def_acl = NULL; } } #ifdef SMB_ACL_NEED_SORT static int id_access_sorter(const void *r1, const void *r2) { id_access *ida1 = (id_access *)r1; id_access *ida2 = (id_access *)r2; id_t rid1 = ida1->id, rid2 = ida2->id; if ((ida1->access ^ ida2->access) & NAME_IS_USER) return ida1->access & NAME_IS_USER ? -1 : 1; return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1; } #endif /* === System ACLs === */ /* Unpack system ACL -> rsync ACL verbatim. Return whether we succeeded. */ static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl) { static item_list temp_ida_list = EMPTY_ITEM_LIST; SMB_ACL_ENTRY_T entry; const char *errfun; int rc; errfun = "sys_acl_get_entry"; for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry); rc == 1; rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) { SMB_ACL_TAG_T tag_type; uint32 access; id_t g_u_id; id_access *ida; if ((rc = sys_acl_get_info(entry, &tag_type, &access, &g_u_id)) != 0) { errfun = "sys_acl_get_info"; break; } /* continue == done with entry; break == store in temporary ida list */ switch (tag_type) { #ifndef HAVE_OSX_ACLS case SMB_ACL_USER_OBJ: if (racl->user_obj == NO_ENTRY) racl->user_obj = access; else rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n"); continue; case SMB_ACL_GROUP_OBJ: if (racl->group_obj == NO_ENTRY) racl->group_obj = access; else rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n"); continue; case SMB_ACL_MASK: if (racl->mask_obj == NO_ENTRY) racl->mask_obj = access; else rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n"); continue; case SMB_ACL_OTHER: if (racl->other_obj == NO_ENTRY) racl->other_obj = access; else rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n"); continue; #endif case SMB_ACL_USER: access |= NAME_IS_USER; break; case SMB_ACL_GROUP: break; default: rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n"); continue; } ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10); ida->id = g_u_id; ida->access = access; } if (rc) { rsyserr(FERROR_XFER, errno, "unpack_smb_acl: %s()", errfun); rsync_acl_free(racl); return False; } /* Transfer the count id_access items out of the temp_ida_list * into the names ida_entries list in racl. */ if (temp_ida_list.count) { #ifdef SMB_ACL_NEED_SORT if (temp_ida_list.count > 1) { qsort(temp_ida_list.items, temp_ida_list.count, sizeof (id_access), id_access_sorter); } #endif racl->names.idas = new_array(id_access, temp_ida_list.count); memcpy(racl->names.idas, temp_ida_list.items, temp_ida_list.count * sizeof (id_access)); } else racl->names.idas = NULL; racl->names.count = temp_ida_list.count; /* Truncate the temporary list now that its idas have been saved. */ temp_ida_list.count = 0; return True; } /* Synactic sugar for system calls */ #define CALL_OR_ERROR(func,args,str) \ do { \ if (func args) { \ errfun = str; \ goto error_exit; \ } \ } while (0) #define COE(func,args) CALL_OR_ERROR(func,args,#func) #define COE2(func,args) CALL_OR_ERROR(func,args,NULL) #ifndef HAVE_OSX_ACLS /* Store the permissions in the system ACL entry. */ static int store_access_in_entry(uint32 access, SMB_ACL_ENTRY_T entry) { if (sys_acl_set_access_bits(entry, access)) { rsyserr(FERROR_XFER, errno, "store_access_in_entry sys_acl_set_access_bits()"); return -1; } return 0; } #endif /* Pack rsync ACL -> system ACL verbatim. Return whether we succeeded. */ static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl) { #ifdef ACLS_NEED_MASK uchar mask_bits; #endif size_t count; id_access *ida; const char *errfun = NULL; SMB_ACL_ENTRY_T entry; if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) { rsyserr(FERROR_XFER, errno, "pack_smb_acl: sys_acl_init()"); return False; } #ifndef HAVE_OSX_ACLS COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_USER_OBJ, racl->user_obj & ~NO_ENTRY, 0) ); #endif for (ida = racl->names.idas, count = racl->names.count; count; ida++, count--) { #ifdef SMB_ACL_NEED_SORT if (!(ida->access & NAME_IS_USER)) break; #endif COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info, (entry, ida->access & NAME_IS_USER ? SMB_ACL_USER : SMB_ACL_GROUP, ida->access & ~NAME_IS_USER, ida->id) ); } #ifndef HAVE_OSX_ACLS COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_GROUP_OBJ, racl->group_obj & ~NO_ENTRY, 0) ); #ifdef SMB_ACL_NEED_SORT for ( ; count; ida++, count--) { COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_GROUP, ida->access, ida->id) ); } #endif #ifdef ACLS_NEED_MASK mask_bits = racl->mask_obj == NO_ENTRY ? racl->group_obj & ~NO_ENTRY : racl->mask_obj; COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, 0) ); #else if (racl->mask_obj != NO_ENTRY) { COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_MASK, racl->mask_obj, 0) ); } #endif COE( sys_acl_create_entry,(smb_acl, &entry) ); COE( sys_acl_set_info,(entry, SMB_ACL_OTHER, racl->other_obj & ~NO_ENTRY, 0) ); #endif #ifdef DEBUG if (sys_acl_valid(*smb_acl) < 0) rprintf(FERROR_XFER, "pack_smb_acl: warning: system says the ACL I packed is invalid\n"); #endif return True; error_exit: if (errfun) { rsyserr(FERROR_XFER, errno, "pack_smb_acl %s()", errfun); } sys_acl_free_acl(*smb_acl); return False; } static int find_matching_rsync_acl(const rsync_acl *racl, SMB_ACL_TYPE_T type, const item_list *racl_list) { static int access_match = -1, default_match = -1; int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match; size_t count = racl_list->count; /* If this is the first time through or we didn't match the last * time, then start at the end of the list, which should be the * best place to start hunting. */ if (*match == -1) *match = racl_list->count - 1; while (count--) { rsync_acl *base = racl_list->items; if (rsync_acl_equal(base + *match, racl)) return *match; if (!(*match)--) *match = racl_list->count - 1; } *match = -1; return *match; } static int get_rsync_acl(const char *fname, rsync_acl *racl, SMB_ACL_TYPE_T type, mode_t mode) { SMB_ACL_T sacl; #ifdef SUPPORT_XATTRS /* --fake-super support: load ACLs from an xattr. */ if (am_root < 0) { char *buf; size_t len; int cnt; if ((buf = get_xattr_acl(fname, type == SMB_ACL_TYPE_ACCESS, &len)) == NULL) return 0; cnt = (len - 4*4) / (4+4); if (len < 4*4 || len != (size_t)cnt*(4+4) + 4*4) { free(buf); return -1; } racl->user_obj = IVAL(buf, 0); if (racl->user_obj == NO_ENTRY) racl->user_obj = (mode >> 6) & 7; racl->group_obj = IVAL(buf, 4); if (racl->group_obj == NO_ENTRY) racl->group_obj = (mode >> 3) & 7; racl->mask_obj = IVAL(buf, 8); racl->other_obj = IVAL(buf, 12); if (racl->other_obj == NO_ENTRY) racl->other_obj = mode & 7; if (cnt) { char *bp = buf + 4*4; id_access *ida = racl->names.idas = new_array(id_access, cnt); racl->names.count = cnt; for ( ; cnt--; ida++, bp += 4+4) { ida->id = IVAL(bp, 0); ida->access = IVAL(bp, 4); } } free(buf); return 0; } #endif if ((sacl = sys_acl_get_file(fname, type)) != 0) { BOOL ok = unpack_smb_acl(sacl, racl); sys_acl_free_acl(sacl); if (!ok) { rsyserr(FERROR_XFER, errno, "get_acl: unpack_smb_acl(%s)", fname); return -1; } } else if (no_acl_syscall_error(errno)) { /* ACLs are not supported, so pretend we have a basic ACL. */ if (type == SMB_ACL_TYPE_ACCESS) rsync_acl_fake_perms(racl, mode); } else { rsyserr(FERROR_XFER, errno, "get_acl: sys_acl_get_file(%s, %s)", fname, str_acl_type(type)); return -1; } return 0; } /* Return the Access Control List for the given filename. */ int get_acl(const char *fname, stat_x *sxp) { sxp->acc_acl = create_racl(); if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) { /* Everyone supports this. */ } else if (S_ISLNK(sxp->st.st_mode)) { return 0; } else if (IS_SPECIAL(sxp->st.st_mode)) { #ifndef NO_SPECIAL_ACLS if (!preserve_specials) #endif return 0; } else if (IS_DEVICE(sxp->st.st_mode)) { #ifndef NO_DEVICE_ACLS if (!preserve_devices) #endif return 0; } else if (IS_MISSING_FILE(sxp->st)) return 0; if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, sxp->st.st_mode) < 0) { free_acl(sxp); return -1; } if (S_ISDIR(sxp->st.st_mode)) { sxp->def_acl = create_racl(); if (get_rsync_acl(fname, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, sxp->st.st_mode) < 0) { free_acl(sxp); return -1; } } return 0; } /* === Send functions === */ /* Send the ida list over the file descriptor. */ static void send_ida_entries(int f, const ida_entries *idal) { id_access *ida; size_t count = idal->count; write_varint(f, idal->count); for (ida = idal->idas; count--; ida++) { uint32 xbits = ida->access << 2; const char *name; if (ida->access & NAME_IS_USER) { xbits |= XFLAG_NAME_IS_USER; name = numeric_ids ? NULL : add_uid(ida->id); } else name = numeric_ids ? NULL : add_gid(ida->id); write_varint(f, ida->id); if (inc_recurse && name) { int len = strlen(name); write_varint(f, xbits | XFLAG_NAME_FOLLOWS); write_byte(f, len); write_buf(f, name, len); } else write_varint(f, xbits); } } static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl_list) { int ndx = find_matching_rsync_acl(racl, type, racl_list); /* Send 0 (-1 + 1) to indicate that literal ACL data follows. */ write_varint(f, ndx + 1); if (ndx < 0) { rsync_acl *new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000); uchar flags = 0; if (racl->user_obj != NO_ENTRY) flags |= XMIT_USER_OBJ; if (racl->group_obj != NO_ENTRY) flags |= XMIT_GROUP_OBJ; if (racl->mask_obj != NO_ENTRY) flags |= XMIT_MASK_OBJ; if (racl->other_obj != NO_ENTRY) flags |= XMIT_OTHER_OBJ; if (racl->names.count) flags |= XMIT_NAME_LIST; write_byte(f, flags); if (flags & XMIT_USER_OBJ) write_varint(f, racl->user_obj); if (flags & XMIT_GROUP_OBJ) write_varint(f, racl->group_obj); if (flags & XMIT_MASK_OBJ) write_varint(f, racl->mask_obj); if (flags & XMIT_OTHER_OBJ) write_varint(f, racl->other_obj); if (flags & XMIT_NAME_LIST) send_ida_entries(f, &racl->names); /* Give the allocated data to the new list object. */ *new_racl = *racl; *racl = empty_rsync_acl; } } /* Send the ACL from the stat_x structure down the indicated file descriptor. * This also frees the ACL data. */ void send_acl(int f, stat_x *sxp) { if (!sxp->acc_acl) { sxp->acc_acl = create_racl(); rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode); } /* Avoid sending values that can be inferred from other data. */ rsync_acl_strip_perms(sxp); send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list); if (S_ISDIR(sxp->st.st_mode)) { if (!sxp->def_acl) sxp->def_acl = create_racl(); send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list); } } /* === Receive functions === */ static uint32 recv_acl_access(int f, uchar *name_follows_ptr) { uint32 access = read_varint(f); if (name_follows_ptr) { int flags = access & 3; access >>= 2; if (am_root >= 0 && access & ~SMB_ACL_VALID_NAME_BITS) goto value_error; if (flags & XFLAG_NAME_FOLLOWS) *name_follows_ptr = 1; else *name_follows_ptr = 0; if (flags & XFLAG_NAME_IS_USER) access |= NAME_IS_USER; } else if (am_root >= 0 && access & ~SMB_ACL_VALID_OBJ_BITS) { value_error: rprintf(FERROR_XFER, "recv_acl_access: value out of range: %x\n", access); exit_cleanup(RERR_STREAMIO); } return access; } static uchar recv_ida_entries(int f, ida_entries *ent) { uchar computed_mask_bits = 0; int i, count = read_varint(f); ent->idas = count ? new_array(id_access, count) : NULL; ent->count = count; for (i = 0; i < count; i++) { uchar has_name; id_t id = read_varint(f); uint32 access = recv_acl_access(f, &has_name); if (has_name) { if (access & NAME_IS_USER) id = recv_user_name(f, id); else id = recv_group_name(f, id, NULL); } else if (access & NAME_IS_USER) { if (inc_recurse && am_root && !numeric_ids) id = match_uid(id); } else { if (inc_recurse && (!am_root || !numeric_ids)) id = match_gid(id, NULL); } ent->idas[i].id = id; ent->idas[i].access = access; computed_mask_bits |= access; } return computed_mask_bits & ~NO_ENTRY; } static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode_t mode) { uchar computed_mask_bits = 0; acl_duo *duo_item; uchar flags; int ndx = read_varint(f); if (ndx < 0 || (size_t)ndx > racl_list->count) { rprintf(FERROR_XFER, "recv_acl_index: %s ACL index %d > %d\n", str_acl_type(type), ndx, (int)racl_list->count); exit_cleanup(RERR_STREAMIO); } if (ndx != 0) return ndx - 1; ndx = racl_list->count; duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000); duo_item->racl = empty_rsync_acl; flags = read_byte(f); if (flags & XMIT_USER_OBJ) duo_item->racl.user_obj = recv_acl_access(f, NULL); if (flags & XMIT_GROUP_OBJ) duo_item->racl.group_obj = recv_acl_access(f, NULL); if (flags & XMIT_MASK_OBJ) duo_item->racl.mask_obj = recv_acl_access(f, NULL); if (flags & XMIT_OTHER_OBJ) duo_item->racl.other_obj = recv_acl_access(f, NULL); if (flags & XMIT_NAME_LIST) computed_mask_bits |= recv_ida_entries(f, &duo_item->racl.names); #ifdef HAVE_OSX_ACLS /* If we received a superfluous mask, throw it away. */ duo_item->racl.mask_obj = NO_ENTRY; (void)mode; #else if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) { /* Mask must be non-empty with lists. */ if (type == SMB_ACL_TYPE_ACCESS) computed_mask_bits = (mode >> 3) & 7; else computed_mask_bits |= duo_item->racl.group_obj & ~NO_ENTRY; duo_item->racl.mask_obj = computed_mask_bits; } #endif duo_item->sacl = NULL; return ndx; } /* Receive the ACL info the sender has included for this file-list entry. */ void receive_acl(int f, struct file_struct *file) { F_ACL(file) = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode); if (S_ISDIR(file->mode)) F_DIR_DEFACL(file) = recv_rsync_acl(f, &default_acl_list, SMB_ACL_TYPE_DEFAULT, 0); } static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl_list) { int ndx; if (!racl) ndx = -1; else if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) == -1) { acl_duo *new_duo; ndx = racl_list->count; new_duo = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000); new_duo->racl = *racl; new_duo->sacl = NULL; *racl = empty_rsync_acl; } return ndx; } /* Turn the ACL data in stat_x into cached ACL data, setting the index * values in the file struct. */ void cache_tmp_acl(struct file_struct *file, stat_x *sxp) { if (prior_access_count == (size_t)-1) prior_access_count = access_acl_list.count; F_ACL(file) = cache_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list); if (S_ISDIR(sxp->st.st_mode)) { if (prior_default_count == (size_t)-1) prior_default_count = default_acl_list.count; F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list); } } static void uncache_duo_acls(item_list *duo_list, size_t start) { acl_duo *duo_item = duo_list->items; acl_duo *duo_start = duo_item + start; duo_item += duo_list->count; duo_list->count = start; while (duo_item-- > duo_start) { rsync_acl_free(&duo_item->racl); if (duo_item->sacl) sys_acl_free_acl(duo_item->sacl); } } void uncache_tmp_acls(void) { if (prior_access_count != (size_t)-1) { uncache_duo_acls(&access_acl_list, prior_access_count); prior_access_count = (size_t)-1; } if (prior_default_count != (size_t)-1) { uncache_duo_acls(&default_acl_list, prior_default_count); prior_default_count = (size_t)-1; } } #ifndef HAVE_OSX_ACLS static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode) { SMB_ACL_ENTRY_T entry; const char *errfun; int rc; if (S_ISDIR(mode)) { /* If the sticky bit is going on, it's not safe to allow all * the new ACL to go into effect before it gets set. */ #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS if (mode & S_ISVTX) mode &= ~0077; #else if (mode & S_ISVTX && !(old_mode & S_ISVTX)) mode &= ~0077; } else { /* If setuid or setgid is going off, it's not safe to allow all * the new ACL to go into effect before they get cleared. */ if ((old_mode & S_ISUID && !(mode & S_ISUID)) || (old_mode & S_ISGID && !(mode & S_ISGID))) mode &= ~0077; #endif } errfun = "sys_acl_get_entry"; for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry); rc == 1; rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) { SMB_ACL_TAG_T tag_type; if ((rc = sys_acl_get_tag_type(entry, &tag_type)) != 0) { errfun = "sys_acl_get_tag_type"; break; } switch (tag_type) { case SMB_ACL_USER_OBJ: COE2( store_access_in_entry,((mode >> 6) & 7, entry) ); break; case SMB_ACL_GROUP_OBJ: /* group is only empty when identical to group perms. */ if (racl->group_obj != NO_ENTRY) break; COE2( store_access_in_entry,((mode >> 3) & 7, entry) ); break; case SMB_ACL_MASK: #ifndef HAVE_SOLARIS_ACLS #ifndef ACLS_NEED_MASK /* mask is only empty when we don't need it. */ if (racl->mask_obj == NO_ENTRY) break; #endif COE2( store_access_in_entry,((mode >> 3) & 7, entry) ); #endif break; case SMB_ACL_OTHER: COE2( store_access_in_entry,(mode & 7, entry) ); break; } } if (rc) { error_exit: if (errfun) { rsyserr(FERROR_XFER, errno, "change_sacl_perms: %s()", errfun); } return (mode_t)-1; } #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS /* Ensure that chmod() will be called to restore any lost setid bits. */ if (old_mode & (S_ISUID | S_ISGID | S_ISVTX) && BITS_EQUAL(old_mode, mode, CHMOD_BITS)) old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX); #endif /* Return the mode of the file on disk, as we will set them. */ return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS); } #endif static int set_rsync_acl(const char *fname, acl_duo *duo_item, SMB_ACL_TYPE_T type, stat_x *sxp, mode_t mode) { if (type == SMB_ACL_TYPE_DEFAULT && duo_item->racl.user_obj == NO_ENTRY) { int rc; #ifdef SUPPORT_XATTRS /* --fake-super support: delete default ACL from xattrs. */ if (am_root < 0) rc = del_def_xattr_acl(fname); else #endif rc = sys_acl_delete_def_file(fname); if (rc < 0) { rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_delete_def_file(%s)", fname); return -1; } #ifdef SUPPORT_XATTRS } else if (am_root < 0) { /* --fake-super support: store ACLs in an xattr. */ int cnt = duo_item->racl.names.count; size_t len = 4*4 + cnt * (4+4); char *buf = new_array(char, len); int rc; SIVAL(buf, 0, duo_item->racl.user_obj); SIVAL(buf, 4, duo_item->racl.group_obj); SIVAL(buf, 8, duo_item->racl.mask_obj); SIVAL(buf, 12, duo_item->racl.other_obj); if (cnt) { char *bp = buf + 4*4; id_access *ida = duo_item->racl.names.idas; for ( ; cnt--; ida++, bp += 4+4) { SIVAL(bp, 0, ida->id); SIVAL(bp, 4, ida->access); } } rc = set_xattr_acl(fname, type == SMB_ACL_TYPE_ACCESS, buf, len); free(buf); return rc; #endif } else { mode_t cur_mode = sxp->st.st_mode; if (!duo_item->sacl && !pack_smb_acl(&duo_item->sacl, &duo_item->racl)) return -1; #ifdef HAVE_OSX_ACLS mode = 0; /* eliminate compiler warning */ #else if (type == SMB_ACL_TYPE_ACCESS) { cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode); if (cur_mode == (mode_t)-1) return 0; } #endif if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) { rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_set_file(%s, %s)", fname, str_acl_type(type)); return -1; } if (type == SMB_ACL_TYPE_ACCESS) sxp->st.st_mode = cur_mode; } return 0; } /* Given a fname, this sets extended access ACL entries, the default ACL (for a * dir), and the regular mode bits on the file. Call this with fname set to * NULL to just check if the ACL is different. * * If the ACL operation has a side-effect of changing the file's mode, the * sxp->st.st_mode value will be changed to match. * * Returns 0 for an unchanged ACL, 1 for changed, -1 for failed. */ int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode) { int changed = 0; int32 ndx; BOOL eq; if (!dry_run && (read_only || list_only)) { errno = EROFS; return -1; } ndx = F_ACL(file); if (ndx >= 0 && (size_t)ndx < access_acl_list.count) { acl_duo *duo_item = access_acl_list.items; duo_item += ndx; eq = sxp->acc_acl && rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, new_mode); if (!eq) { changed = 1; if (!dry_run && fname && set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_ACCESS, sxp, new_mode) < 0) return -1; } } if (!S_ISDIR(new_mode)) return changed; ndx = F_DIR_DEFACL(file); if (ndx >= 0 && (size_t)ndx < default_acl_list.count) { acl_duo *duo_item = default_acl_list.items; duo_item += ndx; eq = sxp->def_acl && rsync_acl_equal(sxp->def_acl, &duo_item->racl); if (!eq) { changed = 1; if (!dry_run && fname && set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_DEFAULT, sxp, new_mode) < 0) return -1; } } return changed; } /* Non-incremental recursion needs to convert all the received IDs. * This is done in a single pass after receiving the whole file-list. */ static void match_racl_ids(const item_list *racl_list) { int list_cnt, name_cnt; acl_duo *duo_item = racl_list->items; for (list_cnt = racl_list->count; list_cnt--; duo_item++) { ida_entries *idal = &duo_item->racl.names; id_access *ida = idal->idas; for (name_cnt = idal->count; name_cnt--; ida++) { if (ida->access & NAME_IS_USER) ida->id = match_uid(ida->id); else ida->id = match_gid(ida->id, NULL); } } } void match_acl_ids(void) { match_racl_ids(&access_acl_list); match_racl_ids(&default_acl_list); } /* This is used by dest_mode(). */ int default_perms_for_dir(const char *dir) { rsync_acl racl; SMB_ACL_T sacl; BOOL ok; int perms; if (dir == NULL) dir = "."; perms = ACCESSPERMS & ~orig_umask; /* Read the directory's default ACL. If it has none, this will successfully return an empty ACL. */ sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT); if (sacl == NULL) { /* Couldn't get an ACL. Darn. */ switch (errno) { case EINVAL: /* If SMB_ACL_TYPE_DEFAULT isn't valid, then the ACLs must be non-POSIX. */ break; #ifdef ENOTSUP case ENOTSUP: #endif case ENOSYS: /* No ACLs are available. */ break; default: if (dry_run && errno == ENOENT) { /* We're doing a dry run, so the containing directory * wasn't actually created. Don't worry about it. */ break; } rprintf(FWARNING, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n", dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno)); } return perms; } /* Convert it. */ racl = empty_rsync_acl; ok = unpack_smb_acl(sacl, &racl); sys_acl_free_acl(sacl); if (!ok) { rprintf(FWARNING, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n"); return perms; } /* Apply the permission-bit entries of the default ACL, if any. */ if (racl.user_obj != NO_ENTRY) { perms = rsync_acl_get_perms(&racl); if (DEBUG_GTE(ACL, 1)) rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir); } rsync_acl_free(&racl); return perms; } #endif /* SUPPORT_ACLS */ rsync-3.2.7/rsync.h0000664000000000000000000012231514323037532012676 0ustar rootroot/* * Copyright (C) 1996, 2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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. */ #define False 0 #define True 1 #define Unset (-1) /* Our BOOL values are always an int. */ #define BLOCK_SIZE 700 #define RSYNC_RSH_ENV "RSYNC_RSH" #define RSYNC_RSH_IO_ENV "RSYNC_RSH_IO" #define RSYNC_NAME "rsync" /* RSYNCD_SYSCONF is now set in config.h */ #define RSYNCD_USERCONF "rsyncd.conf" #define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock" #define URL_PREFIX "rsync://" #define SYMLINK_PREFIX "/rsyncd-munged/" /* This MUST have a trailing slash! */ #define SYMLINK_PREFIX_LEN ((int)sizeof SYMLINK_PREFIX - 1) #define BACKUP_SUFFIX "~" /* a non-zero CHAR_OFFSET makes the rolling sum stronger, but is incompatible with older versions :-( */ #define CHAR_OFFSET 0 /* These flags are only used during the flist transfer. */ #define XMIT_TOP_DIR (1<<0) #define XMIT_SAME_MODE (1<<1) #define XMIT_SAME_RDEV_pre28 (1<<2) /* protocols 20 - 27 */ #define XMIT_EXTENDED_FLAGS (1<<2) /* protocols 28 - now */ #define XMIT_SAME_UID (1<<3) #define XMIT_SAME_GID (1<<4) #define XMIT_SAME_NAME (1<<5) #define XMIT_LONG_NAME (1<<6) #define XMIT_SAME_TIME (1<<7) #define XMIT_SAME_RDEV_MAJOR (1<<8) /* protocols 28 - now (devices only) */ #define XMIT_NO_CONTENT_DIR (1<<8) /* protocols 30 - now (dirs only) */ #define XMIT_HLINKED (1<<9) /* protocols 28 - now (non-dirs) */ #define XMIT_SAME_DEV_pre30 (1<<10) /* protocols 28 - 29 */ #define XMIT_USER_NAME_FOLLOWS (1<<10) /* protocols 30 - now */ #define XMIT_RDEV_MINOR_8_pre30 (1<<11) /* protocols 28 - 29 */ #define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */ #define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */ #define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */ #define XMIT_SAME_ATIME (1<<14) /* any protocol - restricted by command-line option */ #define XMIT_UNUSED_15 (1<<15) /* unused flag bit */ /* The following XMIT flags require an rsync that uses a varint for the flag values */ #define XMIT_RESERVED_16 (1<<16) /* reserved for future fileflags use */ #define XMIT_CRTIME_EQ_MTIME (1<<17) /* any protocol - restricted by command-line option */ /* These flags are used in the live flist data. */ #define FLAG_TOP_DIR (1<<0) /* sender/receiver/generator */ #define FLAG_OWNED_BY_US (1<<0) /* generator: set by make_file() for aux flists only */ #define FLAG_FILE_SENT (1<<1) /* sender/receiver/generator */ #define FLAG_DIR_CREATED (1<<1) /* generator */ #define FLAG_CONTENT_DIR (1<<2) /* sender/receiver/generator */ #define FLAG_MOUNT_DIR (1<<3) /* sender/generator (dirs only) */ #define FLAG_SKIP_HLINK (1<<3) /* receiver/generator (w/FLAG_HLINKED) */ #define FLAG_DUPLICATE (1<<4) /* sender */ #define FLAG_MISSING_DIR (1<<4) /* generator */ #define FLAG_HLINKED (1<<5) /* receiver/generator (checked on all types) */ #define FLAG_HLINK_FIRST (1<<6) /* receiver/generator (w/FLAG_HLINKED) */ #define FLAG_IMPLIED_DIR (1<<6) /* sender/receiver/generator (dirs only) */ #define FLAG_HLINK_LAST (1<<7) /* receiver/generator */ #define FLAG_HLINK_DONE (1<<8) /* receiver/generator (checked on all types) */ #define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */ #define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */ #define FLAG_TIME_FAILED (1<<11)/* generator */ #define FLAG_MOD_NSEC (1<<12) /* sender/receiver/generator */ /* These flags are passed to functions but not stored. */ #define FLAG_DIVERT_DIRS (1<<16) /* sender, but must be unique */ #define FLAG_PERHAPS_DIR (1<<17) /* generator */ /* These flags are for get_dirlist(). */ #define GDL_IGNORE_FILTER_RULES (1<<0) #define GDL_PERHAPS_DIR (1<<1) /* Some helper macros for matching bits. */ #define BITS_SET(val,bits) (((val) & (bits)) == (bits)) #define BITS_SETnUNSET(val,onbits,offbits) (((val) & ((onbits)|(offbits))) == (onbits)) #define BITS_EQUAL(b1,b2,mask) (((unsigned)(b1) & (unsigned)(mask)) \ == ((unsigned)(b2) & (unsigned)(mask))) /* Update this if you make incompatible changes and ALSO update the * SUBPROTOCOL_VERSION if it is not a final (official) release. */ #define PROTOCOL_VERSION 31 /* This is used when working on a new protocol version or for any unofficial * protocol tweaks. It should be a non-zero value for each pre-release repo * change that affects the protocol. The official pre-release versions should * start with 1 (after incrementing the PROTOCOL_VERSION) and go up by 1 for * each new protocol change. For unofficial changes, pick a fairly large * random number that will hopefully not collide with anyone else's unofficial * protocol. It must ALWAYS be 0 when the protocol goes final (and official) * and NEVER before! When rsync negotiates a protocol match, it will only * allow the newest protocol to be used if the SUBPROTOCOL_VERSION matches. * All older protocol versions MUST be compatible with the final, official * release of the protocol, so don't tweak the code to change the protocol * behavior for an older protocol version. */ #define SUBPROTOCOL_VERSION 0 /* We refuse to interoperate with versions that are not in this range. * Note that we assume we'll work with later versions: the onus is on * people writing them to make sure that they don't send us anything * we won't understand. * * Interoperation with old but supported protocol versions * should cause a warning to be printed. At a future date * the old protocol will become the minimum and * compatibility code removed. * * There are two possible explanations for the limit at * MAX_PROTOCOL_VERSION: either to allow new major-rev versions that * do not interoperate with us, and (more likely) so that we can * detect an attempt to connect rsync to a non-rsync server, which is * unlikely to begin by sending a byte between MIN_PROTOCL_VERSION and * MAX_PROTOCOL_VERSION. */ #define MIN_PROTOCOL_VERSION 20 #define OLD_PROTOCOL_VERSION 25 #define MAX_PROTOCOL_VERSION 40 #define MIN_FILECNT_LOOKAHEAD 1000 #define MAX_FILECNT_LOOKAHEAD 10000 #define RSYNC_PORT 873 #define SPARSE_WRITE_SIZE (1024) #define WRITE_SIZE (32*1024) #define CHUNK_SIZE (32*1024) #define MAX_MAP_SIZE (256*1024) #define IO_BUFFER_SIZE (32*1024) #define MAX_BLOCK_SIZE ((int32)1 << 17) /* For compatibility with older rsyncs */ #define OLD_MAX_BLOCK_SIZE ((int32)1 << 29) #define ROUND_UP_1024(siz) ((siz) & (1024-1) ? ((siz) | (1024-1)) + 1 : (siz)) #define IOERR_GENERAL (1<<0) /* For backward compatibility, this must == 1 */ #define IOERR_VANISHED (1<<1) #define IOERR_DEL_LIMIT (1<<2) #define MAX_ARGS 1000 #define MAX_BASIS_DIRS 20 #define MAX_SERVER_ARGS (MAX_BASIS_DIRS*2 + 100) #define COMPARE_DEST 1 #define COPY_DEST 2 #define LINK_DEST 3 #define MPLEX_BASE 7 #define NO_FILTERS 0 #define SERVER_FILTERS 1 #define ALL_FILTERS 2 #define XFLG_FATAL_ERRORS (1<<0) #define XFLG_OLD_PREFIXES (1<<1) #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 */ #define ATTRS_REPORT (1<<0) #define ATTRS_SKIP_MTIME (1<<1) #define ATTRS_ACCURATE_TIME (1<<2) #define ATTRS_SKIP_ATIME (1<<3) #define ATTRS_SKIP_CRTIME (1<<5) #define MSG_FLUSH 2 #define FULL_FLUSH 1 #define NORMAL_FLUSH 0 #define PDIR_CREATE 1 #define PDIR_DELETE 0 /* Note: 0x00 - 0x7F are used for basis_dir[] indexes! */ #define FNAMECMP_BASIS_DIR_LOW 0x00 /* Must remain 0! */ #define FNAMECMP_BASIS_DIR_HIGH 0x7F #define FNAMECMP_FNAME 0x80 #define FNAMECMP_PARTIAL_DIR 0x81 #define FNAMECMP_BACKUP 0x82 #define FNAMECMP_FUZZY 0x83 /* For use by the itemize_changes code */ #define ITEM_REPORT_ATIME (1<<0) #define ITEM_REPORT_CHANGE (1<<1) #define ITEM_REPORT_SIZE (1<<2) /* regular files only */ #define ITEM_REPORT_TIMEFAIL (1<<2) /* symlinks only */ #define ITEM_REPORT_TIME (1<<3) #define ITEM_REPORT_PERMS (1<<4) #define ITEM_REPORT_OWNER (1<<5) #define ITEM_REPORT_GROUP (1<<6) #define ITEM_REPORT_ACL (1<<7) #define ITEM_REPORT_XATTR (1<<8) #define ITEM_REPORT_CRTIME (1<<10) #define ITEM_BASIS_TYPE_FOLLOWS (1<<11) #define ITEM_XNAME_FOLLOWS (1<<12) #define ITEM_IS_NEW (1<<13) #define ITEM_LOCAL_CHANGE (1<<14) #define ITEM_TRANSFER (1<<15) /* These are outside the range of the transmitted flags. */ #define ITEM_MISSING_DATA (1<<16) /* used by log_formatted() */ #define ITEM_DELETED (1<<17) /* used by log_formatted() */ #define ITEM_MATCHED (1<<18) /* used by itemize() */ #define SIGNIFICANT_ITEM_FLAGS (~(\ ITEM_BASIS_TYPE_FOLLOWS | ITEM_XNAME_FOLLOWS | ITEM_LOCAL_CHANGE)) #define CFN_KEEP_DOT_DIRS (1<<0) #define CFN_KEEP_TRAILING_SLASH (1<<1) #define CFN_DROP_TRAILING_DOT_DIR (1<<2) #define CFN_COLLAPSE_DOT_DOT_DIRS (1<<3) #define CFN_REFUSE_DOT_DOT_DIRS (1<<4) #define SP_DEFAULT 0 #define SP_KEEP_DOT_DIRS (1<<0) #define CD_NORMAL 0 #define CD_SKIP_CHDIR 1 /* Log-message categories. FLOG only goes to the log file, not the client; * FCLIENT is the opposite. */ enum logcode { FNONE=0, /* never sent */ FERROR_XFER=1, FINFO=2, /* sent over socket for any protocol */ FERROR=3, FWARNING=4, /* sent over socket for protocols >= 30 */ FERROR_SOCKET=5, FLOG=6, /* only sent via receiver -> generator pipe */ FERROR_UTF8=8, /* only sent via receiver -> generator pipe */ FCLIENT=7 /* never transmitted (e.g. server converts to FINFO) */ }; /* Messages types that are sent over the message channel. The logcode * values must all be present here with identical numbers. */ enum msgcode { MSG_DATA=0, /* raw data on the multiplexed stream */ MSG_ERROR_XFER=FERROR_XFER, MSG_INFO=FINFO, /* remote logging */ MSG_ERROR=FERROR, MSG_WARNING=FWARNING, /* protocol-30 remote logging */ MSG_ERROR_SOCKET=FERROR_SOCKET, /* sibling logging */ MSG_ERROR_UTF8=FERROR_UTF8, /* sibling logging */ MSG_LOG=FLOG, MSG_CLIENT=FCLIENT, /* sibling logging */ MSG_REDO=9, /* reprocess indicated flist index */ MSG_STATS=10, /* message has stats data for generator */ MSG_IO_ERROR=22,/* the sending side had an I/O error */ MSG_IO_TIMEOUT=33,/* tell client about a daemon's timeout value */ MSG_NOOP=42, /* a do-nothing message (legacy protocol-30 only) */ MSG_ERROR_EXIT=86, /* synchronize an error exit (siblings and protocol >= 31) */ MSG_SUCCESS=100,/* successfully updated indicated flist index */ MSG_DELETED=101,/* successfully deleted a file on receiving side */ MSG_NO_SEND=102,/* sender failed to open a file we wanted */ }; enum filetype { FT_UNSUPPORTED, FT_REG, FT_DIR, FT_SYMLINK, FT_SPECIAL, FT_DEVICE }; #define NDX_DONE -1 #define NDX_FLIST_EOF -2 #define NDX_DEL_STATS -3 #define NDX_FLIST_OFFSET -101 /* For calling delete_item() and delete_dir_contents(). */ #define DEL_NO_UID_WRITE (1<<0) /* file/dir has our uid w/o write perm */ #define DEL_RECURSE (1<<1) /* if dir, delete all contents */ #define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */ #define DEL_FOR_FILE (1<<3) /* making room for a replacement file */ #define DEL_FOR_DIR (1<<4) /* making room for a replacement dir */ #define DEL_FOR_SYMLINK (1<<5) /* making room for a replacement symlink */ #define DEL_FOR_DEVICE (1<<6) /* making room for a replacement device */ #define DEL_FOR_SPECIAL (1<<7) /* making room for a replacement special */ #define DEL_FOR_BACKUP (1<<8) /* the delete is for a backup operation */ #define DEL_MAKE_ROOM (DEL_FOR_FILE|DEL_FOR_DIR|DEL_FOR_SYMLINK|DEL_FOR_DEVICE|DEL_FOR_SPECIAL) enum delret { DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY }; /* Defines for make_path() */ #define MKP_DROP_NAME (1<<0) /* drop trailing filename or trailing slash */ #define MKP_SKIP_SLASH (1<<1) /* skip one or more leading slashes */ /* Defines for maybe_send_keepalive() */ #define MSK_ALLOW_FLUSH (1<<0) #define MSK_ACTIVE_RECEIVER (1<<1) #include "errcode.h" #include "config.h" /* The default RSYNC_RSH is always set in config.h. */ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_BSD_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #if defined HAVE_MALLOC_H && (defined HAVE_MALLINFO || !defined HAVE_STDLIB_H) #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include #ifdef HAVE_FCNTL_H #include #else #ifdef HAVE_SYS_FCNTL_H #include #endif #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_FILIO_H #include #endif #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_CTYPE_H #include #endif #ifdef HAVE_GRP_H #include #endif #include #ifdef HAVE_UTIME_H #include #endif #if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES || defined HAVE_SETATTRLIST #define CAN_SET_SYMLINK_TIMES 1 #endif #if defined HAVE_LCHOWN || defined CHOWN_MODIFIES_SYMLINK #define CAN_CHOWN_SYMLINK 1 #endif #if defined HAVE_LCHMOD || defined HAVE_SETATTRLIST #define CAN_CHMOD_SYMLINK 1 #endif #if defined HAVE_UTIMENSAT || defined HAVE_SETATTRLIST #define CAN_SET_NSEC 1 #endif #ifdef CAN_SET_NSEC #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC #define ST_MTIME_NSEC st_mtim.tv_nsec #define ST_ATIME_NSEC st_atim.tv_nsec #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) #define ST_MTIME_NSEC st_mtimensec #define ST_ATIME_NSEC st_atimensec #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) #define ST_MTIME_NSEC st_mtimespec.tv_nsec #define ST_ATIME_NSEC st_atimespec.tv_nsec #endif #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_MODE_H /* apparently AIX needs this for S_ISLNK */ #ifndef S_ISLNK #include #endif #endif /* these are needed for the uid/gid mapping code */ #include #include #include #include #include #ifdef HAVE_NETDB_H #include #endif #include #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_DIRENT_H # include #else # define dirent direct # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif # ifdef HAVE_NDIR_H # include # endif #endif #ifdef MAJOR_IN_MKDEV #include # if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__) # define makedev mkdev # endif #elif defined MAJOR_IN_SYSMACROS #include #endif #ifdef MAKEDEV_TAKES_3_ARGS #define MAKEDEV(devmajor,devminor) makedev(0,devmajor,devminor) #else #ifndef __TANDEM #define MAKEDEV(devmajor,devminor) makedev(devmajor,devminor) #else # define major DEV_TO_MAJOR # define minor DEV_TO_MINOR # define MAKEDEV MAJORMINOR_TO_DEV #endif #endif #ifdef __TANDEM # include # include # define S_IEXEC S_IXUSR # define ROOT_UID 65535 #else # define ROOT_UID 0 #endif #ifdef HAVE_COMPAT_H #include #endif #ifdef HAVE_LIMITS_H # include #endif #if defined USE_ICONV_OPEN && defined HAVE_ICONV_H #include #ifndef ICONV_CONST #define ICONV_CONST #endif #else #ifdef ICONV_CONST #undef ICONV_CONST #endif #ifdef ICONV_OPTION #undef ICONV_OPTION #endif #ifdef iconv_t #undef iconv_t #endif #define iconv_t int #endif #include #include "lib/pool_alloc.h" #ifndef HAVE_ID_T typedef unsigned int id_t; #endif #ifndef HAVE_PID_T typedef int pid_t; #endif #ifndef HAVE_MODE_T typedef unsigned int mode_t; #endif #ifndef HAVE_OFF_T typedef long off_t; #undef SIZEOF_OFF_T #define SIZEOF_OFF_T SIZEOF_LONG #endif #ifndef HAVE_SIZE_T typedef unsigned int size_t; #endif #define BOOL int #ifndef uchar #define uchar unsigned char #endif #ifdef SIGNED_CHAR_OK #define schar signed char #else #define schar char #endif #ifndef int16 #if SIZEOF_INT16_T == 2 # define int16 int16_t #else # define int16 short #endif #endif #ifndef uint16 #if SIZEOF_UINT16_T == 2 # define uint16 uint16_t #else # define uint16 unsigned int16 #endif #endif #if !defined __APPLE__ || defined HAVE_GETATTRLIST #define SUPPORT_ATIMES 1 #endif #if defined HAVE_GETATTRLIST || defined __CYGWIN__ #define SUPPORT_CRTIMES 1 #endif /* 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. */ #ifndef int32 #if SIZEOF_INT32_T == 4 # define int32 int32_t # define SIZEOF_INT32 4 #elif SIZEOF_INT == 4 # define int32 int # define SIZEOF_INT32 4 #elif SIZEOF_LONG == 4 # define int32 long # define SIZEOF_INT32 4 #elif SIZEOF_SHORT == 4 # define int32 short # define SIZEOF_INT32 4 #elif SIZEOF_INT > 4 # define int32 int # define SIZEOF_INT32 SIZEOF_INT #elif SIZEOF_LONG > 4 # define int32 long # define SIZEOF_INT32 SIZEOF_LONG #else # error Could not find a 32-bit integer variable #endif #else # define SIZEOF_INT32 4 #endif #ifndef uint32 #if SIZEOF_UINT32_T == 4 # define uint32 uint32_t #else # define uint32 unsigned int32 #endif #endif #if SIZEOF_OFF_T == 8 || !SIZEOF_OFF64_T || !defined HAVE_STRUCT_STAT64 #define OFF_T off_t #define STRUCT_STAT struct stat #define SIZEOF_CAPITAL_OFF_T SIZEOF_OFF_T #else #define OFF_T off64_t #define STRUCT_STAT struct stat64 #define USE_STAT64_FUNCS 1 #define SIZEOF_CAPITAL_OFF_T SIZEOF_OFF64_T #endif /* CAVEAT: on some systems, int64 will really be a 32-bit integer IFF * that's the maximum size the file system can handle and there is no * 64-bit type available. The rsync source must therefore take steps * to ensure that any code that really requires a 64-bit integer has * it (e.g. the checksum code uses two 32-bit integers for its 64-bit * counter). */ #if SIZEOF_INT64_T == 8 # define int64 int64_t # define SIZEOF_INT64 8 #elif SIZEOF_LONG == 8 # define int64 long # define SIZEOF_INT64 8 #elif SIZEOF_INT == 8 # define int64 int # define SIZEOF_INT64 8 #elif SIZEOF_LONG_LONG == 8 # define int64 long long # define SIZEOF_INT64 8 #elif SIZEOF_OFF64_T == 8 # define int64 off64_t # define SIZEOF_INT64 8 #elif SIZEOF_OFF_T == 8 # define int64 off_t # define SIZEOF_INT64 8 #elif SIZEOF_INT > 8 # define int64 int # define SIZEOF_INT64 SIZEOF_INT #elif SIZEOF_LONG > 8 # define int64 long # define SIZEOF_INT64 SIZEOF_LONG #elif SIZEOF_LONG_LONG > 8 # define int64 long long # define SIZEOF_INT64 SIZEOF_LONG_LONG #else /* As long as it gets... */ # define int64 off_t # define SIZEOF_INT64 SIZEOF_OFF_T #endif #define HT_KEY32 0 #define HT_KEY64 1 struct hashtable { void *nodes; int32 size, entries; uint32 node_size; short key64; }; struct ht_int32_node { void *data; int32 key; }; struct ht_int64_node { void *data; int64 key; }; #define HT_NODE(tbl, bkts, i) ((void*)((char*)(bkts) + (i)*(tbl)->node_size)) #define HT_KEY(node, k64) ((k64)? ((struct ht_int64_node*)(node))->key \ : (int64)((struct ht_int32_node*)(node))->key) #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif #define SUM_LENGTH 16 #define SHORT_SUM_LENGTH 2 #define BLOCKSUM_BIAS 10 #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif /* We want a roomy line buffer that can hold more than MAXPATHLEN, * and significantly more than an overly short MAXPATHLEN. */ #if MAXPATHLEN < 4096 #define BIGPATHBUFLEN (4096+1024) #else #define BIGPATHBUFLEN (MAXPATHLEN+1024) #endif #ifndef NAME_MAX #define NAME_MAX 255 #endif #ifndef SIZE_MAX #define SIZE_MAX ((size_t)-1) #endif #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif #ifndef IN_LOOPBACKNET #define IN_LOOPBACKNET 127 #endif #if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS #define ACLS_NEED_MASK 1 #endif #if defined HAVE_FALLOCATE || HAVE_SYS_FALLOCATE #ifdef HAVE_LINUX_FALLOC_H #include #endif #ifdef FALLOC_FL_KEEP_SIZE #define SUPPORT_PREALLOCATION 1 #elif defined HAVE_FTRUNCATE #define SUPPORT_PREALLOCATION 1 #define PREALLOCATE_NEEDS_TRUNCATE 1 #endif #else /* !fallocate */ #if defined HAVE_EFFICIENT_POSIX_FALLOCATE && defined HAVE_FTRUNCATE #define SUPPORT_PREALLOCATION 1 #define PREALLOCATE_NEEDS_TRUNCATE 1 #endif #endif #if SIZEOF_CHARP == 4 # define PTRS_ARE_32 1 # define PTR_EXTRA_CNT 1 #elif SIZEOF_CHARP == 8 # define PTRS_ARE_64 1 # define PTR_EXTRA_CNT EXTRA64_CNT #else # error Character pointers are not 4 or 8 bytes. #endif #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define USE_FLEXIBLE_ARRAY 1 #define SIZE_T_FMT_MOD "z" /* printf supports %zd */ #define SIZE_T_FMT_CAST size_t #else #define SIZE_T_FMT_MOD "l" /* printf supports %ld */ #define SIZE_T_FMT_CAST long #endif union file_extras { int32 num; uint32 unum; #ifdef PTRS_ARE_32 const char* ptr; #endif }; union file_extras64 { int64 num; #ifdef PTRS_ARE_64 const char* ptr; #endif }; struct file_struct { const char *dirname; /* The dir info inside the transfer */ time_t modtime; /* When the item was last modified */ uint32 len32; /* Lowest 32 bits of the file's length */ uint16 mode; /* The item's type and permissions */ uint16 flags; /* The FLAG_* bits for this item */ #ifdef USE_FLEXIBLE_ARRAY const char basename[]; /* The basename (AKA filename) follows */ #else const char basename[1]; /* A kluge that should work like a flexible array */ #endif }; extern int file_extra_cnt; extern int inc_recurse; extern int atimes_ndx; extern int crtimes_ndx; extern int pathname_ndx; extern int depth_ndx; extern int uid_ndx; extern int gid_ndx; extern int acls_ndx; extern int xattrs_ndx; extern int file_sum_extra_cnt; #ifdef USE_FLEXIBLE_ARRAY #define FILE_STRUCT_LEN (sizeof (struct file_struct)) #else #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) #endif #define EXTRA_LEN (sizeof (union file_extras)) #define DEV_EXTRA_CNT 2 #define DIRNODE_EXTRA_CNT 3 #define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN) #define SUM_EXTRA_CNT file_sum_extra_cnt #define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx)) #define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump)) /* These are guaranteed to be allocated first in the array so that they * are aligned for direct int64-pointer access. */ #define REQ_EXTRA64(f,ndx) ((union file_extras64*)REQ_EXTRA(f,ndx)) #define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0) #define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0) #define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f)) #define HLINK_BUMP(f) ((f)->flags & (FLAG_HLINKED|FLAG_HLINK_DONE) ? inc_recurse+1 : 0) #define ACL_BUMP(f) (acls_ndx ? 1 : 0) /* The length applies to all items. */ #if SIZEOF_INT64 < 8 #define F_LENGTH(f) ((int64)(f)->len32) #else #define F_HIGH_LEN(f) (OPT_EXTRA(f, NSEC_BUMP(f))->unum) #define F_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 ? (int64)F_HIGH_LEN(f) << 32 : 0)) #endif #define F_MOD_NSEC(f) OPT_EXTRA(f, 0)->unum #define F_MOD_NSEC_or_0(f) ((f)->flags & FLAG_MOD_NSEC ? F_MOD_NSEC(f) : 0) /* If there is a symlink string, it is always right after the basename */ #define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1) /* The sending side always has this available: */ #ifdef PTRS_ARE_32 #define F_PATHNAME(f) REQ_EXTRA(f, pathname_ndx)->ptr #else #define F_PATHNAME(f) REQ_EXTRA64(f, pathname_ndx)->ptr #endif /* The receiving side always has this available: */ #define F_DEPTH(f) REQ_EXTRA(f, depth_ndx)->num /* 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 #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num #define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num #define F_CRTIME(f) REQ_EXTRA64(f, crtimes_ndx)->num /* These items are per-entry optional: */ #define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */ #define F_HL_PREV(f) OPT_EXTRA(f, START_BUMP(f)+inc_recurse)->num /* non-dirs */ #define F_DIR_NODE_P(f) (&OPT_EXTRA(f, START_BUMP(f) \ + DIRNODE_EXTRA_CNT - 1)->num) /* sender dirs */ #define F_DIR_RELNAMES_P(f) (&OPT_EXTRA(f, START_BUMP(f) + DIRNODE_EXTRA_CNT \ + PTR_EXTRA_CNT - 1)->num) /* sender dirs */ #define F_DIR_DEFACL(f) OPT_EXTRA(f, START_BUMP(f))->unum /* receiver dirs */ #define F_DIR_DEV_P(f) (&OPT_EXTRA(f, START_BUMP(f) + ACL_BUMP(f) \ + DEV_EXTRA_CNT - 1)->unum) /* receiver dirs */ /* This optional item might follow an F_HL_*() item. */ #define F_RDEV_P(f) (&OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) + DEV_EXTRA_CNT - 1)->unum) /* The sum is only present on regular files. */ #define F_SUM(f) ((char*)OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) \ + SUM_EXTRA_CNT - 1)) /* Some utility defines: */ #define F_IS_ACTIVE(f) (f)->basename[0] #define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED) #define F_HLINK_NOT_FIRST(f) BITS_SETnUNSET((f)->flags, FLAG_HLINKED, FLAG_HLINK_FIRST) #define F_HLINK_NOT_LAST(f) BITS_SETnUNSET((f)->flags, FLAG_HLINKED, FLAG_HLINK_LAST) /* These access the F_DIR_DEV_P() and F_RDEV_P() values: */ #define DEV_MAJOR(a) (a)[0] #define DEV_MINOR(a) (a)[1] /* These access the F_DIRS_NODE_P() values: */ #define DIR_PARENT(a) (a)[0] #define DIR_FIRST_CHILD(a) (a)[1] #define DIR_NEXT_SIBLING(a) (a)[2] #define IS_MISSING_FILE(statbuf) ((statbuf).st_mode == 0) /* * Start the flist array at FLIST_START entries and grow it * by doubling until FLIST_LINEAR then grow by FLIST_LINEAR */ #define FLIST_START (32) #define FLIST_START_LARGE (32 * 1024) #define FLIST_LINEAR (FLIST_START_LARGE * 512) /* * Extent size for allocation pools: A minimum size of 128KB * is needed to mmap them so that freeing will release the * space to the OS. * * Larger sizes reduce leftover fragments and speed free calls * (when they happen). Smaller sizes increase the chance of * freed allocations freeing whole extents. */ #define NORMAL_EXTENT (256 * 1024) #define SMALL_EXTENT (128 * 1024) #define FLIST_TEMP (1<<1) struct file_list { struct file_list *next, *prev; struct file_struct **files, **sorted; alloc_pool_t file_pool; void *pool_boundary; int used, malloced; int low, high; /* 0-relative index values excluding empties */ int ndx_start; /* the start offset for inc_recurse mode */ int flist_num; /* 1-relative file_list number or 0 */ int parent_ndx; /* dir_flist index of parent directory */ int in_progress, to_redo; }; #define SUMFLG_SAME_OFFSET (1<<0) struct sum_buf { OFF_T offset; /**< offset in file of this chunk */ int32 len; /**< length of chunk of file */ uint32 sum1; /**< simple checksum */ int32 chain; /**< next hash-table collision */ short flags; /**< flag bits */ char sum2[SUM_LENGTH]; /**< checksum */ }; struct sum_struct { OFF_T flength; /**< total file length */ struct sum_buf *sums; /**< points to info for each chunk */ int32 count; /**< how many chunks */ int32 blength; /**< block_length */ int32 remainder; /**< flength % block_length */ int s2length; /**< sum2_length */ }; struct map_struct { OFF_T file_size; /* File size (from stat) */ OFF_T p_offset; /* Window start */ OFF_T p_fd_offset; /* offset of cursor in fd ala lseek */ char *p; /* Window pointer */ int32 p_size; /* Largest window size we allocated */ int32 p_len; /* Latest (rounded) window size */ int32 def_window_size; /* Default window size */ int fd; /* File Descriptor */ int status; /* first errno from read errors */ }; #define NAME_IS_FILE (0) /* filter name as a file */ #define NAME_IS_DIR (1<<0) /* filter name as a dir */ #define NAME_IS_XATTR (1<<2) /* filter name as an xattr */ #define FILTRULE_WILD (1<<0) /* pattern has '*', '[', and/or '?' */ #define FILTRULE_WILD2 (1<<1) /* pattern has '**' */ #define FILTRULE_WILD2_PREFIX (1<<2) /* pattern starts with "**" */ #define FILTRULE_WILD3_SUFFIX (1<<3) /* pattern ends with "***" */ #define FILTRULE_ABS_PATH (1<<4) /* path-match on absolute path */ #define FILTRULE_INCLUDE (1<<5) /* this is an include, not an exclude */ #define FILTRULE_DIRECTORY (1<<6) /* this matches only directories */ #define FILTRULE_WORD_SPLIT (1<<7) /* split rules on whitespace */ #define FILTRULE_NO_INHERIT (1<<8) /* don't inherit these rules */ #define FILTRULE_NO_PREFIXES (1<<9) /* parse no prefixes from patterns */ #define FILTRULE_MERGE_FILE (1<<10)/* specifies a file to merge */ #define FILTRULE_PERDIR_MERGE (1<<11)/* merge-file is searched per-dir */ #define FILTRULE_EXCLUDE_SELF (1<<12)/* merge-file name should be excluded */ #define FILTRULE_FINISH_SETUP (1<<13)/* per-dir merge file needs setup */ #define FILTRULE_NEGATE (1<<14)/* rule matches when pattern does not */ #define FILTRULE_CVS_IGNORE (1<<15)/* rule was -C or :C */ #define FILTRULE_SENDER_SIDE (1<<16)/* rule applies to the sending side */ #define FILTRULE_RECEIVER_SIDE (1<<17)/* rule applies to the receiving side */ #define FILTRULE_CLEAR_LIST (1<<18)/* this item is the "!" token */ #define FILTRULE_PERISHABLE (1<<19)/* perishable if parent dir goes away */ #define FILTRULE_XATTR (1<<20)/* rule only applies to xattr names */ #define FILTRULES_SIDES (FILTRULE_SENDER_SIDE | FILTRULE_RECEIVER_SIDE) typedef struct filter_struct { struct filter_struct *next; char *pattern; uint32 rflags; union { int slash_cnt; struct filter_list_struct *mergelist; } u; uchar elide; } filter_rule; typedef struct filter_list_struct { filter_rule *head; filter_rule *tail; char *debug_type; } filter_rule_list; struct stats { int64 total_size; int64 total_transferred_size; int64 total_written; int64 total_read; int64 literal_data; int64 matched_data; int64 flist_buildtime; int64 flist_xfertime; int64 flist_size; int num_files, num_dirs, num_symlinks, num_devices, num_specials; int created_files, created_dirs, created_symlinks, created_devices, created_specials; int deleted_files, deleted_dirs, deleted_symlinks, deleted_devices, deleted_specials; int xferred_files; }; struct chmod_mode_struct; struct flist_ndx_item { struct flist_ndx_item *next; int ndx; }; typedef struct { struct flist_ndx_item *head, *tail; } flist_ndx_list; #define EMPTY_ITEM_LIST {NULL, 0, 0} typedef struct { void *items; size_t count; size_t malloced; } item_list; #define EXPAND_ITEM_LIST(lp, type, incr) \ (type*)expand_item_list(lp, sizeof (type), #type, incr) #define EMPTY_XBUF {NULL, 0, 0, 0} typedef struct { char *buf; size_t pos; /* pos = read pos in the buf */ size_t len; /* len = chars following pos */ size_t size; /* size = total space in buf */ } xbuf; #define INIT_XBUF(xb, str, ln, sz) (xb).buf = (str), (xb).len = (ln), (xb).size = (sz), (xb).pos = 0 #define INIT_XBUF_STRLEN(xb, str) (xb).buf = (str), (xb).len = strlen((xb).buf), (xb).size = (size_t)-1, (xb).pos = 0 /* This one is used to make an output xbuf based on a char[] buffer: */ #define INIT_CONST_XBUF(xb, bf) (xb).buf = (bf), (xb).size = sizeof (bf), (xb).len = (xb).pos = 0 #define ICB_EXPAND_OUT (1<<0) #define ICB_INCLUDE_BAD (1<<1) #define ICB_INCLUDE_INCOMPLETE (1<<2) #define ICB_CIRCULAR_OUT (1<<3) #define ICB_INIT (1<<4) #define IOBUF_KEEP_BUFS 0 #define IOBUF_FREE_BUFS 1 #define MPLX_SWITCHING IOBUF_KEEP_BUFS #define MPLX_ALL_DONE IOBUF_FREE_BUFS #define MPLX_TO_BUFFERED 2 #define RL_EOL_NULLS (1<<0) #define RL_DUMP_COMMENTS (1<<1) #define RL_CONVERT (1<<2) typedef struct { char name_type; #ifdef USE_FLEXIBLE_ARRAY char fname[]; /* has variable size */ #else char fname[1]; /* A kluge that should work like a flexible array */ #endif } relnamecache; #ifdef USE_FLEXIBLE_ARRAY #define RELNAMECACHE_LEN (sizeof (relnamecache)) #else #define RELNAMECACHE_LEN (offsetof(relnamecache, fname)) #endif #include "byteorder.h" #include "lib/mdigest.h" #include "lib/wildmatch.h" #include "lib/permstring.h" #include "lib/addrinfo.h" #ifndef __GNUC__ #define __attribute__(x) #else # if __GNUC__ <= 2 # define NORETURN # endif #endif #define UNUSED(x) x __attribute__((__unused__)) #ifndef NORETURN #define NORETURN __attribute__((__noreturn__)) #endif typedef struct { STRUCT_STAT st; time_t crtime; #ifdef SUPPORT_ACLS struct rsync_acl *acc_acl; /* access ACL */ struct rsync_acl *def_acl; /* default ACL */ #endif #ifdef SUPPORT_XATTRS item_list *xattr; #endif } stat_x; #define ACL_READY(sx) ((sx).acc_acl != NULL) #define XATTR_READY(sx) ((sx).xattr != NULL) #define CLVL_NOT_SPECIFIED INT_MIN #define CPRES_AUTO (-1) #define CPRES_NONE 0 #define CPRES_ZLIB 1 #define CPRES_ZLIBX 2 #define CPRES_LZ4 3 #define CPRES_ZSTD 4 #define NSTR_CHECKSUM 0 #define NSTR_COMPRESS 1 struct name_num_item { int num, flags; const char *name; struct name_num_item *main_nni; }; struct name_num_obj { const char *type; struct name_num_item *negotiated_nni; uchar *saw; int saw_len; struct name_num_item *list; }; #ifdef EXTERNAL_ZLIB #define read_buf read_buf_ #endif #ifndef __cplusplus #include "proto.h" #endif #ifndef SUPPORT_XATTRS #define x_stat(fn,fst,xst) do_stat(fn,fst) #define x_lstat(fn,fst,xst) do_lstat(fn,fst) #define x_fstat(fd,fst,xst) do_fstat(fd,fst) #endif /* We have replacement versions of these if they're missing. */ #ifndef HAVE_ASPRINTF int asprintf(char **ptr, const char *format, ...); #endif #ifndef HAVE_VASPRINTF int vasprintf(char **ptr, const char *format, va_list ap); #endif #if !defined HAVE_VSNPRINTF || !defined HAVE_C99_VSNPRINTF #define vsnprintf rsync_vsnprintf int vsnprintf(char *str, size_t count, const char *fmt, va_list args); #endif #if !defined HAVE_SNPRINTF || !defined HAVE_C99_VSNPRINTF #define snprintf rsync_snprintf int snprintf(char *str, size_t count, const char *fmt,...); #endif #ifndef HAVE_STRERROR extern char *sys_errlist[]; #define strerror(i) sys_errlist[i] #endif #ifndef HAVE_STRCHR # define strchr index # define strrchr rindex #endif #ifndef HAVE_ERRNO_DECL extern int errno; #endif #ifdef HAVE_READLINK #define SUPPORT_LINKS 1 #if !defined NO_SYMLINK_XATTRS && !defined NO_SYMLINK_USER_XATTRS #define do_readlink(path, buf, bufsiz) readlink(path, buf, bufsiz) #endif #endif #ifdef HAVE_LINK #define SUPPORT_HARD_LINKS 1 #endif #ifdef HAVE_SIGACTION #define SIGACTION(n,h) sigact.sa_handler=(h), sigaction((n),&sigact,NULL) #define signal(n,h) we_need_to_call_SIGACTION_not_signal(n,h) #else #define SIGACTION(n,h) signal(n,h) #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif #ifndef S_IRUSR #define S_IRUSR 0400 #endif #ifndef S_IWUSR #define S_IWUSR 0200 #endif #ifndef ACCESSPERMS #define ACCESSPERMS 0777 #endif #ifndef S_ISVTX #define S_ISVTX 0 #endif #define CHMOD_BITS (S_ISUID | S_ISGID | S_ISVTX | ACCESSPERMS) #ifndef _S_IFMT #define _S_IFMT 0170000 #endif #ifndef _S_IFLNK #define _S_IFLNK 0120000 #endif #ifndef S_ISLNK #define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK)) #endif #ifndef S_ISBLK #define S_ISBLK(mode) (((mode) & (_S_IFMT)) == (_S_IFBLK)) #endif #ifndef S_ISCHR #define S_ISCHR(mode) (((mode) & (_S_IFMT)) == (_S_IFCHR)) #endif #ifndef S_ISSOCK #ifdef _S_IFSOCK #define S_ISSOCK(mode) (((mode) & (_S_IFMT)) == (_S_IFSOCK)) #else #define S_ISSOCK(mode) (0) #endif #endif #ifndef S_ISFIFO #ifdef _S_IFIFO #define S_ISFIFO(mode) (((mode) & (_S_IFMT)) == (_S_IFIFO)) #else #define S_ISFIFO(mode) (0) #endif #endif #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) #endif #ifndef S_ISREG #define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) #endif /* work out what fcntl flag to use for non-blocking */ #ifdef O_NONBLOCK # define NONBLOCK_FLAG O_NONBLOCK #elif defined SYSV # define NONBLOCK_FLAG O_NDELAY #else # define NONBLOCK_FLAG FNDELAY #endif #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 #endif #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif #define IS_SPECIAL(mode) (S_ISSOCK(mode) || S_ISFIFO(mode)) #define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode)) /* Initial mask on permissions given to temporary files. Mask off setuid bits and group access because of potential race-condition security holes, and mask other access because mode 707 is bizarre */ #define INITACCESSPERMS 0700 /* handler for null strings in printf format */ #define NS(s) ((s)?(s):"") extern char *do_calloc; /* Convenient wrappers for malloc and realloc. Use them. */ #define new(type) ((type*)my_alloc(NULL, sizeof (type), 1, __FILE__, __LINE__)) #define new0(type) ((type*)my_alloc(do_calloc, sizeof (type), 1, __FILE__, __LINE__)) #define realloc_buf(ptr, num) my_alloc((ptr), (num), 1, __FILE__, __LINE__) #define new_array(type, num) ((type*)my_alloc(NULL, (num), sizeof (type), __FILE__, __LINE__)) #define new_array0(type, num) ((type*)my_alloc(do_calloc, (num), sizeof (type), __FILE__, __LINE__)) #define realloc_array(ptr, type, num) ((type*)my_alloc((ptr), (num), sizeof (type), __FILE__, __LINE__)) #undef strdup #define strdup(s) my_strdup(s, __FILE__, __LINE__) #define out_of_memory(msg) _out_of_memory(msg, __FILE__, __LINE__) #define overflow_exit(msg) _overflow_exit(msg, __FILE__, __LINE__) /* use magic gcc attributes to catch format errors */ void rprintf(enum logcode , const char *, ...) __attribute__((format (printf, 2, 3))) ; /* This is just like rprintf, but it also tries to print some * representation of the error code. Normally errcode = errno. */ void rsyserr(enum logcode, int, const char *, ...) __attribute__((format (printf, 3, 4))) ; /* Make sure that the O_BINARY flag is defined. */ #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef HAVE_STRLCPY size_t strlcpy(char *d, const char *s, size_t bufsize); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *d, const char *s, size_t bufsize); #endif #ifndef WEXITSTATUS #define WEXITSTATUS(stat) ((int)(((stat)>>8)&0xFF)) #endif #ifndef WIFEXITED #define WIFEXITED(stat) ((int)((stat)&0xFF) == 0) #endif #define exit_cleanup(code) _exit_cleanup(code, __FILE__, __LINE__) #ifdef HAVE_GETEUID #define MY_UID() geteuid() #else #define MY_UID() getuid() #endif #ifdef HAVE_GETEGID #define MY_GID() getegid() #else #define MY_GID() getgid() #endif #ifdef FORCE_FD_ZERO_MEMSET #undef FD_ZERO #define FD_ZERO(fdsetp) memset(fdsetp, 0, sizeof (fd_set)) #endif extern short info_levels[], debug_levels[]; #define INFO_GTE(flag, lvl) (info_levels[INFO_##flag] >= (lvl)) #define INFO_EQ(flag, lvl) (info_levels[INFO_##flag] == (lvl)) #define DEBUG_GTE(flag, lvl) (debug_levels[DEBUG_##flag] >= (lvl)) #define DEBUG_EQ(flag, lvl) (debug_levels[DEBUG_##flag] == (lvl)) #define INFO_BACKUP 0 #define INFO_COPY (INFO_BACKUP+1) #define INFO_DEL (INFO_COPY+1) #define INFO_FLIST (INFO_DEL+1) #define INFO_MISC (INFO_FLIST+1) #define INFO_MOUNT (INFO_MISC+1) #define INFO_NAME (INFO_MOUNT+1) #define INFO_NONREG (INFO_NAME+1) #define INFO_PROGRESS (INFO_NONREG+1) #define INFO_REMOVE (INFO_PROGRESS+1) #define INFO_SKIP (INFO_REMOVE+1) #define INFO_STATS (INFO_SKIP+1) #define INFO_SYMSAFE (INFO_STATS+1) #define COUNT_INFO (INFO_SYMSAFE+1) #define DEBUG_ACL 0 #define DEBUG_BACKUP (DEBUG_ACL+1) #define DEBUG_BIND (DEBUG_BACKUP+1) #define DEBUG_CHDIR (DEBUG_BIND+1) #define DEBUG_CONNECT (DEBUG_CHDIR+1) #define DEBUG_CMD (DEBUG_CONNECT+1) #define DEBUG_DEL (DEBUG_CMD+1) #define DEBUG_DELTASUM (DEBUG_DEL+1) #define DEBUG_DUP (DEBUG_DELTASUM+1) #define DEBUG_EXIT (DEBUG_DUP+1) #define DEBUG_FILTER (DEBUG_EXIT+1) #define DEBUG_FLIST (DEBUG_FILTER+1) #define DEBUG_FUZZY (DEBUG_FLIST+1) #define DEBUG_GENR (DEBUG_FUZZY+1) #define DEBUG_HASH (DEBUG_GENR+1) #define DEBUG_HLINK (DEBUG_HASH+1) #define DEBUG_ICONV (DEBUG_HLINK+1) #define DEBUG_IO (DEBUG_ICONV+1) #define DEBUG_NSTR (DEBUG_IO+1) #define DEBUG_OWN (DEBUG_NSTR+1) #define DEBUG_PROTO (DEBUG_OWN+1) #define DEBUG_RECV (DEBUG_PROTO+1) #define DEBUG_SEND (DEBUG_RECV+1) #define DEBUG_TIME (DEBUG_SEND+1) #define COUNT_DEBUG (DEBUG_TIME+1) #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src, char *dst, size_t size); #endif #ifndef HAVE_INET_PTON int inet_pton(int af, const char *src, void *dst); #endif #ifndef HAVE_GETPASS char *getpass(const char *prompt); #endif #ifdef MAINTAINER_MODE const char *get_panic_action(void); #endif #define NOISY_DEATH(msg) do { \ fprintf(stderr, "%s in %s at line %d\n", msg, __FILE__, __LINE__); \ exit_cleanup(RERR_UNSUPPORTED); \ } while (0) #ifdef HAVE_MALLINFO2 #define MEM_ALLOC_INFO mallinfo2 #elif defined HAVE_MALLINFO #define MEM_ALLOC_INFO mallinfo #endif rsync-3.2.7/testrun.c0000664000000000000000000000260211644073450013235 0ustar rootroot/* Run a testsuite script with a timeout. */ #include "rsync.h" #define DEFAULT_TIMEOUT_SECS (5*60) #define TIMEOUT_ENV "TESTRUN_TIMEOUT" int main(int argc, char *argv[]) { pid_t pid; char *timeout_env; int status, timeout_secs, slept = 0; if (argc < 2) { fprintf(stderr, "Usage: testrun [SHELL_OPTIONS] TESTSUITE_SCRIPT [ARGS]\n"); exit(1); } if ((timeout_env = getenv(TIMEOUT_ENV)) != NULL) timeout_secs = atoi(timeout_env); else timeout_secs = DEFAULT_TIMEOUT_SECS; if ((pid = fork()) < 0) { fprintf(stderr, "TESTRUN ERROR: fork failed: %s\n", strerror(errno)); exit(1); } if (pid == 0) { argv[0] = "sh"; execvp(argv[0], argv); fprintf(stderr, "TESTRUN ERROR: failed to exec %s: %s\n", argv[0], strerror(errno)); _exit(1); } while (1) { int ret = waitpid(pid, &status, WNOHANG); if (ret > 0) break; if (ret < 0) { if (errno == EINTR) continue; fprintf(stderr, "TESTRUN ERROR: waitpid failed: %s\n", strerror(errno)); exit(1); } if (slept++ > timeout_secs) { fprintf(stderr, "TESTRUN TIMEOUT: test took over %d seconds.\n", timeout_secs); if (kill(pid, SIGTERM) < 0) fprintf(stderr, "TESTRUN ERROR: failed to kill pid %d: %s\n", (int)pid, strerror(errno)); else fprintf(stderr, "TESTRUN INFO: killed pid %d\n", (int)pid); exit(1); } sleep(1); } if (!WIFEXITED(status)) exit(255); return WEXITSTATUS(status); } rsync-3.2.7/authenticate.c0000664000000000000000000002350414315642465014221 0ustar rootroot/* * Support rsync daemon authentication. * * Copyright (C) 1998-2000 Andrew Tridgell * Copyright (C) 2002-2022 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 "itypes.h" #include "ifuncs.h" extern int read_only; extern char *password_file; extern struct name_num_obj valid_auth_checksums; /*************************************************************************** encode a buffer using base64 - simple and slow algorithm. null terminates the result. ***************************************************************************/ void base64_encode(const char *buf, int len, char *out, int pad) { char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int bit_offset, byte_offset, idx, i; const uchar *d = (const uchar *)buf; int bytes = (len*8 + 5)/6; for (i = 0; i < bytes; i++) { byte_offset = (i*6)/8; bit_offset = (i*6)%8; if (bit_offset < 3) { idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F; } else { idx = (d[byte_offset] << (bit_offset-2)) & 0x3F; if (byte_offset+1 < len) { idx |= (d[byte_offset+1] >> (8-(bit_offset-2))); } } out[i] = b64[idx]; } while (pad && (i % 4)) out[i++] = '='; out[i] = '\0'; } /* Generate a challenge buffer and return it base64-encoded. */ static void gen_challenge(const char *addr, char *challenge) { char input[32]; char digest[MAX_DIGEST_LEN]; struct timeval tv; int len; memset(input, 0, sizeof input); strlcpy(input, addr, 17); sys_gettimeofday(&tv); SIVAL(input, 16, tv.tv_sec); SIVAL(input, 20, tv.tv_usec); SIVAL(input, 24, getpid()); len = sum_init(valid_auth_checksums.negotiated_nni, 0); sum_update(input, sizeof input); sum_end(digest); base64_encode(digest, len, challenge, 0); } /* Generate an MD4 hash created from the combination of the password * and the challenge string and return it base64-encoded. */ static void generate_hash(const char *in, const char *challenge, char *out) { char buf[MAX_DIGEST_LEN]; int len; len = sum_init(valid_auth_checksums.negotiated_nni, 0); sum_update(in, strlen(in)); sum_update(challenge, strlen(challenge)); sum_end(buf); base64_encode(buf, len, out, 0); } /* Return the secret for a user from the secret file, null terminated. * Maximum length is len (not counting the null). */ static const char *check_secret(int module, const char *user, const char *group, const char *challenge, const char *pass) { char line[1024]; char pass2[MAX_DIGEST_LEN*2]; const char *fname = lp_secrets_file(module); STRUCT_STAT st; int ok = 1; int user_len = strlen(user); int group_len = group ? strlen(group) : 0; char *err; FILE *fh; if (!fname || !*fname || (fh = fopen(fname, "r")) == NULL) return "no secrets file"; if (do_fstat(fileno(fh), &st) == -1) { rsyserr(FLOG, errno, "fstat(%s)", fname); ok = 0; } else if (lp_strict_modes(module)) { if ((st.st_mode & 06) != 0) { rprintf(FLOG, "secrets file must not be other-accessible (see strict modes option)\n"); ok = 0; } else if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) { rprintf(FLOG, "secrets file must be owned by root when running as root (see strict modes)\n"); ok = 0; } } if (!ok) { fclose(fh); return "ignoring secrets file"; } if (*user == '#') { /* Reject attempt to match a comment. */ fclose(fh); return "invalid username"; } /* Try to find a line that starts with the user (or @group) name and a ':'. */ err = "secret not found"; while ((user || group) && fgets(line, sizeof line, fh) != NULL) { const char **ptr, *s = strtok(line, "\n\r"); int len; if (!s) continue; if (*s == '@') { ptr = &group; len = group_len; s++; } else { ptr = &user; len = user_len; } if (!*ptr || strncmp(s, *ptr, len) != 0 || s[len] != ':') continue; generate_hash(s+len+1, challenge, pass2); if (strcmp(pass, pass2) == 0) { err = NULL; break; } err = "password mismatch"; *ptr = NULL; /* Don't look for name again. */ } fclose(fh); force_memzero(line, sizeof line); force_memzero(pass2, sizeof pass2); return err; } static const char *getpassf(const char *filename) { STRUCT_STAT st; char buffer[512], *p; int n; if (!filename) return NULL; if (strcmp(filename, "-") == 0) { n = fgets(buffer, sizeof buffer, stdin) == NULL ? -1 : (int)strlen(buffer); } else { int fd; if ((fd = open(filename,O_RDONLY)) < 0) { rsyserr(FERROR, errno, "could not open password file %s", filename); exit_cleanup(RERR_SYNTAX); } if (do_stat(filename, &st) == -1) { rsyserr(FERROR, errno, "stat(%s)", filename); exit_cleanup(RERR_SYNTAX); } if ((st.st_mode & 06) != 0) { rprintf(FERROR, "ERROR: password file must not be other-accessible\n"); exit_cleanup(RERR_SYNTAX); } if (MY_UID() == ROOT_UID && st.st_uid != ROOT_UID) { rprintf(FERROR, "ERROR: password file must be owned by root when running as root\n"); exit_cleanup(RERR_SYNTAX); } n = read(fd, buffer, sizeof buffer - 1); close(fd); } if (n > 0) { buffer[n] = '\0'; if ((p = strtok(buffer, "\n\r")) != NULL) return strdup(p); } rprintf(FERROR, "ERROR: failed to read a password from %s\n", filename); exit_cleanup(RERR_SYNTAX); } /* Possibly negotiate authentication with the client. Use "leader" to * start off the auth if necessary. * * Return NULL if authentication failed. Return "" if anonymous access. * Otherwise return username. */ char *auth_server(int f_in, int f_out, int module, const char *host, const char *addr, const char *leader) { char *users = lp_auth_users(module); char challenge[MAX_DIGEST_LEN*2]; char line[BIGPATHBUFLEN]; const char **auth_uid_groups = NULL; int auth_uid_groups_cnt = -1; const char *err = NULL; int group_match = -1; char *tok, *pass; char opt_ch = '\0'; /* if no auth list then allow anyone in! */ if (!users || !*users) return ""; negotiate_daemon_auth(f_out, 0); gen_challenge(addr, challenge); io_printf(f_out, "%s%s\n", leader, challenge); if (!read_line_old(f_in, line, sizeof line, 0) || (pass = strchr(line, ' ')) == NULL) { rprintf(FLOG, "auth failed on module %s from %s (%s): " "invalid challenge response\n", lp_name(module), host, addr); return NULL; } *pass++ = '\0'; users = strdup(users); for (tok = strtok(users, " ,\t"); tok; tok = strtok(NULL, " ,\t")) { char *opts; /* See if the user appended :deny, :ro, or :rw. */ if ((opts = strchr(tok, ':')) != NULL) { *opts++ = '\0'; opt_ch = isUpper(opts) ? toLower(opts) : *opts; if (opt_ch == 'r') { /* handle ro and rw */ opt_ch = isUpper(opts+1) ? toLower(opts+1) : opts[1]; if (opt_ch == 'o') opt_ch = 'r'; else if (opt_ch != 'w') opt_ch = '\0'; } else if (opt_ch != 'd') /* if it's not deny, ignore it */ opt_ch = '\0'; } else opt_ch = '\0'; if (*tok != '@') { /* Match the username */ if (wildmatch(tok, line)) break; } else { #ifdef HAVE_GETGROUPLIST int j; /* See if authorizing user is a real user, and if so, see * if it is in a group that matches tok+1 wildmat. */ if (auth_uid_groups_cnt < 0) { item_list gid_list = EMPTY_ITEM_LIST; uid_t auth_uid; if (!user_to_uid(line, &auth_uid, False) || getallgroups(auth_uid, &gid_list) != NULL) auth_uid_groups_cnt = 0; else { gid_t *gid_array = gid_list.items; auth_uid_groups_cnt = gid_list.count; auth_uid_groups = new_array(const char *, auth_uid_groups_cnt); for (j = 0; j < auth_uid_groups_cnt; j++) auth_uid_groups[j] = gid_to_group(gid_array[j]); } } for (j = 0; j < auth_uid_groups_cnt; j++) { if (auth_uid_groups[j] && wildmatch(tok+1, auth_uid_groups[j])) { group_match = j; break; } } if (group_match >= 0) break; #else rprintf(FLOG, "your computer doesn't support getgrouplist(), so no @group authorization is possible.\n"); #endif } } free(users); if (!tok) err = "no matching rule"; else if (opt_ch == 'd') err = "denied by rule"; else { const char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL; err = check_secret(module, line, group, challenge, pass); } force_memzero(challenge, sizeof challenge); force_memzero(pass, strlen(pass)); if (auth_uid_groups) { int j; for (j = 0; j < auth_uid_groups_cnt; j++) { if (auth_uid_groups[j]) free((char*)auth_uid_groups[j]); } free(auth_uid_groups); } if (err) { rprintf(FLOG, "auth failed on module %s from %s (%s) for %s: %s\n", lp_name(module), host, addr, line, err); return NULL; } if (opt_ch == 'r') read_only = 1; else if (opt_ch == 'w') read_only = 0; return strdup(line); } void auth_client(int fd, const char *user, const char *challenge) { const char *pass; char pass2[MAX_DIGEST_LEN*2]; if (!user || !*user) user = "nobody"; negotiate_daemon_auth(-1, 1); if (!(pass = getpassf(password_file)) && !(pass = getenv("RSYNC_PASSWORD"))) { /* XXX: cyeoh says that getpass is deprecated, because * it may return a truncated password on some systems, * and it is not in the LSB. * * Andrew Klein says that getpassphrase() is present * on Solaris and reads up to 256 characters. * * OpenBSD has a readpassphrase() that might be more suitable. */ pass = getpass("Password: "); } if (!pass) pass = ""; generate_hash(pass, challenge, pass2); io_printf(fd, "%s %s\n", user, pass2); } rsync-3.2.7/config.h.in0000664000000000000000000005415214324367163013424 0ustar rootroot/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Define to 1 if link() can hard-link special files. */ #undef CAN_HARDLINK_SPECIAL /* Define to 1 if link() can hard-link symlinks. */ #undef CAN_HARDLINK_SYMLINK /* Define to 1 if chown modifies symlinks. */ #undef CHOWN_MODIFIES_SYMLINK /* Undefine if you do not want locale features. By default this is defined. */ #undef CONFIG_LOCALE /* Define to 1 if using 'alloca.c'. */ #undef C_ALLOCA /* Define to 1 if using external zlib */ #undef EXTERNAL_ZLIB /* Used to make "checker" understand that FD_ZERO() clears memory. */ #undef FORCE_FD_ZERO_MEMSET /* Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'. */ #undef GETGROUPS_T /* Define to 1 if the `getpgrp' function requires zero arguments. */ #undef GETPGRP_VOID /* Define to 1 if you have the `aclsort' function. */ #undef HAVE_ACLSORT /* true if you have acl_get_perm_np */ #undef HAVE_ACL_GET_PERM_NP /* Define to 1 if you have the header file. */ #undef HAVE_ACL_LIBACL_H /* true if you have AIX ACLs */ #undef HAVE_AIX_ACLS /* Define to 1 if you have 'alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if works. */ #undef HAVE_ALLOCA_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_NAMESER_H /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF /* Define to 1 if you have the `attropen' function. */ #undef HAVE_ATTROPEN /* Define to 1 if you have the header file. */ #undef HAVE_ATTR_XATTR_H /* Define to 1 if readdir() is broken */ #undef HAVE_BROKEN_READDIR /* Define to 1 if you have the header file. */ #undef HAVE_BSD_STRING_H /* Define to 1 if vsprintf has a C99-compatible return value */ #undef HAVE_C99_VSNPRINTF /* Define to 1 if you have the `chflags' function. */ #undef HAVE_CHFLAGS /* Define to 1 if you have the `chmod' function. */ #undef HAVE_CHMOD /* Define to 1 if you have the `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the header file. */ #undef HAVE_COMPAT_H /* Define to 1 if you have the "connect" function */ #undef HAVE_CONNECT /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DL_H /* Define if posix_fallocate is efficient (Cygwin) */ #undef HAVE_EFFICIENT_POSIX_FALLOCATE /* Define to 1 if errno is declared in errno.h */ #undef HAVE_ERRNO_DECL /* Define to 1 if you have the `extattr_get_link' function. */ #undef HAVE_EXTATTR_GET_LINK /* Define to 1 if you have the fallocate function and it compiles and links without error */ #undef HAVE_FALLOCATE /* Define if FALLOC_FL_PUNCH_HOLE is available. */ #undef HAVE_FALLOC_FL_PUNCH_HOLE /* Define if FALLOC_FL_ZERO_RANGE is available. */ #undef HAVE_FALLOC_FL_ZERO_RANGE /* Define to 1 if you have the `fchmod' function. */ #undef HAVE_FCHMOD /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_FLOAT_H /* True if you have FreeBSD xattrs */ #undef HAVE_FREEBSD_XATTRS /* Define to 1 if you have the `fstat' function. */ #undef HAVE_FSTAT /* Define to 1 if you have the `ftruncate' function. */ #undef HAVE_FTRUNCATE /* Define to 1 if you have the "getaddrinfo" function and required types. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `getattrlist' function. */ #undef HAVE_GETATTRLIST /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the `getegid' function. */ #undef HAVE_GETEGID /* Define to 1 if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define to 1 if you have the `getgrouplist' function. */ #undef HAVE_GETGROUPLIST /* Define to 1 if you have the `getgroups' function. */ #undef HAVE_GETGROUPS /* Define to 1 if you have the `getpass' function. */ #undef HAVE_GETPASS /* Define to 1 if you have the `getpgrp' function. */ #undef HAVE_GETPGRP /* Define to 1 if gettimeofday() takes a time-zone arg */ #undef HAVE_GETTIMEOFDAY_TZ /* Define to 1 if you have the `getxattr' function. */ #undef HAVE_GETXATTR /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* true if you have HPUX ACLs */ #undef HAVE_HPUX_ACLS /* Define to 1 if you have the header file. */ #undef HAVE_ICONV_H /* Define to 1 if you have the `iconv_open' function. */ #undef HAVE_ICONV_OPEN /* Define to 1 if the system has the type `id_t'. */ #undef HAVE_ID_T /* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the `inet_pton' function. */ #undef HAVE_INET_PTON /* Define to 1 if you have the `initgroups' function. */ #undef HAVE_INITGROUPS /* Define to 1 if you have the `innetgr' function. */ #undef HAVE_INNETGR /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* true if you have IRIX ACLs */ #undef HAVE_IRIX_ACLS /* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H /* Define to 1 if you have the `lchmod' function. */ #undef HAVE_LCHMOD /* Define to 1 if you have the `lchown' function. */ #undef HAVE_LCHOWN /* Define to 1 if you have the `acl' library (-lacl). */ #undef HAVE_LIBACL /* Define to 1 if you have the `attr' library (-lattr). */ #undef HAVE_LIBATTR /* Define to 1 if you have the header file. */ #undef HAVE_LIBCHARSET_H /* Define to 1 if you have the `inet' library (-linet). */ #undef HAVE_LIBINET /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `nsl_s' library (-lnsl_s). */ #undef HAVE_LIBNSL_S /* Define to 1 if you have the `popt' library (-lpopt). */ #undef HAVE_LIBPOPT /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV /* Define to 1 if you have the `sec' library (-lsec). */ #undef HAVE_LIBSEC /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the `link' function. */ #undef HAVE_LINK /* Define to 1 if you have the `linkat' function. */ #undef HAVE_LINKAT /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FALLOC_H /* True if you have Linux xattrs (or equivalent) */ #undef HAVE_LINUX_XATTRS /* Define to 1 if you have the `locale_charset' function. */ #undef HAVE_LOCALE_CHARSET /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if the type `long double' works and has more range or precision than `double'. */ #undef HAVE_LONG_DOUBLE /* Define to 1 if the type `long double' works and has more range or precision than `double'. */ #undef HAVE_LONG_DOUBLE_WIDER /* Define to 1 if you have the `lseek64' function. */ #undef HAVE_LSEEK64 /* Define to 1 if you have the `lutimes' function. */ #undef HAVE_LUTIMES /* Define to 1 if you have the header file. */ #undef HAVE_LZ4_H /* Define to 1 if you have the `mallinfo' function. */ #undef HAVE_MALLINFO /* Define to 1 if you have the `mallinfo2' function. */ #undef HAVE_MALLINFO2 /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MCHECK_H /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the `mkfifo' function. */ #undef HAVE_MKFIFO /* Define to 1 if you have the `mknod' function. */ #undef HAVE_MKNOD /* Define to 1 if you have the `mkstemp64' function. */ #undef HAVE_MKSTEMP64 /* Define to 1 if you have the `mktime' function. */ #undef HAVE_MKTIME /* Define to 1 if the system has the type `mode_t'. */ #undef HAVE_MODE_T /* Define to 1 if you have the `mtrace' function. */ #undef HAVE_MTRACE /* Define to 1 if you have the `nanosleep' function. */ #undef HAVE_NANOSLEEP /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETGROUP_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_SYSTM_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IP_H /* Define to 1 if you have the `nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if the system has the type `off_t'. */ #undef HAVE_OFF_T /* Define to 1 if you have the `open64' function. */ #undef HAVE_OPEN64 /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_MD4_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_MD5_H /* true if you have Mac OS X ACLs */ #undef HAVE_OSX_ACLS /* True if you have Mac OS X xattrs */ #undef HAVE_OSX_XATTRS /* Define to 1 if the system has the type `pid_t'. */ #undef HAVE_PID_T /* Define to 1 if you have the header file. */ #undef HAVE_POPT_H /* Define to 1 if you have the header file. */ #undef HAVE_POPT_POPT_H /* true if you have posix ACLs */ #undef HAVE_POSIX_ACLS /* Define to 1 if you have the `posix_fallocate' function. */ #undef HAVE_POSIX_FALLOCATE /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define to 1 if you have the `readlink' function. */ #undef HAVE_READLINK /* Define to 1 if remote shell is remsh, not rsh */ #undef HAVE_REMSH /* Define to 1 if mkstemp() is available and works right */ #undef HAVE_SECURE_MKSTEMP /* Define to 1 if you have the `setattrlist' function. */ #undef HAVE_SETATTRLIST /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS /* Define to 1 if you have the `setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if you have the `setmode' function. */ #undef HAVE_SETMODE /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID /* Define to 1 if you have the `setvbuf' function. */ #undef HAVE_SETVBUF /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION /* Define to 1 if you have the `sigprocmask' function. */ #undef HAVE_SIGPROCMASK /* Define to 1 if the system has the type `size_t'. */ #undef HAVE_SIZE_T /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Do we have sockaddr_in6.sin6_scope_id? */ #undef HAVE_SOCKADDR_IN6_SCOPE_ID /* Do we have sockaddr_in.sin_len? */ #undef HAVE_SOCKADDR_IN_LEN /* Do we have sockaddr.sa_len? */ #undef HAVE_SOCKADDR_LEN /* Do we have sockaddr_un.sun_len? */ #undef HAVE_SOCKADDR_UN_LEN /* Define to 1 if you have the "socketpair" function */ #undef HAVE_SOCKETPAIR /* true if you have solaris ACLs */ #undef HAVE_SOLARIS_ACLS /* True if you have Solaris xattrs */ #undef HAVE_SOLARIS_XATTRS /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strpbrk' function. */ #undef HAVE_STRPBRK /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if the system has the type `struct addrinfo'. */ #undef HAVE_STRUCT_ADDRINFO /* Define to 1 if the system has the type `struct sockaddr_storage'. */ #undef HAVE_STRUCT_SOCKADDR_STORAGE /* Define to 1 if the system has the type `struct stat64'. */ #undef HAVE_STRUCT_STAT64 /* Define to 1 if `st_mtimensec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIMENSEC /* Define to 1 if `st_mtimespec.tv_nsec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC /* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC /* Define to 1 if `st_rdev' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV /* Define to 1 if you have the "struct utimbuf" type */ #undef HAVE_STRUCT_UTIMBUF /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ACL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_ATTR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EXTATTR_H /* Define to 1 if you have the SYS_fallocate syscall number */ #undef HAVE_SYS_FALLOCATE /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FCNTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MODE_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_UN_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_XATTR_H /* Define to 1 if you have the `tcgetpgrp' function. */ #undef HAVE_TCGETPGRP /* true if you have Tru64 ACLs */ #undef HAVE_TRU64_ACLS /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* true if you have UnixWare ACLs */ #undef HAVE_UNIXWARE_ACLS /* Define to 1 if you have the `unsetenv' function. */ #undef HAVE_UNSETENV /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME /* Define to 1 if you have the `utimensat' function. */ #undef HAVE_UTIMENSAT /* Define to 1 if you have the `utimes' function. */ #undef HAVE_UTIMES /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H /* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* Define to 1 if you have the `va_copy' function. */ #undef HAVE_VA_COPY /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the `wait4' function. */ #undef HAVE_WAIT4 /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID /* Define to 1 if you have the header file. */ #undef HAVE_XXHASH_H /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_ZSTD_H /* Define to 1 if you have the `_acl' function. */ #undef HAVE__ACL /* Define to 1 if you have the `_facl' function. */ #undef HAVE__FACL /* Define to 1 if you have the `__acl' function. */ #undef HAVE___ACL /* Define to 1 if you have the `__facl' function. */ #undef HAVE___FACL /* Define to 1 if you have the `__va_copy' function. */ #undef HAVE___VA_COPY /* Define as const if the declaration of iconv() needs const. */ #undef ICONV_CONST /* Define if you want the --iconv option. Specifying a value will set the default iconv setting (a NULL means no --iconv processing by default). */ #undef ICONV_OPTION /* true if you have IPv6 */ #undef INET6 /* Define to 1 if `major', `minor', and `makedev' are declared in . */ #undef MAJOR_IN_MKDEV /* Define to 1 if `major', `minor', and `makedev' are declared in . */ #undef MAJOR_IN_SYSMACROS /* Define to 1 if makedev() takes 3 args */ #undef MAKEDEV_TAKES_3_ARGS /* Define to 1 if mknod() can create FIFOs. */ #undef MKNOD_CREATES_FIFOS /* Define to 1 if mknod() can create sockets. */ #undef MKNOD_CREATES_SOCKETS /* unprivileged group for unprivileged user */ #undef NOBODY_GROUP /* unprivileged user--e.g. nobody */ #undef NOBODY_USER /* True if device files do not support xattrs */ #undef NO_DEVICE_XATTRS /* True if special files do not support xattrs */ #undef NO_SPECIAL_XATTRS /* True if symlinks do not support user xattrs */ #undef NO_SYMLINK_USER_XATTRS /* True if symlinks do not support xattrs */ #undef NO_SYMLINK_XATTRS /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* location of configuration file for rsync server */ #undef RSYNCD_SYSCONF /* location of rsync on remote machine */ #undef RSYNC_PATH /* default -e command */ #undef RSYNC_RSH /* Define to 1 if --secluded-args should be the default */ #undef RSYNC_USE_SECLUDED_ARGS /* Define to 1 if sockets need to be shutdown */ #undef SHUTDOWN_ALL_SOCKETS /* Define to 1 if "signed char" is a valid type */ #undef SIGNED_CHAR_OK /* The size of `char*', as computed by sizeof. */ #undef SIZEOF_CHARP /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of `int16_t', as computed by sizeof. */ #undef SIZEOF_INT16_T /* The size of `int32_t', as computed by sizeof. */ #undef SIZEOF_INT32_T /* The size of `int64_t', as computed by sizeof. */ #undef SIZEOF_INT64_T /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The size of `off64_t', as computed by sizeof. */ #undef SIZEOF_OFF64_T /* The size of `off_t', as computed by sizeof. */ #undef SIZEOF_OFF_T /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT /* The size of `time_t', as computed by sizeof. */ #undef SIZEOF_TIME_T /* The size of `uint16_t', as computed by sizeof. */ #undef SIZEOF_UINT16_T /* The size of `uint32_t', as computed by sizeof. */ #undef SIZEOF_UINT32_T /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 to add support for ACLs */ #undef SUPPORT_ACLS /* Undefine if you do not want LZ4 compression. By default this is defined. */ #undef SUPPORT_LZ4 /* Define to 1 to add support for extended attributes */ #undef SUPPORT_XATTRS /* Undefine if you do not want xxhash checksums. By default this is defined. */ #undef SUPPORT_XXHASH /* Undefine if you do not want zstd compression. By default this is defined. */ #undef SUPPORT_ZSTD /* Define to 1 if you want rsync to make use of iconv_open() */ #undef USE_ICONV_OPEN /* Define to 1 to enable MD5 ASM optimizations */ #undef USE_MD5_ASM /* Undefine if you do not want to use openssl crypto library. By default this is defined. */ #undef USE_OPENSSL /* Define to 1 to enable rolling-checksum ASM optimizations (requires --enable-roll-simd) */ #undef USE_ROLL_ASM /* Define to 1 to enable rolling-checksum SIMD optimizations */ #undef USE_ROLL_SIMD /* String to pass to iconv() for the UTF-8 charset. */ #undef UTF8_CHARSET /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define _GNU_SOURCE so that we get all necessary prototypes */ #undef _GNU_SOURCE /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to `unsigned int' if does not define. */ #undef size_t /* type to use in place of socklen_t if not defined */ #undef socklen_t /* Define to `int' if doesn't define. */ #undef uid_t rsync-3.2.7/COPYING0000664000000000000000000010535614124204403012420 0ustar rootrootREGARDING OPENSSL AND XXHASH In addition, as a special exception, the copyright holders give permission to dynamically link rsync with the OpenSSL and xxhash libraries when those libraries are being distributed in compliance with their license terms, and to distribute a dynamically linked combination of rsync and these libraries. This is also considered to be covered under the GPL's System Libraries exception. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . rsync-3.2.7/install-sh0000775000000000000000000001125114142014605013362 0ustar rootroot#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src ] || [ -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/_inst.$$_ # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 rsync-3.2.7/mkgitver0000775000000000000000000000123014323044767013145 0ustar rootroot#!/bin/sh srcdir=`dirname $0` if [ ! -f git-version.h ]; then touch git-version.h fi if test -d "$srcdir/.git" || test -f "$srcdir/.git"; then gitver=`git describe --abbrev=8 2>/dev/null` # NOTE: I'm avoiding "|" in sed since I'm not sure if sed -r is portable and "\|" fails on some OSes. verchk=`echo "$gitver-" | sed -n '/^v3\.[0-9][0-9]*\.[0-9][0-9]*\(pre[0-9]*\)*-/p'` if [ -n "$verchk" ]; then echo "#define RSYNC_GITVER \"$gitver\"" >git-version.h.new if ! diff git-version.h.new git-version.h >/dev/null; then echo "Updating git-version.h" mv git-version.h.new git-version.h else rm git-version.h.new fi fi fi rsync-3.2.7/exclude.c0000664000000000000000000014000614310656460013164 0ustar rootroot/* * The filter include/exclude routines. * * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2022 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" extern int am_server; extern int am_sender; extern int am_generator; extern int eol_nulls; extern int io_error; extern int xfer_dirs; extern int recurse; extern int local_server; extern int prune_empty_dirs; extern int ignore_perishable; extern int relative_paths; extern int delete_mode; extern int delete_excluded; extern int cvs_exclude; extern int sanitize_paths; extern int protocol_version; extern int trust_sender_args; extern int module_id; extern char curr_dir[MAXPATHLEN]; extern unsigned int curr_dir_len; extern unsigned int module_dirlen; filter_rule_list filter_list = { .debug_type = "" }; filter_rule_list cvs_filter_list = { .debug_type = " [global CVS]" }; filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" }; filter_rule_list implied_filter_list = { .debug_type = " [implied]" }; int saw_xattr_filter = 0; int trust_sender_args = 0; int trust_sender_filter = 0; /* Need room enough for ":MODS " prefix plus some room to grow. */ #define MAX_RULE_PREFIX (16) #define SLASH_WILD3_SUFFIX "/***" /* The dirbuf is set by push_local_filters() to the current subdirectory * relative to curr_dir that is being processed. The path always has a * trailing slash appended, and the variable dirbuf_len contains the length * of this path prefix. The path is always absolute. */ static char dirbuf[MAXPATHLEN+1]; static unsigned int dirbuf_len = 0; static int dirbuf_depth; /* This is True when we're scanning parent dirs for per-dir merge-files. */ static BOOL parent_dirscan = False; /* This array contains a list of all the currently active per-dir merge * files. This makes it easier to save the appropriate values when we * "push" down into each subdirectory. */ static filter_rule **mergelist_parents; static int mergelist_cnt = 0; static int mergelist_size = 0; #define LOCAL_RULE 1 #define REMOTE_RULE 2 static uchar cur_elide_value = REMOTE_RULE; /* Each filter_list_struct describes a singly-linked list by keeping track * of both the head and tail pointers. The list is slightly unusual in that * a parent-dir's content can be appended to the end of the local list in a * special way: the last item in the local list has its "next" pointer set * to point to the inherited list, but the local list's tail pointer points * at the end of the local list. Thus, if the local list is empty, the head * will be pointing at the inherited content but the tail will be NULL. To * help you visualize this, here are the possible list arrangements: * * Completely Empty Local Content Only * ================================== ==================================== * head -> NULL head -> Local1 -> Local2 -> NULL * tail -> NULL tail -------------^ * * Inherited Content Only Both Local and Inherited Content * ================================== ==================================== * head -> Parent1 -> Parent2 -> NULL head -> L1 -> L2 -> P1 -> P2 -> NULL * tail -> NULL tail ---------^ * * This means that anyone wanting to traverse the whole list to use it just * needs to start at the head and use the "next" pointers until it goes * NULL. To add new local content, we insert the item after the tail item * and update the tail (obviously, if "tail" was NULL, we insert it at the * head). To clear the local list, WE MUST NOT FREE THE INHERITED CONTENT * because it is shared between the current list and our parent list(s). * The easiest way to handle this is to simply truncate the list after the * tail item and then free the local list from the head. When inheriting * the list for a new local dir, we just save off the filter_list_struct * values (so we can pop back to them later) and set the tail to NULL. */ static void teardown_mergelist(filter_rule *ex) { int j; if (!ex->u.mergelist) return; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] deactivating mergelist #%d%s\n", who_am_i(), mergelist_cnt - 1, ex->u.mergelist->debug_type); } free(ex->u.mergelist->debug_type); free(ex->u.mergelist); for (j = 0; j < mergelist_cnt; j++) { if (mergelist_parents[j] == ex) { mergelist_parents[j] = NULL; break; } } while (mergelist_cnt && mergelist_parents[mergelist_cnt-1] == NULL) mergelist_cnt--; } static void free_filter(filter_rule *ex) { if (ex->rflags & FILTRULE_PERDIR_MERGE) teardown_mergelist(ex); free(ex->pattern); free(ex); } static void free_filters(filter_rule *ent) { while (ent) { filter_rule *next = ent->next; free_filter(ent); ent = next; } } /* Build a filter structure given a filter pattern. The value in "pat" * is not null-terminated. "rule" is either held or freed, so the * caller should not free it. */ static void add_rule(filter_rule_list *listp, const char *pat, unsigned int pat_len, filter_rule *rule, int xflags) { const char *cp; unsigned int pre_len, suf_len, slash_cnt = 0; char *mention_rule_suffix; if (DEBUG_GTE(FILTER, 1) && pat_len && (pat[pat_len-1] == ' ' || pat[pat_len-1] == '\t')) mention_rule_suffix = " -- CAUTION: trailing whitespace!"; else mention_rule_suffix = DEBUG_GTE(FILTER, 2) ? "" : NULL; if (mention_rule_suffix) { rprintf(FINFO, "[%s] add_rule(%s%.*s%s)%s%s\n", who_am_i(), get_rule_prefix(rule, pat, 0, NULL), (int)pat_len, pat, (rule->rflags & FILTRULE_DIRECTORY) ? "/" : "", listp->debug_type, mention_rule_suffix); } /* These flags also indicate that we're reading a list that * needs to be filtered now, not post-filtered later. */ if (xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && (rule->rflags & FILTRULES_SIDES) == (am_sender ? FILTRULE_RECEIVER_SIDE : FILTRULE_SENDER_SIDE)) { /* This filter applies only to the other side. Drop it. */ free_filter(rule); return; } if (pat_len > 1 && pat[pat_len-1] == '/') { pat_len--; rule->rflags |= FILTRULE_DIRECTORY; } for (cp = pat; cp < pat + pat_len; cp++) { if (*cp == '/') slash_cnt++; } if (!(rule->rflags & (FILTRULE_ABS_PATH | FILTRULE_MERGE_FILE)) && ((xflags & (XFLG_ANCHORED2ABS|XFLG_ABS_IF_SLASH) && *pat == '/') || (xflags & XFLG_ABS_IF_SLASH && slash_cnt))) { rule->rflags |= FILTRULE_ABS_PATH; if (*pat == '/') pre_len = dirbuf_len - module_dirlen - 1; else pre_len = 0; } else pre_len = 0; /* The daemon wants dir-exclude rules to get an appended "/" + "***". */ if (xflags & XFLG_DIR2WILD3 && BITS_SETnUNSET(rule->rflags, FILTRULE_DIRECTORY, FILTRULE_INCLUDE)) { rule->rflags &= ~FILTRULE_DIRECTORY; suf_len = sizeof SLASH_WILD3_SUFFIX - 1; } else suf_len = 0; rule->pattern = new_array(char, pre_len + pat_len + suf_len + 1); if (pre_len) { memcpy(rule->pattern, dirbuf + module_dirlen, pre_len); for (cp = rule->pattern; cp < rule->pattern + pre_len; cp++) { if (*cp == '/') slash_cnt++; } } rule->elide = 0; strlcpy(rule->pattern + pre_len, pat, pat_len + 1); pat_len += pre_len; if (suf_len) { memcpy(rule->pattern + pat_len, SLASH_WILD3_SUFFIX, suf_len+1); pat_len += suf_len; slash_cnt++; } if (strpbrk(rule->pattern, "*[?")) { rule->rflags |= FILTRULE_WILD; if ((cp = strstr(rule->pattern, "**")) != NULL) { rule->rflags |= FILTRULE_WILD2; /* If the pattern starts with **, note that. */ if (cp == rule->pattern) rule->rflags |= FILTRULE_WILD2_PREFIX; /* If the pattern ends with ***, note that. */ if (pat_len >= 3 && rule->pattern[pat_len-3] == '*' && rule->pattern[pat_len-2] == '*' && rule->pattern[pat_len-1] == '*') rule->rflags |= FILTRULE_WILD3_SUFFIX; } } if (rule->rflags & FILTRULE_PERDIR_MERGE) { filter_rule_list *lp; unsigned int len; int i; if ((cp = strrchr(rule->pattern, '/')) != NULL) cp++; else cp = rule->pattern; /* If the local merge file was already mentioned, don't * add it again. */ for (i = 0; i < mergelist_cnt; i++) { filter_rule *ex = mergelist_parents[i]; const char *s; if (!ex) continue; s = strrchr(ex->pattern, '/'); if (s) s++; else s = ex->pattern; len = strlen(s); if (len == pat_len - (cp - rule->pattern) && memcmp(s, cp, len) == 0) { free_filter(rule); return; } } lp = new_array0(filter_rule_list, 1); if (asprintf(&lp->debug_type, " [per-dir %s]", cp) < 0) out_of_memory("add_rule"); rule->u.mergelist = lp; if (mergelist_cnt == mergelist_size) { mergelist_size += 5; mergelist_parents = realloc_array(mergelist_parents, filter_rule *, mergelist_size); } if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] activating mergelist #%d%s\n", who_am_i(), mergelist_cnt, lp->debug_type); } mergelist_parents[mergelist_cnt++] = rule; } else rule->u.slash_cnt = slash_cnt; if (!listp->tail) { rule->next = listp->head; listp->head = listp->tail = rule; } else { rule->next = listp->tail->next; listp->tail->next = rule; listp->tail = rule; } } /* If the wildcards failed, the remote shell might give us a file matching the literal * wildcards. Since "*" & "?" already match themselves, this just needs to deal with * failed "[foo]" idioms. */ static void maybe_add_literal_brackets_rule(filter_rule const *based_on, int arg_len) { filter_rule *rule; const char *arg = based_on->pattern, *cp; char *p; int cnt = 0; if (arg_len < 0) arg_len = strlen(arg); for (cp = arg; *cp; cp++) { if (*cp == '\\' && cp[1]) { cp++; } else if (*cp == '[') cnt++; } if (!cnt) return; rule = new0(filter_rule); rule->rflags = based_on->rflags; rule->u.slash_cnt = based_on->u.slash_cnt; p = rule->pattern = new_array(char, arg_len + cnt + 1); for (cp = arg; *cp; ) { if (*cp == '\\' && cp[1]) { *p++ = *cp++; } else if (*cp == '[') *p++ = '\\'; *p++ = *cp++; } *p++ = '\0'; rule->next = implied_filter_list.head; implied_filter_list.head = rule; if (DEBUG_GTE(FILTER, 3)) { rprintf(FINFO, "[%s] add_implied_include(%s%s)\n", who_am_i(), rule->pattern, rule->rflags & FILTRULE_DIRECTORY ? "/" : ""); } } static char *partial_string_buf = NULL; static int partial_string_len = 0; void implied_include_partial_string(const char *s_start, const char *s_end) { partial_string_len = s_end - s_start; if (partial_string_len <= 0 || partial_string_len >= MAXPATHLEN) { /* too-large should be impossible... */ partial_string_len = 0; return; } if (!partial_string_buf) partial_string_buf = new_array(char, MAXPATHLEN); memcpy(partial_string_buf, s_start, partial_string_len); } void free_implied_include_partial_string() { if (partial_string_buf) { if (partial_string_len) add_implied_include("", 0); free(partial_string_buf); partial_string_buf = NULL; } partial_string_len = 0; /* paranoia */ } /* Each arg the client sends to the remote sender turns into an implied include * that the receiver uses to validate the file list from the sender. */ void add_implied_include(const char *arg, int skip_daemon_module) { int arg_len, saw_wild = 0, saw_live_open_brkt = 0, backslash_cnt = 0; int slash_cnt = 0; const char *cp; char *p; if (trust_sender_args) return; if (partial_string_len) { arg_len = strlen(arg); if (partial_string_len + arg_len >= MAXPATHLEN) { partial_string_len = 0; return; /* Should be impossible... */ } memcpy(partial_string_buf + partial_string_len, arg, arg_len + 1); partial_string_len = 0; arg = partial_string_buf; } if (skip_daemon_module) { if ((cp = strchr(arg, '/')) != NULL) arg = cp + 1; else arg = ""; } if (relative_paths) { if ((cp = strstr(arg, "/./")) != NULL) arg = cp + 3; } else if ((cp = strrchr(arg, '/')) != NULL) { arg = cp + 1; } if (*arg == '.' && arg[1] == '\0') arg++; arg_len = strlen(arg); if (arg_len) { char *new_pat; if (strpbrk(arg, "*[?")) { /* We need to add room to escape backslashes if wildcard chars are present. */ for (cp = arg; (cp = strchr(cp, '\\')) != NULL; cp++) arg_len++; saw_wild = 1; } arg_len++; /* Leave room for the prefixed slash */ p = new_pat = new_array(char, arg_len + 1); *p++ = '/'; slash_cnt++; for (cp = arg; *cp; ) { switch (*cp) { case '\\': if (cp[1] == ']') { if (!saw_wild) cp++; /* A \] in a non-wild filter causes a problem, so drop the \ . */ } else if (!strchr("*[?", cp[1])) { backslash_cnt++; if (saw_wild) *p++ = '\\'; } *p++ = *cp++; break; case '/': if (p[-1] == '/') { /* This is safe because of the initial slash. */ if (*++cp == '\0') { slash_cnt--; p--; } } else if (cp[1] == '\0') { cp++; } else { slash_cnt++; *p++ = *cp++; } break; case '.': if (p[-1] == '/') { if (cp[1] == '/') { cp += 2; if (!*cp) { slash_cnt--; p--; } } else if (cp[1] == '\0') { cp++; slash_cnt--; p--; } else *p++ = *cp++; } else *p++ = *cp++; break; case '[': saw_live_open_brkt = 1; *p++ = *cp++; break; default: *p++ = *cp++; break; } } *p = '\0'; arg_len = p - new_pat; if (!arg_len) free(new_pat); else { filter_rule *rule = new0(filter_rule); rule->rflags = FILTRULE_INCLUDE + (saw_wild ? FILTRULE_WILD : 0); rule->u.slash_cnt = slash_cnt; arg = rule->pattern = new_pat; if (!implied_filter_list.head) implied_filter_list.head = implied_filter_list.tail = rule; else { rule->next = implied_filter_list.head; implied_filter_list.head = rule; } if (DEBUG_GTE(FILTER, 3)) rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), arg); if (saw_live_open_brkt) maybe_add_literal_brackets_rule(rule, arg_len); if (relative_paths && slash_cnt) { int sub_slash_cnt = slash_cnt; while ((p = strrchr(new_pat, '/')) != NULL && p != new_pat) { filter_rule const *ent; filter_rule *R_rule; int found = 0; *p = '\0'; for (ent = implied_filter_list.head; ent; ent = ent->next) { if (ent != rule && strcmp(ent->pattern, new_pat) == 0) { found = 1; break; } } if (found) { *p = '/'; break; /* We added all parent dirs already */ } R_rule = new0(filter_rule); R_rule->rflags = FILTRULE_INCLUDE | FILTRULE_DIRECTORY; /* Check if our sub-path has wildcards or escaped backslashes */ if (saw_wild && strpbrk(new_pat, "*[?\\")) R_rule->rflags |= FILTRULE_WILD; R_rule->pattern = strdup(new_pat); R_rule->u.slash_cnt = --sub_slash_cnt; R_rule->next = implied_filter_list.head; implied_filter_list.head = R_rule; if (DEBUG_GTE(FILTER, 3)) { rprintf(FINFO, "[%s] add_implied_include(%s/)\n", who_am_i(), R_rule->pattern); } if (saw_live_open_brkt) maybe_add_literal_brackets_rule(R_rule, -1); } for (p = new_pat; sub_slash_cnt < slash_cnt; sub_slash_cnt++) { p += strlen(p); *p = '/'; } } } } if (recurse || xfer_dirs) { /* Now create a rule with an added "/" & "**" or "*" at the end */ filter_rule *rule = new0(filter_rule); rule->rflags = FILTRULE_INCLUDE | FILTRULE_WILD; if (recurse) rule->rflags |= FILTRULE_WILD2; /* We must leave enough room for / * * \0. */ if (!saw_wild && backslash_cnt) { /* We are appending a wildcard, so now the backslashes need to be escaped. */ p = rule->pattern = new_array(char, arg_len + backslash_cnt + 3 + 1); for (cp = arg; *cp; ) { /* Note that arg_len != 0 because backslash_cnt > 0 */ if (*cp == '\\') *p++ = '\\'; *p++ = *cp++; } } else { p = rule->pattern = new_array(char, arg_len + 3 + 1); if (arg_len) { memcpy(p, arg, arg_len); p += arg_len; } } *p++ = '/'; *p++ = '*'; if (recurse) *p++ = '*'; *p = '\0'; rule->u.slash_cnt = slash_cnt + 1; rule->next = implied_filter_list.head; implied_filter_list.head = rule; if (DEBUG_GTE(FILTER, 3)) rprintf(FINFO, "[%s] add_implied_include(%s)\n", who_am_i(), rule->pattern); if (saw_live_open_brkt) maybe_add_literal_brackets_rule(rule, p - rule->pattern); } } /* This frees any non-inherited items, leaving just inherited items on the list. */ static void pop_filter_list(filter_rule_list *listp) { filter_rule *inherited; if (!listp->tail) return; inherited = listp->tail->next; /* Truncate any inherited items from the local list. */ listp->tail->next = NULL; /* Now free everything that is left. */ free_filters(listp->head); listp->head = inherited; listp->tail = NULL; } /* This returns an expanded (absolute) filename for the merge-file name if * the name has any slashes in it OR if the parent_dirscan var is True; * otherwise it returns the original merge_file name. If the len_ptr value * is non-NULL the merge_file name is limited by the referenced length * value and will be updated with the length of the resulting name. We * always return a name that is null terminated, even if the merge_file * name was not. */ static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr, unsigned int prefix_skip) { static char buf[MAXPATHLEN]; char *fn, tmpbuf[MAXPATHLEN]; unsigned int fn_len; if (!parent_dirscan && *merge_file != '/') { /* Return the name unchanged it doesn't have any slashes. */ if (len_ptr) { const char *p = merge_file + *len_ptr; while (--p > merge_file && *p != '/') {} if (p == merge_file) { strlcpy(buf, merge_file, *len_ptr + 1); return buf; } } else if (strchr(merge_file, '/') == NULL) return (char *)merge_file; } fn = *merge_file == '/' ? buf : tmpbuf; if (sanitize_paths) { const char *r = prefix_skip ? "/" : NULL; /* null-terminate the name if it isn't already */ if (len_ptr && merge_file[*len_ptr]) { char *to = fn == buf ? tmpbuf : buf; strlcpy(to, merge_file, *len_ptr + 1); merge_file = to; } if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) { rprintf(FERROR, "merge-file name overflows: %s\n", merge_file); return NULL; } fn_len = strlen(fn); } else { strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN); fn_len = clean_fname(fn, CFN_COLLAPSE_DOT_DOT_DIRS); } /* If the name isn't in buf yet, it wasn't absolute. */ if (fn != buf) { int d_len = dirbuf_len - prefix_skip; if (d_len + fn_len >= MAXPATHLEN) { rprintf(FERROR, "merge-file name overflows: %s\n", fn); return NULL; } memcpy(buf, dirbuf + prefix_skip, d_len); memcpy(buf + d_len, fn, fn_len + 1); fn_len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS); } if (len_ptr) *len_ptr = fn_len; return buf; } /* Sets the dirbuf and dirbuf_len values. */ void set_filter_dir(const char *dir, unsigned int dirlen) { unsigned int len; if (*dir != '/') { memcpy(dirbuf, curr_dir, curr_dir_len); dirbuf[curr_dir_len] = '/'; len = curr_dir_len + 1; if (len + dirlen >= MAXPATHLEN) dirlen = 0; } else len = 0; memcpy(dirbuf + len, dir, dirlen); dirbuf[dirlen + len] = '\0'; dirbuf_len = clean_fname(dirbuf, CFN_COLLAPSE_DOT_DOT_DIRS); if (dirbuf_len > 1 && dirbuf[dirbuf_len-1] == '.' && dirbuf[dirbuf_len-2] == '/') dirbuf_len -= 2; if (dirbuf_len != 1) dirbuf[dirbuf_len++] = '/'; dirbuf[dirbuf_len] = '\0'; if (sanitize_paths) dirbuf_depth = count_dir_elements(dirbuf + module_dirlen); } /* This routine takes a per-dir merge-file entry and finishes its setup. * If the name has a path portion then we check to see if it refers to a * parent directory of the first transfer dir. If it does, we scan all the * dirs from that point through the parent dir of the transfer dir looking * for the per-dir merge-file in each one. */ static BOOL setup_merge_file(int mergelist_num, filter_rule *ex, filter_rule_list *lp) { char buf[MAXPATHLEN]; char *x, *y, *pat = ex->pattern; unsigned int len; if (!(x = parse_merge_name(pat, NULL, 0)) || *x != '/') return 0; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] performing parent_dirscan for mergelist #%d%s\n", who_am_i(), mergelist_num, lp->debug_type); } y = strrchr(x, '/'); *y = '\0'; ex->pattern = strdup(y+1); if (!*x) x = "/"; if (*x == '/') strlcpy(buf, x, MAXPATHLEN); else pathjoin(buf, MAXPATHLEN, dirbuf, x); len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS); if (len != 1 && len < MAXPATHLEN-1) { buf[len++] = '/'; buf[len] = '\0'; } /* This ensures that the specified dir is a parent of the transfer. */ for (x = buf, y = dirbuf; *x && *x == *y; x++, y++) {} if (*x) y += strlen(y); /* nope -- skip the scan */ parent_dirscan = True; while (*y) { char save[MAXPATHLEN]; strlcpy(save, y, MAXPATHLEN); *y = '\0'; dirbuf_len = y - dirbuf; strlcpy(x, ex->pattern, MAXPATHLEN - (x - buf)); parse_filter_file(lp, buf, ex, XFLG_ANCHORED2ABS); if (ex->rflags & FILTRULE_NO_INHERIT) { /* Free the undesired rules to clean up any per-dir * mergelists they defined. Otherwise pop_local_filters * may crash trying to restore nonexistent state for * those mergelists. */ free_filters(lp->head); lp->head = NULL; } lp->tail = NULL; strlcpy(y, save, MAXPATHLEN); while ((*x++ = *y++) != '/') {} } parent_dirscan = False; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] completed parent_dirscan for mergelist #%d%s\n", who_am_i(), mergelist_num, lp->debug_type); } free(pat); return 1; } struct local_filter_state { int mergelist_cnt; filter_rule_list mergelists[1]; }; /* 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_filters(const char *dir, unsigned int dirlen) { struct local_filter_state *push; int i; set_filter_dir(dir, dirlen); if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] pushing local filters for %s\n", who_am_i(), dirbuf); } if (!mergelist_cnt) { /* No old state to save and no new merge files to push. */ return NULL; } push = (struct local_filter_state *)new_array(char, sizeof (struct local_filter_state) + (mergelist_cnt-1) * sizeof (filter_rule_list)); push->mergelist_cnt = mergelist_cnt; for (i = 0; i < mergelist_cnt; i++) { filter_rule *ex = mergelist_parents[i]; if (!ex) continue; memcpy(&push->mergelists[i], ex->u.mergelist, sizeof (filter_rule_list)); } /* Note: parse_filter_file() might increase mergelist_cnt, so keep * this loop separate from the above loop. */ for (i = 0; i < mergelist_cnt; i++) { filter_rule *ex = mergelist_parents[i]; filter_rule_list *lp; if (!ex) continue; lp = ex->u.mergelist; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] pushing mergelist #%d%s\n", who_am_i(), i, lp->debug_type); } lp->tail = NULL; /* Switch any local rules to inherited. */ if (ex->rflags & FILTRULE_NO_INHERIT) lp->head = NULL; if (ex->rflags & FILTRULE_FINISH_SETUP) { ex->rflags &= ~FILTRULE_FINISH_SETUP; if (setup_merge_file(i, ex, lp)) set_filter_dir(dir, dirlen); } if (strlcpy(dirbuf + dirbuf_len, ex->pattern, MAXPATHLEN - dirbuf_len) < MAXPATHLEN - dirbuf_len) { parse_filter_file(lp, dirbuf, ex, XFLG_ANCHORED2ABS); } else { io_error |= IOERR_GENERAL; rprintf(FERROR, "cannot add local filter rules in long-named directory: %s\n", full_fname(dirbuf)); } dirbuf[dirbuf_len] = '\0'; } return (void*)push; } void pop_local_filters(void *mem) { struct local_filter_state *pop = (struct local_filter_state *)mem; int i; int old_mergelist_cnt = pop ? pop->mergelist_cnt : 0; if (DEBUG_GTE(FILTER, 2)) rprintf(FINFO, "[%s] popping local filters\n", who_am_i()); for (i = mergelist_cnt; i-- > 0; ) { filter_rule *ex = mergelist_parents[i]; filter_rule_list *lp; if (!ex) continue; lp = ex->u.mergelist; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] popping mergelist #%d%s\n", who_am_i(), i, lp->debug_type); } pop_filter_list(lp); if (i >= old_mergelist_cnt && lp->head) { /* This mergelist does not exist in the state to be restored, but it * still has inherited rules. This can sometimes happen if a per-dir * merge file calls setup_merge_file() in push_local_filters() and that * leaves some inherited rules that aren't in the pushed list state. */ if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] freeing parent_dirscan filters of mergelist #%d%s\n", who_am_i(), i, ex->u.mergelist->debug_type); } pop_filter_list(lp); } } if (!pop) return; /* No state to restore. */ for (i = 0; i < old_mergelist_cnt; i++) { filter_rule *ex = mergelist_parents[i]; if (!ex) continue; memcpy(ex->u.mergelist, &pop->mergelists[i], sizeof (filter_rule_list)); } free(pop); } void change_local_filter_dir(const char *dname, int dlen, int dir_depth) { static int cur_depth = -1; static void *filt_array[MAXPATHLEN/2+1]; if (!dname) { for ( ; cur_depth >= 0; cur_depth--) { if (filt_array[cur_depth]) { pop_local_filters(filt_array[cur_depth]); filt_array[cur_depth] = NULL; } } return; } assert(dir_depth < MAXPATHLEN/2+1); for ( ; cur_depth >= dir_depth; cur_depth--) { if (filt_array[cur_depth]) { pop_local_filters(filt_array[cur_depth]); filt_array[cur_depth] = NULL; } } cur_depth = dir_depth; filt_array[cur_depth] = push_local_filters(dname, dlen); } static int rule_matches(const char *fname, filter_rule *ex, int name_flags) { int slash_handling, str_cnt = 0, anchored_match = 0; int ret_match = ex->rflags & FILTRULE_NEGATE ? 0 : 1; char *p, *pattern = ex->pattern; const char *strings[16]; /* more than enough */ const char *name = fname + (*fname == '/'); if (!*name || ex->elide == cur_elide_value) return 0; if (!(name_flags & NAME_IS_XATTR) ^ !(ex->rflags & FILTRULE_XATTR)) return 0; if (!ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) { /* If the pattern does not have any slashes AND it does * not have a "**" (which could match a slash), then we * just match the name portion of the path. */ if ((p = strrchr(name,'/')) != NULL) name = p+1; } else if (ex->rflags & FILTRULE_ABS_PATH && *fname != '/' && curr_dir_len > module_dirlen + 1) { /* If we're matching against an absolute-path pattern, * we need to prepend our full path info. */ strings[str_cnt++] = curr_dir + module_dirlen + 1; strings[str_cnt++] = "/"; } else if (ex->rflags & FILTRULE_WILD2_PREFIX && *fname != '/') { /* Allow "**"+"/" to match at the start of the string. */ strings[str_cnt++] = "/"; } strings[str_cnt++] = name; if (name_flags & NAME_IS_DIR) { /* Allow a trailing "/"+"***" to match the directory. */ if (ex->rflags & FILTRULE_WILD3_SUFFIX) strings[str_cnt++] = "/"; } else if (ex->rflags & FILTRULE_DIRECTORY) return !ret_match; strings[str_cnt] = NULL; if (*pattern == '/') { anchored_match = 1; pattern++; } if (!anchored_match && ex->u.slash_cnt && !(ex->rflags & FILTRULE_WILD2)) { /* A non-anchored match with an infix slash and no "**" * needs to match the last slash_cnt+1 name elements. */ slash_handling = ex->u.slash_cnt + 1; } else if (!anchored_match && !(ex->rflags & FILTRULE_WILD2_PREFIX) && ex->rflags & FILTRULE_WILD2) { /* A non-anchored match with an infix or trailing "**" (but not * a prefixed "**") needs to try matching after every slash. */ slash_handling = -1; } else { /* The pattern matches only at the start of the path or name. */ slash_handling = 0; } if (ex->rflags & FILTRULE_WILD) { if (wildmatch_array(pattern, strings, slash_handling)) return ret_match; } else if (str_cnt > 1) { if (litmatch_array(pattern, strings, slash_handling)) return ret_match; } else if (anchored_match) { if (strcmp(name, pattern) == 0) return ret_match; } else { int l1 = strlen(name); int l2 = strlen(pattern); if (l2 <= l1 && strcmp(name+(l1-l2),pattern) == 0 && (l1==l2 || name[l1-(l2+1)] == '/')) { return ret_match; } } return !ret_match; } static void report_filter_result(enum logcode code, char const *name, filter_rule const *ent, int name_flags, const char *type) { int log_level = am_sender || am_generator ? 1 : 3; /* If a trailing slash is present to match only directories, * then it is stripped out by add_rule(). So as a special * case we add it back in the log output. */ if (DEBUG_GTE(FILTER, log_level)) { static char *actions[2][2] = { {"show", "hid"}, {"risk", "protect"} }; const char *w = who_am_i(); const char *t = name_flags & NAME_IS_XATTR ? "xattr" : name_flags & NAME_IS_DIR ? "directory" : "file"; rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n", w, actions[*w=='g'][!(ent->rflags & FILTRULE_INCLUDE)], t, name, ent->pattern, ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type); } } /* This function is used to check if a file should be included/excluded * from the list of files based on its name and type etc. The value of * filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */ int name_is_excluded(const char *fname, int name_flags, int filter_level) { if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, name_flags) < 0) { if (!(name_flags & NAME_IS_XATTR)) errno = ENOENT; return 1; } if (filter_level != ALL_FILTERS) return 0; if (filter_list.head && check_filter(&filter_list, FINFO, fname, name_flags) < 0) return 1; return 0; } int check_server_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_flags) { int ret; cur_elide_value = LOCAL_RULE; ret = check_filter(listp, code, name, name_flags); cur_elide_value = REMOTE_RULE; return ret; } /* Return -1 if file "name" is defined to be excluded by the specified * exclude list, 1 if it is included, and 0 if it was not matched. */ int check_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_flags) { filter_rule *ent; for (ent = listp->head; ent; ent = ent->next) { if (ignore_perishable && ent->rflags & FILTRULE_PERISHABLE) continue; if (ent->rflags & FILTRULE_PERDIR_MERGE) { int rc = check_filter(ent->u.mergelist, code, name, name_flags); if (rc) return rc; continue; } if (ent->rflags & FILTRULE_CVS_IGNORE) { int rc = check_filter(&cvs_filter_list, code, name, name_flags); if (rc) return rc; continue; } if (rule_matches(name, ent, name_flags)) { report_filter_result(code, name, ent, name_flags, listp->debug_type); return ent->rflags & FILTRULE_INCLUDE ? 1 : -1; } } return 0; } #define RULE_STRCMP(s,r) rule_strcmp((s), (r), sizeof (r) - 1) static const uchar *rule_strcmp(const uchar *str, const char *rule, int rule_len) { if (strncmp((char*)str, rule, rule_len) != 0) return NULL; if (isspace(str[rule_len]) || str[rule_len] == '_' || !str[rule_len]) return str + rule_len - 1; if (str[rule_len] == ',') return str + rule_len; return NULL; } #define FILTRULES_FROM_CONTAINER (FILTRULE_ABS_PATH | FILTRULE_INCLUDE \ | FILTRULE_DIRECTORY | FILTRULE_NEGATE \ | FILTRULE_PERISHABLE) /* Gets the next include/exclude rule from *rulestr_ptr and advances * *rulestr_ptr to point beyond it. Stores the pattern's start (within * *rulestr_ptr) and length in *pat_ptr and *pat_len_ptr, and returns a newly * allocated filter_rule containing the rest of the information. Returns * NULL if there are no more rules in the input. * * The template provides defaults for the new rule to inherit, and the * template rflags and the xflags additionally affect parsing. */ static filter_rule *parse_rule_tok(const char **rulestr_ptr, const filter_rule *template, int xflags, const char **pat_ptr, unsigned int *pat_len_ptr) { const uchar *s = (const uchar *)*rulestr_ptr; filter_rule *rule; unsigned int len; if (template->rflags & FILTRULE_WORD_SPLIT) { /* Skip over any initial whitespace. */ while (isspace(*s)) s++; /* Update to point to real start of rule. */ *rulestr_ptr = (const char *)s; } if (!*s) return NULL; rule = new0(filter_rule); /* Inherit from the template. Don't inherit FILTRULES_SIDES; we check * that later. */ rule->rflags = template->rflags & FILTRULES_FROM_CONTAINER; /* Figure out what kind of a filter rule "s" is pointing at. Note * that if FILTRULE_NO_PREFIXES is set, the rule is either an include * or an exclude based on the inheritance of the FILTRULE_INCLUDE * flag (above). XFLG_OLD_PREFIXES indicates a compatibility mode * for old include/exclude patterns where just "+ " and "- " are * allowed as optional prefixes. */ if (template->rflags & FILTRULE_NO_PREFIXES) { if (*s == '!' && template->rflags & FILTRULE_CVS_IGNORE) rule->rflags |= FILTRULE_CLEAR_LIST; /* Tentative! */ } else if (xflags & XFLG_OLD_PREFIXES) { if (*s == '-' && s[1] == ' ') { rule->rflags &= ~FILTRULE_INCLUDE; s += 2; } else if (*s == '+' && s[1] == ' ') { rule->rflags |= FILTRULE_INCLUDE; s += 2; } else if (*s == '!') rule->rflags |= FILTRULE_CLEAR_LIST; /* Tentative! */ } else { char ch = 0; BOOL prefix_specifies_side = False; switch (*s) { case 'c': if ((s = RULE_STRCMP(s, "clear")) != NULL) ch = '!'; break; case 'd': if ((s = RULE_STRCMP(s, "dir-merge")) != NULL) ch = ':'; break; case 'e': if ((s = RULE_STRCMP(s, "exclude")) != NULL) ch = '-'; break; case 'h': if ((s = RULE_STRCMP(s, "hide")) != NULL) ch = 'H'; break; case 'i': if ((s = RULE_STRCMP(s, "include")) != NULL) ch = '+'; break; case 'm': if ((s = RULE_STRCMP(s, "merge")) != NULL) ch = '.'; break; case 'p': if ((s = RULE_STRCMP(s, "protect")) != NULL) ch = 'P'; break; case 'r': if ((s = RULE_STRCMP(s, "risk")) != NULL) ch = 'R'; break; case 's': if ((s = RULE_STRCMP(s, "show")) != NULL) ch = 'S'; break; default: ch = *s; if (s[1] == ',') s++; break; } switch (ch) { case ':': trust_sender_filter = 1; rule->rflags |= FILTRULE_PERDIR_MERGE | FILTRULE_FINISH_SETUP; /* FALL THROUGH */ case '.': rule->rflags |= FILTRULE_MERGE_FILE; break; case '+': rule->rflags |= FILTRULE_INCLUDE; break; case '-': break; case 'S': rule->rflags |= FILTRULE_INCLUDE; /* FALL THROUGH */ case 'H': rule->rflags |= FILTRULE_SENDER_SIDE; prefix_specifies_side = True; break; case 'R': rule->rflags |= FILTRULE_INCLUDE; /* FALL THROUGH */ case 'P': rule->rflags |= FILTRULE_RECEIVER_SIDE; prefix_specifies_side = True; break; case '!': rule->rflags |= FILTRULE_CLEAR_LIST; break; default: rprintf(FERROR, "Unknown filter rule: `%s'\n", *rulestr_ptr); exit_cleanup(RERR_SYNTAX); } while (ch != '!' && *++s && *s != ' ' && *s != '_') { if (template->rflags & FILTRULE_WORD_SPLIT && isspace(*s)) { s--; break; } switch (*s) { default: invalid: rprintf(FERROR, "invalid modifier '%c' at position %d in filter rule: %s\n", *s, (int)(s - (const uchar *)*rulestr_ptr), *rulestr_ptr); exit_cleanup(RERR_SYNTAX); case '-': if (!BITS_SETnUNSET(rule->rflags, FILTRULE_MERGE_FILE, FILTRULE_NO_PREFIXES)) goto invalid; rule->rflags |= FILTRULE_NO_PREFIXES; break; case '+': if (!BITS_SETnUNSET(rule->rflags, FILTRULE_MERGE_FILE, FILTRULE_NO_PREFIXES)) goto invalid; rule->rflags |= FILTRULE_NO_PREFIXES | FILTRULE_INCLUDE; break; case '/': rule->rflags |= FILTRULE_ABS_PATH; break; case '!': /* Negation really goes with the pattern, so it * isn't useful as a merge-file default. */ if (rule->rflags & FILTRULE_MERGE_FILE) goto invalid; rule->rflags |= FILTRULE_NEGATE; break; case 'C': if (rule->rflags & FILTRULE_NO_PREFIXES || prefix_specifies_side) goto invalid; rule->rflags |= FILTRULE_NO_PREFIXES | FILTRULE_WORD_SPLIT | FILTRULE_NO_INHERIT | FILTRULE_CVS_IGNORE; break; case 'e': if (!(rule->rflags & FILTRULE_MERGE_FILE)) goto invalid; rule->rflags |= FILTRULE_EXCLUDE_SELF; break; case 'n': if (!(rule->rflags & FILTRULE_MERGE_FILE)) goto invalid; rule->rflags |= FILTRULE_NO_INHERIT; break; case 'p': rule->rflags |= FILTRULE_PERISHABLE; break; case 'r': if (prefix_specifies_side) goto invalid; rule->rflags |= FILTRULE_RECEIVER_SIDE; break; case 's': if (prefix_specifies_side) goto invalid; rule->rflags |= FILTRULE_SENDER_SIDE; break; case 'w': if (!(rule->rflags & FILTRULE_MERGE_FILE)) goto invalid; rule->rflags |= FILTRULE_WORD_SPLIT; break; case 'x': rule->rflags |= FILTRULE_XATTR; saw_xattr_filter = 1; break; } } if (*s) s++; } if (template->rflags & FILTRULES_SIDES) { if (rule->rflags & FILTRULES_SIDES) { /* The filter and template both specify side(s). This * is dodgy (and won't work correctly if the template is * a one-sided per-dir merge rule), so reject it. */ rprintf(FERROR, "specified-side merge file contains specified-side filter: %s\n", *rulestr_ptr); exit_cleanup(RERR_SYNTAX); } rule->rflags |= template->rflags & FILTRULES_SIDES; } if (template->rflags & FILTRULE_WORD_SPLIT) { const uchar *cp = s; /* Token ends at whitespace or the end of the string. */ while (!isspace(*cp) && *cp != '\0') cp++; len = cp - s; } else len = strlen((char*)s); if (rule->rflags & FILTRULE_CLEAR_LIST) { if (!(rule->rflags & FILTRULE_NO_PREFIXES) && !(xflags & XFLG_OLD_PREFIXES) && len) { rprintf(FERROR, "'!' rule has trailing characters: %s\n", *rulestr_ptr); exit_cleanup(RERR_SYNTAX); } if (len > 1) rule->rflags &= ~FILTRULE_CLEAR_LIST; } else if (!len && !(rule->rflags & FILTRULE_CVS_IGNORE)) { rprintf(FERROR, "unexpected end of filter rule: %s\n", *rulestr_ptr); exit_cleanup(RERR_SYNTAX); } /* --delete-excluded turns an un-modified include/exclude into a sender-side rule. */ if (delete_excluded && !(rule->rflags & (FILTRULES_SIDES|FILTRULE_MERGE_FILE|FILTRULE_PERDIR_MERGE))) rule->rflags |= FILTRULE_SENDER_SIDE; *pat_ptr = (const char *)s; *pat_len_ptr = len; *rulestr_ptr = *pat_ptr + len; return rule; } static void get_cvs_excludes(uint32 rflags) { static int initialized = 0; char *p, fname[MAXPATHLEN]; if (initialized) return; initialized = 1; parse_filter_str(&cvs_filter_list, default_cvsignore(), rule_template(rflags | (protocol_version >= 30 ? FILTRULE_PERISHABLE : 0)), 0); p = module_id >= 0 && lp_use_chroot(module_id) ? "/" : getenv("HOME"); if (p && pathjoin(fname, MAXPATHLEN, p, ".cvsignore") < MAXPATHLEN) parse_filter_file(&cvs_filter_list, fname, rule_template(rflags), 0); parse_filter_str(&cvs_filter_list, getenv("CVSIGNORE"), rule_template(rflags), 0); } const filter_rule *rule_template(uint32 rflags) { static filter_rule template; /* zero-initialized */ template.rflags = rflags; return &template; } void parse_filter_str(filter_rule_list *listp, const char *rulestr, const filter_rule *template, int xflags) { filter_rule *rule; const char *pat; unsigned int pat_len; if (!rulestr) return; while (1) { uint32 new_rflags; /* Remember that the returned string is NOT '\0' terminated! */ if (!(rule = parse_rule_tok(&rulestr, template, xflags, &pat, &pat_len))) break; if (pat_len >= MAXPATHLEN) { rprintf(FERROR, "discarding over-long filter: %.*s\n", (int)pat_len, pat); free_continue: free_filter(rule); continue; } new_rflags = rule->rflags; if (new_rflags & FILTRULE_CLEAR_LIST) { if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] clearing filter list%s\n", who_am_i(), listp->debug_type); } pop_filter_list(listp); listp->head = NULL; goto free_continue; } if (new_rflags & FILTRULE_MERGE_FILE) { if (!pat_len) { pat = ".cvsignore"; pat_len = 10; } if (new_rflags & FILTRULE_EXCLUDE_SELF) { const char *name; filter_rule *excl_self; excl_self = new0(filter_rule); /* Find the beginning of the basename and add an exclude for it. */ for (name = pat + pat_len; name > pat && name[-1] != '/'; name--) {} add_rule(listp, name, (pat + pat_len) - name, excl_self, 0); rule->rflags &= ~FILTRULE_EXCLUDE_SELF; } if (new_rflags & FILTRULE_PERDIR_MERGE) { if (parent_dirscan) { const char *p; unsigned int len = pat_len; if ((p = parse_merge_name(pat, &len, module_dirlen))) add_rule(listp, p, len, rule, 0); else free_filter(rule); continue; } } else { const char *p; unsigned int len = pat_len; if ((p = parse_merge_name(pat, &len, 0))) parse_filter_file(listp, p, rule, XFLG_FATAL_ERRORS); free_filter(rule); continue; } } add_rule(listp, pat, pat_len, rule, xflags); if (new_rflags & FILTRULE_CVS_IGNORE && !(new_rflags & FILTRULE_MERGE_FILE)) get_cvs_excludes(new_rflags); } } void parse_filter_file(filter_rule_list *listp, const char *fname, const filter_rule *template, int xflags) { FILE *fp; char line[BIGPATHBUFLEN]; char *eob = line + sizeof line - 1; BOOL word_split = (template->rflags & FILTRULE_WORD_SPLIT) != 0; if (!fname || !*fname) return; if (*fname != '-' || fname[1] || am_server) { if (daemon_filter_list.head) { strlcpy(line, fname, sizeof line); clean_fname(line, CFN_COLLAPSE_DOT_DOT_DIRS); if (check_filter(&daemon_filter_list, FLOG, line, 0) < 0) fp = NULL; else fp = fopen(line, "rb"); } else fp = fopen(fname, "rb"); } else fp = stdin; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] parse_filter_file(%s,%x,%x)%s\n", who_am_i(), fname, template->rflags, xflags, fp ? "" : " [not found]"); } if (!fp) { if (xflags & XFLG_FATAL_ERRORS) { rsyserr(FERROR, errno, "failed to open %sclude file %s", template->rflags & FILTRULE_INCLUDE ? "in" : "ex", fname); exit_cleanup(RERR_FILEIO); } return; } dirbuf[dirbuf_len] = '\0'; while (1) { char *s = line; int ch, overflow = 0; while (1) { if ((ch = getc(fp)) == EOF) { if (ferror(fp) && errno == EINTR) { clearerr(fp); continue; } break; } if (word_split && isspace(ch)) break; if (eol_nulls? !ch : (ch == '\n' || ch == '\r')) break; if (s < eob) *s++ = ch; else overflow = 1; } if (overflow) { rprintf(FERROR, "discarding over-long filter: %s...\n", line); s = line; } *s = '\0'; /* Skip an empty token and (when line parsing) comments. */ if (*line && (word_split || (*line != ';' && *line != '#'))) parse_filter_str(listp, line, template, xflags); if (ch == EOF) break; } fclose(fp); } /* If the "for_xfer" flag is set, the prefix is made compatible with the * current protocol_version (if possible) or a NULL is returned (if not * possible). */ char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer, unsigned int *plen_ptr) { static char buf[MAX_RULE_PREFIX+1]; char *op = buf; int legal_len = for_xfer && protocol_version < 29 ? 1 : MAX_RULE_PREFIX-1; if (rule->rflags & FILTRULE_PERDIR_MERGE) { if (legal_len == 1) return NULL; *op++ = ':'; } else if (rule->rflags & FILTRULE_INCLUDE) *op++ = '+'; else if (legal_len != 1 || ((*pat == '-' || *pat == '+') && pat[1] == ' ')) *op++ = '-'; else legal_len = 0; if (rule->rflags & FILTRULE_ABS_PATH) *op++ = '/'; if (rule->rflags & FILTRULE_NEGATE) *op++ = '!'; if (rule->rflags & FILTRULE_CVS_IGNORE) *op++ = 'C'; else { if (rule->rflags & FILTRULE_NO_INHERIT) *op++ = 'n'; if (rule->rflags & FILTRULE_WORD_SPLIT) *op++ = 'w'; if (rule->rflags & FILTRULE_NO_PREFIXES) { if (rule->rflags & FILTRULE_INCLUDE) *op++ = '+'; else *op++ = '-'; } } if (rule->rflags & FILTRULE_EXCLUDE_SELF) *op++ = 'e'; if (rule->rflags & FILTRULE_XATTR) *op++ = 'x'; if (rule->rflags & FILTRULE_SENDER_SIDE && (!for_xfer || protocol_version >= 29)) *op++ = 's'; if (rule->rflags & FILTRULE_RECEIVER_SIDE && (!for_xfer || protocol_version >= 29 || (delete_excluded && am_sender))) *op++ = 'r'; if (rule->rflags & FILTRULE_PERISHABLE) { if (!for_xfer || protocol_version >= 30) *op++ = 'p'; else if (am_sender) return NULL; } if (op - buf > legal_len) return NULL; if (legal_len) *op++ = ' '; *op = '\0'; if (plen_ptr) *plen_ptr = op - buf; return buf; } static void send_rules(int f_out, filter_rule_list *flp) { filter_rule *ent; for (ent = flp->head; ent; ent = ent->next) { unsigned int len, plen, dlen; int elide = 0; char *p; /* Note we need to check delete_excluded here in addition to * the code in parse_rule_tok() because some rules may have * been added before we found the --delete-excluded option. * We must also elide any CVS merge-file rules to avoid a * backward compatibility problem, and we elide any no-prefix * merge files as an optimization (since they can only have * include/exclude rules). */ if (ent->rflags & FILTRULE_SENDER_SIDE) elide = am_sender ? LOCAL_RULE : REMOTE_RULE; if (ent->rflags & FILTRULE_RECEIVER_SIDE) elide = elide ? 0 : am_sender ? REMOTE_RULE : LOCAL_RULE; else if (delete_excluded && !elide && (!(ent->rflags & FILTRULE_PERDIR_MERGE) || ent->rflags & FILTRULE_NO_PREFIXES)) elide = am_sender ? LOCAL_RULE : REMOTE_RULE; ent->elide = elide; if (elide == LOCAL_RULE) continue; if (ent->rflags & FILTRULE_CVS_IGNORE && !(ent->rflags & FILTRULE_MERGE_FILE)) { int f = am_sender || protocol_version < 29 ? f_out : -2; send_rules(f, &cvs_filter_list); if (f == f_out) continue; } p = get_rule_prefix(ent, ent->pattern, 1, &plen); if (!p) { rprintf(FERROR, "filter rules are too modern for remote rsync.\n"); exit_cleanup(RERR_PROTOCOL); } if (f_out < 0) continue; len = strlen(ent->pattern); dlen = ent->rflags & FILTRULE_DIRECTORY ? 1 : 0; if (!(plen + len + dlen)) continue; write_int(f_out, plen + len + dlen); if (plen) write_buf(f_out, p, plen); write_buf(f_out, ent->pattern, len); if (dlen) write_byte(f_out, '/'); } } /* This is only called by the client. */ void send_filter_list(int f_out) { int receiver_wants_list = prune_empty_dirs || (delete_mode && (!delete_excluded || protocol_version >= 29)); if (local_server || (am_sender && !receiver_wants_list)) f_out = -1; if (cvs_exclude && am_sender) { if (protocol_version >= 29) parse_filter_str(&filter_list, ":C", rule_template(0), 0); parse_filter_str(&filter_list, "-C", rule_template(0), 0); } send_rules(f_out, &filter_list); if (f_out >= 0) write_int(f_out, 0); if (cvs_exclude) { if (!am_sender || protocol_version < 29) parse_filter_str(&filter_list, ":C", rule_template(0), 0); if (!am_sender) parse_filter_str(&filter_list, "-C", rule_template(0), 0); } } /* This is only called by the server. */ void recv_filter_list(int f_in) { char line[BIGPATHBUFLEN]; int xflags = protocol_version >= 29 ? 0 : XFLG_OLD_PREFIXES; int receiver_wants_list = prune_empty_dirs || (delete_mode && (!delete_excluded || protocol_version >= 29)); unsigned int len; if (!local_server && (am_sender || receiver_wants_list)) { while ((len = read_int(f_in)) != 0) { if (len >= sizeof line) overflow_exit("recv_rules"); read_sbuf(f_in, line, len); parse_filter_str(&filter_list, line, rule_template(0), xflags); } } if (cvs_exclude) { if (local_server || am_sender || protocol_version < 29) parse_filter_str(&filter_list, ":C", rule_template(0), 0); if (local_server || am_sender) parse_filter_str(&filter_list, "-C", rule_template(0), 0); } if (local_server) /* filter out any rules that aren't for us. */ send_rules(-1, &filter_list); } rsync-3.2.7/define-from-md.awk0000775000000000000000000000146413672730211014670 0ustar rootroot#!/usr/bin/awk -f # The caller must pass args: -v hfile=NAME rsync.1.md BEGIN { heading = "/* DO NOT EDIT THIS FILE! It is auto-generated from a list of values in " ARGV[1] "! */" if (hfile ~ /compress/) { define = "#define DEFAULT_DONT_COMPRESS" prefix = "*." } else { define = "#define DEFAULT_CVSIGNORE" prefix = "" } value_list = "" } /^ > [^ ]+$/ { gsub(/`/, "") if (value_list != "") value_list = value_list " " value_list = value_list prefix $2 next } value_list ~ /\.gz / && hfile ~ /compress/ { exit } value_list ~ /SCCS / && hfile ~ /cvsignore/ { exit } value_list = "" END { if (value_list != "") print heading "\n\n" define " \"" value_list "\"" > hfile else { print "Failed to find a value list in " ARGV[1] " for " hfile exit 1 } } rsync-3.2.7/util2.c0000664000000000000000000000675513712075436012611 0ustar rootroot/* * Utility routines used in rsync. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2020 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 "itypes.h" #include "inums.h" extern size_t max_alloc; char *do_calloc = "42"; /** * Sleep for a specified number of milliseconds. * * Always returns True. **/ int msleep(int t) { #ifdef HAVE_NANOSLEEP struct timespec ts; ts.tv_sec = t / 1000; ts.tv_nsec = (t % 1000) * 1000000L; while (nanosleep(&ts, &ts) < 0 && errno == EINTR) {} #elif defined HAVE_USLEEP usleep(t*1000); #else int tdiff = 0; struct timeval tval, t1, t2; gettimeofday(&t1, NULL); while (tdiff < t) { tval.tv_sec = (t-tdiff)/1000; tval.tv_usec = 1000*((t-tdiff)%1000); errno = 0; select(0,NULL,NULL, NULL, &tval); gettimeofday(&t2, NULL); tdiff = (t2.tv_sec - t1.tv_sec)*1000 + (t2.tv_usec - t1.tv_usec)/1000; if (tdiff < 0) t1 = t2; /* Time went backwards, so start over. */ } #endif return True; } void *my_alloc(void *ptr, size_t num, size_t size, const char *file, int line) { if (max_alloc && num >= max_alloc/size) { if (!file) return NULL; rprintf(FERROR, "[%s] exceeded --max-alloc=%s setting (file=%s, line=%d)\n", who_am_i(), do_big_num(max_alloc, 0, NULL), src_file(file), line); exit_cleanup(RERR_MALLOC); } if (!ptr) ptr = malloc(num * size); else if (ptr == do_calloc) ptr = calloc(num, size); else ptr = realloc(ptr, num * size); if (!ptr && file) _out_of_memory("my_alloc caller", file, line); return ptr; } const char *sum_as_hex(int csum_type, const char *sum, int flist_csum) { static char buf[MAX_DIGEST_LEN*2+1]; int i, x1, x2; int canonical = canonical_checksum(csum_type); int sum_len = csum_len_for_type(csum_type, flist_csum); char *c; if (!canonical) return NULL; assert(sum_len*2 < (int)sizeof buf); for (i = sum_len, c = buf; --i >= 0; ) { int ndx = canonical < 0 ? sum_len - i - 1 : i; x2 = CVAL(sum, ndx); x1 = x2 >> 4; x2 &= 0xF; *c++ = x1 <= 9 ? x1 + '0' : x1 + 'a' - 10; *c++ = x2 <= 9 ? x2 + '0' : x2 + 'a' - 10; } *c = '\0'; return buf; } NORETURN void _out_of_memory(const char *msg, const char *file, int line) { rprintf(FERROR, "[%s] out of memory: %s (file=%s, line=%d)\n", who_am_i(), msg, src_file(file), line); exit_cleanup(RERR_MALLOC); } NORETURN void _overflow_exit(const char *msg, const char *file, int line) { rprintf(FERROR, "[%s] buffer overflow: %s (file=%s, line=%d)\n", who_am_i(), msg, src_file(file), line); exit_cleanup(RERR_MALLOC); } const char *src_file(const char *file) { static const char *util2 = __FILE__; static int prefix = -1; if (prefix < 0) { const char *cp = strrchr(util2, '/'); prefix = cp ? cp - util2 + 1 : 0; } if (prefix && strncmp(file, util2, prefix) == 0) return file + prefix; return file; } rsync-3.2.7/rrsync.1.html0000664000000000000000000002077714324367163013754 0ustar rootroot rrsync(1) manpage

NAME

rrsync -⁠ a script to setup restricted rsync users via ssh logins

SYNOPSIS

rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR

The single non-option argument specifies the restricted DIR to use. It can be relative to the user's home directory or an absolute path.

The online version of this manpage (that includes cross-linking of topics) is available at https://download.samba.org/pub/rsync/rrsync.1.

DESCRIPTION

A user's ssh login can be restricted to only allow the running of an rsync transfer in one of two easy ways:

  • forcing the running of the rrsync script
  • forcing the running of an rsync daemon-over-ssh command.

Both of these setups use a feature of ssh that allows a command to be forced to run instead of an interactive shell. However, if the user's home shell is bash, please see BASH SECURITY ISSUE for a potential issue.

To use the rrsync script, edit the user's ~/.ssh/authorized_keys file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted:

command="rrsync DIR"
command="rrsync -ro DIR"
command="rrsync -munge -no-del DIR"

Then, ensure that the rrsync script has your desired option restrictions. You may want to copy the script to a local bin dir with a unique name if you want to have multiple configurations. One or more rrsync options can be specified prior to the DIR if you want to further restrict the transfer.

To use an rsync daemon setup, edit the user's ~/.ssh/authorized_keys file and add a prefix like one of the following (followed by a space) in front of each ssh-key line that should be restricted:

command="rsync --server --daemon ."
command="rsync --server --daemon --config=/PATH/TO/rsyncd.conf ."

Then, ensure that the rsyncd.conf file is created with one or more module names with the appropriate path and option restrictions. If rsync's --config option is omitted, it defaults to ~/rsyncd.conf. See the rsyncd.conf(5) manpage for details of how to configure an rsync daemon.

When using rrsync, there can be just one restricted dir per authorized key. A daemon setup, on the other hand, allows multiple module names inside the config file, each one with its own path setting.

The remainder of this manpage is dedicated to using the rrsync script.

OPTIONS

-ro

Allow only reading from the DIR. Implies -no-del and -no-lock.

-wo

Allow only writing to the DIR.

-munge

Enable rsync's --munge-links on the server side.

-no-del

Disable rsync's --delete* and --remove* options.

-no-lock

Avoid the single-run (per-user) lock check. Useful with -munge.

-help, -h

Output this help message and exit.

SECURITY RESTRICTIONS

The rrsync script validates the path arguments it is sent to try to restrict them to staying within the specified DIR.

The rrsync script rejects rsync's --copy-links option (by default) so that a copy cannot dereference a symlink within the DIR to get to a file outside the DIR.

The rrsync script rejects rsync's --protect-args (-s) option because it would allow options to be sent to the server-side that the script cannot check. If you want to support --protect-args, use a daemon-over-ssh setup.

The rrsync script accepts just a subset of rsync's options that the real rsync uses when running the server command. A few extra convenience options are also included to help it to interact with BackupPC and accept some convenient user overrides.

The script (or a copy of it) can be manually edited if you want it to customize the option handling.

BASH SECURITY ISSUE

If your users have bash set as their home shell, bash may try to be overly helpful and ensure that the user's login bashrc files are run prior to executing the forced command. This can be a problem if the user can somehow update their home bashrc files, perhaps via the restricted copy, a shared home directory, or something similar.

One simple way to avoid the issue is to switch the user to a simpler shell, such as dash. When choosing the new home shell, make sure that you're not choosing bash in disguise, as it is unclear if it avoids the security issue.

Another potential fix is to ensure that the user's home directory is not a shared mount and that they have no means of copying files outside of their restricted directories. This may require you to force the enabling of symlink munging on the server side.

A future version of openssh may have a change to the handling of forced commands that allows it to avoid using the user's home shell.

EXAMPLES

The ~/.ssh/authorized_keys file might have lines in it like this:

command="rrsync client/logs" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzG...
command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmk...

FILES

~/.ssh/authorized_keys

SEE ALSO

rsync(1), rsyncd.conf(5)

VERSION

This manpage is current for version 3.2.7 of rsync.

CREDITS

rsync is distributed under the GNU General Public License. See the file COPYING for details.

An rsync web site is available at https://rsync.samba.org/ and its github project is https://github.com/WayneD/rsync.

AUTHOR

The original rrsync perl script was written by Joe Smith. Many people have later contributed to it. The python version was created by Wayne Davison.

20 Oct 2022

rsync-3.2.7/rsync.c0000664000000000000000000005703114275762461012707 0ustar rootroot/* * Routines common to more than one of the rsync processes. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2022 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" #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET #include #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO #include #endif extern int dry_run; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_perms; extern int preserve_executability; extern int preserve_mtimes; extern int omit_dir_times; extern int omit_link_times; extern int am_root; extern int am_server; extern int am_daemon; extern int am_sender; extern int am_receiver; extern int am_generator; extern int am_starting_up; extern int allow_8bit_chars; extern int protocol_version; extern int got_kill_signal; extern int called_from_signal_handler; extern int inc_recurse; extern int inplace; extern int flist_eof; extern int file_old_total; extern int keep_dirlinks; extern int make_backups; extern int sanitize_paths; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern struct chmod_mode_struct *daemon_chmod_modes; #ifdef ICONV_OPTION extern char *iconv_opt; #endif #define UPDATED_OWNER (1<<0) #define UPDATED_GROUP (1<<1) #define UPDATED_MTIME (1<<2) #define UPDATED_ATIME (1<<3) #define UPDATED_ACLS (1<<4) #define UPDATED_MODE (1<<5) #define UPDATED_CRTIME (1<<6) #ifdef ICONV_CONST iconv_t ic_chck = (iconv_t)-1; # ifdef ICONV_OPTION iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1; # endif static const char *default_charset(void) { # if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET return locale_charset(); # elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO return nl_langinfo(CODESET); # else return ""; /* Works with (at the very least) gnu iconv... */ # endif } void setup_iconv(void) { const char *defset = default_charset(); # ifdef ICONV_OPTION const char *charset; char *cp; # endif if (!am_server && !allow_8bit_chars) { /* It's OK if this fails... */ ic_chck = iconv_open(defset, defset); if (DEBUG_GTE(ICONV, 2)) { if (ic_chck == (iconv_t)-1) { rprintf(FINFO, "msg checking via isprint()" " (iconv_open(\"%s\", \"%s\") errno: %d)\n", defset, defset, errno); } else { rprintf(FINFO, "msg checking charset: %s\n", defset); } } } else ic_chck = (iconv_t)-1; # ifdef ICONV_OPTION if (!iconv_opt) return; if ((cp = strchr(iconv_opt, ',')) != NULL) { if (am_server) /* A local transfer needs this. */ iconv_opt = cp + 1; else *cp = '\0'; } if (!*iconv_opt || (*iconv_opt == '.' && iconv_opt[1] == '\0')) charset = defset; else charset = iconv_opt; if ((ic_send = iconv_open(UTF8_CHARSET, charset)) == (iconv_t)-1) { rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n", UTF8_CHARSET, charset); exit_cleanup(RERR_UNSUPPORTED); } if ((ic_recv = iconv_open(charset, UTF8_CHARSET)) == (iconv_t)-1) { rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n", charset, UTF8_CHARSET); exit_cleanup(RERR_UNSUPPORTED); } if (DEBUG_GTE(ICONV, 1)) { rprintf(FINFO, "[%s] charset: %s\n", who_am_i(), *charset ? charset : "[LOCALE]"); } # endif } /* This function converts the chars in the "in" xbuf into characters in the * "out" xbuf. The ".len" chars of the "in" xbuf is used starting from its * ".pos". The ".size" of the "out" xbuf restricts how many characters can * be stored, starting at its ".pos+.len" position. Note that the last byte * of the "out" xbuf is not used, which reserves space for a trailing '\0' * (though it is up to the caller to store a trailing '\0', as needed). * * We return a 0 on success or a -1 on error. An error also sets errno to * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0. * The "in" xbuf is altered to update ".pos" and ".len". The "out" xbuf has * data appended, and its ".len" incremented (see below for a ".size" note). * * If ICB_CIRCULAR_OUT is set in "flags", the chars going into the "out" xbuf * can wrap around to the start, and the xbuf may have its ".size" reduced * (presumably by 1 byte) if the iconv code doesn't have space to store a * multi-byte character at the physical end of the ".buf" (though no reducing * happens if ".pos" is <= 1, since there is no room to wrap around). * * If ICB_EXPAND_OUT is set in "flags", the "out" xbuf will be allocated if * empty, and (as long as ICB_CIRCULAR_OUT is not set) expanded if too small. * This prevents the return of E2BIG (except for a circular xbuf). * * If ICB_INCLUDE_BAD is set in "flags", any badly-encoded chars are included * verbatim in the "out" xbuf, so EILSEQ will not be returned. * * If ICB_INCLUDE_INCOMPLETE is set in "flags", any incomplete multi-byte * chars are included, which ensures that EINVAL is not returned. * * If ICB_INIT is set, the iconv() conversion state is initialized prior to * processing the characters. */ int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags) { ICONV_CONST char *ibuf; size_t icnt, ocnt, opos; char *obuf; if (!out->size && flags & ICB_EXPAND_OUT) { size_t siz = ROUND_UP_1024(in->len * 2); alloc_xbuf(out, siz); } else if (out->len+1 >= out->size) { /* There is no room to even start storing data. */ if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) { errno = E2BIG; return -1; } realloc_xbuf(out, out->size + ROUND_UP_1024(in->len * 2)); } if (flags & ICB_INIT) iconv(ic, NULL, 0, NULL, 0); ibuf = in->buf + in->pos; icnt = in->len; opos = out->pos + out->len; if (flags & ICB_CIRCULAR_OUT) { if (opos >= out->size) { opos -= out->size; /* We know that out->pos is not 0 due to the "no room" check * above, so this can't go "negative". */ ocnt = out->pos - opos - 1; } else { /* Allow the use of all bytes to the physical end of the buffer * unless pos is 0, in which case we reserve our trailing '\0'. */ ocnt = out->size - opos - (out->pos ? 0 : 1); } } else ocnt = out->size - opos - 1; obuf = out->buf + opos; while (icnt) { while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) { if (errno == EINTR) continue; if (errno == EINVAL) { if (!(flags & ICB_INCLUDE_INCOMPLETE)) goto finish; if (!ocnt) goto e2big; } else if (errno == EILSEQ) { if (!(flags & ICB_INCLUDE_BAD)) goto finish; if (!ocnt) goto e2big; } else if (errno == E2BIG) { size_t siz; e2big: opos = obuf - out->buf; if (flags & ICB_CIRCULAR_OUT && out->pos > 1 && opos > out->pos) { /* We are in a divided circular buffer at the physical * end with room to wrap to the start. If iconv() refused * to use one or more trailing bytes in the buffer, we * set the size to ignore the unused bytes. */ if (opos < out->size) reduce_iobuf_size(out, opos); obuf = out->buf; ocnt = out->pos - 1; continue; } if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) { errno = E2BIG; goto finish; } siz = ROUND_UP_1024(in->len * 2); realloc_xbuf(out, out->size + siz); obuf = out->buf + opos; ocnt += siz; continue; } else { rsyserr(FERROR, errno, "unexpected error from iconv()"); exit_cleanup(RERR_UNSUPPORTED); } *obuf++ = *ibuf++; ocnt--, icnt--; if (!icnt) break; } } errno = 0; finish: opos = obuf - out->buf; if (flags & ICB_CIRCULAR_OUT && opos < out->pos) opos += out->size; out->len = opos - out->pos; in->len = icnt; in->pos = ibuf - in->buf; return errno ? -1 : 0; } #endif void send_protected_args(int fd, char *args[]) { int i; #ifdef ICONV_OPTION int convert = ic_send != (iconv_t)-1; xbuf outbuf, inbuf; if (convert) alloc_xbuf(&outbuf, 1024); #endif for (i = 0; args[i]; i++) {} /* find first NULL */ args[i] = "rsync"; /* set a new arg0 */ if (DEBUG_GTE(CMD, 1)) print_child_argv("protected args:", args + i + 1); do { if (!args[i][0]) write_buf(fd, ".", 2); #ifdef ICONV_OPTION else if (convert) { INIT_XBUF_STRLEN(inbuf, args[i]); iconvbufs(ic_send, &inbuf, &outbuf, ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_INIT); outbuf.buf[outbuf.len] = '\0'; write_buf(fd, outbuf.buf, outbuf.len + 1); outbuf.len = 0; } #endif else write_buf(fd, args[i], strlen(args[i]) + 1); } while (args[++i]); write_byte(fd, 0); #ifdef ICONV_OPTION if (convert) free(outbuf.buf); #endif } int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) { int len, iflags = 0; struct file_list *flist; uchar fnamecmp_type = FNAMECMP_FNAME; int ndx; read_loop: while (1) { ndx = read_ndx(f_in); if (ndx >= 0) break; if (ndx == NDX_DONE) return ndx; if (ndx == NDX_DEL_STATS) { read_del_stats(f_in); if (am_sender && am_server) write_del_stats(f_out); continue; } if (!inc_recurse || am_sender) { int last; if (first_flist) last = first_flist->prev->ndx_start + first_flist->prev->used - 1; else last = -1; rprintf(FERROR, "Invalid file index: %d (%d - %d) [%s]\n", ndx, NDX_DONE, last, who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (ndx == NDX_FLIST_EOF) { flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); write_int(f_out, NDX_FLIST_EOF); continue; } ndx = NDX_FLIST_OFFSET - ndx; if (ndx < 0 || ndx >= dir_flist->used) { ndx = NDX_FLIST_OFFSET - ndx; rprintf(FERROR, "Invalid dir index: %d (%d - %d) [%s]\n", ndx, NDX_FLIST_OFFSET, NDX_FLIST_OFFSET - dir_flist->used + 1, who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } /* Send all the data we read for this flist to the generator. */ start_flist_forward(ndx); flist = recv_file_list(f_in, ndx); flist->parent_ndx = ndx; stop_flist_forward(); } iflags = protocol_version >= 29 ? read_shortint(f_in) : ITEM_TRANSFER | ITEM_MISSING_DATA; /* Support the protocol-29 keep-alive style. */ if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) { if (am_sender) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); goto read_loop; } flist = flist_for_ndx(ndx, "read_ndx_and_attrs"); if (flist != cur_flist) { cur_flist = flist; if (am_sender) { file_old_total = cur_flist->used; for (flist = first_flist; flist != cur_flist; flist = flist->next) file_old_total += flist->used; } } if (iflags & ITEM_BASIS_TYPE_FOLLOWS) fnamecmp_type = read_byte(f_in); *type_ptr = fnamecmp_type; if (iflags & ITEM_XNAME_FOLLOWS) { if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) exit_cleanup(RERR_PROTOCOL); if (sanitize_paths) { sanitize_path(buf, buf, "", 0, SP_DEFAULT); len = strlen(buf); } } else { *buf = '\0'; len = -1; } *len_ptr = len; if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } *iflag_ptr = iflags; return ndx; } /* free a sums struct */ void free_sums(struct sum_struct *s) { if (s->sums) free(s->sums); free(s); } /* This is only called when we aren't preserving permissions. Figure out what * the permissions should be and return them merged back into the mode. */ mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, int exists) { int new_mode; /* If the file already exists, we'll return the local permissions, * possibly tweaked by the --executability option. */ if (exists) { new_mode = (flist_mode & ~CHMOD_BITS) | (stat_mode & CHMOD_BITS); if (preserve_executability && S_ISREG(flist_mode)) { /* If the source file is executable, grant execute * rights to everyone who can read, but ONLY if the * file isn't already executable. */ if (!(flist_mode & 0111)) new_mode &= ~0111; else if (!(stat_mode & 0111)) new_mode |= (new_mode & 0444) >> 2; } } else { /* Apply destination default permissions and turn * off special permissions. */ new_mode = flist_mode & (~CHMOD_BITS | dflt_perms); } return new_mode; } static int same_mtime(struct file_struct *file, STRUCT_STAT *st, int extra_accuracy) { #ifdef ST_MTIME_NSEC uint32 f1_nsec = F_MOD_NSEC_or_0(file); uint32 f2_nsec = (uint32)st->ST_MTIME_NSEC; #else uint32 f1_nsec = 0, f2_nsec = 0; #endif if (extra_accuracy) /* ignore modify_window when setting the time after a transfer or checksum check */ return file->modtime == st->st_mtime && f1_nsec == f2_nsec; return same_time(file->modtime, f1_nsec, st->st_mtime , f2_nsec); } int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags) { int updated = 0; stat_x sx2; int change_uid, change_gid; mode_t new_mode = file->mode; int inherit; if (!sxp) { if (dry_run) return 1; if (link_stat(fname, &sx2.st, 0) < 0) { rsyserr(FERROR_XFER, errno, "stat %s failed", full_fname(fname)); return 0; } init_stat_x(&sx2); sxp = &sx2; inherit = !preserve_perms; } else inherit = !preserve_perms && file->flags & FLAG_DIR_CREATED; if (inherit && S_ISDIR(new_mode) && sxp->st.st_mode & S_ISGID) { /* We just created this directory and its setgid * bit is on, so make sure it stays on. */ new_mode |= S_ISGID; } if (daemon_chmod_modes && !S_ISLNK(new_mode)) new_mode = tweak_mode(new_mode, daemon_chmod_modes); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp)) get_acl(fname, sxp); #endif change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file); change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file); #ifndef CAN_CHOWN_SYMLINK if (S_ISLNK(sxp->st.st_mode)) { ; } else #endif if (change_uid || change_gid) { if (DEBUG_GTE(OWN, 1)) { if (change_uid) { rprintf(FINFO, "set uid of %s from %u to %u\n", fname, (unsigned)sxp->st.st_uid, F_OWNER(file)); } if (change_gid) { rprintf(FINFO, "set gid of %s from %u to %u\n", fname, (unsigned)sxp->st.st_gid, F_GROUP(file)); } } if (am_root >= 0) { uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid; gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid; if (do_lchown(fname, uid, gid) != 0) { /* We shouldn't have attempted to change uid * or gid unless have the privilege. */ rsyserr(FERROR_XFER, errno, "%s %s failed", change_uid ? "chown" : "chgrp", full_fname(fname)); goto cleanup; } if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1) rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname)); if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1) rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname)); /* A lchown had been done, so we need to re-stat if * the destination had the setuid or setgid bits set * (due to the side effect of the chown call). */ if (sxp->st.st_mode & (S_ISUID | S_ISGID)) { link_stat(fname, &sxp->st, keep_dirlinks && S_ISDIR(sxp->st.st_mode)); } } if (change_uid) updated |= UPDATED_OWNER; if (change_gid) updated |= UPDATED_GROUP; } #ifdef SUPPORT_XATTRS if (am_root < 0) set_stat_xattr(fname, file, new_mode); if (preserve_xattrs && fnamecmp) set_xattr(fname, file, fnamecmp, sxp); #endif if ((omit_dir_times && S_ISDIR(sxp->st.st_mode)) || (omit_link_times && S_ISLNK(sxp->st.st_mode))) flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME; else { if (!preserve_mtimes) flags |= ATTRS_SKIP_MTIME; if (!atimes_ndx || S_ISDIR(sxp->st.st_mode)) flags |= ATTRS_SKIP_ATIME; /* Don't set the creation date on the root folder of an HFS+ volume. */ if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode)) flags |= ATTRS_SKIP_CRTIME; } if (sxp != &sx2) memcpy(&sx2.st, &sxp->st, sizeof sx2.st); if (!(flags & ATTRS_SKIP_MTIME) && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) { sx2.st.st_mtime = file->modtime; #ifdef ST_MTIME_NSEC sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file); #endif updated |= UPDATED_MTIME; } if (!(flags & ATTRS_SKIP_ATIME)) { time_t file_atime = F_ATIME(file); if (flags & ATTRS_ACCURATE_TIME || !same_time(sxp->st.st_atime, 0, file_atime, 0)) { sx2.st.st_atime = file_atime; #ifdef ST_ATIME_NSEC sx2.st.ST_ATIME_NSEC = 0; #endif updated |= UPDATED_ATIME; } } #ifdef SUPPORT_CRTIMES if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) { time_t file_crtime = F_CRTIME(file); if (sxp->crtime == 0) sxp->crtime = get_create_time(fname, &sxp->st); if (!same_time(sxp->crtime, 0L, file_crtime, 0L)) { if ( #ifdef HAVE_GETATTRLIST do_setattrlist_crtime(fname, file_crtime) == 0 #elif defined __CYGWIN__ do_SetFileTime(fname, file_crtime) == 0 #else #error Unknown crtimes implementation #endif ) updated |= UPDATED_CRTIME; } } #endif if (updated & (UPDATED_MTIME|UPDATED_ATIME)) { int ret = set_times(fname, &sx2.st); if (ret < 0) { rsyserr(FERROR_XFER, errno, "failed to set times on %s", full_fname(fname)); goto cleanup; } if (ret > 0) { /* ret == 1 if symlink could not be set */ updated &= ~(UPDATED_MTIME|UPDATED_ATIME); file->flags |= FLAG_TIME_FAILED; } } #ifdef SUPPORT_ACLS /* It's OK to call set_acl() now, even for a dir, as the generator * will enable owner-writability using chmod, if necessary. * * If set_acl() changes permission bits in the process of setting * an access ACL, it changes sxp->st.st_mode so we know whether we * need to chmod(). */ if (preserve_acls && !S_ISLNK(new_mode)) { if (set_acl(fname, file, sxp, new_mode) > 0) updated |= UPDATED_ACLS; } #endif #ifdef HAVE_CHMOD if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) { int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode); if (ret < 0) { rsyserr(FERROR_XFER, errno, "failed to set permissions on %s", full_fname(fname)); goto cleanup; } if (ret == 0) /* ret == 1 if symlink could not be set */ updated |= UPDATED_MODE; } #endif if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) { if (updated) rprintf(FCLIENT, "%s\n", fname); else rprintf(FCLIENT, "%s is uptodate\n", fname); } cleanup: if (sxp == &sx2) free_stat_x(&sx2); return updated; } /* This is only called for SIGINT, SIGHUP, and SIGTERM. */ void sig_int(int sig_num) { called_from_signal_handler = 1; /* KLUGE: if the user hits Ctrl-C while ssh is prompting * for a password, then our cleanup's sending of a SIGUSR1 * signal to all our children may kill ssh before it has a * chance to restore the tty settings (i.e. turn echo back * on). By sleeping for a short time, ssh gets a bigger * chance to do the right thing. If child processes are * not ssh waiting for a password, then this tiny delay * shouldn't hurt anything. */ msleep(400); /* If we're an rsync daemon listener (not a daemon server), * we'll exit with status 0 if we received SIGTERM. */ if (am_daemon && !am_server && sig_num == SIGTERM) exit_cleanup(0); /* If the signal arrived on the server side (or for the receiver * process on the client), we want to try to do a controlled shutdown * that lets the client side (generator process) know what happened. * To do this, we set a flag and let the normal process handle the * shutdown. We only attempt this if multiplexed IO is in effect and * we didn't already set the flag. */ if (!got_kill_signal && (am_server || am_receiver)) { got_kill_signal = sig_num; called_from_signal_handler = 0; return; } exit_cleanup(RERR_SIGNAL); } /* Finish off a file transfer: renaming the file and setting the file's * attributes (e.g. permissions, ownership, etc.). If the robust_rename() * call is forced to copy the temp file and partialptr is both non-NULL and * not an absolute path, we stage the file into the partial-dir and then * rename it into place. This returns 1 on success or 0 on failure. */ int finish_transfer(const char *fname, const char *fnametmp, const char *fnamecmp, const char *partialptr, struct file_struct *file, int ok_to_set_time, int overwriting_basis) { int ret; const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL; if (inplace) { if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "finishing %s\n", fname); fnametmp = fname; goto do_set_file_attrs; } if (make_backups > 0 && overwriting_basis) { int ok = make_backup(fname, False); if (!ok) exit_cleanup(RERR_FILEIO); if (ok == 1 && fnamecmp == fname) fnamecmp = get_backup_name(fname); } /* Change permissions before putting the file into place. */ set_file_attrs(fnametmp, file, NULL, fnamecmp, ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME); /* move tmp file over real file */ if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname); ret = robust_rename(fnametmp, fname, temp_copy_name, file->mode); if (ret < 0) { rsyserr(FERROR_XFER, errno, "%s %s -> \"%s\"", ret == -2 ? "copy" : "rename", full_fname(fnametmp), fname); if (!partialptr || (ret == -2 && temp_copy_name) || robust_rename(fnametmp, partialptr, NULL, file->mode) < 0) do_unlink(fnametmp); return 0; } if (ret == 0) { /* The file was moved into place (not copied), so it's done. */ return 1; } /* The file was copied, so tweak the perms of the copied file. If it * was copied to partialptr, move it into its final destination. */ fnametmp = temp_copy_name ? temp_copy_name : fname; do_set_file_attrs: set_file_attrs(fnametmp, file, NULL, fnamecmp, ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME); if (temp_copy_name) { if (do_rename(fnametmp, fname) < 0) { rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\"", full_fname(fnametmp), fname); return 0; } handle_partial_dir(temp_copy_name, PDIR_DELETE); } return 1; } struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc) { struct file_list *flist = cur_flist; if (!flist && !(flist = first_flist)) goto not_found; while (ndx < flist->ndx_start-1) { if (flist == first_flist) goto not_found; flist = flist->prev; } while (ndx >= flist->ndx_start + flist->used) { if (!(flist = flist->next)) goto not_found; } return flist; not_found: if (fatal_error_loc) { int first, last; if (first_flist) { first = first_flist->ndx_start - 1; last = first_flist->prev->ndx_start + first_flist->prev->used - 1; } else { first = 0; last = -1; } rprintf(FERROR, "File-list index %d not in %d - %d (%s) [%s]\n", ndx, first, last, fatal_error_loc, who_am_i()); exit_cleanup(RERR_PROTOCOL); } return NULL; } const char *who_am_i(void) { if (am_starting_up) return am_server ? "server" : "client"; return am_sender ? "sender" : am_generator ? "generator" : am_receiver ? "receiver" : "Receiver"; /* pre-forked receiver */ } rsync-3.2.7/TODO0000664000000000000000000003640213674220313012057 0ustar rootroot-*- indented-text -*- FEATURES ------------------------------------------------------------ Use chroot only if supported Allow supplementary groups in rsyncd.conf 2002/04/09 Handling IPv6 on old machines Other IPv6 stuff Add ACL support 2001/12/02 proxy authentication 2002/01/23 SOCKS 2002/01/23 FAT support --diff david.e.sewell 2002/03/15 Add daemon --no-fork option Create more granular verbosity 2003/05/15 DOCUMENTATION -------------------------------------------------------- Keep list of open issues and todos on the web site Perhaps redo manual as SGML LOGGING -------------------------------------------------------------- Memory accounting Improve error messages Better statistics Rasmus 2002/03/08 Perhaps flush stdout like syslog Log child death on signal verbose output David Stein 2001/12/20 internationalization DEVELOPMENT -------------------------------------------------------- Handling duplicate names Use generic zlib 2002/02/25 TDB 2002/03/12 Splint 2002/03/12 PERFORMANCE ---------------------------------------------------------- Traverse just one directory at a time Allow skipping MD4 file_sum 2002/04/08 Accelerate MD4 TESTING -------------------------------------------------------------- Torture test Cross-test versions 2001/08/22 Test on kernel source Test large files Create mutator program for testing Create configure option to enable dangerous tests Create pipe program for testing Create test makefile target for some tests RELATED PROJECTS ----------------------------------------------------- rsyncsh https://rsync.samba.org/rsync-and-debian/ rsyncable gzip patch rsyncsplit as alternative to real integration with gzip? reverse rsync over HTTP Range FEATURES ------------------------------------------------------------ Use chroot only if supported If the platform doesn't support it, then don't even try. If running as non-root, then don't fail, just give a warning. (There was a thread about this a while ago?) https://lists.samba.org/pipermail/rsync/2001-August/thread.html https://lists.samba.org/pipermail/rsync/2001-September/thread.html -- -- Allow supplementary groups in rsyncd.conf 2002/04/09 Perhaps allow supplementary groups to be specified in rsyncd.conf; then make the first one the primary gid and all the rest be supplementary gids. -- -- Handling IPv6 on old machines The KAME IPv6 patch is nice in theory but has proved a bit of a nightmare in practice. The basic idea of their patch is that rsync is rewritten to use the new getaddrinfo()/getnameinfo() interface, rather than gethostbyname()/gethostbyaddr() as in rsync 2.4.6. Systems that don't have the new interface are handled by providing our own implementation in lib/, which is selectively linked in. The problem with this is that it is really hard to get right on platforms that have a half-working implementation, so redefining these functions clashes with system headers, and leaving them out breaks. This affects at least OSF/1, RedHat 5, and Cobalt, which are moderately important. Perhaps the simplest solution would be to have two different files implementing the same interface, and choose either the new or the old API. This is probably necessary for systems that e.g. have IPv6, but gethostbyaddr() can't handle it. The Linux manpage claims this is currently the case. In fact, our internal sockets interface (things like open_socket_out(), etc) is much narrower than the getaddrinfo() interface, and so probably simpler to get right. In addition, the old code is known to work well on old machines. We could drop the rather large lib/getaddrinfo files. -- -- Other IPv6 stuff Implement suggestions from http://www.kame.net/newsletter/19980604/ and ftp://ftp.iij.ad.jp/pub/RFC/rfc2553.txt If a host has multiple addresses, then listen try to connect to all in order until we get through. (getaddrinfo may return multiple addresses.) This is kind of implemented already. Possibly also when starting as a server we may need to listen on multiple passive addresses. This might be a bit harder, because we may need to select on all of them. Hm. -- -- Add ACL support 2001/12/02 Transfer ACLs. Need to think of a standard representation. Probably better not to even try to convert between NT and POSIX. Possibly can share some code with Samba. NOTE: there is a patch that implements this in the "patches" subdir. -- -- proxy authentication 2002/01/23 Allow RSYNC_PROXY to be http://user:pass@proxy.foo:3128/, and do HTTP Basic Proxy-Authentication. Multiple schemes are possible, up to and including the insanity that is NTLM, but Basic probably covers most cases. -- -- SOCKS 2002/01/23 Add --with-socks, and then perhaps a command-line option to put them on or off. This might be more reliable than LD_PRELOAD hacks. -- -- FAT support rsync to a FAT partition on a Unix machine doesn't work very well at the moment. I think we get errors about invalid filenames and perhaps also trying to do atomic renames. I guess the code to do this is currently #ifdef'd on Windows; perhaps we ought to intelligently fall back to it on Unix too. -- -- --diff david.e.sewell 2002/03/15 Allow people to specify the diff command. (Might want to use wdiff, gnudiff, etc.) Just diff the temporary file with the destination file, and delete the tmp file rather than moving it into place. Interaction with --partial. Security interactions with daemon mode? -- -- Add daemon --no-fork option Very useful for debugging. Also good when running under a daemon-monitoring process that tries to restart the service when the parent exits. -- -- Create more granular verbosity 2003/05/15 Control output with the --report option. The option takes as a single argument (no whitespace) a comma delimited lists of keywords. This would separate debugging from "logging" as well as fine grained selection of statistical reporting and what actions are logged. https://lists.samba.org/archive/rsync/2003-May/006059.html -- -- DOCUMENTATION -------------------------------------------------------- Keep list of open issues and todos on the web site -- -- Perhaps redo manual as SGML The man page is getting rather large, and there is more information that ought to be added. TexInfo source is probably a dying format. Linuxdoc looks like the most likely contender. I know DocBook is favoured by some people, but it's so bloody verbose, even with emacs support. -- -- LOGGING -------------------------------------------------------------- Memory accounting At exit, show how much memory was used for the file list, etc. We also do a weird exponential-growth allocation in flist.c. I'm not sure this makes sense with modern mallocs. At any rate it will make us allocate a huge amount of memory for large file lists. -- -- Improve error messages If we hang or get SIGINT, then explain where we were up to. Perhaps have a static buffer that contains the current function name, or some kind of description of what we were trying to do. This is a little easier on people than needing to run strace/truss. "The dungeon collapses! You are killed." Rather than "unexpected eof" give a message that is more detailed if possible and also more helpful. If we get an error writing to a socket, then we should perhaps continue trying to read to see if an error message comes across explaining why the socket is closed. I'm not sure if this would work, but it would certainly make our messages more helpful. What happens if a directory is missing -x attributes. Do we lose our load? (Debian #28416) Probably fixed now, but a test case would be good. -- -- Better statistics Rasmus 2002/03/08 hey, how about an rsync option that just gives you the summary without the list of files? And perhaps gives more information like the number of new files, number of changed, deleted, etc. ? nice idea there is --stats but at the moment it's very tridge-oriented rather than user-friendly it would be nice to improve it that would also work well with --dryrun -- -- Perhaps flush stdout like syslog Perhaps flush stdout after each filename, so that people trying to monitor progress in a log file can do so more easily. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48108 -- -- Log child death on signal If a child of the rsync daemon dies with a signal, we should notice that when we reap it and log a message. -- -- verbose output David Stein 2001/12/20 At end of transfer, show how many files were or were not transferred correctly. -- -- internationalization Change to using gettext(). Probably need to ship this for platforms that don't have it. Solicit translations. Does anyone care? Before we bother modifying the code, we ought to get the manual translated first, because that's possibly more useful and at any rate demonstrates desire. -- -- DEVELOPMENT -------------------------------------------------------- Handling duplicate names Some folks would like rsync to be deterministic in how it handles duplicate names that come from mering multiple source directories into a single destination directory; e.g. the last name wins. We could do this by switching our sort algorithm to one that will guarantee that the names won't be reordered. Alternately, we could assign an ever-increasing number to each item as we insert it into the list and then make sure that we leave the largest number when cleaning the file list (see clean_flist()). Another solution would be to add a hash table, and thus never put any duplicate names into the file list (and bump the protocol to handle this). -- -- Use generic zlib 2002/02/25 Perhaps don't use our own zlib. Advantages: - will automatically be up to date with bugfixes in zlib - can leave it out for small rsync on e.g. recovery disks - can use a shared library - avoids people breaking rsync by trying to do this themselves and messing up Should we ship zlib for systems that don't have it, or require people to install it separately? Apparently this will make us incompatible with versions of rsync that use the patched version of rsync. Probably the simplest way to do this is to just disable gzip (with a warning) when talking to old versions. -- -- Splint 2002/03/12 Build rsync with SPLINT to try to find security holes. Add annotations as necessary. Keep track of the number of warnings found initially, and see how many of them are real bugs, or real security bugs. Knowing the percentage of likely hits would be really interesting for other projects. -- -- PERFORMANCE ---------------------------------------------------------- Allow skipping MD4 file_sum 2002/04/08 If we're doing a local transfer, or using -W, then perhaps don't send the file checksum. If we're doing a local transfer, then calculating MD4 checksums uses 90% of CPU and is unlikely to be useful. We should not allow it to be disabled separately from -W, though as it is the only thing that lets us know when the rsync algorithm got out of sync and messed the file up (i.e. if the basis file changed between checksum generation and reception). -- -- Accelerate MD4 Perhaps borrow an assembler MD4 from someone? Make sure we call MD4 with properly-sized blocks whenever possible to avoid copying into the residue region? -- -- TESTING -------------------------------------------------------------- Torture test Something that just keeps running rsync continuously over a data set likely to generate problems. -- -- Cross-test versions 2001/08/22 Part of the regression suite should be making sure that we don't break backwards compatibility: old clients vs new servers and so on. Ideally we would test both up and down from the current release to all old versions. Run current rsync versions against significant past releases. We might need to omit broken old versions, or versions in which particular functionality is broken It might be sufficient to test downloads from well-known public rsync servers running different versions of rsync. This will give some testing and also be the most common case for having different versions and not being able to upgrade. The new --protocol option may help in this. -- -- Test on kernel source Download all versions of kernel; unpack, sync between them. Also sync between uncompressed tarballs. Compare directories after transfer. Use local mode; ssh; daemon; --whole-file and --no-whole-file. Use awk to pull out the 'speedup' number for each transfer. Make sure it is >= x. -- -- Test large files Sparse and non-sparse -- -- Create mutator program for testing Insert bytes, delete bytes, swap blocks, ... -- -- Create configure option to enable dangerous tests -- -- Create pipe program for testing Create pipe program that makes slow/jerky connections for testing Versions of read() and write() that corrupt the stream, or abruptly fail -- -- Create test makefile target for some tests Separate makefile target to run rough tests -- or perhaps just run them every time? -- -- RELATED PROJECTS ----------------------------------------------------- rsyncsh Write a small emulation of interactive ftp as a Pythonn program that calls rsync. Commands such as "cd", "ls", "ls *.c" etc map fairly directly into rsync commands: it just needs to remember the current host, directory and so on. We can probably even do completion of remote filenames. -- -- https://rsync.samba.org/rsync-and-debian/ -- -- rsyncable gzip patch Exhaustive, tortuous testing Cleanups? -- -- rsyncsplit as alternative to real integration with gzip? -- -- reverse rsync over HTTP Range Goswin Brederlow suggested this on Debian; I think tridge and I talked about it previous in relation to rproxy. Addendum: It looks like someone is working on a version of this: http://zsync.moria.org.uk/ -- -- rsync-3.2.7/getgroups.c0000664000000000000000000000276213676015150013557 0ustar rootroot/* * Print out the gids of all groups for the current user. This is like * `id -G` on Linux, but it's too hard to find a portable equivalent. * * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2020 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * 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" int main(UNUSED(int argc), UNUSED(char *argv[])) { int n, i; gid_t *list; gid_t gid = MY_GID(); int gid_in_list = 0; #ifdef HAVE_GETGROUPS if ((n = getgroups(0, NULL)) < 0) { perror("getgroups"); return 1; } #else n = 0; #endif list = (gid_t*)malloc(sizeof (gid_t) * (n + 1)); if (!list) { fprintf(stderr, "out of memory!\n"); exit(1); } #ifdef HAVE_GETGROUPS if (n > 0) n = getgroups(n, list); #endif for (i = 0; i < n; i++) { printf("%lu ", (unsigned long)list[i]); if (list[i] == gid) gid_in_list = 1; } /* The default gid might not be in the list on some systems. */ if (!gid_in_list) printf("%lu", (unsigned long)gid); printf("\n"); return 0; } rsync-3.2.7/rsync3.txt0000664000000000000000000003453413674220313013355 0ustar rootroot-*- indented-text -*- Notes towards a new version of rsync Martin Pool , September 2001. Good things about the current implementation: - Widely known and adopted. - Fast/efficient, especially for moderately small sets of files over slow links (transoceanic or modem.) - Fairly reliable. - The choice of running over a plain TCP socket or tunneling over ssh. - rsync operations are idempotent: you can always run the same command twice to make sure it worked properly without any fear. (Are there any exceptions?) - Small changes to files cause small deltas. - There is a way to evolve the protocol to some extent. - rdiff and rsync --write-batch allow generation of standalone patch sets. rsync+ is pretty cheesy, though. xdelta seems cleaner. - Process triangle is creative, but seems to provoke OS bugs. - "Morning-after property": you don't need to know anything on the local machine about the state of the remote machine, or about transfers that have been done in the past. - You can easily push or pull simply by switching the order of files. - The "modules" system has some neat features compared to e.g. Apache's per-directory configuration. In particular, because you can set a userid and chroot directory, there is strong protection between different modules. I haven't seen any calls for a more flexible system. Bad things about the current implementation: - Persistent and hard-to-diagnose hang bugs remain - Protocol is sketchily documented, tied to this implementation, and hard to modify/extend - Both the program and the protocol assume a single non-interactive one-way transfer - A list of all files are held in memory for the entire transfer, which cripples scalability to large file trees - Opening a new socket for every operation causes problems, especially when running over SSH with password authentication. - Renamed files are not handled: the old file is removed, and the new file created from scratch. - The versioning approach assumes that future versions of the program know about all previous versions, and will do the right thing. - People always get confused about ':' vs '::' - Error messages can be cryptic. - Default behaviour is not intuitive: in too many cases rsync will happily do nothing. Perhaps -a should be the default? - People get confused by trailing slashes, though it's hard to think of another reasonable way to make this necessary distinction between a directory and its contents. Protocol philosophy: *The* big difference between protocols like HTTP, FTP, and NFS is that their fundamental operations are "read this file", "delete this file", and "make this directory", whereas rsync is "make this directory like this one". Questionable features: These are neat, but not necessarily clean or worth preserving. - The remote rsync can be wrapped by some other program, such as in tridge's rsync-mail scripts. The general feature of sending and retrieving mail over rsync is good, but this is perhaps not the right way to implement it. Desirable features: These don't really require architectural changes; they're just something to keep in mind. - Synchronize ACLs and extended attributes - Anonymous servers should be efficient - Code should be portable to non-UNIX systems - Should be possible to document the protocol in RFC form - --dry-run option - IPv6 support. Pretty straightforward. - Allow the basis and destination files to be different. For example, you could use this when you have a CD-ROM and want to download an updated image onto a hard drive. - Efficiently interrupt and restart a transfer. We can write a checkpoint file that says where we're up to in the filesystem. Alternatively, as long as transfers are idempotent, we can just restart the whole thing. [NFSv4] - Scripting support. - Propagate atimes and do not modify them. This is very ugly on Unix. It might be better to try to add O_NOATIME to kernels, and call that. - Unicode. Probably just use UTF-8 for everything. - Open authentication system. Can we use PAM? Is SASL an adequate mapping of PAM to the network, or useful in some other way? - Resume interrupted transfers without the --partial flag. We need to leave the temporary file behind, and then know to use it. This leaves a risk of large temporary files accumulating, which is not good. Perhaps it should be off by default. - tcpwrappers support. Should be trivial; can already be done through tcpd or inetd. - Socks support built in. It's not clear this is any better than just linking against the socks library, though. - When run over SSH, invoke with predictable command-line arguments, so that people can restrict what commands sshd will run. (Is this really required?) - Comparison mode: give a list of which files are new, gone, or different. Set return code depending on whether anything has changed. - Internationalized messages (gettext?) - Optionally use real regexps rather than globs? - Show overall progress. Pretty hard to do, especially if we insist on not scanning the directory tree up front. Regression testing: - Support automatic testing. - Have hard internal timeouts against hangs. - Be deterministic. - Measure performance. Hard links: At the moment, we can recreate hard links, but it's a bit inefficient: it depends on holding a list of all files in the tree. Every time we see a file with a linkcount >1, we need to search for another known name that has the same (fsid,inum) tuple. We could do that more efficiently by keeping a list of only files with linkcount>1, and removing files from that list as all their names become known. Command-line options: We have rather a lot at the moment. We might get more if the tool becomes more flexible. Do we need a .rc or configuration file? That wouldn't really fit with its pattern of use: cp and tar don't have them, though ssh does. Scripting issues: - Perhaps support multiple scripting languages: candidates include Perl, Python, Tcl, Scheme (guile?), sh, ... - Simply running a subprocess and looking at its stdout/exit code might be sufficient, though it could also be pretty slow if it's called often. - There are security issues about running remote code, at least if it's not running in the users own account. So we can either disallow it, or use some kind of sandbox system. - Python is a good language, but the syntax is not so good for giving small fragments on the command line. - Tcl is broken Lisp. - Lots of sysadmins know Perl, though Perl can give some bizarre or confusing errors. The built in stat operators and regexps might be useful. - Sadly probably not enough people know Scheme. - sh is hard to embed. Scripting hooks: - Whether to transfer a file - What basis file to use - Logging - Whether to allow transfers (for public servers) - Authentication - Locking - Cache - Generating backup path/name. - Post-processing of backups, e.g. to do compression. - After transfer, before replacement: so that we can spit out a diff of what was changed, or kick off some kind of reconciliation process. VFS: Rather than talking straight to the filesystem, rsyncd talks through an internal API. Samba has one. Is it useful? - Could be a tidy way to implement cached signatures. - Keep files compressed on disk? Interactive interface: - Something like ncFTP, or integration into GNOME-vfs. Probably hold a single socket connection open. - Can either call us as a separate process, or as a library. - The standalone process needs to produce output in a form easily digestible by a calling program, like the --emacs feature some have. Same goes for output: rpm outputs a series of hash symbols, which are easier for a GUI to handle than "\r30% complete" strings. - Yow! emacs support. (You could probably build that already, of course.) I'd like to be able to write a simple script on a remote machine that rsyncs it to my workstation, edits it there, then pushes it back up. Pie-in-the-sky features: These might have a severe impact on the protocol, and are not clearly in our core requirements. It looks like in many of them having scripting hooks will allow us - Transport over UDP multicast. The hard part is handling multiple destinations which have different basis files. We can look at multicast-TFTP for inspiration. - Conflict resolution. Possibly general scripting support will be sufficient. - Integrate with locking. It's hard to see a good general solution, because Unix systems have several locking mechanisms, and grabbing the lock from programs that don't expect it could cause deadlocks, timeouts, or other problems. Scripting support might help. - Replicate in place, rather than to a temporary file. This is dangerous in the case of interruption, and it also means that the delta can't refer to blocks that have already been overwritten. On the other hand we could semi-trivially do this at first by simply generating a delta with no copy instructions. - Replicate block devices. Most of the difficulties here are to do with replication in place, though on some systems we will also have to do I/O on block boundaries. - Peer to peer features. Flavour of the year. Can we think about ways for clients to smoothly and voluntarily become servers for content they receive? - Imagine a situation where the destination has a much faster link to the cloud than the source. In this case, Mojo Nation downloads interleaved blocks from several slower servers. The general situation might be a way for a master rsync process to farm out tasks to several subjobs. In this particular case they'd need different sockets. This might be related to multicast. Unlikely features: - Allow remote source and destination. If this can be cleanly designed into the protocol, perhaps with the remote machine acting as a kind of echo, then it's good. It's uncommon enough that we don't want to shape the whole protocol around it, though. In fact, in a triangle of machines there are two possibilities: all traffic passes from remote1 to remote2 through local, or local just sets up the transfer and then remote1 talks to remote2. FTP supports the second but it's not clearly good. There are some security problems with being able to instruct one machine to open a connection to another. In favour of evolving the protocol: - Keeping compatibility with existing rsync servers will help with adoption and testing. - We should at the very least be able to fall back to the new protocol. - Error handling is not so good. In favour of using a new protocol: - Maintaining compatibility might soak up development time that would better go into improving a new protocol. - If we start from scratch, it can be documented as we go, and we can avoid design decisions that make the protocol complex or implementation-bound. Error handling: - Errors should come back reliably, and be clearly associated with the particular file that caused the problem. - Some errors ought to cause the whole transfer to abort; some are just warnings. If any errors have occurred, then rsync ought to return an error. Concurrency: - We want to keep the CPU, filesystem, and network as full as possible as much of the time as possible. - We can do nonblocking network IO, but not so for disk. - It makes sense to on the destination be generating signatures and applying patches at the same time. - Can structure this with nonblocking, threads, separate processes, etc. Uses: - Mirroring software distributions: - Synchronizing laptop and desktop - NFS filesystem migration/replication. See http://www.ietf.org/proceedings/00jul/00july-133.htm#P24510_1276764 - Sync with PDA - Network backup systems - CVS filemover Conflict resolution: - Requires application-specific knowledge. We want to provide policy, rather than mechanism. - Possibly allowing two-way migration across a single connection would be useful. Moved files: - There's no trivial way to detect renamed files, especially if they move between directories. - If we had a picture of the remote directory from last time on either machine, then the inode numbers might give us a hint about files which may have been renamed. - Files that are renamed and not modified can be detected by examining the directory listing, looking for files with the same size/date as the origin. Filesystem migration: NFSv4 probably wants to migrate file locks, but that's not really our problem. Atomic updates: The NFSv4 working group wants atomic migration. Most of the responsibility for this lies on the NFS server or OS. If migrating a whole tree, then we could do a nearly-atomic rename at the end. This ties in to having separate basis and destination files. There's no way in Unix to replace a whole set of files atomically. However, if we get them all onto the destination machine and then do the updates quickly it would greatly reduce the window. Scalability: We should aim to work well on machines in use in a year or two. That probably means transfers of many millions of files in one batch, and gigabytes or terabytes of data. For argument's sake: at the low end, we want to sync ten files for a total of 10kb across a 1kB/s link. At the high end, we want to sync 1e9 files for 1TB of data across a 1GB/s link. On the whole CPU usage is not normally a limiting factor, if only because running over SSH burns a lot of cycles on encryption. Perhaps have resource throttling without relying on rlimit. Streaming: A big attraction of rsync is that there are few round-trip delays: basically only one to get started, and then everything is pipelined. This is a problem with FTP, and NFS (at least up to v3). NFSv4 can pipeline operations, but building on that is probably a bit complicated. Related work: - mirror.pl - ProFTPd - Apache - BitTorrent -- p2p mirroring http://bitconjurer.org/BitTorrent/ rsync-3.2.7/main.c0000664000000000000000000014340714316341143012462 0ustar rootroot/* * The startup routines, including main(), for rsync. * * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2022 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 "inums.h" #include "ifuncs.h" #include "io.h" #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H #include #endif #include #ifdef __TANDEM #include #endif extern int dry_run; extern int list_only; extern int io_timeout; extern int am_root; extern int am_server; extern int am_sender; extern int am_daemon; extern int inc_recurse; extern int blocking_io; extern int always_checksum; extern int remove_source_files; extern int output_needs_newline; extern int called_from_signal_handler; extern int need_messages_from_generator; extern int kluge_around_eof; extern int got_xfer_error; extern int old_style_args; extern int msgs2stderr; extern int module_id; extern int read_only; extern int copy_links; extern int copy_dirlinks; extern int copy_unsafe_links; extern int keep_dirlinks; extern int preserve_hard_links; extern int protocol_version; extern int mkpath_dest_arg; extern int file_total; extern int recurse; extern int xfer_dirs; extern int protect_args; extern int relative_paths; extern int sanitize_paths; extern int curr_dir_depth; extern int curr_dir_len; extern int module_id; extern int rsync_port; extern int whole_file; extern int read_batch; extern int write_batch; extern int batch_fd; extern int sock_f_in; extern int sock_f_out; extern int filesfrom_fd; extern int connect_timeout; extern int send_msgs_to_gen; extern dev_t filesystem_dev; extern pid_t cleanup_child_pid; extern size_t bwlimit_writemax; extern unsigned int module_dirlen; extern BOOL flist_receiving_enabled; extern BOOL want_progress_now; extern BOOL shutting_down; extern int backup_dir_len; extern int basis_dir_cnt; extern int default_af_hint; extern int stdout_format_has_i; extern struct stats stats; extern char *stdout_format; extern char *logfile_format; extern char *filesfrom_host; extern char *partial_dir; extern char *rsync_path; extern char *shell_cmd; extern char *password_file; extern char *backup_dir; extern char *copy_as; extern char *tmpdir; extern char curr_dir[MAXPATHLEN]; extern char backup_dir_buf[MAXPATHLEN]; extern char *basis_dir[MAX_BASIS_DIRS+1]; extern struct file_list *first_flist; extern filter_rule_list daemon_filter_list, implied_filter_list; uid_t our_uid; gid_t our_gid; int am_receiver = 0; /* Only set to 1 after the receiver/generator fork. */ int am_generator = 0; /* Only set to 1 after the receiver/generator fork. */ int local_server = 0; int daemon_connection = 0; /* 0 = no daemon, 1 = daemon via remote shell, -1 = daemon via socket */ mode_t orig_umask = 0; int batch_gen_fd = -1; int sender_keeps_checksum = 0; int raw_argc, cooked_argc; char **raw_argv, **cooked_argv; /* There's probably never more than at most 2 outstanding child processes, * but set it higher, just in case. */ #define MAXCHILDPROCS 7 #ifdef HAVE_SIGACTION # ifdef HAVE_SIGPROCMASK # define SIGACTMASK(n,h) SIGACTION(n,h), sigaddset(&sigmask,(n)) # else # define SIGACTMASK(n,h) SIGACTION(n,h) # endif static struct sigaction sigact; #endif struct pid_status { pid_t pid; int status; } pid_stat_table[MAXCHILDPROCS]; static time_t starttime, endtime; static int64 total_read, total_written; static void show_malloc_stats(void); /* Works like waitpid(), but if we already harvested the child pid in our * remember_children(), we succeed instead of returning an error. */ pid_t wait_process(pid_t pid, int *status_ptr, int flags) { pid_t waited_pid; do { waited_pid = waitpid(pid, status_ptr, flags); } while (waited_pid == -1 && errno == EINTR); if (waited_pid == -1 && errno == ECHILD) { /* Status of requested child no longer available: check to * see if it was processed by remember_children(). */ int cnt; for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) { if (pid == pid_stat_table[cnt].pid) { *status_ptr = pid_stat_table[cnt].status; pid_stat_table[cnt].pid = 0; return pid; } } } return waited_pid; } int shell_exec(const char *cmd) { char *shell = getenv("RSYNC_SHELL"); int status; pid_t pid; if (!shell) return system(cmd); if ((pid = fork()) < 0) return -1; if (pid == 0) { execlp(shell, shell, "-c", cmd, NULL); _exit(1); } int ret = wait_process(pid, &status, 0); return ret < 0 ? -1 : status; } /* Wait for a process to exit, calling io_flush while waiting. */ static void wait_process_with_flush(pid_t pid, int *exit_code_ptr) { pid_t waited_pid; int status; while ((waited_pid = wait_process(pid, &status, WNOHANG)) == 0) { msleep(20); io_flush(FULL_FLUSH); } /* TODO: If the child exited on a signal, then log an * appropriate error message. Perhaps we should also accept a * message describing the purpose of the child. Also indicate * this to the caller so that they know something went wrong. */ if (waited_pid < 0) { rsyserr(FERROR, errno, "waitpid"); *exit_code_ptr = RERR_WAITCHILD; } else if (!WIFEXITED(status)) { #ifdef WCOREDUMP if (WCOREDUMP(status)) *exit_code_ptr = RERR_CRASHED; else #endif if (WIFSIGNALED(status)) *exit_code_ptr = RERR_TERMINATED; else *exit_code_ptr = RERR_WAITCHILD; } else *exit_code_ptr = WEXITSTATUS(status); } void write_del_stats(int f) { if (read_batch) write_int(f, NDX_DEL_STATS); else write_ndx(f, NDX_DEL_STATS); write_varint(f, stats.deleted_files - stats.deleted_dirs - stats.deleted_symlinks - stats.deleted_devices - stats.deleted_specials); write_varint(f, stats.deleted_dirs); write_varint(f, stats.deleted_symlinks); write_varint(f, stats.deleted_devices); write_varint(f, stats.deleted_specials); } void read_del_stats(int f) { stats.deleted_files = read_varint(f); stats.deleted_files += stats.deleted_dirs = read_varint(f); stats.deleted_files += stats.deleted_symlinks = read_varint(f); stats.deleted_files += stats.deleted_devices = read_varint(f); stats.deleted_files += stats.deleted_specials = read_varint(f); } static void become_copy_as_user() { char *gname; uid_t uid; gid_t gid; if (!copy_as) return; if (DEBUG_GTE(CMD, 2)) rprintf(FINFO, "[%s] copy_as=%s\n", who_am_i(), copy_as); if ((gname = strchr(copy_as, ':')) != NULL) *gname++ = '\0'; if (!user_to_uid(copy_as, &uid, True)) { rprintf(FERROR, "Invalid copy-as user: %s\n", copy_as); exit_cleanup(RERR_SYNTAX); } if (gname) { if (!group_to_gid(gname, &gid, True)) { rprintf(FERROR, "Invalid copy-as group: %s\n", gname); exit_cleanup(RERR_SYNTAX); } } else { struct passwd *pw; if ((pw = getpwuid(uid)) == NULL) { rsyserr(FERROR, errno, "getpwuid failed"); exit_cleanup(RERR_SYNTAX); } gid = pw->pw_gid; } if (setgid(gid) < 0) { rsyserr(FERROR, errno, "setgid failed"); exit_cleanup(RERR_SYNTAX); } #ifdef HAVE_SETGROUPS if (setgroups(1, &gid)) { rsyserr(FERROR, errno, "setgroups failed"); exit_cleanup(RERR_SYNTAX); } #endif #ifdef HAVE_INITGROUPS if (!gname && initgroups(copy_as, gid) < 0) { rsyserr(FERROR, errno, "initgroups failed"); exit_cleanup(RERR_SYNTAX); } #endif if (setuid(uid) < 0 #ifdef HAVE_SETEUID || seteuid(uid) < 0 #endif ) { rsyserr(FERROR, errno, "setuid failed"); exit_cleanup(RERR_SYNTAX); } our_uid = MY_UID(); our_gid = MY_GID(); am_root = (our_uid == ROOT_UID); if (gname) gname[-1] = ':'; } /* This function gets called from all 3 processes. We want the client side * to actually output the text, but the sender is the only process that has * all the stats we need. So, if we're a client sender, we do the report. * If we're a server sender, we write the stats on the supplied fd. If * we're the client receiver we read the stats from the supplied fd and do * the report. All processes might also generate a set of debug stats, if * the verbose level is high enough (this is the only thing that the * generator process and the server receiver ever do here). */ static void handle_stats(int f) { endtime = time(NULL); /* Cache two stats because the read/write code can change it. */ total_read = stats.total_read; total_written = stats.total_written; if (INFO_GTE(STATS, 3)) { /* These come out from every process */ show_malloc_stats(); show_flist_stats(); } if (am_generator) return; if (am_daemon) { if (f == -1 || !am_sender) return; } if (am_server) { if (am_sender) { write_varlong30(f, total_read, 3); write_varlong30(f, total_written, 3); write_varlong30(f, stats.total_size, 3); if (protocol_version >= 29) { write_varlong30(f, stats.flist_buildtime, 3); write_varlong30(f, stats.flist_xfertime, 3); } } return; } /* this is the client */ if (f < 0 && !am_sender) /* e.g. when we got an empty file list. */ ; else if (!am_sender) { /* Read the first two in opposite order because the meaning of * read/write swaps when switching from sender to receiver. */ total_written = read_varlong30(f, 3); total_read = read_varlong30(f, 3); stats.total_size = read_varlong30(f, 3); if (protocol_version >= 29) { stats.flist_buildtime = read_varlong30(f, 3); stats.flist_xfertime = read_varlong30(f, 3); } } else if (write_batch) { /* The --read-batch process is going to be a client * receiver, so we need to give it the stats. */ write_varlong30(batch_fd, total_read, 3); write_varlong30(batch_fd, total_written, 3); write_varlong30(batch_fd, stats.total_size, 3); if (protocol_version >= 29) { write_varlong30(batch_fd, stats.flist_buildtime, 3); write_varlong30(batch_fd, stats.flist_xfertime, 3); } } } static void output_itemized_counts(const char *prefix, int *counts) { static char *labels[] = { "reg", "dir", "link", "dev", "special" }; char buf[1024], *pre = " ("; int j, len = 0; int total = counts[0]; if (total) { counts[0] -= counts[1] + counts[2] + counts[3] + counts[4]; for (j = 0; j < 5; j++) { if (counts[j]) { len += snprintf(buf+len, sizeof buf - len - 2, "%s%s: %s", pre, labels[j], comma_num(counts[j])); pre = ", "; } } buf[len++] = ')'; } buf[len] = '\0'; rprintf(FINFO, "%s: %s%s\n", prefix, comma_num(total), buf); } static const char *bytes_per_sec_human_dnum(void) { if (starttime == (time_t)-1 || endtime == (time_t)-1) return "UNKNOWN"; return human_dnum((total_written + total_read) / (0.5 + (endtime - starttime)), 2); } static void output_summary(void) { if (INFO_GTE(STATS, 2)) { rprintf(FCLIENT, "\n"); output_itemized_counts("Number of files", &stats.num_files); if (protocol_version >= 29) output_itemized_counts("Number of created files", &stats.created_files); if (protocol_version >= 31) output_itemized_counts("Number of deleted files", &stats.deleted_files); rprintf(FINFO,"Number of regular files transferred: %s\n", comma_num(stats.xferred_files)); rprintf(FINFO,"Total file size: %s bytes\n", human_num(stats.total_size)); rprintf(FINFO,"Total transferred file size: %s bytes\n", human_num(stats.total_transferred_size)); rprintf(FINFO,"Literal data: %s bytes\n", human_num(stats.literal_data)); rprintf(FINFO,"Matched data: %s bytes\n", human_num(stats.matched_data)); rprintf(FINFO,"File list size: %s\n", human_num(stats.flist_size)); if (stats.flist_buildtime) { rprintf(FINFO, "File list generation time: %s seconds\n", comma_dnum((double)stats.flist_buildtime / 1000, 3)); rprintf(FINFO, "File list transfer time: %s seconds\n", comma_dnum((double)stats.flist_xfertime / 1000, 3)); } rprintf(FINFO,"Total bytes sent: %s\n", human_num(total_written)); rprintf(FINFO,"Total bytes received: %s\n", human_num(total_read)); } if (INFO_GTE(STATS, 1)) { rprintf(FCLIENT, "\n"); rprintf(FINFO, "sent %s bytes received %s bytes %s bytes/sec\n", human_num(total_written), human_num(total_read), bytes_per_sec_human_dnum()); rprintf(FINFO, "total size is %s speedup is %s%s\n", human_num(stats.total_size), comma_dnum((double)stats.total_size / (total_written+total_read), 2), write_batch < 0 ? " (BATCH ONLY)" : dry_run ? " (DRY RUN)" : ""); } fflush(stdout); fflush(stderr); } /** * If our C library can get malloc statistics, then show them to FINFO **/ static void show_malloc_stats(void) { #ifdef MEM_ALLOC_INFO struct MEM_ALLOC_INFO mi = MEM_ALLOC_INFO(); /* mallinfo or mallinfo2 */ rprintf(FCLIENT, "\n"); rprintf(FINFO, RSYNC_NAME "[%d] (%s%s%s) heap statistics:\n", (int)getpid(), am_server ? "server " : "", am_daemon ? "daemon " : "", who_am_i()); #define PRINT_ALLOC_NUM(title, descr, num) \ rprintf(FINFO, " %-11s%10" SIZE_T_FMT_MOD "d (" descr ")\n", \ title ":", (SIZE_T_FMT_CAST)(num)); PRINT_ALLOC_NUM("arena", "bytes from sbrk", mi.arena); PRINT_ALLOC_NUM("ordblks", "chunks not in use", mi.ordblks); PRINT_ALLOC_NUM("smblks", "free fastbin blocks", mi.smblks); PRINT_ALLOC_NUM("hblks", "chunks from mmap", mi.hblks); PRINT_ALLOC_NUM("hblkhd", "bytes from mmap", mi.hblkhd); PRINT_ALLOC_NUM("allmem", "bytes from sbrk + mmap", mi.arena + mi.hblkhd); PRINT_ALLOC_NUM("usmblks", "always 0", mi.usmblks); PRINT_ALLOC_NUM("fsmblks", "bytes in freed fastbin blocks", mi.fsmblks); PRINT_ALLOC_NUM("uordblks", "bytes used", mi.uordblks); PRINT_ALLOC_NUM("fordblks", "bytes free", mi.fordblks); PRINT_ALLOC_NUM("keepcost", "bytes in releasable chunk", mi.keepcost); #undef PRINT_ALLOC_NUM #endif /* MEM_ALLOC_INFO */ } /* Start the remote shell. cmd may be NULL to use the default. */ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, int remote_argc, int *f_in_p, int *f_out_p) { int i, argc = 0; char *args[MAX_ARGS], *need_to_free = NULL; pid_t pid; int dash_l_set = 0; if (!read_batch && !local_server) { char *t, *f, in_quote = '\0'; char *rsh_env = getenv(RSYNC_RSH_ENV); if (!cmd) cmd = rsh_env; if (!cmd) cmd = RSYNC_RSH; cmd = need_to_free = strdup(cmd); for (t = f = cmd; *f; f++) { if (*f == ' ') continue; /* Comparison leaves rooms for server_options(). */ if (argc >= MAX_ARGS - MAX_SERVER_ARGS) goto arg_overflow; args[argc++] = t; while (*f != ' ' || in_quote) { if (!*f) { if (in_quote) { rprintf(FERROR, "Missing trailing-%c in remote-shell command.\n", in_quote); exit_cleanup(RERR_SYNTAX); } f--; break; } if (*f == '\'' || *f == '"') { if (!in_quote) { in_quote = *f++; continue; } if (*f == in_quote && *++f != in_quote) { in_quote = '\0'; continue; } } *t++ = *f++; } *t++ = '\0'; } /* NOTE: must preserve t == start of command name until the end of the args handling! */ if ((t = strrchr(cmd, '/')) != NULL) t++; else t = cmd; /* Check to see if we've already been given '-l user' in the remote-shell command. */ for (i = 0; i < argc-1; i++) { if (!strcmp(args[i], "-l") && args[i+1][0] != '-') dash_l_set = 1; } #ifdef HAVE_REMSH /* remsh (on HPUX) takes the arguments the other way around */ args[argc++] = machine; if (user && !(daemon_connection && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } #else if (user && !(daemon_connection && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } #ifdef AF_INET if (default_af_hint == AF_INET && strcmp(t, "ssh") == 0) args[argc++] = "-4"; /* we're using ssh so we can add a -4 option */ #endif #ifdef AF_INET6 if (default_af_hint == AF_INET6 && strcmp(t, "ssh") == 0) args[argc++] = "-6"; /* we're using ssh so we can add a -6 option */ #endif args[argc++] = machine; #endif args[argc++] = rsync_path; if (blocking_io < 0 && (strcmp(t, "rsh") == 0 || strcmp(t, "remsh") == 0)) blocking_io = 1; if (daemon_connection > 0) { args[argc++] = "--server"; args[argc++] = "--daemon"; } else server_options(args, &argc); if (argc >= MAX_ARGS - 2) goto arg_overflow; } args[argc++] = "."; if (!daemon_connection) { while (remote_argc > 0) { if (argc >= MAX_ARGS - 1) { arg_overflow: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } args[argc++] = safe_arg(NULL, *remote_argv++); remote_argc--; } } args[argc] = NULL; if (DEBUG_GTE(CMD, 2)) { for (i = 0; i < argc; i++) rprintf(FCLIENT, "cmd[%d]=%s ", i, args[i]); rprintf(FCLIENT, "\n"); } if (read_batch) { int from_gen_pipe[2]; set_allow_inc_recurse(); if (fd_pair(from_gen_pipe) < 0) { rsyserr(FERROR, errno, "pipe"); exit_cleanup(RERR_IPC); } batch_gen_fd = from_gen_pipe[0]; *f_out_p = from_gen_pipe[1]; *f_in_p = batch_fd; pid = (pid_t)-1; /* no child pid */ #ifdef ICONV_CONST setup_iconv(); #endif } else if (local_server) { /* If the user didn't request --[no-]whole-file, force * it on, but only if we're not batch processing. */ if (whole_file < 0 && !write_batch) whole_file = 1; set_allow_inc_recurse(); pid = local_child(argc, args, f_in_p, f_out_p, child_main); #ifdef ICONV_CONST setup_iconv(); #endif } else { pid = piped_child(args, f_in_p, f_out_p); #ifdef ICONV_CONST setup_iconv(); #endif if (protect_args && !daemon_connection) send_protected_args(*f_out_p, args); } if (need_to_free) free(need_to_free); return pid; } /* Older versions turn an empty string as a reference to the current directory. * We now treat this as an error unless --old-args was used. */ static char *dot_dir_or_error() { if (old_style_args || am_server) return "."; rprintf(FERROR, "Empty destination arg specified (use \".\" or see --old-args).\n"); exit_cleanup(RERR_SYNTAX); } /* The receiving side operates in one of two modes: * * 1. it receives any number of files into a destination directory, * placing them according to their names in the file-list. * * 2. it receives a single file and saves it using the name in the * destination path instead of its file-list name. This requires a * "local name" for writing out the destination file. * * So, our task is to figure out what mode/local-name we need. * For mode 1, we change into the destination directory and return NULL. * For mode 2, we change into the directory containing the destination * file (if we aren't already there) and return the local-name. */ static char *get_local_name(struct file_list *flist, char *dest_path) { STRUCT_STAT st; int statret, trailing_slash; char *cp; if (DEBUG_GTE(RECV, 1)) { rprintf(FINFO, "get_local_name count=%d %s\n", file_total, NS(dest_path)); } if (!dest_path || list_only) return NULL; if (!*dest_path) dest_path = dot_dir_or_error(); if (daemon_filter_list.head) { char *slash = strrchr(dest_path, '/'); if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0'))) *slash = '\0'; else slash = NULL; if ((*dest_path != '.' || dest_path[1] != '\0') && (check_filter(&daemon_filter_list, FLOG, dest_path, 0) < 0 || check_filter(&daemon_filter_list, FLOG, dest_path, 1) < 0)) { rprintf(FERROR, "ERROR: daemon has excluded destination \"%s\"\n", dest_path); exit_cleanup(RERR_FILESELECT); } if (slash) *slash = '/'; } /* See what currently exists at the destination. */ statret = do_stat(dest_path, &st); cp = strrchr(dest_path, '/'); trailing_slash = cp && !cp[1]; if (mkpath_dest_arg && statret < 0 && (cp || file_total > 1)) { int save_errno = errno; int ret = make_path(dest_path, file_total > 1 && !trailing_slash ? 0 : MKP_DROP_NAME); if (ret < 0) goto mkdir_error; if (ret && (INFO_GTE(NAME, 1) || stdout_format_has_i)) { if (file_total == 1 || trailing_slash) *cp = '\0'; rprintf(FINFO, "created %d director%s for %s\n", ret, ret == 1 ? "y" : "ies", dest_path); if (file_total == 1 || trailing_slash) *cp = '/'; } if (ret) statret = do_stat(dest_path, &st); else errno = save_errno; } if (statret == 0) { /* If the destination is a dir, enter it and use mode 1. */ if (S_ISDIR(st.st_mode)) { if (!change_dir(dest_path, CD_NORMAL)) { rsyserr(FERROR, errno, "change_dir#1 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } filesystem_dev = st.st_dev; /* ensures --force works right w/-x */ return NULL; } if (file_total > 1) { rprintf(FERROR, "ERROR: destination must be a directory when" " copying more than 1 file\n"); exit_cleanup(RERR_FILESELECT); } if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) { rprintf(FERROR, "ERROR: cannot overwrite non-directory" " with a directory\n"); exit_cleanup(RERR_FILESELECT); } } else if (errno != ENOENT) { /* If we don't know what's at the destination, fail. */ rsyserr(FERROR, errno, "ERROR: cannot stat destination %s", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } /* If we need a destination directory because the transfer is not * of a single non-directory or the user has requested one via a * destination path ending in a slash, create one and use mode 1. */ if (file_total > 1 || trailing_slash) { if (trailing_slash) *cp = '\0'; /* Lop off the final slash (if any). */ if (statret == 0) { rprintf(FERROR, "ERROR: destination path is not a directory\n"); exit_cleanup(RERR_SYNTAX); } if (do_mkdir(dest_path, ACCESSPERMS) != 0) { mkdir_error: rsyserr(FERROR, errno, "mkdir %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILEIO); } if (flist->high >= flist->low && strcmp(flist->files[flist->low]->basename, ".") == 0) flist->files[0]->flags |= FLAG_DIR_CREATED; if (INFO_GTE(NAME, 1) || stdout_format_has_i) rprintf(FINFO, "created directory %s\n", dest_path); if (dry_run) { /* Indicate that dest dir doesn't really exist. */ dry_run++; } if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) { rsyserr(FERROR, errno, "change_dir#2 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } return NULL; } /* Otherwise, we are writing a single file, possibly on top of an * existing non-directory. Change to the item's parent directory * (if it has a path component), return the basename of the * destination file as the local name, and use mode 2. */ if (!cp) return dest_path; if (cp == dest_path) dest_path = "/"; *cp = '\0'; if (!change_dir(dest_path, CD_NORMAL)) { rsyserr(FERROR, errno, "change_dir#3 %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILESELECT); } *cp = '/'; return cp + 1; } /* This function checks on our alternate-basis directories. If we're in * dry-run mode and the destination dir does not yet exist, we'll try to * tweak any dest-relative paths to make them work for a dry-run (the * destination dir must be in curr_dir[] when this function is called). * We also warn about any arg that is non-existent or not a directory. */ static void check_alt_basis_dirs(void) { STRUCT_STAT st; char *slash = strrchr(curr_dir, '/'); int j; for (j = 0; j < basis_dir_cnt; j++) { char *bdir = basis_dir[j]; int bd_len = strlen(bdir); if (bd_len > 1 && bdir[bd_len-1] == '/') bdir[--bd_len] = '\0'; if (dry_run > 1 && *bdir != '/') { int len = curr_dir_len + 1 + bd_len + 1; char *new = new_array(char, len); if (slash && strncmp(bdir, "../", 3) == 0) { /* We want to remove only one leading "../" prefix for * the directory we couldn't create in dry-run mode: * this ensures that any other ".." references get * evaluated the same as they would for a live copy. */ *slash = '\0'; pathjoin(new, len, curr_dir, bdir + 3); *slash = '/'; } else pathjoin(new, len, curr_dir, bdir); basis_dir[j] = bdir = new; } if (do_stat(bdir, &st) < 0) rprintf(FWARNING, "%s arg does not exist: %s\n", alt_dest_opt(0), bdir); else if (!S_ISDIR(st.st_mode)) rprintf(FWARNING, "%s arg is not a dir: %s\n", alt_dest_opt(0), bdir); } } /* This is only called by the sender. */ static void read_final_goodbye(int f_in, int f_out) { int i, iflags, xlen; uchar fnamecmp_type; char xname[MAXPATHLEN]; shutting_down = True; if (protocol_version < 29) i = read_int(f_in); else { i = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type, xname, &xlen); if (protocol_version >= 31 && i == NDX_DONE) { if (am_sender) write_ndx(f_out, NDX_DONE); else { if (batch_gen_fd >= 0) { while (read_int(batch_gen_fd) != NDX_DEL_STATS) {} read_del_stats(batch_gen_fd); } write_int(f_out, NDX_DONE); } i = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type, xname, &xlen); } } if (i != NDX_DONE) { rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n", i, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } static void do_server_sender(int f_in, int f_out, int argc, char *argv[]) { struct file_list *flist; char *dir; if (DEBUG_GTE(SEND, 1)) rprintf(FINFO, "server_sender starting pid=%d\n", (int)getpid()); if (am_daemon && lp_write_only(module_id)) { rprintf(FERROR, "ERROR: module is write only\n"); exit_cleanup(RERR_SYNTAX); } if (am_daemon && read_only && remove_source_files) { rprintf(FERROR, "ERROR: --remove-%s-files cannot be used with a read-only module\n", remove_source_files == 1 ? "source" : "sent"); exit_cleanup(RERR_SYNTAX); } if (argc < 1) { rprintf(FERROR, "ERROR: do_server_sender called without args\n"); exit_cleanup(RERR_SYNTAX); } become_copy_as_user(); dir = argv[0]; if (!relative_paths) { if (!change_dir(dir, CD_NORMAL)) { rsyserr(FERROR, errno, "change_dir#3 %s failed", full_fname(dir)); exit_cleanup(RERR_FILESELECT); } } argc--; argv++; if (argc == 0 && (recurse || xfer_dirs || list_only)) { argc = 1; argv--; argv[0] = "."; } flist = send_file_list(f_out,argc,argv); if (!flist || flist->used == 0) { /* Make sure input buffering is off so we can't hang in noop_io_until_death(). */ io_end_buffering_in(0); /* TODO: we should really exit in a more controlled manner. */ exit_cleanup(0); } io_start_buffering_in(f_in); send_files(f_in, f_out); io_flush(FULL_FLUSH); handle_stats(f_out); if (protocol_version >= 24) read_final_goodbye(f_in, f_out); io_flush(FULL_FLUSH); exit_cleanup(0); } static int do_recv(int f_in, int f_out, char *local_name) { int pid; int exit_code = 0; int error_pipe[2]; /* The receiving side mustn't obey this, or an existing symlink that * points to an identical file won't be replaced by the referent. */ copy_links = copy_dirlinks = copy_unsafe_links = 0; #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && !inc_recurse) match_hard_links(first_flist); #endif if (fd_pair(error_pipe) < 0) { rsyserr(FERROR, errno, "pipe failed in do_recv"); exit_cleanup(RERR_IPC); } if (backup_dir) { STRUCT_STAT st; int ret; if (backup_dir_len > 1) backup_dir_buf[backup_dir_len-1] = '\0'; ret = do_stat(backup_dir_buf, &st); if (ret != 0 || !S_ISDIR(st.st_mode)) { if (ret == 0) { rprintf(FERROR, "The backup-dir is not a directory: %s\n", backup_dir_buf); exit_cleanup(RERR_SYNTAX); } if (errno != ENOENT) { rprintf(FERROR, "Failed to stat %s: %s\n", backup_dir_buf, strerror(errno)); exit_cleanup(RERR_FILEIO); } if (INFO_GTE(BACKUP, 1)) rprintf(FINFO, "(new) backup_dir is %s\n", backup_dir_buf); } else if (INFO_GTE(BACKUP, 1)) rprintf(FINFO, "backup_dir is %s\n", backup_dir_buf); if (backup_dir_len > 1) backup_dir_buf[backup_dir_len-1] = '/'; } if (tmpdir) { STRUCT_STAT st; int ret = do_stat(tmpdir, &st); if (ret < 0 || !S_ISDIR(st.st_mode)) { if (ret == 0) { rprintf(FERROR, "The temp-dir is not a directory: %s\n", tmpdir); exit_cleanup(RERR_SYNTAX); } if (errno == ENOENT) { rprintf(FERROR, "The temp-dir does not exist: %s\n", tmpdir); exit_cleanup(RERR_SYNTAX); } rprintf(FERROR, "Failed to stat temp-dir %s: %s\n", tmpdir, strerror(errno)); exit_cleanup(RERR_FILEIO); } } io_flush(FULL_FLUSH); if ((pid = do_fork()) == -1) { rsyserr(FERROR, errno, "fork failed in do_recv"); exit_cleanup(RERR_IPC); } if (pid == 0) { am_receiver = 1; send_msgs_to_gen = am_server; close(error_pipe[0]); /* We can't let two processes write to the socket at one time. */ io_end_multiplex_out(MPLX_SWITCHING); if (f_in != f_out) close(f_out); sock_f_out = -1; f_out = error_pipe[1]; bwlimit_writemax = 0; /* receiver doesn't need to do this */ if (read_batch) io_start_buffering_in(f_in); io_start_multiplex_out(f_out); recv_files(f_in, f_out, local_name); io_flush(FULL_FLUSH); handle_stats(f_in); if (output_needs_newline) { fputc('\n', stdout); output_needs_newline = 0; } write_int(f_out, NDX_DONE); send_msg(MSG_STATS, (char*)&stats.total_read, sizeof stats.total_read, 0); io_flush(FULL_FLUSH); /* Handle any keep-alive packets from the post-processing work * that the generator does. */ if (protocol_version >= 29) { kluge_around_eof = -1; /* This should only get stopped via a USR2 signal. */ read_final_goodbye(f_in, f_out); rprintf(FERROR, "Invalid packet at end of run [%s]\n", who_am_i()); exit_cleanup(RERR_PROTOCOL); } /* Finally, we go to sleep until our parent kills us with a * USR2 signal. We sleep for a short time, as on some OSes * a signal won't interrupt a sleep! */ while (1) msleep(20); } am_generator = 1; implied_filter_list.head = implied_filter_list.tail = NULL; flist_receiving_enabled = True; io_end_multiplex_in(MPLX_SWITCHING); if (write_batch && !am_server) stop_write_batch(); close(error_pipe[1]); if (f_in != f_out) close(f_in); sock_f_in = -1; f_in = error_pipe[0]; io_start_buffering_out(f_out); io_start_multiplex_in(f_in); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && inc_recurse) { struct file_list *flist; for (flist = first_flist; flist; flist = flist->next) match_hard_links(flist); } #endif generate_files(f_out, local_name); handle_stats(-1); io_flush(FULL_FLUSH); shutting_down = True; if (protocol_version >= 24) { /* send a final goodbye message */ write_ndx(f_out, NDX_DONE); } io_flush(FULL_FLUSH); kill(pid, SIGUSR2); wait_process_with_flush(pid, &exit_code); return exit_code; } static void do_server_recv(int f_in, int f_out, int argc, char *argv[]) { int exit_code; struct file_list *flist; char *local_name = NULL; int negated_levels; if (filesfrom_fd >= 0 && msgs2stderr != 1 && protocol_version < 31) { /* We can't mix messages with files-from data on the socket, * so temporarily turn off info/debug messages. */ negate_output_levels(); negated_levels = 1; } else negated_levels = 0; if (DEBUG_GTE(RECV, 1)) rprintf(FINFO, "server_recv(%d) starting pid=%d\n", argc, (int)getpid()); if (am_daemon && read_only) { rprintf(FERROR,"ERROR: module is read only\n"); exit_cleanup(RERR_SYNTAX); return; } become_copy_as_user(); if (argc > 0) { char *dir = argv[0]; argc--; argv++; if (!am_daemon && !change_dir(dir, CD_NORMAL)) { rsyserr(FERROR, errno, "change_dir#4 %s failed", full_fname(dir)); exit_cleanup(RERR_FILESELECT); } } if (protocol_version >= 30) io_start_multiplex_in(f_in); else io_start_buffering_in(f_in); recv_filter_list(f_in); if (filesfrom_fd >= 0) { /* We need to send the files-from names to the sender at the * same time that we receive the file-list from them, so we * need the IO routines to automatically write out the names * onto our f_out socket as we read the file-list. This * avoids both deadlock and extra delays/buffers. */ start_filesfrom_forwarding(filesfrom_fd); filesfrom_fd = -1; } flist = recv_file_list(f_in, -1); if (!flist) { rprintf(FERROR,"server_recv: recv_file_list error\n"); exit_cleanup(RERR_FILESELECT); } if (inc_recurse && file_total == 1) recv_additional_file_list(f_in); if (negated_levels) negate_output_levels(); if (argc > 0) local_name = get_local_name(flist,argv[0]); /* Now that we know what our destination directory turned out to be, * we can sanitize the --link-/copy-/compare-dest args correctly. */ if (sanitize_paths) { char **dir_p; for (dir_p = basis_dir; *dir_p; dir_p++) *dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT); if (partial_dir) partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT); } check_alt_basis_dirs(); if (daemon_filter_list.head) { char **dir_p; filter_rule_list *elp = &daemon_filter_list; for (dir_p = basis_dir; *dir_p; dir_p++) { char *dir = *dir_p; if (*dir == '/') dir += module_dirlen; if (check_filter(elp, FLOG, dir, 1) < 0) goto options_rejected; } if (partial_dir && *partial_dir == '/' && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) { options_rejected: rprintf(FERROR, "Your options have been rejected by the server.\n"); exit_cleanup(RERR_SYNTAX); } } exit_code = do_recv(f_in, f_out, local_name); exit_cleanup(exit_code); } int child_main(int argc, char *argv[]) { start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); return 0; } void start_server(int f_in, int f_out, int argc, char *argv[]) { set_nonblocking(f_in); set_nonblocking(f_out); io_set_sock_fds(f_in, f_out); setup_protocol(f_out, f_in); if (protocol_version >= 23) io_start_multiplex_out(f_out); if (am_daemon && io_timeout && protocol_version >= 31) send_msg_int(MSG_IO_TIMEOUT, io_timeout); if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ if (need_messages_from_generator) io_start_multiplex_in(f_in); else io_start_buffering_in(f_in); recv_filter_list(f_in); do_server_sender(f_in, f_out, argc, argv); } else do_server_recv(f_in, f_out, argc, argv); exit_cleanup(0); } /* This is called once the connection has been negotiated. It is used * for rsyncd, remote-shell, and local connections. */ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) { struct file_list *flist = NULL; int exit_code = 0, exit_code2 = 0; char *local_name = NULL; cleanup_child_pid = pid; if (!read_batch) { set_nonblocking(f_in); set_nonblocking(f_out); } io_set_sock_fds(f_in, f_out); setup_protocol(f_out,f_in); /* We set our stderr file handle to blocking because ssh might have * set it to non-blocking. This can be particularly troublesome if * stderr is a clone of stdout, because ssh would have set our stdout * to non-blocking at the same time (which can easily cause us to lose * output from our print statements). This kluge shouldn't cause ssh * any problems for how we use it. Note also that we delayed setting * this until after the above protocol setup so that we know for sure * that ssh is done twiddling its file descriptors. */ set_blocking(STDERR_FILENO); if (am_sender) { keep_dirlinks = 0; /* Must be disabled on the sender. */ if (always_checksum && (log_format_has(stdout_format, 'C') || log_format_has(logfile_format, 'C'))) sender_keeps_checksum = 1; if (protocol_version >= 30) io_start_multiplex_out(f_out); else io_start_buffering_out(f_out); if (protocol_version >= 31 || (!filesfrom_host && protocol_version >= 23)) io_start_multiplex_in(f_in); else io_start_buffering_in(f_in); send_filter_list(f_out); if (filesfrom_host) filesfrom_fd = f_in; if (write_batch && !am_server) start_write_batch(f_out); become_copy_as_user(); flist = send_file_list(f_out, argc, argv); if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO,"file list sent\n"); if (protocol_version < 31 && filesfrom_host && protocol_version >= 23) io_start_multiplex_in(f_in); io_flush(NORMAL_FLUSH); send_files(f_in, f_out); io_flush(FULL_FLUSH); handle_stats(-1); if (protocol_version >= 24) read_final_goodbye(f_in, f_out); if (pid != -1) { if (DEBUG_GTE(EXIT, 2)) rprintf(FINFO,"client_run waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process_with_flush(pid, &exit_code); } output_summary(); io_flush(FULL_FLUSH); exit_cleanup(exit_code); } if (!read_batch) { if (protocol_version >= 23) io_start_multiplex_in(f_in); if (need_messages_from_generator) io_start_multiplex_out(f_out); else io_start_buffering_out(f_out); } become_copy_as_user(); send_filter_list(read_batch ? -1 : f_out); if (filesfrom_fd >= 0) { start_filesfrom_forwarding(filesfrom_fd); filesfrom_fd = -1; } if (write_batch && !am_server) start_write_batch(f_in); flist = recv_file_list(f_in, -1); if (inc_recurse && file_total == 1) recv_additional_file_list(f_in); if (flist && flist->used > 0) { local_name = get_local_name(flist, argv[0]); check_alt_basis_dirs(); exit_code2 = do_recv(f_in, f_out, local_name); } else { handle_stats(-1); output_summary(); } if (pid != -1) { if (DEBUG_GTE(RECV, 1)) rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process_with_flush(pid, &exit_code); } return MAX(exit_code, exit_code2); } static void dup_argv(char *argv[]) { int i; for (i = 0; argv[i]; i++) argv[i] = strdup(argv[i]); } /* Start a client for either type of remote connection. Work out * whether the arguments request a remote shell or rsyncd connection, * and call the appropriate connection function, then run_client. * * Calls either start_socket_client (for sockets) or do_cmd and * client_run (for ssh). */ static int start_client(int argc, char *argv[]) { char *p, *shell_machine = NULL, *shell_user = NULL; char **remote_argv; int remote_argc, env_port = rsync_port; int f_in, f_out; int ret; pid_t pid; /* Don't clobber argv[] so that ps(1) can still show the right * command line. */ dup_argv(argv); if (!read_batch) { /* for read_batch, NO source is specified */ char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); if (path) { /* source is remote */ char *dummy_host; int dummy_port = 0; *argv = path; remote_argv = argv; remote_argc = argc; argv += argc - 1; if (argc == 1 || **argv == ':') argc = 0; /* no dest arg */ else if (check_for_hostspec(*argv, &dummy_host, &dummy_port)) { rprintf(FERROR, "The source and destination cannot both be remote.\n"); exit_cleanup(RERR_SYNTAX); } else { remote_argc--; /* don't count dest */ argc = 1; } if (filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } am_sender = 0; if (rsync_port) daemon_connection = shell_cmd ? 1 : -1; } else { /* source is local, check dest arg */ am_sender = 1; if (argc > 1) { p = argv[--argc]; if (!*p) p = dot_dir_or_error(); remote_argv = argv + argc; } else { static char *dotarg[1] = { "." }; p = dotarg[0]; remote_argv = dotarg; } remote_argc = 1; path = check_for_hostspec(p, &shell_machine, &rsync_port); if (path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, "--files-from hostname is not the same as the transfer hostname\n"); exit_cleanup(RERR_SYNTAX); } if (!path) { /* no hostspec found, so src & dest are local */ local_server = 1; if (filesfrom_host) { rprintf(FERROR, "--files-from cannot be remote when the transfer is local\n"); exit_cleanup(RERR_SYNTAX); } shell_machine = NULL; rsync_port = 0; } else { /* hostspec was found, so dest is remote */ argv[argc] = path; if (rsync_port) daemon_connection = shell_cmd ? 1 : -1; } } } else { /* read_batch */ local_server = 1; if (check_for_hostspec(argv[argc-1], &shell_machine, &rsync_port)) { rprintf(FERROR, "remote destination is not allowed with --read-batch\n"); exit_cleanup(RERR_SYNTAX); } remote_argv = argv += argc - 1; remote_argc = argc = 1; rsync_port = 0; } /* A local transfer doesn't unbackslash anything, so leave the args alone. */ if (local_server) old_style_args = 2; if (!rsync_port && remote_argc && !**remote_argv) /* Turn an empty arg into a dot dir. */ *remote_argv = "."; if (am_sender) { char *dummy_host; int dummy_port = rsync_port; int i; if (!argv[0][0]) goto invalid_empty; /* For local source, extra source args must not have hostspec. */ for (i = 1; i < argc; i++) { if (!argv[i][0]) { invalid_empty: rprintf(FERROR, "Empty source arg specified.\n"); exit_cleanup(RERR_SYNTAX); } if (check_for_hostspec(argv[i], &dummy_host, &dummy_port)) { rprintf(FERROR, "Unexpected remote arg: %s\n", argv[i]); exit_cleanup(RERR_SYNTAX); } } } else { char *dummy_host; int dummy_port = rsync_port; int i; if (filesfrom_fd < 0) add_implied_include(remote_argv[0], daemon_connection); /* For remote source, any extra source args must have either * the same hostname or an empty hostname. */ for (i = 1; i < remote_argc; i++) { char *arg = check_for_hostspec(remote_argv[i], &dummy_host, &dummy_port); if (!arg) { rprintf(FERROR, "Unexpected local arg: %s\n", remote_argv[i]); rprintf(FERROR, "If arg is a remote file/dir, prefix it with a colon (:).\n"); exit_cleanup(RERR_SYNTAX); } if (*dummy_host && strcmp(dummy_host, shell_machine) != 0) { rprintf(FERROR, "All source args must come from the same machine.\n"); exit_cleanup(RERR_SYNTAX); } if (rsync_port != dummy_port) { if (!rsync_port || !dummy_port) rprintf(FERROR, "All source args must use the same hostspec format.\n"); else rprintf(FERROR, "All source args must use the same port number.\n"); exit_cleanup(RERR_SYNTAX); } if (!rsync_port && !*arg) /* Turn an empty arg into a dot dir. */ arg = "."; remote_argv[i] = arg; add_implied_include(arg, daemon_connection); } } if (rsync_port < 0) rsync_port = RSYNC_PORT; else env_port = rsync_port; if (daemon_connection < 0) return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv); if (password_file && !daemon_connection) { rprintf(FERROR, "The --password-file option may only be " "used when accessing an rsync daemon.\n"); exit_cleanup(RERR_SYNTAX); } if (connect_timeout) { rprintf(FERROR, "The --contimeout option may only be " "used when connecting to an rsync daemon.\n"); exit_cleanup(RERR_SYNTAX); } if (shell_machine) { p = strrchr(shell_machine,'@'); if (p) { *p = 0; shell_user = shell_machine; shell_machine = p+1; } } if (DEBUG_GTE(CMD, 2)) { rprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n", NS(shell_cmd), NS(shell_machine), NS(shell_user), NS(remote_argv[0])); } #ifdef HAVE_PUTENV if (daemon_connection) set_env_num("RSYNC_PORT", env_port); #else (void)env_port; #endif pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc, &f_in, &f_out); /* if we're running an rsync server on the remote host over a * remote shell command, we need to do the RSYNCD protocol first */ if (daemon_connection) { int tmpret; tmpret = start_inband_exchange(f_in, f_out, shell_user, remote_argc, remote_argv); if (tmpret < 0) return tmpret; } ret = client_run(f_in, f_out, pid, argc, argv); fflush(stdout); fflush(stderr); return ret; } static void sigusr1_handler(UNUSED(int val)) { called_from_signal_handler = 1; exit_cleanup(RERR_SIGNAL1); } static void sigusr2_handler(UNUSED(int val)) { if (!am_server) output_summary(); close_all(); if (got_xfer_error) _exit(RERR_PARTIAL); _exit(0); } #if defined SIGINFO || defined SIGVTALRM static void siginfo_handler(UNUSED(int val)) { if (!am_server && !INFO_GTE(PROGRESS, 1)) want_progress_now = True; } #endif void remember_children(UNUSED(int val)) { #ifdef WNOHANG int cnt, status; pid_t pid; /* An empty waitpid() loop was put here by Tridge and we could never * get him to explain why he put it in, so rather than taking it * out we're instead saving the child exit statuses for later use. * The waitpid() loop presumably eliminates all possibility of leaving * zombie children, maybe that's why he did it. */ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { /* save the child's exit status */ for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) { if (pid_stat_table[cnt].pid == 0) { pid_stat_table[cnt].pid = pid; pid_stat_table[cnt].status = status; break; } } } #endif #ifndef HAVE_SIGACTION signal(SIGCHLD, remember_children); #endif } /** * This routine catches signals and tries to send them to gdb. * * Because it's called from inside a signal handler it ought not to * use too many library routines. * * @todo Perhaps use "screen -X" instead/as well, to help people * debugging without easy access to X. Perhaps use an environment * variable, or just call a script? * * @todo The /proc/ magic probably only works on Linux (and * Solaris?) Can we be more portable? **/ #ifdef MAINTAINER_MODE const char *get_panic_action(void) { const char *cmd_fmt = getenv("RSYNC_PANIC_ACTION"); if (cmd_fmt) return cmd_fmt; return "xterm -display :0 -T Panic -n Panic -e gdb /proc/%d/exe %d"; } /** * Handle a fatal signal by launching a debugger, controlled by $RSYNC_PANIC_ACTION. * * This signal handler is only installed if we were configured with * --enable-maintainer-mode. Perhaps it should always be on and we * should just look at the environment variable, but I'm a bit leery * of a signal sending us into a busy loop. **/ static void rsync_panic_handler(UNUSED(int whatsig)) { char cmd_buf[300]; int ret, pid_int = getpid(); snprintf(cmd_buf, sizeof cmd_buf, get_panic_action(), pid_int, pid_int); /* Unless we failed to execute gdb, we allow the process to * continue. I'm not sure if that's right. */ ret = shell_exec(cmd_buf); if (ret) _exit(ret); } #endif static void unset_env_var(const char *var) { #ifdef HAVE_UNSETENV unsetenv(var); #else #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=", var) < 0) out_of_memory("unset_env_var"); putenv(mem); #else (void)var; #endif #endif } int main(int argc,char *argv[]) { int ret; raw_argc = argc; raw_argv = argv; #ifdef HAVE_SIGACTION # ifdef HAVE_SIGPROCMASK sigset_t sigmask; sigemptyset(&sigmask); # endif sigact.sa_flags = SA_NOCLDSTOP; #endif SIGACTMASK(SIGUSR1, sigusr1_handler); SIGACTMASK(SIGUSR2, sigusr2_handler); SIGACTMASK(SIGCHLD, remember_children); #ifdef MAINTAINER_MODE SIGACTMASK(SIGSEGV, rsync_panic_handler); SIGACTMASK(SIGFPE, rsync_panic_handler); SIGACTMASK(SIGABRT, rsync_panic_handler); SIGACTMASK(SIGBUS, rsync_panic_handler); #endif #ifdef SIGINFO SIGACTMASK(SIGINFO, siginfo_handler); #endif #ifdef SIGVTALRM SIGACTMASK(SIGVTALRM, siginfo_handler); #endif starttime = time(NULL); our_uid = MY_UID(); our_gid = MY_GID(); am_root = our_uid == ROOT_UID; unset_env_var("DISPLAY"); #if defined USE_OPENSSL && defined SET_OPENSSL_CONF #define TO_STR2(x) #x #define TO_STR(x) TO_STR2(x) /* ./configure --with-openssl-conf=/etc/ssl/openssl-rsync.cnf * defines SET_OPENSSL_CONF as that unquoted pathname. */ if (!getenv("OPENSSL_CONF")) /* Don't override it if it's already set. */ set_env_str("OPENSSL_CONF", TO_STR(SET_OPENSSL_CONF)); #undef TO_STR #undef TO_STR2 #endif memset(&stats, 0, sizeof(stats)); /* Even a non-daemon runs needs the default config values to be set, e.g. * lp_dont_compress() is queried when no --skip-compress option is set. */ reset_daemon_vars(); if (argc < 2) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } /* Get the umask for use in permission calculations. We no longer set * it to zero; that is ugly and pointless now that all the callers that * relied on it have been reeducated to work with default ACLs. */ umask(orig_umask = umask(0)); #if defined CONFIG_LOCALE && defined HAVE_SETLOCALE setlocale(LC_CTYPE, ""); setlocale(LC_NUMERIC, ""); #endif if (!parse_arguments(&argc, (const char ***) &argv)) { option_error(); exit_cleanup(RERR_SYNTAX); } if (write_batch && poptDupArgv(argc, (const char **)argv, &cooked_argc, (const char ***)&cooked_argv) != 0) out_of_memory("main"); SIGACTMASK(SIGINT, sig_int); SIGACTMASK(SIGHUP, sig_int); SIGACTMASK(SIGTERM, sig_int); #if defined HAVE_SIGACTION && HAVE_SIGPROCMASK sigprocmask(SIG_UNBLOCK, &sigmask, NULL); #endif /* Ignore SIGPIPE; we consistently check error codes and will * see the EPIPE. */ SIGACTION(SIGPIPE, SIG_IGN); #ifdef SIGXFSZ SIGACTION(SIGXFSZ, SIG_IGN); #endif /* Initialize change_dir() here because on some old systems getcwd * (implemented by forking "pwd" and reading its output) doesn't * work when there are other child processes. Also, on all systems * that implement getcwd that way "pwd" can't be found after chroot. */ change_dir(NULL, CD_NORMAL); if ((write_batch || read_batch) && !am_server) { open_batch_files(); /* sets batch_fd */ if (read_batch) read_stream_flags(batch_fd); else write_stream_flags(batch_fd); } if (write_batch < 0) dry_run = 1; if (am_server) { #ifdef ICONV_CONST setup_iconv(); #endif } else if (am_daemon) return daemon_main(); if (am_server && protect_args) { char buf[MAXPATHLEN]; protect_args = 2; read_args(STDIN_FILENO, NULL, buf, sizeof buf, 1, &argv, &argc, NULL); if (!parse_arguments(&argc, (const char ***) &argv)) { option_error(); exit_cleanup(RERR_SYNTAX); } } if (argc < 1) { usage(FERROR); exit_cleanup(RERR_SYNTAX); } if (am_server) { set_nonblocking(STDIN_FILENO); set_nonblocking(STDOUT_FILENO); if (am_daemon) return start_daemon(STDIN_FILENO, STDOUT_FILENO); start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); } ret = start_client(argc, argv); if (ret == -1) exit_cleanup(RERR_STARTCLIENT); else exit_cleanup(ret); return ret; } rsync-3.2.7/clientname.c0000664000000000000000000003330114170671375013657 0ustar rootroot/* * Functions for looking up the remote name or addr of a socket. * * Copyright (C) 1992-2001 Andrew Tridgell * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2002-2022 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. */ /* * This file is now converted to use the new-style getaddrinfo() * interface, which supports IPv6 but is also supported on recent * IPv4-only machines. On systems that don't have that interface, we * emulate it using the KAME implementation. */ #include "rsync.h" #include "itypes.h" extern int am_daemon; static const char default_name[] = "UNKNOWN"; static const char proxyv2sig[] = "\r\n\r\n\0\r\nQUIT\n"; static char ipaddr_buf[100]; #define PROXY_V2_SIG_SIZE ((int)sizeof proxyv2sig - 1) #define PROXY_V2_HEADER_SIZE (PROXY_V2_SIG_SIZE + 1 + 1 + 2) #define CMD_LOCAL 0 #define CMD_PROXY 1 #define PROXY_FAM_TCPv4 0x11 #define PROXY_FAM_TCPv6 0x21 #define GET_SOCKADDR_FAMILY(ss) ((struct sockaddr*)ss)->sa_family static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len); static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size); static int valid_ipaddr(const char *s, int allow_scope); /* Return the IP addr of the client as a string. */ char *client_addr(int fd) { struct sockaddr_storage ss; socklen_t length = sizeof ss; if (*ipaddr_buf) return ipaddr_buf; if (am_daemon < 0) { /* daemon over --rsh mode */ char *env_str; strlcpy(ipaddr_buf, "0.0.0.0", sizeof ipaddr_buf); if ((env_str = getenv("REMOTE_HOST")) != NULL || (env_str = getenv("SSH_CONNECTION")) != NULL || (env_str = getenv("SSH_CLIENT")) != NULL || (env_str = getenv("SSH2_CLIENT")) != NULL) { char *p; strlcpy(ipaddr_buf, env_str, sizeof ipaddr_buf); /* Truncate the value to just the IP address. */ if ((p = strchr(ipaddr_buf, ' ')) != NULL) *p = '\0'; } if (valid_ipaddr(ipaddr_buf, True)) return ipaddr_buf; } client_sockaddr(fd, &ss, &length); getnameinfo((struct sockaddr *)&ss, length, ipaddr_buf, sizeof ipaddr_buf, NULL, 0, NI_NUMERICHOST); return ipaddr_buf; } /** * Return the DNS name of the client. * * The name is statically cached so that repeated lookups are quick, * so there is a limit of one lookup per customer. * * If anything goes wrong, including the name->addr->name check, then * we just use "UNKNOWN", so you can use that value in hosts allow * lines. * * After translation from sockaddr to name we do a forward lookup to * make sure nobody is spoofing PTR records. **/ char *client_name(const char *ipaddr) { static char name_buf[100]; char port_buf[100]; struct sockaddr_storage ss; socklen_t ss_len; struct addrinfo hint, *answer; int err; if (*name_buf) return name_buf; strlcpy(name_buf, default_name, sizeof name_buf); if (strcmp(ipaddr, "0.0.0.0") == 0) return name_buf; memset(&ss, 0, sizeof ss); memset(&hint, 0, sizeof hint); #ifdef AI_NUMERICHOST hint.ai_flags = AI_NUMERICHOST; #endif hint.ai_socktype = SOCK_STREAM; if ((err = getaddrinfo(ipaddr, NULL, &hint, &answer)) != 0) { rprintf(FLOG, "malformed address %s: %s\n", ipaddr, gai_strerror(err)); return name_buf; } switch (answer->ai_family) { case AF_INET: ss_len = sizeof (struct sockaddr_in); memcpy(&ss, answer->ai_addr, ss_len); break; #ifdef INET6 case AF_INET6: ss_len = sizeof (struct sockaddr_in6); memcpy(&ss, answer->ai_addr, ss_len); break; #endif default: NOISY_DEATH("Unknown ai_family value"); } freeaddrinfo(answer); /* reverse lookup */ err = getnameinfo((struct sockaddr*)&ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf, NI_NAMEREQD | NI_NUMERICSERV); if (err) { strlcpy(name_buf, default_name, sizeof name_buf); rprintf(FLOG, "name lookup failed for %s: %s\n", ipaddr, gai_strerror(err)); } else check_name(ipaddr, &ss, name_buf, sizeof name_buf); return name_buf; } /* Try to read a proxy protocol header (V1 or V2). Returns 1 on success or 0 on failure. */ int read_proxy_protocol_header(int fd) { union { struct { char line[108]; } v1; struct { char sig[PROXY_V2_SIG_SIZE]; char ver_cmd; char fam; char len[2]; union { struct { char src_addr[4]; char dst_addr[4]; char src_port[2]; char dst_port[2]; } ip4; struct { char src_addr[16]; char dst_addr[16]; char src_port[2]; char dst_port[2]; } ip6; struct { char src_addr[108]; char dst_addr[108]; } unx; } addr; } v2; } hdr; read_buf(fd, (char*)&hdr, PROXY_V2_SIG_SIZE); if (memcmp(hdr.v2.sig, proxyv2sig, PROXY_V2_SIG_SIZE) == 0) { /* Proxy V2 */ int ver, cmd, size; read_buf(fd, (char*)&hdr + PROXY_V2_SIG_SIZE, PROXY_V2_HEADER_SIZE - PROXY_V2_SIG_SIZE); ver = (hdr.v2.ver_cmd & 0xf0) >> 4; cmd = (hdr.v2.ver_cmd & 0x0f); size = (hdr.v2.len[0] << 8) + hdr.v2.len[1]; if (ver != 2 || size + PROXY_V2_HEADER_SIZE > (int)sizeof hdr) return 0; /* Grab all the remaining data in the binary request. */ read_buf(fd, (char*)&hdr + PROXY_V2_HEADER_SIZE, size); switch (cmd) { case CMD_PROXY: switch (hdr.v2.fam) { case PROXY_FAM_TCPv4: if (size != sizeof hdr.v2.addr.ip4) return 0; inet_ntop(AF_INET, hdr.v2.addr.ip4.src_addr, ipaddr_buf, sizeof ipaddr_buf); return valid_ipaddr(ipaddr_buf, False); #ifdef INET6 case PROXY_FAM_TCPv6: if (size != sizeof hdr.v2.addr.ip6) return 0; inet_ntop(AF_INET6, hdr.v2.addr.ip6.src_addr, ipaddr_buf, sizeof ipaddr_buf); return valid_ipaddr(ipaddr_buf, False); #endif default: break; } /* For an unsupported protocol we'll ignore the proxy data (leaving ipaddr_buf unset) * and accept the connection, which will get handled as a normal socket addr. */ return 1; case CMD_LOCAL: return 1; default: break; } return 0; } if (memcmp(hdr.v1.line, "PROXY", 5) == 0) { /* Proxy V1 */ char *endc, *sp, *p = hdr.v1.line + PROXY_V2_SIG_SIZE; int port_chk; *p = '\0'; if (!strchr(hdr.v1.line, '\n')) { while (1) { read_buf(fd, p, 1); if (*p++ == '\n') break; if (p - hdr.v1.line >= (int)sizeof hdr.v1.line - 1) return 0; } *p = '\0'; } endc = strchr(hdr.v1.line, '\r'); if (!endc || endc[1] != '\n' || endc[2]) return 0; *endc = '\0'; p = hdr.v1.line + 5; if (!isSpace(p++)) return 0; if (strncmp(p, "TCP4", 4) == 0) p += 4; else if (strncmp(p, "TCP6", 4) == 0) p += 4; else if (strncmp(p, "UNKNOWN", 7) == 0) return 1; else return 0; if (!isSpace(p++)) return 0; if ((sp = strchr(p, ' ')) == NULL) return 0; *sp = '\0'; if (!valid_ipaddr(p, False)) return 0; strlcpy(ipaddr_buf, p, sizeof ipaddr_buf); /* It will always fit when valid. */ p = sp + 1; if ((sp = strchr(p, ' ')) == NULL) return 0; *sp = '\0'; if (!valid_ipaddr(p, False)) return 0; /* Ignore destination address. */ p = sp + 1; if ((sp = strchr(p, ' ')) == NULL) return 0; *sp = '\0'; port_chk = strtol(p, &endc, 10); if (*endc || port_chk == 0) return 0; /* Ignore source port. */ p = sp + 1; port_chk = strtol(p, &endc, 10); if (*endc || port_chk == 0) return 0; /* Ignore destination port. */ return 1; } return 0; } /** * Get the sockaddr for the client. * * If it comes in as an ipv4 address mapped into IPv6 format then we * convert it back to a regular IPv4. **/ static void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len) { memset(ss, 0, sizeof *ss); if (getpeername(fd, (struct sockaddr *) ss, ss_len)) { /* FIXME: Can we really not continue? */ rsyserr(FLOG, errno, "getpeername on fd%d failed", fd); exit_cleanup(RERR_SOCKETIO); } #ifdef INET6 if (GET_SOCKADDR_FAMILY(ss) == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) { /* OK, so ss is in the IPv6 family, but it is really * an IPv4 address: something like * "::ffff:10.130.1.2". If we use it as-is, then the * reverse lookup might fail or perhaps something else * bad might happen. So instead we convert it to an * equivalent address in the IPv4 address family. */ struct sockaddr_in6 sin6; struct sockaddr_in *sin; memcpy(&sin6, ss, sizeof sin6); sin = (struct sockaddr_in *)ss; memset(sin, 0, sizeof *sin); sin->sin_family = AF_INET; *ss_len = sizeof (struct sockaddr_in); #ifdef HAVE_SOCKADDR_IN_LEN sin->sin_len = *ss_len; #endif sin->sin_port = sin6.sin6_port; /* There is a macro to extract the mapped part * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem * to be present in the Linux headers. */ memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12], sizeof sin->sin_addr); } #endif } /** * Compare an addrinfo from the resolver to a sockinfo. * * Like strcmp, returns 0 for identical. **/ static int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss) { int ss_family = GET_SOCKADDR_FAMILY(ss); const char fn[] = "compare_addrinfo_sockaddr"; if (ai->ai_family != ss_family) { rprintf(FLOG, "%s: response family %d != %d\n", fn, ai->ai_family, ss_family); return 1; } /* The comparison method depends on the particular AF. */ if (ss_family == AF_INET) { const struct sockaddr_in *sin1, *sin2; sin1 = (const struct sockaddr_in *) ss; sin2 = (const struct sockaddr_in *) ai->ai_addr; return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof sin1->sin_addr); } #ifdef INET6 if (ss_family == AF_INET6) { const struct sockaddr_in6 *sin1, *sin2; sin1 = (const struct sockaddr_in6 *) ss; sin2 = (const struct sockaddr_in6 *) ai->ai_addr; if (ai->ai_addrlen < (int)sizeof (struct sockaddr_in6)) { rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n", fn, (int)ai->ai_addrlen); return 1; } if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof sin1->sin6_addr)) return 1; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID if (sin1->sin6_scope_id != sin2->sin6_scope_id) return 1; #endif return 0; } #endif /* INET6 */ /* don't know */ return 1; } /** * Do a forward lookup on @p name_buf and make sure it corresponds to * @p ss -- otherwise we may be being spoofed. If we suspect we are, * then we don't abort the connection but just emit a warning, and * change @p name_buf to be "UNKNOWN". * * We don't do anything with the service when checking the name, * because it doesn't seem that it could be spoofed in any way, and * getaddrinfo on random service names seems to cause problems on AIX. **/ static int check_name(const char *ipaddr, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size) { struct addrinfo hints, *res, *res0; int error; int ss_family = GET_SOCKADDR_FAMILY(ss); memset(&hints, 0, sizeof hints); hints.ai_family = ss_family; hints.ai_flags = AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(name_buf, NULL, &hints, &res0); if (error) { rprintf(FLOG, "forward name lookup for %s failed: %s\n", name_buf, gai_strerror(error)); strlcpy(name_buf, default_name, name_buf_size); return error; } /* Given all these results, we expect that one of them will be * the same as ss. The comparison is a bit complicated. */ for (res = res0; res; res = res->ai_next) { if (!compare_addrinfo_sockaddr(res, ss)) break; /* OK, identical */ } if (!res0) { /* We hit the end of the list without finding an * address that was the same as ss. */ rprintf(FLOG, "no known address for \"%s\": " "spoofed address?\n", name_buf); strlcpy(name_buf, default_name, name_buf_size); } else if (res == NULL) { /* We hit the end of the list without finding an * address that was the same as ss. */ rprintf(FLOG, "%s is not a known address for \"%s\": " "spoofed address?\n", ipaddr, name_buf); strlcpy(name_buf, default_name, name_buf_size); } freeaddrinfo(res0); return 0; } /* Returns 1 for a valid IPv4 or IPv6 addr, or 0 for a bad one. */ static int valid_ipaddr(const char *s, int allow_scope) { int i; if (strchr(s, ':') != NULL) { /* Only IPv6 has a colon. */ int count, saw_double_colon = 0; int ipv4_at_end = 0; if (*s == ':') { /* A colon at the start must be a :: */ if (*++s != ':') return 0; saw_double_colon = 1; s++; } for (count = 0; count < 8; count++) { if (!*s) return saw_double_colon; if (allow_scope && *s == '%') { if (saw_double_colon) break; return 0; } if (strchr(s, ':') == NULL && strchr(s, '.') != NULL) { if ((!saw_double_colon && count != 6) || (saw_double_colon && count > 6)) return 0; ipv4_at_end = 1; break; } if (!isHexDigit(s++)) /* Need 1-4 hex digits */ return 0; if (isHexDigit(s) && isHexDigit(++s) && isHexDigit(++s) && isHexDigit(++s)) return 0; if (*s == ':') { if (!*++s) return 0; if (*s == ':') { if (saw_double_colon) return 0; saw_double_colon = 1; s++; } } } if (!ipv4_at_end) { if (allow_scope && *s == '%') for (s++; isAlNum(s); s++) { } return !*s && s[-1] != '%'; } } /* IPv4 */ for (i = 0; i < 4; i++) { long n; char *end; if (i && *s++ != '.') return 0; n = strtol(s, &end, 10); if (n > 255 || n < 0 || end <= s || end > s+3) return 0; s = end; } return !*s; }