rsync-bpc-3.1.2.1/0000775000047500004750000000000013510756427012532 5ustar craigcraigrsync-bpc-3.1.2.1/testhelp/0000775000047500004750000000000013510756401014352 5ustar craigcraigrsync-bpc-3.1.2.1/testhelp/maketree.py0000664000047500004750000000720213510756401016522 0ustar craigcraig#! /usr/bin/python2.2 # 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-bpc-3.1.2.1/itypes.h0000664000047500004750000000247513510756407014226 0ustar craigcraig/* Inline functions for rsync. * * Copyright (C) 2007-2015 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 isPrint(const char *ptr) { return isprint(*(unsigned char *)ptr); } static inline int isSpace(const char *ptr) { return isspace(*(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-bpc-3.1.2.1/options.c0000664000047500004750000030007113510756407014370 0ustar craigcraig/* * 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-2015 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 #include extern int module_id; extern int local_server; extern int sanitize_paths; extern int daemon_over_rsh; extern unsigned int module_dirlen; extern filter_rule_list filter_list; extern filter_rule_list daemon_filter_list; #define NOT_SPECIFIED (-42) 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 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_times = 0; int update_only = 0; int cvs_exclude = 0; int dry_run = 0; int do_xfers = 1; 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 def_compress_level = 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 = 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 human_readable = 1; int recurse = 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; long block_size = 0; /* "long" because popt can't set an int32. */ char *skip_compress = 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 *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 compare_dest = 0; int copy_dest = 0; int link_dest = 0; int basis_dir_cnt = 0; char *dest_option = NULL; static int remote_option_alloc = 0; int remote_option_cnt = 0; const char **remote_options = 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; extern int BPC_HardLinkMax; extern int BPC_PoolV3Enabled; char *bpc_top_dir; char *bpc_host_name; char *bpc_share_name; int bpc_backup_num = -1; int bpc_backup_compress; int bpc_backup_prev_num = -1; int bpc_backup_prev_compress; char *bpc_merge_bkup_info; int bpc_backup_inode0; int bpc_backup_attrib_new = 0; int bpc_log_level = 0; #define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */ char *batch_name = NULL; int need_unsorted_flist = 0; #ifdef ICONV_OPTION char *iconv_opt = ICONV_OPTION; #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*/ NULL, /*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(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 that are skipped due to options used"), 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-2)"), 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(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 omit_dir_times = 0; static int omit_link_times = 0; 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; #ifdef HAVE_SETVBUF static char *outbuf_mode; #endif 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++; if (!(buf = new_array(char, len))) out_of_memory("make_output_option"); 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) { 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 for each increase in verbose level:\n"); for (j = 1; 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 = 1; 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 = 1; 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; } static void print_rsync_version(enum logcode f) { char *subprotocol = ""; char const *got_socketpair = "no "; char const *have_inplace = "no "; char const *hardlinks = "no "; char const *prealloc = "no "; char const *symtimes = "no "; char const *acls = "no "; char const *xattrs = "no "; char const *links = "no "; char const *iconv = "no "; char const *ipv6 = "no "; STRUCT_STAT *dumstat; #if SUBPROTOCOL_VERSION != 0 if (asprintf(&subprotocol, ".PR%d", SUBPROTOCOL_VERSION) < 0) out_of_memory("print_rsync_version"); #endif #ifdef HAVE_SOCKETPAIR got_socketpair = ""; #endif #ifdef HAVE_FTRUNCATE have_inplace = ""; #endif #ifdef SUPPORT_HARD_LINKS hardlinks = ""; #endif #ifdef SUPPORT_PREALLOCATION prealloc = ""; #endif #ifdef SUPPORT_ACLS acls = ""; #endif #ifdef SUPPORT_XATTRS xattrs = ""; #endif #ifdef SUPPORT_LINKS links = ""; #endif #ifdef INET6 ipv6 = ""; #endif #ifdef ICONV_OPTION iconv = ""; #endif #ifdef CAN_SET_SYMLINK_TIMES symtimes = ""; #endif rprintf(f, "%s version %s protocol version %d%s\n", RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol); rprintf(f, "Copyright (C) 1996-2015 by Andrew Tridgell, Wayne Davison, and others.\n"); rprintf(f, "Web site: http://rsync.samba.org/\n"); rprintf(f, "Capabilities:\n"); rprintf(f, " %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n", (int)(sizeof (OFF_T) * 8), (int)(sizeof dumstat->st_ino * 8), /* Don't check ino_t! */ (int)(sizeof (time_t) * 8), (int)(sizeof (int64) * 8)); rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n", got_socketpair, hardlinks, links, ipv6, have_inplace); rprintf(f, " %sappend, %sACLs, %sxattrs, %siconv, %ssymtimes, %sprealloc\n", have_inplace, acls, xattrs, iconv, symtimes, prealloc); #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_bpc is special version of rsync for BackupPC.\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"); rprintf(F," -v, --verbose increase verbosity\n"); rprintf(F," --info=FLAGS fine-grained informational verbosity\n"); rprintf(F," --debug=FLAGS fine-grained debug verbosity\n"); rprintf(F," --msgs2stderr special output handling for debugging\n"); rprintf(F," -q, --quiet suppress non-error messages\n"); rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n"); rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n"); rprintf(F," -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)\n"); rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n"); rprintf(F," -r, --recursive recurse into directories\n"); rprintf(F," -R, --relative use relative path names\n"); rprintf(F," --no-implied-dirs don't send implied dirs with --relative\n"); rprintf(F," -b, --backup make backups (see --suffix & --backup-dir)\n"); rprintf(F," --backup-dir=DIR make backups into hierarchy based in DIR\n"); rprintf(F," --suffix=SUFFIX set backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX); rprintf(F," -u, --update skip files that are newer on the receiver\n"); rprintf(F," --inplace update destination files in-place (SEE MAN PAGE)\n"); rprintf(F," --append append data onto shorter files\n"); rprintf(F," --append-verify like --append, but with old data in file checksum\n"); rprintf(F," -d, --dirs transfer directories without recursing\n"); rprintf(F," -l, --links copy symlinks as symlinks\n"); rprintf(F," -L, --copy-links transform symlink into referent file/dir\n"); rprintf(F," --copy-unsafe-links only \"unsafe\" symlinks are transformed\n"); rprintf(F," --safe-links ignore symlinks that point outside the source tree\n"); rprintf(F," --munge-links munge symlinks to make them safer (but unusable)\n"); rprintf(F," -k, --copy-dirlinks transform symlink to a dir into referent dir\n"); rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -H, --hard-links preserve hard links\n"); rprintf(F," -p, --perms preserve permissions\n"); rprintf(F," -E, --executability preserve the file's executability\n"); rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n"); #ifdef SUPPORT_ACLS rprintf(F," -A, --acls preserve ACLs (implies --perms)\n"); #endif #ifdef SUPPORT_XATTRS rprintf(F," -X, --xattrs preserve extended attributes\n"); #endif rprintf(F," -o, --owner preserve owner (super-user only)\n"); rprintf(F," -g, --group preserve group\n"); rprintf(F," --devices preserve device files (super-user only)\n"); rprintf(F," --specials preserve special files\n"); rprintf(F," -D same as --devices --specials\n"); rprintf(F," -t, --times preserve modification times\n"); rprintf(F," -O, --omit-dir-times omit directories from --times\n"); rprintf(F," -J, --omit-link-times omit symlinks from --times\n"); rprintf(F," --super receiver attempts super-user activities\n"); #ifdef SUPPORT_XATTRS rprintf(F," --fake-super store/recover privileged attrs using xattrs\n"); #endif rprintf(F," -S, --sparse handle sparse files efficiently\n"); #ifdef SUPPORT_PREALLOCATION rprintf(F," --preallocate allocate dest files before writing them\n"); #else rprintf(F," --preallocate pre-allocate dest files on remote receiver\n"); #endif rprintf(F," -n, --dry-run perform a trial run with no changes made\n"); rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n"); rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n"); rprintf(F," -B, --block-size=SIZE force a fixed checksum block-size\n"); rprintf(F," -e, --rsh=COMMAND specify the remote shell to use\n"); rprintf(F," --rsync-path=PROGRAM specify the rsync to run on the remote machine\n"); rprintf(F," --existing skip creating new files on receiver\n"); rprintf(F," --ignore-existing skip updating files that already exist on receiver\n"); rprintf(F," --remove-source-files sender removes synchronized files (non-dirs)\n"); rprintf(F," --del an alias for --delete-during\n"); rprintf(F," --delete delete extraneous files from destination dirs\n"); rprintf(F," --delete-before receiver deletes before transfer, not during\n"); rprintf(F," --delete-during receiver deletes during the transfer\n"); rprintf(F," --delete-delay find deletions during, delete after\n"); rprintf(F," --delete-after receiver deletes after transfer, not during\n"); rprintf(F," --delete-excluded also delete excluded files from destination dirs\n"); rprintf(F," --ignore-missing-args ignore missing source args without error\n"); rprintf(F," --delete-missing-args delete missing source args from destination\n"); rprintf(F," --ignore-errors delete even if there are I/O errors\n"); rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); rprintf(F," --max-size=SIZE don't transfer any file larger than SIZE\n"); rprintf(F," --min-size=SIZE don't transfer any file smaller than SIZE\n"); rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --usermap=STRING custom username mapping\n"); rprintf(F," --groupmap=STRING custom groupname mapping\n"); rprintf(F," --chown=USER:GROUP simple username/groupname mapping\n"); rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n"); rprintf(F," --contimeout=SECONDS set daemon connection timeout in seconds\n"); rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n"); rprintf(F," -M, --remote-option=OPTION send OPTION to the remote side only\n"); rprintf(F," --size-only skip files that match in size\n"); rprintf(F," --modify-window=NUM compare mod-times with reduced accuracy\n"); rprintf(F," -T, --temp-dir=DIR create temporary files in directory DIR\n"); rprintf(F," -y, --fuzzy find similar file for basis if no dest file\n"); rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n"); rprintf(F," --copy-dest=DIR ... and include copies of unchanged files\n"); rprintf(F," --link-dest=DIR hardlink to files in DIR when unchanged\n"); rprintf(F," -z, --compress compress file data during the transfer\n"); rprintf(F," --compress-level=NUM explicitly set compression level\n"); rprintf(F," --skip-compress=LIST skip compressing files with a suffix in LIST\n"); rprintf(F," -C, --cvs-exclude auto-ignore files the same way CVS does\n"); rprintf(F," -f, --filter=RULE add a file-filtering RULE\n"); rprintf(F," -F same as --filter='dir-merge /.rsync-filter'\n"); rprintf(F," repeated: --filter='- .rsync-filter'\n"); rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n"); rprintf(F," --exclude-from=FILE read exclude patterns from FILE\n"); rprintf(F," --include=PATTERN don't exclude files matching PATTERN\n"); rprintf(F," --include-from=FILE read include patterns from FILE\n"); rprintf(F," --files-from=FILE read list of source-file names from FILE\n"); rprintf(F," -0, --from0 all *-from/filter files are delimited by 0s\n"); rprintf(F," -s, --protect-args no space-splitting; only wildcard special-chars\n"); rprintf(F," --address=ADDRESS bind address for outgoing socket to daemon\n"); rprintf(F," --port=PORT specify double-colon alternate port number\n"); rprintf(F," --sockopts=OPTIONS specify custom TCP options\n"); rprintf(F," --blocking-io use blocking I/O for the remote shell\n"); rprintf(F," --stats give some file-transfer stats\n"); rprintf(F," -8, --8-bit-output leave high-bit chars unescaped in output\n"); rprintf(F," -h, --human-readable output numbers in a human-readable format\n"); rprintf(F," --progress show progress during transfer\n"); rprintf(F," -P same as --partial --progress\n"); rprintf(F," -i, --itemize-changes output a change-summary for all updates\n"); rprintf(F," --out-format=FORMAT output updates using the specified FORMAT\n"); rprintf(F," --log-file=FILE log what we're doing to the specified FILE\n"); rprintf(F," --log-file-format=FMT log updates using the specified FMT\n"); rprintf(F," --password-file=FILE read daemon-access password from FILE\n"); rprintf(F," --list-only list the files instead of copying them\n"); rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); #ifdef HAVE_SETVBUF rprintf(F," --outbuf=N|L|B set output buffering to None, Line, or Block\n"); #endif rprintf(F," --write-batch=FILE write a batched update to FILE\n"); rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n"); rprintf(F," --read-batch=FILE read a batched update from FILE\n"); rprintf(F," --protocol=NUM force an older protocol version to be used\n"); #ifdef ICONV_OPTION rprintf(F," --iconv=CONVERT_SPEC request charset conversion of filenames\n"); #endif rprintf(F," --checksum-seed=NUM set block/file checksum seed (advanced)\n"); rprintf(F," -4, --ipv4 prefer IPv4\n"); rprintf(F," -6, --ipv6 prefer IPv6\n"); rprintf(F," --version print version number\n"); rprintf(F,"(-h) --help show this help (-h is --help only if used alone)\n"); rprintf(F," --bpc-top-dir=DIR absolute path to top BackupPC data directory\n"); rprintf(F," --bpc-hardlink-max=NUM hard link count maximum on TopDir file system\n"); rprintf(F," --bpc-v3pool-used=NUM flag for whether the V3 pool is in use\n"); rprintf(F," --bpc-host-name=HOST host name being backed up\n"); rprintf(F," --bpc-share-name=HOST share name being backed up\n"); rprintf(F," --bpc-bkup-num=NUM new backup number\n"); rprintf(F," --bpc-bkup-comp=NUM compression level for new backup\n"); rprintf(F," --bpc-bkup-prevnum=NUM previous backup number for reverse deltas\n"); rprintf(F," --bpc-bkup-prevcomp=NUM compression level for previous backup\n"); rprintf(F," --bpc-bkup-merge=N/C/V,... list of backups to merge, with number/compress/version for each\n"); rprintf(F," --bpc-bkup-inode0=NUM starting inode number for new backup\n"); rprintf(F," --bpc-attrib-new use new-style attribute files\n"); rprintf(F," --bpc-log-level=NUM log level\n"); 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) man pages for full documentation.\n"); rprintf(F,"See http://rsync.samba.org/ for updates, bug reports, and answers\n"); } enum {OPT_VERSION = 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_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_SERVER, 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", 0, POPT_ARG_NONE, 0, OPT_VERSION, 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 }, {"msgs2stderr", 0, POPT_ARG_NONE, &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_times, 1, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_times, 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", 0, 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 }, {"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 }, {"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 }, {"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 }, {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 }, {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 }, {"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_VAL, &do_compression, 1, 0, 0 }, {"new-compress", 0, POPT_ARG_VAL, &do_compression, 2, 0, 0 }, {"no-compress", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 }, {"no-z", 0, POPT_ARG_VAL, &do_compression, 0, 0, 0 }, {"skip-compress", 0, POPT_ARG_STRING, &skip_compress, 0, 0, 0 }, {"compress-level", 0, POPT_ARG_INT, &def_compress_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}, {"protect-args", 's', 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}, {"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 }, {"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 }, #ifdef ICONV_OPTION {"iconv", 0, POPT_ARG_STRING, &iconv_opt, 0, 0, 0 }, {"no-iconv", 0, POPT_ARG_NONE, 0, OPT_NO_ICONV, 0, 0 }, #endif {"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 }, {"qsort", 0, POPT_ARG_NONE, &use_qsort, 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 }, {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, #ifdef HAVE_SETVBUF {"outbuf", 0, POPT_ARG_STRING, &outbuf_mode, 0, 0, 0 }, #endif {"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 }, /* BackupPC options */ {"bpc-top-dir", 0, POPT_ARG_STRING, &bpc_top_dir, 0, 0, 0 }, {"bpc-hardlink-max", 0, POPT_ARG_INT, &BPC_HardLinkMax, 0, 0, 0 }, {"bpc-v3pool-used", 0, POPT_ARG_INT, &BPC_PoolV3Enabled, 0, 0, 0 }, {"bpc-host-name", 0, POPT_ARG_STRING, &bpc_host_name, 0, 0, 0 }, {"bpc-share-name", 0, POPT_ARG_STRING, &bpc_share_name, 0, 0, 0 }, {"bpc-bkup-num", 0, POPT_ARG_INT, &bpc_backup_num, 0, 0, 0 }, {"bpc-bkup-comp", 0, POPT_ARG_INT, &bpc_backup_compress, 0, 0, 0 }, {"bpc-bkup-prevnum", 0, POPT_ARG_INT, &bpc_backup_prev_num, 0, 0, 0 }, {"bpc-bkup-prevcomp",0, POPT_ARG_INT, &bpc_backup_prev_compress, 0, 0, 0 }, {"bpc-bkup-merge", 0, POPT_ARG_STRING, &bpc_merge_bkup_info, 0, 0, 0 }, {"bpc-bkup-inode0", 0, POPT_ARG_INT, &bpc_backup_inode0, 0, 0, 0 }, {"bpc-attrib-new", 0, POPT_ARG_NONE, &bpc_backup_attrib_new, 0, 0, 0 }, {"bpc-log-level", 0, POPT_ARG_INT, &bpc_log_level, 0, 0, 0 }, {0,0,0,0, 0, 0, 0} }; static void daemon_usage(enum logcode F) { print_rsync_version(F); rprintf(F,"\n"); rprintf(F,"Usage: rsync --daemon [OPTION]...\n"); rprintf(F," --address=ADDRESS bind to the specified address\n"); rprintf(F," --bwlimit=RATE limit socket I/O bandwidth\n"); rprintf(F," --config=FILE specify alternate rsyncd.conf file\n"); rprintf(F," -M, --dparam=OVERRIDE override global daemon config parameter\n"); rprintf(F," --no-detach do not detach from the parent\n"); rprintf(F," --port=PORT listen on alternate port number\n"); rprintf(F," --log-file=FILE override the \"log file\" setting\n"); rprintf(F," --log-file-format=FMT override the \"log format\" setting\n"); rprintf(F," --sockopts=OPTIONS specify custom TCP options\n"); rprintf(F," -v, --verbose increase verbosity\n"); rprintf(F," -4, --ipv4 prefer IPv4\n"); rprintf(F," -6, --ipv6 prefer IPv6\n"); rprintf(F," --help show this help screen\n"); 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) man page.\n"); } 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); msleep(20); } /** * Tweak the option table to disable all options that the rsyncd.conf * file has told us to refuse. **/ static void set_refuse_options(char *bp) { struct poptOption *op; char *cp, shortname[2]; int is_wild, found_match; shortname[1] = '\0'; while (1) { while (*bp == ' ') bp++; if (!*bp) break; if ((cp = strchr(bp, ' ')) != NULL) *cp= '\0'; is_wild = strpbrk(bp, "*?[") != NULL; found_match = 0; for (op = long_options; ; op++) { *shortname = op->shortName; if (!op->longName && !*shortname) break; if ((op->longName && wildmatch(bp, op->longName)) || (*shortname && wildmatch(bp, shortname))) { if (op->argInfo == POPT_ARG_VAL) op->argInfo = POPT_ARG_NONE; op->val = (op - long_options) + OPT_REFUSED_BASE; found_match = 1; /* These flags are set to let us easily check * an implied option later in the code. */ switch (*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 (wildmatch("delete", op->longName)) refused_delete = op->val; else if (wildmatch("delete-before", op->longName)) refused_delete_before = op->val; else if (wildmatch("delete-during", op->longName)) refused_delete_during = op->val; else if (wildmatch("partial", op->longName)) refused_partial = op->val; else if (wildmatch("progress", op->longName)) refused_progress = op->val; else if (wildmatch("inplace", op->longName)) refused_inplace = op->val; else if (wildmatch("no-iconv", op->longName)) refused_no_iconv = op->val; break; } if (!is_wild) break; } } if (!found_match) { rprintf(FLOG, "No match for refuse-options string \"%s\"\n", bp); } if (!cp) break; *cp = ' '; bp = cp + 1; } } static int count_args(const char **argv) { int i = 0; if (argv) { while (argv[i] != NULL) i++; } return i; } static OFF_T parse_size_arg(char **size_arg, char def_suf) { int reps, mult, make_compatible = 0; const char *arg; OFF_T size = 1; for (arg = *size_arg; isDigit(arg); arg++) {} if (*arg == '.') 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; default: return -1; } if (*arg == 'b' || *arg == 'B') mult = 1000, make_compatible = 1, arg++; else if (!*arg || *arg == '+' || *arg == '-') mult = 1024; else if (strncasecmp(arg, "ib", 2) == 0) mult = 1024, arg += 2; else return -1; while (reps--) size *= mult; size *= atof(*size_arg); if ((*arg == '+' || *arg == '-') && arg[1] == '1') size += atoi(arg), make_compatible = 1, arg += 2; if (*arg) return -1; if (size > 0 && make_compatible && def_suf == 'b') { /* We convert this manually because we may need %lld precision, * and that's not a portable sprintf() escape. */ char buf[128], *s = buf + sizeof buf - 1; OFF_T num = size; *s = '\0'; while (num) { *--s = (char)(num % 10) + '0'; num /= 10; } if (!(*size_arg = strdup(s))) out_of_memory("parse_size_arg"); } return size; } static void create_refuse_error(int which) { /* 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, "The server is configured to refuse --%s\n", op->longName) - 1; if (op->shortName) { snprintf(err_buf + n, sizeof err_buf - n, " (-%c)\n", op->shortName); } } /** * 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; char *ref = lp_refuse_options(module_id); const char *arg, **argv = *argv_p; int argc = *argc_p; int opt; if (ref && *ref) set_refuse_options(ref); if (am_daemon) { set_refuse_options("log-file*"); #ifdef ICONV_OPTION if (!*lp_charset(module_id)) set_refuse_options("iconv"); #endif } #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); while ((opt = poptGetNextOpt(pc)) != -1) { /* most options are handled automatically by popt; * only special cases are returned and listed here. */ switch (opt) { case OPT_VERSION: print_rsync_version(FINFO); exit_cleanup(0); 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) out_of_memory("parse_arguments"); 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_times = 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 '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 '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_options) out_of_memory("parse_arguments"); if (!remote_option_cnt) remote_options[0] = "ARG0"; } remote_options[++remote_option_cnt] = arg; remote_options[remote_option_cnt+1] = NULL; break; case OPT_WRITE_BATCH: /* batch_name is already set */ write_batch = 1; 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_MAX_SIZE: if ((max_size = parse_size_arg(&max_size_arg, 'b')) < 0) { snprintf(err_buf, sizeof err_buf, "--max-size value is invalid: %s\n", max_size_arg); return 0; } break; case OPT_MIN_SIZE: if ((min_size = parse_size_arg(&min_size_arg, 'b')) < 0) { snprintf(err_buf, sizeof err_buf, "--min-size value is invalid: %s\n", min_size_arg); return 0; } break; case OPT_BWLIMIT: { OFF_T limit = parse_size_arg(&bwlimit_arg, 'K'); if (limit < 0) { snprintf(err_buf, sizeof err_buf, "--bwlimit value is invalid: %s\n", bwlimit_arg); return 0; } bwlimit = (limit + 512) / 1024; if (limit && !bwlimit) { snprintf(err_buf, sizeof err_buf, "--bwlimit value is too small: %s\n", bwlimit_arg); return 0; } } break; case OPT_APPEND: if (am_server) append_mode++; else append_mode = 1; break; case OPT_LINK_DEST: #ifdef SUPPORT_HARD_LINKS link_dest = 1; dest_option = "--link-dest"; goto set_dest_dir; #else snprintf(err_buf, sizeof err_buf, "hard links are not supported on this %s\n", am_server ? "server" : "client"); return 0; #endif case OPT_COPY_DEST: copy_dest = 1; dest_option = "--copy-dest"; goto set_dest_dir; case OPT_COMPARE_DEST: compare_dest = 1; dest_option = "--compare-dest"; set_dest_dir: 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, dest_option); 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; 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; 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; } 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; } 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 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 (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_PROTECTED_ARGS protect_args = 1; #else protect_args = 0; #endif } } if ( !bpc_top_dir || !bpc_host_name || !bpc_share_name || bpc_backup_num < 0 ) { snprintf(err_buf, sizeof(err_buf), "BackupPC options are compulsory for running rsync_bpc\n"); exit_cleanup(RERR_SYNTAX); } if (human_readable > 1 && argc == 2 && !am_server) { /* Allow the old meaning of 'h' (--help) on its own. */ usage(FINFO); exit_cleanup(0); } if (do_compression || def_compress_level != NOT_SPECIFIED) { if (def_compress_level == NOT_SPECIFIED) def_compress_level = Z_DEFAULT_COMPRESSION; else if (def_compress_level < Z_DEFAULT_COMPRESSION || def_compress_level > Z_BEST_COMPRESSION) { snprintf(err_buf, sizeof err_buf, "--compress-level value is invalid: %d\n", def_compress_level); return 0; } else if (def_compress_level == Z_NO_COMPRESSION) do_compression = 0; else if (!do_compression) do_compression = 1; if (do_compression && refused_compress) { create_refuse_error(refused_compress); return 0; } #ifdef EXTERNAL_ZLIB if (do_compression == 1) { snprintf(err_buf, sizeof err_buf, "This rsync lacks old-style --compress due to its external zlib. Try -zz.\n"); if (am_server) return 0; fprintf(stderr, "%s" "Continuing without compression.\n\n", err_buf); do_compression = 0; } #endif } #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) { /* 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; 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 (block_size > MAX_BLOCK_SIZE) { snprintf(err_buf, sizeof err_buf, "--block-size=%lu is too large (max: %u)\n", block_size, MAX_BLOCK_SIZE); return 0; } 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 (compare_dest + copy_dest + link_dest > 1) { snprintf(err_buf, sizeof err_buf, "You may not mix --compare-dest, --copy-dest, and --link-dest.\n"); return 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; 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 (preserve_times) { preserve_times = PRESERVE_FILE_TIMES; if (!omit_dir_times) preserve_times |= PRESERVE_DIR_TIMES; #ifdef CAN_SET_SYMLINK_TIMES if (!omit_link_times) preserve_times |= PRESERVE_LINK_TIMES; #endif } if (make_backups && !backup_dir) { omit_dir_times = 0; /* Implied, so avoid -O to sender. */ preserve_times &= ~PRESERVE_DIR_TIMES; } 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 (sparse_files ) { /* sparse files are not supported by BackupPC */ snprintf(err_buf, sizeof err_buf, "--sparse is not supported by rsync_bpc and BackupPC\n"); return 0; } 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 (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; } } } 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; } /** * 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 (daemon_over_rsh > 0) { args[ac++] = "--daemon"; *argc_p = ac; /* if we're passing --daemon, we're done */ return; } 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'; /* the -q option is intentionally left out */ 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) 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_times) argstr[x++] = 't'; 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 == 1) argstr[x++] = 'z'; set_allow_inc_recurse(); /* 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) { /* Use "eFlags" alias so that cull_options doesn't think that these are no-arg option letters. */ #define eFlags argstr /* We make use of the -e option to let the server know about * any pre-release protocol version && some behavior flags. */ eFlags[x++] = 'e'; #if SUBPROTOCOL_VERSION != 0 if (protocol_version == PROTOCOL_VERSION) { x += snprintf(argstr+x, sizeof argstr - x, "%d.%d", PROTOCOL_VERSION, SUBPROTOCOL_VERSION); } else #endif eFlags[x++] = '.'; if (allow_inc_recurse) eFlags[x++] = 'i'; #ifdef CAN_SET_SYMLINK_TIMES eFlags[x++] = 'L'; /* symlink time-setting support */ #endif #ifdef ICONV_OPTION eFlags[x++] = 's'; /* symlink iconv translation support */ #endif eFlags[x++] = 'f'; /* flist I/O-error safety support */ eFlags[x++] = 'x'; /* xattr hardlink optimization not desired */ eFlags[x++] = 'C'; /* support checksum seed order fix */ #undef eFlags } if (x >= (int)sizeof argstr) { /* Not possible... */ rprintf(FERROR, "argstr overflow in server_options().\n"); exit_cleanup(RERR_MALLOC); } argstr[x] = '\0'; if (x > 1) args[ac++] = argstr; #ifdef ICONV_OPTION if (iconv_opt) { char *set = strchr(iconv_opt, ','); if (set) set++; else set = iconv_opt; if (asprintf(&arg, "--iconv=%s", set) < 0) goto oom; args[ac++] = arg; } #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 && def_compress_level != Z_DEFAULT_COMPRESSION) { if (asprintf(&arg, "--compress-level=%d", def_compress_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 (block_size) { if (asprintf(&arg, "-B%lu", 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) { args[ac++] = "--backup-dir"; args[ac++] = backup_dir; } /* Only send --suffix if it specifies a non-default value. */ if (strcmp(backup_suffix, backup_dir ? "" : BACKUP_SUFFIX) != 0) { /* We use the following syntax to avoid weirdness with '~'. */ if (asprintf(&arg, "--suffix=%s", backup_suffix) < 0) goto oom; args[ac++] = arg; } 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++] = "--min-size"; args[ac++] = min_size_arg; } if (max_size >= 0) { args[ac++] = "--max-size"; args[ac++] = 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) { if (asprintf(&arg, "--skip-compress=%s", skip_compress) < 0) goto oom; args[ac++] = 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) { if (asprintf(&arg, "--modify-window=%d", 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++] = 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) { if (asprintf(&arg, "--usermap=%s", usermap) < 0) goto oom; args[ac++] = arg; } if (groupmap) { if (asprintf(&arg, "--groupmap=%s", groupmap) < 0) goto oom; args[ac++] = arg; } 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++] = tmpdir; } 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++] = dest_option; args[ac++] = 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; arg = make_output_option(debug_words, debug_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"; if (files_from && (!am_sender || filesfrom_host)) { if (filesfrom_host) { args[ac++] = "--files-from"; args[ac++] = 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 (remove_source_files == 1) args[ac++] = "--remove-source-files"; else if (remove_source_files) args[ac++] = "--remove-sent-files"; if (preallocate_files && am_sender) args[ac++] = "--preallocate"; if (ac > MAX_SERVER_ARGS) { /* Not possible... */ rprintf(FERROR, "argc overflow in server_options().\n"); exit_cleanup(RERR_MALLOC); } if (do_compression > 1) args[ac++] = "--new-compress"; 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++] = (char*)remote_options[j]; } *argc_p = ac; return; oom: out_of_memory("server_options"); } /* 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 specfication 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 = RSYNC_PORT; return path; } } *host_ptr = parse_hostspec(s, &path, NULL); if (!*host_ptr) return NULL; if (*path == ':') { if (port_ptr && !*port_ptr) *port_ptr = RSYNC_PORT; return path + 1; } if (port_ptr) *port_ptr = 0; return path; } rsync-bpc-3.1.2.1/generator.c0000664000047500004750000020723613510756407014674 0ustar craigcraig/* * 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-2015 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 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_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 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 checksum_len; extern char *partial_dir; extern int compare_dest; extern int copy_dest; extern int link_dest; extern int whole_file; extern int list_only; extern int read_batch; extern int write_batch; extern int safe_symlinks; extern long block_size; /* "long" because popt can't set an int32. */ 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; 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; enum nonregtype { TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK }; /* 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, NULL)) < 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; int j, len, mode; 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; 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 (file->flags & FLAG_TOP_DIR) filesystem_dev = *fs_dev; else if (filesystem_dev != *fs_dev) return; } 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 time_differs(struct file_struct *file, stat_x *sxp) { return cmp_time(sxp->st.st_mtime, file->modtime); } static inline int perms_differ(struct file_struct *file, stat_x *sxp) { /* fprintf(stderr, "perms_differ(%s, %d): modes = (0%o, 0%o)\n", file->basename, preserve_perms, file->mode, sxp->st.st_mode); */ 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) { /* fprintf(stderr, "unchanged_attrs(%s): mode (%o,%o), mtime (%lu,%lu), uid (%u,%u)\n", fname, file->mode, sxp->st.st_mode, file->modtime, sxp->st.st_mtime, (uid_t)F_OWNER(file), sxp->st.st_uid); */ if (S_ISLNK(file->mode)) { #ifdef CAN_SET_SYMLINK_TIMES if (preserve_times & PRESERVE_LINK_TIMES && time_differs(file, sxp)) 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_times && time_differs(file, sxp)) 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_times ? 0 : S_ISDIR(file->mode) ? preserve_times & PRESERVE_DIR_TIMES : S_ISLNK(file->mode) ? preserve_times & PRESERVE_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 ? cmp_time(file->modtime, sxp->st.st_mtime) != 0 : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) iflags |= ITEM_REPORT_TIME; #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST 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); } } } /* Perform our quick-check heuristic for determining if a file is unchanged. */ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st) { if (st->st_size != F_LENGTH(file)) { /* fprintf(stderr, "unchanged_file(%s): size changed (%lu vs %lu)\n", fn, st->st_size, F_LENGTH(file)); */ return 0; } if ((st->st_nlink <= 1 && F_IS_HLINKED(file)) || (st->st_nlink > 1 && !F_IS_HLINKED(file))) { /* fprintf(stderr, "unchanged_file(%s): links changed (nlink %lu, isHlink %d)\n", fn, st->st_nlink, F_IS_HLINKED(file)); */ return 0; } /* if always checksum is set then we use the checksum instead of the file time to determine whether to sync */ if (always_checksum > 0 && S_ISREG(st->st_mode)) { char sum[MAX_DIGEST_LEN]; int csumError = file_checksum(fn, st, sum); /* { uchar *p = (uchar*)F_SUM(file); fprintf(stderr, "unchanged_file(%s): %s (err=%d) %02x%02x%02x%02x... vs %02x%02x%02x%02x...\n", fn, memcmp(sum, F_SUM(file), checksum_len) ? "neq" : "equal", csumError, p[0], p[1], p[2], p[3], sum[0] & 0xff, sum[1] & 0xff, sum[2] & 0xff, sum[3] & 0xff); } */ if ( csumError || memcmp(sum, F_SUM(file), checksum_len) ) return 0; } if (size_only > 0) { /* fprintf(stderr, "unchanged_file(%s): size_only is %d\n", fn, size_only); */ return 1; } if (ignore_times) { /* fprintf(stderr, "unchanged_file(%s): ignore_times is set\n", fn); */ return 0; } if ( preserve_perms && !BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS) ) { /* fprintf(stderr, "unchanged_file(%s): permission changed (0%o, 0%o)\n", fn, st->st_mode, file->mode); */ return 0; } /* fprintf(stderr, "unchanged_file(%s): returning cmd_time(%ld, %ld)\n", fn, st->st_mtime, file->modtime); */ return cmp_time(st->st_mtime, file->modtime) == 0; } /* * 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) && cmp_time(fp->modtime, 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); /* Add some extra weight to how well the suffixes match. */ dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len) * 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; switch (match_level) { case 0: best_match = j; match_level = 1; /* FALL THROUGH */ case 1: if (!unchanged_file(cmpbuf, file, &sxp->st)) continue; best_match = j; match_level = 2; /* FALL THROUGH */ case 2: if (!unchanged_attrs(cmpbuf, file, sxp)) { free_stat_x(sxp); continue; } best_match = j; match_level = 3; break; } break; } 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 && !copy_dest) { if (find_exact_for_existing) { if (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 (link_dest) { if (!hard_link_one(file, fname, cmpbuf, 1)) goto try_a_copy; 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 nonregtype type; uint32 *devp; #ifdef SUPPORT_LINKS char lnk[MAXPATHLEN]; int len; #endif int j = 0; #ifndef SUPPORT_LINKS if (S_ISLNK(file->mode)) return -1; #endif if (S_ISDIR(file->mode)) { type = TYPE_DIR; } else if (IS_SPECIAL(file->mode)) type = TYPE_SPECIAL; else if (IS_DEVICE(file->mode)) type = TYPE_DEVICE; #ifdef SUPPORT_LINKS else if (S_ISLNK(file->mode)) type = TYPE_SYMLINK; #endif else { 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; switch (type) { case TYPE_DIR: if (!S_ISDIR(sxp->st.st_mode)) continue; break; case TYPE_SPECIAL: if (!IS_SPECIAL(sxp->st.st_mode)) continue; break; case TYPE_DEVICE: if (!IS_DEVICE(sxp->st.st_mode)) continue; break; case TYPE_SYMLINK: #ifdef SUPPORT_LINKS if (!S_ISLNK(sxp->st.st_mode)) continue; break; #else return -1; #endif } if (match_level < 1) { match_level = 1; best_match = j; } switch (type) { case TYPE_DIR: case TYPE_SPECIAL: break; case TYPE_DEVICE: devp = F_RDEV_P(file); if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp))) continue; break; case TYPE_SYMLINK: #ifdef SUPPORT_LINKS if ((len = bpc_readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0) continue; lnk[len] = '\0'; if (strcmp(lnk, F_SYMLINK(file)) != 0) continue; break; #else return -1; #endif } 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 (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 = compare_dest && type != TYPE_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, type == TYPE_DIR ? "/" : ""); } return -2; } return j; } static void list_file_entry(struct file_struct *f) { char permbuf[PERMSTRING_SIZE]; int64 len; int colwidth = human_readable ? 14 : 11; if (!F_IS_ACTIVE(f)) { /* this can happen if duplicate names were removed */ return; } permstring(permbuf, f->mode); len = F_LENGTH(f); /* TODO: indicate '+' if the entry has an ACL. */ #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(f->mode)) { rprintf(FINFO, "%s %*s %s %s -> %s\n", permbuf, colwidth, human_num(len), timestring(f->modtime), f_name(f, NULL), F_SYMLINK(f)); } else #endif if (missing_args == 2 && f->mode == 0) { rprintf(FINFO, "%-*s %s\n", colwidth + 31, "*missing", f_name(f, NULL)); } else { rprintf(FINFO, "%s %*s %s %s\n", permbuf, colwidth, human_num(len), timestring(f->modtime), f_name(f, NULL)); } } 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; int skip_unchanged_check = 0; int is_dir = !S_ISDIR(file->mode) ? 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; } 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) && flist_find_name(cur_flist, dn, 1) < 0) { rprintf(FERROR, "ABORTING due to invalid path from sender: %s/%s\n", dn, file->basename); exit_cleanup(RERR_PROTOCOL); } if (relative_paths && !implied_dirs && 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; } #if 0 /* was SUPPORT_ACLS */ if (!preserve_perms) dflt_perms = default_perms_for_dir(dn); #endif } parent_dirname = dn; if (need_fuzzy_dirlist && S_ISREG(file->mode)) { 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); if (fuzzy_dirlist[i] && fuzzy_dirlist[i]->used == 0) { flist_free(fuzzy_dirlist[i]); fuzzy_dirlist[i] = NULL; } } need_fuzzy_dirlist = 0; } 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; } /* fprintf(stderr, "recv_generator: fname %s: statret %d, isdir %d, protocol %d, always %d\n", fname, statret, is_dir, protocol_version, always_checksum); */ if ( statret != 0 && !is_dir && protocol_version >= 30 && always_checksum ) { /* * For protocol_version >= 30 and if always_checksum is set, we can use the * MD5 whole-file digest to check the pool. Use that as the basis if the * file is there. The receiver does the same in recv_files(). */ if ( S_ISREG(file->mode) && !bpc_sysCall_poolFileCheck(fname, file) && !link_stat(fname, &sx.st, 0) ) { statret = 0; stat_errno = 0; /* * make sure we send file deltas to ensure our guess is correct. */ skip_unchanged_check = 1; } } 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 (ignore_existing > 0 && statret == 0 && (!is_dir || !S_ISDIR(sx.st.st_mode))) { if (INFO_GTE(SKIP, 1) && is_dir >= 0) rprintf(FINFO, "%s exists\n", fname); #ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out); #endif bpc_sysCall_statusFileSize(0); 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_times & PRESERVE_DIR_TIMES)) return; /* 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 && (S_ISDIR(sx.st.st_mode) || 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 && !S_ISDIR(sx.st.st_mode)) { 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 && !S_ISDIR(sx.st.st_mode); 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 && S_ISLNK(file->mode)) { #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); } return; } if (statret == 0) { char lnk[MAXPATHLEN]; int len; if (S_ISLNK(sx.st.st_mode) && (len = bpc_readlink(fname, lnk, MAXPATHLEN-1)) > 0 && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') { /* 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 bpc_sysCall_statusFileSize(len); 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 (link_dest) { /* Resort to --copy-dest behavior. */ } else #endif if (!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 && !S_ISLNK(sx.st.st_mode)) 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 bpc_sysCall_statusFileSize(F_LENGTH(file)); /* 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 && IS_DEVICE(file->mode)) || (preserve_specials && IS_SPECIAL(file->mode))) { dev_t rdev; int del_for_flag = 0; if (IS_DEVICE(file->mode)) { uint32 *devp = F_RDEV_P(file); rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); } else rdev = 0; if (statret == 0) { if (IS_DEVICE(file->mode)) { if (!IS_DEVICE(sx.st.st_mode)) statret = -1; del_for_flag = DEL_FOR_DEVICE; } else { if (!IS_SPECIAL(sx.st.st_mode)) statret = -1; del_for_flag = DEL_FOR_SPECIAL; } if (statret == 0 && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT) && (IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev == rdev)) { /* 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 bpc_sysCall_statusFileSize(0); 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 (link_dest) { /* Resort to --copy-dest behavior. */ } else #endif if (!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 bpc_sysCall_statusFileSize(0); if (remove_source_files == 1) goto return_with_success; } goto cleanup; } if (!S_ISREG(file->mode)) { if (solo_file) fname = f_name(file, NULL); rprintf(FINFO, "skipping non-regular file \"%s\"\n", fname); bpc_sysCall_statusFileSize(0); 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 && cmp_time(sx.st.st_mtime, file->modtime) > 0) { 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 bpc_sysCall_statusFileSize(F_LENGTH(file)); goto cleanup; } fnamecmp_type = FNAMECMP_FNAME; if (statret == 0 && !S_ISREG(sx.st.st_mode)) { 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 || !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) { /* 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 (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH) ; else if (fnamecmp_type == FNAMECMP_FUZZY) ; else if (!skip_unchanged_check && unchanged_file(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); 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 bpc_sysCall_statusFileSize(F_LENGTH(file)); if (remove_source_files != 1) goto cleanup; return_with_success: if (!dry_run) send_msg_int(MSG_SUCCESS, ndx); goto cleanup; } skip_unchanged_check = 0; 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 bpc_sysCall_statusFileSize(F_LENGTH(file)); 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 = 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))) { bpc_close(fd); goto cleanup; } if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) { bpc_close(fd); 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; bpc_close(fd); 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; bpc_close(fd); 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); bpc_close(fd); } 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); } bpc_close(fd); } cleanup: if (back_file) { int save_preserve_xattrs = preserve_xattrs; if (f_copy >= 0) bpc_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); /* * For BackupPC, creating the special file as a temporary and renaming it * (the so-called atomic method) is problematic for several reasons. So * we force it to do it the old way by forcing skip_atomic to 1. */ skip_atomic = 1; 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) { bpc_tmpNameFlagSet(tmpname); 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 && cmp_time(st.st_mtime, file->modtime) != 0) set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode); } 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_times & PRESERVE_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); if (!deldelay_buf) out_of_memory("delete-delay"); } 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-bpc-3.1.2.1/xattrs.c0000664000047500004750000007033413510756407014230 0ustar craigcraig/* * Extended Attribute support for rsync. * Written by Jay Fenlason, vaguely based on the ACLs patch. * * Copyright (C) 2004 Red Hat, Inc. * Copyright (C) 2006-2015 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; #define RSYNC_XAL_INITIAL 5 #define RSYNC_XAL_LIST_INITIAL 100 #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; static size_t namebuf_len = 0; static char *namebuf = NULL; static item_list empty_xattr = EMPTY_ITEM_LIST; static item_list rsync_xal_l = EMPTY_ITEM_LIST; 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); if (!namebuf) out_of_memory("get_xattr_names"); } 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); if (!namebuf) out_of_memory("get_xattr_names"); } 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 (datum_len + extra_len < datum_len) overflow_exit("get_xattr_data"); if (!(ptr = new_array(char, datum_len + extra_len))) out_of_memory("get_xattr_data"); 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; #ifdef HAVE_LINUX_XATTRS /* We always ignore the system namespace, and non-root * ignores everything but the user namespace. */ 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_DIGEST_LEN; sum_init(checksum_seed); sum_update(ptr, datum_len); free(ptr); if (!(ptr = new_array(char, name_offset + name_len))) out_of_memory("rsync_xal_get"); *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; #ifdef HAVE_LINUX_XATTRS /* We always ignore the system namespace, and non-root * ignores everything but the user namespace. */ 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 int find_matching_xattr(item_list *xalp) { size_t i, j; item_list *lst = rsync_xal_l.items; for (i = 0; i < rsync_xal_l.count; i++) { rsync_xa *rxas1 = lst[i].items; rsync_xa *rxas2 = xalp->items; /* Wrong number of elements? */ if (lst[i].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, MAX_DIGEST_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 i; } return -1; } /* Store *xalp on the end of rsync_xal_l */ static void rsync_xal_store(item_list *xalp) { item_list *new_lst = EXPAND_ITEM_LIST(&rsync_xal_l, item_list, RSYNC_XAL_LIST_INITIAL); /* 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_lst = empty_xattr; (void)EXPAND_ITEM_LIST(new_lst, rsync_xa, xalp->count); memcpy(new_lst->items, xalp->items, xalp->count * sizeof (rsync_xa)); new_lst->count = xalp->count; xalp->count = 0; } /* 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, MAX_DIGEST_LEN); else write_bigbuf(f, rxa->datum, rxa->datum_len); } ndx = rsync_xal_l.count; /* pre-incremented count */ 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) { item_list *lst = rsync_xal_l.items; 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) lst += F_XATTR(file); 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, MAX_DIGEST_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) { item_list *lst = rsync_xal_l.items; int cnt, prior_req = 0; rsync_xa *rxa; lst += F_XATTR(file); 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) { item_list *lst = rsync_xal_l.items; 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); } lst += F_XATTR(file); cnt = lst->count; rxa = lst->items; num = 0; while ((rel_pos = read_varint(f_in)) != 0) { num += rel_pos; /* Note that the sender-related num values may not be in order on the receiver! */ while (cnt && (am_sender ? rxa->num < num : rxa->num != num)) { rxa++; cnt--; } 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 (rxa->name_len + rxa->datum_len < rxa->name_len) overflow_exit("recv_xattr_request"); rxa->datum = new_array(char, rxa->datum_len + rxa->name_len); if (!rxa->datum) out_of_memory("recv_xattr_request"); 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 + MAX_DIGEST_LEN : datum_len; size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0; if ((dget_len + extra_len < dget_len) || (dget_len + extra_len + name_len < dget_len)) overflow_exit("receive_xattr"); ptr = new_array(char, dget_len + extra_len + name_len); if (!ptr) out_of_memory("receive_xattr"); name = ptr + dget_len + extra_len; read_buf(f, name, name_len); if (dget_len == datum_len) read_buf(f, ptr, dget_len); else { *ptr = XSTATE_ABBREV; read_buf(f, ptr + 1, MAX_DIGEST_LEN); } #ifdef HAVE_LINUX_XATTRS /* Non-root can only save the user namespace. */ if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) { if (!am_root) { 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_l.count; /* pre-incremented count */ 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) { item_list *xattr_item = rsync_xal_l.items; item_list *xattr_start = xattr_item + prior_xattr_count; xattr_item += rsync_xal_l.count; rsync_xal_l.count = prior_xattr_count; while (xattr_item-- > xattr_start) rsync_xal_free(xattr_item); 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_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(checksum_seed); sum_update(ptr, len); sum_end(sum); if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_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; #ifdef HAVE_LINUX_XATTRS /* We always ignore the system namespace, and non-root * ignores everything but the user namespace. */ 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) { int ndx; item_list *lst = rsync_xal_l.items; 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 ndx = F_XATTR(file); return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp); } #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) { int mode, 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-bpc-3.1.2.1/access.c0000664000047500004750000001407613510756407014145 0ustar craigcraig/* * Routines to authenticate access to a daemon (hosts allow/deny). * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2004-2015 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" 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; /* 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) { if (!(*host_ptr = strdup(tok))) *host_ptr = undetermined_hostname; } 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); if (!list2) out_of_memory("access_match"); 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-bpc-3.1.2.1/authenticate.c0000664000047500004750000002332613510756407015360 0ustar craigcraig/* * Support rsync daemon authentication. * * Copyright (C) 1998-2000 Andrew Tridgell * Copyright (C) 2002-2015 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 int read_only; extern char *password_file; /*************************************************************************** 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()); sum_init(0); sum_update(input, sizeof input); len = 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; sum_init(0); sum_update(in, strlen(in)); sum_update(challenge, strlen(challenge)); len = 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 (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() == 0 && st.st_uid != 0) { 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); memset(line, 0, sizeof line); memset(pass2, 0, 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 (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() == 0 && st.st_uid != 0) { 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]; 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 ""; 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'; if (!(users = strdup(users))) out_of_memory("auth_server"); 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; if ((auth_uid_groups = new_array(char *, auth_uid_groups_cnt)) == NULL) out_of_memory("auth_server"); 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 { char *group = group_match >= 0 ? auth_uid_groups[group_match] : NULL; err = check_secret(module, line, group, challenge, pass); } memset(challenge, 0, sizeof challenge); memset(pass, 0, strlen(pass)); if (auth_uid_groups) { int j; for (j = 0; j < auth_uid_groups_cnt; j++) { if (auth_uid_groups[j]) free(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"; 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-bpc-3.1.2.1/lib/0000775000047500004750000000000013510756407013276 5ustar craigcraigrsync-bpc-3.1.2.1/lib/wildmatch.h0000664000047500004750000000043213510756401015414 0ustar craigcraig/* 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-bpc-3.1.2.1/lib/permstring.h0000664000047500004750000000010713510756401015631 0ustar craigcraig#define PERMSTRING_SIZE 11 void permstring(char *perms, mode_t mode); rsync-bpc-3.1.2.1/lib/sysacls.c0000664000047500004750000020221513510756407015125 0ustar craigcraig/* * Unix SMB/CIFS implementation. * Based on the Samba ACL support code. * Copyright (C) Jeremy Allison 2000. * Copyright (C) 2007-2015 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 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 preceed 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) /*---------------------------------------------*/ #include /* * 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. */ static BOOL hpux_acl_call_presence(void) { 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; 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 preceed 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 strucutres. * 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;in_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 availabe 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 trival 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 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;icount <= 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; struct new_acl_entry *entry; 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 = *entry_p = link->entryp; DEBUG(10,("*entry_p is %d\n",entry_p)); DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access)); /* 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; 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; } rsync-bpc-3.1.2.1/lib/sysacls.h0000664000047500004750000001746013510756407015140 0ustar craigcraig/* * Unix SMB/Netbios implementation. * Version 2.2.x * Portable SMB ACL interface * Copyright (C) Jeremy Allison 2000 * Copyright (C) 2007-2015 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. */ #undef GROUP #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-bpc-3.1.2.1/lib/dummy.in0000664000047500004750000000014613510756401014754 0ustar craigcraigThis is a dummy file to ensure that the lib directory gets created by configure when a VPATH is used. rsync-bpc-3.1.2.1/lib/inet_pton.c0000664000047500004750000001173513510756401015442 0ustar craigcraig/* * 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-bpc-3.1.2.1/lib/snprintf.c0000664000047500004750000010637413510756401015312 0ustar craigcraig/* * 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 nast 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, formated 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. * addedd 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-bpc-3.1.2.1/lib/pool_alloc.c0000664000047500004750000002140013510756401015554 0ustar craigcraig#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)(); /* function to call 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 *), int flags) { struct alloc_pool *pool; if (!(pool = new0(struct alloc_pool))) return NULL; if ((MINALIGN & (MINALIGN - 1)) != 0) { if (bomb) (*bomb)("Compiler error: MINALIGN is not a power of 2\n"); 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); 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-bpc-3.1.2.1/lib/mdigest.h0000664000047500004750000000152113510756401015074 0ustar craigcraig/* The include file for both the MD4 and MD5 routines. */ #define MD4_DIGEST_LEN 16 #define MD5_DIGEST_LEN 16 #define MAX_DIGEST_LEN MD5_DIGEST_LEN #define CSUM_CHUNK 64 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 get_mdfour(uchar digest[MD4_DIGEST_LEN], const uchar *in, int length); 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]); void get_md5(uchar digest[MD5_DIGEST_LEN], const uchar *input, int n); rsync-bpc-3.1.2.1/lib/inet_ntop.c0000664000047500004750000001147513510756401015443 0ustar craigcraig/* * 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-bpc-3.1.2.1/lib/getaddrinfo.c0000664000047500004750000002502013510756401015721 0ustar craigcraig/* 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-bpc-3.1.2.1/lib/pool_alloc.30000664000047500004750000001526713510756401015512 0ustar craigcraig.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 *), 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-bpc-3.1.2.1/lib/permstring.c0000664000047500004750000000345013510756407015636 0ustar craigcraig/* * A single utility routine. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001 Martin Pool * Copyright (C) 2003-2015 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-bpc-3.1.2.1/lib/addrinfo.h0000664000047500004750000001127213510756401015232 0ustar craigcraig/* 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-bpc-3.1.2.1/lib/md5.c0000664000047500004750000001571113510756401014126 0ustar craigcraig/* * RFC 1321 compliant MD5 implementation * * Copyright (C) 2001-2003 Christophe Devine * * 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; } 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; } while (length >= CSUM_CHUNK) { md5_process(ctx, input); length -= CSUM_CHUNK; input += CSUM_CHUNK; } 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); } 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); } #ifdef TEST_MD5 #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-bpc-3.1.2.1/lib/wildmatch.c0000664000047500004750000002261313510756401015414 0ustar craigcraig/* ** 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-bpc-3.1.2.1/lib/mdfour.c0000664000047500004750000001374013510756407014743 0ustar craigcraig/* * 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-2015 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); } 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); } #ifdef TEST_MDFOUR 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-bpc-3.1.2.1/lib/sysxattrs.c0000664000047500004750000001565013510756407015535 0ustar craigcraig/* * Extended attribute support for rsync. * * Copyright (C) 2004 Red Hat, Inc. * Copyright (C) 2003-2015 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 bpc_lgetxattr(path, name, value, size); } ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { return bpc_fgetxattr(filedes, name, value, size); } int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size) { return bpc_lsetxattr(path, name, value, size, 0); } int sys_lremovexattr(const char *path, const char *name) { return bpc_lremovexattr(path, name); } ssize_t sys_llistxattr(const char *path, char *list, size_t size) { return bpc_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, 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, 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, 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; if ((ret += len+1) > 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-bpc-3.1.2.1/lib/pool_alloc.h0000664000047500004750000000154413510756401015570 0ustar craigcraig#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 *), 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-bpc-3.1.2.1/lib/sysxattrs.h0000664000047500004750000000133013510756401015522 0ustar craigcraig#ifdef SUPPORT_XATTRS #if defined HAVE_ATTR_XATTR_H #include #elif defined HAVE_SYS_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-bpc-3.1.2.1/lib/compat.c0000664000047500004750000001414113510756407014726 0ustar craigcraig/* * Reimplementations of standard functions for platforms that don't have them. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2015 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; #ifndef HAVE_STRDUP char *strdup(char *s) { int len = strlen(s) + 1; char *ret = (char *)malloc(len); if (ret) memcpy(ret, s, len); return ret; } #endif #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 ocurrence 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 } #define HUMANIFY(mult) \ do { \ 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 { \ dnum /= mult; \ units = 'T'; \ } \ if (num < 0) \ dnum = -dnum; \ snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \ return bufs[n]; \ } \ } while (0) /* 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) { char buf[32]; snprintf(buf, sizeof buf, "%f", 3.14); if (strchr(buf, '.') != NULL) number_separator = ','; else number_separator = '.'; } n = (n + 1) % (sizeof bufs / sizeof bufs[0]); if (human_flag > 1) { if (human_flag == 2) HUMANIFY(1000); else HUMANIFY(1024); } 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-bpc-3.1.2.1/lib/getpass.c0000664000047500004750000000343713510756401015111 0ustar craigcraig/* * 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-bpc-3.1.2.1/configure.ac0000664000047500004750000010563113510756407015024 0ustar craigcraigdnl Process this file with autoconf to produce a configure script. AC_INIT([rsync],[3.1.2.1],[http://rsync.samba.org/bugzilla.html]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([byteorder.h]) AC_CONFIG_HEADER(config.h) AC_PREREQ([2.69]) AC_SUBST(RSYNC_VERSION, $PACKAGE_VERSION) AC_MSG_NOTICE([Configuring rsync $PACKAGE_VERSION]) AC_DEFINE_UNQUOTED(RSYNC_VERSION, ["$PACKAGE_VERSION"], [rsync release 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 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_EGREP AC_PROG_INSTALL AC_PROG_MKDIR_P AC_PROG_CC_STDC AC_SUBST(SHELL) AC_PATH_PROG([PERL], [perl]) 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 AC_ARG_ENABLE(profile, AS_HELP_STRING([--enable-profile],[turn on CPU profiling])) if test x"$enable_profile" = x"yes"; then CFLAGS="$CFLAGS -pg" fi # Specifically, this turns on panic_action handling. AC_ARG_ENABLE(maintainer-mode, AS_HELP_STRING([--enable-maintainer-mode],[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(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(protected-args, AS_HELP_STRING([--with-protected-args],[make --protected-args option the default])) if test x"$with_protected_args" = x"yes"; then AC_DEFINE_UNQUOTED(RSYNC_USE_PROTECTED_ARGS, 1, [Define to 1 if --protected-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]) AC_CHECK_PROG(HAVE_YODL2MAN, yodl2man, 1, 0) if test x$HAVE_YODL2MAN = x1; then MAKE_MAN=man else MAKE_MAN=man-copy fi # 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-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", [unprivileged user--e.g. nobody]) AC_DEFINE_UNQUOTED(NOBODY_GROUP, "$NOBODY_GROUP", [unprivileged group for unprivileged user]) # 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 #include #include #include #include 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); exit(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 ipv6type=unknown ipv6lib=none ipv6trylibc=yes AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--disable-ipv6],[do not even try to use IPv6])) if test x"$enable_ipv6" != x"no"; then AC_MSG_CHECKING([ipv6 stack type]) for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta cygwin; do case $i in inria) # http://www.kame.net/ AC_EGREP_CPP(yes, [ #include #ifdef IPV6_INRIA_VERSION yes #endif], [ipv6type=$i; AC_DEFINE(INET6, 1, [true if you have IPv6]) ]) ;; kame) # http://www.kame.net/ AC_EGREP_CPP(yes, [ #include #ifdef __KAME__ yes #endif], [ipv6type=$i; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; linux-glibc) # http://www.v6.linux.or.jp/ AC_EGREP_CPP(yes, [ #include #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif], [ipv6type=$i; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; linux-inet6) # http://www.v6.linux.or.jp/ if test -d /usr/inet6 -o -f /usr/inet6/lib/libinet6.a; then ipv6type=$i ipv6lib=inet6 ipv6libdir=/usr/inet6/lib ipv6trylibc=yes; AC_DEFINE(INET6, 1, [true if you have IPv6]) CFLAGS="-I/usr/inet6/include $CFLAGS" fi ;; solaris) # http://www.sun.com AC_EGREP_CPP(yes, [ #include #ifdef __sun yes #endif], [ipv6type=$i; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; toshiba) AC_EGREP_CPP(yes, [ #include #ifdef _TOSHIBA_INET6 yes #endif], [ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; v6d) AC_EGREP_CPP(yes, [ #include #ifdef __V6D__ yes #endif], [ipv6type=$i; ipv6lib=v6; ipv6libdir=/usr/local/v6/lib; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; zeta) AC_EGREP_CPP(yes, [ #include #ifdef _ZETA_MINAMI_INET6 yes #endif], [ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; cygwin) AC_EGREP_CPP(yes, [ #include #ifdef _CYGWIN_IN6_H yes #endif], [ipv6type=$i; AC_DEFINE(INET6, 1, [true if you have IPv6])]) ;; esac if test "$ipv6type" != "unknown"; then break fi done AC_MSG_RESULT($ipv6type) AC_SEARCH_LIBS(getaddrinfo, inet6) fi dnl Do you want to disable use of locale functions AC_ARG_ENABLE([locale], AS_HELP_STRING([--disable-locale],[disable 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_C_BIGENDIAN AC_HEADER_DIRENT AC_HEADER_TIME 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 grp.h compat.h sys/param.h ctype.h sys/wait.h \ sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \ sys/un.h sys/attr.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \ netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \ sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \ popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netinet/ip.h \ zlib.h) AC_HEADER_MAJOR AC_CACHE_CHECK([if makedev takes 3 args],rsync_cv_MAKEDEV_TAKES_3_ARGS,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #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) exit(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_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]) AC_TYPE_GETGROUPS AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_mtimensec, 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([[ #include #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 -e '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], [#include #include ]) # 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, [ #include #include #include #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" -a 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([[#include #include #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?]) ], [], [ #include #include ]) AC_CHECK_MEMBER([struct sockaddr_in.sin_len], [ AC_DEFINE(HAVE_SOCKADDR_IN_LEN, 1, [Do we have sockaddr_in.sin_len?]) ], [], [ #include #include #include ]) AC_CHECK_MEMBER([struct sockaddr_un.sun_len], [ AC_DEFINE(HAVE_SOCKADDR_UN_LEN, 1, [Do we have sockaddr_un.sun_len?]) ], [], [ #include #include #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?]) ], [], [ #include #include #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 strdup chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ strlcat strlcpy strtol mallinfo 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 usleep) 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 #include ]], [[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_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[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 all use of iconv_open() function]), [], [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 rsync's --iconv option]), [], [enable_iconv=$enable_iconv_open]) AH_TEMPLATE([ICONV_OPTION], [Define if you want the --iconv option. Specifing 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 main() { 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) exit(1); exit(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([[ #if HAVE_UNISTD_H # include #endif #include #include #define FILENAME "conftest.dangle" main() { unlink(FILENAME); if (symlink("conftest.no-such", FILENAME) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) exit(1); exit(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 #include #include #define FILENAME "conftest.fifi" main() { unlink(FILENAME); if (mkfifo(FILENAME, 0777) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) exit(1); exit(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([[ #include #include main() { int fd[2]; exit((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 not using our zlib unless --with-included-zlib=yes is given. if test x"$with_included_zlib" != x"yes"; then with_included_zlib=no fi if 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 = ""]])],[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([[#include #include main() { 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) exit(0); exit(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([[#include #include ]], [[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(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 #include ]], [[struct timeval tv; exit(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([[ #include #include void foo(const char *format, ...) { va_list ap; int len; char buf[5]; 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); exit(0); } main() { foo("hello"); } ]])],[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 #include #include #include main() { struct stat st; char tpl[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); if (fd == -1) exit(1); unlink(tpl); if (fstat(fd, &st) != 0) exit(1); if ((st.st_mode & 0777) != 0600) exit(1); exit(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 main() { 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 main() { 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 < #include ]], [[ 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([[#include #include ]], [[ 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 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*) 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" -o x"$enable_xattr_support" = x"no" -o 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_bpc ${RSYNC_VERSION} configuration successful]) AC_MSG_RESULT() if test x$HAVE_YODL2MAN != x1; then AC_MSG_RESULT([ Note that yodl2man was not found, so pre-existing manpage files will be]) AC_MSG_RESULT([ used w/o change (if available) -- no .yo file changes will be used.]) AC_MSG_RESULT() fi rsync-bpc-3.1.2.1/uidlist.c0000664000047500004750000003242213510756407014354 0ustar craigcraig/* * 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-2015 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 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 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); if (!node) out_of_memory("add_to_list"); 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 */ char *uid_to_user(uid_t uid) { struct passwd *pass = getpwuid(uid); if (pass) return strdup(pass->pw_name); return NULL; } /* turn a gid into a group name */ char *gid_to_group(gid_t gid) { struct group *grp = getgrgid(gid); if (grp) return strdup(grp->gr_name); return NULL; } /* 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) { struct passwd *pass; if (!name || !*name) return 0; if (num_ok && name[strspn(name, "0123456789")] == '\0') { *uid_p = id_parse(name); return 1; } if (!(pass = getpwnam(name))) 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) { struct group *grp; if (!name || !*name) return 0; if (num_ok && name[strspn(name, "0123456789")] == '\0') { *gid_p = id_parse(name); return 1; } if (!(grp = getgrnam(name))) 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 (!gidset) out_of_memory("is_in_group"); 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 (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); if (!gidbuf) out_of_memory("is_in_group"); 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 (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) ? uid : id; } else { gid_t gid; id2 = group_to_gid(name, &gid, False) ? 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 definate candidate for a faster algorithm */ uid_t match_uid(uid_t uid) { static struct idlist *last = NULL; struct idlist *list; if (last && uid == last->id) return last->id2; for (list = uidlist; list; list = list->next) { if (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 && gid == last->id) list = last; else { for (list = gidlist; list; list = list->next) { if (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; if (uid == 0) /* don't map root */ return NULL; for (list = uidlist; list; list = list->next) { if (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; if (gid == 0) /* don't map root */ return NULL; for (list = gidlist; list; list = list->next) { if (list->id == gid) return NULL; } noiu.name = gid_to_group(gid); node = add_to_list(&gidlist, gid, noiu, 0, 0); return node->u.name; } /* send a complete uid/gid mapping to the peer */ void send_id_list(int f) { struct idlist *list; if (preserve_uid || preserve_acls) { int len; /* we send sequences of uid/byte-length/name */ for (list = uidlist; list; list = list->next) { if (!list->u.name) continue; len = strlen(list->u.name); write_varint30(f, list->id); write_byte(f, len); write_buf(f, list->u.name, len); } /* terminate the uid list with a 0 uid. We explicitly exclude * 0 from the list */ write_varint30(f, 0); } if (preserve_gid || preserve_acls) { int len; for (list = gidlist; list; list = list->next) { if (!list->u.name) continue; len = strlen(list->u.name); write_varint30(f, list->id); write_byte(f, len); write_buf(f, list->u.name, len); } write_varint30(f, 0); } } uid_t recv_user_name(int f, uid_t uid) { struct idlist *node; int len = read_byte(f); char *name = new_array(char, len+1); if (!name) out_of_memory("recv_user_name"); read_sbuf(f, name, len); if (numeric_ids < 0) { free(name); 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 = new_array(char, len+1); if (!name) out_of_memory("recv_group_name"); read_sbuf(f, name, len); if (numeric_ids < 0) { free(name); 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 ((preserve_gid || preserve_acls) && numeric_ids <= 0) { /* read the gid list */ while ((id = read_varint30(f)) != 0) recv_group_name(f, id, 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 */ } /* The 0 user/group doesn't get its name sent, so add it explicitly. */ recv_add_id(idlist_ptr, *idmap_ptr, 0, numeric_ids ? NULL : usernames ? uid_to_user(0) : gid_to_group(0)); } #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 */ 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; 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! */ 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-bpc-3.1.2.1/shconfig.in0000775000047500004750000000055013510756401014655 0ustar craigcraig#! /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-bpc-3.1.2.1/progress.c0000664000047500004750000001341413510756407014543 0ustar craigcraig/* * 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-2015 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 need_unsorted_flist; extern int output_needs_newline; extern struct stats stats; extern struct file_list *cur_flist; #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) strlcpy(rembuf, " ??:??:??", sizeof rembuf); else { snprintf(rembuf, sizeof rembuf, "%4d:%02d:%02d", (int) (remain / 3600.0), (int) (remain / 60.0) % 60, (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) { output_needs_newline = 1; rflush(FCLIENT); } } 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 end_progress(OFF_T size) { if (!am_server) { struct timeval now; gettimeofday(&now, NULL); if (INFO_GTE(PROGRESS, 2)) { 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-bpc-3.1.2.1/cleanup.c0000664000047500004750000001704413510756407014331 0ustar craigcraig/* * End-of-run cleanup routines. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2015 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_generator; 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; 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, file, line); } /* FALLTHROUGH */ #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; } } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (cleanup_got_literal && (cleanup_fname || cleanup_fd_w != -1)) { if (cleanup_fd_r != -1) { bpc_close(cleanup_fd_r); cleanup_fd_r = -1; } if (cleanup_fd_w != -1) { flush_write_file(cleanup_fd_w); bpc_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); } } /* FALLTHROUGH */ #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); /* FALLTHROUGH */ #include "case_N.h" switch_step++; bpc_sysCall_cleanup(); 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); /* FALLTHROUGH */ #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)" : ""); } /* FALLTHROUGH */ #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 && (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); } noop_io_until_death(); } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (am_server && exit_code) msleep(100); close_all(); /* FALLTHROUGH */ default: break; } 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-bpc-3.1.2.1/COPYING0000664000047500004750000010451313510756401013561 0ustar craigcraig 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-bpc-3.1.2.1/rsyncd.conf.yo0000664000047500004750000013162013510756407015332 0ustar craigcraigmailto(rsync-bugs@samba.org) manpage(rsyncd.conf)(5)(21 Dec 2015)()() manpagename(rsyncd.conf)(configuration file for rsync in daemon mode) manpagesynopsis() rsyncd.conf manpagedescription() 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. manpagesection(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 bf(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. manpagesection(LAUNCHING THE RSYNC DAEMON) The rsync daemon is launched by specifying the bf(--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 "bf(rsync --daemon)" from a suitable startup script. When run via inetd you should add a line like this to /etc/services: verb( rsync 873/tcp) and a single line something like this to /etc/inetd.conf: verb( 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 bf(not) send the rsync daemon a HUP signal to force it to reread the tt(rsyncd.conf) file. The file is re-read on each client connection. manpagesection(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 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 %%. startdit() dit(bf(motd file)) This parameter allows you to specify a "message of the day" 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 bf(--dparam=motdfile=FILE) command-line option when starting the daemon. dit(bf(pid file)) This parameter tells the rsync daemon to write its process ID to that file. If the file already exists, the rsync daemon will abort rather than overwrite the file. This can be overridden by the bf(--dparam=pidfile=FILE) command-line option when starting the daemon. dit(bf(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 bf(--port) command-line option. dit(bf(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 bf(--address) command-line option. dit(bf(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 man page for the code(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 bf(--sockopts) command-line option. dit(bf(listen backlog)) You can override the default backlog value when the daemon listens for connections. It defaults to 5. enddit() manpagesection(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. startdit() dit(bf(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. dit(bf(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 tt(rsyncd.conf). 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: verb( 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. dit(bf(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). As an additional safety feature, you can specify a dot-dir in the module's "path" to indicate the point where the chroot should occur. This allows rsync to run in a chroot with a non-"/" path for the top of the transfer hierarchy. Doing this guards against unintended library loading (since those absolute paths will not be inside the transfer hierarchy unless you have used an unwise pathname), and lets you setup libraries for the chroot that are outside of the transfer. For example, specifying "/var/rsync/./module1" will chroot to the "/var/rsync" directory and set the inside-chroot path to "/module1". If you had omitted the dot-dir, the chroot would have used the whole path, and the inside-chroot path would have been "/". When "use chroot" is false or the inside-chroot path is not "/", rsync will: (1) munge symlinks by default for security reasons (see "munge symlinks" for a way to turn this off, but only if you trust your users), (2) substitute leading slashes in absolute paths with the module's path (so that options such as bf(--backup-dir), bf(--compare-dest), etc. interpret an absolute path as rooted in the module's "path" dir), and (3) trim ".." path elements from args if rsync believes they would escape the module hierarchy. The default for "use chroot" is true, and is the safer choice (especially if the module is not read-only). When this parameter is enabled, the "numeric-ids" option will also default to being enabled (disabling name lookups). See below for what a chroot needs in order for name lookups to succeed. 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). At that point it will be safe to enable the mapping of users and groups by name using this "numeric ids" daemon parameter. Note also that you are free to setup custom user/group information in the chroot area that is different from your normal system. For example, you could abbreviate the list of users and groups. dit(bf(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 bf(--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 enabled unless 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. That includes being the code being able to call functions like code(getpwuid()), code(getgrgid()), code(getpwname()), and code(getgrnam())). You should test what libraries and config files are required for your OS and get those setup before starting to test name mapping in rsync. dit(bf(munge symlinks)) This parameter tells rsync to modify all symlinks in the same way as the (non-daemon-affecting) bf(--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 and the inside-chroot path is "/", 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. dit(bf(charset)) This specifies the name of the character set in which the module's filenames are stored. If the client uses an bf(--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 bf(--iconv) option is refused, just as if "iconv" had been specified via "refuse options". If you wish to force users to always use bf(--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. dit(bf(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. dit(bf(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 code(syslog()) doesn't work for chrooted programs. The file is opened before code(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 bf(--log-file=FILE) or bf(--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. dit(bf(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). dit(bf(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 bf(--info) and bf(--debug) logging. If the max value is 2, then no info and/or debug value that is higher than what would be set by bf(-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. dit(bf(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 tt(/var/run/rsyncd.lock). dit(bf(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. dit(bf(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. dit(bf(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. dit(bf(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: verb( uid = %RSYNC_USER_NAME% gid = * ) dit(bf(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). dit(bf(fake super)) Setting "fake super = yes" for a module causes the daemon side to behave as if the bf(--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. dit(bf(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 (bf(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 em(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 bf(--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. dit(bf(exclude)) This parameter takes a space-separated list of daemon exclude patterns. As with the client bf(--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. dit(bf(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. dit(bf(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. dit(bf(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. dit(bf(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 bf(--perms). See the description of the bf(--chmod) rsync option and the bf(chmod)(1) manpage for information on the format of this string. dit(bf(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 bf(--chmod) rsync option and the bf(chmod)(1) manpage for information on the format of this string. dit(bf(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: verb( 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. 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 bf(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. dit(bf(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 tt(/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 a "user auth" module will be possible. dit(bf(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. dit(bf(hosts allow)) This parameter allows you to specify a list of patterns that are matched against a connecting clients hostname and IP address. If none of the patterns match then the connection is rejected. Each pattern can be in one of five forms: quote(itemization( it() 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. it() 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. it() 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. it() 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). it() 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. )) Note IPv6 link-local addresses can have a scope in the address specification: quote( tt( fe80::1%link1)nl() tt( fe80::%link1/64)nl() tt( fe80::%link1/ffff:ffff:ffff:ffff::)nl() ) You can also combine "hosts allow" with a separate "hosts deny" parameter. If both parameters are specified then the "hosts allow" parameter is checked first and a match results in the client being able to connect. The "hosts deny" parameter is then checked and a match means that the host is rejected. If the host does not match either the "hosts allow" or the "hosts deny" patterns then it is allowed to connect. The default is no "hosts allow" parameter, which means all hosts can connect. dit(bf(hosts deny)) This parameter allows you to specify a list of 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. dit(bf(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. dit(bf(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. dit(bf(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 bf(--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. dit(bf(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. dit(bf(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. dit(bf(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. "bf(%-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 bf(--human-readable) command-line option, though the default is for human-readability to be off. Each added apostrophe increases the level (e.g. "bf(%''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: quote(itemization( it() %a the remote IP address (only available for a daemon) it() %b the number of bytes actually transferred it() %B the permission bits of the file (e.g. rwxrwxrwt) it() %c the total size of the block checksums received for the basis file (only when sending) it() %C the full-file MD5 checksum if bf(--checksum) is enabled or a file was transferred (only for protocol 30 or above). it() %f the filename (long form on sender; no trailing "/") it() %G the gid of the file (decimal) or "DEFAULT" it() %h the remote host name (only available for a daemon) it() %i an itemized list of what is being updated it() %l the length of the file in bytes it() %L the string " -> SYMLINK", " => HARDLINK", or "" (where bf(SYMLINK) or bf(HARDLINK) is a filename) it() %m the module name it() %M the last-modified time of the file it() %n the filename (short form; trailing "/" on dir) it() %o the operation, which is "send", "recv", or "del." (the latter includes the trailing period) it() %p the process ID of this rsync session it() %P the module path it() %t the current date time it() %u the authenticated username or an empty string it() %U the uid of the file (decimal) )) For a list of what the characters mean that are output by "%i", see the bf(--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. dit(bf(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). dit(bf(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. For example, this would refuse bf(--checksum) (bf(-c)) and all the various delete options: quote(tt( refuse options = c delete)) The reason the above refuses all delete options is that the options imply bf(--delete), and implied options are refused just like explicit options. As an additional safety feature, the refusal of "delete" also refuses bf(remove-source-files) when the daemon is the sender; if you want the latter without the former, instead refuse "delete-*" -- that refuses all the delete modes without affecting bf(--remove-source-files). When an option is refused, the daemon prints an error message and exits. To prevent all compression when serving files, you can use "dont compress = *" (see below) instead of "refuse options = compress" to avoid returning an error to a client that requests compression. dit(bf(dont compress)) 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 is 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 not be compressed during transfer. See the bf(--skip-compress) parameter in the bf(rsync)(1) manpage for the list of file suffixes that are not compressed by default. Specifying a value for the "dont compress" parameter changes the default when the daemon is the sender. dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run before and/or after the transfer. If the bf(pre-xfer exec) command fails, the transfer is aborted before it begins. Any output from the script on stdout (up to several KB) will be displayed to the user when aborting, but is NOT displayed if the script returns success. Any output from the script on stderr goes to the daemon's stderr, which is typically discarded (though see --no-detatch option for a way to see the stderr output, which can assist with debugging). The following environment variables will be set, though some are specific to the pre-xfer or the post-xfer environment: quote(itemization( it() bf(RSYNC_MODULE_NAME): The name of the module being accessed. it() bf(RSYNC_MODULE_PATH): The path configured for the module. it() bf(RSYNC_HOST_ADDR): The accessing host's IP address. it() bf(RSYNC_HOST_NAME): The accessing host's name. it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user). it() bf(RSYNC_PID): A unique number for this transfer. it() bf(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. it() bf(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. it() bf(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. it() bf(RSYNC_RAW_STATUS): (post-xfer only) the raw exit value from code(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. enddit() manpagesection(CONFIG DIRECTIVES) There are currently two config directives available that allow a config file to incorporate the contents of other files: bf(&include) and bf(&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 bf(&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 bf(&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 bf(&include) or bf(&merge) directive refers to a directory, it will read in all the bf(*.conf) or bf(*.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: verb( &include /path/rsyncd.d ) would be the same as this set of directives: verb( &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 bf(&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 bf(&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 bf(motd file)), or globals that will affect other include files. For example, this is a useful /etc/rsyncd.conf file: verb( 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). manpagesection(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. Future versions of rsync may support SSL for better authentication and encryption, but that is still being investigated. manpagesection(EXAMPLES) A simple rsyncd.conf file that allow anonymous rsync to a ftp area at tt(/home/ftp) would be: verb( [ftp] path = /home/ftp comment = ftp export area ) A more sophisticated example would be: verb( 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: quote( tt(tridge:mypass)nl() tt(susan:herpass)nl() ) manpagefiles() /etc/rsyncd.conf or rsyncd.conf manpageseealso() bf(rsync)(1) manpagediagnostics() manpagebugs() Please report bugs! The rsync bug tracking system is online at url(http://rsync.samba.org/)(http://rsync.samba.org/) manpagesection(VERSION) This man page is current for version 3.1.2 of rsync. manpagesection(CREDITS) rsync is distributed under the GNU General Public License. See the file COPYING for details. The primary ftp site for rsync is url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/rsync). A WEB site is available at url(http://rsync.samba.org/)(http://rsync.samba.org/) We would be delighted to hear from you if you like this program. This program uses the zlib compression library written by Jean-loup Gailly and Mark Adler. manpagesection(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! manpageauthor() rsync was written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. Mailing lists for support and development are available at url(http://lists.samba.org)(lists.samba.org) rsync-bpc-3.1.2.1/popt/0000775000047500004750000000000013510756401013504 5ustar craigcraigrsync-bpc-3.1.2.1/popt/COPYING0000664000047500004750000000237513510756401014546 0ustar craigcraigCopyright (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-bpc-3.1.2.1/popt/findme.h0000664000047500004750000000077013510756401015123 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/dummy.in0000664000047500004750000000000013510756401015155 0ustar craigcraigrsync-bpc-3.1.2.1/popt/popthelp.c0000664000047500004750000005411113510756401015505 0ustar craigcraig/* -*- 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-bpc-3.1.2.1/popt/poptparse.c0000664000047500004750000001233713510756401015673 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/findme.c0000664000047500004750000000242413510756401015114 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/poptconfig.c0000664000047500004750000001075213510756401016025 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/README.rsync0000664000047500004750000000044613510756401015525 0ustar craigcraigThis 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-bpc-3.1.2.1/popt/popt.c0000664000047500004750000010517213510756401014640 0ustar craigcraig/** \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; strncpy(te, a, alen); 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-bpc-3.1.2.1/popt/CHANGES0000664000047500004750000000244113510756401014500 0ustar craigcraig1.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-bpc-3.1.2.1/popt/README0000664000047500004750000000152613510756401014370 0ustar craigcraigThis is the popt command line option parsing library. While it is similar 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 (available from Addison Wesley in May, 1998). Comments on popt should be addressed to ewt@redhat.com. rsync-bpc-3.1.2.1/popt/poptint.h0000664000047500004750000000550013510756401015352 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/popt.h0000664000047500004750000003767213510756401014656 0ustar craigcraig/** \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-bpc-3.1.2.1/popt/system.h0000664000047500004750000000510413510756401015201 0ustar craigcraig#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 #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-bpc-3.1.2.1/proto.h-tstamp0000664000047500004750000000000013510756401015332 0ustar craigcraigrsync-bpc-3.1.2.1/tweak_manpage0000775000047500004750000000111013510756401015244 0ustar craigcraig#!/usr/bin/perl -i -p use strict; use warnings; # We only need to use "\&'" or "\&." at the start of a line. s/(?<=.)\\\&(['.])/$1/g; # Some quotes turn into open/close quotes. s/'(.)'/\\(oq$1\\(cq/g; s/(^|[ (])"(?!( |$))/$1\\(lq/gm; s/(? 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 http://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. -- -- http://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-bpc-3.1.2.1/install-sh0000775000047500004750000001124513510756401014531 0ustar craigcraig#! /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 -o -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-bpc-3.1.2.1/wildtest.txt0000664000047500004750000001021113510756401015115 0ustar craigcraig# 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-bpc-3.1.2.1/errcode.h0000664000047500004750000000541613510756407014332 0ustar craigcraig/* * Error codes returned by rsync. * * Copyright (C) 1998-2000 Andrew Tridgell * Copyright (C) 2003-2015 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-bpc-3.1.2.1/syscall.c0000664000047500004750000001701113510756407014346 0ustar craigcraig/* * 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-2015 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 preserve_perms; extern int preserve_executability; #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 *fname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return bpc_unlink(fname); } #ifdef SUPPORT_LINKS int do_symlink(const char *lnk, const char *fname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return bpc_symlink(lnk, fname); } #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS ssize_t do_readlink(const char *path, char *buf, size_t bufsiz) { return bpc_readlink(path, buf, bufsiz); } #endif #endif #ifdef HAVE_LINK int do_link(const char *fname1, const char *fname2) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return bpc_link(fname1, fname2); } #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 bpc_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; return bpc_mknod(pathname, mode, dev); } int do_rmdir(const char *pathname) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return bpc_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; } return bpc_open(pathname, flags | O_BINARY, mode); } #ifdef HAVE_CHMOD int do_chmod(const char *path, mode_t mode) { int code; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; #ifdef HAVE_LCHMOD code = bpc_lchmod(path, mode & CHMOD_BITS); #else 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; code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW); # else code = 1; # endif } else code = bpc_chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */ #endif /* !HAVE_LCHMOD */ if (code != 0 && (preserve_perms || preserve_executability)) return code; return 0; } #endif int do_rename(const char *fname1, const char *fname2) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; return bpc_rename(fname1, fname2); } #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 = bpc_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 *fname, mode_t mode) { if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; trim_trailing_slashes(fname); return bpc_mkdir(fname, mode); } /* like mkstemp but forces permissions */ int do_mkstemp(char *template, mode_t perms, char *origFileName) { 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 = bpc_mkstemp(template, origFileName); if (fd == -1) return -1; #if defined HAVE_SETMODE && O_BINARY setmode(fd, O_BINARY); #endif return fd; } #else if (!bpc_mktemp(template)) return -1; return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms); #endif } int do_stat(const char *fname, STRUCT_STAT *st) { return bpc_stat(fname, st); } int do_lstat(const char *fname, STRUCT_STAT *st) { return bpc_lstat(fname, st); } int do_fstat(int fd, STRUCT_STAT *st) { return bpc_fstat(fd, st); } OFF_T do_lseek(int fd, OFF_T offset, int whence) { return bpc_lseek(fd, offset, whence); } #ifdef HAVE_LUTIMES int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) { struct timeval t[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; t[0].tv_sec = time(NULL); t[0].tv_usec = 0; t[1].tv_sec = modtime; t[1].tv_usec = mod_nsec / 1000; return bpc_lutimes(fname, t); } #endif #ifdef HAVE_UTIMES int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) { struct timeval t[2]; if (dry_run) return 0; RETURN_ERROR_IF_RO_OR_LO; t[0].tv_sec = time(NULL); t[0].tv_usec = 0; t[1].tv_sec = modtime; t[1].tv_usec = mod_nsec / 1000; return bpc_utimes(fname, t); } #elif defined HAVE_UTIME int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) { return bpc_utime(fname, modtime); } #else #error Need utimes or utime function. #endif #ifdef SUPPORT_PREALLOCATION int do_fallocate(int fd, OFF_T offset, OFF_T length) { #ifdef FALLOC_FL_KEEP_SIZE #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE #else #define DO_FALLOC_OPTIONS 0 #endif RETURN_ERROR_IF(dry_run, 0); RETURN_ERROR_IF_RO_OR_LO; #if defined HAVE_FALLOCATE return fallocate(fd, DO_FALLOC_OPTIONS, offset, length); #elif defined HAVE_SYS_FALLOCATE return syscall(SYS_fallocate, fd, DO_FALLOC_OPTIONS, (loff_t)offset, (loff_t)length); #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE return posix_fallocate(fd, offset, length); #else #error Coding error in SUPPORT_PREALLOCATION logic. #endif } #endif 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-bpc-3.1.2.1/pipe.c0000664000047500004750000001215613510756407013636 0ustar craigcraig/* * 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-2015 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-bpc-3.1.2.1/rsyncd.conf.50000664000047500004750000013716013510756407015054 0ustar craigcraig.TH "rsyncd.conf" "5" "21 Dec 2015" "" "" .SH "NAME" rsyncd.conf \- configuration file for rsync in daemon mode .SH "SYNOPSIS" .PP rsyncd.conf .PP .SH "DESCRIPTION" .PP The rsyncd.conf file is the runtime configuration file for rsync when run as an rsync daemon. .PP The rsyncd.conf file controls authentication, access, logging and available modules. .PP .SH "FILE FORMAT" .PP 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 \(dq\&name = value\(dq\&. .PP The file is line\-based \-\- that is, each newline\-terminated line represents either a comment, a module name or a parameter. .PP 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. .PP Any line \fBbeginning\fP 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\(cq\&s content.) .PP Any line ending in a \e is \(dq\&continued\(dq\& on the next line in the customary UNIX fashion. .PP 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. .PP .SH "LAUNCHING THE RSYNC DAEMON" .PP The rsync daemon is launched by specifying the \fB\-\-daemon\fP option to rsync. .PP 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. .PP 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 \(dq\&\fBrsync \-\-daemon\fP\(dq\& from a suitable startup script. .PP When run via inetd you should add a line like this to /etc/services: .PP .nf rsync 873/tcp .fi .PP and a single line something like this to /etc/inetd.conf: .PP .nf rsync stream tcp nowait root /usr/bin/rsync rsyncd \-\-daemon .fi .PP Replace \(dq\&/usr/bin/rsync\(dq\& 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. .PP Note that you should \fBnot\fP send the rsync daemon a HUP signal to force it to reread the \f(CWrsyncd.conf\fP file. The file is re\-read on each client connection. .PP .SH "GLOBAL PARAMETERS" .PP The first parameters in the file (before a [module] header) are the global parameters. Rsync also allows for the use of a \(dq\&[global]\(dq\& module name to indicate the start of one or more global\-parameter sections (the name must be lower case). .PP 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. .PP 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 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 %%. .PP .IP "\fBmotd file\fP" This parameter allows you to specify a \(dq\&message of the day\(dq\& 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 .IP "\fBpid file\fP" This parameter tells the rsync daemon to write its process ID to that file. If the file already exists, the rsync daemon will abort rather than overwrite the file. This can be overridden by the \fB\-\-dparam=pidfile=FILE\fP command\-line option when starting the daemon. .IP .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 .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 .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 man page for the \f(CWsetsockopt()\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 .IP "\fBlisten backlog\fP" You can override the default backlog value when the daemon listens for connections. It defaults to 5. .IP .SH "MODULE PARAMETERS" .PP 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 \(dq\&global\(dq\& as that exact name indicates that global parameters follow (see above). .PP As with GLOBAL PARAMETERS, you may use references to environment variables in the values of parameters. See the GLOBAL PARAMETERS section for more details. .PP .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 .IP "\fBpath\fP" This parameter specifies the directory in the daemon\(cq\&s filesystem to make available in this module. You must specify this parameter for each module in \f(CWrsyncd.conf\fP. .IP You may base the path\(cq\&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\(cq\&s name in the path: .IP .nf path = /home/%RSYNC_USER_NAME% .fi .IP It is fine if the path includes internal spaces \-\- they will be retained verbatim (which means that you shouldn\(cq\&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 .IP "\fBuse chroot\fP" If \(dq\&use chroot\(dq\& is true, the rsync daemon will chroot to the \(dq\&path\(dq\& 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 As an additional safety feature, you can specify a dot\-dir in the module\(cq\&s \(dq\&path\(dq\& to indicate the point where the chroot should occur. This allows rsync to run in a chroot with a non\-\(dq\&/\(dq\& path for the top of the transfer hierarchy. Doing this guards against unintended library loading (since those absolute paths will not be inside the transfer hierarchy unless you have used an unwise pathname), and lets you setup libraries for the chroot that are outside of the transfer. For example, specifying \(dq\&/var/rsync/./module1\(dq\& will chroot to the \(dq\&/var/rsync\(dq\& directory and set the inside\-chroot path to \(dq\&/module1\(dq\&. If you had omitted the dot\-dir, the chroot would have used the whole path, and the inside\-chroot path would have been \(dq\&/\(dq\&. .IP When \(dq\&use chroot\(dq\& is false or the inside\-chroot path is not \(dq\&/\(dq\&, rsync will: (1) munge symlinks by default for security reasons (see \(dq\&munge symlinks\(dq\& for a way to turn this off, but only if you trust your users), (2) substitute leading slashes in absolute paths with the module\(cq\&s path (so that options such as \fB\-\-backup\-dir\fP, \fB\-\-compare\-dest\fP, etc. interpret an absolute path as rooted in the module\(cq\&s \(dq\&path\(dq\& dir), and (3) trim \(dq\&..\(dq\& path elements from args if rsync believes they would escape the module hierarchy. The default for \(dq\&use chroot\(dq\& is true, and is the safer choice (especially if the module is not read\-only). .IP When this parameter is enabled, the \(dq\&numeric\-ids\(dq\& option will also default to being enabled (disabling name lookups). See below for what a chroot needs in order for name lookups to succeed. .IP If you copy library resources into the module\(cq\&s chroot area, you should protect them through your OS\(cq\&s normal user/group or ACL settings (to prevent the rsync module\(cq\&s user from being able to change them), and then hide them from the user\(cq\&s view via \(dq\&exclude\(dq\& (see how in the discussion of that parameter). At that point it will be safe to enable the mapping of users and groups by name using this \(dq\&numeric ids\(dq\& daemon parameter. .IP Note also that you are free to setup custom user/group information in the chroot area that is different from your normal system. For example, you could abbreviate the list of users and groups. .IP .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 \(dq\&uid\(dq\&) or for \(dq\&fake super\(dq\& to be configured. .IP A chroot\-enabled module should not have this parameter enabled unless you\(cq\&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. That includes being the code being able to call functions like \f(CWgetpwuid()\fP , \f(CWgetgrgid()\fP , \f(CWgetpwname()\fP , and \f(CWgetgrnam()\fP ). You should test what libraries and config files are required for your OS and get those setup before starting to test name mapping in rsync. .IP .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 \(dq\&use chroot\(dq\& is on and the inside\-chroot path is \(dq\&/\(dq\&, 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 \(dq\&use chroot\(dq\& is off, rsync can even be tricked into showing or changing data that is outside the module\(cq\&s path (as access\-permissions allow). .IP The way rsync disables the use of symlinks is to prefix each one with the string \(dq\&/rsyncd\-munged/\(dq\&. 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 \(dq\&munge symlinks\(dq\& parameter in a chroot area that has an inside\-chroot path of \(dq\&/\(dq\&, you should add \(dq\&/rsyncd\-munged/\(dq\& to the exclude setting for the module so that a user can\(cq\&t try to create it. .IP Note: rsync makes no attempt to verify that any pre\-existing symlinks in the module\(cq\&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 \(dq\&/rsyncd\-munged/\(dq\& to the start of every symlink\(cq\&s value. There is a perl script in the support directory of the source code named \(dq\&munge\-symlinks\(dq\& that can be used to add or remove this prefix from your symlinks. .IP When this parameter is disabled on a writable module and \(dq\&use chroot\(dq\& is off (or the inside\-chroot path is not \(dq\&/\(dq\&), incoming symlinks will be modified to drop a leading slash and to remove \(dq\&..\(dq\& path elements that rsync believes will allow a symlink to escape the module\(cq\&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 .IP "\fBcharset\fP" This specifies the name of the character set in which the module\(cq\&s filenames are stored. If the client uses an \fB\-\-iconv\fP option, the daemon will use the value of the \(dq\&charset\(dq\& 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 \(dq\&charset\(dq\& parameter is not set, the \fB\-\-iconv\fP option is refused, just as if \(dq\&iconv\(dq\& had been specified via \(dq\&refuse options\(dq\&. .IP If you wish to force users to always use \fB\-\-iconv\fP for a particular module, add \(dq\&no\-iconv\(dq\& to the \(dq\&refuse options\(dq\& parameter. Keep in mind that this will restrict access to your module to very new rsync clients. .IP .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 \(dq\&lock file\(dq\& parameter. .IP .IP "\fBlog file\fP" When the \(dq\&log file\(dq\& 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 \f(CWsyslog()\fP doesn\(cq\&t work for chrooted programs. The file is opened before \f(CWchroot()\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\(cq\&s log file and the default for all the modules, which still allows modules to override the default setting. .IP .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 \(dq\&log file\(dq\& setting is a non\-empty string (either set in the per\-modules settings, or inherited from the global settings). .IP .IP "\fBmax verbosity\fP" This parameter allows you to control the maximum amount of verbose information that you\(cq\&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\(cq\&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 \(dq\&rsync \-\-info=help\(dq\& and \(dq\&rsync \-\-debug=help\(dq\&. For instance, it takes max\-verbosity 4 to be able to output debug TIME2 and FLIST3. .IP .IP "\fBlock file\fP" This parameter specifies the file to use to support the \(dq\&max connections\(dq\& 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 \f(CW/var/run/rsyncd.lock\fP. .IP .IP "\fBread only\fP" This parameter determines whether clients will be able to upload files or not. If \(dq\&read only\(dq\& is true then any attempted uploads will fail. If \(dq\&read only\(dq\& 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 \(dq\&auth users\(dq\& can override this setting on a per\-user basis. .IP .IP "\fBwrite only\fP" This parameter determines whether clients will be able to download files or not. If \(dq\&write only\(dq\& is true then any attempted downloads will fail. If \(dq\&write only\(dq\& 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 .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 \(dq\&hosts allow\(dq\& or \(dq\&hosts deny\(dq\& attempts to access it. Realize that if \(dq\&reverse lookup\(dq\& 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 .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 \(dq\&gid\(dq\& parameter this determines what file permissions are available. The default when run by a super\-user is to switch to the system\(cq\&s \(dq\&nobody\(dq\& user. The default for a non\-super\-user is to not try to change the user. See also the \(dq\&gid\(dq\& 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: .IP .nf uid = %RSYNC_USER_NAME% gid = * .fi .IP .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 \(dq\&*\(dq\& as the first gid in the list, which will be replaced by all the normal groups for the transfer\(cq\&s user (see \(dq\&uid\(dq\&). The default when run by a super\-user is to switch to your OS\(cq\&s \(dq\&nobody\(dq\& (or perhaps \(dq\&nogroup\(dq\&) 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 .IP "\fBfake super\fP" Setting \(dq\&fake super = yes\(dq\& 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 .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 \(dq\&filter\(dq\&, \(dq\&include from\(dq\&, \(dq\&include\(dq\&, \(dq\&exclude from\(dq\&, and \(dq\&exclude\(dq\& 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, \(dq\&/secret\(dq\&, you \fImust\fP exclude everything in the subtree; the easiest way to do this is with a triple\-star pattern like \(dq\&/secret/***\(dq\&. .IP The \(dq\&filter\(dq\& 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. \(dq\&\- /foo \- /bar\(dq\& is parsed as two rules). You may specify one or more merge\-file rules using the normal syntax. Only one \(dq\&filter\(dq\& 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 .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 \(dq\&\- \(dq\& or \(dq\&+ \(dq\& to explicitly indicate exclude/include. Only one \(dq\&exclude\(dq\& parameter can apply to a given module. See the \(dq\&filter\(dq\& parameter for a description of how excluded files affect the daemon. .IP .IP "\fBinclude\fP" Use an \(dq\&include\(dq\& to override the effects of the \(dq\&exclude\(dq\& parameter. Only one \(dq\&include\(dq\& parameter can apply to a given module. See the \(dq\&filter\(dq\& parameter for a description of how excluded files affect the daemon. .IP .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 \(dq\&exclude from\(dq\& parameter can apply to a given module; if you have multiple exclude\-from files, you can specify them as a merge file in the \(dq\&filter\(dq\& parameter. See the \(dq\&filter\(dq\& parameter for a description of how excluded files affect the daemon. .IP .IP "\fBinclude from\fP" Analogue of \(dq\&exclude from\(dq\& for a file of daemon include patterns. Only one \(dq\&include from\(dq\& parameter can apply to a given module. See the \(dq\&filter\(dq\& parameter for a description of how excluded files affect the daemon. .IP .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 .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 .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 \(dq\&auth users\(dq\& 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 \(dq\&secrets file\(dq\& parameter. The default is for all users to be able to connect without a password (this is called \(dq\&anonymous rsync\(dq\&). .IP In addition to username matching, you can specify groupname matching via a \(cq\&@\(cq\& 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 \(dq\&@rsync\(dq\& 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 \(dq\&deny\(dq\& a user or a group, set the access to \(dq\&ro\(dq\& (read\-only), or set the access to \(dq\&rw\(dq\& (read/write). Setting an auth\-rule\-specific ro/rw setting overrides the module\(cq\&s \(dq\&read only\(dq\& 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: .IP .nf auth users = joe:deny @guest:deny admin:rw @rsync:ro susan joe sam .fi .IP In the above rule, user joe will be denied access no matter what. Any user that is in the group \(dq\&guest\(dq\& is also denied access. The user \(dq\&admin\(dq\& gets access in read/write mode, but only if the admin user is not in group \(dq\&guest\(dq\& (because the admin user\-matching rule would never be reached if the user is in group \(dq\&guest\(dq\&). Any other user who is in group \(dq\&rsync\(dq\& 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\(cq\&t match an earlier group\-matching rule. .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 \(dq\&USING RSYNC\-DAEMON FEATURES VIA A REMOTE SHELL CONNECTION\(dq\& 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 .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 \(dq\&auth users\(dq\& 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\(cq\&t work. .IP The use of group\-specific lines are only relevant when the module is being authorized using a matching \(dq\&@groupname\(dq\& rule. When that happens, the user can be authorized via either their \(dq\&username:password\(dq\& line or the \(dq\&@groupname:password\(dq\& 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 \(dq\&auth users\(dq\& 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 \(dq\&secrets file\(dq\& parameter, you must choose a name (such as \f(CW/etc/rsyncd.secrets\fP). The file must normally not be readable by \(dq\&other\(dq\&; see \(dq\&strict modes\(dq\&. If the file is not found or is rejected, no logins for a \(dq\&user auth\(dq\& module will be possible. .IP .IP "\fBstrict modes\fP" This parameter determines whether or not the permissions on the secrets file will be checked. If \(dq\&strict modes\(dq\& 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 \(dq\&strict modes\(dq\& 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 .IP "\fBhosts allow\fP" This parameter allows you to specify a list of patterns that are matched against a connecting clients hostname and IP address. If none of the patterns match then the connection is rejected. .IP Each pattern can be in one of five 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\(cq\&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 \(dq\&reverse lookup\(dq\& is enabled (the default). .IP o a hostname. A plain hostname is matched against the reverse DNS of the connecting IP (if \(dq\&reverse lookup\(dq\& is enabled), and/or the IP of the given hostname is matched against the connecting IP (if \(dq\&forward lookup\(dq\& is enabled, as it is by default). Any match will be allowed in. .RE .IP Note IPv6 link\-local addresses can have a scope in the address specification: .IP .RS \f(CW fe80::1%link1\fP .br \f(CW fe80::%link1/64\fP .br \f(CW fe80::%link1/ffff:ffff:ffff:ffff::\fP .br .RE .IP You can also combine \(dq\&hosts allow\(dq\& with a separate \(dq\&hosts deny\(dq\& parameter. If both parameters are specified then the \(dq\&hosts allow\(dq\& parameter is checked first and a match results in the client being able to connect. The \(dq\&hosts deny\(dq\& parameter is then checked and a match means that the host is rejected. If the host does not match either the \(dq\&hosts allow\(dq\& or the \(dq\&hosts deny\(dq\& patterns then it is allowed to connect. .IP The default is no \(dq\&hosts allow\(dq\& parameter, which means all hosts can connect. .IP .IP "\fBhosts deny\fP" This parameter allows you to specify a list of patterns that are matched against a connecting clients hostname and IP address. If the pattern matches then the connection is rejected. See the \(dq\&hosts allow\(dq\& parameter for more information. .IP The default is no \(dq\&hosts deny\(dq\& parameter, which means all hosts can connect. .IP .IP "\fBreverse lookup\fP" Controls whether the daemon performs a reverse lookup on the client\(cq\&s IP address to determine its hostname, which is used for \(dq\&hosts allow\(dq\&/\(dq\&hosts deny\(dq\& checks and the \(dq\&%h\(dq\& 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 \(dq\&UNDETERMINED\(dq\& 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 .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 .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 .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\(cq\&t want those files to be seen at all. .IP .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 \(dq\&log format\(dq\& parameter. .IP .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. \(dq\&\fB%\-50n %8l %07p\fP\(dq\&). 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. \(dq\&\fB%'\&'\&l %'\&b %f\fP\(dq\&). .IP The default log format is \(dq\&%o %h [%a] %m (%u) %f %l\(dq\&, and a \(dq\&%t [%p] \(dq\& is always prefixed when using the \(dq\&log file\(dq\& parameter. (A perl script that will summarize this default log format is included in the rsync source code distribution in the \(dq\&support\(dq\& 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 MD5 checksum if \fB\-\-checksum\fP is enabled or a file was transferred (only for protocol 30 or above). .IP o %f the filename (long form on sender; no trailing \(dq\&/\(dq\&) .IP o %G the gid of the file (decimal) or \(dq\&DEFAULT\(dq\& .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 \(dq\& \-> SYMLINK\(dq\&, \(dq\& => HARDLINK\(dq\&, or \(dq\&\(dq\& (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 \(dq\&/\(dq\& on dir) .IP o %o the operation, which is \(dq\&send\(dq\&, \(dq\&recv\(dq\&, or \(dq\&del.\(dq\& (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 \(dq\&%i\(dq\&, 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 .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\(cq\&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 .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. For example, this would refuse \fB\-\-checksum\fP (\fB\-c\fP) and all the various delete options: .IP .RS \f(CW refuse options = c delete\fP .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. As an additional safety feature, the refusal of \(dq\&delete\(dq\& also refuses \fBremove\-source\-files\fP when the daemon is the sender; if you want the latter without the former, instead refuse \(dq\&delete\-*\(dq\& \-\- that refuses all the delete modes without affecting \fB\-\-remove\-source\-files\fP. .IP When an option is refused, the daemon prints an error message and exits. To prevent all compression when serving files, you can use \(dq\&dont compress = *\(dq\& (see below) instead of \(dq\&refuse options = compress\(dq\& to avoid returning an error to a client that requests compression. .IP .IP "\fBdont compress\fP" 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 is expensive in terms of CPU usage, so it is usually good to not try to compress files that won\(cq\&t compress well, such as already compressed files. .IP The \(dq\&dont compress\(dq\& parameter takes a space\-separated list of case\-insensitive wildcard patterns. Any source filename matching one of the patterns will not be compressed during transfer. .IP See the \fB\-\-skip\-compress\fP parameter in the \fBrsync\fP(1) manpage for the list of file suffixes that are not compressed by default. Specifying a value for the \(dq\&dont compress\(dq\& parameter changes the default when the daemon is the sender. .IP .IP "\fBpre\-xfer exec\fP, \fBpost\-xfer exec\fP" You may specify a command to be run before and/or after the transfer. If the \fBpre\-xfer exec\fP command fails, the transfer is aborted before it begins. Any output from the script on stdout (up to several KB) will be displayed to the user when aborting, but is NOT displayed if the script returns success. Any output from the script on stderr goes to the daemon\(cq\&s stderr, which is typically discarded (though see \-\-no\-detatch option for a way to see the stderr output, which can assist with debugging). .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\(cq\&s IP address. .IP o \fBRSYNC_HOST_NAME\fP: The accessing host\(cq\&s name. .IP o \fBRSYNC_USER_NAME\fP: The accessing user\(cq\&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 \(dq\&mod/path1 mod/path2\(dq\&, etc. .IP o \fBRSYNC_ARG#\fP: (pre\-xfer only) The pre\-request arguments are set in these numbered values. RSYNC_ARG0 is always \(dq\&rsyncd\(dq\&, followed by the options that were used in RSYNC_ARG1, and so on. There will be a value of \(dq\&.\(dq\& 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\(cq\&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 \f(CWwaitpid()\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\(cq\&s uid/gid setting) without any chroot restrictions. .IP .SH "CONFIG DIRECTIVES" .PP 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\(cq\&s contents are considered to be. .PP 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. .PP The \fB&merge\fP directive, on the other hand, treats the file\(cq\&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. .PP 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 \(dq\&rsyncd.d\(dq\& with the files \(dq\&foo.conf\(dq\&, \(dq\&bar.conf\(dq\&, and \(dq\&baz.conf\(dq\& inside it, this directive: .PP .nf &include /path/rsyncd.d .fi .PP would be the same as this set of directives: .PP .nf &include /path/rsyncd.d/bar.conf &include /path/rsyncd.d/baz.conf &include /path/rsyncd.d/foo.conf .fi .PP except that it adjusts as files are added and removed from the directory. .PP 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. .PP 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. .PP For example, this is a useful /etc/rsyncd.conf file: .PP .nf port = 873 log file = /var/log/rsync.log pid file = /var/lock/rsync.lock &merge /etc/rsyncd.d &include /etc/rsyncd.d .fi .PP 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). .PP .SH "AUTHENTICATION STRENGTH" .PP 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.) .PP 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. .PP Future versions of rsync may support SSL for better authentication and encryption, but that is still being investigated. .PP .SH "EXAMPLES" .PP A simple rsyncd.conf file that allow anonymous rsync to a ftp area at \f(CW/home/ftp\fP would be: .PP .nf [ftp] path = /home/ftp comment = ftp export area .fi .PP A more sophisticated example would be: .PP .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 .PP The /etc/rsyncd.secrets file would look something like this: .PP .RS \f(CWtridge:mypass\fP .br \f(CWsusan:herpass\fP .br .RE .PP .SH "FILES" .PP /etc/rsyncd.conf or rsyncd.conf .PP .SH "SEE ALSO" .PP \fBrsync\fP(1) .PP .SH "DIAGNOSTICS" .PP .SH "BUGS" .PP Please report bugs! The rsync bug tracking system is online at http://rsync.samba.org/ .PP .SH "VERSION" .PP This man page is current for version 3.1.2 of rsync. .PP .SH "CREDITS" .PP rsync is distributed under the GNU General Public License. See the file COPYING for details. .PP The primary ftp site for rsync is ftp://rsync.samba.org/pub/rsync. .PP A WEB site is available at http://rsync.samba.org/ .PP We would be delighted to hear from you if you like this program. .PP This program uses the zlib compression library written by Jean\-loup Gailly and Mark Adler. .PP .SH "THANKS" .PP Thanks to Warren Stanley for his original idea and patch for the rsync daemon. Thanks to Karsten Thygesen for his many suggestions and documentation! .PP .SH "AUTHOR" .PP rsync was written by Andrew Tridgell and Paul Mackerras. Many people have later contributed to it. .PP Mailing lists for support and development are available at http://lists.samba.org rsync-bpc-3.1.2.1/batch.c0000664000047500004750000001531513510756407013762 0ustar craigcraig/* * Support for the batch-file options. * * Copyright (C) 1999 Weiss * Copyright (C) 2004 Chris Shoemaker * Copyright (C) 2004-2015 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 protocol_version; extern char *batch_name; #ifdef ICONV_OPTION extern char *iconv_opt; #endif extern filter_rule_list filter_list; 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(int fd, char *arg) { char *x, *s; int len, ret = 0; if (*arg == '-' && (x = strchr(arg, '=')) != NULL) { if (write(fd, arg, x - arg + 1) != x - arg + 1) ret = -1; arg += x - arg + 1; } if (strpbrk(arg, " \"'&;|[]()$#!*?^\\") != NULL) { if (write(fd, "'", 1) != 1) ret = -1; for (s = arg; (x = strchr(s, '\'')) != NULL; s = x + 1) { if (write(fd, s, x - s + 1) != x - s + 1 || write(fd, "'", 1) != 1) ret = -1; } len = strlen(s); if (write(fd, s, len) != len || write(fd, "'", 1) != 1) ret = -1; return ret; } len = strlen(arg); if (write(fd, arg, len) != len) ret = -1; return ret; } 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 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(int argc, char *argv[], int file_arg_cnt) { int fd, i, len, err = 0; char *p, filename[MAXPATHLEN]; stringjoin(filename, sizeof filename, batch_name, ".sh", NULL); fd = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR); if (fd < 0) { rsyserr(FERROR, errno, "Batch file %s open error", filename); exit_cleanup(RERR_FILESELECT); } /* Write argvs info to BATCH.sh file */ if (write_arg(fd, argv[0]) < 0) err = 1; if (filter_list.head) { if (protocol_version >= 29) write_sbuf(fd, " --filter=._-"); else write_sbuf(fd, " --exclude-from=-"); } for (i = 1; i < argc - file_arg_cnt; i++) { p = argv[i]; 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 (write(fd, " ", 1) != 1) err = 1; if (strncmp(p, "--write-batch", len = 13) == 0 || strncmp(p, "--only-write-batch", len = 18) == 0) { if (write(fd, "--read-batch", 12) != 12) err = 1; if (p[len] == '=') { if (write(fd, "=", 1) != 1 || write_arg(fd, p + len + 1) < 0) err = 1; } } else { if (write_arg(fd, p) < 0) err = 1; } } if (!(p = check_for_hostspec(argv[argc - 1], &p, &i))) p = argv[argc - 1]; if (write(fd, " ${1:-", 6) != 6 || write_arg(fd, p) < 0) err = 1; write_byte(fd, '}'); if (filter_list.head) write_filter_rules(fd); if (write(fd, "\n", 1) != 1 || close(fd) < 0 || err) { rsyserr(FERROR, errno, "Batch file %s write error", filename); exit_cleanup(RERR_FILEIO); } } rsync-bpc-3.1.2.1/tech_report.tex0000664000047500004750000003452313510756401015571 0ustar craigcraig\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-bpc-3.1.2.1/fileio.c0000664000047500004750000001536213510756407014152 0ustar craigcraig/* * File IO utilities used in rsync. * * Copyright (C) 1998 Andrew Tridgell * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2015 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 boundries. */ #define ALIGN_BOUNDRY 1024 /* How far past the boundary is an offset? */ #define ALIGNED_OVERSHOOT(oft) ((oft) & (ALIGN_BOUNDRY-1)) /* Round up a length to the next boundary */ #define ALIGNED_LENGTH(len) ((((len) - 1) | (ALIGN_BOUNDRY-1)) + 1) extern int sparse_files; static OFF_T sparse_seek = 0; int sparse_end(int f, OFF_T size) { int ret; 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 = bpc_write(f, "", 1); } while (ret < 0 && errno == EINTR); ret = ret <= 0 ? -1 : 0; } #endif sparse_seek = 0; return ret; } static int write_sparse(int f, 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) do_lseek(f, sparse_seek, SEEK_CUR); sparse_seek = l2; while ((ret = bpc_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 = bpc_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. */ int write_file(int f, 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, buf, len1); } else { if (!wf_writeBuf) { wf_writeBufSize = WRITE_SIZE * 8; wf_writeBufCnt = 0; wf_writeBuf = new_array(char, wf_writeBufSize); if (!wf_writeBuf) out_of_memory("write_file"); } 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; } /* 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; if (!(map = new0(struct map_struct))) out_of_memory("map_file"); 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); if (!map->p) out_of_memory("map_ptr"); 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 = bpc_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; memset(map, 0, sizeof map[0]); free(map); return ret; } rsync-bpc-3.1.2.1/proto.h0000664000047500004750000005620013510756407014047 0ustar craigcraig/* This file is automatically generated with "make proto". DO NOT EDIT */ int allow_access(const char *addr, const char **host_ptr, int i); void free_acl(stat_x *sxp); int get_acl(const char *fname, stat_x *sxp); void send_acl(int f, stat_x *sxp); void receive_acl(int f, struct file_struct *file); void cache_tmp_acl(struct file_struct *file, stat_x *sxp); void uncache_tmp_acls(void); int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode); void match_acl_ids(void); void base64_encode(const char *buf, int len, char *out, int pad); char *auth_server(int f_in, int f_out, int module, const char *host, const char *addr, const char *leader); void auth_client(int fd, const char *user, const char *challenge); char *get_backup_name(const char *fname); int make_backup(const char *fname, BOOL prefer_rename); void write_stream_flags(int fd); void read_stream_flags(int fd); void check_batch_flags(void); void write_batch_shell_file(int argc, char *argv[], int file_arg_cnt); void bpc_sysCall_init( char *topDir, /* backuppc top-level data dir path */ char *hostName, /* host name */ char *shareNameUM, /* unmangled share name */ int newBkupNum, /* new backup number */ int newCompress, /* compression level for new backup */ int prevBkupNum, /* prior backup number (or -1) */ int prevCompress, /* comperssion level for prior backup */ char *mergeBkupInfo, /* which backups to merge together on read */ ino_t inode0, /* starting inode number for this backup */ int attrib_new, /* flag to turn on new-style attrib file names */ int logLevel /* logging level */ ); void bpc_am_generator(int generator, int pid); int bpc_sysCall_cleanup(void); void bpc_progress_fileDone(void); void bpc_sysCall_statusFileSize(unsigned long fileSize); void bpc_sysCall_setInode0Debug(int inode0, char *hostName, char *shareNameUM, int prevBkupNum, int prevCompress); char *bpc_mktemp(char *template); int bpc_mkstemp(char *template, char *origFileName); int bpc_sysCall_checkFileMatch(char *fileName, char *tmpName, struct file_struct *rsyncFile, char *file_sum, off_t fileSize); int bpc_sysCall_poolFileCheck(char *fileName, struct file_struct *rsyncFile); void bpc_sysCall_printfileStatus(char *fileName, char *status); int bpc_lchmod(const char *fileName, mode_t mode); int bpc_fchmod(int filedes, mode_t mode); int bpc_unlink(const char *fileName); int bpc_lstat(const char *fileName, struct stat *buf); int bpc_fstat(int filedes, struct stat *buf); int bpc_stat(const char *fileName, struct stat *buf); int bpc_file_checksum(char *fileName, char *sum, int checksum_len); int bpc_symlink(const char *fileName, const char *symName); int bpc_link(const char *targetName, const char *linkName); int bpc_nlinkSet(const char *targetName, uint32 nlinks); int bpc_lutimes(const char *fileName, struct timeval *t); int bpc_utimes(const char *fileName, struct timeval *t); int bpc_lutime(const char *fileName, time_t mtime); int bpc_utime(const char *fileName, time_t mtime); int bpc_lchown(const char *fileName, uid_t uid, gid_t gid); int bpc_rename(const char *oldName, const char *newName); int bpc_rename_request(char *oldName, char *newName, uint32 isTemp, char *bufP, char *bufEnd); int bpc_mknod(const char *fileName, mode_t mode, dev_t dev); int bpc_open(const char *fileName, int flags, mode_t mode); int bpc_close(int fdNum); off_t bpc_lseek(int fdNum, off_t offset, int whence); off_t bpc_ftruncate(int fdNum, off_t length); ssize_t bpc_read(int fdNum, void *buf, size_t readSize); ssize_t bpc_write(int fdNum, const void *buf, size_t writeSize); ssize_t bpc_readlink(const char *fileName, char *buffer, size_t bufferSize); int bpc_access(const char *fileName, int mode); void bpc_tmpNameFlagSet(const char *tmpName); int bpc_chdir(const char *dirName); int bpc_mkdir(const char *dirName, mode_t mode); int bpc_rmdir(const char *dirName); DIR *bpc_opendir(const char *path); struct dirent *bpc_readdir(DIR *dir); int bpc_closedir(DIR *dir); ssize_t bpc_lgetxattr(const char *path, const char *name, void *value, size_t size); ssize_t bpc_fgetxattr(int filedes, const char *name, void *value, size_t size); int bpc_lsetxattr(const char *path, const char *name, const void *value, size_t size, UNUSED(int flags)); int bpc_lremovexattr(const char *path, const char *name); ssize_t bpc_llistxattr(const char *path, char *list, size_t size); uint32 get_checksum1(char *buf1, int32 len); void get_checksum2(char *buf, int32 len, char *sum); int file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum); void sum_init(int seed); void sum_update(const char *p, int32 len); int sum_end(char *sum); struct chmod_mode_struct *parse_chmod(const char *modestr, struct chmod_mode_struct **root_mode_ptr); int tweak_mode(int mode, struct chmod_mode_struct *chmod_modes); int free_chmod_mode(struct chmod_mode_struct *chmod_modes); void close_all(void); NORETURN void _exit_cleanup(int code, const char *file, int line); void cleanup_disable(void); void cleanup_set(const char *fnametmp, const char *fname, struct file_struct *file, int fd_r, int fd_w); void cleanup_set_pid(pid_t pid); char *client_addr(int fd); char *client_name(int fd); void client_sockaddr(int fd, struct sockaddr_storage *ss, socklen_t *ss_len); int lookup_name(int fd, const struct sockaddr_storage *ss, socklen_t ss_len, char *name_buf, size_t name_buf_size, char *port_buf, size_t port_buf_size); int compare_addrinfo_sockaddr(const struct addrinfo *ai, const struct sockaddr_storage *ss); int check_name(int fd, const struct sockaddr_storage *ss, char *name_buf, size_t name_buf_size); int start_socket_client(char *host, int remote_argc, char *remote_argv[], int argc, char *argv[]); int start_inband_exchange(int f_in, int f_out, const char *user, int argc, char *argv[]); int start_daemon(int f_in, int f_out); int daemon_main(void); void set_allow_inc_recurse(void); void setup_protocol(int f_out,int f_in); int claim_connection(char *fname, int max_connections); enum delret delete_item(char *fbuf, uint16 mode, uint16 flags); uint16 get_del_for_flag(uint16 mode); void set_filter_dir(const char *dir, unsigned int dirlen); void *push_local_filters(const char *dir, unsigned int dirlen); void pop_local_filters(void *mem); void change_local_filter_dir(const char *dname, int dlen, int dir_depth); int check_filter(filter_rule_list *listp, enum logcode code, const char *name, int name_is_dir); const filter_rule *rule_template(uint32 rflags); void parse_filter_str(filter_rule_list *listp, const char *rulestr, const filter_rule *template, int xflags); void parse_filter_file(filter_rule_list *listp, const char *fname, const filter_rule *template, int xflags); char *get_rule_prefix(filter_rule *rule, const char *pat, int for_xfer, unsigned int *plen_ptr); void send_filter_list(int f_out); void recv_filter_list(int f_in); int sparse_end(int f, OFF_T size); int flush_write_file(int f); int write_file(int f, char *buf, int len); struct map_struct *map_file(int fd, OFF_T len, int32 read_size, int32 blk_size); char *map_ptr(struct map_struct *map, OFF_T offset, int32 len); int unmap_file(struct map_struct *map); void init_flist(void); void show_flist_stats(void); int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks); int change_pathname(struct file_struct *file, const char *dir, int dirlen); struct file_struct *make_file(const char *fname, struct file_list *flist, STRUCT_STAT *stp, int flags, int filter_level); void unmake_file(struct file_struct *file); void send_extra_file_list(int f, int at_least); struct file_list *send_file_list(int f, int argc, char *argv[]); struct file_list *recv_file_list(int f, int dir_ndx); void recv_additional_file_list(int f); int flist_find(struct file_list *flist, struct file_struct *f); int flist_find_name(struct file_list *flist, const char *fname, int want_dir_match); int flist_find_ignore_dirness(struct file_list *flist, struct file_struct *f); void clear_file(struct file_struct *file); struct file_list *flist_new(int flags, char *msg); void flist_free(struct file_list *flist); int f_name_cmp(const struct file_struct *f1, const struct file_struct *f2); int f_name_has_prefix(const struct file_struct *f1, const struct file_struct *f2); char *f_name_buf(void); char *f_name(const struct file_struct *f, char *fbuf); struct file_list *get_dirlist(char *dirname, int dlen, int flags); int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp); void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret, stat_x *sxp, int32 iflags, uchar fnamecmp_type, const char *xname); int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st); 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); void check_for_finished_files(int itemizing, enum logcode code, int check_redo); void generate_files(int f_out, const char *local_name); struct hashtable *hashtable_create(int size, int key64); void hashtable_destroy(struct hashtable *tbl); void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing); void hashtable_iterate(struct hashtable *tbl, void (*callback)(int64 key, void*, void*), void *arg1); void init_hard_links(void); struct ht_int64_node *idev_find(int64 dev, int64 ino); void idev_destroy(void); void match_hard_links(struct file_list *flist); int hard_link_check(struct file_struct *file, int ndx, char *fname, int statret, stat_x *sxp, int itemizing, enum logcode code); int hard_link_one(struct file_struct *file, const char *fname, const char *oldname, int terse); 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); int skip_hard_link(struct file_struct *file, struct file_list **flist_p); void hard_link_bpc_update_link_count(void); void reduce_iobuf_size(xbuf *out, size_t new_size); void restore_iobuf_size(xbuf *out); void noop_io_until_death(void); int send_msg(enum msgcode code, const char *buf, size_t len, int convert); void send_msg_int(enum msgcode code, int num); void io_set_sock_fds(int f_in, int f_out); void set_io_timeout(int secs); void increment_active_files(int ndx, int itemizing, enum logcode code); int get_redo_num(void); int get_hlink_num(void); void start_filesfrom_forwarding(int fd); int read_line(int fd, char *buf, size_t bufsiz, int flags); 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); BOOL io_start_buffering_out(int f_out); BOOL io_start_buffering_in(int f_in); void io_end_buffering_in(BOOL free_buffers); void io_end_buffering_out(BOOL free_buffers); void maybe_flush_socket(int important); void maybe_send_keepalive(time_t now, int flags); void start_flist_forward(int ndx); void stop_flist_forward(void); void wait_for_receiver(void); unsigned short read_shortint(int f); int32 read_int(int f); int32 read_varint(int f); int64 read_varlong(int f, uchar min_bytes); int64 read_longint(int f); void read_buf(int f, char *buf, size_t len); void read_sbuf(int f, char *buf, size_t len); uchar read_byte(int f); int read_vstring(int f, char *buf, int bufsize); void read_sum_head(int f, struct sum_struct *sum); void write_sum_head(int f, struct sum_struct *sum); void io_flush(int flush_it_all); void write_shortint(int f, unsigned short x); void write_int(int f, int32 x); void write_varint(int f, int32 x); void write_varlong(int f, int64 x, uchar min_bytes); void write_longint(int f, int64 x); void write_bigbuf(int f, const char *buf, size_t len); void write_buf(int f, const char *buf, size_t len); void write_sbuf(int f, const char *buf); void write_byte(int f, uchar c); void write_vstring(int f, const char *str, int len); void write_ndx(int f, int32 ndx); int32 read_ndx(int f); int read_line_old(int fd, char *buf, size_t bufsiz, int eof_ok); void io_printf(int fd, const char *format, ...); void io_start_multiplex_out(int fd); void io_start_multiplex_in(int fd); int io_end_multiplex_in(int mode); int io_end_multiplex_out(int mode); void start_write_batch(int fd); void stop_write_batch(void); char *lp_bind_address(void); char *lp_motd_file(void); char *lp_pid_file(void); char *lp_socket_options(void); int lp_listen_backlog(void); int lp_rsync_port(void); char *lp_auth_users(int module_id); char *lp_charset(int module_id); char *lp_comment(int module_id); char *lp_dont_compress(int module_id); char *lp_exclude(int module_id); char *lp_exclude_from(int module_id); char *lp_filter(int module_id); char *lp_gid(int module_id); char *lp_hosts_allow(int module_id); char *lp_hosts_deny(int module_id); char *lp_include(int module_id); char *lp_include_from(int module_id); char *lp_incoming_chmod(int module_id); char *lp_lock_file(int module_id); char *lp_log_file(int module_id); char *lp_log_format(int module_id); char *lp_name(int module_id); char *lp_outgoing_chmod(int module_id); char *lp_path(int module_id); char *lp_postxfer_exec(int module_id); char *lp_prexfer_exec(int module_id); char *lp_refuse_options(int module_id); char *lp_secrets_file(int module_id); char *lp_temp_dir(int module_id); char *lp_uid(int module_id); int lp_max_connections(int module_id); int lp_max_verbosity(int module_id); int lp_syslog_facility(int module_id); int lp_timeout(int module_id); BOOL lp_fake_super(int module_id); BOOL lp_forward_lookup(int module_id); BOOL lp_ignore_errors(int module_id); BOOL lp_ignore_nonreadable(int module_id); BOOL lp_list(int module_id); BOOL lp_munge_symlinks(int module_id); BOOL lp_numeric_ids(int module_id); BOOL lp_read_only(int module_id); BOOL lp_reverse_lookup(int module_id); BOOL lp_strict_modes(int module_id); BOOL lp_transfer_logging(int module_id); BOOL lp_use_chroot(int module_id); BOOL lp_write_only(int module_id); int lp_load(char *pszFname, int globals_only); BOOL set_dparams(int syntax_check_only); int lp_num_modules(void); int lp_number(char *name); void log_init(int restart); void logfile_close(void); void logfile_reopen(void); void rwrite(enum logcode code, const char *buf, int len, int is_utf8); void rprintf(enum logcode code, const char *format, ...); void rsyserr(enum logcode code, int errcode, const char *format, ...); void rflush(enum logcode code); void remember_initial_stats(void); int log_format_has(const char *format, char esc); void log_item(enum logcode code, struct file_struct *file, int iflags, const char *hlink); void maybe_log_item(struct file_struct *file, int iflags, int itemizing, const char *buf); void log_delete(const char *fname, int mode); void log_exit(int code, const char *file, int line); pid_t wait_process(pid_t pid, int *status_ptr, int flags); void write_del_stats(int f); void read_del_stats(int f); int child_main(int argc, char *argv[]); void start_server(int f_in, int f_out, int argc, char *argv[]); int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]); void remember_children(UNUSED(int val)); const char *get_panic_action(void); int main(int argc,char *argv[]); void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len); void match_report(void); void limit_output_verbosity(int level); void reset_output_levels(void); void negate_output_levels(void); void usage(enum logcode F); void option_error(void); int parse_arguments(int *argc_p, const char ***argv_p); void server_options(char **args, int *argc_p); char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr); int pm_process( char *FileName, BOOL (*sfunc)(char *), BOOL (*pfunc)(char *, char *) ); pid_t piped_child(char **command, int *f_in, int *f_out); pid_t local_child(int argc, char **argv, int *f_in, int *f_out, int (*child_main)(int, char*[])); void set_current_file_index(struct file_struct *file, int ndx); void end_progress(OFF_T size); void show_progress(OFF_T ofs, OFF_T size); int get_tmpname(char *fnametmp, const char *fname, BOOL make_unique); int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file); int recv_files(int f_in, int f_out, char *local_name); void setup_iconv(void); int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags); void send_protected_args(int fd, char *args[]); int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr); void free_sums(struct sum_struct *s); mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms, int exists); int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, const char *fnamecmp, int flags); void sig_int(int sig_num); 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); struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc); const char *who_am_i(void); void successful_send(int ndx); void send_files(int f_in, int f_out); int try_bind_local(int s, int ai_family, int ai_socktype, const char *bind_addr); int open_socket_out(char *host, int port, const char *bind_addr, int af_hint); int open_socket_out_wrapped(char *host, int port, const char *bind_addr, int af_hint); int is_a_socket(int fd); void start_accept_loop(int port, int (*fn)(int, int)); void set_socket_options(int fd, char *options); int do_unlink(const char *fname); int do_symlink(const char *lnk, const char *fname); ssize_t do_readlink(const char *path, char *buf, size_t bufsiz); int do_link(const char *fname1, const char *fname2); int do_lchown(const char *path, uid_t owner, gid_t group); int do_mknod(const char *pathname, mode_t mode, dev_t dev); int do_rmdir(const char *pathname); int do_open(const char *pathname, int flags, mode_t mode); int do_chmod(const char *path, mode_t mode); int do_rename(const char *fname1, const char *fname2); int do_ftruncate(int fd, OFF_T size); void trim_trailing_slashes(char *name); int do_mkdir(char *fname, mode_t mode); int do_mkstemp(char *template, mode_t perms, char *origFileName); int do_stat(const char *fname, STRUCT_STAT *st); int do_lstat(const char *fname, STRUCT_STAT *st); int do_fstat(int fd, STRUCT_STAT *st); OFF_T do_lseek(int fd, OFF_T offset, int whence); int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec); int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec); int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)); int do_fallocate(int fd, OFF_T offset, OFF_T length); int do_open_nofollow(const char *pathname, int flags); void set_compression(const char *fname); void send_token(int f, int32 token, struct map_struct *buf, OFF_T offset, int32 n, int32 toklen); int32 recv_token(int f, char **data); void see_token(char *data, int32 toklen); char *uid_to_user(uid_t uid); char *gid_to_group(gid_t gid); int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok); int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok); uid_t match_uid(uid_t uid); gid_t match_gid(gid_t gid, uint16 *flags_ptr); const char *add_uid(uid_t uid); const char *add_gid(gid_t gid); void send_id_list(int f); uid_t recv_user_name(int f, uid_t uid); gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr); void recv_id_list(int f, struct file_list *flist); void parse_name_map(char *map, BOOL usernames); const char *getallgroups(uid_t uid, item_list *gid_list); void set_nonblocking(int fd); void set_blocking(int fd); int fd_pair(int fd[2]); void print_child_argv(const char *prefix, char **cmd); int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode); int make_path(char *fname, int flags); int full_write(int desc, const char *ptr, size_t len); int copy_file(const char *source, const char *dest, int ofd, mode_t mode); int robust_unlink(const char *fname); int robust_rename(const char *from, const char *to, const char *partialptr, int mode); pid_t do_fork(void); void kill_all(int sig); int lock_range(int fd, int offset, int len); int glob_expand(const char *arg, char ***argv_p, int *argc_p, int *maxargs_p); void glob_expand_module(char *base1, char *arg, char ***argv_p, int *argc_p, int *maxargs_p); void strlower(char *s); size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2); size_t stringjoin(char *dest, size_t destsize, ...); int count_dir_elements(const char *p); int clean_fname(char *name, int flags); char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags); int change_dir(const char *dir, int set_path_only); char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr); char *full_fname(const char *fn); char *partial_dir_fname(const char *fname); int handle_partial_dir(const char *fname, int create); int unsafe_symlink(const char *dest, const char *src); char *timestring(time_t t); int cmp_time(time_t file1, time_t file2); int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6); const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr); uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2); struct bitbag *bitbag_create(int max_ndx); void bitbag_set_bit(struct bitbag *bb, int ndx); void bitbag_clear_bit(struct bitbag *bb, int ndx); int bitbag_check_bit(struct bitbag *bb, int ndx); int bitbag_next_bit(struct bitbag *bb, int after); void flist_ndx_push(flist_ndx_list *lp, int ndx); int flist_ndx_pop(flist_ndx_list *lp); void *expand_item_list(item_list *lp, size_t item_size, const char *desc, int incr); int msleep(int t); void *_new_array(unsigned long num, unsigned int size, int use_calloc); void *_realloc_array(void *ptr, unsigned int size, size_t num); const char *sum_as_hex(const char *sum); NORETURN void out_of_memory(const char *str); NORETURN void overflow_exit(const char *str); void free_xattr(stat_x *sxp); int get_xattr(const char *fname, stat_x *sxp); int copy_xattrs(const char *source, const char *dest); int send_xattr(int f, stat_x *sxp); int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all); void send_xattr_request(const char *fname, struct file_struct *file, int f_out); int recv_xattr_request(struct file_struct *file, int f_in); void receive_xattr(int f, struct file_struct *file); void cache_tmp_xattr(struct file_struct *file, stat_x *sxp); void uncache_tmp_xattrs(void); int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp, stat_x *sxp); char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p); int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len); int del_def_xattr_acl(const char *fname); int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst); int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode); int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst); int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst); int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst); int sys_gettimeofday(struct timeval *tv); char *do_big_num(int64 num, int human_flag, const char *fract); char *do_big_dnum(double dnum, int human_flag, int decimal_digits); rsync-bpc-3.1.2.1/chmod.c0000664000047500004750000001273713510756407014000 0ustar craigcraig/* * Implement the core of the --chmod option. * * Copyright (C) 2002 Scott Howard * Copyright (C) 2005-2015 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 succcess * (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-bpc-3.1.2.1/config.sub0000664000047500004750000010530113510756401014502 0ustar craigcraig#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-04-24' # 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 with a ChangeLog entry to config-patches@gnu.org. # # 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: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # 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 $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -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-2013 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" 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 # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` 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* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -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*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; 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 ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; 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-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-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-unknown 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 ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; 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 ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; 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 ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; 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 ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; 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 ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # 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) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/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 ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First 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* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -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 ;; -nsk*) os=-nsk ;; # 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 ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` 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 $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; 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 ;; or1k-*) 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 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-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 ;; *-next) os=-nextstep3 ;; *-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 ;; *) 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. vendor=unknown case $basic_machine 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 ;; -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 basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsync-bpc-3.1.2.1/config.h.in0000664000047500004750000005015613510756407014562 0ustar craigcraig/* 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 one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* 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 you have and it should be used (not on Ultrix). */ #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 vsprintf has a C99-compatible return value */ #undef HAVE_C99_VSNPRINTF /* 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 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 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 `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 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 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 `mallinfo' function. */ #undef HAVE_MALLINFO /* 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 header file. */ #undef HAVE_MEMORY_H /* 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 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 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_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 /* 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 `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_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 `strdup' function. */ #undef HAVE_STRDUP /* 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_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_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 `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_ZLIB_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. Specifing 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 --protected-args should be the default */ #undef RSYNC_USE_PROTECTED_ARGS /* rsync release version */ #undef RSYNC_VERSION /* 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 `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 you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 to add support for ACLs */ #undef SUPPORT_ACLS /* Define to 1 to add support for extended attributes */ #undef SUPPORT_XATTRS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if you want rsync to make use of iconv_open() */ #undef USE_ICONV_OPEN /* 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 /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #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-bpc-3.1.2.1/util2.c0000664000047500004750000000516413510756407013741 0ustar craigcraig/* * 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-2015 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 checksum_len; /** * Sleep for a specified number of milliseconds. * * Always returns TRUE. (In the future it might return FALSE if * interrupted.) **/ int msleep(int t) { #ifdef 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; } #define MALLOC_MAX 0x40000000 void *_new_array(unsigned long num, unsigned int size, int use_calloc) { if (num >= MALLOC_MAX/size) return NULL; return use_calloc ? calloc(num, size) : malloc(num * size); } void *_realloc_array(void *ptr, unsigned int size, size_t num) { if (num >= MALLOC_MAX/size) return NULL; if (!ptr) return malloc(size * num); return realloc(ptr, size * num); } const char *sum_as_hex(const char *sum) { static char buf[MAX_DIGEST_LEN*2+1]; int i, x1, x2; char *c = buf + checksum_len*2; assert(c - buf < (int)sizeof buf); *c = '\0'; for (i = checksum_len; --i >= 0; ) { x1 = CVAL(sum, i); x2 = x1 >> 4; x1 &= 0xF; *--c = x1 <= 9 ? x1 + '0' : x1 + 'a' - 10; *--c = x2 <= 9 ? x2 + '0' : x2 + 'a' - 10; } return buf; } NORETURN void out_of_memory(const char *str) { rprintf(FERROR, "ERROR: out of memory in %s [%s]\n", str, who_am_i()); exit_cleanup(RERR_MALLOC); } NORETURN void overflow_exit(const char *str) { rprintf(FERROR, "ERROR: buffer overflow in %s [%s]\n", str, who_am_i()); exit_cleanup(RERR_MALLOC); } rsync-bpc-3.1.2.1/t_unsafe.c0000664000047500004750000000257013510756407014504 0ustar craigcraig/* * Test harness for unsafe_symlink(). Not linked into rsync itself. * * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2015 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; int human_readable = 0; int preserve_perms = 0; int preserve_executability = 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-bpc-3.1.2.1/token.c0000664000047500004750000004010713510756407014016 0ustar craigcraig/* * Routines used by the file-transfer code. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2015 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 extern int do_compression; extern int protocol_version; extern int module_id; extern int def_compress_level; extern char *skip_compress; static int compression_level, per_file_default_level; struct suffix_tree { struct suffix_tree *sibling; struct suffix_tree *child; char letter, word_end; }; static char *match_list; static struct suffix_tree *suftree; 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; } if (!(newnode = new(struct suffix_tree))) out_of_memory("add_suffix"); 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; if (!(buf = new_array(char, strlen(f) + 1))) out_of_memory("add_nocompress_suffixes"); 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); if (!(match_list = t = new_array(char, strlen(f) + 2))) out_of_memory("set_compression"); per_file_default_level = def_compress_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 = 0; 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) { const struct suffix_tree *node; const char *s; char ltr; if (!do_compression) return; if (!match_list) init_set_compression(); 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 = 0; 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 = 0; return; } if (!(node = node->child)) return; } } /* 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 (!buf) out_of_memory("simple_recv_token"); } 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) { int32 n, r; static int init_done, flush_pending; 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, compression_level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { rprintf(FERROR, "compression init failed\n"); exit_cleanup(RERR_PROTOCOL); } if ((obuf = new_array(char, OBUF_SIZE)) == NULL) out_of_memory("send_deflated_token"); 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 == 1) { /* Add the data in the current block to the compressor's * history and hash table. */ #ifndef EXTERNAL_ZLIB 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); #else toklen++; rprintf(FERROR, "Impossible error in external-zlib code (1).\n"); exit_cleanup(RERR_STREAMIO); #endif } } /* 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); } if (!(cbuf = new_array(char, MAX_DATA_COUNT)) || !(dbuf = new_array(char, AVAIL_OUT_SIZE(CHUNK_SIZE)))) out_of_memory("recv_deflated_token"); 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] = 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) { #ifndef EXTERNAL_ZLIB 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); #else buf++; len++; rprintf(FERROR, "Impossible error in external-zlib code (2).\n"); exit_cleanup(RERR_STREAMIO); #endif } /** * 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) { if (!do_compression) simple_send_token(f, token, buf, offset, n); else send_deflated_token(f, token, buf, offset, n, toklen); } /* * receive a token or buffer from the other end. If the reurn 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) { int tok; if (!do_compression) { tok = simple_recv_token(f,data); } else { tok = recv_deflated_token(f, data); } return tok; } /* * look at the data corresponding to a token, if necessary */ void see_token(char *data, int32 toklen) { if (do_compression == 1) see_deflate_token(data, toklen); } rsync-bpc-3.1.2.1/trimslash.c0000664000047500004750000000235513510756407014707 0ustar craigcraig/* * Simple utility used only by the test harness. * * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2015 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 preserve_perms = 0; int preserve_executability = 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-bpc-3.1.2.1/prepare-source.mak0000664000047500004750000000030313510756401016144 0ustar craigcraigconf: configure.sh config.h.in aclocal.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-bpc-3.1.2.1/checksum.c0000664000047500004750000001375013510756407014504 0ustar craigcraig/* * Routines to support checksumming of bytes. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2004-2015 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 checksum_seed; extern int protocol_version; extern int proper_seed_order; /* a simple 32 bit checksum that can be upadted 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); } void get_checksum2(char *buf, int32 len, char *sum) { md_context m; if (protocol_version >= 30) { uchar seedbuf[4]; md5_begin(&m); if (proper_seed_order) { if (checksum_seed) { SIVALu(seedbuf, 0, checksum_seed); md5_update(&m, seedbuf, 4); } md5_update(&m, (uchar *)buf, len); } else { md5_update(&m, (uchar *)buf, len); if (checksum_seed) { SIVALu(seedbuf, 0, checksum_seed); md5_update(&m, seedbuf, 4); } } md5_result(&m, (uchar *)sum); } else { 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; if (!buf1) out_of_memory("get_checksum2"); } 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 || protocol_version >= 27) mdfour_update(&m, (uchar *)(buf1+i), len-i); mdfour_result(&m, (uchar *)sum); } } int file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) { struct map_struct *buf; OFF_T i, len = st_p->st_size; md_context m; int32 remainder; int fd; memset(sum, 0, MAX_DIGEST_LEN); /* * Try to grab the digest from the attributes, which are both MD5 for protocol >= 30. * Otherwise fall through and do it the slow way. */ if ( protocol_version >= 30 ) { if ( !bpc_file_checksum((char *)fname, sum, MD5_DIGEST_LEN) ) return 0; /* * if bpc_file_checksum() fails on an empty file it likely means we have a wrong * digest, so don't recompute; this will cause the file to get re-transferred and * the digest will be updated. */ if ( len == 0 ) return -1; } fd = do_open(fname, O_RDONLY, 0); if (fd == -1) return -1; buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK); if (protocol_version >= 30) { md5_begin(&m); for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) { md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK), CSUM_CHUNK); } remainder = (int32)(len - i); if (remainder > 0) md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder); md5_result(&m, (uchar *)sum); } else { 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 || protocol_version >= 27) mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder); mdfour_result(&m, (uchar *)sum); } bpc_close(fd); unmap_file(buf); return 0; } static int32 sumresidue; static md_context md; void sum_init(int seed) { char s[4]; if (protocol_version >= 30) md5_begin(&md); else { mdfour_begin(&md); sumresidue = 0; SIVAL(s, 0, seed); sum_update(s, 4); } } /** * Feed data into an MD4 accumulator, md. The results may be * retrieved using sum_end(). md is used for different purposes at * different points during execution. * * @todo Perhaps get rid of md and just pass in the address each time. * Very slightly clearer and slower. **/ void sum_update(const char *p, int32 len) { if (protocol_version >= 30) { md5_update(&md, (uchar *)p, len); return; } if (len + sumresidue < CSUM_CHUNK) { memcpy(md.buffer + sumresidue, p, len); sumresidue += len; return; } if (sumresidue) { int32 i = CSUM_CHUNK - sumresidue; memcpy(md.buffer + sumresidue, p, i); mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK); len -= i; p += i; } while (len >= CSUM_CHUNK) { mdfour_update(&md, (uchar *)p, CSUM_CHUNK); len -= CSUM_CHUNK; p += CSUM_CHUNK; } sumresidue = len; if (sumresidue) memcpy(md.buffer, p, sumresidue); } int sum_end(char *sum) { if (protocol_version >= 30) { md5_result(&md, (uchar *)sum); return MD5_DIGEST_LEN; } if (sumresidue || protocol_version >= 27) mdfour_update(&md, (uchar *)md.buffer, sumresidue); mdfour_result(&md, (uchar *)sum); return MD4_DIGEST_LEN; } rsync-bpc-3.1.2.1/rsync3.txt0000664000047500004750000003477713510756401014526 0ustar craigcraig-*- 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 http://freshmeat.net/project/mirror/ - ProFTPd - Apache - http://freshmeat.net/search/?site=Freshmeat&q=mirror§ion=projects - BitTorrent -- p2p mirroring http://bitconjurer.org/BitTorrent/ rsync-bpc-3.1.2.1/socket.c0000664000047500004750000005315713510756407014177 0ustar craigcraig/* * Socket functions used in rsync. * * Copyright (C) 1992-2001 Andrew Tridgell * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2015 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" #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; #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 = ""; } snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", host, port, authhdr, authbuf); len = strlen(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 * connetcion 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); if (!errnos) out_of_memory("open_socket_out"); 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; if (!(prog = new_array(char, len))) out_of_memory("open_socket_out_wrapped"); 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); if (!socks || !errmsgs) out_of_memory("open_socket_in"); /* 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; 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); if (!options) out_of_memory("set_socket_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. * * Retruns 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(system(prog)); } close(fd[1]); return fd[0]; } rsync-bpc-3.1.2.1/getfsdev.c0000664000047500004750000000057613510756401014505 0ustar craigcraig#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-bpc-3.1.2.1/OLDNEWS0000664000047500004750000047531213510756407013602 0ustar craigcraigNEWS for rsync 3.1.1 (22 Jun 2014) Protocol: 31 (unchanged) Changes since 3.1.0: 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 support/rsync-no-vanished wrapper script. - 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) Protocol: 31 (changed) Changes since 3.0.9: 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 multibyte 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 nano-second 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 extendible, 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) Protocol: 30 (unchanged) Changes since 3.0.8: 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 man pages. - Fixed the user home-dir handling in the support/lsh script. - Some minor manpage improvements. NEWS for rsync 3.0.8 (26 Mar 2011) Protocol: 30 (unchanged) Changes since 3.0.7: 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 support/rrsync script, and also some regex changes that make vim highlighting happier. - Fixed some issues in the support/mnt-excl script. - 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) Protocol: 30 (unchanged) Changes since 3.0.6: 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) Protocol: 30 (unchanged) Changes since 3.0.5: 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) Protocol: 30 (unchanged) Changes since 3.0.4: 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 support/atomic-rsync script able to perform a fully atomic update of the copied hierarchy when the destination is setup using a particular symlink idiom. NEWS for rsync 3.0.4 (6 Sep 2008) Protocol: 30 (unchanged) Changes since 3.0.3: 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) Protocol: 30 (unchanged) Changes since 3.0.2: 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 man pages, 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) Protocol: 30 (unchanged) Changes since 3.0.1: 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) Protocol: 30 (unchanged) Changes since 3.0.0: 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 support/rrsync script to work with the latest options that rsync sends (including its flag-specifying use of -e to the server). 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) Protocol: 30 (changed) Changes since 2.6.9: 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 transfering 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 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) Protocol: 29 (unchanged) Changes since 2.6.8: 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 man page 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) Protocol: 29 (unchanged) Changes since 2.6.7: 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) Protocol: 29 (unchanged) Changes since 2.6.6: 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 multibyte 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/-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 man page 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 support/rrsync script has been upgraded to verify the args of options that take args (instead of rejecting any such options). The script was also changed to try to be more secure and to fix a problem in the parsing of a pull operation that has multiple sources. - 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) Protocol: 29 (unchanged) Changes since 2.6.4: 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 man pages 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) Protocol: 29 (changed) Changes since 2.6.3: 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) Protocol: 28 (unchanged) Changes since 2.6.2: 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 over- writing 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 man page 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 man page. - 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 man pages, 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) Protocol: 28 (unchanged) Changes since 2.6.1: 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) Protocol: 28 (changed) Changes since 2.6.0: 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 mis- understood 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) Protocol: 27 (changed) Changes since 2.5.7: 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) Protocol: 26 (unchanged) Changes since 2.5.6: 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) Protocol: 26 (unchanged) Changes since 2.5.5: 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) Protocol: 26 (unchanged) Changes since 2.5.4: 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) Protocol: 26 (unchanged) Changes since 2.5.3: 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) Protocol: 26 (unchanged) Changes since 2.5.2: 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 man page (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) Protocol: 26 (changed) Changes since 2.5.1: SECURITY FIXES: * Signedness security patch from Sebastian Krahmer -- in some cases we were not sufficiently careful about reading integers from the network. 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) Protocol: 25 (unchanged) Changes since 2.5.0: 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) Protocol: 25 (changed) Changes since 2.4.6: 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 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 CVS. rsync-bpc-3.1.2.1/loadparm.c0000664000047500004750000006006013510756407014475 0ustar craigcraig/* * 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-2015 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 stucture * * 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" extern item_list dparam_list; #define strequal(a, b) (strcasecmp(a, b)==0) #define BOOLSTR(b) ((b) ? "Yes" : "No") #ifndef LOG_DAEMON #define LOG_DAEMON 0 #endif #define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \ " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg *.png" \ " *.lzo *.rzip *.lzma *.rar *.ace *.gpg *.xz *.txz *.lz *.tlz" /* the following are used by loadparm for option lists */ typedef enum { P_BOOL, P_BOOLREV, 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)) /* This structure describes global (ie., server-wide) parameters. */ typedef struct { char *bind_address; char *motd_file; char *pid_file; char *socket_options; int listen_backlog; int rsync_port; } global_vars; /* This structure describes a single section. Their order must match the * initializers below, which you can accomplish by keeping each sub-section * sorted. (e.g. in vim, just visually select each subsection and use !sort.) * NOTE: the char* variables MUST all remain at the start of the stuct! */ typedef struct { char *auth_users; char *charset; char *comment; char *dont_compress; char *exclude; char *exclude_from; char *filter; char *gid; char *hosts_allow; char *hosts_deny; char *include; char *include_from; char *incoming_chmod; char *lock_file; char *log_file; char *log_format; char *name; char *outgoing_chmod; char *path; char *postxfer_exec; char *prexfer_exec; char *refuse_options; char *secrets_file; char *temp_dir; char *uid; /* NOTE: update this macro if the last char* variable changes! */ #define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1) int max_connections; int max_verbosity; int syslog_facility; int timeout; BOOL fake_super; BOOL forward_lookup; BOOL ignore_errors; BOOL ignore_nonreadable; BOOL list; BOOL munge_symlinks; BOOL numeric_ids; BOOL read_only; BOOL reverse_lookup; BOOL strict_modes; BOOL transfer_logging; BOOL use_chroot; BOOL write_only; } local_vars; /* This structure describes the global variables (g) as well as the globally * specified values of the local variables (l), which are used when modules * don't specify their own values. */ typedef struct { global_vars g; local_vars l; } all_vars; /* The application defaults for all the variables. "Defaults" is * used to re-initialize "Vars" before each config-file read. * * In order to keep these sorted in the same way as the structure * above, use the variable name in the leading comment, including a * trailing ';' (to avoid a sorting problem with trailing digits). */ static const all_vars Defaults = { /* ==== global_vars ==== */ { /* bind_address; */ NULL, /* motd_file; */ NULL, /* pid_file; */ NULL, /* socket_options; */ NULL, /* listen_backlog; */ 5, /* rsync_port; */ 0, }, /* ==== local_vars ==== */ { /* auth_users; */ NULL, /* charset; */ NULL, /* comment; */ NULL, /* dont_compress; */ DEFAULT_DONT_COMPRESS, /* exclude; */ NULL, /* exclude_from; */ NULL, /* filter; */ NULL, /* gid; */ NULL, /* hosts_allow; */ NULL, /* hosts_deny; */ NULL, /* include; */ NULL, /* include_from; */ NULL, /* incoming_chmod; */ NULL, /* lock_file; */ DEFAULT_LOCK_FILE, /* log_file; */ NULL, /* log_format; */ "%o %h [%a] %m (%u) %f %l", /* name; */ NULL, /* outgoing_chmod; */ NULL, /* path; */ NULL, /* postxfer_exec; */ NULL, /* prexfer_exec; */ NULL, /* refuse_options; */ NULL, /* secrets_file; */ NULL, /* temp_dir; */ NULL, /* uid; */ NULL, /* max_connections; */ 0, /* max_verbosity; */ 1, /* syslog_facility; */ LOG_DAEMON, /* timeout; */ 0, /* fake_super; */ False, /* forward_lookup; */ True, /* ignore_errors; */ False, /* ignore_nonreadable; */ False, /* list; */ True, /* munge_symlinks; */ (BOOL)-1, /* numeric_ids; */ (BOOL)-1, /* read_only; */ True, /* reverse_lookup; */ True, /* strict_modes; */ True, /* transfer_logging; */ False, /* use_chroot; */ True, /* write_only; */ False, } }; /* The currently configured values for all the variables. */ static all_vars Vars; /* 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; #define NUMPARAMETERS (sizeof (parm_table) / sizeof (struct parm_struct)) static struct enum_list enum_facilities[] = { #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 } }; static struct parm_struct parm_table[] = { {"address", P_STRING, P_GLOBAL,&Vars.g.bind_address, NULL,0}, {"listen backlog", P_INTEGER,P_GLOBAL,&Vars.g.listen_backlog, NULL,0}, {"motd file", P_STRING, P_GLOBAL,&Vars.g.motd_file, NULL,0}, {"pid file", P_STRING, P_GLOBAL,&Vars.g.pid_file, NULL,0}, {"port", P_INTEGER,P_GLOBAL,&Vars.g.rsync_port, NULL,0}, {"socket options", P_STRING, P_GLOBAL,&Vars.g.socket_options, NULL,0}, {"auth users", P_STRING, P_LOCAL, &Vars.l.auth_users, NULL,0}, {"charset", P_STRING, P_LOCAL, &Vars.l.charset, NULL,0}, {"comment", P_STRING, P_LOCAL, &Vars.l.comment, NULL,0}, {"dont compress", P_STRING, P_LOCAL, &Vars.l.dont_compress, NULL,0}, {"exclude from", P_STRING, P_LOCAL, &Vars.l.exclude_from, NULL,0}, {"exclude", P_STRING, P_LOCAL, &Vars.l.exclude, NULL,0}, {"fake super", P_BOOL, P_LOCAL, &Vars.l.fake_super, NULL,0}, {"filter", P_STRING, P_LOCAL, &Vars.l.filter, NULL,0}, {"forward lookup", P_BOOL, P_LOCAL, &Vars.l.forward_lookup, NULL,0}, {"gid", P_STRING, P_LOCAL, &Vars.l.gid, NULL,0}, {"hosts allow", P_STRING, P_LOCAL, &Vars.l.hosts_allow, NULL,0}, {"hosts deny", P_STRING, P_LOCAL, &Vars.l.hosts_deny, NULL,0}, {"ignore errors", P_BOOL, P_LOCAL, &Vars.l.ignore_errors, NULL,0}, {"ignore nonreadable",P_BOOL, P_LOCAL, &Vars.l.ignore_nonreadable, NULL,0}, {"include from", P_STRING, P_LOCAL, &Vars.l.include_from, NULL,0}, {"include", P_STRING, P_LOCAL, &Vars.l.include, NULL,0}, {"incoming chmod", P_STRING, P_LOCAL, &Vars.l.incoming_chmod, NULL,0}, {"list", P_BOOL, P_LOCAL, &Vars.l.list, NULL,0}, {"lock file", P_STRING, P_LOCAL, &Vars.l.lock_file, NULL,0}, {"log file", P_STRING, P_LOCAL, &Vars.l.log_file, NULL,0}, {"log format", P_STRING, P_LOCAL, &Vars.l.log_format, NULL,0}, {"max connections", P_INTEGER,P_LOCAL, &Vars.l.max_connections, NULL,0}, {"max verbosity", P_INTEGER,P_LOCAL, &Vars.l.max_verbosity, NULL,0}, {"munge symlinks", P_BOOL, P_LOCAL, &Vars.l.munge_symlinks, NULL,0}, {"name", P_STRING, P_LOCAL, &Vars.l.name, NULL,0}, {"numeric ids", P_BOOL, P_LOCAL, &Vars.l.numeric_ids, NULL,0}, {"outgoing chmod", P_STRING, P_LOCAL, &Vars.l.outgoing_chmod, NULL,0}, {"path", P_PATH, P_LOCAL, &Vars.l.path, NULL,0}, #ifdef HAVE_PUTENV {"post-xfer exec", P_STRING, P_LOCAL, &Vars.l.postxfer_exec, NULL,0}, {"pre-xfer exec", P_STRING, P_LOCAL, &Vars.l.prexfer_exec, NULL,0}, #endif {"read only", P_BOOL, P_LOCAL, &Vars.l.read_only, NULL,0}, {"refuse options", P_STRING, P_LOCAL, &Vars.l.refuse_options, NULL,0}, {"reverse lookup", P_BOOL, P_LOCAL, &Vars.l.reverse_lookup, NULL,0}, {"secrets file", P_STRING, P_LOCAL, &Vars.l.secrets_file, NULL,0}, {"strict modes", P_BOOL, P_LOCAL, &Vars.l.strict_modes, NULL,0}, {"syslog facility", P_ENUM, P_LOCAL, &Vars.l.syslog_facility, enum_facilities,0}, {"temp dir", P_PATH, P_LOCAL, &Vars.l.temp_dir, NULL,0}, {"timeout", P_INTEGER,P_LOCAL, &Vars.l.timeout, NULL,0}, {"transfer logging", P_BOOL, P_LOCAL, &Vars.l.transfer_logging, NULL,0}, {"uid", P_STRING, P_LOCAL, &Vars.l.uid, NULL,0}, {"use chroot", P_BOOL, P_LOCAL, &Vars.l.use_chroot, NULL,0}, {"write only", P_BOOL, P_LOCAL, &Vars.l.write_only, NULL,0}, {NULL, P_BOOL, P_NONE, NULL, NULL,0} }; /* Initialise the Default all_vars structure. */ static void reset_all_vars(void) { memcpy(&Vars, &Defaults, sizeof Vars); } /* Expand %VAR% references. Any unknown vars or unrecognized * syntax leaves the raw chars unchanged. */ static char *expand_vars(char *str) { char *buf, *t, *f; int bufsize; if (strchr(str, '%') == NULL) return str; bufsize = strlen(str) + 2048; if ((buf = new_array(char, bufsize+1)) == NULL) /* +1 for trailing '\0' */ out_of_memory("expand_vars"); for (t = buf, f = str; bufsize && *f; ) { if (*f == '%' && *++f != '%') { char *percent = strchr(f, '%'); if (percent) { char *val; *percent = '\0'; val = getenv(f); *percent = '%'; if (val) { int len = strlcpy(t, val, bufsize+1); if (len > bufsize) break; bufsize -= len; t += len; f = percent + 1; continue; } } f--; } *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; } /* 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, ptr) \ char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");} #define FN_GLOBAL_BOOL(fn_name, ptr) \ BOOL fn_name(void) {return *(BOOL *)(ptr);} #define FN_GLOBAL_CHAR(fn_name, ptr) \ char fn_name(void) {return *(char *)(ptr);} #define FN_GLOBAL_INTEGER(fn_name, ptr) \ int fn_name(void) {return *(int *)(ptr);} #define FN_LOCAL_STRING(fn_name, val) \ char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? 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;} FN_GLOBAL_STRING(lp_bind_address, &Vars.g.bind_address) FN_GLOBAL_STRING(lp_motd_file, &Vars.g.motd_file) FN_GLOBAL_STRING(lp_pid_file, &Vars.g.pid_file) FN_GLOBAL_STRING(lp_socket_options, &Vars.g.socket_options) FN_GLOBAL_INTEGER(lp_listen_backlog, &Vars.g.listen_backlog) FN_GLOBAL_INTEGER(lp_rsync_port, &Vars.g.rsync_port) FN_LOCAL_STRING(lp_auth_users, auth_users) FN_LOCAL_STRING(lp_charset, charset) FN_LOCAL_STRING(lp_comment, comment) FN_LOCAL_STRING(lp_dont_compress, dont_compress) FN_LOCAL_STRING(lp_exclude, exclude) FN_LOCAL_STRING(lp_exclude_from, exclude_from) FN_LOCAL_STRING(lp_filter, filter) FN_LOCAL_STRING(lp_gid, gid) FN_LOCAL_STRING(lp_hosts_allow, hosts_allow) FN_LOCAL_STRING(lp_hosts_deny, hosts_deny) FN_LOCAL_STRING(lp_include, include) FN_LOCAL_STRING(lp_include_from, include_from) FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod) FN_LOCAL_STRING(lp_lock_file, lock_file) FN_LOCAL_STRING(lp_log_file, log_file) FN_LOCAL_STRING(lp_log_format, log_format) FN_LOCAL_STRING(lp_name, name) FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod) FN_LOCAL_STRING(lp_path, path) FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec) FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec) FN_LOCAL_STRING(lp_refuse_options, refuse_options) FN_LOCAL_STRING(lp_secrets_file, secrets_file) FN_LOCAL_STRING(lp_temp_dir, temp_dir) FN_LOCAL_STRING(lp_uid, uid) FN_LOCAL_INTEGER(lp_max_connections, max_connections) FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity) FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility) FN_LOCAL_INTEGER(lp_timeout, timeout) FN_LOCAL_BOOL(lp_fake_super, fake_super) FN_LOCAL_BOOL(lp_forward_lookup, forward_lookup) FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors) FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable) FN_LOCAL_BOOL(lp_list, list) FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks) FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids) FN_LOCAL_BOOL(lp_read_only, read_only) FN_LOCAL_BOOL(lp_reverse_lookup, reverse_lookup) FN_LOCAL_BOOL(lp_strict_modes, strict_modes) FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging) FN_LOCAL_BOOL(lp_use_chroot, use_chroot) FN_LOCAL_BOOL(lp_write_only, write_only) /* 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) { if (!v) *s = NULL; else if (!(*s = strdup(v))) out_of_memory("string_set"); } /* Copy the local_vars, strdup'ing any strings. NOTE: this depends on * the structure starting with a contiguous list of the char* variables, * and having an accurate count in the LOCAL_STRING_COUNT() macro. */ static void copy_section(local_vars *psectionDest, local_vars *psectionSource) { int count = LOCAL_STRING_COUNT(); char **strings = (char**)psectionDest; memcpy(psectionDest, psectionSource, sizeof psectionDest[0]); while (count--) { if (strings[count] && !(strings[count] = strdup(strings[count]))) out_of_memory("copy_section"); } } /* 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 compare. */ static int strwicmp(char *psz1, char *psz2) { /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */ /* appropriate value. */ if (psz1 == psz2) return 0; if (psz1 == NULL) return -1; if (psz2 == NULL) return 1; /* sync the strings on first non-whitespace */ while (1) { while (isSpace(psz1)) psz1++; while (isSpace(psz2)) psz2++; if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0') 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 (strwicmp(iSECTION(i).name, name) == 0) 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 (strwicmp(parm_table[iIndex].label, parmname) == 0) 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) { if (strwicmp(parmvalue, "yes") == 0 || strwicmp(parmvalue, "true") == 0 || strwicmp(parmvalue, "1") == 0) *pb = True; else if (strwicmp(parmvalue, "no") == 0 || strwicmp(parmvalue, "False") == 0 || strwicmp(parmvalue, "0") == 0) *pb = False; 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 vars */ break; default: /* expand any %VARS% now */ parmvalue = expand_vars(parmvalue); break; } switch (parm_table[parmnum].type) { case P_BOOL: set_boolean(parm_ptr, parmvalue); break; case P_BOOLREV: set_boolean(parm_ptr, parmvalue); *(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", (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 = strwicmp(sectionname, GLOBAL_NAME) == 0; /* 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_all_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-bpc-3.1.2.1/backup.c0000664000047500004750000002175013510756407014146 0ustar craigcraig/* * Backup handling code. * * Copyright (C) 1999 Andrew Tridgell * Copyright (C) 2003-2015 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)) { rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname); unmake_file(file); #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, 0); preserve_xattrs = save_preserve_xattrs; unmake_file(file); #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-bpc-3.1.2.1/Doxyfile0000664000047500004750000001575613510756401014246 0ustar craigcraig# 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-bpc-3.1.2.1/aclocal.m40000664000047500004750000000132613510756401014364 0ustar craigcraig# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 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/socklen_t.m4]) rsync-bpc-3.1.2.1/getgroups.c0000664000047500004750000000276113510756407014721 0ustar craigcraig/* * 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-2015 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-bpc-3.1.2.1/case_N.h0000664000047500004750000000374213510756407014077 0ustar craigcraig/* * Allow an arbitrary sequence of case labels. * * Copyright (C) 2006-2015 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 segement 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 case 1: #elif !defined CASE_N_STATE_2 #define CASE_N_STATE_2 case 2: #elif !defined CASE_N_STATE_3 #define CASE_N_STATE_3 case 3: #elif !defined CASE_N_STATE_4 #define CASE_N_STATE_4 case 4: #elif !defined CASE_N_STATE_5 #define CASE_N_STATE_5 case 5: #elif !defined CASE_N_STATE_6 #define CASE_N_STATE_6 case 6: #elif !defined CASE_N_STATE_7 #define CASE_N_STATE_7 case 7: #elif !defined CASE_N_STATE_8 #define CASE_N_STATE_8 case 8: #elif !defined CASE_N_STATE_9 #define CASE_N_STATE_9 case 9: #elif !defined CASE_N_STATE_10 #define CASE_N_STATE_10 case 10: #elif !defined CASE_N_STATE_11 #define CASE_N_STATE_11 case 11: #elif !defined CASE_N_STATE_12 #define CASE_N_STATE_12 case 12: #elif !defined CASE_N_STATE_13 #define CASE_N_STATE_13 case 13: #elif !defined CASE_N_STATE_14 #define CASE_N_STATE_14 case 14: #elif !defined CASE_N_STATE_15 #define CASE_N_STATE_15 case 15: #elif !defined CASE_N_STATE_16 #define CASE_N_STATE_16 case 16: #else #error Need to add more case statements! #endif rsync-bpc-3.1.2.1/receiver.c0000664000047500004750000011243113510756407014502 0ustar craigcraig/* * Routines only used by the receiving process. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2015 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 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 always_checksum; extern int relative_paths; extern int preserve_hard_links; extern int preserve_perms; extern int preserve_xattrs; 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_len; extern int checksum_seed; extern int inplace; extern int allowed_lull; extern int delay_updates; 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; static struct bitbag *delayed_bits = NULL; static int phase = 0, redoing = 0; static flist_ndx_list batch_redo_list; /* We're either 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 (bpc_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, (char*)fname); #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, fname); } #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, OFF_T total_size, struct sum_struct *sum, int numMatchTokens, int nextToken, char *nextData, char *file_sum2) { static char file_sum1[MAX_DIGEST_LEN]; struct map_struct *mapbuf; int32 len, sum_len; OFF_T offset = 0; OFF_T offset2; int offsetDefer; char *data; int32 i; char *map = NULL; int replayTokenCnt = 0; #ifdef SUPPORT_PREALLOCATION #ifdef PREALLOCATE_NEEDS_TRUNCATE OFF_T preallocated_len = 0; #endif if (preallocate_files && fd != -1 && total_size > 0 && (!inplace || 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 (do_fallocate(fd, 0, total_size) == 0) { #ifdef PREALLOCATE_NEEDS_TRUNCATE preallocated_len = total_size; #endif } else rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname)); } #endif 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(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); } } offsetDefer = 0; while ( 1 ) { /* * We have to replay any tokens that were potentially read-ahead * to see if the file was identical. * numMatchTokens < 0 means there are no replay tokens * numMatchTokens >= 0 means there are numMatchTokens from -1 * to -numMatchTokens, followed by * (nextToken, *nextData). * * If numMatchTokens >= 0 and nextToken == 0, then then file_sum * was already ready from f_in. Otherwise, we need to read it * here. */ if ( replayTokenCnt >= 0 && numMatchTokens >= 0 ) { if ( replayTokenCnt < numMatchTokens ) { /* * replay -1, -2, ..., -numMatchTokens */ i = -replayTokenCnt - 1; replayTokenCnt++; } else { /* * replay the next token - after this we are * up to date. */ i = nextToken; data = nextData; replayTokenCnt = -1; } } else { i = recv_token(f_in, &data); } if ( i == 0 ) break; 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 ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if (fd != -1 && write_file(fd,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) { offset += len; offsetDefer = 1; continue; } } if (fd != -1 && map) { if ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if ( write_file(fd, map, len) != (int)len) goto report_write_error; } offset += len; } if ( offsetDefer ) { OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; if ((pos = do_lseek(fd, offset, SEEK_SET)) != offset) { rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f", full_fname(fname), (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } offsetDefer = 0; } if (flush_write_file(fd) < 0) goto report_write_error; #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 ((1 #ifdef PREALLOCATE_NEEDS_TRUNCATE || preallocated_len > offset #endif ) && fd != -1 && 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); if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) { report_write_error: rsyserr(FERROR_XFER, errno, "write failed on %s", full_fname(fname)); exit_cleanup(RERR_FILEIO); } sum_len = sum_end(file_sum1); if (mapbuf) unmap_file(mapbuf); if ( numMatchTokens < 0 || nextToken != 0 ) { /* * If numMatchTokens >= 0 and nextToken == 0, then the caller already * read ahead to the digest. Otherwise we have to read it here. */ read_buf(f_in, file_sum2, sum_len); } if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"got file_sum\n"); if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0) return 0; return 1; } static void discard_receive_data(int f_in, OFF_T length, struct sum_struct *sum, int numMatchTokens, int nextToken, char *nextData, char *file_sum) { receive_data(f_in, NULL, -1, 0, NULL, -1, length, sum, numMatchTokens, nextToken, nextData, file_sum); } 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_int(MSG_SUCCESS, 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[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); #if 0 /* was SUPPORT_ACLS */ const char *parent_dirname = ""; #endif int ndx, recv_ok; 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); while (1) { struct sum_struct sum; int numMatchTokens = -1, nextToken = 0; char *nextData = NULL; static char file_sum[MAX_DIGEST_LEN]; 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 && INFO_GTE(PROGRESS, 2) && cur_flist) { set_current_file_index(NULL, 0); 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); #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 && INFO_GTE(PROGRESS, 1)) set_current_file_index(file, ndx); stats.xferred_files++; stats.total_transferred_size += F_LENGTH(file); cleanup_got_literal = 0; if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) { rprintf(FERROR, "attempt to hack rsync failed.\n"); exit_cleanup(RERR_PROTOCOL); } read_sum_head(f_in, &sum); 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, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); 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, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); continue; } if (write_batch < 0) { log_item(FCLIENT, file, iflags, NULL); if (!am_server) discard_receive_data(f_in, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); if (inc_recurse) send_msg_int(MSG_SUCCESS, 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, fname, 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; } /* * Opening/reading/writing files in BackupPC is quite expensive, given the * compression. Before we open the file and call mkstemp, we peek ahead at * the delta tokens to see if the file is unchanged. If so, we skip the file * open, mkstemp and writing. The file is unchanged if the tokens * are sequential matching block numbers, which are encoded as * negative integers (ie: -1, -2, -3...), with no literal data * tokens (which have positive numbers). * * If the file has changed, at some point a matching block token * will be out of order, or we will encounter a literal data token. * At that point, we stop reading ahead and proceed as normal. * We pass the number of matching block tokens, and the first * unexpected token, to receive_data(), so it can process all * the tokens back (basically playing them back). * * Of course, this only applies if the file exists already, * and protocol_version 30 is required since older protocols * use MD4 for the full-file digest, not MD5. * * First we need to read the sum struct, then start reading the * tokens. */ recv_ok = 0; if ( protocol_version >= 30 ) { numMatchTokens = 0; while ( (nextToken = recv_token(f_in, &nextData)) != 0 ) { if ( nextToken != -numMatchTokens - 1 ) break; numMatchTokens++; } if ( nextToken == 0 ) { OFF_T flength = (OFF_T)numMatchTokens * sum.blength; if ( sum.remainder && numMatchTokens > 0 ) flength -= sum.blength - sum.remainder; /* * Likely exact match - read the final file digest and make * sure the digest and file size match the existing file. * If so, this call creates the temporary file so the * attributes can be checked/set, and then renamed as * before. */ read_buf(f_in, file_sum, MD5_DIGEST_LEN); if ( !bpc_sysCall_checkFileMatch(fnamecmp, fnametmp, file, file_sum, flength) ) { recv_ok = 1; if ( log_before_transfer ) { iflags &= ~ITEM_REPORT_CHANGE; log_item(FCLIENT, file, iflags, NULL); } } } } if ( !recv_ok ) { /* * proceed as normal, remembering to replay the tokens we read ahead above: * first, numMatchTokens: -1, -2, ..., -numMatchTokens, * then (nextToken,nextData). After that we go back to reading the * remaining tokens from f_in. */ /* open the file */ fd1 = do_open(fnamecmp, O_RDONLY, 0); if ( fd1 < 0 && protocol_version >= 30 && always_checksum ) { /* * For protocol_version >= 30 and if always_checksum is set, we can use the * MD5 whole-file digest to check for a potential match via the pool. * Use that as the basis if the file is there. The generator does * the same in recv_generator(). */ if ( S_ISREG(file->mode) && !bpc_sysCall_poolFileCheck(fnamecmp, file) ) { fd1 = do_open(fnamecmp, O_RDONLY, 0); } } if (fd1 == -1 && protocol_version < 29) { if (fnamecmp != fname) { 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; fd1 = do_open(fnamecmp, O_RDONLY, 0); } } updating_basis_or_equiv = 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, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); bpc_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, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); bpc_close(fd1); if (inc_recurse) send_msg_int(MSG_NO_SEND, ndx); continue; } if (fd1 != -1 && !S_ISREG(st.st_mode)) { bpc_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; #if 0 /* was 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) { fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600); if (fd2 == -1) { rsyserr(FERROR_XFER, errno, "open %s failed", full_fname(fname)); } else if (updating_basis_or_equiv) cleanup_set(NULL, NULL, file, fd1, fd2); } else { fd2 = open_tmpfile(fnametmp, fname, file); if (fd2 != -1) cleanup_set(fnametmp, partialptr, file, fd1, fd2); } if (fd2 == -1) { discard_receive_data(f_in, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); if (fd1 != -1) bpc_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, F_LENGTH(file), &sum, numMatchTokens, nextToken, nextData, file_sum); log_item(log_code, file, iflags, NULL); if (fd1 != -1) bpc_close(fd1); if (bpc_close(fd2) < 0) { rsyserr(FERROR, errno, "close failed on %s", full_fname(fnametmp)); exit_cleanup(RERR_FILEIO); } } log_item(log_code, file, iflags, NULL); 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) { do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); } } else if (keep_partial && partialptr) { 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 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_int(MSG_SUCCESS, ndx); break; case 0: { enum logcode msgtype = redoing ? FERROR_XFER : FWARNING; if (msgtype == FERROR_XFER || INFO_GTE(NAME, 1)) { 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; bpc_sysCall_printfileStatus(fname, "retry"); } else if (inc_recurse) { send_msg_int(MSG_NO_SEND, ndx); bpc_sysCall_printfileStatus(fname, "fail"); } 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-bpc-3.1.2.1/clientname.c0000664000047500004750000002230513510756407015015 0ustar craigcraig/* * 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-2015 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" static const char default_name[] = "UNKNOWN"; extern int am_server; /** * Return the IP addr of the client as a string **/ char *client_addr(int fd) { static char addr_buf[100]; static int initialised; struct sockaddr_storage ss; socklen_t length = sizeof ss; if (initialised) return addr_buf; initialised = 1; if (am_server) { /* daemon over --rsh mode */ char *env_str; strlcpy(addr_buf, "0.0.0.0", sizeof addr_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(addr_buf, env_str, sizeof addr_buf); /* Truncate the value to just the IP address. */ if ((p = strchr(addr_buf, ' ')) != NULL) *p = '\0'; } } else { client_sockaddr(fd, &ss, &length); getnameinfo((struct sockaddr *)&ss, length, addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST); } return addr_buf; } static int get_sockaddr_family(const struct sockaddr_storage *ss) { return ((struct sockaddr *) ss)->sa_family; } /** * 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(int fd) { static char name_buf[100]; static char port_buf[100]; static int initialised; struct sockaddr_storage ss; socklen_t ss_len; if (initialised) return name_buf; strlcpy(name_buf, default_name, sizeof name_buf); initialised = 1; memset(&ss, 0, sizeof ss); if (am_server) { /* daemon over --rsh mode */ char *addr = client_addr(fd); struct addrinfo hint, *answer; int err; if (strcmp(addr, "0.0.0.0") == 0) return name_buf; memset(&hint, 0, sizeof hint); #ifdef AI_NUMERICHOST hint.ai_flags = AI_NUMERICHOST; #endif hint.ai_socktype = SOCK_STREAM; if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) { rprintf(FLOG, "malformed address %s: %s\n", addr, 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: exit_cleanup(RERR_SOCKETIO); } freeaddrinfo(answer); } else { ss_len = sizeof ss; client_sockaddr(fd, &ss, &ss_len); } if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf) == 0) check_name(fd, &ss, name_buf, sizeof name_buf); return name_buf; } /** * 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. **/ 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 } /** * Look up a name from @p ss into @p name_buf. * * @param fd file descriptor for client socket. **/ int lookup_name(int fd, const struct sockaddr_storage *ss, socklen_t ss_len, char *name_buf, size_t name_buf_size, char *port_buf, size_t port_buf_size) { int name_err; /* reverse lookup */ name_err = getnameinfo((struct sockaddr *) ss, ss_len, name_buf, name_buf_size, port_buf, port_buf_size, NI_NAMEREQD | NI_NUMERICSERV); if (name_err != 0) { strlcpy(name_buf, default_name, name_buf_size); rprintf(FLOG, "name lookup failed for %s: %s\n", client_addr(fd), gai_strerror(name_err)); return name_err; } return 0; } /** * Compare an addrinfo from the resolver to a sockinfo. * * Like strcmp, returns 0 for identical. **/ 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 < 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. **/ int check_name(int fd, 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", client_addr(fd), name_buf); strlcpy(name_buf, default_name, name_buf_size); } freeaddrinfo(res0); return 0; } rsync-bpc-3.1.2.1/delete.c0000664000047500004750000001455013510756407014143 0ustar craigcraig/* * Deletion routines used in rsync. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2015 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-bpc-3.1.2.1/connection.c0000664000047500004750000000245613510756401015034 0ustar craigcraig/* * Support the max connections option. * * Copyright (C) 1998 Andrew Tridgell * * 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-bpc-3.1.2.1/clientserver.c0000664000047500004750000007570213510756407015414 0ustar craigcraig/* * 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-2015 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 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 rsync_port; extern int protect_args; extern int ignore_errors; extern int preserve_xattrs; extern int kluge_around_eof; extern int daemon_over_rsh; extern int munge_symlinks; 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 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 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 char *auth_user; int read_only = 0; int module_id = -1; struct chmod_mode_struct *daemon_chmod_modes; /* 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; #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; #if SUBPROTOCOL_VERSION != 0 int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; #else int our_sub = 0; #endif char *motd; io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub); if (!am_client) { 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: server is speaking an incompatible beta of protocol 30\n"); else io_printf(f_out, "@ERROR: your client is speaking an incompatible beta of protocol 30\n"); return -1; } remote_sub = 0; } 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; if (!(modname = new_array(char, modlen+1+1))) /* room for '/' & '\0' */ out_of_memory("start_inband_exchange"); 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; /* set daemon_over_rsh to false since we need to build the * true set of args passed through the rsh/ssh connection; * this is a no-op for direct-socket-connection mode */ daemon_over_rsh = 0; server_options(sargs, &sargc); if (sargc >= MAX_ARGS - 2) goto arg_overflow; sargs[sargc++] = "."; 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 if (**argv == '-') { if (asprintf(sargs + sargc++, "./%s", *argv) < 0) out_of_memory("start_inband_exchange"); } else sargs[sargc++] = *argv; 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 --protect-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; } static char *finish_pre_exec(pid_t pid, int write_fd, int read_fd, char *request, char **early_argv, char **argv) { char buf[BIGPATHBUFLEN], *bp; int j = 0, status = -1, msglen = sizeof buf - 1; 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. */ } for ( ; argv[j]; j++) write_buf(write_fd, argv[j], strlen(argv[j])+1); write_byte(write_fd, 0); close(write_fd); /* Read the stdout from the pre-xfer exec program. This it is only * displayed to the user if the script also returns an error status. */ for (bp = 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; if (j > 1 && bp[-1] == '\n' && bp[-2] == '\r') { bp--; j--; bp[-1] = '\n'; } } *bp = '\0'; close(read_fd); if (wait_process(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { char *e; if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s%s\n%s", status, status < 0 ? ": " : "", status < 0 ? strerror(errno) : "", *buf ? ":" : "", buf) < 0) return "out_of_memory in finish_pre_exec\n"; return e; } return NULL; } #ifdef 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 static int path_failure(int f_out, const char *dir, BOOL was_chdir) { if (was_chdir) rsyserr(FLOG, errno, "chdir %s failed\n", 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 void set_env_str(const char *var, const char *str) { #ifdef HAVE_PUTENV char *mem; if (asprintf(&mem, "%s=%s", var, str) < 0) out_of_memory("set_env_str"); putenv(mem); #endif } #ifdef HAVE_PUTENV static void set_env_num(const char *var, long num) { char *mem; if (asprintf(&mem, "%s=%ld", var, num) < 0) out_of_memory("set_env_num"); putenv(mem); } #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); 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(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 && am_server) { 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(i) && !logfile_format) logfile_format = lp_log_format(i); 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 == 0); p = *lp_uid(i) ? lp_uid(i) : 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(i) ? strtok(lp_gid(i), ", ") : 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 = 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(i); 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) { 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(i); parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3); p = lp_include_from(i); 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(i); 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(i); 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(i); parse_filter_str(&daemon_filter_list, p, rule_template(FILTRULE_WORD_SPLIT), XFLG_ABS_IF_SLASH | XFLG_DIR2WILD3 | XFLG_OLD_PREFIXES); log_init(1); #ifdef HAVE_PUTENV if (*lp_prexfer_exec(i) || *lp_postxfer_exec(i)) { int status; /* 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(i)) { pid_t pid = fork(); if (pid < 0) { rsyserr(FLOG, errno, "fork failed"); io_printf(f_out, "@ERROR: fork failed\n"); return -1; } if (pid) { close(f_in); if (f_out != f_in) close(f_out); set_env_num("RSYNC_PID", (long)pid); 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 (system(lp_postxfer_exec(i)) < 0) status = -1; _exit(status); } } /* 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(i)) { int arg_fds[2], error_fds[2]; set_env_num("RSYNC_PID", (long)getpid()); if (pipe(arg_fds) < 0 || pipe(error_fds) < 0 || (pre_exec_pid = fork()) < 0) { rsyserr(FLOG, errno, "pre-xfer exec preparation failed"); io_printf(f_out, "@ERROR: pre-xfer exec preparation failed\n"); return -1; } if (pre_exec_pid == 0) { char buf[BIGPATHBUFLEN]; int j, len; close(arg_fds[1]); close(error_fds[0]); pre_exec_arg_fd = arg_fds[0]; pre_exec_error_fd = error_fds[1]; set_blocking(pre_exec_arg_fd); set_blocking(pre_exec_error_fd); len = read_arg_from_pipe(pre_exec_arg_fd, buf, BIGPATHBUFLEN); if (len <= 0) _exit(1); set_env_str("RSYNC_REQUEST", buf); for (j = 0; ; j++) { len = read_arg_from_pipe(pre_exec_arg_fd, buf, BIGPATHBUFLEN); if (len <= 0) { if (!len) break; _exit(1); } if (asprintf(&p, "RSYNC_ARG%d=%s", j, buf) >= 0) putenv(p); } close(pre_exec_arg_fd); close(STDIN_FILENO); dup2(pre_exec_error_fd, STDOUT_FILENO); close(pre_exec_error_fd); status = system(lp_prexfer_exec(i)); if (!WIFEXITED(status)) _exit(1); _exit(WEXITSTATUS(status)); } close(arg_fds[0]); close(error_fds[1]); pre_exec_arg_fd = arg_fds[1]; pre_exec_error_fd = error_fds[0]; set_blocking(pre_exec_arg_fd); set_blocking(pre_exec_error_fd); } } #endif if (use_chroot) { /* * XXX: The 'use chroot' flag is a fairly reliable * source of confusion, because it fails under two * important circumstances: running as non-root, * running on Win32 (or possibly others). On the * other hand, if you are running as root, then it * might be better to always use chroot. * * So, perhaps if we can't chroot we should just issue * a warning, unless a "require chroot" flag is set, * in which case we fail. */ 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 || !use_chroot) sanitize_paths = 1; if ((munge_symlinks = lp_munge_symlinks(i)) < 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 } 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; } am_root = (MY_UID() == 0); } if (lp_temp_dir(i) && *lp_temp_dir(i)) { tmpdir = lp_temp_dir(i); 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; munge_symlinks = save_munge_symlinks; /* The client mustn't control this. */ if (pre_exec_pid) { err_msg = finish_pre_exec(pre_exec_pid, pre_exec_arg_fd, pre_exec_error_fd, request, orig_early_argv, orig_argv); } 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(i)) { 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(i)); #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); } 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(i) != False : lp_numeric_ids(i) == True)) numeric_ids = -1; /* Set --numeric-ids w/o breaking protocol. */ if (lp_timeout(i) && (!io_timeout || lp_timeout(i) < io_timeout)) set_io_timeout(lp_timeout(i)); /* 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(i); else p = lp_incoming_chmod(i); 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; } /* 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_server && 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; int i; 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); addr = client_addr(f_in); host = lp_reverse_lookup(-1) ? client_name(f_in) : undetermined_hostname; rprintf(FLOG, "connect from %s (%s)\n", host, addr); if (!am_server) { 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 (!*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[16]; pid_t pid = getpid(); int fd, len; if (!pid_file || !*pid_file) return; cleanup_set_pid(pid); if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) { failure: cleanup_set_pid(0); fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno)); rsyserr(FLOG, errno, "failed to create pid file %s", pid_file); exit_cleanup(RERR_FILEIO); } snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid); len = strlen(pidbuf); if (write(fd, pidbuf, len) != len) goto failure; close(fd); } /* 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-bpc-3.1.2.1/m4/0000775000047500004750000000000013510756407013050 5ustar craigcraigrsync-bpc-3.1.2.1/m4/have_type.m40000664000047500004750000000115713510756401015274 0ustar craigcraigdnl AC_HAVE_TYPE(TYPE,INCLUDES) AC_DEFUN([AC_HAVE_TYPE], [ AC_REQUIRE([AC_HEADER_STDC]) 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-bpc-3.1.2.1/m4/socklen_t.m40000664000047500004750000000307013510756407015273 0ustar craigcraigdnl 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_TRY_COMPILE([ #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-bpc-3.1.2.1/m4/validate_cache_system_type.m40000664000047500004750000000167713510756401020700 0ustar craigcraigdnl 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-bpc-3.1.2.1/params.c0000664000047500004750000005352513510756401014163 0ustar craigcraig/* 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 stipped 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 ); if( NULL == bufr ) { rprintf(FLOG, "%s Memory re-allocation failure.", func); return( False ); } } /* 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 ); if( NULL == bufr ) { rprintf(FLOG, "%s Memory re-allocation failure.", func) ; return( False ); } } 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 ); if( NULL == bufr ) { rprintf(FLOG, "%s Memory re-allocation failure.", func) ; return( False ); } } 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 ); if( NULL == bufr ) { rprintf(FLOG, "%s memory allocation failure.\n", func); fclose(InFile); return( False ); } 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-bpc-3.1.2.1/INSTALL0000664000047500004750000000470313510756401013557 0ustar craigcraigTo build and install rsync: $ ./configure $ make # make install You may set the installation directory and other parameters by 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. 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 OSX NOTES ------------- Some versions of Mac OS X (Darwin) seem to have an IPv6 stack, but do not completely implement the "New Sockets" API. says that Apple started to support IPv6 in 10.2 (Jaguar). If your build fails, try again after running configure with --disable-ipv6. IBM AIX NOTES ------------- IBM AIX has a largefile problem with mkstemp. See IBM PR-51921. The workaround is to append the below to config.h #ifdef _LARGE_FILES #undef HAVE_SECURE_MKSTEMP #endif rsync-bpc-3.1.2.1/doc/0000775000047500004750000000000013510756401013267 5ustar craigcraigrsync-bpc-3.1.2.1/doc/README-SGML0000664000047500004750000000124013510756401014704 0ustar craigcraigHandling 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-bpc-3.1.2.1/doc/profile.txt0000664000047500004750000000361713510756401015477 0ustar craigcraigNotes 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-bpc-3.1.2.1/doc/rsync.sgml0000664000047500004750000002710313510756401015314 0ustar craigcraig 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 ommitted 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-bpc-3.1.2.1/match.c0000664000047500004750000003073613510756407014001 0ustar craigcraig/* * Block matching used by the file-transfer code. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2015 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 int checksum_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); if (!hash_table) out_of_memory("build_hash_table"); 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(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); } if (sum_end(sender_file_sum) != checksum_len) overflow_exit("checksum_len"); /* Impossible... */ /* 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 < checksum_len && sender_file_sum[i] == 0; i++) {} memset(sender_file_sum, 0, checksum_len); if (i == checksum_len) sender_file_sum[i-1]++; } if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"sending file_sum\n"); write_buf(f, sender_file_sum, checksum_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-bpc-3.1.2.1/NEWS0000664000047500004750000000446613510756407013241 0ustar craigcraigNEWS for rsync-bpc 3.1.2. 3.1.2.1 released 8 Jul 2019: - fix to use correct int format when reading v3 attrib files - allow mtime to be signed in attrib files - remove any extraneous BPC_FTYPE_DELETED file types in non-merged backup 3.1.2.0 released 1 Dec 2018. 28 Dec 2017: initial beta version based on rsync 3.1.2 (not released) NEWS for rsync 3.1.2 (21 Dec 2015) Protocol: 31 (unchanged) Changes since 3.1.1: 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. rsync-bpc-3.1.2.1/rsync.h0000664000047500004750000011042713510756407014044 0ustar craigcraig/* * Copyright (C) 1996, 2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2015 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 BLOCK_SIZE 700 #define RSYNC_RSH_ENV "RSYNC_RSH" #define RSYNC_RSH_IO_ENV "RSYNC_RSH_IO" #define RSYNC_NAME "rsync_bpc" /* 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 */ #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 */ /* 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 */ /* These flags are for get_dirlist(). */ #define GDL_IGNORE_FILTER_RULES (1<<0) /* 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 */ #define PROTOCOL_VERSION 31 /* This is used when working on a new protocol version in CVS, and should * be a new non-zero value for each CVS change that affects the protocol. * It must ALWAYS be 0 when the protocol goes final (and NEVER before)! */ #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 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 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_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 */ MSG_RENAME=104 /* rename request sent from the recevier to generator */ }; #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" /* * Override some config.h settings, based on what is supported in bpc_sysCalls.c * Special for BackupPC */ #define SUPPORT_XATTRS 1 #define HAVE_LINUX_XATTRS 1 #undef HAVE_FREEBSD_XATTRS #undef HAVE_OSX_XATTRS #undef NO_DEVICE_XATTRS #undef NO_SPECIAL_XATTRS #undef NO_SYMLINK_XATTRS #define SUPPORT_HARD_LINKS 1 #define SUPPORT_LINKS 1 #define CAN_HARDLINK_SYMLINK 1 #define CAN_HARDLINK_SPECIAL 1 #define HAVE_CHMOD 1 #define HAVE_LCHMOD 1 #define HAVE_FTRUNCATE 1 #undef HAVE_SETMODE #define HAVE_SECURE_MKSTEMP 1 #undef HAVE_UTIMENSAT #define HAVE_LUTIMES 1 #undef HAVE_UTIMES #define HAVE_LUTIME 1 /* 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_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 TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #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 #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 #ifdef HAVE_UTIMENSAT #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC #define ST_MTIME_NSEC st_mtim.tv_nsec #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) #define ST_MTIME_NSEC st_mtimensec #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 #include #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 #define MAKEDEV(devmajor,devminor) makedev(devmajor,devminor) #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 /* 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 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 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 0 #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 union file_extras { int32 num; uint32 unum; }; 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 */ const char basename[1]; /* The basename (AKA filename) follows */ }; extern int file_extra_cnt; extern int inc_recurse; extern int uid_ndx; extern int gid_ndx; extern int acls_ndx; extern int xattrs_ndx; #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) #define EXTRA_LEN (sizeof (union file_extras)) #define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN) #define DEV_EXTRA_CNT 2 #define DIRNODE_EXTRA_CNT 3 #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) #define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx)) #define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump)) #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_LENGTH(f) ((int64)(f)->len32 + ((f)->flags & FLAG_LENGTH64 \ ? (int64)OPT_EXTRA(f, NSEC_BUMP(f))->unum << 32 : 0)) #endif #define F_MOD_NSEC(f) ((f)->flags & FLAG_MOD_NSEC ? OPT_EXTRA(f, 0)->unum : 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: */ #define F_PATHNAME(f) (*(const char**)REQ_EXTRA(f, PTR_EXTRA_CNT)) /* The receiving side always has this available: */ #define F_DEPTH(f) REQ_EXTRA(f, 1)->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 /* 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 * 1024) #define FLIST_LINEAR (FLIST_START * 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 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 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; } 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; char fname[1]; /* has variable size */ } relnamecache; #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; #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) #include "proto.h" #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)) #define PRESERVE_FILE_TIMES (1<<0) #define PRESERVE_DIR_TIMES (1<<1) #define PRESERVE_LINK_TIMES (1<<2) /* 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):"") /* Convenient wrappers for malloc and realloc. Use them. */ #define new(type) ((type*)malloc(sizeof (type))) #define new0(type) ((type*)calloc(1, sizeof (type))) #define new_array(type, num) ((type*)_new_array((num), sizeof (type), 0)) #define new_array0(type, num) ((type*)_new_array((num), sizeof (type), 1)) #define realloc_array(ptr, type, num) ((type*)_realloc_array((ptr), sizeof(type), (num))) /* 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_PROGRESS (INFO_NAME+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_OWN (DEBUG_IO+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 rsync-bpc-3.1.2.1/README0000664000047500004750000001113213510756401013400 0ustar craigcraigWHAT IS RSYNC-BPC? ------------------ Rsync-bpc is a customized version of rsync that is used as part of BackupPC, an open source backup system. The main change to rsync is adding a shim layer (in the subdirectory backuppc, and in bpc_sysCalls.c) that emulates the system calls for accessing the file system so that rsync can directly read/write files in BackupPC's format. Rsync-bpc is fully line-compatible with vanilla rsync, so it can talk to rsync servers and clients. Rsync-bpc serves no purpose outside of BackupPC. WHAT 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 for more detailed information. 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) man page for details on how to setup an rsync daemon. See the rsync(1) man page for info on how to connect to an rsync daemon. WEB SITE -------- The main rsync web site is here: http://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 for full details: http://rsync.samba.org/lists.html BUG REPORTS ----------- To visit this web page for full the details on bug reporting: http://rsync.samba.org/bugzilla.html That page contains links to the current bug list, and information on how to report a bug well. You might also like to try searching the Internet for the error message you've received, or looking in the mailing list archives at: http://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 rsync@lists.samba.org . GIT REPOSITORY -------------- If you want to get the very latest version of rsync direct from the source code repository then you can use git: git clone git://git.samba.org/rsync.git See the download page for full details on all the ways to grab the source, including nightly tar files, web-browsing of the git repository, etc.: http://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 in this distribution, or at: http://www.fsf.org/licenses/gpl.html AVAILABILITY ------------ The main web site for rsync is http://rsync.samba.org/ The main ftp site is ftp://rsync.samba.org/pub/rsync/ This is also available as rsync://rsync.samba.org/rsyncftp/ rsync-bpc-3.1.2.1/tls.c0000664000047500004750000001561513510756407013506 0ustar craigcraig/* * Trivial ls for comparing two directories after running an rsync. * * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2003-2015 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; int preserve_perms = 0; int preserve_executability = 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) { int mode, 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 void failed(char const *what, char const *where) { fprintf(stderr, PROGRAM ": %s %s: %s\n", what, where, strerror(errno)); exit(1); } static void list_file(const char *fname) { STRUCT_STAT buf; char permbuf[PERMSTRING_SIZE]; struct tm *mt; char datebuf[50]; char linkbuf[4096]; if (do_lstat(fname, &buf) < 0) failed("stat", fname); #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); if (buf.st_mtime) { int len; mt = gmtime(&buf.st_mtime); len = snprintf(datebuf, sizeof datebuf, "%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); #ifdef ST_MTIME_NSEC if (nsec_times) { snprintf(datebuf + len, sizeof datebuf - len, ".%09d", (int)buf.ST_MTIME_NSEC); } #endif } else { int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1); memset(datebuf, ' ', len); datebuf[len] = '\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\n", (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink, datebuf, fname, linkbuf); } static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ {"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 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," -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-bpc-3.1.2.1/inums.h0000664000047500004750000000271613510756407014042 0ustar craigcraig/* Inline functions for rsync. * * Copyright (C) 2008-2015 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-bpc-3.1.2.1/wildtest.c0000664000047500004750000001277713510756407014551 0ustar craigcraig/* * Test suite for the wildmatch code. * * Copyright (C) 2003-2015 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-bpc-3.1.2.1/packaging/0000775000047500004750000000000013510756401014446 5ustar craigcraigrsync-bpc-3.1.2.1/packaging/release-rsync0000775000047500004750000003162113510756401017153 0ustar craigcraig#!/usr/bin/perl # 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. use strict; use warnings; use Cwd; use Getopt::Long; use Term::ReadKey; use Date::Format; my $dest = $ENV{HOME} . '/samba-rsync-ftp'; my $passfile = $ENV{HOME} . '/.rsyncpass'; my $path = $ENV{PATH}; my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen'; &Getopt::Long::Configure('bundling'); &usage if !&GetOptions( 'branch|b=s' => \( my $master_branch = 'master' ), 'help|h' => \( my $help_opt ), ); &usage if $help_opt; my $now = time; my $cl_today = time2str('* %a %b %d %Y', $now); my $year = time2str('%Y', $now); my $ztoday = time2str('%d %b %Y', $now); (my $today = $ztoday) =~ s/^0//; my $curdir = Cwd::cwd; END { unlink($passfile); } my @extra_files; open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n"; while () { if (s/^GENFILES=//) { while (s/\\$//) { $_ .= ; } @extra_files = split(' ', $_); last; } } close IN; my $break = <) { if (/^AC_INIT\(\[rsync\],\s*\[(\d.+?)\]/) { $confversion = $1; last; } } close IN; die "Unable to find AC_INIT with version in configure.ac\n" unless defined $confversion; open(IN, '<', 'OLDNEWS') or die $!; $_ = ; my($lastversion) = /(\d+\.\d+\.\d+)/; my($last_protocol_version, %pdate); while () { if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) { $pdate{$ver} = $pdate if defined $pdate; $last_protocol_version = $pver if $ver eq $lastversion; } } close IN; die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version; my $protocol_version; open(IN, '<', 'rsync.h') or die $!; while () { if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) { $protocol_version = $1; last; } } close IN; die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version; my $version = $confversion; $version =~ s/dev/pre1/ || $version =~ s/pre(\d+)/ 'pre' . ($1 + 1) /e; print "Please enter the version number of this release: [$version] "; chomp($_ = ); if ($_ eq '.') { $version =~ s/pre\d+//; } elsif ($_ ne '') { $version = $_; } die "Invalid version: `$version'\n" unless $version =~ /^[\d.]+(pre\d+)?$/; if (`git tag -l v$version` ne '') { print "Tag v$version already exists.\n\nDelete tag or quit? [q/del] "; $_ = ; exit 1 unless /^del/i; system "git tag -d v$version"; } if ($version =~ s/[-.]*pre[-.]*/pre/ && $confversion !~ /dev$/) { $lastversion = $confversion; } print "Enter the previous version to produce a patch against: [$lastversion] "; chomp($_ = ); $lastversion = $_ if $_ ne ''; $lastversion =~ s/[-.]*pre[-.]*/pre/; my $pre = $version =~ /(pre\d+)/ ? $1 : ''; my $release = $pre ? '0.1' : '1'; print "Please enter the RPM release number of this release: [$release] "; chomp($_ = ); $release = $_ if $_ ne ''; $release .= ".$pre" if $pre; (my $finalversion = $version) =~ s/pre\d+//; my($proto_changed,$proto_change_date); if ($protocol_version eq $last_protocol_version) { $proto_changed = 'unchanged'; $proto_change_date = "\t\t"; } else { $proto_changed = 'changed'; if (!defined($proto_change_date = $pdate{$finalversion})) { while (1) { print "On what date did the protocol change to $protocol_version get checked in? (dd Mmm yyyy) "; chomp($_ = ); last if /^\d\d \w\w\w \d\d\d\d$/; } $proto_change_date = "$_\t"; } } my($srcdir,$srcdiffdir,$lastsrcdir,$skipping); if ($lastversion =~ /pre/) { if (!$pre) { die "You should not diff a release version against a pre-release version.\n"; } $srcdir = $srcdiffdir = $lastsrcdir = 'src-previews'; $skipping = ' ** SKIPPING **'; } elsif ($pre) { $srcdir = $srcdiffdir = 'src-previews'; $lastsrcdir = 'src'; $skipping = ' ** SKIPPING **'; } else { $srcdir = $lastsrcdir = 'src'; $srcdiffdir = 'src-diffs'; $skipping = ''; } print "\n", $break, < "; $_ = ; my %specvars = ( 'Version:' => $finalversion, 'Release:' => $release, '%define fullversion' => "\%{version}$pre", 'Released' => "$version.", '%define srcdir' => $srcdir ); my @tweak_files = ( glob('packaging/*.spec'), glob('packaging/*/*.spec'), glob('*.yo'), qw( configure.ac rsync.h NEWS OLDNEWS options.c ) ); foreach my $fn (@tweak_files) { open(IN, '<', $fn) or die $!; undef $/; $_ = ; $/ = "\n"; close IN; if ($fn =~ /configure/) { s/^(AC_INIT\(\[rsync\],\s*\[)\d.+?(\])/$1$version$2/m or die "Unable to update AC_INIT with version in $fn\n"; } elsif ($fn =~ /\.spec/) { while (my($str, $val) = each %specvars) { s/^\Q$str\E .*/$str $val/m or die "Unable to update $str in $fn\n"; } s/^\* \w\w\w \w\w\w \d\d \d\d\d\d (.*)/$cl_today $1/m or die "Unable to update ChangeLog header in $fn\n"; } elsif ($fn =~ /\.yo/) { s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m or die "Unable to update date in manpage() header in $fn\n"; s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m or die "Unable to update current version info in $fn\n"; } elsif ($fn eq 'rsync.h') { s{(#define\s+SUBPROTOCOL_VERSION)\s+(\d+)} { $1 . ' ' . get_subprotocol_version($2) }e or die "Unable to find SUBPROTOCOL_VERSION define in $fn\n"; } elsif ($fn eq 'NEWS') { s{^(NEWS for rsync \Q$finalversion\E )(\(UNRELEASED\))\s*(\nProtocol: )(\d+) (\([^)]+\))\n} { $1 . ($pre ? $2 : "($today)") . "$3$protocol_version ($proto_changed)\n" }ei or die "The first 2 lines of $fn are not in the right format. They must be:\n" . "NEWS for rsync $finalversion (UNRELEASED)\n" . "Protocol: $protocol_version ($proto_changed)\n"; } elsif ($fn eq 'OLDNEWS') { s{^(\t\S\S\s\S\S\S\s\d\d\d\d)(\t\Q$finalversion\E\t).*} { ($pre ? $1 : "\t$ztoday") . $2 . $proto_change_date . $protocol_version }em or die "Unable to find \"?? ??? $year\t$finalversion\" line in $fn\n"; } elsif ($fn eq 'options.c') { if (s/(Copyright \(C\) 2002-)(\d+)( Wayne Davison)/$1$year$3/ && $2 ne $year) { die "Copyright comments need to be updated to $year in all files!\n"; } # Adjust the year in the --version output. s/(rprintf\(f, "Copyright \(C\) 1996-)(\d+)/$1$year/ or die "Unable to find Copyright string in --version output of $fn\n"; next if $2 eq $year; } else { die "Unrecognized file in \@tweak_files: $fn\n"; } open(OUT, '>', $fn) or die $!; print OUT $_; close OUT; } print $break; system "git diff --color | less -p '^diff .*'"; my $srctar_name = "rsync-$version.tar.gz"; my $pattar_name = "rsync-patches-$version.tar.gz"; my $diff_name = "rsync-$lastversion-$version.diffs.gz"; my $srctar_file = "$dest/$srcdir/$srctar_name"; my $pattar_file = "$dest/$srcdir/$pattar_name"; my $diff_file = "$dest/$srcdiffdir/$diff_name"; my $news_file = "$dest/$srcdir/rsync-$version-NEWS"; my $lasttar_file = "$dest/$lastsrcdir/rsync-$lastversion.tar.gz"; print $break, < "; my $ans = ; system "git commit -a -m 'Preparing for release of $version'" and exit 1; print "Updating files in \"patches\" dir ...\n"; system "packaging/patch-update --branch=$master_branch"; if ($ans =~ /^y/i) { print "\nVisiting all \"patch/$master_branch/*\" branches ...\n"; system "packaging/patch-update --branch=$master_branch --skip-check --shell"; } if (-d 'patches/.git') { system "cd patches && git commit -a -m 'The patches for $version.'" and exit 1; } print $break, < "; $_ = ; # We want to use our passphrase-providing "gpg" script, so modify the PATH. $ENV{PATH} = "$curdir/packaging/bin:$path"; my $passphrase; while (1) { ReadMode('noecho'); print "\nEnter your GPG pass-phrase: "; chomp($passphrase = ); ReadMode(0); print "\n"; # Briefly create a temp file with the passphrase for git's tagging use. my $oldmask = umask 077; unlink($passfile); open(OUT, '>', $passfile) or die $!; print OUT $passphrase, "\n"; close OUT; umask $oldmask; $ENV{'GPG_PASSFILE'} = $passfile; $_ = `git tag -s -m 'Version $version.' v$version 2>&1`; print $_; next if /bad passphrase/; exit 1 if /failed/; if (-d 'patches/.git') { $_ = `cd patches && git tag -s -m 'Version $version.' v$version 2>&1`; print $_; exit 1 if /bad passphrase|failed/; } unlink($passfile); last; } $ENV{PATH} = $path; # Extract the generated files from the old tar. @_ = @extra_files; map { s#^#rsync-$lastversion/# } @_; system "tar xzf $lasttar_file @_"; rename("rsync-$lastversion", 'a'); print "Creating $diff_file ...\n"; system "$make_gen_cmd && rsync -a @extra_files b/" and exit 1; my $sed_script = 's:^((---|\+\+\+) [ab]/[^\t]+)\t.*:\1:'; system "(git diff v$lastversion v$version; diff -upN a b | sed -r '$sed_script') | gzip -9 >$diff_file"; system "rm -rf a"; rename('b', "rsync-$version"); print "Creating $srctar_file ...\n"; system "git archive --format=tar --prefix=rsync-$version/ v$version | tar xf -"; system "support/git-set-file-times --prefix=rsync-$version/"; system "fakeroot tar czf $srctar_file rsync-$version; rm -rf rsync-$version"; print "Updating files in \"rsync-$version/patches\" dir ...\n"; mkdir("rsync-$version", 0755); mkdir("rsync-$version/patches", 0755); system "packaging/patch-update --skip-check --branch=$master_branch --gen=rsync-$version/patches"; print "Creating $pattar_file ...\n"; system "fakeroot tar chzf $pattar_file rsync-$version/patches; rm -rf rsync-$version"; print "Updating the other files in $dest ...\n"; system "rsync -a README NEWS OLDNEWS TODO $dest"; unlink($news_file); link("$dest/NEWS", $news_file); system "git log --name-status | gzip -9 >$dest/ChangeLog.gz"; system "yodl2html -o $dest/rsync.html rsync.yo"; system "yodl2html -o $dest/rsyncd.conf.html rsyncd.conf.yo"; foreach my $fn ($srctar_file, $pattar_file, $diff_file) { unlink("$fn.asc"); open(GPG, '|-', "gpg --batch --passphrase-fd=0 -ba $fn") or die $!; print GPG $passphrase, "\n"; close GPG; } if (!$pre) { system "rm $dest/rsync-*.gz $dest/rsync-*.asc $dest/rsync-*-NEWS $dest/src-previews/rsync-*diffs.gz*"; foreach my $fn ($srctar_file, "$srctar_file.asc", $pattar_file, "$pattar_file.asc", $diff_file, "$diff_file.asc", $news_file) { (my $top_fn = $fn) =~ s#/src(-\w+)?/#/#; link($fn, $top_fn); } } print $break, <<'EOT'; 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)! EOT exit; sub get_subprotocol_version { my($subver) = @_; if ($pre && $proto_changed eq 'changed') { return $subver == 0 ? 1 : $subver; } 0; } sub usage { die <= 4 %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-client Provides the rsync-ssl script that makes use of stunnel 4 to open an ssl connection to an rsync daemon (on port 874). This setup does NOT require any local stunnel daemon to be running to connect to the remote ssl rsyncd. %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.1.2. * 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-bpc-3.1.2.1/packaging/lsb/rsync.xinetd0000664000047500004750000000047313510756401017605 0ustar craigcraig# 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-bpc-3.1.2.1/packaging/var-checker0000775000047500004750000000421213510756401016565 0ustar craigcraig#!/usr/bin/perl # 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. use strict; use warnings; my %add_syscall_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c tls.c trimslash.c ); my %add_compat_c = map { $_ => 1 } qw( t_stub.c tls.c trimslash.c wildtest.c ); my %add_util_c = map { $_ => 1 } qw( t_stub.c t_unsafe.c ); my %sizes; open(IN, '<', 'syscall.c') or die $!; undef $/; my $syscall_c = ; $/ = "\n"; close IN; $syscall_c =~ s/^extern\s.*//mg; open(IN, '<', 'lib/compat.c') or die $!; undef $/; my $compat_c = ; $/ = "\n"; close IN; $compat_c =~ s/^extern\s.*//mg; open(IN, '<', 'util.c') or die $!; undef $/; my $util_c = ; $/ = "\n"; close IN; $util_c =~ s/^extern\s.*//mg; my @files = glob('*.c'); foreach my $fn (@files) { open(IN, '<', $fn) or die $!; undef $/; $_ = ; $/ = "\n"; close IN; my @vars = /^(?!(?:extern|enum)\s)([a-zA-Z]\S*\s+.*);/mg; my @externs = /^extern\s+(.*);/mg; $_ .= $syscall_c if $add_syscall_c{$fn}; $_ .= $compat_c if $add_compat_c{$fn}; $_ .= $util_c if $add_util_c{$fn}; s/INFO_GTE/info_levels/g; s/DEBUG_GTE/debug_levels/g; check_vars($fn, 'var', @vars); check_vars($fn, 'extern', @externs); } exit; # The file's contents are in $_. sub check_vars { my $fn = shift; my $type = shift; foreach my $line (@_) { $line =~ s/\s*\{.*\}//; $line =~ s/\s*\(.*\)//; foreach my $item (split(/\s*,\s*/, $line)) { $item =~ s/\s*=.*//; my $sz = $item =~ s/(\[.*?\])// ? $1 : ''; my($var) = $item =~ /([^*\s]+)$/; if (!defined $var) { print "Bogus match? ($item)\n"; next; } if ($sz) { if (defined $sizes{$var}) { if ($sizes{$var} ne $sz) { print $fn, ' has inconsistent size for "', $var, "\": $sizes{$var} vs $sz\n"; } } else { $sizes{$var} = $sz; } } my @matches = /(?; exit 1 unless /^y/i; $_[0] = $master_branch = $branch; # Updates caller's $master_branch too. } if ($check_patches_dir && -d 'patches/.git') { ($branch) = check_git_status($fatal_unless_clean, 'patches'); if ($branch ne $master_branch) { print "The *patches* checkout is on branch $branch, not branch $master_branch.\n"; print "Do you want to change it to branch $master_branch? [n] "; $_ = ; exit 1 unless /^y/i; system "cd patches && git checkout '$master_branch'"; } } return $cur_branch; } sub check_git_status { my($fatal_unless_clean, $subdir) = @_; $subdir = '.' unless defined $subdir; my $status = `cd '$subdir' && git status`; my $is_clean = $status =~ /\nnothing to commit.+working directory clean/; my($cur_branch) = $status =~ /^(?:# )?On branch (.+)\n/; if ($fatal_unless_clean && !$is_clean) { if ($subdir eq '.') { $subdir = ''; } else { $subdir = " *$subdir*"; } die "The$subdir checkout is not clean:\n", $status; } ($cur_branch, $is_clean, $status); } 1; rsync-bpc-3.1.2.1/packaging/solaris/0000775000047500004750000000000013510756401016122 5ustar craigcraigrsync-bpc-3.1.2.1/packaging/solaris/build_pkg.sh0000664000047500004750000000474713510756401020432 0ustar craigcraig#!/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 $FAKE_ROOT/doc/rsync/README 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 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-bpc-3.1.2.1/packaging/systemd/0000775000047500004750000000000013510756401016136 5ustar craigcraigrsync-bpc-3.1.2.1/packaging/systemd/rsync.service0000664000047500004750000000027413510756401020661 0ustar craigcraig[Unit] Description=fast remote file copy program daemon ConditionPathExists=/etc/rsyncd.conf [Service] ExecStart=/usr/bin/rsync --daemon --no-detach [Install] WantedBy=multi-user.target rsync-bpc-3.1.2.1/packaging/branch-from-patch0000775000047500004750000001034513510756401017672 0ustar craigcraig#!/usr/bin/perl use strict; use warnings; use Getopt::Long; &Getopt::Long::Configure('bundling'); &usage if !&GetOptions( 'branch|b=s' => \( my $master_branch = 'master' ), 'skip-check' => \( my $skip_branch_check ), 'delete' => \( my $delete_local_branches ), 'help|h' => \( my $help_opt ), ); &usage if $help_opt; require 'packaging/git-status.pl'; check_git_state($master_branch, !$skip_branch_check, 1); my %local_branch; open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n"; while () { if (m# patch/\Q$master_branch\E/(.*)#o) { $local_branch{$1} = 1; } } close PIPE; if ($delete_local_branches) { foreach my $name (sort keys %local_branch) { my $branch = "patch/$master_branch/$name"; system 'git', 'branch', '-D', $branch and exit 1; } %local_branch = ( ); } my @patch_list; foreach (@ARGV) { if (!-f $_) { die "File not found: $_\n"; } die "Filename is not a .diff file: $_\n" unless /\.diff$/; push @patch_list, $_; } exit unless @patch_list; my(%scanned, %created, %info); foreach my $patch (@patch_list) { my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$}; next if $scanned{$name}++; open IN, '<', $patch or die "Unable to open $patch: $!\n"; my $info = ''; my $commit; while () { if (m#^based-on: (\S+)#) { $commit = $1; last; } last if m#^index .*\.\..* \d#; last if m#^diff --git #; last if m#^--- (old|a)/#; $info .= $_; } close IN; $info =~ s/\s+\Z/\n/; my $parent = $master_branch; my @patches = $info =~ m#patch -p1 ', "PATCH.$name" or die $!; print OUT $info; close OUT; system 'git', 'add', "PATCH.$name" and exit 1; open IN, '<', $patch or die "Unable to open $patch: $!\n"; $_ = join('', ); close IN; open PIPE, '|-', 'patch -p1' or die $!; print PIPE $_; close PIPE; system 'rm -f *.orig */*.orig'; while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) { chmod oct($1), $2; system 'git', 'add', $2; } while (1) { system 'git status'; print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: '; $_ = ; last if /^$/; chomp; system "git add $_"; } while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") { exit 1 if system '/bin/zsh'; } } sub usage { die < \$make_tar, 'upload|u' => \$upload, 'help|h' => \$help_opt, ) || $help_opt; our $name = time2str('rsync-HEAD-%Y%m%d-%H%M%Z', time, 'GMT'); our $ztoday = time2str('%d %b %Y', time); our $today = $ztoday; our $gen_target = $upload ? 'gensend' : 'gen'; die "$dest does not exist\n" unless -d $dest; die "There is no .git dir in the current directory.\n" unless -d '.git'; die "There is no rsync checkout in the current directory.\n" unless -f 'rsyncd.conf.yo'; if ($make_tar) { open(IN, '-|', 'git status') or die $!; my $status = join('', ); close IN; die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit.+working directory clean/; die "The checkout is not on the master branch.\n" unless $status =~ /^(?:# )?On branch master\n/; system "make $gen_target" and die "make $gen_target failed!\n"; my @extra_files; open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n"; while () { if (s/^GENFILES=//) { while (s/\\$//) { $_ .= ; } @extra_files = split(' ', $_); last; } } close IN; my $confversion; open(IN, '<', 'configure.ac') or die "Unable to open configure.ac: $!\n"; while () { if (/^AC_INIT\(\[rsync\],\s*\[(\d.+?)\]/) { $confversion = $1; last; } } close IN; die "Unable to find AC_INIT with version in configure.ac\n" unless defined $confversion; open(IN, '<', 'OLDNEWS') or die "Unable to open OLDNEWS: $!\n"; $_ = ; my($lastversion) = /(\d+\.\d+\.\d+)/; my $last_protocol_version; while () { if (my($ver,$pdate,$pver) = /^\s+\S\S\s\S\S\S\s\d\d\d\d\s+(\d+\.\d+\.\d+)\s+(\d\d \w\w\w \d\d\d\d\s+)?(\d+)$/) { $last_protocol_version = $pver if $ver eq $lastversion; } } close IN; die "Unable to determine protocol_version for $lastversion.\n" unless defined $last_protocol_version; my($protocol_version,$subprotocol_version); open(IN, '<', 'rsync.h') or die "Unable to open rsync.h: $!\n"; while () { if (/^#define\s+PROTOCOL_VERSION\s+(\d+)/) { $protocol_version = $1; } elsif (/^#define\s+SUBPROTOCOL_VERSION\s+(\d+)/) { $subprotocol_version = $1; } } close IN; die "Unable to determine the current PROTOCOL_VERSION.\n" unless defined $protocol_version; die "Unable to determine the current SUBPROTOCOL_VERSION.\n" unless defined $subprotocol_version; if ($confversion =~ /dev|pre/) { if ($last_protocol_version ne $protocol_version) { if ($subprotocol_version == 0) { die "SUBPROTOCOL_VERSION must not be 0 for a non-final release with a changed PROTOCOL_VERSION.\n"; } } else { if ($subprotocol_version != 0) { die "SUBPROTOCOL_VERSION must be 0 when the PROTOCOL_VERSION hasn't changed from the last release.\n"; } } } else { if ($subprotocol_version != 0) { die "SUBPROTOCOL_VERSION must be 0 for a final release.\n"; } } print "Creating $name.tar.gz\n"; system "rsync -a @extra_files $name/"; system "git archive --format=tar --prefix=$name/ HEAD | tar xf -"; system "support/git-set-file-times --prefix=$name/"; system "fakeroot tar czf $dest/$name.tar.gz $name; rm -rf $name"; unlink($nightly_symlink); symlink("$name.tar.gz", $nightly_symlink); } foreach my $fn (qw( rsync.yo rsyncd.conf.yo )) { my $yo_tmp = "$dest/$fn"; (my $html_fn = "$dest/$fn") =~ s/\.yo/.html/; open(IN, '<', $fn) or die $!; undef $/; $_ = ; $/ = "\n"; close IN; s/^(manpage\([^)]+\)\(\d+\)\()[^)]+(\).*)/$1$today$2/m; #s/^(This man ?page is current for version) \S+ (of rsync)/$1 $version $2/m; open(OUT, '>', $yo_tmp) or die $!; print OUT $_; close OUT; system 'yodl2html', '-o', $html_fn, $yo_tmp; unlink($yo_tmp); } chdir($dest) or die $!; my $cnt = 0; open(PIPE, '-|', 'ls -1t rsync-HEAD-*') or die $!; while () { chomp; next if $cnt++ < 10; unlink($_); } close PIPE; system 'ls -ltr'; if ($upload) { my $opt = ''; if (defined $ENV{RSYNC_PARTIAL_DIR}) { $opt = " -f 'R $ENV{RSYNC_PARTIAL_DIR}'"; } system "rsync$opt -aviHP --delete-after . $samba_host\:/home/ftp/pub/rsync/dev/nightly"; } exit; sub usage { die < \( my $master_branch = 'master' ), 'skip-check' => \( my $skip_branch_check ), 'shell|s' => \( my $launch_shell ), 'gen:s' => \( my $incl_generated_files ), 'help|h' => \( my $help_opt ), ); &usage if $help_opt; $ENV{GIT_MERGE_AUTOEDIT} = 'no'; if (defined $incl_generated_files) { $patches_dir = $incl_generated_files if $incl_generated_files ne ''; $incl_generated_files = 1; } die "No '$patches_dir' directory was found.\n" unless -d $patches_dir; die "No '.git' directory present in the current dir.\n" unless -d '.git'; require 'packaging/git-status.pl'; my $starting_branch = check_git_state($master_branch, !$skip_branch_check, 1); my $master_commit; open PIPE, '-|', "git log -1 --no-color $master_branch" or die $!; while () { if (/^commit (\S+)/) { $master_commit = $1; last; } } close PIPE; die "Unable to determine commit hash for master branch: $master_branch\n" unless defined $master_commit; if ($incl_generated_files) { my @extra_files = get_extra_files(); die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir; mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n"; system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/master/" and exit 1; } our $last_touch = time; my %patches; # Start by finding all patches so that we can load all possible parents. open(PIPE, '-|', 'git', 'branch', '-l') or die $!; while () { if (m# patch/\Q$master_branch\E/(.*)#o) { $patches{$1} = 1; } } close PIPE; my @patches = sort keys %patches; my(%parent, %description); foreach my $patch (@patches) { my $branch = "patch/$master_branch/$patch"; my $desc = ''; open(PIPE, '-|', 'git', 'diff', '-U1000', "$master_branch...$branch", '--', "PATCH.$patch") or die $!; while () { last if /^@@ /; } while () { next unless s/^[ +]//; if (m#patch -p1 = time; system "git checkout $starting_branch" and exit 1; exit; sub update_patch { my($patch) = @_; my $parent = $parent{$patch}; my $based_on; if (defined $parent) { unless ($completed{$parent}++) { update_patch($parent); } $based_on = $parent = "patch/$master_branch/$parent"; } else { $parent = $master_branch; $based_on = $master_commit; } print "======== $patch ========\n"; sleep 1 while $incl_generated_files && $last_touch >= time; system "git checkout patch/$master_branch/$patch" and return 0; my $ok = system("git merge $based_on") == 0; if (!$ok || $launch_shell) { my($parent_dir) = $parent =~ m{([^/]+)$}; print qq|"git merge $based_on" incomplete -- please fix.\n| if !$ok; $ENV{PS1} = "[$parent_dir] $patch: "; while (1) { if (system($ENV{SHELL}) != 0) { print "Abort? [n/y] "; $_ = ; next unless /^y/i; return 0; } my($cur_branch, $is_clean, $status) = check_git_status(0); last if $is_clean; print $status; } } open(OUT, '>', "$patches_dir/$patch.diff") or die $!; print OUT $description{$patch}, "\nbased-on: $based_on\n"; my @extra_files; if ($incl_generated_files) { @extra_files = get_extra_files(); system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/$patch/" and exit 1; } $last_touch = time; open(PIPE, '-|', 'git', 'diff', $based_on) or die $!; DIFF: while () { while (m{^diff --git a/PATCH}) { while () { last if m{^diff --git a/}; } last DIFF if !defined $_; } next if /^index /; print OUT $_; } close PIPE; if ($incl_generated_files) { my $parent_dir; if ($parent eq $master_branch) { $parent_dir = 'master'; } else { ($parent_dir) = $parent =~ m{([^/]+)$}; } open(PIPE, '-|', 'diff', '-Nurp', "$tmp_dir/$parent_dir", "$tmp_dir/$patch") or die $!; while () { s#^(diff -Nurp) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o; s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o; s#^\Q+++\E $tmp_dir/[^/]+/([^\t]+)\t.*#+++ b/$1#o; print OUT $_; } close PIPE; unlink @extra_files; } close OUT; 1; } exit; sub get_extra_files { my @extras; open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n"; while () { if (s/^GENFILES=//) { while (s/\\$//) { $_ .= ; } @extras = split(' ', $_); last; } } close IN; return @extras; } sub usage { die < 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, 'one-file-system' => 0, 'owner' => 0, 'perms' => 0, 'recursive' => 0, 'times' => 0, ); our $last_long_opt; open(IN, '../options.c') or die "Unable to open ../options.c: $!\n"; while () { if (/\Qargstr[x++]\E = '([^.ie])'/) { $short_no_arg{$1} = 1; undef $last_long_opt; } elsif (/\Qasprintf(\E[^,]+, "-([a-zA-Z0-9])\%l?[ud]"/) { $short_with_num{$1} = 1; undef $last_long_opt; } elsif (/\Qargs[ac++]\E = "--([^"=]+)"/) { $last_long_opt = $1; $long_opt{$1} = 0 unless exists $long_opt{$1}; } elsif (defined($last_long_opt) && /\Qargs[ac++]\E = ([^["\s]+);/ && $1 ne 'dest_option') { $long_opt{$last_long_opt} = 2; undef $last_long_opt; } elsif (/dest_option = "--([^"]+)"/) { $long_opt{$1} = 2; undef $last_long_opt; } elsif (/\Qasprintf(\E[^,]+, "--([^"=]+)=/ || /\Qargs[ac++]\E = "--([^"=]+)=/) { $long_opt{$1} = 1; undef $last_long_opt; } } close IN; my $short_no_arg = join('', sort keys %short_no_arg); my $short_with_num = join('', sort keys %short_with_num); print < $val,\n"; } print ");\n\n"; rsync-bpc-3.1.2.1/support/0000775000047500004750000000000013510756407014244 5ustar craigcraigrsync-bpc-3.1.2.1/support/cvs2includes0000775000047500004750000000227413510756401016575 0ustar craigcraig#!/usr/bin/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-bpc-3.1.2.1/support/git-set-file-times0000775000047500004750000000161613510756401017600 0ustar craigcraig#!/usr/bin/perl use strict; use warnings; # Sets mtime and atime of files to the latest commit time in git. # # This is useful after the first clone of the rsync repository BEFORE you # do any building. It is also safe if you have done a "make distclean". my %ls; my $commit_time; my $prefix = @ARGV && $ARGV[0] =~ s/^--prefix=// ? shift : ''; $/ = "\0"; open FH, 'git ls-files -z|' or die $!; while () { chomp; $ls{$_} = $_; } close FH; $/ = "\n"; open FH, "git log -r --name-only --no-color --pretty=raw -z @ARGV |" or die $!; while () { chomp; if (/^committer .*? (\d+) (?:[\-\+]\d+)$/) { $commit_time = $1; } elsif (s/\0\0commit [a-f0-9]{40}$// or s/\0$//) { my @files = delete @ls{split(/\0/, $_)}; @files = grep { defined $_ } @files; next unless @files; map { s/^/$prefix/ } @files; utime $commit_time, $commit_time, @files; } last unless %ls; } close FH; rsync-bpc-3.1.2.1/support/munge-symlinks0000775000047500004750000000266613510756401017160 0ustar craigcraig#!/usr/bin/perl # This script will either prefix all symlink values with the string # "/rsyncd-munged/" or remove that prefix. use strict; use Getopt::Long; my $SYMLINK_PREFIX = '/rsyncd-munged/'; my $munge_opt; &GetOptions( 'munge' => sub { $munge_opt = 1 }, 'unmunge' => sub { $munge_opt = 0 }, 'all' => \( my $all_opt ), 'help|h' => \( my $help_opt ), ) or &usage; &usage if $help_opt || !defined $munge_opt; my $munged_re = $all_opt ? qr/^($SYMLINK_PREFIX)+(?=.)/ : qr/^$SYMLINK_PREFIX(?=.)/; push(@ARGV, '.') unless @ARGV; open(PIPE, '-|', 'find', @ARGV, '-type', 'l') or die $!; while () { chomp; my $lnk = readlink($_) or next; if ($munge_opt) { next if !$all_opt && $lnk =~ /$munged_re/; $lnk =~ s/^/$SYMLINK_PREFIX/; } else { next unless $lnk =~ s/$munged_re//; } if (!unlink($_)) { warn "Unable to unlink symlink: $_ ($!)\n"; } elsif (!symlink($lnk, $_)) { warn "Unable to recreate symlink: $_ -> $lnk ($!)\n"; } else { print "$_ -> $lnk\n"; } } close PIPE; exit; sub usage { die <) { 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-bpc-3.1.2.1/support/deny-rsync0000775000047500004750000000174513510756401016266 0ustar craigcraig#!/bin/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-bpc-3.1.2.1/support/mapfrom0000775000047500004750000000116513510756401015630 0ustar craigcraig#!/usr/bin/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-bpc-3.1.2.1/support/rsync-no-vanished0000775000047500004750000000041313510756401017531 0ustar craigcraig#!/bin/bash IGNOREEXIT=24 IGNOREOUT='^(file has vanished: |rsync warning: some files vanished before they could be transferred)' set -o pipefail rsync "${@}" 2>&1 | (egrep -v "$IGNOREOUT" || true) ret=$? if [[ $ret == $IGNOREEXIT ]]; then ret=0 fi exit $ret rsync-bpc-3.1.2.1/support/lsh.sh0000775000047500004750000000167413510756401015373 0ustar craigcraig#!/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. user='' do_cd=y # Default path is user's home dir, just like ssh. 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 ;; *) 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-bpc-3.1.2.1/support/savetransfer.c0000664000047500004750000001072013510756401017105 0ustar craigcraig/* 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-bpc-3.1.2.1/support/file-attr-restore0000775000047500004750000001150413510756401017535 0ustar craigcraig#!/usr/bin/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 < \( 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 ), ) or &usage; &usage unless @ARGV > 1; my $host = shift; if ($host =~ s/^([^@]+)\@//) { $login_name = $1; } if ($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"; } push @cmd, '/bin/sh', '-c', "@ARGV"; exec @cmd; die "Failed to exec: $!\n"; sub usage { die < \$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 gt $b; } sub domnamcompare { $sdiff = length($a) - length($b); ($sdiff < 0) ? -1 : ($sdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; } sub bytecompare { $bdiff = $groupbytes{$b} - $groupbytes{$a}; ($bdiff < 0) ? -1 : ($bdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; } sub faccompare { $fdiff = $fac{$b} - $fac{$a}; ($fdiff < 0) ? -1 : ($fdiff > 0) ? 1 : ($a lt $b) ? -1 : ($a gt $b) ? 1 : 0; } sub usage { die <> 8; } exit $?; } if (!defined $old_dir) { atomic_symlink($symlink_content, $dest_arg); exit; } rename($dest_dir, $old_dir) or die "Unable to rename $dest_dir to $old_dir: $!"; rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!"; exit; sub atomic_symlink { my($target, $link) = @_; my $newlink = "$link~new~"; unlink($newlink); # Just in case symlink($target, $newlink) or die "Unable to symlink $newlink -> $target: $!\n"; rename($newlink, $link) or die "Unable to rename $newlink to $link: $!\n"; } sub usage { die <) { push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/; } print join(',', @_), "\n"; rsync-bpc-3.1.2.1/support/rsync-slash-strip0000775000047500004750000000120313510756401017565 0ustar craigcraig#!/bin/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. args=() for arg in "${@}"; do if [[ "$arg" == / ]]; then args=("${args[@]}" /) else args=("${args[@]}" "${arg%/}") fi done exec /usr/bin/rsync "${args[@]}" rsync-bpc-3.1.2.1/support/logfilter0000775000047500004750000000211413510756401016151 0ustar craigcraig#!/usr/bin/perl # Filter the rsync daemon log messages by module name. The log file can be # in either syslog format or rsync's own log-file format. Note that the # MODULE_NAME parameter is used in a regular-expression match in order to # allow regex wildcards to be used. You can also limit the output by # directory hierarchy in a module. Examples: # # logfilter foo /var/log/rsyncd.log # output lines for module foo # logfilter foo/dir /var/log/syslog # limit lines to those in dir of foo use strict; my $match = shift; die "Usage: logfilter MODULE_NAME [LOGFILE ...]\n" unless defined $match; 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 '; my %pids; while (<>) { 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-bpc-3.1.2.1/support/instant-rsyncd0000775000047500004750000000533713510756401017154 0ustar craigcraig#!/bin/bash # instant-rsyncd lets you quickly set up and start a simple, unprivileged rsync # daemon with a single module in the current directory. I've found it # invaluable for quick testing, and I use it when writing a list of commands # that people can paste into a terminal to reproduce a daemon-related bug. # Sysadmins deploying an rsync daemon for the first time may find it helpful as # a starting point. # # Usage: instant-rsyncd MODULE PORT RSYNCD-USERNAME [RSYNC-PATH] # The script asks for the rsyncd user's password twice on stdin, once to set it # and once to log in to test the daemon. # -- Matt McCutchen 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-bpc-3.1.2.1/support/mnt-excl0000775000047500004750000000346413510756401015722 0ustar craigcraig#!/usr/bin/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-bpc-3.1.2.1/support/rrsync0000664000047500004750000001610713510756401015506 0ustar craigcraig#!/usr/bin/perl # Name: /usr/local/bin/rrsync (should also have a symlink in /usr/bin) # Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys # Author: Joe Smith 30-Sep-2004 # Modified by: Wayne Davison use strict; use Socket; use Cwd 'abs_path'; use File::Glob ':glob'; # You may configure these values to your liking. See also the section # of options if you want to disable any options that rsync accepts. use constant RSYNC => '/usr/bin/rsync'; use constant LOGFILE => 'rrsync.log'; my $Usage = < 0, 'backup-dir' => 2, 'block-size' => 1, 'bwlimit' => 1, 'checksum-seed' => 1, 'compare-dest' => 2, 'compress-level' => 1, 'copy-dest' => 2, '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, '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-delete' => 1, 'max-size' => 1, 'min-size' => 1, 'modify-window' => 1, 'new-compress' => 0, 'no-implied-dirs' => 0, 'no-r' => 0, 'no-relative' => 0, 'no-specials' => 0, 'numeric-ids' => 0, 'one-file-system' => 0, 'only-write-batch' => 1, 'owner' => 0, 'partial' => 0, 'partial-dir' => 2, 'perms' => 0, 'preallocate' => 0, 'recursive' => 0, 'remove-sent-files' => $only eq 'r' ? -1 : 0, 'remove-source-files' => $only eq 'r' ? -1 : 0, 'safe-links' => 0, 'sender' => 0, 'server' => 0, 'size-only' => 0, 'skip-compress' => 1, 'specials' => 0, 'stats' => 0, 'suffix' => 1, 'super' => 0, 'temp-dir' => 2, 'timeout' => 1, 'times' => 0, 'use-qsort' => 0, 'usermap' => 1, ); ### END of options data produced by the cull_options script. ### if ($short_disabled ne '') { $short_no_arg =~ s/[$short_disabled]//go; $short_with_num =~ s/[$short_disabled]//go; } $short_no_arg = "[$short_no_arg]" if length($short_no_arg) > 1; $short_with_num = "[$short_with_num]" if length($short_with_num) > 1; my $write_log = -f LOGFILE && open(LOG, '>>', LOGFILE); chdir($subdir) or die "$0: Unable to chdir to restricted dir: $!\n"; my(@opts, @args); my $in_options = 1; my $last_opt = ''; my $check_type; while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) { $_ = $1; if ($check_type) { push(@opts, check_arg($last_opt, $_, $check_type)); $check_type = 0; } elsif ($in_options) { push(@opts, $_); if ($_ eq '.') { $in_options = 0; } else { die "$0: invalid option: '-'\n" if $_ eq '-'; next if /^-$short_no_arg*(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o; my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/; my $disabled; if (defined $opt) { my $ct = $long_opt{$opt}; last unless defined $ct; next if $ct == 0; if ($ct > 0) { if (!defined $arg) { $check_type = $ct; $last_opt = $opt; next; } $arg = check_arg($opt, $arg, $ct); $opts[-1] =~ s/=.*/=$arg/; next; } $disabled = 1; $opt = "--$opt"; } elsif ($short_disabled ne '') { $disabled = /^-$short_no_arg*([$short_disabled])/o; $opt = "-$1"; } last unless $disabled; # Generate generic failure die "$0: option $opt has been disabled on this server.\n"; } } else { if ($subdir ne '/') { # Validate args to ensure they don't try to leave our restricted dir. s{//+}{/}g; s{^/}{}; s{^$}{.}; die "$0: do not use .. in any path!\n" if m{(^|/)\\?\.\\?\.(\\?/|$)}; } push(@args, bsd_glob($_, GLOB_LIMIT|GLOB_NOCHECK|GLOB_BRACE|GLOB_QUOTE)); } } die "$0: invalid rsync-command syntax or options\n" if $in_options; @args = ( '.' ) if !@args; if ($write_log) { my ($mm,$hh) = (localtime)[1,2]; my $host = $ENV{SSH_CONNECTION} || 'unknown'; $host =~ s/ .*//; # Keep only the client's IP addr $host =~ s/^::ffff://; $host = gethostbyaddr(inet_aton($host),AF_INET) || $host; printf LOG "%02d:%02d %-13s [%s]\n", $hh, $mm, $host, "@opts @args"; close LOG; } # Note: This assumes that the rsync protocol will not be maliciously hijacked. exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!"; sub check_arg { my($opt, $arg, $type) = @_; $arg =~ s/\\(.)/$1/g; if ($subdir ne '/' && ($type == 3 || ($type == 2 && !$am_sender))) { $arg =~ s{//}{/}g; die "Do not use .. in --$opt; anchor the path at the root of your restricted dir.\n" if $arg =~ m{(^|/)\.\.(/|$)}; $arg =~ s{^/}{$subdir/}; } $arg; } rsync-bpc-3.1.2.1/io.c0000664000047500004750000020012713510756407013305 0ustar craigcraig/* * 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-2015 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 msgs2stderr; extern int inc_recurse; extern int io_error; 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 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 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 batch_fd = -1; 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; 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 [%s]", who_am_i()); 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)) { int n = read(fd, buf + got, len - got); if (DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] safe_read(%d)=%ld\n", who_am_i(), fd, (long)n); if (n == 0) break; if (n < 0) { if (errno == EINTR) continue; rsyserr(FERROR, errno, "safe_read failed to read %ld bytes [%s]", (long)len, who_am_i()); 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) { int 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 %ld bytes to %s [%s]", (long)len, what_fd_is(fd), who_am_i()); 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 [%s]", what_fd_is(fd), who_am_i()); 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) { int 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); } return; } if (DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] files-from read=%ld\n", who_am_i(), (long)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; 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. */ 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; /* Eliminate any multi-'\0' runs. */ while (f != eob) { if (!(*t++ = *f++)) { while (f != eob && *f == '\0') f++; } } 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 && 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 && 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 %ld bytes, iobuf.in.buf is only %ld bytes.\n", (long)needed, (long)iobuf.in.size); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%ld, %sinput)\n", who_am_i(), (long)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 %ld bytes, iobuf.out.buf is only %ld bytes.\n", (long)needed, (long)(iobuf.out.size - iobuf.out_empty_len)); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%ld, outroom) needs to flush %ld\n", who_am_i(), (long)needed, iobuf.out.len + needed > iobuf.out.size ? (long)(iobuf.out.len + needed - iobuf.out.size) : 0L); } break; case PIO_NEED_MSGROOM: /* We never resize the circular message buffer. */ if (iobuf.msg.size < needed) { fprintf(stderr, "need to write %ld bytes, iobuf.msg.buf is only %ld bytes.\n", (long)needed, (long)iobuf.msg.size); exit_cleanup(RERR_PROTOCOL); } if (msgs2stderr && DEBUG_GTE(IO, 3)) { rprintf(FINFO, "[%s] perform_io(%ld, msgroom) needs to flush %ld\n", who_am_i(), (long)needed, iobuf.msg.len + needed > iobuf.msg.size ? (long)(iobuf.msg.len + needed - iobuf.msg.size) : 0L); } break; case 0: if (msgs2stderr && DEBUG_GTE(IO, 3)) rprintf(FINFO, "[%s] perform_io(%ld, %d)\n", who_am_i(), (long)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 && DEBUG_GTE(IO, 1)) { rprintf(FINFO, "[%s] send_msg(%d, %ld)\n", who_am_i(), (int)MSG_DATA, (long)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; int 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 && DEBUG_GTE(IO, 2)) rprintf(FINFO, "[%s] recv=%ld\n", who_am_i(), (long)n); if (io_timeout) { last_io_in = time(NULL); if (flags & PIO_NEED_INPUT) maybe_send_keepalive(last_io_in, 0); } stats.total_read += n; iobuf.in.len += n; } 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; int 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, "[%s] write error", who_am_i()); drain_multiplex_messages(); exit_cleanup(RERR_SOCKETIO); } } if (msgs2stderr && DEBUG_GTE(IO, 2)) { rprintf(FINFO, "[%s] %s sent=%ld\n", who_am_i(), out == &iobuf.out ? "out" : "msg", (long)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; 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 || code != MSG_INFO); if (!OUT_MULTIPLEXED) return 0; if (want_debug) rprintf(FINFO, "[%s] send_msg(%d, %ld)\n", who_am_i(), (int)code, (long)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) perform_io(needed, PIO_NEED_MSGROOM); 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=%ld\n", who_am_i(), (long)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); } 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: bpc_sysCall_statusFileSize(F_LENGTH(flist->files[ndx - flist->ndx_start])); if (remove_source_files) 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, 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 if (!(argv = new_array(char *, maxargs))) out_of_memory("read_args"); 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; if (!(argv = realloc_array(argv, char *, maxargs))) out_of_memory("read_args"); } if (dot_pos) { if (request_p && request_len < 1024) { int len = strlen(buf); if (request_len) request_p[0][request_len++] = ' '; if (!(*request_p = realloc_array(*request_p, char, request_len + len + 1))) out_of_memory("read_args"); 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 { if (!(p = strdup(buf))) out_of_memory("read_args"); 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 && 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 && 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 && 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 && 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 (DEBUG_GTE(IO, 1) && msgs2stderr) rprintf(FINFO, "[%s] got msg=%d, len=%ld\n", who_am_i(), (int)tag, (long)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 != 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); } val = raw_read_int(); 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_RENAME: { static xbuf rename_buf = EMPTY_XBUF; char *bufP, *oldName, *newName; uint32 oldLen, newLen, isTemp; if ( !rename_buf.size ) { alloc_xbuf(&rename_buf, 4096); } if ( msg_bytes > 0 && (unsigned)msg_bytes > rename_buf.size - 1 ) { realloc_xbuf(&rename_buf, msg_bytes + 4096); } raw_read_buf(rename_buf.buf, msg_bytes); bufP = rename_buf.buf; oldLen = IVAL(bufP, 0); bufP += sizeof(uint32); newLen = IVAL(bufP, 0); bufP += sizeof(uint32); isTemp = IVAL(bufP, 0); bufP += sizeof(uint32); oldName = bufP; bufP += oldLen; newName = bufP; bufP += newLen; bpc_rename_request(oldName, newName, isTemp, bufP, rename_buf.buf + msg_bytes); iobuf.in_multiplexed = 1; } 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 %ld bytes\n", who_am_i(), (long)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; } 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 } 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_it_all) { if (iobuf.out.len > iobuf.out_empty_len) { if (flush_it_all) /* FULL_FLUSH: flush everything in the output buffers */ perform_io(iobuf.out.size - iobuf.out_empty_len, PIO_NEED_OUTROOM); else /* NORMAL_FLUSH: flush at least 1 byte */ perform_io(iobuf.out.size - iobuf.out.len + 1, PIO_NEED_OUTROOM); } 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 = 4; SIVAL(b, 1, x); while (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[cnt]; 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 && 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 && 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 && 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 && 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_byte(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-bpc-3.1.2.1/util.c0000664000047500004750000011754613510756407013667 0ustar craigcraig/* * 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-2015 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 protect_args; extern int modify_window; extern int relative_paths; extern int preserve_times; extern int preserve_xattrs; 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_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) { static int switch_step = 0; if (DEBUG_GTE(TIME, 1)) { rprintf(FINFO, "set modtime of %s to (%ld) %s", fname, (long)modtime, asctime(localtime(&modtime))); } switch (switch_step) { #ifdef HAVE_UTIMENSAT #include "case_N.h" if (do_utimensat(fname, modtime, mod_nsec) == 0) break; if (errno != ENOSYS) return -1; switch_step++; /* FALLTHROUGH */ #endif #ifdef HAVE_LUTIMES #include "case_N.h" if (do_lutimes(fname, modtime, mod_nsec) == 0) break; if (errno != ENOSYS) return -1; switch_step++; /* FALLTHROUGH */ #endif #include "case_N.h" switch_step++; if (preserve_times & PRESERVE_LINK_TIMES) { preserve_times &= ~PRESERVE_LINK_TIMES; if (S_ISLNK(mode)) return 1; } /* FALLTHROUGH */ #include "case_N.h" #ifdef HAVE_UTIMES if (do_utimes(fname, modtime, mod_nsec) == 0) break; #else if (do_utime(fname, modtime, mod_nsec) == 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 = bpc_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 = bpc_read(desc, ptr, len); } while (n_chars < 0 && errno == EINTR); return n_chars; } /* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file. * Otherwise, it just 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 ofd, mode_t mode) { int ifd; char buf[1024 * 8]; int len; /* Number of bytes read into `buf'. */ #ifdef PREALLOCATE_NEEDS_TRUNCATE OFF_T preallocated_len = 0, offset = 0; #endif 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 (ofd < 0) { 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)); bpc_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) { if (do_fallocate(ofd, 0, srcst.st_size) == 0) { #ifdef PREALLOCATE_NEEDS_TRUNCATE preallocated_len = srcst.st_size; #endif } else 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)); bpc_close(ifd); bpc_close(ofd); errno = save_errno; return -1; } #ifdef PREALLOCATE_NEEDS_TRUNCATE offset += len; #endif } if (len < 0) { int save_errno = errno; rsyserr(FERROR_XFER, errno, "read %s", full_fname(source)); bpc_close(ifd); bpc_close(ofd); errno = save_errno; return -1; } if (bpc_close(ifd) < 0) { rsyserr(FWARNING, errno, "close failed on %s", full_fname(source)); } #ifdef PREALLOCATE_NEEDS_TRUNCATE /* Source file might have shrunk since we fstatted it. * Cut off any extra preallocated zeros from dest file. */ if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) { /* If we fail to truncate, the dest file may be wrong, so we * must trigger the "partial transfer" error. */ rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); } #endif if (bpc_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; 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) \ if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \ out_of_memory("glob_expand") 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); if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf))) out_of_memory("glob_match"); } } /* 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); if (!s) out_of_memory("glob_expand"); 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; } if (!(arg = strdup(arg))) out_of_memory("glob_expand_module"); 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++; } } /* 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); if (*p == '/') { if (!rootdir) rootdir = module_dir; rlen = strlen(rootdir); depth = 0; p++; } if (dest) { if (rlen + plen + 1 >= MAXPATHLEN) return NULL; } else if (!(dest = new_array(char, rlen + plen + 1))) out_of_memory("sanitize_path"); if (rlen) { memcpy(dest, rootdir, rlen); if (rlen > 1) 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; strcpy(curr_dir, "/"); 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 && bpc_chdir(dir)) return 0; skipped_chdir = set_path_only; memcpy(curr_dir, dir, len + 1); } else { 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 && bpc_chdir(curr_dir)) { 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); if (!(path = strdup(curr_dir))) out_of_memory("normalize_path"); curr_dir[curr_dir_len] = '\0'; } else if (force_newbuf) { if (!(path = strdup(path))) out_of_memory("normalize_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 char TimeBuf[200]; struct tm *tm = localtime(&t); char *p; #ifdef HAVE_STRFTIME strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); #else strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf); #endif if ((p = strchr(TimeBuf, '\n')) != NULL) *p = '\0'; return TimeBuf; } /* Determine if two time_t values are equivalent (either exact, or in * the modification timestamp window established by --modify-window). * * @retval 0 if the times should be treated as the same * * @retval +1 if the first is later * * @retval -1 if the 2nd is later **/ int cmp_time(time_t file1, time_t file2) { if (file2 > file1) { /* The final comparison makes sure that modify_window doesn't overflow a * time_t, which would mean that file2 must be in the equality window. */ if (!modify_window || (file2 > file1 + modify_window && file1 + modify_window > file1)) return -1; } else if (file1 > file2) { if (!modify_window || (file1 > file2 + modify_window && file2 + modify_window > file2)) return 1; } return 0; } #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 signficant. */ 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 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; int32 cost; unsigned i1, i2; 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; if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*)))) out_of_memory("bitbag_create"); 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]) { if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4))) out_of_memory("bitbag_set_bit"); } 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; if (!(item = new(struct flist_ndx_item))) out_of_memory("flist_ndx_push"); 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 new_size = lp->malloced; if (incr < 0) new_size += -incr; /* increase slowly */ else if (new_size < (size_t)incr) new_size = incr; else if (new_size) new_size *= 2; else new_size = 1; if (new_size <= lp->malloced) overflow_exit("expand_item_list"); /* Using _realloc_array() lets us pass the size, not a type. */ new_ptr = _realloc_array(lp->items, item_size, new_size); if (DEBUG_GTE(FLIST, 3)) { rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", who_am_i(), desc, big_num(new_size * item_size), new_ptr == lp->items ? " not" : ""); } if (!new_ptr) out_of_memory("expand_item_list"); lp->items = new_ptr; lp->malloced = new_size; } return (char*)lp->items + (lp->count++ * item_size); } rsync-bpc-3.1.2.1/Makefile.in0000664000047500004750000001541113510756407014577 0ustar craigcraig# Makefile for rsync_bpc. This is processed by configure to produce the final # Makefile prefix=@prefix@ datarootdir=@datarootdir@ exec_prefix=@exec_prefix@ stunnel4=@STUNNEL4@ bindir=@bindir@ mandir=@mandir@ LIBS=@LIBS@ CC=@CC@ CFLAGS=@CFLAGS@ CPPFLAGS=@CPPFLAGS@ EXEEXT=@EXEEXT@ LDFLAGS=@LDFLAGS@ LIBOBJDIR=lib/ INSTALLCMD=@INSTALL@ INSTALLMAN=@INSTALL@ srcdir=@srcdir@ MKDIR_P=@MKDIR_P@ VPATH=$(srcdir) SHELL=/bin/sh VERSION=@RSYNC_VERSION@ .SUFFIXES: .SUFFIXES: .c .o GENFILES=configure.sh aclocal.m4 config.h.in proto.h proto.h-tstamp HEADERS=byteorder.h config.h errcode.h proto.h rsync.h ifuncs.h itypes.h inums.h \ lib/pool_alloc.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 BPCOBJ=bpc_sysCalls.o backuppc/bpc_attrib.o backuppc/bpc_dirOps.o backuppc/bpc_hashtable.o backuppc/bpc_poolWrite.o \ backuppc/bpc_attribCache.o backuppc/bpc_fileZIO.o backuppc/bpc_lib.o backuppc/bpc_refCount.o OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \ util.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 \ fileio.o batch.o clientname.o chmod.o acls.o xattrs.o OBJS3=progress.o pipe.o 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) $(BPCOBJ) @BUILD_ZLIB@ @BUILD_POPT@ TLS_OBJ = tls.o syscall.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_bpc$(EXEEXT) tls$(EXEEXT) getgroups$(EXEEXT) getfsdev$(EXEEXT) \ testrun$(EXEEXT) trimslash$(EXEEXT) t_unsafe$(EXEEXT) wildtest$(EXEEXT) CHECK_SYMLINKS = # 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@ all: Makefile rsync_bpc$(EXEEXT) install: all -${MKDIR_P} ${DESTDIR}${bindir} ${INSTALLCMD} ${INSTALL_STRIP} -m 755 rsync_bpc$(EXEEXT) ${DESTDIR}${bindir} install-all: install install-strip: $(MAKE) INSTALL_STRIP='-s' install rsync_bpc$(EXEEXT): $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(BPCOBJ): backuppc/backuppc.h $(OBJS): $(HEADERS) $(CHECK_OBJS): $(HEADERS) flist.o: rounding.h rounding.h: rounding.c rsync.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 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 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 util.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) gen: conf proto.h gensend: gen rsync -aivzc $(GENFILES) $${SAMBA_HOST-samba.org}:/home/ftp/pub/rsync/generated-files/ conf: cd $(srcdir) && $(MAKE) -f prepare-source.mak conf reconfigure: configure.sh ./config.status --recheck ./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 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 config.h perl $(srcdir)/mkproto.pl $(srcdir)/*.c $(srcdir)/lib/compat.c man: rsync.1: rsync.yo yodl2man -o rsync.1 $(srcdir)/rsync.yo -$(srcdir)/tweak_manpage rsync.1 rsyncd.conf.5: rsyncd.conf.yo yodl2man -o rsyncd.conf.5 $(srcdir)/rsyncd.conf.yo -$(srcdir)/tweak_manpage rsyncd.conf.5 clean: cleantests rm -f *~ $(OBJS) $(CHECK_PROGS) $(CHECK_OBJS) $(CHECK_SYMLINKS) \ rounding rounding.h *.old 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. distclean: clean rm -f Makefile config.h config.status rm -f lib/dummy popt/dummy zlib/dummy backuppc/dummy rm -f $(srcdir)/Makefile $(srcdir)/config.h $(srcdir)/config.status rm -f $(srcdir)/lib/dummy $(srcdir)/popt/dummy $(srcdir)/zlib/dummy $(srcdir)/backuppc/dummy rm -f config.cache config.log rm -f $(srcdir)/config.cache $(srcdir)/config.log rm -f shconfig $(srcdir)/shconfig rm -f $(GENFILES) rm -rf autom4te.cache # 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) 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 wildtest.o: wildtest.c 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) # 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 doxygen: cd $(srcdir) && rm dox/html/* && doxygen # for maintainers only doxygen-upload: rsync -avzv $(srcdir)/dox/html/ --delete \ $${SAMBA_HOST-samba.org}:/home/httpd/html/rsync/doxygen/head/ rsync-bpc-3.1.2.1/rsyncsh.txt0000664000047500004750000000247313510756401014762 0ustar craigcraigrsyncsh 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-bpc-3.1.2.1/backuppc/0000775000047500004750000000000013510756401014312 5ustar craigcraigrsync-bpc-3.1.2.1/backuppc/bpc_attribCache.c0000664000047500004750000007310713510756401017523 0ustar craigcraig/* * Routines for caching multiple directories. * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" #define BPC_ATTRIBCACHE_DIR_COUNT_MAX (380) #define BPC_ATTRIBCACHE_DIR_HT_SIZE (512) void bpc_attribCache_init(bpc_attribCache_info *ac, char *hostName, int backupNum, char *shareNameUM, int compress) { ac->backupNum = backupNum; ac->compress = compress; ac->cacheLruCnt = 0; ac->bkupMergeList = NULL; ac->bkupMergeCnt = 0; ac->currentDir[0] = '\0'; ac->deltaInfo = NULL; strncpy(ac->hostName, hostName, BPC_MAXPATHLEN); ac->hostName[BPC_MAXPATHLEN - 1] = '\0'; strncpy(ac->shareNameUM, shareNameUM, BPC_MAXPATHLEN); ac->shareNameUM[BPC_MAXPATHLEN - 1] = '\0'; bpc_fileNameEltMangle(ac->shareName, BPC_MAXPATHLEN, ac->shareNameUM); ac->shareNameLen = strlen(ac->shareName); snprintf(ac->hostDir, BPC_MAXPATHLEN, "%s/pc/%s", BPC_TopDir, ac->hostName); snprintf(ac->backupTopDir, BPC_MAXPATHLEN, "%s/pc/%s/%d", BPC_TopDir, ac->hostName, ac->backupNum); bpc_path_create(ac->backupTopDir); bpc_hashtable_create(&ac->attrHT, BPC_ATTRIBCACHE_DIR_HT_SIZE, sizeof(bpc_attribCache_dir)); bpc_hashtable_create(&ac->inodeHT, BPC_ATTRIBCACHE_DIR_HT_SIZE, sizeof(bpc_attribCache_dir)); } void bpc_attribCache_setDeltaInfo(bpc_attribCache_info *ac, bpc_deltaCount_info *deltaInfo) { ac->deltaInfo = deltaInfo; } /* * Caller is responsible for calling malloc for bkupList. */ void bpc_attribCache_setMergeList(bpc_attribCache_info *ac, bpc_backup_info *bkupList, int bkupCnt) { ac->bkupMergeList = bkupList; ac->bkupMergeCnt = bkupCnt; } static void bpc_attribCache_destroyEntry(bpc_attribCache_dir *attr) { bpc_attrib_dirDestroy(&attr->dir); } void bpc_attribCache_destroy(bpc_attribCache_info *ac) { bpc_hashtable_iterate(&ac->attrHT, (void*)bpc_attribCache_destroyEntry, NULL); bpc_hashtable_destroy(&ac->attrHT); bpc_hashtable_iterate(&ac->inodeHT, (void*)bpc_attribCache_destroyEntry, NULL); bpc_hashtable_destroy(&ac->inodeHT); if ( ac->bkupMergeList ) free(ac->bkupMergeList); ac->bkupMergeList = NULL; ac->bkupMergeCnt = 0; } int bpc_attribCache_readOnly(bpc_attribCache_info *ac, int readOnly) { if ( readOnly >= 0 ) ac->readOnly = readOnly; return ac->readOnly; } void bpc_attribCache_setCurrentDirectory(bpc_attribCache_info *ac, char *dir) { char *p; snprintf(ac->currentDir, BPC_MAXPATHLEN, "%s", dir); p = ac->currentDir + strlen(ac->currentDir) - 1; while ( p >= ac->currentDir && p[0] == '/' ) *p-- = '\0'; } /* * Given a backup path, split it into the directory, file name, and path to the directory (starting * with the share name, ie: relative to ac->backupTopDir). * * splitPath will strip initial "./" and trailing "/." or "/" before splitting the path, but isn't * capable of handling paths with "/." in the middle, or ".." anywhere. */ static void splitPath(bpc_attribCache_info *ac, char *dir, char *fileName, char *attribPath, char *path) { char *dirOrig = dir; char fullPath[BPC_MAXPATHLEN]; size_t pathLen; /* * remove initial "./" */ while ( path[0] == '.' && path[1] == '/' ) { path += 2; while ( path[0] == '/' ) path++; } /* * if this is a relative path, prepend ac->currentDir (provided ac->currentDir is set) */ if ( path[0] != '/' && ac->currentDir[0] ) { snprintf(fullPath, BPC_MAXPATHLEN, "%s/%s", ac->currentDir, path); path = fullPath; } /* * strip trailing "/." or "/" */ pathLen = strlen(path); while ( (pathLen > 1 && path[pathLen - 2] == '/' && path[pathLen - 1] == '.') || (pathLen > 0 && path[pathLen - 1] == '/') ) { if ( path != fullPath ) { strncpy(fullPath, path, BPC_MAXPATHLEN); path = fullPath; } if ( path[pathLen - 1] == '/' ) { pathLen -= 1; } else { pathLen -= 2; } path[pathLen] = '\0'; if ( BPC_LogLevel >= 9 ) bpc_logMsgf("splitPath: trimming path = '%s'\n", path); } if ( !path[0] || (!path[1] && (path[0] == '.' || path[0] == '/')) ) { strcpy(fileName, ac->shareNameUM); strcpy(dir, "/"); strcpy(attribPath, "/attrib"); } else { char *p; int dirLen = BPC_MAXPATHLEN - ac->shareNameLen; strcpy(dir, ac->shareName); dir += strlen(dir); if ( (p = strrchr(path, '/')) ) { if ( *path != '/' ) { *dir++ = '/'; dirLen--; *dir = '\0'; } strcpy(fileName, p+1); *p = '\0'; bpc_fileNameMangle(dir, dirLen, path); *p = '/'; } else { strcpy(fileName, path); } snprintf(attribPath, BPC_MAXPATHLEN, "%s/attrib", dirOrig); } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("splitPath: returning dir = '%s', fileName = '%s', attrib = '%s' from path = '%s'\n", dirOrig, fileName, attribPath, path); } static void inodePath(UNUSED(bpc_attribCache_info *ac), char *indexStr, char *attribPath, char *attribFile, ino_t inode) { snprintf(attribPath, BPC_MAXPATHLEN, "inode/%02x", (unsigned int)(inode >> 17) & 0x7f); snprintf(attribFile, BPC_MAXPATHLEN, "attrib%02x", (unsigned int)(inode >> 10) & 0x7f); do { bpc_byte2hex(indexStr, inode & 0xff); indexStr += 2; inode >>= 8; } while ( inode ); *indexStr = '\0'; } static void bpc_attribCache_removeDeletedEntries(bpc_attrib_file *file, void *arg) { bpc_attribCache_dir *attr = (bpc_attribCache_dir*)arg; if ( file->type != BPC_FTYPE_DELETED ) return; attr->dirty = 1; bpc_attrib_fileDestroy(file); bpc_hashtable_nodeDelete(&attr->dir.filesHT, file); } static bpc_attribCache_dir *bpc_attribCache_loadPath(bpc_attribCache_info *ac, char *fileName, char *path) { char dir[BPC_MAXPATHLEN], attribPath[BPC_MAXPATHLEN]; bpc_attribCache_dir *attr; int attribPathLen, status; splitPath(ac, dir, fileName, attribPath, path); attribPathLen = strlen(attribPath); if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attribCache_loadPath: path = %s -> dir = %s, fileName = %s, attribPath = %s\n", path, dir, fileName, attribPath); attr = bpc_hashtable_find(&ac->attrHT, (uchar*)attribPath, attribPathLen, 1); if ( !attr || attr->key.key != attribPath ) { /* * cache hit - return the existing attributes */ if ( attr ) attr->lruCnt = ac->cacheLruCnt++; return attr; } if ( !(attr->key.key = malloc(attribPathLen + 1)) ) { bpc_logErrf("bpc_attribCache_loadPath: can't allocate %d bytes\n", attribPathLen + 1); return NULL; } strcpy(attr->key.key, attribPath); bpc_attrib_dirInit(&attr->dir, ac->compress); attr->dirty = 0; attr->dirOk = 0; attr->lruCnt = ac->cacheLruCnt++; if ( ac->bkupMergeCnt > 0 ) { int i; char topDir[BPC_MAXPATHLEN], fullAttribPath[BPC_MAXPATHLEN]; /* * Merge multiple attrib files to create the "view" for this backup. * There are two cases: merging forward for v3, or merging in reverse * for v4+. bkupMergeList is already in the order we need. */ for ( i = 0 ; i < ac->bkupMergeCnt ; i++ ) { bpc_attrib_dir dir; ssize_t entrySize; char *entries, *fileName; int attribFileExists, attribDirExists = 1; STRUCT_STAT st; snprintf(topDir, sizeof(topDir), "%s/pc/%s/%d", BPC_TopDir, ac->hostName, ac->bkupMergeList[i].num); snprintf(fullAttribPath, sizeof(fullAttribPath), "%s/%s", topDir, attribPath); attribFileExists = !stat(fullAttribPath, &st) && S_ISREG(st.st_mode); if ( !attribFileExists ) { char *p; if ( (p = strrchr(fullAttribPath, '/')) ) { *p = '\0'; attribDirExists = !stat(fullAttribPath, &st) && S_ISDIR(st.st_mode); } } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attribCache_loadPath: path = %s, file exists = %d, dir exists = %d\n", fullAttribPath, attribFileExists, attribDirExists); if ( ac->bkupMergeList[i].version < 4 && i == ac->bkupMergeCnt - 1 && !attribFileExists && !attribDirExists ) { /* * For V3, if the last backup doesn't have a directory, then the merged view is empty */ bpc_attrib_dirDestroy(&attr->dir); bpc_attrib_dirInit(&attr->dir, ac->compress); break; } if ( (ac->bkupMergeList[i].version < 4 && !attribFileExists) || !attribDirExists ) { /* * nothing to update here - keep going */ continue; } bpc_attrib_dirInit(&dir, ac->bkupMergeList[i].compress); if ( (status = bpc_attrib_dirRead(&dir, topDir, attribPath, ac->bkupMergeList[i].num)) ) { bpc_logErrf("bpc_attribCache_loadPath: bpc_attrib_dirRead(%s/%s) returned %d\n", topDir, attribPath, status); } entrySize = bpc_attrib_getEntries(&dir, NULL, 0); if ( (entries = malloc(entrySize)) && bpc_attrib_getEntries(&dir, entries, entrySize) == entrySize ) { for ( fileName = entries ; fileName < entries + entrySize ; fileName += strlen(fileName) + 1 ) { bpc_attrib_file *file = bpc_attrib_fileGet(&dir, fileName, 0); if ( !file ) continue; if ( file->type == BPC_FTYPE_DELETED ) { bpc_attrib_fileDeleteName(&attr->dir, fileName); } else { bpc_attrib_file *fileDest; if ( !(fileDest = bpc_attrib_fileGet(&attr->dir, fileName, 1)) ) return NULL; if ( fileDest->key.key == fileName ) { /* * new entry - initialize */ bpc_attrib_fileInit(fileDest, fileName, 0); } bpc_attrib_fileCopy(fileDest, file); fileDest->backupNum = ac->bkupMergeList[i].num; } } } else { bpc_logErrf("bpc_attribCache_loadPath(%s/%s): can't malloc %lu bytes for entries\n", topDir, attribPath, (unsigned long)entrySize); if ( entries ) free(entries); bpc_attrib_dirDestroy(&dir); return NULL; } free(entries); bpc_attrib_dirDestroy(&dir); } } else { /* * non-merge case - read the single attrib file */ if ( (status = bpc_attrib_dirRead(&attr->dir, ac->backupTopDir, attribPath, ac->backupNum)) ) { bpc_logErrf("bpc_attribCache_loadPath: bpc_attrib_dirRead(%s, %s) returned %d\n", ac->backupTopDir, attribPath, status); } /* * remove any extraneous BPC_FTYPE_DELETED file types */ bpc_hashtable_iterate(&attr->dir.filesHT, (void*)bpc_attribCache_removeDeletedEntries, attr); } if ( bpc_hashtable_entryCount(&ac->attrHT) > BPC_ATTRIBCACHE_DIR_COUNT_MAX ) { bpc_attribCache_flush(ac, 0, NULL); } return attr; } static bpc_attribCache_dir *bpc_attribCache_loadInode(bpc_attribCache_info *ac, char *indexStr, ino_t inode) { char attribPath[BPC_MAXPATHLEN], attribDir[BPC_MAXPATHLEN], attribFile[BPC_MAXPATHLEN]; bpc_attribCache_dir *attr; int attribPathLen, status; inodePath(ac, indexStr, attribDir, attribFile, inode); attribPathLen = snprintf(attribPath, sizeof(attribPath), "%s/%s", attribDir, attribFile); attr = bpc_hashtable_find(&ac->inodeHT, (uchar*)attribPath, attribPathLen, 1); if ( !attr || attr->key.key != attribPath ) { if ( attr ) attr->lruCnt = ac->cacheLruCnt++; return attr; } /* * new entry - read the attrib file */ if ( !(attr->key.key = malloc(attribPathLen + 1)) ) { bpc_logErrf("bpc_attribCache_loadInode: can't allocate %d bytes\n", attribPathLen + 1); return NULL; } strcpy(attr->key.key, attribPath); bpc_attrib_dirInit(&attr->dir, ac->compress); attr->dirty = 0; attr->dirOk = 1; attr->lruCnt = ac->cacheLruCnt++; if ( ac->bkupMergeCnt > 0 ) { int i; char inodeDir[BPC_MAXPATHLEN], fullAttribPath[BPC_MAXPATHLEN]; /* * Merge multiple attrib files to create the "view" for this backup. * There is only one case here, v4, since v3 didn't have inodes. */ for ( i = 0 ; i < ac->bkupMergeCnt ; i++ ) { bpc_attrib_dir dir; ssize_t entrySize; char *entries, *fileName; int attribFileExists, attribDirExists = 1; STRUCT_STAT st; snprintf(inodeDir, sizeof(inodeDir), "%s/pc/%s/%d/%s", BPC_TopDir, ac->hostName, ac->bkupMergeList[i].num, attribDir); snprintf(fullAttribPath, sizeof(fullAttribPath), "%s/%s", inodeDir, attribFile); attribFileExists = !stat(fullAttribPath, &st) && S_ISREG(st.st_mode); if ( !attribFileExists ) { attribDirExists = !stat(inodeDir, &st) && S_ISDIR(st.st_mode); } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attribCache_loadInode: path = %s, file exists = %d, dir exists = %d\n", fullAttribPath, attribFileExists, attribDirExists); if ( (ac->bkupMergeList[i].version < 4 && !attribFileExists) || !attribDirExists ) { /* * nothing to update here - keep going */ continue; } bpc_attrib_dirInit(&dir, ac->bkupMergeList[i].compress); if ( (status = bpc_attrib_dirRead(&dir, inodeDir, attribFile, ac->bkupMergeList[i].num)) ) { bpc_logErrf("bpc_attribCache_loadInode: bpc_attrib_dirRead(%s/%s) returned %d\n", inodeDir, attribFile, status); } entrySize = bpc_attrib_getEntries(&dir, NULL, 0); if ( (entries = malloc(entrySize)) && bpc_attrib_getEntries(&dir, entries, entrySize) == entrySize ) { for ( fileName = entries ; fileName < entries + entrySize ; fileName += strlen(fileName) + 1 ) { bpc_attrib_file *file = bpc_attrib_fileGet(&dir, fileName, 0); if ( !file ) continue; if ( file->type == BPC_FTYPE_DELETED ) { bpc_attrib_fileDeleteName(&attr->dir, fileName); } else { bpc_attrib_file *fileDest; if ( !(fileDest = bpc_attrib_fileGet(&attr->dir, fileName, 1)) ) return NULL; if ( fileDest->key.key == fileName ) { /* * new entry - initialize */ bpc_attrib_fileInit(fileDest, fileName, 0); } bpc_attrib_fileCopy(fileDest, file); } } } else { bpc_logErrf("bpc_attribCache_loadInode(%s): can't malloc %lu bytes for entries\n", fullAttribPath, (unsigned long)entrySize); if ( entries ) free(entries); bpc_attrib_dirDestroy(&dir); return NULL; } free(entries); bpc_attrib_dirDestroy(&dir); } } else { /* * non-merge case - read the single attrib file */ char inodeDir[BPC_MAXPATHLEN]; snprintf(inodeDir, sizeof(inodeDir), "%s/%s", ac->backupTopDir, attribDir); if ( (status = bpc_attrib_dirRead(&attr->dir, inodeDir, attribFile, ac->backupNum)) ) { bpc_logErrf("bpc_attribCache_loadInode: bpc_attrib_dirRead(%s/%s) returned %d\n", inodeDir, attribFile, status); } } if ( bpc_hashtable_entryCount(&ac->inodeHT) > BPC_ATTRIBCACHE_DIR_COUNT_MAX ) { bpc_attribCache_flush(ac, 0, NULL); } return attr; } bpc_attrib_file *bpc_attribCache_getFile(bpc_attribCache_info *ac, char *path, int allocate_if_missing, int dontReadInode) { char fileName[BPC_MAXPATHLEN]; bpc_attribCache_dir *attr; bpc_attrib_file *file; if ( !(attr = bpc_attribCache_loadPath(ac, fileName, path)) ) return NULL; attr->lruCnt = ac->cacheLruCnt++; if ( !(file = bpc_attrib_fileGet(&attr->dir, fileName, allocate_if_missing)) ) return NULL; if ( allocate_if_missing && file->key.key == fileName ) { /* * new entry - initialize */ bpc_attrib_fileInit(file, fileName, 0); file->compress = ac->compress; } if ( dontReadInode || file->nlinks == 0 ) return file; return bpc_attribCache_getInode(ac, file->inode, allocate_if_missing); } int bpc_attribCache_setFile(bpc_attribCache_info *ac, char *path, bpc_attrib_file *file, int dontOverwriteInode) { char fileName[BPC_MAXPATHLEN], indexStr[256]; bpc_attribCache_dir *attr, *attrInode; bpc_attrib_file *fileDest; if ( !(attr = bpc_attribCache_loadPath(ac, fileName, path)) ) return -1; attr->lruCnt = ac->cacheLruCnt++; file->compress = ac->compress; if ( !(fileDest = bpc_attrib_fileGet(&attr->dir, fileName, 1)) ) return -1; if ( fileDest->key.key == fileName ) { /* * new entry - initialize */ bpc_attrib_fileInit(fileDest, fileName, 0); } bpc_attrib_fileCopy(fileDest, file); attr->dirty = 1; if ( file->nlinks > 0 ) { bpc_attrib_file *inodeDest = bpc_attribCache_getInode(ac, file->inode, 0); if ( !dontOverwriteInode || !inodeDest ) { inodeDest = bpc_attribCache_getInode(ac, file->inode, 1); bpc_attrib_fileCopyOpt(inodeDest, file, 0); attrInode = bpc_attribCache_loadInode(ac, indexStr, file->inode); attrInode->dirty = 1; /* * remove the digest from the file attributes since the reference counting is reflected * by the inode (can't do this up above since fileDest might be the same as file). */ fileDest->digest.len = 0; return 1; } else { /* * remove the digest from the file attributes since the reference counting is reflected * by the inode (can't do this up above since fileDest might be the same as file). */ fileDest->digest.len = 0; return 0; } } return 1; } int bpc_attribCache_deleteFile(bpc_attribCache_info *ac, char *path) { char fileName[BPC_MAXPATHLEN]; bpc_attribCache_dir *attr; if ( !(attr = bpc_attribCache_loadPath(ac, fileName, path)) ) return -1; attr->lruCnt = ac->cacheLruCnt++; bpc_attrib_fileDeleteName(&attr->dir, fileName); attr->dirty = 1; return 0; } bpc_attrib_file *bpc_attribCache_getInode(bpc_attribCache_info *ac, ino_t inode, int allocate_if_missing) { char indexStr[256]; bpc_attribCache_dir *attr; bpc_attrib_file *file; if ( !(attr = bpc_attribCache_loadInode(ac, indexStr, inode)) ) return NULL; attr->lruCnt = ac->cacheLruCnt++; if ( !(file = bpc_attrib_fileGet(&attr->dir, indexStr, allocate_if_missing)) ) return NULL; if ( allocate_if_missing && file->key.key == indexStr ) { /* * new entry - initialize */ bpc_attrib_fileInit(file, indexStr, 0); file->compress = ac->compress; } return file; } int bpc_attribCache_setInode(bpc_attribCache_info *ac, ino_t inode, bpc_attrib_file *inodeSrc) { char indexStr[256]; bpc_attribCache_dir *attr; bpc_attrib_file *inodeDest; if ( !(attr = bpc_attribCache_loadInode(ac, indexStr, inode)) ) return -1; attr->lruCnt = ac->cacheLruCnt++; if ( !(inodeDest = bpc_attrib_fileGet(&attr->dir, indexStr, 1)) ) return -1; if ( inodeDest->key.key == indexStr ) { /* * new entry - initialize */ bpc_attrib_fileInit(inodeDest, indexStr, 0); } bpc_attrib_fileCopy(inodeDest, inodeSrc); attr->dirty = 1; return 0; } int bpc_attribCache_deleteInode(bpc_attribCache_info *ac, ino_t inode) { char indexStr[256]; bpc_attribCache_dir *attr; if ( !(attr = bpc_attribCache_loadInode(ac, indexStr, inode)) ) return -1; attr->lruCnt = ac->cacheLruCnt++; bpc_attrib_fileDeleteName(&attr->dir, indexStr); attr->dirty = 1; return 0; } int bpc_attribCache_getDirEntryCnt(bpc_attribCache_info *ac, char *path) { bpc_attribCache_dir *attr; char fileName[BPC_MAXPATHLEN]; size_t pathLen = strlen(path); /* * Append a fake file name so we actually open the directory's contents, not the directory entry one level up */ if ( pathLen >= BPC_MAXPATHLEN - 3 ) return -1; strcpy(path + pathLen, "/x"); attr = bpc_attribCache_loadPath(ac, fileName, path); path[pathLen] = '\0'; if ( !attr ) return -1; return bpc_hashtable_entryCount(&attr->dir.filesHT); } typedef struct { char *entries; ssize_t entryIdx; ssize_t entrySize; } dirEntry_info; static void bpc_attribCache_getDirEntry(bpc_attrib_file *file, dirEntry_info *info) { ssize_t len = strlen(file->name) + 1; if ( info->entryIdx < 0 ) return; if ( info->entries ) { if ( info->entryIdx + len + (ssize_t)sizeof(ino_t) > info->entrySize ) { info->entryIdx = -1; return; } memcpy(info->entries + info->entryIdx, file->name, len); info->entryIdx += len; memcpy(info->entries + info->entryIdx, &file->inode, sizeof(ino_t)); info->entryIdx += sizeof(ino_t); } else { info->entryIdx += len + sizeof(ino_t); } } ssize_t bpc_attribCache_getDirEntries(bpc_attribCache_info *ac, char *path, char *entries, ssize_t entrySize) { bpc_attribCache_dir *attr; char fileName[BPC_MAXPATHLEN], fullPath[BPC_MAXPATHLEN]; dirEntry_info info; size_t pathLen = strlen(path); ino_t inode = 0; /* * Append a fake file name so we actually open the directory's contents, not the directory entry one level up */ if ( pathLen >= BPC_MAXPATHLEN - 3 ) return -1; if ( pathLen == 1 && path[0] == '.' ) { if ( ac->currentDir[0] ) { snprintf(fullPath, BPC_MAXPATHLEN, "%s/x", ac->currentDir); } else { strcpy(fullPath, "/x"); } attr = bpc_attribCache_loadPath(ac, fileName, fullPath); strcpy(path, "."); } else { snprintf(fullPath, BPC_MAXPATHLEN, "%s/x", path); attr = bpc_attribCache_loadPath(ac, fileName, fullPath); } if ( !attr ) return -1; attr->lruCnt = ac->cacheLruCnt++; info.entries = entries; info.entryIdx = 0; info.entrySize = entrySize; if ( entries && entrySize >= (ssize_t)(5 + 2 * sizeof(ino_t)) ) { strcpy(info.entries + info.entryIdx, "."); info.entryIdx += 2; /* dummy inode number */ memcpy(info.entries + info.entryIdx, &inode, sizeof(inode)); info.entryIdx += sizeof(inode); strcpy(info.entries + info.entryIdx, ".."); info.entryIdx += 3; /* dummy inode number */ memcpy(info.entries + info.entryIdx, &inode, sizeof(inode)); info.entryIdx += sizeof(inode); } else { info.entryIdx += 5 + 2 * sizeof(ino_t); } bpc_hashtable_iterate(&attr->dir.filesHT, (void*)bpc_attribCache_getDirEntry, &info); return info.entryIdx; } typedef struct { char *path; int pathLen; int all; bpc_attribCache_info *ac; int entryCnt; int entryIdx; bpc_attribCache_dir **entries; bpc_hashtable *ht; int errorCnt; } flush_info; static void bpc_attribCache_dirWrite(bpc_attribCache_dir *attr, flush_info *info) { int status; if ( !info->ac->readOnly && !info->all && info->path ) { if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attribCache_dirWrite: comparing %s vs key %s\n", info->path, attr->key.key); if ( strncmp(info->path, attr->key.key, info->pathLen) || (((char*)attr->key.key)[info->pathLen] != '/' && ((char*)attr->key.key)[info->pathLen] != '\0') ) { if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attribCache_dirWrite: skipping %s (doesn't match %s)\n", (char*)attr->key.key, info->path); return; } } if ( !info->ac->readOnly && attr->dirty ) { bpc_digest *oldDigest = bpc_attrib_dirDigestGet(&attr->dir); if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_attribCache_dirWrite: writing %s/%s with %d entries (oldDigest = 0x%02x%02x...)\n", info->ac->backupTopDir, (char*)attr->key.key, bpc_hashtable_entryCount(&attr->dir.filesHT), oldDigest ? oldDigest->digest[0] : 0, oldDigest ? oldDigest->digest[1] : 0); if ( (status = bpc_attrib_dirWrite(info->ac->deltaInfo, &attr->dir, info->ac->backupTopDir, attr->key.key, oldDigest)) ) { bpc_logErrf("bpc_attribCache_dirWrite: failed to write attributes for dir %s\n", (char*)attr->key.key); info->errorCnt++; } } /* * Now deallocate memory */ bpc_attrib_dirDestroy(&attr->dir); if ( attr->key.key ) free(attr->key.key); bpc_hashtable_nodeDelete(info->ht, attr); } static void bpc_attribCache_flush_lruListFill(bpc_attribCache_dir *attr, flush_info *info) { if ( info->entryIdx >= info->entryCnt ) return; info->entries[info->entryIdx++] = attr; } static int bpc_attribCache_flush_lruCompare(bpc_attribCache_dir **d1, bpc_attribCache_dir **d2) { return (*d1)->lruCnt - (*d2)->lruCnt; } /* * Build a list of all entries in the hash table, sorted by LRU count from lowest to highest */ static void bpc_attribCache_flush_lruList(flush_info *info) { int i; /* * allocate list of all entries */ info->entryCnt = bpc_hashtable_entryCount(info->ht); info->entryIdx = 0; info->entries = NULL; if ( info->entryCnt == 0 ) return; if ( !(info->entries = malloc(info->entryCnt * sizeof(*info->entries))) ) { bpc_logErrf("bpc_attribCache_flush_lruList: can't allocated %lu bytes\n", (unsigned long)info->entryCnt * sizeof(*info->entries)); return; } bpc_hashtable_iterate(info->ht, (void*)bpc_attribCache_flush_lruListFill, info); /* * sort by lruCnt, from lowest to highest */ qsort(info->entries, info->entryCnt, sizeof(*info->entries), (void*)bpc_attribCache_flush_lruCompare); /* * Now flush the oldest half of the entries */ for ( i = 0 ; i < info->entryCnt / 2 ; i++ ) { bpc_attribCache_dirWrite(info->entries[i], info); } if ( info->entries ) free(info->entries); } /* * Flush some or all of the cache. If all, then flush everything. If path is not NULL * then just those entries that start with that path are flushed. */ void bpc_attribCache_flush(bpc_attribCache_info *ac, int all, char *path) { flush_info info; char attribPath[BPC_MAXPATHLEN]; info.all = all; info.ac = ac; if ( path ) { char pathDeep[BPC_MAXPATHLEN]; char fileName[BPC_MAXPATHLEN], dir[BPC_MAXPATHLEN]; snprintf(pathDeep, BPC_MAXPATHLEN, "%s/foo", path); splitPath(ac, dir, fileName, attribPath, pathDeep); info.path = attribPath; info.pathLen = strlen(info.path); } else { info.path = NULL; info.pathLen = 0; } info.entryCnt = 0; info.entryIdx = 0; info.entries = NULL; info.errorCnt = 0; if ( !all && !path ) { /* * flush the oldest half of the entries based on the lruCnt */ info.ht = &ac->attrHT; bpc_attribCache_flush_lruList(&info); info.ht = &ac->inodeHT; bpc_attribCache_flush_lruList(&info); } else { info.ht = &ac->attrHT; bpc_hashtable_iterate(&ac->attrHT, (void*)bpc_attribCache_dirWrite, &info); info.ht = &ac->inodeHT; bpc_hashtable_iterate(&ac->inodeHT, (void*)bpc_attribCache_dirWrite, &info); } if ( info.errorCnt ) { /* * Any errors likely mean the deltas are probably out of sync with the * file system, so request an fsck. */ bpc_poolRefRequestFsck(ac->backupTopDir, 1); } } /* * Returns the full mangled path, given a file path. */ void bpc_attribCache_getFullMangledPath(bpc_attribCache_info *ac, char *path, char *dirName, int backupNum) { char *p; int len; do { p = dirName; while ( dirName[0] == '.' && dirName[1] == '/' ) dirName += 2; while ( dirName[0] == '/' ) dirName++; } while ( p != dirName ); if ( backupNum < 0 || ac->bkupMergeCnt <= 0 ) { backupNum = ac->backupNum; } len = snprintf(path, BPC_MAXPATHLEN, "%s/pc/%s/%d/%s", BPC_TopDir, ac->hostName, backupNum, ac->shareName); if ( (dirName[0] == '/' && dirName[1] == '\0') || dirName[0] == '\0' || len >= BPC_MAXPATHLEN - 1 ) { return; } path[len++] = '/'; bpc_fileNameMangle(path + len, BPC_MAXPATHLEN - len, dirName); } rsync-bpc-3.1.2.1/backuppc/bpc_fileZIO.c0000664000047500004750000004010413510756401016602 0ustar craigcraig/* * Routines for reading and writing compressed files using zlib * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" /* * A freelist of unused data buffers. * We use the first sizeof(void*) bytes of the buffer as a single-linked * list, with a NULL at the end. */ static void *DataBufferFreeList = (void*)NULL; /* * Open a regular or compressed file for reading or writing/create */ int bpc_fileZIO_open(bpc_fileZIO_fd *fd, char *fileName, int writeFile, int compressLevel) { fd->strm.next_out = NULL; fd->strm.zalloc = NULL; fd->strm.zfree = NULL; fd->strm.opaque = NULL; fd->compressLevel = compressLevel; fd->first = 1; fd->write = writeFile; fd->eof = 0; fd->error = 0; fd->writeTeeStderr = 0; fd->lineBuf = NULL; fd->lineBufSize = 0; fd->lineBufLen = 0; fd->lineBufIdx = 0; fd->lineBufEof = 0; fd->bufSize = 1 << 20; /* 1MB */ if ( writeFile ) { fd->fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0660); if ( fd->fd < 0 ) { /* * try removing first */ unlink(fileName); fd->fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0660); } if ( fd->fd < 0 ) return -1; if ( fd->compressLevel ) { if (deflateInit2(&fd->strm, compressLevel, Z_DEFLATED, MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) { bpc_logErrf("bpc_fileZIO_open: compression init failed\n"); return -1; } fd->strm.next_out = (Bytef*)fd->buf; fd->strm.avail_out = fd->bufSize; } } else { fd->fd = open(fileName, O_RDONLY); if ( fd->fd < 0 ) return -1; if ( fd->compressLevel ) { if ( inflateInit(&fd->strm) != Z_OK ) { bpc_logErrf("bpc_fileZIO_open: compression init failed\n"); return -1; } fd->strm.avail_in = 0; } } if ( DataBufferFreeList ) { fd->buf = DataBufferFreeList; DataBufferFreeList = *(void**)DataBufferFreeList; } else { fd->buf = malloc(fd->bufSize); } if ( !fd->buf ) { bpc_logErrf("bpc_fileZIO_open: fatal error: can't allocate %u bytes\n", (unsigned)fd->bufSize); return -1; } if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_fileZIO_open(%s, %d, %d) -> %d\n", fileName, writeFile, compressLevel, fd->fd); return 0; } /* * Open an existing FILE stream for reading/writing. * Note: we used unbuffered integer fds here, and we simply grab the underlying integer fd. That will * mess up the FILE stream buffering if anything has been read/written from/to the FILE. * * This function is only used to support the legacy BackupPC::FileZIO feature that allows you to * pass STDIN in as an argument to open(). */ int bpc_fileZIO_fdopen(bpc_fileZIO_fd *fd, FILE *stream, int writeFile, int compressLevel) { fd->strm.next_out = NULL; fd->strm.zalloc = NULL; fd->strm.zfree = NULL; fd->strm.opaque = NULL; fd->compressLevel = compressLevel; fd->first = 1; fd->write = writeFile; fd->eof = 0; fd->error = 0; fd->writeTeeStderr = 0; fd->lineBuf = NULL; fd->lineBufSize = 0; fd->lineBufLen = 0; fd->lineBufIdx = 0; fd->lineBufEof = 0; fd->fd = fileno(stream); if ( fd->fd < 0 ) return -1; fd->bufSize = 1 << 20; /* 1MB */ if ( !(fd->buf = malloc(fd->bufSize)) ) { bpc_logErrf("bpc_fileZIO_fdopen: can't allocate %u bytes\n", (unsigned)fd->bufSize); return -1; } if ( fd->compressLevel ) { if ( writeFile ) { if (deflateInit2(&fd->strm, compressLevel, Z_DEFLATED, MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) { bpc_logErrf("bpc_fileZIO_open: compression init failed\n"); return -1; } fd->strm.next_out = (Bytef*)fd->buf; fd->strm.avail_out = fd->bufSize; } else { if ( inflateInit(&fd->strm) != Z_OK ) { bpc_logErrf("bpc_fileZIO_open: compression init failed\n"); return -1; } fd->strm.avail_in = 0; } } if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_fileZIO_fdopen(%d, %d) -> %d\n", writeFile, compressLevel, fd->fd); return 0; } void bpc_fileZIO_writeTeeStderr(bpc_fileZIO_fd *fd, int tee) { fd->writeTeeStderr = tee; } /* * Read from a compressed or regular file. */ ssize_t bpc_fileZIO_read(bpc_fileZIO_fd *fd, uchar *buf, size_t nRead) { size_t totalRead = 0; if ( fd->write || fd->fd < 0 ) return -1; if ( fd->compressLevel == 0 ) { ssize_t thisRead; while ( nRead > 0 ) { do { thisRead = read(fd->fd, buf, nRead); } while ( thisRead < 0 && errno == EINTR ); if ( thisRead < 0 ) return thisRead; if ( thisRead == 0 ) return totalRead; buf += thisRead; nRead -= thisRead; totalRead += thisRead; } return totalRead; } if ( fd->error ) return fd->error; while ( nRead > 0 ) { /* * Start by trying to read more of the compressed input file */ int maxRead, thisRead = -1; if ( fd->strm.avail_in == 0 ) { fd->strm.next_in = (Bytef*)fd->buf; } maxRead = fd->bufSize - ((fd->strm.next_in - (Bytef*)fd->buf) + fd->strm.avail_in); if ( !fd->eof && maxRead > 0 ) { do { thisRead = read(fd->fd, fd->strm.next_in + fd->strm.avail_in, maxRead); } while ( thisRead < 0 && errno == EINTR ); if ( thisRead < 0 ) { fd->error = thisRead; return fd->error; } fd->strm.avail_in += thisRead; if ( thisRead == 0 ) { fd->eof = 1; } } while ( nRead > 0 ) { int status, numOut; fd->strm.next_out = (Bytef*)buf; fd->strm.avail_out = nRead; if ( fd->first && fd->strm.avail_in > 0 ) { /* * we are at the very start of a new zlib block (or it could be cached checksums) */ fd->first = 0; if ( fd->strm.next_in[0] == 0xd6 || fd->strm.next_in[0] == 0xd7 ) { /* * Flag 0xd6 or 0xd7 means this is a compressed file with * appended md4 block checksums for rsync. Change * the first byte back to 0x78 and proceed. */ fd->strm.next_in[0] = 0x78; } else if ( fd->strm.next_in[0] == 0xb3 ) { /* * Flag 0xb3 means this is the start of the rsync * block checksums, so consider this as EOF for * the compressed file. Also seek the file so * it is positioned at the 0xb3. */ fd->eof = 1; /* TODO: check return status */ lseek(fd->fd, -fd->strm.avail_in, SEEK_CUR); fd->strm.avail_in = 0; } } status = inflate(&fd->strm, fd->eof ? Z_SYNC_FLUSH : Z_NO_FLUSH); numOut = fd->strm.next_out - (Bytef*)buf; nRead -= numOut; buf += numOut; totalRead += numOut; if ( BPC_LogLevel >= 10 ) bpc_logMsgf("inflate returns %d; thisRead = %d, avail_in = %d, numOut = %d\n", status, thisRead, fd->strm.avail_in, numOut); if ( fd->eof && fd->strm.avail_in == 0 && numOut == 0 ) return totalRead; if ( status == Z_OK && fd->strm.avail_in == 0 ) break; if ( status == Z_BUF_ERROR && fd->strm.avail_in == 0 && numOut == 0 ) break; if ( status == Z_STREAM_END ) { inflateReset(&fd->strm); fd->first = 1; } if ( status < 0 ) { /* * return error immediately if there are no bytes to return */ if ( totalRead <= 0 ) return status; /* * save error return for next call and return remaining buffer */ fd->error = status; return totalRead; } } } return totalRead; } /* * Write to a compressed or regular file. * Write flush and eof is indicated with nWrite == 0. */ ssize_t bpc_fileZIO_write(bpc_fileZIO_fd *fd, uchar *buf, size_t nWrite) { if ( !fd->write || fd->fd < 0 ) return -1; if ( fd->eof ) return 0; if ( fd->writeTeeStderr && nWrite > 0 ) (void)fwrite((char*)buf, nWrite, 1, stderr); if ( fd->compressLevel == 0 ) { int thisWrite, totalWrite = 0; while ( nWrite > 0 ) { do { thisWrite = write(fd->fd, buf, nWrite); } while ( thisWrite < 0 && errno == EINTR ); if ( thisWrite < 0 ) return thisWrite; buf += thisWrite; nWrite -= thisWrite; totalWrite += thisWrite; } return totalWrite; } if ( fd->error ) return fd->error; if ( nWrite == 0 || (fd->strm.total_in > (1 << 23) && fd->strm.total_out < (1 << 18)) ) { /* * final or intermediate flush (if the compression ratio is too high, since the * perl Compress::Zlib implementation allocates the output buffer for inflate * and it could grow to be very large). */ if ( BPC_LogLevel >= 10 ) bpc_logMsgf("Flushing (nWrite = %d)\n", nWrite); while ( 1 ) { int status, numOut, thisWrite; char *writePtr = fd->buf; fd->strm.next_in = NULL; fd->strm.avail_in = 0; fd->strm.next_out = (Bytef*)fd->buf; fd->strm.avail_out = fd->bufSize; status = deflate(&fd->strm, Z_FINISH); numOut = fd->strm.next_out - (Bytef*)fd->buf; while ( numOut > 0 ) { do { thisWrite = write(fd->fd, writePtr, numOut); } while ( thisWrite < 0 && errno == EINTR ); if ( thisWrite < 0 ) return thisWrite; numOut -= thisWrite; writePtr += thisWrite; } if ( status != Z_OK ) break; } deflateReset(&fd->strm); } if ( nWrite == 0 ) { fd->eof = 1; return nWrite; } fd->strm.next_in = (Bytef*)buf; fd->strm.avail_in = nWrite; while ( fd->strm.avail_in > 0 ) { int numOut, thisWrite; char *writePtr = fd->buf; fd->strm.next_out = (Bytef*)fd->buf; fd->strm.avail_out = fd->bufSize; deflate(&fd->strm, Z_NO_FLUSH); numOut = fd->strm.next_out - (Bytef*)fd->buf; while ( numOut > 0 ) { do { thisWrite = write(fd->fd, writePtr, numOut); } while ( thisWrite < 0 && errno == EINTR ); if ( thisWrite < 0 ) return thisWrite; numOut -= thisWrite; writePtr += thisWrite; } } return nWrite; } int bpc_fileZIO_close(bpc_fileZIO_fd *fd) { if ( fd->fd < 0 ) return -1; if ( fd->compressLevel ) { if ( fd->write ) { /* * Flush the output file */ bpc_fileZIO_write(fd, NULL, 0); deflateEnd(&fd->strm); } else { inflateEnd(&fd->strm); } } if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_fileZIO_close(%d)\n", fd->fd); close(fd->fd); if ( fd->lineBuf ) free(fd->lineBuf); fd->lineBuf = NULL; if ( fd->buf ) { *(void**)fd->buf = DataBufferFreeList; DataBufferFreeList = fd->buf; fd->buf = NULL; } fd->fd = -1; return 0; } int bpc_fileZIO_rewind(bpc_fileZIO_fd *fd) { if ( fd->write ) return -1; if ( fd->compressLevel ) { inflateReset(&fd->strm); fd->first = 1; fd->eof = 0; fd->error = 0; fd->strm.avail_in = 0; } return lseek(fd->fd, 0, SEEK_SET) == 0 ? 0 : -1; } /* * Returns \n terminated lines, one at a time, from the opened read stream. * The returned string is not '\0' terminated. At EOF sets *str = NULL; */ int bpc_fileZIO_readLine(bpc_fileZIO_fd *fd, char **str, size_t *strLen) { if ( !fd->lineBuf ) { /* * allocate initial read buffer */ fd->lineBufSize = 65536; if ( !(fd->lineBuf = malloc(fd->lineBufSize)) ) { bpc_logErrf("bpc_fileZIO_readLine: can't allocate %u bytes\n", (unsigned)fd->lineBufSize); return -1; } fd->lineBufLen = 0; fd->lineBufIdx = 0; fd->lineBufEof = 0; } while ( 1 ) { char *p; if ( fd->lineBufIdx < fd->lineBufLen ) { if ( (p = memchr(fd->lineBuf + fd->lineBufIdx, '\n', fd->lineBufLen - fd->lineBufIdx)) ) { /* * found next complete line */ p++; *str = fd->lineBuf + fd->lineBufIdx; *strLen = p - (fd->lineBuf + fd->lineBufIdx); fd->lineBufIdx += p - (fd->lineBuf + fd->lineBufIdx); return 0; } else if ( fd->lineBufEof ) { /* * return last string - not \n terminated */ *str = fd->lineBuf + fd->lineBufIdx; *strLen = fd->lineBufLen - fd->lineBufIdx; fd->lineBufIdx += fd->lineBufLen - fd->lineBufIdx; return 0; } else if ( fd->lineBufLen >= fd->lineBufSize ) { /* * No complete lines left, and buffer is full. Either move the unused buffer down to make * more room for reading, or make the buffer bigger. */ if ( fd->lineBufIdx > 0 ) { memmove(fd->lineBuf, fd->lineBuf + fd->lineBufIdx, fd->lineBufLen - fd->lineBufIdx); fd->lineBufLen -= fd->lineBufIdx; fd->lineBufIdx = 0; } else { fd->lineBufSize *= 2; if ( !(fd->lineBuf = realloc(fd->lineBuf, fd->lineBufSize)) ) { bpc_logErrf("bpc_fileZIO_readLine: can't reallocate %u bytes\n", (unsigned)fd->lineBufSize); return -1; } } } } if ( fd->lineBufIdx >= fd->lineBufLen && fd->lineBufEof ) { /* * at EOF */ *str = NULL; *strLen = 0; return 0; } if ( fd->lineBufIdx >= fd->lineBufLen ) { fd->lineBufLen = 0; fd->lineBufIdx = 0; } if ( fd->lineBufLen < fd->lineBufSize && !fd->lineBufEof ) { int nread = bpc_fileZIO_read(fd, (uchar*)fd->lineBuf + fd->lineBufLen, fd->lineBufSize - fd->lineBufLen); if ( nread < 0 ) { bpc_logErrf("bpc_fileZIO_readLine: reading %u returned %d\n", (unsigned)(fd->lineBufSize - fd->lineBufLen), nread); return nread; } if ( nread == 0 ) fd->lineBufEof = 1; fd->lineBufLen += nread; } } } rsync-bpc-3.1.2.1/backuppc/backuppc.h0000664000047500004750000004122313510756401016255 0ustar craigcraig/* * Definitions for BackupPC libraries. * * Copyright (C) 2013 Craig Barratt. * * 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. */ #ifndef _BACKUPPC_H_ #define _BACKUPPC_H_ #include #include "zlib/zlib.h" #define BPC_MAXPATHLEN (2 * MAXPATHLEN) extern char BPC_PoolDir[]; extern char BPC_CPoolDir[]; extern char BPC_PoolDir3[]; extern char BPC_CPoolDir3[]; extern char BPC_TopDir[]; extern int BPC_HardLinkMax; extern int BPC_PoolV3Enabled; extern int BPC_TmpFileUnique; extern int BPC_LogLevel; /* * Maximum length of a digest - 16 bytes for MD5, but 4 bytes of collision counting */ #define BPC_DIGEST_LEN_MAX 20 #define uint64 unsigned int64 typedef struct { uchar digest[BPC_DIGEST_LEN_MAX]; int len; } bpc_digest; /* * Simple hash table functions. * * Any structure stored in a hash table should start with a bpc_hashtable_key entry for the key. */ typedef struct { void *key; /* a NULL key means this node is empty or deleted; also used for free list */ uint32 keyLen; /* with a NULL key, a zero value means empty; non-zero means deleted */ uint32 keyHash; } bpc_hashtable_key; typedef struct { bpc_hashtable_key **nodes; uint32 nodeSize; uint32 size; uint32 entries; /* total number of user entries */ uint32 entriesDel; /* number of entries flagged as deleted */ } bpc_hashtable; void bpc_hashtable_create(bpc_hashtable *tbl, uint32 size, uint32 nodeSize); void bpc_hashtable_destroy(bpc_hashtable *tbl); void bpc_hashtable_erase(bpc_hashtable *tbl); uint32 bpc_hashtable_hash(uchar *key, uint32 keyLen); void *bpc_hashtable_find(bpc_hashtable *tbl, unsigned char *key, unsigned int keyLen, int allocate_if_missing); void bpc_hashtable_growSize(bpc_hashtable *tbl, uint32 newSize); void bpc_hashtable_nodeDelete(bpc_hashtable *tbl, void *node); void bpc_hashtable_iterate(bpc_hashtable *tbl, void (*callback)(void*, void*), void *arg1); void *bpc_hashtable_nextEntry(bpc_hashtable *tbl, uint *idx); int bpc_hashtable_entryCount(bpc_hashtable *tbl); /* * Reference counting */ typedef struct { bpc_hashtable ht; int initDone; } bpc_refCount_info; void bpc_poolRefInit(bpc_refCount_info *info, int entryCnt); void bpc_poolRefDestroy(bpc_refCount_info *info); void bpc_poolRefSet(bpc_refCount_info *info, bpc_digest *digest, int32 count); int bpc_poolRefDelete(bpc_refCount_info *info, bpc_digest *digest); int bpc_poolRefGet(bpc_refCount_info *info, bpc_digest *digest, int32 *count); int bpc_poolRefIncr(bpc_refCount_info *info, bpc_digest *digest, int32 delta); int bpc_poolRefIterate(bpc_refCount_info *info, bpc_digest *digest, int32 *count, uint *idx); void bpc_poolRefCountPrint(bpc_refCount_info *info); int bpc_poolRefFileWrite(bpc_refCount_info *info, char *fileName); int bpc_poolRefFileRead(bpc_refCount_info *info, char *fileName); void bpc_poolRefRequestFsck(char *targetDir, int ext); /* * Delta counting */ typedef struct { bpc_refCount_info refCnt[2]; char targetDir[BPC_MAXPATHLEN]; } bpc_deltaCount_info; void bpc_poolRefDeltaFileInit(bpc_deltaCount_info *info, char *hostDir); void bpc_poolRefDeltaFileDestroy(bpc_deltaCount_info *info); uint32 bpc_poolRefDeltaFileFlush(bpc_deltaCount_info *info); void bpc_poolRefDeltaUpdate(bpc_deltaCount_info *info, int compress, bpc_digest *digest, int32 count); void bpc_poolRefDeltaPrint(bpc_deltaCount_info *info); void bpc_poolRefDeltaFileInitOld(char *hostDir); uint32 bpc_poolRefDeltaFileFlushOld(void); void bpc_poolRefDeltaUpdateOld(int compress, bpc_digest *digest, int32 count); void bpc_poolRefDeltaPrintOld(void); /* * Compressed file IO. A compressed file descriptor contains a buffer for compressed data. */ typedef struct { z_stream strm; char *buf; size_t bufSize; int fd; int first; int write; int eof; int error; int compressLevel; int writeTeeStderr; /* * readLine buffer */ char *lineBuf; size_t lineBufSize; size_t lineBufLen; size_t lineBufIdx; int lineBufEof; } bpc_fileZIO_fd; int bpc_fileZIO_open(bpc_fileZIO_fd *fd, char *fileName, int writeFile, int compressLevel); int bpc_fileZIO_fdopen(bpc_fileZIO_fd *fd, FILE *stream, int writeFile, int compressLevel); void bpc_fileZIO_writeTeeStderr(bpc_fileZIO_fd *fd, int tee); ssize_t bpc_fileZIO_read(bpc_fileZIO_fd *fd, uchar *buf, size_t nRead); ssize_t bpc_fileZIO_write(bpc_fileZIO_fd *fd, uchar *buf, size_t nWrite); int bpc_fileZIO_readLine(bpc_fileZIO_fd *fd, char **str, size_t *strLen); int bpc_fileZIO_close(bpc_fileZIO_fd *fd); int bpc_fileZIO_rewind(bpc_fileZIO_fd *fd); #define BPC_POOL_WRITE_BUF_SZ (8 * 1048576) /* 8 MB - must be at least 1MB so the V3 digest calculation can occur */ #define BPC_POOL_WRITE_CONCURRENT_MATCH (16) /* number of pool files we concurrently match */ typedef struct _bpc_candidate_file { bpc_digest digest; OFF_T fileSize; int v3File; char fileName[BPC_MAXPATHLEN]; struct _bpc_candidate_file *next; } bpc_candidate_file; typedef struct { bpc_fileZIO_fd fd; int used; int v3File; OFF_T fileSize; bpc_digest digest; char fileName[BPC_MAXPATHLEN]; } bpc_candidate_match; typedef struct { int compress; int state; int eof; int retValue; int retryCnt; OFF_T fileSize; OFF_T poolFileSize; bpc_digest digest; bpc_digest digest_v3; md_context md5; /* * Set of active potential file matches. All files match up to matchPosn. */ OFF_T matchPosn; bpc_candidate_match match[BPC_POOL_WRITE_CONCURRENT_MATCH]; bpc_candidate_file *candidateList; /* * When we first build the candidate match list, we remember where the first * zero-length file is (if any), and the next open slot. If these change * before we insert a new file, we know to try again (since someone probably * won a race to get there first). */ int digestExtZeroLen, digestExtOpen; /* * Temporary output file if the in-memory buffer is too small */ int fdOpen; bpc_fileZIO_fd fd; char tmpFileName[BPC_MAXPATHLEN]; /* * Error count */ int errorCnt; /* * Initial file buffer - used if the entire file fits, or otherwise keeps the first 1MB * of the file so we can compute the V3 digest. If we have the entire file in memory * then fileWritten == 0. * * This buffer is allocated to be size BPC_POOL_WRITE_BUF_SZ on open() and freed on close(). */ uint32 bufferIdx; uchar *buffer; } bpc_poolWrite_info; int bpc_poolWrite_open(bpc_poolWrite_info *info, int compress, bpc_digest *digest); int bpc_poolWrite_write(bpc_poolWrite_info *info, uchar *data, size_t dataLen); int bpc_poolWrite_createPoolDir(bpc_poolWrite_info *info, bpc_digest *digest); void bpc_poolWrite_close(bpc_poolWrite_info *info, int *match, bpc_digest *digest, OFF_T *poolFileSize, int *errorCnt); void bpc_poolWrite_cleanup(bpc_poolWrite_info *info); void bpc_poolWrite_repeatPoolWrite(bpc_poolWrite_info *info, char *fileName); int bpc_poolWrite_copyToPool(bpc_poolWrite_info *info, char *poolPath, char *fileName); void bpc_poolWrite_addToPool(bpc_poolWrite_info *info, char *fileName, int v3PoolFile); int bpc_poolWrite_unmarkPendingDelete(char *poolPath); /* * General library routines */ void bpc_lib_conf_init(char *topDir, int hardLinkMax, int poolV3Enabled, int logLevel); void bpc_lib_setTmpFileUnique(int val); int bpc_lib_setLogLevel(int logLevel); void bpc_byte2hex(char *outStr, int byte); uchar bpc_hexStr2byte(char c1, char c2); void bpc_digest_buffer2MD5(bpc_digest *digest, uchar *buffer, size_t bufferLen); void bpc_digest_append_ext(bpc_digest *digest, uint32 ext); void bpc_digest_digest2str(bpc_digest *digest, char *hexStr); void bpc_digest_str2digest(bpc_digest *digest, char *hexStr); int bpc_digest_compare(bpc_digest *digest1, bpc_digest *digest2); void bpc_digest_md52path(char *path, int compress, bpc_digest *digest); void bpc_digest_md52path_v3(char *path, int compress, bpc_digest *digest); void bpc_digest_buffer2MD5_v3(bpc_digest *digest, uchar *buffer, size_t bufferLen); void bpc_fileNameEltMangle(char *path, int pathSize, char *pathUM); void bpc_fileNameMangle(char *path, int pathSize, char *pathUM); void bpc_logMsgf(char *fmt, ...); void bpc_logErrf(char *fmt, ...); void bpc_logMsgGet(char **mesg, size_t *mesgLen); void bpc_logMsgErrorCntGet(unsigned long *errorCnt); void bpc_logMsgCBSet(void (*cb)(int errFlag, char *mesg, size_t mesgLen)); /* * Directory operations */ int bpc_path_create(char *path); int bpc_path_remove(bpc_deltaCount_info *deltaInfo, char *path, int compress); int bpc_path_refCountAll(bpc_deltaCount_info *deltaInfo, char *path, int compress, int incr); int bpc_path_refCountAllInodeMax(bpc_deltaCount_info *deltaInfo, char *path, int compress, int incr, unsigned int *inodeMax); int bpc_lockRangeFd(int fd, OFF_T offset, OFF_T len, int block); int bpc_unlockRangeFd(int fd, OFF_T offset, OFF_T len); int bpc_lockRangeFile(char *lockFile, OFF_T offset, OFF_T len, int block); void bpc_unlockRangeFile(int lockFd); /* * File attribs */ typedef struct { bpc_hashtable_key key; void *value; uint32 valueLen; } bpc_attrib_xattr; typedef struct { bpc_hashtable_key key; char *name; ushort type; ushort compress; /* * isTemp is set if this is a temporary attribute entry (eg: mkstemp), that * doesn't have referencing counting for the digest. Therefore, when a * temporary file is created or deleted, there is no change to the * reference counts. */ ushort isTemp; uint32 mode; uid_t uid; gid_t gid; uint32 nlinks; time_t mtime; OFF_T size; ino_t inode; int32 backupNum; bpc_digest digest; /* * hash table of bpc_attrib_xattr entries, indexed by xattr key */ bpc_hashtable xattrHT; } bpc_attrib_file; /* * A directory is a hash table of file attributes, indexed by file name */ typedef struct { bpc_digest digest; ushort compress; /* * hash table of bpc_attrib_file entries, indexed by file name */ bpc_hashtable filesHT; } bpc_attrib_dir; bpc_attrib_xattr *bpc_attrib_xattrGet(bpc_attrib_file *file, void *key, int keyLen, int allocate_if_missing); void bpc_attrib_xattrDestroy(bpc_attrib_xattr *xattr); int bpc_attrib_xattrDelete(bpc_attrib_file *file, void *key, int keyLen); int bpc_attrib_xattrDeleteAll(bpc_attrib_file *file); int bpc_attrib_xattrSetValue(bpc_attrib_file *file, void *key, int keyLen, void *value, uint32 valueLen); int bpc_attrib_xattrCount(bpc_attrib_file *file); size_t bpc_attrib_xattrList(bpc_attrib_file *file, char *list, size_t listLen, int ignoreRsyncACLs); void bpc_attrib_fileInit(bpc_attrib_file *file, char *fileName, int xattrNumEntries); void bpc_attrib_fileDestroy(bpc_attrib_file *file); bpc_attrib_file *bpc_attrib_fileGet(bpc_attrib_dir *dir, char *fileName, int allocate_if_missing); void bpc_attrib_fileCopyOpt(bpc_attrib_file *fileDest, bpc_attrib_file *fileSrc, int overwriteEmptyDigest); void bpc_attrib_fileCopy(bpc_attrib_file *fileDest, bpc_attrib_file *fileSrc); int bpc_attrib_fileCompare(bpc_attrib_file *file0, bpc_attrib_file *file1); void bpc_attrib_fileDeleteName(bpc_attrib_dir *dir, char *fileName); int bpc_attrib_fileCount(bpc_attrib_dir *dir); char *bpc_attrib_fileType2Text(int type); void bpc_attrib_dirInit(bpc_attrib_dir *dir, int compressLevel); void bpc_attrib_dirDestroy(bpc_attrib_dir *dir); ssize_t bpc_attrib_getEntries(bpc_attrib_dir *dir, char *entries, ssize_t entrySize); void bpc_attrib_dirRefCount(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, int incr); void bpc_attrib_dirRefCountInodeMax(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, int incr, unsigned int *inodeMax); void bpc_attrib_attribFilePath(char *path, char *dir, char *attribFileName); bpc_digest *bpc_attrib_dirDigestGet(bpc_attrib_dir *dir); uchar *bpc_attrib_buf2file(bpc_attrib_file *file, uchar *buf, uchar *bufEnd, int xattrNumEntries); uchar *bpc_attrib_buf2fileFull(bpc_attrib_file *file, uchar *buf, uchar *bufEnd); uchar *bpc_attrib_file2buf(bpc_attrib_file *file, uchar *buf, uchar *bufEnd); int bpc_attrib_digestRead(bpc_attrib_dir *dir, bpc_digest *digest, char *attribPath); int bpc_attrib_dirRead(bpc_attrib_dir *dir, char *dirPath, char *attribFileName, int backupNum); int bpc_attrib_dirWrite(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, char *dirPath, char *attribFileName, bpc_digest *oldDigest); void bpc_attrib_backwardCompat(int writeOldStyleAttribFile, int keepOldAttribFiles); /* * Attrib caching */ #define BPC_FTYPE_FILE (0) #define BPC_FTYPE_HARDLINK (1) #define BPC_FTYPE_SYMLINK (2) #define BPC_FTYPE_CHARDEV (3) #define BPC_FTYPE_BLOCKDEV (4) #define BPC_FTYPE_DIR (5) #define BPC_FTYPE_FIFO (6) #define BPC_FTYPE_SOCKET (8) #define BPC_FTYPE_UNKNOWN (9) #define BPC_FTYPE_DELETED (10) #define BPC_FTYPE_INVALID (11) typedef struct { int num; int compress; int version; } bpc_backup_info; typedef struct { int backupNum; int compress; int readOnly; uint cacheLruCnt; /* * optional merging of backups to create view for restore */ bpc_backup_info *bkupMergeList; int bkupMergeCnt; /* * Hash table of cached file attributes. * Key is the mangled attrib path (excluding backupTopDir[], and including attrib file name). * Value is a bpc_attrib_dir structure. * - Keys of the bpc_attrib_dir hash table are the file names in that directory. */ bpc_hashtable attrHT; /* * Hash table of cached inode attributes. * Key is the inode attribute path (excluding backupTopDir[]). * Value is a bpc_attrib_dir structure. * - Keys of the bpc_attrib_dir hash table are the inode numbers converted to ascii hex, lsb first. */ bpc_hashtable inodeHT; /* * Delta reference count for any changes as we write/change files or attributes */ bpc_deltaCount_info *deltaInfo; char shareName[BPC_MAXPATHLEN]; int shareNameLen; char shareNameUM[BPC_MAXPATHLEN]; char hostName[BPC_MAXPATHLEN]; char hostDir[BPC_MAXPATHLEN]; char backupTopDir[BPC_MAXPATHLEN]; char currentDir[BPC_MAXPATHLEN]; } bpc_attribCache_info; typedef struct { bpc_hashtable_key key; int dirty; /* * We flag directories whose parents either don't exist or aren't directories. * We ignore attributes on bad directories. * Initially this flag is zero, meaning we don't know if this directory is ok. * After we check, > 0 means parent does exist and is a directory ; < 0 means dir is bad */ int dirOk; uint lruCnt; bpc_attrib_dir dir; } bpc_attribCache_dir; void bpc_attribCache_init(bpc_attribCache_info *ac, char *host, int backupNum, char *shareNameUM, int compress); void bpc_attribCache_setDeltaInfo(bpc_attribCache_info *ac, bpc_deltaCount_info *deltaInfo); void bpc_attribCache_setMergeList(bpc_attribCache_info *ac, bpc_backup_info *bkupList, int bkupCnt); void bpc_attribCache_destroy(bpc_attribCache_info *ac); int bpc_attribCache_readOnly(bpc_attribCache_info *ac, int readOnly); void bpc_attribCache_setCurrentDirectory(bpc_attribCache_info *ac, char *dir); bpc_attrib_file *bpc_attribCache_getFile(bpc_attribCache_info *ac, char *path, int allocate_if_missing, int dontReadInode); int bpc_attribCache_setFile(bpc_attribCache_info *ac, char *path, bpc_attrib_file *file, int dontOverwriteInode); int bpc_attribCache_deleteFile(bpc_attribCache_info *ac, char *path); bpc_attrib_file *bpc_attribCache_getInode(bpc_attribCache_info *ac, ino_t inode, int allocate_if_missing); int bpc_attribCache_setInode(bpc_attribCache_info *ac, ino_t inode, bpc_attrib_file *inodeSrc); int bpc_attribCache_deleteInode(bpc_attribCache_info *ac, ino_t inode); int bpc_attribCache_getDirEntryCnt(bpc_attribCache_info *ac, char *path); ssize_t bpc_attribCache_getDirEntries(bpc_attribCache_info *ac, char *path, char *entries, ssize_t entrySize); void bpc_attribCache_flush(bpc_attribCache_info *ac, int all, char *path); void bpc_attribCache_getFullMangledPath(bpc_attribCache_info *ac, char *path, char *dirName, int backupNum); #endif rsync-bpc-3.1.2.1/backuppc/bpc_poolWrite.c0000664000047500004750000010560713510756401017277 0ustar craigcraig/* * Routines for matching and writing files in the pool. * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" static uint32 PoolWriteCnt = 0; /* * Buffer used in various places for copying, comparing etc */ #define COMPARE_BUF_SZ (1 << 20) /* 1.0 MB */ static uchar TempBuf[2 * COMPARE_BUF_SZ]; /* * A freelist of unused BPC_POOL_WRITE_BUF_SZ sized-buffers. * We use the first sizeof(void*) bytes of the buffer as a single-linked * list, with a NULL at the end. */ static void *DataBufferFreeList = (void*)NULL; int bpc_poolWrite_open(bpc_poolWrite_info *info, int compress, bpc_digest *digest) { int i; info->compress = compress; info->eof = 0; info->errorCnt = 0; info->state = 0; info->bufferIdx = 0; info->fileSize = 0; info->matchPosn = 0; info->candidateList = NULL; info->fdOpen = 0; info->retValue = -1; info->poolFileSize = 0; info->retryCnt = 0; info->digestExtOpen = -1; info->digestExtZeroLen = -1; for ( i = 0 ; i < BPC_POOL_WRITE_CONCURRENT_MATCH ; i++ ) { info->match[i].used = 0; } if ( DataBufferFreeList ) { info->buffer = DataBufferFreeList; DataBufferFreeList = *(void**)DataBufferFreeList; } else { info->buffer = malloc(BPC_POOL_WRITE_BUF_SZ); } if ( !info->buffer ) { bpc_logErrf("bpc_poolWrite_open: can't allocate %d bytes for buffer\n", BPC_POOL_WRITE_BUF_SZ); return -1; } if ( digest ) { info->digest = *digest; /* TODO: don't have V3 digest at this point! */ info->state = 2; } else { info->digest.len = 0; } info->digest_v3.len = 0; if ( snprintf(info->tmpFileName, sizeof(info->tmpFileName), "%s/%d.%d.%d", compress ? BPC_CPoolDir : BPC_PoolDir, (int)getpid(), PoolWriteCnt++, BPC_TmpFileUnique >= 0 ? BPC_TmpFileUnique : 0) >= (int)sizeof(info->tmpFileName) - 1 ) { bpc_logErrf("bpc_poolWrite_open: file name too long %s\n", info->tmpFileName); return -1; } return 0; } /* * Fill out the array of candidate matching files. Returns the number of active * matching files. */ static int bpc_poolWrite_updateMatches(bpc_poolWrite_info *info) { int i, nMatch = 0; for ( i = 0 ; i < BPC_POOL_WRITE_CONCURRENT_MATCH ; i++ ) { if ( info->match[i].used ) { nMatch++; continue; } while ( info->candidateList ) { int match = 1; bpc_candidate_file *candidateFile; candidateFile = info->candidateList; info->candidateList = candidateFile->next; if ( bpc_fileZIO_open(&info->match[i].fd, candidateFile->fileName, 0, info->compress) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_updateMatches: can't open candidate file %s for read\n", candidateFile->fileName); free(candidateFile); continue; } /* * We need to check that the first info->matchPosn bytes of the candidate file match * the original file. */ if ( info->matchPosn > 0 ) { if ( info->fdOpen ) { /* * Compare the candidate file against the data in the file */ uchar *buf0 = TempBuf; uchar *buf1 = TempBuf + COMPARE_BUF_SZ; OFF_T idx = 0; bpc_fileZIO_rewind(&info->fd); while ( idx < info->matchPosn ) { OFF_T thisRead = info->matchPosn - idx; OFF_T nread0, nread1; if ( thisRead > COMPARE_BUF_SZ ) thisRead = COMPARE_BUF_SZ; nread0 = bpc_fileZIO_read(&info->fd, buf0, thisRead); nread1 = bpc_fileZIO_read(&info->match[i].fd, buf1, thisRead); if ( nread0 != nread1 || memcmp(buf0, buf1, nread0) ) { /* * Need to keep reading the original file to get back to matchPosn */ match = 0; } idx += nread0; } } else { /* * Compare the candidate file against the data in the buffer */ uchar *buf1 = TempBuf; OFF_T idx = 0; while ( idx < info->matchPosn ) { OFF_T thisRead = info->matchPosn - idx; OFF_T nread1; if ( thisRead > COMPARE_BUF_SZ ) thisRead = COMPARE_BUF_SZ; if ( thisRead > info->bufferIdx - idx ) thisRead = info->bufferIdx - idx; nread1 = bpc_fileZIO_read(&info->match[i].fd, buf1, thisRead); if ( thisRead != nread1 || memcmp(info->buffer + idx, buf1, thisRead) ) { match = 0; break; } idx += thisRead; } } } if ( !match ) { if ( BPC_LogLevel >= 8 ) bpc_logMsgf("Discarding %s since it doesn't match starting portion\n", candidateFile->fileName); bpc_fileZIO_close(&info->match[i].fd); free(candidateFile); continue; } info->match[i].used = 1; info->match[i].digest = candidateFile->digest; info->match[i].v3File = candidateFile->v3File; info->match[i].fileSize = candidateFile->fileSize; strcpy(info->match[i].fileName, candidateFile->fileName); nMatch++; if ( BPC_LogLevel >= 9 ) bpc_logMsgf("match[%d] now set to %s\n", i, info->match[i].fileName); free(candidateFile); break; } } return nMatch; } /* * Write a chunk to the current pool file. * * Call with undef to indicate EOF / close. */ int bpc_poolWrite_write(bpc_poolWrite_info *info, uchar *data, size_t dataLen) { if ( info->errorCnt ) return -1; info->fileSize += dataLen; if ( info->state == 0 ) { /* * In this state we are at the start of the file and don't have a digest yet */ if ( data ) { /* * Cumulate small writes at the start of the file */ if ( info->bufferIdx + dataLen <= BPC_POOL_WRITE_BUF_SZ ) { memcpy(info->buffer + info->bufferIdx, data, dataLen); info->bufferIdx += dataLen; return 0; } /* * We have more data than the buffer can fit. Top off the buffer if it has less than * 1MB of data so that we can compute the V3 digest. */ if ( data && info->bufferIdx < (1 << 20) && BPC_POOL_WRITE_BUF_SZ >= (1 << 20) ) { uint32 addTo1MB = (1 << 20) - info->bufferIdx; memcpy(info->buffer + info->bufferIdx, data, addTo1MB); info->bufferIdx += addTo1MB; data += addTo1MB; dataLen -= addTo1MB; } if ( !info->digest.len ) { ssize_t writeRet; /* * We don't have a digest and the file is bigger than the buffer. * So we need to write the data to a temp file and compute the MD5 * digest as we write the file. */ if ( bpc_fileZIO_open(&info->fd, info->tmpFileName, 1, info->compress) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: can't open/create %s for writing", info->tmpFileName); return -1; } info->fdOpen = 1; md5_begin(&info->md5); if ( info->bufferIdx > 0 ) { if ( (writeRet = bpc_fileZIO_write(&info->fd, info->buffer, info->bufferIdx)) != (signed)info->bufferIdx ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: write of %lu bytes to %s failed, return = %d", (unsigned long)info->bufferIdx, info->tmpFileName, (int)writeRet); return -1; } md5_update(&info->md5, info->buffer, info->bufferIdx); } info->state = 1; } else { /* * We have the new digest, so figure out the list of candidate matching files */ /* TODO: don't have V3 digest at this point! */ info->state = 2; } } else { /* * We are at EOF, so we can compute the digests based on the entire file in * the buffer. */ info->eof = 1; bpc_digest_buffer2MD5(&info->digest, info->buffer, info->bufferIdx); if ( BPC_PoolV3Enabled ) { bpc_digest_buffer2MD5_v3(&info->digest_v3, info->buffer, info->bufferIdx); if ( BPC_LogLevel >= 8 ) { char hexStr_v3[BPC_DIGEST_LEN_MAX * 2 + 1], hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&info->digest, hexStr); bpc_digest_digest2str(&info->digest_v3, hexStr_v3); bpc_logMsgf("bpc_poolWrite_write: digest is %s, v3 is %s\n", hexStr, hexStr_v3); } } else if ( BPC_LogLevel >= 8 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&info->digest, hexStr); bpc_logMsgf("bpc_poolWrite_write: digest is %s\n", hexStr); } info->state = 2; } } if ( info->state == 1 ) { ssize_t writeRet; /* * In this state we are writing the data to a compressed temporary file, and * accumulating the digests. */ if ( dataLen > 0 ) { if ( (writeRet = bpc_fileZIO_write(&info->fd, data, dataLen)) != (ssize_t)dataLen ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: write of %lu bytes to %s failed, return = %d", (unsigned long)dataLen, info->tmpFileName, (int)writeRet); return -1; } md5_update(&info->md5, data, dataLen); } if ( !data ) { /* * We are at EOF. Close the output file and re-open it for reading. * Compute the digests too. */ bpc_fileZIO_close(&info->fd); if ( bpc_fileZIO_open(&info->fd, info->tmpFileName, 0, info->compress) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: can't open %s for reading", info->tmpFileName); return -1; } info->fdOpen = 1; md5_result(&info->md5, info->digest.digest); info->digest.len = MD5_DIGEST_LEN; if ( BPC_PoolV3Enabled ) { bpc_digest_buffer2MD5_v3(&info->digest_v3, info->buffer, info->fileSize); if ( BPC_LogLevel >= 8 ) { char hexStr_v3[BPC_DIGEST_LEN_MAX * 2 + 1], hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&info->digest, hexStr); bpc_digest_digest2str(&info->digest_v3, hexStr_v3); bpc_logMsgf("bpc_poolWrite_write: digest is %s, v3 is %s\n", hexStr, hexStr_v3); } } else if ( BPC_LogLevel >= 8 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&info->digest, hexStr); bpc_logMsgf("bpc_poolWrite_write: digest is %s\n", hexStr); } info->state = 2; } } if ( info->state == 2 ) { uint32 ext = 0; char poolPath[BPC_MAXPATHLEN]; STRUCT_STAT st; /* * In this state we have either the full file in info->buffer, or the full file * is opened for reading with info->fd. We also have digests computed. * * We figure out the list of candidate files to match. If there are any * new digest files then we just try to match them. Otherwise we also * try to match any old V3 files. * * Since the empty file is never stored in the pool, we have to make sure * that any digest that collides (ie: 0xd41d8cd98f00b204e9800998ecf8427e) * doesn't use the first slot (ie: make sure it has an extension > 0) */ static uchar zeroLenMD5[] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }; if ( info->fileSize > 0 && !memcmp(info->digest.digest, zeroLenMD5, sizeof(zeroLenMD5)) ) { ext++; } info->digestExtZeroLen = -1; while ( 1 ) { char poolPath[BPC_MAXPATHLEN]; bpc_digest_append_ext(&info->digest, ext); bpc_digest_md52path(poolPath, info->compress, &info->digest); /* * For >= V4.x pool, don't attempt to match pool files that * are empty, since in >= V4.x we don't rename pool * files in a repeated chain and instead replace them * with an empty file. * If the candidate has the other execute bit set, we do a safe * reset of the bit and allow matches to occur. This is used to flag * pool files that will be deleted next time BackupPC_refCountUpdate * runs, so resetting that bit prevents the deletion. */ if ( stat(poolPath, &st) ) break; if ( S_ISREG(st.st_mode) ) { if ( st.st_size > 0 ) { bpc_candidate_file *candidateFile; if ( (st.st_mode & S_IXOTH) && bpc_poolWrite_unmarkPendingDelete(poolPath) ) { bpc_logErrf("Couldn't unmark candidate matching file %s (skipped; errno = %d)\n", poolPath, errno); info->errorCnt++; break; } candidateFile = malloc(sizeof(bpc_candidate_file)); if ( !candidateFile ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: can't allocate bpc_candidate_file\n"); return -1; } candidateFile->digest = info->digest; candidateFile->fileSize = st.st_size; candidateFile->v3File = 0; strcpy(candidateFile->fileName, poolPath); candidateFile->next = info->candidateList; info->candidateList = candidateFile; if ( BPC_LogLevel >= 7 ) bpc_logMsgf("Candidate matching file %s\n", candidateFile->fileName); } else if ( info->digestExtZeroLen < 0 ) { /* * Remember the first empty file in case we have to insert a * new pool file here. */ info->digestExtZeroLen = ext; } } ext++; } /* * Remember the next open slot in case we have to add a new pool * file here. */ info->digestExtOpen = ext; bpc_digest_append_ext(&info->digest, 0); if ( BPC_PoolV3Enabled && !info->candidateList ) { /* * No matching candidate files so far, so now look in V3 pool */ ext = 0; while ( 1 ) { bpc_digest_append_ext(&info->digest_v3, ext); bpc_digest_md52path_v3(poolPath, info->compress, &info->digest_v3); ext++; /* * For V3.x pool, don't attempt to match pool files: * - that already have too many hardlinks. * - with only one link since starting in BackupPC v3.0, * BackupPC_nightly could be running in parallel (and * removing those files). This doesn't eliminate all * possible race conditions, but just reduces the * odds. Other design steps eliminate the remaining * race conditions of linking vs removing. */ if ( stat(poolPath, &st) ) break; if ( S_ISREG(st.st_mode) && 1 < st.st_nlink && st.st_nlink < (unsigned)BPC_HardLinkMax ) { bpc_candidate_file *candidateFile = malloc(sizeof(bpc_candidate_file)); if ( !candidateFile ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: can't allocate bpc_candidate_file\n"); return -1; } candidateFile->digest = info->digest_v3; candidateFile->fileSize = st.st_size; candidateFile->v3File = 1; strcpy(candidateFile->fileName, poolPath); candidateFile->next = info->candidateList; info->candidateList = candidateFile; if ( BPC_LogLevel >= 7 ) bpc_logMsgf("Candidate v3 matching file %s\n", candidateFile->fileName); } } bpc_digest_append_ext(&info->digest_v3, 0); } /* * Open the first set of candidate files. */ bpc_poolWrite_updateMatches(info); info->state = 3; } if ( info->state == 3 ) { /* * In this state we are continuing to match against candidate files */ while ( 1 ) { int i, replaceCnt = 0, nMatch = 0; uchar *buf0 = TempBuf; uchar *buf1 = TempBuf + COMPARE_BUF_SZ; uchar *buf; OFF_T nread0; if ( info->fdOpen ) { nread0 = bpc_fileZIO_read(&info->fd, buf0, COMPARE_BUF_SZ); buf = buf0; } else { nread0 = COMPARE_BUF_SZ; if ( nread0 > info->bufferIdx - info->matchPosn ) nread0 = info->bufferIdx - info->matchPosn; buf = info->buffer + info->matchPosn; } for ( i = 0 ; i < BPC_POOL_WRITE_CONCURRENT_MATCH ; i++ ) { OFF_T nread1; if ( !info->match[i].used ) continue; nMatch++; /* * Try to read an extra byte when we expect EOF, to make sure the candidate file is also at EOF */ nread1 = bpc_fileZIO_read(&info->match[i].fd, buf1, nread0 > 0 ? nread0 : 1); if ( BPC_LogLevel >= 9 ) bpc_logMsgf("Read %d bytes of %d from match[%d] (%s)\n", (int)nread1, (int)nread0, i, info->match[i].fileName); if ( nread0 != nread1 || (nread0 > 0 && memcmp(buf, buf1, nread0)) ) { bpc_fileZIO_close(&info->match[i].fd); if ( BPC_LogLevel >= 8 ) bpc_logMsgf("match[%d] no longer matches\n", i); info->match[i].used = 0; replaceCnt++; } } info->matchPosn += nread0; if ( replaceCnt ) { nMatch = bpc_poolWrite_updateMatches(info); } if ( nread0 == 0 || nMatch == 0 ) { /* * we are at eof (with a match) or there are no matches */ info->state = 4; break; } } } if ( info->state == 4 ) { /* * see if there is a matching file */ int i, nMatch = 0, iMatch = 0; for ( i = BPC_POOL_WRITE_CONCURRENT_MATCH -1 ; i >= 0 ; i-- ) { if ( !info->match[i].used ) continue; nMatch++; iMatch = i; } if ( nMatch == 0 ) { ssize_t writeRet; /* * Need to write a new file if not written already */ if ( !info->fdOpen && info->fileSize > 0 ) { if ( bpc_fileZIO_open(&info->fd, info->tmpFileName, 1, info->compress) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: can't open/create %s for writing", info->tmpFileName); return -1; } if ( info->bufferIdx > 0 ) { if ( (writeRet = bpc_fileZIO_write(&info->fd, info->buffer, info->bufferIdx)) != (ssize_t)info->bufferIdx ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_write: write of %u bytes to %s failed, return = %d", info->bufferIdx, info->tmpFileName, (int)writeRet); return -1; } } bpc_fileZIO_close(&info->fd); } if ( info->fileSize > 0 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_append_ext(&info->digest, 0); bpc_digest_digest2str(&info->digest, hexStr); if ( BPC_LogLevel >= 5 ) bpc_logMsgf("No match... adding %s to pool (digest = %s)\n", info->tmpFileName, hexStr); bpc_poolWrite_addToPool(info, info->tmpFileName, 0); } else { if ( BPC_LogLevel >= 5 ) bpc_logMsgf("Zero length file - don't match anything\n"); info->digest.len = 0; info->retValue = 1; info->poolFileSize = 0; } } else { /* * We matched a pool file */ if ( nMatch > 1 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; if ( BPC_LogLevel >= 4 ) bpc_logMsgf("Botch - got multiple pool file matches\n"); info->errorCnt++; bpc_digest_digest2str(&info->digest, hexStr); bpc_logErrf("bpc_poolWrite_write: got %d matching files for digest %s\n", nMatch, hexStr); } if ( BPC_LogLevel >= 7 ) bpc_logMsgf("Found match with match[%d] (%s)\n", iMatch, info->match[iMatch].fileName); if ( info->match[iMatch].v3File ) { bpc_digest_append_ext(&info->digest, 0); bpc_poolWrite_addToPool(info, info->match[iMatch].fileName, info->match[iMatch].v3File); } else { info->digest = info->match[iMatch].digest; info->retValue = 1; info->poolFileSize = info->match[iMatch].fileSize; } if ( info->fdOpen ) { bpc_fileZIO_close(&info->fd); unlink(info->tmpFileName); info->fdOpen = 0; } } } return 0; } int bpc_poolWrite_createPoolDir(bpc_poolWrite_info *info, bpc_digest *digest) { char path[BPC_MAXPATHLEN], *p; int ret; /* * get the full path, and prune off the file name to get the directory */ bpc_digest_md52path(path, info->compress, digest); if ( !(p = strrchr(path, '/')) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_createPoolDir: can't find trailing / in path %s", path); return -1; } *p = '\0'; if ( (ret = bpc_path_create(path)) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_createPoolDir: can't create directory path %s", path); } return ret; } void bpc_poolWrite_cleanup(bpc_poolWrite_info *info) { int i; if ( info->fdOpen ) bpc_fileZIO_close(&info->fd); info->fdOpen = 0; while ( info->candidateList ) { bpc_candidate_file *candidateFile = info->candidateList; info->candidateList = candidateFile->next; free(candidateFile); } for ( i = 0 ; i < BPC_POOL_WRITE_CONCURRENT_MATCH ; i++ ) { if ( !info->match[i].used ) continue; bpc_fileZIO_close(&info->match[i].fd); info->match[i].used = 0; } if ( info->buffer ) { *(void**)info->buffer = DataBufferFreeList; DataBufferFreeList = info->buffer; info->buffer = NULL; } } /* * Called after the data is written. The return information is passed via four arguments: * * (match, digest, poolFileSize, errorCnt) * * The return values are: * * - match: * If match == 0, then the file doesn't match either the new or old pools. * The file has been added to the pool. * * If match == 1, then the file matches the new pool. No file is * written. * * If match == 2, then the file matches the old pool. The old pool * file was moved to become the new pool file. * * - digest: the 16+ byte binary MD5 digest, possibly appended with * on or more additional bytes to point to the right pool file in * case there are MD5 collisions * * - poolFileSize: the compressed pool file size * * - errorCnt: number of errors */ void bpc_poolWrite_close(bpc_poolWrite_info *info, int *match, bpc_digest *digest, OFF_T *poolFileSize, int *errorCnt) { bpc_poolWrite_write(info, NULL, 0); bpc_poolWrite_cleanup(info); *match = info->retValue; *digest = info->digest; *poolFileSize = info->poolFileSize; *errorCnt = info->errorCnt; } void bpc_poolWrite_repeatPoolWrite(bpc_poolWrite_info *info, char *fileNameTmp) { bpc_poolWrite_cleanup(info); if ( BPC_LogLevel >= 5 ) bpc_logMsgf("bpc_poolWrite_repeatPoolWrite: rewriting %s\n", fileNameTmp); if ( info->retryCnt++ > 8 ) { bpc_logErrf("bpc_poolWrite_repeatPoolWrite: giving up on %s after %d attempts\n", fileNameTmp, info->retryCnt); info->errorCnt++; unlink(fileNameTmp); return; } strcpy(info->tmpFileName, fileNameTmp); if ( bpc_fileZIO_open(&info->fd, fileNameTmp, 0, info->compress) < 0 ) { bpc_logErrf("bpc_poolWrite_repeatPoolWrite: can't open %s for reading", fileNameTmp); info->errorCnt++; return; } info->eof = 1; info->state = 2; info->fdOpen = 1; bpc_poolWrite_write(info, NULL, 0); } int bpc_poolWrite_copyToPool(bpc_poolWrite_info *info, char *poolPath, char *fileName) { int fdRead, fdWrite; int nRead, nWrite; if ( (fdWrite = open(poolPath, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0 ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_copyToPool: can't open/create %s for writing", poolPath); return -1; } if ( (fdRead = open(fileName, O_RDONLY)) < 0 ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_copyToPool: can't open %s for reading", fileName); return -1; } while ( (nRead = read(fdRead, info->buffer, sizeof(info->buffer))) > 0 ) { uchar *p = info->buffer; int thisWrite; nWrite = 0; while ( nWrite < nRead ) { do { thisWrite = write(fdWrite, p, nRead - nWrite); } while ( thisWrite < 0 && errno == EINTR ); if ( thisWrite < 0 ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_copyToPool: write to %s failed (errno = %d)", poolPath, errno); close(fdWrite); close(fdRead); unlink(poolPath); return -1; } p += thisWrite; nWrite += thisWrite; } } close(fdWrite); close(fdRead); return 0; } void bpc_poolWrite_addToPool(bpc_poolWrite_info *info, char *fileName, int v3PoolFile) { STRUCT_STAT st; char poolPath[BPC_MAXPATHLEN]; int redo = 0; if ( bpc_poolWrite_createPoolDir(info, &info->digest) ) return; /* * If originally present, make sure the zero-length file is still there (and still * zero-length), and the open slot is still open. If not, it probably means someone * beat us to it, and we should re-do the whole pool matching to see if the newly * added pool file now matches. */ if ( info->digestExtZeroLen >= 0 ) { bpc_digest_append_ext(&info->digest, info->digestExtZeroLen); bpc_digest_md52path(poolPath, info->compress, &info->digest); if ( stat(poolPath, &st) || st.st_size != 0 ) { redo = 1; } } if ( !redo ) { bpc_digest_append_ext(&info->digest, info->digestExtOpen); bpc_digest_md52path(poolPath, info->compress, &info->digest); if ( !stat(poolPath, &st) ) { redo = 1; } } /* * Try to insert the new file at the zero-length file slot (if present). */ if ( !redo && info->digestExtZeroLen >= 0 ) { char lockFile[BPC_MAXPATHLEN]; int lockFd; /* * We can replace a zero-length file, but only via locking to * avoid race conditions. Since the hardlinking code below doesn't * use a lock, we can't remove the file and use a hardlink * because of race conditions - another process might be * inserting with the same digest and grab the slot. * * So we make sure we have exclusive access via a lock file, * check that the file is still zero-length, and then rename * the file. If that fails then we redo everything. */ bpc_digest_append_ext(&info->digest, info->digestExtZeroLen); bpc_digest_md52path(poolPath, info->compress, &info->digest); if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_poolWrite_addToPool: replacing empty pool file %s with %s\n", poolPath, fileName); snprintf(lockFile, BPC_MAXPATHLEN, "%s.lock", poolPath); lockFd = bpc_lockRangeFile(lockFile, 0, 1, 1); /* * If we don't have the lock, or the file is no longer zero length, or the rename fails, * then try again. */ if ( lockFd < 0 || stat(poolPath, &st) || st.st_size != 0 || rename(fileName, poolPath) ) { if ( BPC_LogLevel >= 5 ) { bpc_logMsgf("bpc_poolWrite_addToPool: lock/rename failed: need to repeat write (lockFd = %d, size = %lu, errno = %d)\n", lockFd, (unsigned long)st.st_size, errno); } if ( lockFd >= 0 ) { bpc_unlockRangeFile(lockFd); } unlink(lockFile); redo = 1; } else { chmod(poolPath, 0444); stat(poolPath, &st); info->retValue = v3PoolFile ? 2 : 0; info->poolFileSize = st.st_size; bpc_unlockRangeFile(lockFd); unlink(lockFile); return; } } /* * Now try to link the file to the new empty slot at the end */ if ( !redo ) { int linkOk, statOk; ino_t fileIno, poolIno; /* * Since this is a new slot, there is no need to do locking since * the link or open operations below are atomic/exclusive. * * First try to hardlink to the empty pool file slot */ bpc_digest_append_ext(&info->digest, info->digestExtOpen); bpc_digest_md52path(poolPath, info->compress, &info->digest); if ( stat(fileName, &st) ) { info->errorCnt++; bpc_logErrf("bpc_poolWrite_addToPool: can't stat %s\n", fileName); return; } fileIno = st.st_ino; linkOk = !link(fileName, poolPath); if ( !(statOk = !stat(poolPath, &st)) ) linkOk = 0; poolIno = st.st_ino; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_poolWrite_addToPool: link %s -> %s (linkOk = %d, statOk = %d, ino = %lu/%lu)\n", poolPath, fileName, linkOk, statOk, (unsigned long)fileIno, (unsigned long)poolIno); /* * make sure the link really worked by checking inode numbers * TODO: test these different cases. */ if ( statOk && fileIno == poolIno ) { /* * remove the original file and return */ unlink(fileName); chmod(poolPath, 0444); info->retValue = v3PoolFile ? 2 : 0; info->poolFileSize = st.st_size; return; } /* * Something failed. If the stat failed, the hardlink failure wasn't due * to another file being added by someone else. Perhaps the cpool is * split across multiple file systems? */ if ( !statOk ) { /* * The hardlink failed. This could be due to hitting the hardlink * limit, or the fact that fileName and poolPath are on different * file systems, or the fileName didn't get written. * Just copy the file instead (assuming fileName got written). */ bpc_poolWrite_copyToPool(info, poolPath, fileName); return; } } /* * We need to redo the pool write, since it appears someone else has added * a pool file with the same digest. */ bpc_poolWrite_repeatPoolWrite(info, fileName); } /* * Safely remove the o+x permission that marks a file for future deletion. * Similar locking is done by BackupPC_refCountUpdate so we can avoid any * race conditions with the file actually being deleted. * * Returns 0 on success. */ int bpc_poolWrite_unmarkPendingDelete(char *poolPath) { char lockFile[BPC_MAXPATHLEN], *p; STRUCT_STAT st; int lockFd; /* * The lock file is in the first level of pool sub directories - one level * up from the full path. So we need to find the 2nd last '/'. */ snprintf(lockFile, BPC_MAXPATHLEN, "%s", poolPath); if ( !(p = strrchr(lockFile, '/')) ) return -1; *p = '\0'; if ( !(p = strrchr(lockFile, '/')) ) return -1; snprintf(p + 1, BPC_MAXPATHLEN - (p + 1 - lockFile), "%s", "LOCK"); if ( (lockFd = bpc_lockRangeFile(lockFile, 0, 1, 1)) < 0 ) return -1; if ( !stat(poolPath, &st) && !chmod(poolPath, st.st_mode & ~S_IXOTH & ~S_IFMT) ) { if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_poolWrite_unmarkPendingDelete(%s) succeeded\n", poolPath); bpc_unlockRangeFile(lockFd); return 0; } else { bpc_logErrf("bpc_poolWrite_unmarkPendingDelete(%s) failed; errno = %d\n", poolPath, errno); bpc_unlockRangeFile(lockFd); return -1; } } rsync-bpc-3.1.2.1/backuppc/bpc_lib.c0000664000047500004750000002707213510756401016060 0ustar craigcraig/* * Library routines * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" char BPC_TopDir[BPC_MAXPATHLEN]; char BPC_PoolDir[BPC_MAXPATHLEN]; char BPC_CPoolDir[BPC_MAXPATHLEN]; char BPC_PoolDir3[BPC_MAXPATHLEN]; char BPC_CPoolDir3[BPC_MAXPATHLEN]; int BPC_HardLinkMax = 32000; int BPC_PoolV3Enabled = 0; int BPC_TmpFileUnique = -1; int BPC_LogLevel = 0; static char *hexDigits = "0123456789abcdef"; void bpc_lib_conf_init(char *topDir, int hardLinkMax, int poolV3Enabled, int logLevel) { if ( logLevel >= 8 ) bpc_logMsgf("bpc_lib_conf_init: topDir = %s, logLevel = %d\n", topDir, logLevel); snprintf(BPC_TopDir, sizeof(BPC_TopDir), "%s", topDir); snprintf(BPC_CPoolDir, sizeof(BPC_CPoolDir), "%s/%s", BPC_TopDir, "cpool"); snprintf(BPC_CPoolDir3, sizeof(BPC_CPoolDir3), "%s/%s", BPC_TopDir, "cpool"); snprintf(BPC_PoolDir, sizeof(BPC_PoolDir), "%s/%s", BPC_TopDir, "pool"); snprintf(BPC_PoolDir3, sizeof(BPC_PoolDir3), "%s/%s", BPC_TopDir, "pool"); BPC_HardLinkMax = hardLinkMax; BPC_PoolV3Enabled = poolV3Enabled; BPC_LogLevel = logLevel; } void bpc_lib_setTmpFileUnique(int val) { BPC_TmpFileUnique = val; } int bpc_lib_setLogLevel(int logLevel) { if ( logLevel >= 0 ) { BPC_LogLevel = logLevel; } return BPC_LogLevel; } /* * Converts a byte to two ascii hex digits at outStr[0] and outStr[1]. * Nothing is written at outStr[2]; ie: no NULL termination */ void bpc_byte2hex(char *outStr, int byte) { outStr[0] = hexDigits[(byte >> 4) & 0xf]; outStr[1] = hexDigits[(byte >> 0) & 0xf]; } static uchar bpc_hexChar2nibble(char c) { if ( '0' <= c && c <= '9' ) return c - '0'; if ( 'A' <= c && c <= 'F' ) return 0xa + (c - 'A'); if ( 'a' <= c && c <= 'f' ) return 0xa + (c - 'a'); return 0; } uchar bpc_hexStr2byte(char c1, char c2) { return (bpc_hexChar2nibble(c1) << 4) | bpc_hexChar2nibble(c2); } void bpc_digest_buffer2MD5(bpc_digest *digest, uchar *buffer, size_t bufferLen) { md_context md5; md5_begin(&md5); md5_update(&md5, buffer, bufferLen); md5_result(&md5, digest->digest); digest->len = MD5_DIGEST_LEN; } void bpc_digest_append_ext(bpc_digest *digest, uint32 ext) { int i; digest->len = 16; if ( ext == 0 ) return; for ( i = 24 ; i >= 0 ; i -= 8 ) { if ( ext >= (1U << i) ) { digest->digest[digest->len++] = (ext >> i) & 0xff; } } } /* * returns 0 if the two digests are equal, non-zero if they are not */ int bpc_digest_compare(bpc_digest *digest1, bpc_digest *digest2) { if ( digest1->len != digest2->len ) return digest1->len - digest2->len; return memcmp(digest1->digest, digest2->digest, digest1->len); } void bpc_digest_digest2str(bpc_digest *digest, char *hexStr) { int i; char *out = hexStr; for ( i = 0 ; i < digest->len ; i++ ) { bpc_byte2hex(out, digest->digest[i]); out += 2; } *out = '\0'; } void bpc_digest_str2digest(bpc_digest *digest, char *hexStr) { for ( digest->len = 0 ; hexStr[0] && hexStr[1] && digest->len < BPC_DIGEST_LEN_MAX ; hexStr += 2 ) { digest->digest[digest->len++] = bpc_hexStr2byte(hexStr[0], hexStr[1]); } } void bpc_digest_md52path(char *path, int compress, bpc_digest *digest) { char *out; /* * MD5 digest of an empty file (ie, md5sum /dev/null) */ static uchar emptyFileMD5[] = { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }; #if 0 /* * Test code to create collisions in pool files. * If you turn on this test, you should also force the zeroLenMD5 * digest comparison in bpc_poolWrite_write() to true. */ bpc_digest fixedDigest = *digest; digest = &fixedDigest; memcpy(digest->digest, emptyFileMD5, sizeof(emptyFileMD5)); #endif if ( digest->len == sizeof(emptyFileMD5) && !memcmp(digest->digest, emptyFileMD5, sizeof(emptyFileMD5)) ) { strcpy(path, "/dev/null"); return; } strncpy(path, compress ? BPC_CPoolDir : BPC_PoolDir, BPC_MAXPATHLEN - 32); path[BPC_MAXPATHLEN - 48] = '\0'; out = path + strlen(path); *out++ = '/'; bpc_byte2hex(out, digest->digest[0] & 0xfe); out += 2; *out++ = '/'; bpc_byte2hex(out, digest->digest[1] & 0xfe); out += 2; *out++ = '/'; bpc_digest_digest2str(digest, out); } void bpc_digest_md52path_v3(char *path, int compress, bpc_digest *digest) { int i; char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; uint32 ext = 0; char n0 = hexDigits[(digest->digest[0] >> 4) & 0xf]; char n1 = hexDigits[(digest->digest[0] >> 0) & 0xf]; char n2 = hexDigits[(digest->digest[1] >> 4) & 0xf]; bpc_digest_digest2str(digest, hexStr); for ( i = 16 ; i < digest->len ; i++ ) { ext |= digest->digest[i - 16] << (8 * (i - 16)); } if ( ext > 0 ) { snprintf(path, BPC_MAXPATHLEN, "%s/%c/%c/%c/%s_%d", compress ? BPC_CPoolDir3 : BPC_PoolDir3, n0, n1, n2, hexStr, ext); } else { snprintf(path, BPC_MAXPATHLEN, "%s/%c/%c/%c/%s", compress ? BPC_CPoolDir3 : BPC_PoolDir3, n0, n1, n2, hexStr); } } void bpc_digest_buffer2MD5_v3(bpc_digest *digest, uchar *buffer, size_t bufferLen) { char lenStr[256]; md_context md5; md5_begin(&md5); sprintf(lenStr, "%llu", (long long unsigned int)bufferLen); md5_update(&md5, (uchar*)lenStr, strlen(lenStr)); if ( bufferLen > 262144 ) { /* * add the first and last 131072 bytes of the buffer, * up to 1MB. */ int seekPosn = (bufferLen > 1048576 ? 1048576 : bufferLen) - 131072; md5_update(&md5, buffer, 131072); md5_update(&md5, buffer + seekPosn, 131072); } else { /* * add the whole buffer */ md5_update(&md5, buffer, bufferLen); } md5_result(&md5, digest->digest); digest->len = MD5_DIGEST_LEN; } static void bpc_fileNameEltMangle2(char *path, int pathSize, char *pathUM, int stopAtSlash) { if ( !*pathUM || (stopAtSlash && *pathUM == '/') ) { *path = '\0'; return; } *path++ = 'f'; pathSize--; for ( ; *pathUM && pathSize > 4 ; ) { if ( stopAtSlash && *pathUM == '/' ) break; if ( *pathUM != '%' && *pathUM != '/' && *pathUM != '\n' && *pathUM != '\r' ) { *path++ = *pathUM++; pathSize--; } else { *path++ = '%'; pathSize--; bpc_byte2hex(path, *pathUM++); path += 2; pathSize -= 2; } } *path = '\0'; } void bpc_fileNameEltMangle(char *path, int pathSize, char *pathUM) { bpc_fileNameEltMangle2(path, pathSize, pathUM, 0); } void bpc_fileNameMangle(char *path, int pathSize, char *pathUM) { char *p; for ( ; *pathUM && pathSize > 4 ; ) { int len; bpc_fileNameEltMangle2(path, pathSize, pathUM, 1); len = strlen(path); path += len; pathSize -= len; if ( !(p = strchr(pathUM, '/')) ) break; for ( pathUM = p + 1 ; *pathUM == '/' ; pathUM++ ) { } if ( *pathUM ) { *path++ = '/'; pathSize--; } } *path = '\0'; } /* * Simple logging functions. If you register callbacks, they will be called. * Otherwise, messages are accumulated, and a callback allows the * log strings to be fetched. * * We store the data in a single buffer of '\0'-terminated strings. */ typedef struct { char *mesg; size_t mesgSize; size_t mesgLen; unsigned long errorCnt; } LogMsgData; static LogMsgData LogData; static void (*LogMsgCB)(int, char *mesg, size_t mesgLen); void bpc_logMsgf(char *fmt, ...) { int strLen, pad = 0; va_list args; va_start(args, fmt); if ( !LogData.mesg ) { LogData.mesgSize = 8192; LogData.mesgLen = 0; if ( !(LogData.mesg = malloc(LogData.mesgSize)) ) { printf("bpc_logMessagef: panic: can't allocate %lu bytes\n", (unsigned long)LogData.mesgSize); LogData.errorCnt++; return; } } if ( BPC_TmpFileUnique >= 0 ) pad = 2; strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args); if ( strLen + 2 + pad + LogData.mesgLen > LogData.mesgSize ) { LogData.mesgSize += LogData.mesgSize + strLen + 2 + pad; if ( !(LogData.mesg = realloc(LogData.mesg, LogData.mesgSize)) ) { printf("bpc_logMessagef: panic: can't realloc %lu bytes\n", (unsigned long)LogData.mesgSize); LogData.errorCnt++; return; } va_start(args, fmt); strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args); va_end(args); } if ( strLen > 0 ) { if ( pad ) { LogData.mesg[LogData.mesgLen++] = BPC_TmpFileUnique ? 'G' : 'R'; LogData.mesg[LogData.mesgLen++] = ' '; } LogData.mesgLen += strLen + 1; } if ( LogMsgCB ) { (*LogMsgCB)(0, LogData.mesg, LogData.mesgLen - 1); LogData.mesgLen = 0; } va_end(args); } /* * For now, this is just the same as bpc_logMsgf(). We can't call a common routine that * does the work, since args might need to be parsed twice when the buffer is grown. */ void bpc_logErrf(char *fmt, ...) { int strLen, pad = 0; va_list args; va_start(args, fmt); if ( !LogData.mesg ) { LogData.mesgSize = 8192; LogData.mesgLen = 0; if ( !(LogData.mesg = malloc(LogData.mesgSize)) ) { printf("bpc_logMessagef: panic: can't allocate %lu bytes\n", (unsigned long)LogData.mesgSize); LogData.errorCnt++; return; } } if ( BPC_TmpFileUnique >= 0 ) pad = 2; strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args); if ( strLen + 2 + pad + LogData.mesgLen > LogData.mesgSize ) { LogData.mesgSize += LogData.mesgSize + strLen + 2 + pad; if ( !(LogData.mesg = realloc(LogData.mesg, LogData.mesgSize)) ) { printf("bpc_logMessagef: panic: can't realloc %lu bytes\n", (unsigned long)LogData.mesgSize); LogData.errorCnt++; return; } va_start(args, fmt); strLen = vsnprintf(LogData.mesg + LogData.mesgLen + pad, LogData.mesgSize - LogData.mesgLen - pad, fmt, args); va_end(args); } if ( strLen > 0 ) { if ( pad ) { LogData.mesg[LogData.mesgLen++] = BPC_TmpFileUnique ? 'G' : 'R'; LogData.mesg[LogData.mesgLen++] = ' '; } LogData.mesgLen += strLen + 1; } if ( LogMsgCB ) { (*LogMsgCB)(0, LogData.mesg, LogData.mesgLen - 1); LogData.mesgLen = 0; } va_end(args); } void bpc_logMsgGet(char **mesg, size_t *mesgLen) { *mesg = LogData.mesg; *mesgLen = LogData.mesgLen; LogData.mesgLen = 0; } void bpc_logMsgErrorCntGet(unsigned long *errorCnt) { *errorCnt = LogData.errorCnt; LogData.errorCnt = 0; } void bpc_logMsgCBSet(void (*cb)(int errFlag, char *mesg, size_t mesgLen)) { LogMsgCB = cb; } rsync-bpc-3.1.2.1/backuppc/bpc_dirOps.c0000664000047500004750000002453713510756401016555 0ustar craigcraig/* * Directory and file system operations * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" /* * Create all the directories in the given path. Path must be non-const. Trailing '/' characters are removed. */ int bpc_path_create(char *path) { char *p = path; STRUCT_STAT st; int levels = 0; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_path_create(%s)\n", path); /* * check if it exists already */ if ( !stat(path, &st) && S_ISDIR(st.st_mode) ) return 0; /* * We walk up until we find the deepest level directory that exists. * First remove trailing slashes. */ p = path + strlen(path); while ( p > path && p[-1] == '/' ) p--; if ( *p == '/' ) *p = '\0'; while ( p > path ) { while ( p > path && p[-1] != '/' ) p--; while ( p > path && p[-1] == '/' ) p--; if ( *p == '/' ) { *p = '\0'; levels++; if ( !stat(path, &st) && S_ISDIR(st.st_mode) ) break; } } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_create: found that %s exists (%d levels up)\n", path, levels); /* * We have removed levels '/' characters from path. Replace each one and create the directory. */ while ( levels-- > 0 ) { p = path + strlen(path); *p = '/'; if ( mkdir(path, ACCESSPERMS) < 0 && errno != EEXIST) { bpc_logErrf("bpc_path_create: can't create %s (errno %d)\n", path, errno); return -1; } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_create: created %s\n", path); } return 0; } /* * Remove all the files below path (if a directory) and path itself. Deduct reference counts * for every attrib file removed. * * Note that inodes are *not* updated, even in cases where nlinks > 0. */ int bpc_path_remove(bpc_deltaCount_info *deltaInfo, char *path, int compress) { char filePath[BPC_MAXPATHLEN]; STRUCT_STAT st; DIR *dir; struct dirent *dp; int errorCnt = 0; size_t dirListSize = 0, dirListLen = 0; char *dirList = NULL, *dirListP; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_path_remove(%s)\n", path); if ( !(dir = opendir(path)) ) { unlink(path); return errorCnt; } while ( (dp = readdir(dir)) ) { if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") ) continue; snprintf(filePath, sizeof(filePath), "%s/%s", path, dp->d_name); if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_path_remove: removing %s\n", filePath); if ( stat(filePath, &st) ) { /* * hmmm. stat failed - just try to remove it */ unlink(filePath); continue; } if ( S_ISDIR(st.st_mode) ) { /* * To avoid recursing with dir still open (consuming an open fd), remember all the dirs * and recurse after we close dir. */ if ( !dirList ) { dirListSize = 4096; if ( !(dirList = malloc(dirListSize)) ) { bpc_logErrf("bpc_path_remove: can't allocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } if ( dirListLen + strlen(dp->d_name) + 1 >= dirListSize ) { dirListSize = dirListSize * 2 + strlen(dp->d_name); if ( !(dirList = realloc(dirList, dirListSize)) ) { bpc_logErrf("bpc_path_remove: can't reallocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } strcpy(dirList + dirListLen, dp->d_name); dirListLen += strlen(dp->d_name) + 1; } else { /* * if this is an attrib file, we need to read it and deduct the reference counts. */ if ( !strncmp(dp->d_name, "attrib", 6) ) { bpc_attrib_dir dir; bpc_attrib_dirInit(&dir, compress); if ( bpc_attrib_dirRead(&dir, NULL, filePath, 0) ) { bpc_logErrf("bpc_path_remove: can't read attrib file %s\n", filePath); errorCnt++; } if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_remove: adjusting ref counts from attrib file %s\n", filePath); if ( !unlink(filePath) ) { /* * Only reduce the ref counts if we succeeded in removing the attrib file */ bpc_attrib_dirRefCount(deltaInfo, &dir, -1); } bpc_attrib_dirDestroy(&dir); } else { if ( unlink(filePath) ) errorCnt++; } } } closedir(dir); /* * Now visit the subdirs we have saved above. */ if ( dirList ) { for ( dirListP = dirList ; dirListP < dirList + dirListLen ; dirListP += strlen(dirListP) + 1 ) { snprintf(filePath, sizeof(filePath), "%s/%s", path, dirListP); errorCnt += bpc_path_remove(deltaInfo, filePath, compress); } free(dirList); } if ( rmdir(path) ) errorCnt++; return errorCnt; } /* * Reference count all the files below the directory path, based on the attrib * files in and below path. */ int bpc_path_refCountAllInodeMax(bpc_deltaCount_info *deltaInfo, char *path, int compress, int incr, unsigned int *inodeMax) { char filePath[BPC_MAXPATHLEN]; STRUCT_STAT st; DIR *dir; struct dirent *dp; int errorCnt = 0; size_t dirListSize = 0, dirListLen = 0; char *dirList = NULL, *dirListP; if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_path_refCountAll(%s)\n", path); if ( !(dir = opendir(path)) ) { return errorCnt; } while ( (dp = readdir(dir)) ) { if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") ) continue; snprintf(filePath, sizeof(filePath), "%s/%s", path, dp->d_name); if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_path_refCountAll: got %s\n", filePath); if ( stat(filePath, &st) ) continue; if ( S_ISDIR(st.st_mode) ) { /* * To avoid recursing with dir still open (consuming an open fd), remember all the dirs * and recurse after we close dir. */ if ( !dirList ) { dirListSize = 4096; if ( !(dirList = malloc(dirListSize)) ) { bpc_logErrf("bpc_path_refCountAll: can't allocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } if ( dirListLen + strlen(dp->d_name) + 1 >= dirListSize ) { dirListSize = dirListSize * 2 + strlen(dp->d_name); if ( !(dirList = realloc(dirList, dirListSize)) ) { bpc_logErrf("bpc_path_refCountAll: can't reallocate %u bytes\n", (unsigned)dirListSize); return ++errorCnt; } } strcpy(dirList + dirListLen, dp->d_name); dirListLen += strlen(dp->d_name) + 1; } else { /* * if this is an attrib file, we need to read it and deduct the reference counts. */ if ( !strncmp(dp->d_name, "attrib", 6) ) { bpc_attrib_dir dir; bpc_attrib_dirInit(&dir, compress); if ( bpc_attrib_dirRead(&dir, path, dp->d_name, 0) ) { bpc_logErrf("bpc_path_refCountAll: can't read attrib file %s\n", filePath); errorCnt++; } else { if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_path_refCountAll: adjusting ref counts from attrib file %s\n", filePath); bpc_attrib_dirRefCountInodeMax(deltaInfo, &dir, incr, inodeMax); } bpc_attrib_dirDestroy(&dir); } } } closedir(dir); /* * Now visit the subdirs we have saved above. */ if ( dirList ) { for ( dirListP = dirList ; dirListP < dirList + dirListLen ; dirListP += strlen(dirListP) + 1 ) { snprintf(filePath, sizeof(filePath), "%s/%s", path, dirListP); errorCnt += bpc_path_refCountAllInodeMax(deltaInfo, filePath, compress, incr, inodeMax); } free(dirList); } return errorCnt; } /* * Reference count all the files below the directory path, based on the attrib * files in and below path. */ int bpc_path_refCountAll(bpc_deltaCount_info *deltaInfo, char *path, int compress, int incr) { return bpc_path_refCountAllInodeMax(deltaInfo, path, compress, incr, NULL); } /* * Add an exclusive lock to the byte range in the given file. * Blocks until the lock becomes available. */ int bpc_lockRangeFd(int fd, OFF_T offset, OFF_T len, int block) { 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, block ? F_SETLKW : F_SETLK, &lock); } int bpc_unlockRangeFd(int fd, OFF_T offset, OFF_T len) { struct flock lock; lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = offset; lock.l_len = len; lock.l_pid = 0; return fcntl(fd, F_SETLK, &lock); } int bpc_lockRangeFile(char *lockFile, OFF_T offset, OFF_T len, int block) { int fd; if ( (fd = open(lockFile, O_CREAT | O_RDWR, 0660)) < 0 ) { bpc_logErrf("bpc_lockRangeFile: can't open/create lock file %s\n", lockFile); return fd; } if ( bpc_lockRangeFd(fd, offset, len, block) ) { close(fd); if ( block ) { bpc_logErrf("bpc_lockRangeFile: lock(%s) failed (errno = %d)\n", lockFile, errno); } return -1; } return fd; } void bpc_unlockRangeFile(int lockFd) { if ( lockFd >= 0 ) close(lockFd); } rsync-bpc-3.1.2.1/backuppc/bpc_hashtable.c0000664000047500004750000003422113510756401017237 0ustar craigcraig/* * Routines to provide a memory-efficient hashtable. * * Copyright (C) 2007-2009 Wayne Davison * * Modified for BackupPC to use arbitrary-length binary keys, and supporting * a rudimentary delete feature by Craig Barratt. In 6/2016 rewrote to * make the storage an array of pointers to entries, instead of inplace. * That way entries fetched from the hashtable are still value after a * resize. Still no chaining. * * 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 "backuppc.h" /* * Simple freelist of hash table entries. We maintain a single linked list of * unused entries of each size, indexed by the FREELIST_SIZE2IDX() macro. * * FreeList[0] isn't used, * FreeList[1] is a free list of blocks of size 8, * FreeList[2] is a free list of blocks of size 16, ... * * eg, if you ask for a block of size 9, a block of size 16 will be returned. */ static bpc_hashtable_key **FreeList; static uint32 FreeListSz; /* * to map size to the FreeList index we round up to the nearest multiple of 8 */ #define FREELIST_SIZE2IDX(size) (((size) + 7) / 8) #define FREELIST_IDX2SIZE(idx) ((idx) * 8) /* * how many new blocks to allocate when the free list is empty */ #define FREELIST_ALLOC_CNT (512) /* * allocate a single block of a given size by grabbing one off the FreeList */ static bpc_hashtable_key *bpc_hashtable_entryAlloc(uint32 size) { uint32 freeListIdx = FREELIST_SIZE2IDX(size); bpc_hashtable_key *key; size = FREELIST_IDX2SIZE(freeListIdx); if ( freeListIdx >= FreeListSz ) { /* * need a bigger array of freelists */ if ( !(FreeList = (bpc_hashtable_key**)realloc(FreeList, 2 * freeListIdx * sizeof(bpc_hashtable_key*))) ) { bpc_logErrf("bpc_hashtable_entryAlloc: out of memory\n"); return NULL; } memset(FreeList + FreeListSz, 0, (2 * freeListIdx - FreeListSz) * sizeof(bpc_hashtable_key*)); FreeListSz = 2 * freeListIdx; } if ( !FreeList[freeListIdx] ) { char *newBuf; uint32 i; /* * need to populate the freelist with more blocks */ if ( !(newBuf = (char*)malloc(size * FREELIST_ALLOC_CNT)) ) { bpc_logErrf("bpc_hashtable_entryAlloc: out of memory\n"); return NULL; } FreeList[freeListIdx] = (bpc_hashtable_key*)newBuf; /* * chain all the buffers together in a linked list */ key = (bpc_hashtable_key*)newBuf; for ( i = 0 ; i < FREELIST_ALLOC_CNT - 1 ; i++ ) { key->key = (void*)key + size; key = key->key; } key->key = NULL; } key = FreeList[freeListIdx]; FreeList[freeListIdx] = key->key; memset(key, 0, size); return key; } /* * free a block of a given size by putting it back on the FreeList */ static void bpc_hashtable_entryFree(bpc_hashtable_key *key, uint32 size) { uint32 freeListIdx = FREELIST_SIZE2IDX(size); key->key = FreeList[freeListIdx]; FreeList[freeListIdx] = key; } #define HASH_LOAD_LIMIT(size) ((size)*3/4) /* * This implements a very simple linear hash table (no chaining etc). * * It has rudimentary support for delete, by flagging the deleted node. It doesn't * shift other nodes on delete, but can re-use a deleted node on insert. */ /* * Create a hash table of the initial given size, with entries of size nodeSize */ void bpc_hashtable_create(bpc_hashtable *tbl, uint32 size, uint32 nodeSize) { /* Pick a power of 2 that can hold the requested size. */ if ( (size & (size-1)) || size < 16 ) { uint32 req = size; size = 16; while ( size < req ) { size *= 2; } } if ( !(tbl->nodes = calloc(size, sizeof(tbl->nodes[0]))) ) { bpc_logErrf("bpc_hashtable_create: out of memory\n"); return; } tbl->size = size; tbl->entries = 0; tbl->entriesDel = 0; tbl->nodeSize = nodeSize; return; } void bpc_hashtable_destroy(bpc_hashtable *tbl) { uint32 i; for ( i = 0 ; i < tbl->size ; i++ ) { if ( tbl->nodes[i] ) { bpc_hashtable_entryFree(tbl->nodes[i], tbl->nodeSize); } } free(tbl->nodes); } void bpc_hashtable_erase(bpc_hashtable *tbl) { uint32 i; for ( i = 0 ; i < tbl->size ; i++ ) { if ( tbl->nodes[i] ) { bpc_hashtable_entryFree(tbl->nodes[i], tbl->nodeSize); } } memset(tbl->nodes, 0, tbl->size * sizeof(tbl->nodes[0])); tbl->entries = 0; tbl->entriesDel = 0; } /* * Compute a hash for a given key. Note that it is *not* modulo the table size - the returned * hash is independent of the table size, so we don't have to recompute this hash if we * resize the table. However, the current implementation does recompute the hash when * we resize the hash table :(. Oh well. */ uint32 bpc_hashtable_hash(uchar *key, uint32 keyLen) { /* Based on Jenkins One-at-a-time hash. */ uint32 ndx; for ( ndx = 0 ; keyLen > 0 ; keyLen-- ) { ndx += *key++; ndx += (ndx << 10); ndx ^= (ndx >> 6); } ndx += (ndx << 3); ndx ^= (ndx >> 11); ndx += (ndx << 15); return ndx; } #if 0 static void bpc_hashttable_check(bpc_hashtable *tbl, char *str) { bpc_hashtable_key **node = tbl->nodes; uint i, entries = 0, entriesDel = 0; for ( i = 0 ; i < tbl->size ; i++, node++ ) { bpc_hashtable_key *keyInfo = *node; if ( !keyInfo ) { continue; } if ( !keyInfo->key && keyInfo->keyLen == 1 ) { entriesDel++; } else { entries++; } } if ( entries != tbl->entries ) { bpc_logErrf("bpc_hashttable_check: botch at %s on HT (%u,%u): got %u entries vs %u expected\n", str, tbl->size, tbl->nodeSize, entries, tbl->entries); tbl->entries = entries; } if ( entriesDel != tbl->entriesDel ) { bpc_logErrf("bpc_hashttable_check: botch at %s on HT (%u,%u): got %u entriesDel vs %u expected\n", str, tbl->size, tbl->nodeSize, entriesDel, tbl->entriesDel); tbl->entriesDel = entriesDel; } } #endif /* * Ensure the hash table is of size at least newSize */ void bpc_hashtable_growSize(bpc_hashtable *tbl, uint32 newSize) { bpc_hashtable_key **old_nodes = tbl->nodes; bpc_hashtable_key **old_node = tbl->nodes; uint32 oldSize = tbl->size; uint i, j, ndx; /* Pick a power of 2 that can hold the requested newSize. */ if ( (newSize & (newSize-1)) || newSize < 16 ) { uint32 req = newSize; newSize = 16; while ( newSize < req ) { newSize *= 2; } } if ( tbl->size >= newSize ) return; if ( !(tbl->nodes = (bpc_hashtable_key**)calloc(newSize, sizeof(tbl->nodes[0]))) ) { bpc_logErrf("bpc_hashtable_create: out of memory\n"); return; } tbl->entries = 0; tbl->entriesDel = 0; tbl->size = newSize; for ( i = 0 ; i < oldSize ; i++, old_node++ ) { bpc_hashtable_key *keyInfo = *old_node; /* empty slot */ if ( !keyInfo ) continue; /* deleted slot: free it and don't reinsert */ if ( !keyInfo->key && keyInfo->keyLen == 1 ) { bpc_hashtable_entryFree(keyInfo, tbl->nodeSize); continue; } ndx = keyInfo->keyHash & (tbl->size - 1); for ( j = 0 ; j < tbl->size ; j++, ndx++ ) { if ( ndx >= tbl->size ) ndx = 0; if ( tbl->nodes[ndx] ) continue; tbl->nodes[ndx] = keyInfo; tbl->entries++; break; } if ( j >= tbl->size ) { bpc_logErrf("bpc_hashtable_growSize: botch on filling new hashtable (%d,%d)\n", newSize, tbl->entries); return; } } free(old_nodes); } /* * This returns the node for the indicated key, either newly created or * already existing. Returns NULL if not allocating and not found. */ void *bpc_hashtable_find(bpc_hashtable *tbl, unsigned char *key, unsigned int keyLen, int allocate_if_missing) { bpc_hashtable_key *keyInfo, *keyDeleted = NULL; uint32 i, ndx, keyHash; if ( allocate_if_missing && tbl->entries + tbl->entriesDel > HASH_LOAD_LIMIT(tbl->size) ) { bpc_hashtable_growSize(tbl, tbl->size * 2); } /* bpc_hashttable_check(tbl, "find"); */ /* * If it already exists, return the node. If we're not * allocating, return NULL if the key is not found. */ ndx = keyHash = bpc_hashtable_hash(key, keyLen); ndx &= tbl->size - 1; for ( i = 0 ; i < tbl->size ; i++ ) { keyInfo = tbl->nodes[ndx]; if ( !keyInfo ) { /* * Not found since we hit an empty node (ie: not a deleted one) * If requested, place the new at a prior deleted node, or here */ if ( allocate_if_missing ) { tbl->entries++; if ( keyDeleted ) { /* * we found a prior deleted entry, so use it instead */ keyInfo = keyDeleted; tbl->entriesDel--; } else { tbl->nodes[ndx] = keyInfo = bpc_hashtable_entryAlloc(tbl->nodeSize); } keyInfo->key = key; keyInfo->keyLen = keyLen; keyInfo->keyHash = keyHash; /* TODO - check this? */ if ( !key ) { bpc_logErrf("bpc_hashtable_find: botch adding NULL key to hT (%d,%d)\n", tbl->size, tbl->nodeSize); } return (void*)keyInfo; } return (void*)NULL; } else { if ( !keyInfo->key && keyInfo->keyLen == 1 ) { if ( !keyDeleted ) { /* * this is the first deleted slot, which we remember so we can insert a new entry * here if we don't find the desired entry, and allocate_if_missing != 0 */ keyDeleted = keyInfo; } } else if ( keyInfo->keyHash == keyHash && keyInfo->keyLen == keyLen && !memcmp(key, keyInfo->key, keyLen) ) { return (void*)keyInfo; } } ndx++; if ( ndx >= tbl->size ) ndx = 0; } return (void*)NULL; } /* * Remove a node from the hash table. Node must be a valid node returned by bpc_hashtable_find! * Node gets cleared. */ void bpc_hashtable_nodeDelete(bpc_hashtable *tbl, void *node) { bpc_hashtable_key *keyInfo = (bpc_hashtable_key*)node; memset(node, 0, tbl->nodeSize); /* * special delete flag (key is NULL, keyLen is 1), so that the linear hash table continues * finding entries past this point. * TODO optimization: if the next entry is empty, then we can make this empty too. */ keyInfo->keyLen = 1; tbl->entries--; tbl->entriesDel++; /* bpc_hashttable_check(tbl, "delete"); */ } /* * Iterate over all the entries in the hash table, calling a callback for each valid entry * * Note: this function won't work if the callback adds new entries to the hash table while * iterating over the entries. You can update or delete entries, but adding an entry might * cause the * hash table size to be bumped, which breaks the indexing. So don't add new * entries while iterating over the table. */ void bpc_hashtable_iterate(bpc_hashtable *tbl, void (*callback)(void*, void*), void *arg1) { uint i, entries = 0, entriesDel = 0; /* bpc_hashttable_check(tbl, "iterate"); */ for ( i = 0 ; i < tbl->size ; i++ ) { bpc_hashtable_key *keyInfo = tbl->nodes[i]; if ( !keyInfo ) continue; if ( !keyInfo->key ) { if ( keyInfo->keyLen == 1 ) entriesDel++; continue; } (*callback)((void*)keyInfo, arg1); if ( !keyInfo->key ) { if ( keyInfo->keyLen == 1 ) entriesDel++; continue; } else { entries++; } } if ( entries != tbl->entries ) { bpc_logErrf("bpc_hashtable_iterate: botch on HT (%u,%u): got %u entries vs %u expected\n", tbl->size, tbl->nodeSize, entries, tbl->entries); tbl->entries = entries; } if ( entriesDel != tbl->entriesDel ) { bpc_logErrf("bpc_hashtable_iterate: botch on HT (%u,%u): got %u entriesDel vs %u expected\n", tbl->size, tbl->nodeSize, entriesDel, tbl->entriesDel); tbl->entriesDel = entriesDel; } } /* * An alternative way to iterate over all the hash table entries. Initially index should * be zero, and is updated on each call. A pointer to each entry is returned. After * the last entry, NULL is returned, and idx is set back to zero. * * Note: this function won't work if you add new entries to the hash table while iterating * over the entries. You can update or delete entries, but adding an entry might cause the * hash table size to be bumped, which breaks the indexing. So don't add new entries while * iterating over the table. */ void *bpc_hashtable_nextEntry(bpc_hashtable *tbl, uint *idx) { uint i = *idx; /* bpc_hashttable_check(tbl, "next entry"); */ for ( ; i < (uint)tbl->size ; i++ ) { bpc_hashtable_key *keyInfo = tbl->nodes[i]; if ( !keyInfo || !keyInfo->key ) continue; *idx = i + 1; return (void*)keyInfo; } *idx = 0; return NULL; } /* * Return the number of entries in the hash table */ int bpc_hashtable_entryCount(bpc_hashtable *tbl) { /* bpc_hashttable_check(tbl, "entryCount"); */ return tbl->entries; } rsync-bpc-3.1.2.1/backuppc/bpc_attrib.c0000664000047500004750000013664713510756401016610 0ustar craigcraig/* * Routines for read/writing/managing file attributes * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" /* * Type of attribute file. This is saved as a magic number at the * start of the file. This type is for V3 and earlier. */ #define BPC_ATTRIB_TYPE_UNIX (0x17555555) /* * super set of UNIX, including extended attribs and digest, for 4.x+ */ #define BPC_ATTRIB_TYPE_XATTR (0x17565353) /* * starting in 4.x, attrib files in the pc backup tree are * just digests that give the location of the real attrib file * in the pool. attrib files written in the pc backup tree * start with this magic number, followed by the digest. */ #define BPC_ATTRIB_TYPE_DIGEST (0x17585451) static char *FileType2Text[] = { "file", "hardlink", "symlink", "chardev", "blockdev", "dir", "fifo", "?", "socket", "?", "deleted", }; /* * Ensure by default we use old-style "attrib" files for <= 4.0.0alpha3 compatibility. * Newer versions of BackupPC turn this off to use new attribute file naming. */ static int WriteOldStyleAttribFile = 1; static int KeepOldAttribFiles = 1; void bpc_attrib_backwardCompat(int writeOldStyleAttribFile, int keepOldAttribFiles) { if ( writeOldStyleAttribFile >= 0 ) WriteOldStyleAttribFile = writeOldStyleAttribFile; if ( keepOldAttribFiles >= 0 ) KeepOldAttribFiles = keepOldAttribFiles; if ( BPC_LogLevel >= 2 ) { bpc_logMsgf("bpc_attrib_backwardCompat: WriteOldStyleAttribFile = %d, KeepOldAttribFiles = %d\n", WriteOldStyleAttribFile, KeepOldAttribFiles); } } #define CONV_BUF_TO_UINT32(buf) ((buf)[0] << 24 | (buf)[1] << 16 | (buf)[2] << 8 | (buf)[3]) #define CONV_UINT32_TO_BUF(buf, val) { *(buf)++ = ((val) >> 24) & 0xff; \ *(buf)++ = ((val) >> 16) & 0xff; \ *(buf)++ = ((val) >> 8) & 0xff; \ *(buf)++ = ((val) >> 0) & 0xff; } /* * Note on xattr keys: they are treated as opaque strings of bytes, and the convention * is to include the '\0' byte termination in the keyLen (ie: it is strlen(key) + 1). */ bpc_attrib_xattr *bpc_attrib_xattrGet(bpc_attrib_file *file, void *key, int keyLen, int allocate_if_missing) { return (bpc_attrib_xattr*)bpc_hashtable_find(&file->xattrHT, key, keyLen, allocate_if_missing); } void bpc_attrib_xattrDestroy(bpc_attrib_xattr *xattr) { if ( xattr->key.key ) free(xattr->key.key); if ( xattr->value ) free(xattr->value); } int bpc_attrib_xattrDelete(bpc_attrib_file *file, void *key, int keyLen) { bpc_attrib_xattr *xattr = bpc_hashtable_find(&file->xattrHT, key, keyLen, 0); if ( !xattr ) return -1; bpc_attrib_xattrDestroy(xattr); bpc_hashtable_nodeDelete(&file->xattrHT, xattr); return 0; } static void bpc_attrib_xattrDeleteNode(bpc_attrib_xattr *xattr, bpc_attrib_file *file) { bpc_attrib_xattrDestroy(xattr); bpc_hashtable_nodeDelete(&file->xattrHT, xattr); } int bpc_attrib_xattrDeleteAll(bpc_attrib_file *file) { bpc_hashtable_iterate(&file->xattrHT, (void*)bpc_attrib_xattrDeleteNode, file); return 0; } /* * returns >0 if the new value is the same as the current value. * returns 0 if the new value was set correctly * returns <0 on error. */ int bpc_attrib_xattrSetValue(bpc_attrib_file *file, void *key, int keyLen, void *value, uint32 valueLen) { bpc_attrib_xattr *xattr = bpc_attrib_xattrGet(file, key, keyLen, 1); if ( !xattr->value ) { /* * new entry */ if ( !(xattr->key.key = malloc(keyLen)) ) { bpc_logErrf("bpc_attrib_xattrSetValue: can't allocate %d bytes for key\n", keyLen); return -1; } memcpy(xattr->key.key, key, keyLen); xattr->key.keyLen = keyLen; } else { /* * existing entry - no need to recopy key. If value array isn't big enough then create another. */ if ( valueLen > xattr->valueLen ) { free(xattr->value); xattr->value = NULL; } else if ( valueLen == xattr->valueLen && !memcmp(xattr->value, value, valueLen) ) { /* * same value - no change */ return 1; } } if ( !xattr->value && !(xattr->value = malloc(valueLen)) ) { bpc_logErrf("bpc_attrib_xattrSetValue: can't allocate %d bytes for value\n", valueLen); return -1; } memcpy(xattr->value, value, valueLen); xattr->valueLen = valueLen; return 0; } void bpc_attrib_xattrCopy(bpc_attrib_xattr *xattrSrc, bpc_attrib_file *fileDest) { bpc_attrib_xattr *xattr; uchar *key = (uchar*)malloc(xattrSrc->key.keyLen > 0 ? xattrSrc->key.keyLen : 1); uchar *value = (uchar*)malloc(xattrSrc->valueLen > 0 ? xattrSrc->valueLen : 1); if ( !key || !value ) { bpc_logErrf("bpc_attrib_xattrCopy: can't allocate %d,%d bytes\n", xattrSrc->key.keyLen + 1, xattrSrc->valueLen + 1); return; } memcpy(key, xattrSrc->key.key, xattrSrc->key.keyLen); memcpy(value, xattrSrc->value, xattrSrc->valueLen); xattr = bpc_attrib_xattrGet(fileDest, key, xattrSrc->key.keyLen, 1); if ( xattr->value ) { /* * Shouldn't be present, but if so clear it out and write the new key */ bpc_attrib_xattrDestroy(xattr); xattr->key.key = key; xattr->key.keyLen = xattrSrc->key.keyLen; } xattr->value = value; xattr->valueLen = xattrSrc->valueLen; } int bpc_attrib_xattrCount(bpc_attrib_file *file) { return bpc_hashtable_entryCount(&file->xattrHT); } typedef struct { char *list; ssize_t idx; ssize_t listLen; int ignoreRsyncACLs; } xattrList_info; static void bpc_attrib_xattrListKey(bpc_attrib_xattr *xattr, xattrList_info *info) { if ( info->idx < 0 ) return; if ( info->ignoreRsyncACLs ) { static struct { char *str; unsigned int len; } ignoreKeys[] = { { "user.rsync.%aacl", sizeof("user.rsync.%aacl"), }, /* note: sizeof() includes the \0 terminator */ { "user.rsync.%dacl", sizeof("user.rsync.%dacl"), }, }; uint i; for ( i = 0 ; i < sizeof(ignoreKeys) / sizeof(ignoreKeys[0]) ; i++ ) { if ( xattr->key.keyLen == ignoreKeys[i].len && !memcmp(xattr->key.key, ignoreKeys[i].str, xattr->key.keyLen) ) { return; } } } if ( info->list ) { if ( info->idx + (signed)xattr->key.keyLen > info->listLen ) { info->idx = -1; return; } /* * keyLen already includes the \0 terminating byte */ memcpy(info->list + info->idx, xattr->key.key, xattr->key.keyLen); info->idx += xattr->key.keyLen; } else { info->idx += xattr->key.keyLen; } } /* * Concatenate all the xattr keys, (which the caller has ensured are \0 terminated), * into a single string. Return the number of bytes in the output string. * Returns -1 if listLen is too short to fit all the keys. * If list is NULL, instead returns the number of bytes required to store all the keys. */ size_t bpc_attrib_xattrList(bpc_attrib_file *file, char *list, size_t listLen, int ignoreRsyncACLs) { xattrList_info info; info.list = list; info.idx = 0; info.listLen = listLen; info.ignoreRsyncACLs = ignoreRsyncACLs; bpc_hashtable_iterate(&file->xattrHT, (void*)bpc_attrib_xattrListKey, &info); return info.idx; } void bpc_attrib_fileDestroy(bpc_attrib_file *file) { if ( file->name) free(file->name); bpc_hashtable_iterate(&file->xattrHT, (void*)bpc_attrib_xattrDestroy, NULL); bpc_hashtable_destroy(&file->xattrHT); } /* * Return the attributes for the given file. * If allocate_if_missing == 0 and not present, then NULL is returned. * If allocate_if_missing != 0 and not present, then an empty struct is returned with the key filled in, * and file->name is NULL. */ bpc_attrib_file *bpc_attrib_fileGet(bpc_attrib_dir *dir, char *fileName, int allocate_if_missing) { return bpc_hashtable_find(&dir->filesHT, (uchar*)fileName, strlen(fileName), allocate_if_missing); } /* * Initialize an empty file structure (ie: one returned by bpc_attrib_fileGet() that is empty) */ void bpc_attrib_fileInit(bpc_attrib_file *file, char *fileName, int xattrNumEntries) { int fileNameLen = strlen(fileName); if ( file->name ) bpc_attrib_fileDestroy(file); file->name = (char*)malloc(fileNameLen + 1); if ( !file->name ) { bpc_logErrf("bpc_attrib_fileInit: can't allocate %d bytes for file name\n", fileNameLen + 1); return; } memcpy(file->name, fileName, fileNameLen + 1); file->isTemp = 0; file->key.key = file->name; bpc_hashtable_create(&file->xattrHT, 16 + xattrNumEntries, sizeof(bpc_attrib_xattr)); } /* * Copy all the attributes from fileSrc to fileDest. fileDest should already have a * valid allocated fileName and allocated xattr hash. The fileDest xattr hash is * emptied before the copy, meaning it is over written. * * If overwriteEmptyDigest == 0, an empty digest in fileSrc will not overwrite fileDest. */ void bpc_attrib_fileCopyOpt(bpc_attrib_file *fileDest, bpc_attrib_file *fileSrc, int overwriteEmptyDigest) { if ( fileDest == fileSrc ) return; fileDest->type = fileSrc->type; fileDest->compress = fileSrc->compress; fileDest->mode = fileSrc->mode; fileDest->isTemp = fileSrc->isTemp; fileDest->uid = fileSrc->uid; fileDest->gid = fileSrc->gid; fileDest->nlinks = fileSrc->nlinks; fileDest->mtime = fileSrc->mtime; fileDest->size = fileSrc->size; fileDest->inode = fileSrc->inode; fileDest->backupNum = fileSrc->backupNum; if ( fileSrc->digest.len > 0 || overwriteEmptyDigest ) { fileDest->digest = fileSrc->digest; } bpc_hashtable_iterate(&fileDest->xattrHT, (void*)bpc_attrib_xattrDestroy, NULL); bpc_hashtable_erase(&fileDest->xattrHT); bpc_hashtable_iterate(&fileSrc->xattrHT, (void*)bpc_attrib_xattrCopy, fileDest); } /* * Copy all the attributes from fileSrc to fileDest. fileDest should already have a * valid allocated fileName and allocated xattr hash. The fileDest xattr hash is * emptied before the copy, meaning it is over written. */ void bpc_attrib_fileCopy(bpc_attrib_file *fileDest, bpc_attrib_file *fileSrc) { if ( fileDest == fileSrc ) return; bpc_attrib_fileCopyOpt(fileDest, fileSrc, 1); } /* * Check if two file attribute structures are the same. Returns 0 if they are the same. */ int bpc_attrib_fileCompare(bpc_attrib_file *file0, bpc_attrib_file *file1) { uint idx = 0; if ( file0->type != file1->type || file0->compress != file1->compress || file0->mode != file1->mode || file0->uid != file1->uid || file0->gid != file1->gid || file0->nlinks != file1->nlinks || file0->mtime != file1->mtime || file0->size != file1->size || file0->inode != file1->inode || file0->digest.len != file1->digest.len || memcmp(file0->digest.digest, file1->digest.digest, file0->digest.len) || bpc_attrib_xattrCount(file0) != bpc_attrib_xattrCount(file1) ) { if ( BPC_LogLevel >= 9 ) bpc_logMsgf("bpc_attrib_fileCompare: %s %s differ\n", file0->name, file1->name); return 1; } while ( 1 ) { bpc_attrib_xattr *xattr0 = bpc_hashtable_nextEntry(&file0->xattrHT, &idx), *xattr1; if ( !xattr0 ) return 0; if ( !(xattr1 = bpc_attrib_xattrGet(file1, xattr0->key.key, xattr0->key.keyLen, 0)) ) return 1; if ( xattr0->valueLen != xattr1->valueLen || memcmp(xattr0->value, xattr1->value, xattr0->valueLen) ) return 1; } } void bpc_attrib_fileDeleteName(bpc_attrib_dir *dir, char *fileName) { bpc_attrib_file *file = bpc_hashtable_find(&dir->filesHT, (uchar*)fileName, strlen(fileName), 0); if ( !file ) return; bpc_attrib_fileDestroy(file); bpc_hashtable_nodeDelete(&dir->filesHT, file); } int bpc_attrib_fileCount(bpc_attrib_dir *dir) { return bpc_hashtable_entryCount(&dir->filesHT); } char *bpc_attrib_fileType2Text(int type) { if ( type < 0 || type >= (int)(sizeof(FileType2Text) / sizeof(FileType2Text[0])) ) return "?"; return FileType2Text[type]; } void bpc_attrib_dirInit(bpc_attrib_dir *dir, int compressLevel) { dir->digest.len = 0; dir->compress = compressLevel; bpc_hashtable_create(&dir->filesHT, 512, sizeof(bpc_attrib_file)); } void bpc_attrib_dirDestroy(bpc_attrib_dir *dir) { bpc_hashtable_iterate(&dir->filesHT, (void*)bpc_attrib_fileDestroy, NULL); bpc_hashtable_destroy(&dir->filesHT); } typedef struct { bpc_deltaCount_info *deltaInfo; int incr; unsigned int *inodeMax; } fileRefCnt_info; static void bpc_attrib_fileRefCount(bpc_attrib_file *file, fileRefCnt_info *info) { if ( file->digest.len > 0 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&file->digest, hexStr); if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_attrib_fileRefCount: file %s digest %s delta %d\n", file->name, hexStr, info->incr); bpc_poolRefDeltaUpdate(info->deltaInfo, file->compress, &file->digest, info->incr); } if ( info->inodeMax && file->inode > *info->inodeMax ) { *info->inodeMax = file->inode; } } /* * call refDeltaUpdate with incr (typically +/-1) for every entry in the directory, * as well as the dir itself. */ void bpc_attrib_dirRefCountInodeMax(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, int incr, unsigned int *inodeMax) { fileRefCnt_info info; info.deltaInfo = deltaInfo; info.incr = incr; info.inodeMax = inodeMax; bpc_hashtable_iterate(&dir->filesHT, (void*)bpc_attrib_fileRefCount, &info); if ( dir->digest.len > 0 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&dir->digest, hexStr); if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_attrib_dirRefCount: attrib digest %s delta = %d\n", hexStr, incr); bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, &dir->digest, incr); } else { if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_attrib_dirRefCount: no attrib digest -> no delta\n"); } } /* * call refDeltaUpdate with incr (typically +/-1) for every entry in the directory, * as well as the dir itself. */ void bpc_attrib_dirRefCount(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, int incr) { bpc_attrib_dirRefCountInodeMax(deltaInfo, dir, incr, NULL); } typedef struct { char *entries; ssize_t entryIdx; ssize_t entrySize; } dirEntry_info; static void bpc_attrib_getDirEntry(bpc_attrib_file *file, dirEntry_info *info) { ssize_t len = strlen(file->name) + 1; if ( info->entryIdx < 0 ) return; if ( info->entries ) { if ( info->entryIdx + len > info->entrySize ) { info->entryIdx = -1; return; } memcpy(info->entries + info->entryIdx, file->name, len); } info->entryIdx += len; } ssize_t bpc_attrib_getEntries(bpc_attrib_dir *dir, char *entries, ssize_t entrySize) { dirEntry_info info; info.entries = entries; info.entryIdx = 0; info.entrySize = entrySize; bpc_hashtable_iterate(&dir->filesHT, (void*)bpc_attrib_getDirEntry, &info); return info.entryIdx; } void bpc_attrib_attribFilePath(char *path, char *dir, char *attribFileName) { if ( !dir ) { snprintf(path, BPC_MAXPATHLEN, "%s", attribFileName); } else { snprintf(path, BPC_MAXPATHLEN, "%s/%s", dir, attribFileName ? attribFileName : "attrib"); } } bpc_digest *bpc_attrib_dirDigestGet(bpc_attrib_dir *dir) { return &dir->digest; } static int read_more_data(bpc_fileZIO_fd *fd, uchar *buf, size_t bufSize, size_t *nRead, uchar **bufPP, char *attribPath) { int thisRead; /* * move the remaining part of the buffer down, and read more data */ *nRead = (buf + *nRead) - *bufPP; memmove(buf, *bufPP, *nRead); *bufPP = buf; thisRead = bpc_fileZIO_read(fd, buf + *nRead, bufSize - *nRead); if ( thisRead < 0 ) { bpc_logErrf("bpc_attrib_dirRead: can't read more bytes from %s\n", attribPath); return -1; } *nRead += thisRead; return 0; } /* * Read variable-length unsigned integer in 7 bit chunks, LSB first. */ static int64 getVarInt(uchar **bufPP, uchar *bufEnd) { int64 result = 0; uchar *bufP = *bufPP; int i = 0; while ( bufP < bufEnd ) { uchar c = *bufP++; result |= ((int64)(c & 0x7f)) << i; if ( !(c & 0x80) ) { *bufPP = bufP; return result; } i += 7; } /* * we ran out of data... make sure bufP is greater than bufEnd, since * returning it to be equal (ie: bufP) will be incorrectly interpreted as * meaning the integer correctly ended right at the end of the buffer. */ *bufPP = bufEnd + 1; return result; } /* * V3 variable length integer read, MSB first, which is compatible with perl pack("w") */ static int64 getVarInt_v3(uchar **bufPP, uchar *bufEnd) { int64 result = 0; uchar *bufP = *bufPP; while ( bufP < bufEnd ) { uchar c = *bufP++; result = (result << 7) | (c & 0x7f); if ( !(c & 0x80) ) { *bufPP = bufP; return result; } } /* * we ran out of data... make sure bufP is greater than bufEnd, since * returning it to be equal (ie: bufP) will be incorrectly interpreted as * meaning the integer correctly ended right at the end of the buffer. */ *bufPP = bufEnd + 1; return result; } /* * Write variable-length unsigned integer in 7 bit chunks, LSB first */ static void setVarInt(uchar **bufPP, uchar *bufEnd, int64 value) { uchar *bufP = *bufPP; int maxBytes = (sizeof(value) * 8 + 6) / 7; do { uchar c = value & 0x7f; value >>= 7; maxBytes--; if ( value && maxBytes > 0 ) c |= 0x80; if ( bufP < bufEnd ) { *bufP++ = c; } else { bufP++; } } while ( value && maxBytes > 0 ); *bufPP = bufP; } /* * Unpack the data in buf[] into the file structure, after the file name and xattr entry * count have been extracted. Returns next unused buffer location. * * If there isn't enough data to extract a complete file structure, the return value * will be greater than bufEnd. You should gather more data and re-call the function. */ uchar *bpc_attrib_buf2file(bpc_attrib_file *file, uchar *buf, uchar *bufEnd, int xattrNumEntries) { uchar *bufP = buf; int i; file->type = getVarInt(&bufP, bufEnd); file->mtime = getVarInt(&bufP, bufEnd); file->mode = getVarInt(&bufP, bufEnd); file->uid = getVarInt(&bufP, bufEnd); file->gid = getVarInt(&bufP, bufEnd); file->size = getVarInt(&bufP, bufEnd); file->inode = getVarInt(&bufP, bufEnd); file->compress = getVarInt(&bufP, bufEnd); file->nlinks = getVarInt(&bufP, bufEnd); file->digest.len = getVarInt(&bufP, bufEnd); file->isTemp = 0; if ( file->digest.len > 0 && bufP + file->digest.len <= bufEnd ) { memcpy(file->digest.digest, bufP, file->digest.len); } bufP += file->digest.len; for ( i = 0 ; i < xattrNumEntries ; i++ ) { uint keyLen = getVarInt(&bufP, bufEnd); uint valueLen = getVarInt(&bufP, bufEnd); if ( bufP + keyLen + valueLen <= bufEnd ) { bpc_attrib_xattrSetValue(file, bufP, keyLen, bufP + keyLen, valueLen); } bufP += keyLen + valueLen; } return bufP; } /* * Extract an entire packed file structure, starting with the fileName length varint. * Returns next unused buffer location. It is assumed the file structure is already * initialized and has a valid fileName allocated, so we don't allocate it here. * * If there isn't enough data to extract a complete file structure, the return value * will be greater than bufEnd. You should gather more data and re-call the function. * On certain errors, returns NULL; */ uchar *bpc_attrib_buf2fileFull(bpc_attrib_file *file, uchar *bufP, uchar *bufEnd) { uint fileNameLen, xattrNumEntries; fileNameLen = getVarInt(&bufP, bufEnd); if ( fileNameLen > BPC_MAXPATHLEN - 1 ) { bpc_logErrf("bpc_attrib_buf2fileFull: got unreasonable file name length %d\n", fileNameLen); return NULL; } bufP += fileNameLen; xattrNumEntries = getVarInt(&bufP, bufEnd); bufP = bpc_attrib_buf2file(file, bufP, bufEnd, xattrNumEntries); return bufP; } /* * Read the attribute file at dirPath/attribFilePath and populate dir */ int bpc_attrib_dirRead(bpc_attrib_dir *dir, char *dirPath, char *attribFilePath, int backupNum) { char attribPath[BPC_MAXPATHLEN]; bpc_fileZIO_fd fd; size_t nRead; uint32 magic = 0; uchar buf[8 * 65536], *bufP; STRUCT_STAT st; char *p, *attribFileName; bpc_attrib_attribFilePath(attribPath, dirPath, attribFilePath); dir->digest.len = 0; /* * attribFileName points to the last portion of attribFilePath, or the whole * string if it doesn't contain '/' */ if ( (attribFileName = strrchr(attribFilePath, '/')) ) { attribFileName++; } else { attribFileName = attribFilePath; } if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_attrib_dirRead(%s); dirPath = %s, attribFilePath = %s, attribFileName = %s\n", attribPath, dirPath, attribFilePath, attribFileName); if ( (p = strchr(attribFileName, '_')) && !stat(attribPath, &st) && S_ISREG(st.st_mode) ) { /* * Explicit path name to new-style attrib file, and it exists; extract digest */ if ( !strcmp(p + 1, "0") ) return 0; bpc_digest_str2digest(&dir->digest, p + 1); if ( BPC_LogLevel >= 6 ) { char str[256]; bpc_digest_digest2str(&dir->digest, str); bpc_logMsgf("bpc_attrib_dirRead: called with attrib file %s: digest = %s, len = %d\n", attribPath, str, dir->digest.len); } /* * Write new type attrib files (since we found a new-style one) */ WriteOldStyleAttribFile = 0; magic = BPC_ATTRIB_TYPE_XATTR; } else if ( stat(attribPath, &st) || !S_ISREG(st.st_mode) || strchr(attribFileName, '_') ) { DIR *dirOs; struct dirent *dp; int attribFileNameLen = strlen(attribFileName); char attribDirPath[BPC_MAXPATHLEN]; /* * Starting in 0.50, the attrib files are zero length with the digest encoded in * the file name, so there is no file just called "attrib". Look in the directory * to find it. */ strcpy(attribDirPath, attribPath); if ( (p = strrchr(attribDirPath, '/')) ) { *p = '\0'; } else { strcpy(attribDirPath, "."); } if ( !(dirOs = opendir(attribDirPath)) ) { /* * This is a benign error - just return as though there is an empty attrib file */ if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_attrib_dirRead: can't opendir %s (note: this is ok)\n", attribDirPath); return 0; } while ( (dp = readdir(dirOs)) ) { if ( strncmp(dp->d_name, attribFileName, attribFileNameLen) ) continue; p = dp->d_name + attribFileNameLen; if ( p[0] != '_' ) continue; p++; if ( !strcmp(p, "0") ) { /* * An empty attrib file is legit; just return with no entries */ if ( BPC_LogLevel >= 6 ) { bpc_logMsgf("bpc_attrib_dirRead: Got empty attrib file %s\n", dp->d_name); } closedir(dirOs); return 0; } bpc_digest_str2digest(&dir->digest, p); if ( BPC_LogLevel >= 6 ) { char str[256]; bpc_digest_digest2str(&dir->digest, str); bpc_logMsgf("bpc_attrib_dirRead: Got attrib file %s: digest = %s, len = %d\n", dp->d_name, str, dir->digest.len); } /* * Write new type attrib files (since we found a new-style one) */ WriteOldStyleAttribFile = 0; break; } closedir(dirOs); if ( dir->digest.len == 0 ) return 0; magic = BPC_ATTRIB_TYPE_XATTR; } else { if ( bpc_fileZIO_open(&fd, attribPath, 0, dir->compress) ) { bpc_logErrf("bpc_attrib_dirRead: can't open %s\n", attribPath); return -1; } nRead = bpc_fileZIO_read(&fd, buf, sizeof(buf)); if ( nRead == 0 ) { /* * an empty file is legit - this means an empty directory (ie: zero attrib entries). * indicate this with an empty digest and empty hash of entries. */ bpc_fileZIO_close(&fd); if ( !strcmp(attribFileName, "attrib") ) { char attribPathTemp[BPC_MAXPATHLEN + 16]; strcpy(attribPathTemp, attribPath); strcat(attribPathTemp, "_0"); if ( rename(attribPath, attribPathTemp) ) { bpc_logErrf("bpc_attrib_dirRead: rename of empty attrib file from %s to %s failed\n", attribPath, attribPathTemp); return -1; } else if ( BPC_LogLevel >= 6 ) { bpc_logMsgf("bpc_attrib_dirRead: renamed empty attrib file %s -> %s\n", attribPath, attribPathTemp); } } return 0; } if ( nRead < 4 ) { bpc_logErrf("bpc_attrib_dirRead: can't read at least 4 bytes from %s\n", attribPath); bpc_fileZIO_close(&fd); return -1; } magic = CONV_BUF_TO_UINT32(buf); } if ( magic == BPC_ATTRIB_TYPE_DIGEST ) { char attribPathNew[BPC_MAXPATHLEN]; int fdNum; size_t digestLen = nRead - 4, attribPathLen = strlen(attribPath); if ( nRead < 20 ) { bpc_logErrf("bpc_attrib_dirRead: can't read at least 20 bytes from %s\n", attribPath); return -1; } bpc_fileZIO_close(&fd); if ( digestLen > sizeof(dir->digest.digest) ) digestLen = sizeof(dir->digest.digest); memcpy(dir->digest.digest, buf + 4, digestLen); dir->digest.len = digestLen; if ( !KeepOldAttribFiles ) { /* * replace the attrib file with a new-style attrib file where the digest is encoded * in a zero length file name */ if ( attribPathLen + dir->digest.len * 2 + 2 >= sizeof(attribPathNew) ) { bpc_logErrf("bpc_attrib_dirRead: new digest path too long (%d, %d, %d)\n", attribPathLen, dir->digest.len, sizeof(attribPathNew)); return -1; } strcpy(attribPathNew, attribPath); attribPathNew[attribPathLen++] = '_'; bpc_digest_digest2str(&dir->digest, attribPathNew + attribPathLen); if ( (fdNum = open(attribPathNew, O_WRONLY | O_CREAT | O_TRUNC, 0660)) < 0 ) { bpc_logErrf("bpc_attrib_dirRead: can't open/create empty attrib file %s\n", attribPathNew); return -1; } close(fdNum); unlink(attribPath); if ( BPC_LogLevel >= 4 ) bpc_logMsgf("bpc_attrib_dirRead: replaced %s with %s\n", attribPath, attribPathNew); } } if ( dir->digest.len > 0 ) { /* * Handle V4+ case - open the pool file directly * For V3, digest.len == 0 since we opened the attrib file above (it is stored hardlinked in the backup * directory; there is no digest) */ bpc_digest_md52path(attribPath, dir->compress, &dir->digest); if ( bpc_fileZIO_open(&fd, attribPath, 0, dir->compress) ) { bpc_logErrf("bpc_attrib_dirRead: can't open %s\n", attribPath); return -1; } nRead = bpc_fileZIO_read(&fd, buf, sizeof(buf)); if ( nRead < 4 ) { bpc_logErrf("bpc_attrib_dirRead: can't read at least 4 bytes from %s\n", attribPath); bpc_fileZIO_close(&fd); return -1; } magic = CONV_BUF_TO_UINT32(buf); } bufP = buf + 4; if ( magic == BPC_ATTRIB_TYPE_XATTR ) { int retry = 0; while ( bufP < buf + nRead ) { uint fileNameLen, xattrNumEntries; char *fileName; bpc_attrib_file *file; uchar *bufPsave = bufP; if ( nRead == sizeof(buf) && bufP > buf + nRead - 2 * BPC_MAXPATHLEN && read_more_data(&fd, buf, sizeof(buf), &nRead, &bufP, attribPath) ) { bpc_fileZIO_close(&fd); return -1; } fileNameLen = getVarInt(&bufP, buf + nRead); if ( fileNameLen > BPC_MAXPATHLEN - 1 ) { bpc_logErrf("bpc_attrib_dirRead: got unreasonable file name length %d\n", fileNameLen); bpc_fileZIO_close(&fd); return -1; } /* * Save the fileName, but it's not NULL terminated yet. * After we consume the next varint, we can safely NULL-terminate * the fileName, which allows us to look up or create the file entry. */ fileName = (char*)bufP; bufP += fileNameLen; xattrNumEntries = getVarInt(&bufP, buf + nRead); fileName[fileNameLen] = '\0'; file = bpc_attrib_fileGet(dir, fileName, 1); bpc_attrib_fileInit(file, fileName, xattrNumEntries); file->backupNum = backupNum; bufP = bpc_attrib_buf2file(file, bufP, buf + nRead, xattrNumEntries); if ( bufP > buf + nRead ) { /* * Need to get more data and try again. We have allocated file->name, * and perhaps partially filled the xattr structure, which will be ok * on the retry since the same structure will be used. */ if ( retry ) { bpc_logErrf("bpc_attrib_dirRead: BOTCH: couldn't complete file conversion on retry (%ld,%ld,%ld)\n", bufP - buf, bufPsave - buf, nRead); bpc_fileZIO_close(&fd); return -1; } if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_attrib_dirRead: retrying file conversion\n"); bufP = bufPsave; if ( read_more_data(&fd, buf, sizeof(buf), &nRead, &bufP, attribPath) ) { bpc_fileZIO_close(&fd); return -1; } retry = 1; } else { retry = 0; } if ( !retry && BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_attrib_dirRead(%s): Got file %s: type = %d, mode = 0%o, uid/gid = %d/%d, size = %d\n", attribPath, file->name, file->type, file->mode, file->uid, file->gid, file->size); } } else if ( magic == BPC_ATTRIB_TYPE_UNIX ) { while ( bufP < buf + nRead ) { uint fileNameLen; char *fileName; bpc_attrib_file *file; int64 sizeDiv4GB; uint type; if ( nRead == sizeof(buf) && bufP > buf + nRead - 2 * BPC_MAXPATHLEN && read_more_data(&fd, buf, sizeof(buf), &nRead, &bufP, attribPath) ) { bpc_fileZIO_close(&fd); return -1; } fileNameLen = getVarInt_v3(&bufP, buf + nRead); if ( fileNameLen > 2 * BPC_MAXPATHLEN - 16 ) { bpc_logErrf("bpc_attrib_dirRead: got unreasonable file name length %d\n", fileNameLen); bpc_fileZIO_close(&fd); return -1; } /* * Save the fileName, but it's not NULL terminated yet. * After we get the next data, we can safely NULL-terminate the fileName. */ fileName = (char*)bufP; bufP += fileNameLen; type = getVarInt_v3(&bufP, buf + nRead); fileName[fileNameLen] = '\0'; file = bpc_attrib_fileGet(dir, fileName, 1); bpc_attrib_fileInit(file, fileName, 0); file->type = type; file->mode = getVarInt_v3(&bufP, buf + nRead); file->uid = getVarInt_v3(&bufP, buf + nRead); file->gid = getVarInt_v3(&bufP, buf + nRead); sizeDiv4GB = getVarInt_v3(&bufP, buf + nRead); file->size = (sizeDiv4GB << 32) + getVarInt_v3(&bufP, buf + nRead); file->mtime = CONV_BUF_TO_UINT32(bufP); bufP += 4; file->compress = dir->compress; file->backupNum = backupNum; if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_attrib_dirRead(%s): Got v3 file %s: type = %d, mode = 0%o, uid/gid = %d/%d, size = %d\n", attribPath, file->name, file->type, file->mode, file->uid, file->gid, file->size); } } else { bpc_logErrf("Unexpected magic number 0x%x read from %s\n", magic, attribPath); return -1; } /* TODO: make sure we are at EOF? */ bpc_fileZIO_close(&fd); return 0; } typedef struct { uchar *bufP; uchar *bufEnd; } buf_info; typedef struct { bpc_poolWrite_info fd; uchar buf[4 * 65536]; uchar *bufP; } write_info; static void write_file_flush(write_info *info) { if ( info->bufP > info->buf ) { if ( BPC_LogLevel >= 7 ) bpc_logMsgf("write_file_flush: writing %lu bytes to pool\n", (unsigned long)(info->bufP - info->buf)); bpc_poolWrite_write(&info->fd, info->buf, info->bufP - info->buf); } info->bufP = info->buf; } static void bpc_attrib_xattrWrite(bpc_attrib_xattr *xattr, buf_info *info) { setVarInt(&info->bufP, info->bufEnd, xattr->key.keyLen); setVarInt(&info->bufP, info->bufEnd, xattr->valueLen); if ( info->bufP + xattr->key.keyLen <= info->bufEnd ) { memcpy(info->bufP, xattr->key.key, xattr->key.keyLen); } info->bufP += xattr->key.keyLen; if ( info->bufP + xattr->valueLen <= info->bufEnd ) { memcpy(info->bufP, xattr->value, xattr->valueLen); } info->bufP += xattr->valueLen; } /* * Write a file structure to the memory buffer. Returns the next unused buffer * pointer. If the buffer is exhausted, no data is written past the buffer end, * Therefore, if the return value is greater than bufEnd, then the conversion * failed to fit. The routine can be called again with at least (bufP - buf) * bytes allocated. */ uchar *bpc_attrib_file2buf(bpc_attrib_file *file, uchar *buf, uchar *bufEnd) { uchar *bufP = buf; size_t fileNameLen = strlen(file->name); uint xattrEntryCnt = bpc_hashtable_entryCount(&file->xattrHT); buf_info info; setVarInt(&bufP, bufEnd, fileNameLen); if ( bufP + fileNameLen < bufEnd ) { memcpy(bufP, file->name, fileNameLen); } bufP += fileNameLen; setVarInt(&bufP, bufEnd, xattrEntryCnt); setVarInt(&bufP, bufEnd, file->type); setVarInt(&bufP, bufEnd, file->mtime); setVarInt(&bufP, bufEnd, file->mode); setVarInt(&bufP, bufEnd, file->uid); setVarInt(&bufP, bufEnd, file->gid); setVarInt(&bufP, bufEnd, file->size); setVarInt(&bufP, bufEnd, file->inode); setVarInt(&bufP, bufEnd, file->compress); setVarInt(&bufP, bufEnd, file->nlinks); setVarInt(&bufP, bufEnd, file->digest.len); if ( bufP + file->digest.len <= bufEnd ) { memcpy(bufP, file->digest.digest, file->digest.len); } bufP += file->digest.len; info.bufEnd = bufEnd; info.bufP = bufP; bpc_hashtable_iterate(&file->xattrHT, (void*)bpc_attrib_xattrWrite, &info); return info.bufP; } static void bpc_attrib_fileWrite(bpc_attrib_file *file, write_info *info) { uchar *bufP; if ( file->isTemp ) { if ( BPC_LogLevel >= 6 ) bpc_logMsgf("Skipping temp file %s: type = %d, mode = 0%o, uid/gid = %lu/%lu, size = %lu, inode = %lu, nlinks = %d, digest = 0x%02x%02x%02x..., bufUsed = %lu\n", file->name, file->type, file->mode, (unsigned long)file->uid, (unsigned long)file->gid, (unsigned long)file->size, (unsigned long)file->inode, file->nlinks, file->digest.digest[0], file->digest.digest[1], file->digest.digest[2], (unsigned long)(info->bufP - info->buf)); return; } bufP = bpc_attrib_file2buf(file, info->bufP, info->buf + sizeof(info->buf)); if ( BPC_LogLevel >= 6 ) bpc_logMsgf("Wrote file %s: type = %d, mode = 0%o, uid/gid = %lu/%lu, size = %lu, inode = %lu, nlinks = %d, digest = 0x%02x%02x%02x..., bufUsed = %lu\n", file->name, file->type, file->mode, (unsigned long)file->uid, (unsigned long)file->gid, (unsigned long)file->size, (unsigned long)file->inode, file->nlinks, file->digest.digest[0], file->digest.digest[1], file->digest.digest[2], (unsigned long)(info->bufP - info->buf)); if ( bufP <= info->buf + sizeof(info->buf) ) { /* * it fit into the buffer */ info->bufP = bufP; return; } /* * we overflowed the buffer - flush and try again */ write_file_flush(info); bufP = bpc_attrib_file2buf(file, info->bufP, info->buf + sizeof(info->buf)); if ( bufP <= info->buf + sizeof(info->buf) ) { info->bufP = bufP; return; } bpc_logErrf("bpc_attrib_fileWrite: BOTCH: can't fit file into buffer (%ld, %ld)\n", bufP - info->buf, sizeof(info->buf)); } /* * Pre 0.50 attribute writing. Writes a small file that contains the file hash of the attrib file */ static int bpc_attrib_dirWriteOld(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, char *dirPath, char *attribFileName, bpc_digest *oldDigest) { char attribPath[BPC_MAXPATHLEN], attribPathTemp[BPC_MAXPATHLEN]; bpc_fileZIO_fd fd; bpc_digest digest; int status; OFF_T poolFileSize; int errorCnt; static write_info info; char *p; bpc_attrib_attribFilePath(attribPath, dirPath, attribFileName); if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_attrib_dirWriteOld(%s)\n", attribPath); snprintf(attribPathTemp, BPC_MAXPATHLEN, "%s.%d", attribPath, getpid()); if ( (p = strrchr(attribPathTemp, '/')) ) { *p = '\0'; if ( bpc_path_create(attribPathTemp) ) return -1; *p = '/'; } if ( bpc_hashtable_entryCount(&dir->filesHT) == 0 ) { int fdNum; /* * Empty directory - we just generate an empty attrib file, which we don't pool */ if ( (fdNum = open(attribPathTemp, O_WRONLY | O_CREAT | O_TRUNC, 0660)) < 0 ) { bpc_logErrf("bpc_attrib_dirWrite: can't open/create raw %s for writing\n", attribPathTemp); return -1; } close(fdNum); if ( rename(attribPathTemp, attribPath) ) { bpc_logErrf("bpc_attrib_dirWrite: rename from %s to %s failed\n", attribPathTemp, attribPath); return -1; } if ( oldDigest ) bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, oldDigest, -1); dir->digest.len = 0; return 0; } info.bufP = info.buf; CONV_UINT32_TO_BUF(info.bufP, BPC_ATTRIB_TYPE_XATTR); bpc_poolWrite_open(&info.fd, dir->compress, NULL); bpc_hashtable_iterate(&dir->filesHT, (void*)bpc_attrib_fileWrite, &info); write_file_flush(&info); bpc_poolWrite_close(&info.fd, &status, &digest, &poolFileSize, &errorCnt); if ( errorCnt ) return -1; /* * Now write the small atttib file, which just contains a magic number and the digest */ if ( bpc_fileZIO_open(&fd, attribPathTemp, 1, dir->compress) ) { bpc_logErrf("bpc_attrib_dirWrite: can't open/create %s for writing\n", attribPathTemp); return -1; } info.bufP = info.buf; CONV_UINT32_TO_BUF(info.bufP, BPC_ATTRIB_TYPE_DIGEST); if ( digest.len > 0 ) { memcpy(info.bufP, digest.digest, digest.len); info.bufP += digest.len; } if ( bpc_fileZIO_write(&fd, info.buf, info.bufP - info.buf) < 0 ) { bpc_logErrf("bpc_attrib_dirWrite: can't write to %s\n", attribPathTemp); bpc_fileZIO_close(&fd); return -1; } bpc_fileZIO_close(&fd); if ( rename(attribPathTemp, attribPath) ) { bpc_logErrf("bpc_attrib_dirWrite: rename from %s to %s failed\n", attribPathTemp, attribPath); return -1; } if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_attrib_dirWrite: new attrib digest = 0x%02x%02x%02x..., oldDigest = 0x%02x%02x...\n", digest.digest[0], digest.digest[1], digest.digest[2], oldDigest ? oldDigest->digest[0] : 0x0, oldDigest ? oldDigest->digest[1] : 0x0); if ( oldDigest ) bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, oldDigest, -1); bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, &digest, 1); /* * update with the new digest */ memcpy(&dir->digest, &digest, sizeof(digest)); return 0; } int bpc_attrib_dirWrite(bpc_deltaCount_info *deltaInfo, bpc_attrib_dir *dir, char *dirPath, char *attribFileName, bpc_digest *oldDigest) { char attribPath[BPC_MAXPATHLEN], attribPathTemp[BPC_MAXPATHLEN], *baseAttribFileName; bpc_digest digest; int status; OFF_T poolFileSize; int errorCnt; static write_info info; char *p; int fdNum; size_t attribPathLen, baseAttribFileNameLen; if ( WriteOldStyleAttribFile ) return bpc_attrib_dirWriteOld(deltaInfo, dir, dirPath, attribFileName, oldDigest); /* * baseAttribFileName points to the last portion of attribFileName, or the whole * string if it doesn't contain '/' */ if ( (baseAttribFileName = strrchr(attribFileName, '/')) ) { baseAttribFileName++; } else { baseAttribFileName = attribFileName; } baseAttribFileNameLen = strlen(baseAttribFileName); bpc_attrib_attribFilePath(attribPath, dirPath, attribFileName); if ( BPC_LogLevel >= 6 ) bpc_logMsgf("bpc_attrib_dirWrite(%s): dirPath = %s, attribFileName = %s, baseAttribFileName = %s\n", attribPath, dirPath, attribFileName, baseAttribFileName); snprintf(attribPathTemp, BPC_MAXPATHLEN, "%s.%d", attribPath, getpid()); if ( (p = strrchr(attribPathTemp, '/')) ) { *p = '\0'; if ( bpc_path_create(attribPathTemp) ) return -1; *p = '/'; } attribPathLen = strlen(attribPath); if ( bpc_hashtable_entryCount(&dir->filesHT) > 0 ) { /* * Write the attribute file to the pool */ info.bufP = info.buf; CONV_UINT32_TO_BUF(info.bufP, BPC_ATTRIB_TYPE_XATTR); bpc_poolWrite_open(&info.fd, dir->compress, NULL); bpc_hashtable_iterate(&dir->filesHT, (void*)bpc_attrib_fileWrite, &info); write_file_flush(&info); bpc_poolWrite_close(&info.fd, &status, &digest, &poolFileSize, &errorCnt); if ( errorCnt ) return -1; /* * Starting in 0.50, the attrib file is always empty (so it takes no extra blocks) * and we simply include the digest in the file name by appending the hex digits. * * An empty attrib file is simply "attrib_0", and a legacy attrib file (pre <0.50) * is "attrib". */ if ( attribPathLen + digest.len * 2 + 2 >= sizeof(attribPath) ) { bpc_logErrf("bpc_attrib_dirWrite: path too long (%d, %d, %d)\n", strlen(attribPath), digest.len, sizeof(attribPath)); return -1; } attribPath[attribPathLen++] = '_'; bpc_digest_digest2str(&digest, attribPath + attribPathLen); } else { digest.len = 0; attribPath[attribPathLen++] = '_'; strcpy(attribPath + attribPathLen, "0"); } /* * Now create an empty attrib file */ if ( (fdNum = open(attribPathTemp, O_WRONLY | O_CREAT | O_TRUNC, 0660)) < 0 ) { bpc_logErrf("bpc_attrib_dirWrite: can't open/create raw %s for writing\n", attribPathTemp); return -1; } close(fdNum); if ( rename(attribPathTemp, attribPath) ) { bpc_logErrf("bpc_attrib_dirWrite: rename from %s to %s failed\n", attribPathTemp, attribPath); return -1; } if ( BPC_LogLevel >= 5 ) bpc_logMsgf("bpc_attrib_dirWrite: created new attrib file %s\n", attribPath); if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_attrib_dirWrite: new attrib digest = 0x%02x%02x%02x..., oldDigest = 0x%02x%02x...\n", digest.digest[0], digest.digest[1], digest.digest[2], oldDigest ? oldDigest->digest[0] : 0x0, oldDigest ? oldDigest->digest[1] : 0x0); bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, &digest, 1); if ( oldDigest ) { if ( !bpc_digest_compare(&digest, oldDigest) ) { if ( BPC_LogLevel >= 2 ) bpc_logMsgf("bpc_attrib_dirWrite: old attrib has same digest; no changes to ref counts\n"); return 0; } if ( attribPathLen + oldDigest->len * 2 + 2 >= sizeof(attribPath) ) { bpc_logErrf("bpc_attrib_dirWrite: oldDigest path too long (%d, %d, %d)\n", strlen(attribPath), oldDigest->len, sizeof(attribPath)); return -1; } strcpy(attribPathTemp, attribPath); if ( oldDigest->len > 0 ) { bpc_poolRefDeltaUpdate(deltaInfo, dir->compress, oldDigest, -1); bpc_digest_digest2str(oldDigest, attribPathTemp + attribPathLen); } else { strcpy(attribPathTemp + attribPathLen, "0"); } if ( !unlink(attribPathTemp) ) { if ( BPC_LogLevel >= 5 ) bpc_logMsgf("bpc_attrib_dirWrite: removed old attrib file %s\n", attribPathTemp); } else { DIR *dirOs; struct dirent *dp; char deletePath[BPC_MAXPATHLEN]; /* * Scan the directory and remove any other attribute files that have the * same root. */ if ( !(p = strrchr(attribPath, '/')) ) { bpc_logErrf("bpc_attrib_dirWrite: can't find a '/' in %s\n", attribPath); return -1; } *p++ = '\0'; if ( !(dirOs = opendir(attribPath)) ) { bpc_logErrf("bpc_attrib_dirWrite: can't opendir %s\n", attribPath); return -1; } while ( (dp = readdir(dirOs)) ) { if ( strncmp(dp->d_name, baseAttribFileName, baseAttribFileNameLen) || !strcmp(dp->d_name, p) ) continue; snprintf(deletePath, sizeof(deletePath), "%s/%s", attribPath, dp->d_name); unlink(deletePath); if ( BPC_LogLevel >= 5 ) bpc_logMsgf("bpc_attrib_dirWrite: removed other old attrib file %s\n", deletePath); } closedir(dirOs); } } /* * update with the new digest */ memcpy(&dir->digest, &digest, sizeof(digest)); return 0; } rsync-bpc-3.1.2.1/backuppc/bpc_refCount.c0000664000047500004750000004077213510756401017101 0ustar craigcraig/* * Routines to provide reference counting * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc.h" /* * magic number that appears at the start of the reference count (or delta count file) */ #define BPC_POOL_REF_MAGIC (0x178e553c) #define CONV_BUF_TO_UINT32(buf) ((buf)[0] << 24 | (buf)[1] << 16 | (buf)[2] << 8 | (buf)[3]) #define CONV_UINT32_TO_BUF(buf, val) { *(buf)++ = ((val) >> 24) & 0xff; \ *(buf)++ = ((val) >> 16) & 0xff; \ *(buf)++ = ((val) >> 8) & 0xff; \ *(buf)++ = ((val) >> 0) & 0xff; } typedef struct { bpc_hashtable_key key; int32 count; bpc_digest digest; } DigestInfo; typedef struct { int fd; uchar *bufP; int errorCnt; uchar buf[4 * 65536]; } write_info; void bpc_poolRefInit(bpc_refCount_info *info, int entryCnt) { bpc_hashtable_create(&info->ht, entryCnt, sizeof(DigestInfo)); } void bpc_poolRefDestroy(bpc_refCount_info *info) { bpc_hashtable_destroy(&info->ht); } void bpc_poolRefSet(bpc_refCount_info *info, bpc_digest *digest, int32 count) { DigestInfo *d = bpc_hashtable_find(&info->ht, digest->digest, digest->len, 1); if ( d->key.key == digest ) { /* * new entry - copy in digest */ d->digest = *digest; d->key.key = d->digest.digest; } d->count = count; return; } int bpc_poolRefGet(bpc_refCount_info *info, bpc_digest *digest, int32 *count) { DigestInfo *d = bpc_hashtable_find(&info->ht, digest->digest, digest->len, 0); if ( !d ) return -1; *count = d->count; return 0; } int bpc_poolRefDelete(bpc_refCount_info *info, bpc_digest *digest) { DigestInfo *d = bpc_hashtable_find(&info->ht, digest->digest, digest->len, 0); if ( !d ) return -1; bpc_hashtable_nodeDelete(&info->ht, d); return 0; } int bpc_poolRefIncr(bpc_refCount_info *info, bpc_digest *digest, int32 delta) { DigestInfo *d = bpc_hashtable_find(&info->ht, digest->digest, digest->len, 1); if ( d->key.key == digest ) { /* * new entry - copy in digest */ d->digest = *digest; d->key.key = d->digest.digest; } d->count += delta; if ( BPC_LogLevel >= 8 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&d->digest, hexStr); bpc_logMsgf("bpc_poolRefIncr(%s, %d), count now %d\n", hexStr, delta, d->count); } return d->count; } int bpc_poolRefIterate(bpc_refCount_info *info, bpc_digest *digest, int32 *count, uint *idx) { DigestInfo *d = bpc_hashtable_nextEntry(&info->ht, idx); if ( !d ) return -1; *digest = d->digest; *count = d->count; return 0; } void bpc_poolRefPrintEntry(DigestInfo *info) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&info->digest, hexStr); fprintf(stderr, "%-20s %d\n", hexStr, info->count); } void bpc_poolRefCountPrint(bpc_refCount_info *info) { bpc_hashtable_iterate(&info->ht, (void*)bpc_poolRefPrintEntry, NULL); } static void write_file_flush(write_info *out) { uchar *p = out->buf; while ( p < out->bufP ) { int nWrite = write(out->fd, p, out->bufP - p); if ( nWrite < 0 ) { if ( errno == EINTR ) continue; out->errorCnt++; return; } p += nWrite; } out->bufP = out->buf; } static int bpc_poolRef_read_more_data(int fd, uchar *buf, size_t bufSize, size_t *nRead, uchar **bufPP, char *fileName) { int thisRead; /* * move the remaining part of the buffer down, and read more data */ *nRead = (buf + *nRead) - *bufPP; if ( *nRead > 0 ) memmove(buf, *bufPP, *nRead); *bufPP = buf; do { do { thisRead = read(fd, buf + *nRead, bufSize - *nRead); } while ( thisRead < 0 && errno == EINTR ); if ( thisRead < 0 ) { bpc_logErrf("bpc_poolRefFileRead: can't read more bytes from %s (errno %d)\n", fileName, errno); return -1; } if ( BPC_LogLevel >= 8 ) bpc_logMsgf("bpc_poolRef_read_more_data: read %d bytes (nRead = %d, sizeof(buf) = %d)\n", thisRead, *nRead, bufSize); *nRead += thisRead; } while ( thisRead > 0 && *nRead < sizeof(buf) ); return 0; } /* * Read variable-length unsigned integer in 7 bit chunks, LSB first. * * To handle signed numbers, the very first LSB is a sign bit, meaning the first byte * stores just 6 bits. */ static int64 getVarInt(uchar **bufPP, uchar *bufLast) { int64 result = 0; uchar *bufP = *bufPP, c = '\0'; int i = 6, negative = 0; if ( bufP < bufLast ) { c = *bufP++; negative = c & 0x1; result = (c & 0x7e) >> 1; } while ( bufP < bufLast && (c & 0x80) ) { c = *bufP++; result |= (c & 0x7f) << i; i += 7; } *bufPP = bufP; if ( negative ) result = -result; return result; } /* * Write variable-length unsigned integer in 7 bit chunks, LSB first. * * To handle signed numbers, the very first LSB is a sign bit, meaning the first byte * stores just 6 bits. */ static void setVarInt(uchar **bufPP, uchar *bufLast, int64 value) { uchar *bufP = *bufPP; int negative = 0; if ( value < 0 ) { value = -value; negative = 1; } if ( bufP < bufLast ) { uchar c = ((value & 0x3f) << 1) | negative; value >>= 6; if ( value ) c |= 0x80; *bufP++ = c; } while ( value && bufP < bufLast ) { uchar c = value & 0x7f; value >>= 7; if ( value ) c |= 0x80; *bufP++ = c; } *bufPP = bufP; } static void bpc_poolRefFileWriteEntry(DigestInfo *info, write_info *out) { if ( out->bufP > out->buf + sizeof(out->buf) - BPC_DIGEST_LEN_MAX - 16 ) write_file_flush(out); *out->bufP++ = (uchar)info->digest.len; memcpy(out->bufP, info->digest.digest, info->digest.len); out->bufP += info->digest.len; setVarInt(&out->bufP, out->buf + sizeof(out->buf), info->count); } /* * Write a pool reference file from the hash table. */ int bpc_poolRefFileWrite(bpc_refCount_info *info, char *fileName) { write_info out; out.errorCnt = 0; out.bufP = out.buf; out.fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0666); if ( out.fd < 0 ) { /* * Maybe the directory doesn't exist - try to create it and try again */ char dir[BPC_MAXPATHLEN], *p; snprintf(dir, sizeof(dir), "%s", fileName); if ( (p = strrchr(dir, '/')) ) { *p = '\0'; bpc_path_create(dir); out.fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0666); } if ( out.fd < 0 ) { bpc_logErrf("bpc_poolRefFileWrite: can't open/create pool delta file name %s (errno %d)\n", fileName, errno); out.errorCnt++; return out.errorCnt; } } /* * start with the magic number, then the total number of entries */ CONV_UINT32_TO_BUF(out.bufP, BPC_POOL_REF_MAGIC); setVarInt(&out.bufP, out.buf + sizeof(out.buf), bpc_hashtable_entryCount(&info->ht)); /* * now write all the digests and counts */ bpc_hashtable_iterate(&info->ht, (void*)bpc_poolRefFileWriteEntry, &out); if ( out.bufP > out.buf ) write_file_flush(&out); if ( close(out.fd) < 0 ) { bpc_logErrf("bpc_poolRefFileWrite: pool delta close failed to %s (errno %d)\n", fileName, errno); out.errorCnt++; } return out.errorCnt; } /* * Read a pool reference file into the hash table, which should be already initialized. */ int bpc_poolRefFileRead(bpc_refCount_info *info, char *fileName) { int fd = open(fileName, O_RDONLY); uint32 entryCnt, i; bpc_digest digest; int64 count; size_t nRead = 0; uint32 magic; uchar buf[8 * 65536]; uchar *bufP = buf; if ( fd < 0 ) { bpc_logErrf("bpc_poolRefFileRead: can't open %s (errno %d)\n", fileName, errno); return -1; } if ( bpc_poolRef_read_more_data(fd, buf, sizeof(buf), &nRead, &bufP, fileName) < 0 ) { bpc_logErrf("bpc_poolRefFileRead: can't read data from %s (errno %d)\n", fileName, errno); return -1; } magic = CONV_BUF_TO_UINT32(bufP); bufP += 4; if ( magic != BPC_POOL_REF_MAGIC ) { bpc_logErrf("bpc_poolRefFileRead: bad magic number 0x%x (expected 0x%x)\n", magic, BPC_POOL_REF_MAGIC); return -1; } entryCnt = getVarInt(&bufP, buf + nRead); if ( BPC_LogLevel >= 4 ) bpc_logMsgf("bpc_poolRefFileRead: got %d entries (nRead = %d)\n", entryCnt, nRead); /* * make sure the hash table is big enough in one go to avoid multiple doublings */ bpc_hashtable_growSize(&info->ht, entryCnt * 4 / 3); for ( i = 0 ; i < entryCnt ; i++ ) { DigestInfo *digestInfo; if ( nRead == sizeof(buf) && bufP > buf + nRead - 64 && bpc_poolRef_read_more_data(fd, buf, sizeof(buf), &nRead, &bufP, fileName) < 0 ) { bpc_logErrf("bpc_poolRefFileRead: can't read more data from %s (errno %d)\n", fileName, errno); return -1; } digest.len = *bufP++; if ( digest.len > (int)sizeof(digest.digest) ) digest.len = sizeof(digest.digest); memcpy(digest.digest, bufP, digest.len); bufP += digest.len; count = getVarInt(&bufP, buf + nRead); if ( BPC_LogLevel >= 7 ) bpc_logMsgf("bpc_poolRefFileRead: entry %d: digest len = %d, digest = 0x%02x%02x%02x...., count = %d\n", i, digest.len, digest.digest[0], digest.digest[1], digest.digest[2], count); digestInfo = bpc_hashtable_find(&info->ht, digest.digest, digest.len, 1); if ( digestInfo->key.key == digest.digest ) { /* * new entry since the key points to our key - copy info into new node and set key locally */ digestInfo->digest = digest; digestInfo->key.key = digestInfo->digest.digest; } digestInfo->count = count; } close(fd); return 0; } /* * Mark this host backup as needing an fsck. Multiple requests can be supported with * unique numbers. ext == 0 is used for the overall backup process, and it is removed when * the backup finished. Various errors can use other extensions. If any files are * present, an fsck is done either by the next backup, BackupPC_refCountUpdate or * BackupPC_fsck. */ void bpc_poolRefRequestFsck(char *backupDir, int ext) { char fileName[BPC_MAXPATHLEN]; int fd; snprintf(fileName, sizeof(fileName), "%s/refCnt/needFsck%d", backupDir, ext); if ( (fd = open(fileName, O_CREAT | O_WRONLY, 0660)) < 0 ) { bpc_logErrf("bpc_poolRefRequestFsck: can't open/create fsck request file %s (errno %d)\n", fileName, errno); } } /*********************************************************************** * Reference count deltas - we maintain two hash tables for uncompressed * and compressed deltas. ***********************************************************************/ /* * Legacy support for <= 4.0.0beta3. */ static bpc_deltaCount_info DeltaInfoOld; static int OutputFileCnt = 0; void bpc_poolRefDeltaFileInit(bpc_deltaCount_info *info, char *hostDir) { if ( snprintf(info->targetDir, sizeof(info->targetDir), "%s", hostDir) >= (int)sizeof(info->targetDir) - 1 ) { bpc_logErrf("bpc_poolRefDeltaFileInit: targetDir %s truncated\n", hostDir); } bpc_poolRefInit(&info->refCnt[0], 256); bpc_poolRefInit(&info->refCnt[1], 1 << 20); info->refCnt[0].initDone = info->refCnt[1].initDone = 1; } void bpc_poolRefDeltaFileDestroy(bpc_deltaCount_info *info) { bpc_poolRefDestroy(&info->refCnt[0]); bpc_poolRefDestroy(&info->refCnt[1]); } uint32 bpc_poolRefDeltaFileFlush(bpc_deltaCount_info *info) { char tempFileName[BPC_MAXPATHLEN], finalFileName[BPC_MAXPATHLEN]; int compress; int errorCnt = 0; int fd; if ( !info ) info = &DeltaInfoOld; /* backward compatibility */ if ( !info->refCnt[0].initDone ) return 1; for ( compress = 0 ; compress < 2 ; compress++ ) { uint entryCnt = bpc_hashtable_entryCount(&info->refCnt[compress].ht); if ( entryCnt == 0 ) continue; do { if ( snprintf(tempFileName, sizeof(tempFileName), "%s/refCnt/tpoolCntDelta_%d_%d_%d_%d", info->targetDir, compress, BPC_TmpFileUnique, OutputFileCnt, getpid()) >= (int)sizeof(tempFileName) - 1 ) { bpc_logErrf("bpc_poolRefDeltaFileFlush: pool delta file name %s truncated\n", tempFileName); errorCnt++; } if ( (fd = open(tempFileName, O_RDONLY, 0666)) >= 0 ) { close(fd); OutputFileCnt++; } } while ( fd >= 0 ); errorCnt += bpc_poolRefFileWrite(&info->refCnt[compress], tempFileName); if ( snprintf(finalFileName, sizeof(finalFileName), "%s/refCnt/poolCntDelta_%d_%d_%d_%d", info->targetDir, compress, BPC_TmpFileUnique >= 0 ? BPC_TmpFileUnique : 0, OutputFileCnt, getpid()) >= (int)sizeof(finalFileName) - 1 ) { bpc_logErrf("bpc_poolRefDeltaFileFlush: pool delta file name %s truncated\n", finalFileName); errorCnt++; } if ( errorCnt ) { unlink(tempFileName); continue; } if ( rename(tempFileName, finalFileName) != 0 ) { bpc_logErrf("bpc_poolRefDeltaFileFlush: can't rename %s to %s (errno %d)\n", tempFileName, finalFileName, errno); unlink(tempFileName); errorCnt++; } if ( !errorCnt ) { bpc_hashtable_erase(&info->refCnt[compress].ht); } } OutputFileCnt++; if ( errorCnt ) { /* * Need to fsck this particular backup on this host */ bpc_poolRefRequestFsck(info->targetDir, getpid()); } return errorCnt; } void bpc_poolRefDeltaUpdate(bpc_deltaCount_info *info, int compress, bpc_digest *digest, int32 count) { DigestInfo *digestInfo; if ( !info ) info = &DeltaInfoOld; /* backward compatibility */ if ( !digest || digest->len == 0 ) return; if ( !info->refCnt[0].initDone ) return; digestInfo = bpc_hashtable_find(&info->refCnt[compress ? 1 : 0].ht, digest->digest, digest->len, 1); if ( digestInfo->key.key == digest->digest ) { /* * new entry since the key points to our key - copy info into new node and set key locally */ digestInfo->digest = *digest; digestInfo->key.key = digestInfo->digest.digest; } digestInfo->count += count; if ( BPC_LogLevel >= 8 ) { char hexStr[BPC_DIGEST_LEN_MAX * 2 + 1]; bpc_digest_digest2str(&digestInfo->digest, hexStr); bpc_logMsgf("bpc_poolRefDeltaUpdate(%s, %d), count now %d\n", hexStr, count, digestInfo->count); } if ( bpc_hashtable_entryCount(&info->refCnt[compress ? 1 : 0].ht) > (1 << 20) ) { bpc_poolRefDeltaFileFlush(info); } } void bpc_poolRefDeltaPrint(bpc_deltaCount_info *info) { if ( !info ) info = &DeltaInfoOld; /* backward compatibility */ if ( !info->refCnt[0].initDone ) return; fprintf(stderr, "Uncompressed HT:\n"); bpc_hashtable_iterate(&info->refCnt[0].ht, (void*)bpc_poolRefPrintEntry, NULL); fprintf(stderr, "Compressed HT:\n"); bpc_hashtable_iterate(&info->refCnt[1].ht, (void*)bpc_poolRefPrintEntry, NULL); } /* * Legacy support for <= 4.0.0beta3. */ void bpc_poolRefDeltaFileInitOld(char *hostDir) { bpc_poolRefDeltaFileInit(&DeltaInfoOld, hostDir); } uint32 bpc_poolRefDeltaFileFlushOld(void) { return bpc_poolRefDeltaFileFlush(&DeltaInfoOld); } /* * Increment/decrement the reference count for the given digest */ void bpc_poolRefDeltaUpdateOld(int compress, bpc_digest *digest, int32 count) { bpc_poolRefDeltaUpdate(&DeltaInfoOld, compress, digest, count); } void bpc_poolRefDeltaPrintOld(void) { bpc_poolRefDeltaPrint(&DeltaInfoOld); } rsync-bpc-3.1.2.1/sender.c0000664000047500004750000002574613510756407014172 0ustar craigcraig/* * Routines only used by the sending process. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2015 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 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 io_error; extern int flist_eof; extern int allowed_lull; 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 batch_fd; extern int write_batch; extern int file_old_total; extern struct stats stats; extern struct file_list *cur_flist, *first_flist, *dir_flist; 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; int32 i; int lull_mod = protocol_version >= 31 ? 0 : allowed_lull * 5; OFF_T offset = 0; if (!(s = new(struct sum_struct))) out_of_memory("receive_sums"); 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); if (!(s->sums = new_array(struct sum_buf, s->count))) out_of_memory("receive_sums"); 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 (do_lstat(fname, &st) < 0) { failed_op = "re-lstat"; goto failed; } if (S_ISREG(file->mode) /* Symlinks & devices don't need this check: */ && (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"); 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 && INFO_GTE(PROGRESS, 2) && cur_flist) { set_current_file_index(NULL, 0); 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 && (protocol_version >= 29 ? fnamecmp_type == FNAMECMP_FNAME : make_backups <= 0); if (!am_server && INFO_GTE(PROGRESS, 1)) set_current_file_index(file, ndx); stats.xferred_files++; stats.total_transferred_size += F_LENGTH(file); remember_initial_stats(); bpc_sysCall_statusFileSize(F_LENGTH(file)); 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); bpc_close(fd); exit_cleanup(RERR_FILEIO); } 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); 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)); } } bpc_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-bpc-3.1.2.1/hashtable.c0000664000047500004750000001214313510756407014630 0ustar craigcraig/* * Routines to provide a memory-efficient hashtable. * * Copyright (C) 2007-2015 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; } if (!(tbl = new(struct hashtable)) || !(tbl->nodes = new_array0(char, size * node_size))) out_of_memory("hashtable_create"); 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); } /* This returns the node for the indicated key, either newly created or * already existing. Returns NULL if not allocating and not found. */ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing) { 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 (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) { void *old_nodes = tbl->nodes; int size = tbl->size * 2; int i; if (!(tbl->nodes = new_array0(char, size * tbl->node_size))) out_of_memory("hashtable_node"); 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; node = hashtable_find(tbl, move_key, 1); node->data = move_node->data; } 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 (!allocate_if_missing) 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; tbl->entries++; return node; } /* * Iterate over all the entries in the hash table, calling a callback for each valid entry * * Note: this function won't work if the callback adds new entries to the hash table while * iterating over the entries. You can update or delete entries, but adding an entry might * cause the hash table size to be bumped, which breaks the indexing. So don't add new * entries while iterating over the table. */ void hashtable_iterate(struct hashtable *tbl, void (*callback)(int64 key, void*, void*), void *arg1) { int32 ndx; int key64 = tbl->key64, nkey; struct ht_int32_node *node; for ( ndx = 0 ; ndx < tbl->size ; ndx++ ) { node = HT_NODE(tbl, tbl->nodes, ndx); nkey = HT_KEY(node, key64); if ( nkey == 0 ) continue; (*callback)(nkey, (void*)node, arg1); } } rsync-bpc-3.1.2.1/stunnel-rsyncd.conf.in0000664000047500004750000000175313510756401016774 0ustar craigcraig# 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/ca-bundle.pem # 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-bpc-3.1.2.1/bpc_sysCalls.c0000664000047500004750000021762213510756401015321 0ustar craigcraig/* * Emulate system calls for BackupPC. * * Copyright (C) 2013 Craig Barratt. * * 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 "backuppc/backuppc.h" #include "ifuncs.h" #define MAX_FD (64) #define MAX_BUF_SZ (8 << 20) /* 8MB */ /* * A freelist of unused MAX_BUF_SZ sized-buffers. * We use the first sizeof(void*) bytes of the buffer as a single-linked * list, with a NULL at the end */ static void *DataBufferFreeList = (void*)NULL; extern int am_generator; extern int always_checksum; extern int preserve_hard_links; extern int protocol_version; static bpc_attribCache_info acNew; static bpc_attribCache_info acOld; static int acOldUsed; static bpc_deltaCount_info DeltaNew; static bpc_deltaCount_info DeltaOld; static int LogLevel; static int DoneInit = 0; static int CompressLevel; typedef struct _bpc_sysCall_stats { ino_t Inode0, InodeCurr; int64 ErrorCnt; int64 ExistFileCnt, ExistFileSize, ExistFileCompSize; int64 NewFileCnt, NewFileSize, NewFileCompSize; int64 TotalFileCnt, TotalFileSize; } bpc_sysCall_stats; static bpc_sysCall_stats Stats; static void logMsgCB(UNUSED(int errFlag), char *mesg, size_t mesgLen) { fwrite(mesg, 1, mesgLen, stderr); fflush(stderr); //rwrite(errFlag ? FERROR : FINFO, mesg, mesgLen, 0); } void bpc_sysCall_init( char *topDir, /* backuppc top-level data dir path */ char *hostName, /* host name */ char *shareNameUM, /* unmangled share name */ int newBkupNum, /* new backup number */ int newCompress, /* compression level for new backup */ int prevBkupNum, /* prior backup number (or -1) */ int prevCompress, /* comperssion level for prior backup */ char *mergeBkupInfo, /* which backups to merge together on read */ ino_t inode0, /* starting inode number for this backup */ int attrib_new, /* flag to turn on new-style attrib file names */ int logLevel /* logging level */ ) { static char hostDir[BPC_MAXPATHLEN]; extern int BPC_HardLinkMax; extern int BPC_PoolV3Enabled; bpc_logMsgCBSet(logMsgCB); bpc_lib_conf_init(topDir, BPC_HardLinkMax, BPC_PoolV3Enabled, logLevel); bpc_attribCache_init(&acNew, hostName, newBkupNum, shareNameUM, newCompress); snprintf(hostDir, sizeof(hostDir), "%s/pc/%s/%d", topDir, hostName, newBkupNum); bpc_poolRefDeltaFileInit(&DeltaNew, hostDir); bpc_attribCache_setDeltaInfo(&acNew, &DeltaNew); CompressLevel = newCompress; if ( prevBkupNum >= 0 ) { bpc_attribCache_init(&acOld, hostName, prevBkupNum, shareNameUM, prevCompress); snprintf(hostDir, sizeof(hostDir), "%s/pc/%s/%d", topDir, hostName, prevBkupNum); bpc_poolRefDeltaFileInit(&DeltaOld, hostDir); bpc_attribCache_setDeltaInfo(&acOld, &DeltaOld); acOldUsed = 1; } else { acOldUsed = 0; } Stats.InodeCurr = Stats.Inode0 = inode0; LogLevel = logLevel; /* * If attrib_new, write new-style attrib files (<= 4.0.0beta3 uses old-style), which * are 0-length files with the digest encoded in the file name (eg: attrib_md5HexDigest). * We can still read the old-style files, but we upgrade them as we go. */ bpc_attrib_backwardCompat(!attrib_new, !attrib_new); if ( mergeBkupInfo && *mergeBkupInfo ) { /* * Count number of backups to merge: 1 + number of commas. */ int i, bkupCnt = 1; char *p = mergeBkupInfo; bpc_backup_info *bkupList; while ( (p = strchr(p + 1, ',')) ) { bkupCnt++; } p = mergeBkupInfo; if ( !(bkupList = calloc(bkupCnt, sizeof(bpc_backup_info))) ) { bpc_logErrf("bpc_sysCall_init: can't allocate backup list (%d)\n", bkupCnt); return; } for ( i = 0 ; i < bkupCnt ; i++ ) { if ( sscanf(p, "%d/%d/%d", &bkupList[i].num, &bkupList[i].compress, &bkupList[i].version) != 3 ) { bpc_logErrf("bpc_sysCall_init: can't parse bkup info string %s\n", p); return; } if ( !(p = strchr(p, ',')) ) break; p++; } bpc_attribCache_setMergeList(&acNew, bkupList, bkupCnt); } DoneInit = 1; } void bpc_am_generator(int generator, int pid) { if ( generator ) { Stats.InodeCurr = 2 * (Stats.InodeCurr / 2) + 0; bpc_logMsgf("xferPids %d,%d\n", getpid(), pid); } else { Stats.InodeCurr = 2 * (Stats.InodeCurr / 2) + 1; bpc_attribCache_readOnly(&acNew, 1); if ( acOldUsed ) bpc_attribCache_readOnly(&acOld, 1); } bpc_lib_setTmpFileUnique(generator); } int bpc_sysCall_cleanup(void) { fflush(stdout); fflush(stderr); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_cleanup: doneInit = %d\n", DoneInit); if ( !DoneInit ) return 0; if ( am_generator ) { if ( preserve_hard_links ) hard_link_bpc_update_link_count(); bpc_attribCache_flush(&acNew, 1, NULL); if ( acOldUsed ) bpc_attribCache_flush(&acOld, 1, NULL); } if ( LogLevel >= 6 ) { fprintf(stderr, "RefCnt Deltas for new backup\n"); bpc_poolRefDeltaPrint(&DeltaNew); if ( acOldUsed ) { fprintf(stderr, "RefCnt Deltas for prev backup\n"); bpc_poolRefDeltaPrint(&DeltaOld); } } Stats.ErrorCnt += bpc_poolRefDeltaFileFlush(&DeltaNew); if ( acOldUsed ) { Stats.ErrorCnt += bpc_poolRefDeltaFileFlush(&DeltaOld); } fprintf(stderr, "%s: %llu errors, %llu filesExist, %llu sizeExist, %llu sizeExistComp, %llu filesTotal, %llu sizeTotal, %llu filesNew, %llu sizeNew, %llu sizeNewComp, %llu inode\n", am_generator ? "DoneGen" : "Done", (unsigned long long)Stats.ErrorCnt, (unsigned long long)Stats.ExistFileCnt, (unsigned long long)Stats.ExistFileSize, (unsigned long long)Stats.ExistFileCompSize, (unsigned long long)Stats.TotalFileCnt, (unsigned long long)Stats.TotalFileSize, (unsigned long long)Stats.NewFileCnt, (unsigned long long)Stats.NewFileSize, (unsigned long long)Stats.NewFileCompSize, (unsigned long long)Stats.InodeCurr); fflush(stdout); fflush(stderr); return Stats.ErrorCnt; } void bpc_progress_fileDone(void) { static int fileCnt = 0, fileCntNext = 1; fileCnt++; if ( fileCnt < fileCntNext ) return; fileCntNext = fileCnt + 20; fprintf(stderr, "__bpc_progress_fileCnt__ %d\n", fileCnt); } void bpc_sysCall_statusFileSize(unsigned long fileSize) { Stats.TotalFileCnt++; Stats.TotalFileSize += fileSize; bpc_progress_fileDone(); } void bpc_sysCall_setInode0Debug(int inode0, char *hostName, char *shareNameUM, int prevBkupNum, int prevCompress) { Stats.Inode0 = inode0; if ( prevBkupNum >= 0 ) { bpc_attribCache_init(&acOld, hostName, prevBkupNum, shareNameUM, prevCompress); acOldUsed = 1; } } /* * File handling */ typedef struct { int used; int fdNum; int flags; int dirty; int mode; int fdUnusedNext; off_t posn; off_t fileSize; int tmpFd; char *fileName; char *tmpFileName; char *buffer; size_t bufferSize; bpc_digest digest; } FdInfo; static FdInfo Fd[MAX_FD]; /* * We keep a simple integer index free list. This is the head of the free list. * Fd[i].fdUnusedNext points to the next entry on the free list. */ static int FdUnused = -1; /* * Find a spare file descriptor. The integer file descriptors we return * here have no relation to real file descriptors. They are simply handles * that allow us to index into the $io->{fileDesc} array. So long as the * caller uses the returned file descriptor only to call these functions * (ie: not to directly make IO system calls) then we are ok. */ static int bpc_fileDescriptorNew(void) { int i; if ( FdUnused < 0 ) { /* * initialize the free list */ FdUnused = 3; for ( i = FdUnused ; i < MAX_FD ; i++ ) { Fd[i].used = 0; Fd[i].fdNum = i; Fd[i].tmpFd = -1; Fd[i].fdUnusedNext = i + 1; } Fd[MAX_FD-1].fdUnusedNext = -1; } i = FdUnused; if ( i >= 0 ) { FdUnused = Fd[i].fdUnusedNext; return i; } else { bpc_logErrf("bpc_fileDescriptorNew: out of file descriptors\n"); Stats.ErrorCnt++; return -1; } } static void bpc_fileDescFree(FdInfo *fd) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_fileDescFree: fdNum = %d, tmpFd = %d, tmpFileName = %s\n", fd->fdNum, fd->tmpFd, fd->tmpFileName ? fd->tmpFileName : "NULL"); if ( fd->tmpFd >= 0 ) { close(fd->tmpFd); fd->tmpFd = -1; } if ( fd->fileName ) free(fd->fileName); if ( fd->buffer ) { *(void**)fd->buffer = DataBufferFreeList; DataBufferFreeList = fd->buffer; } if ( fd->tmpFileName ) { unlink(fd->tmpFileName); free(fd->tmpFileName); } fd->used = 0; fd->fdUnusedNext = FdUnused; fd->fileName = NULL; fd->buffer = NULL; fd->tmpFileName = NULL; FdUnused = fd->fdNum; } static int TmpFileCnt = 0; static int bpc_fileWriteBuffer(int fdNum, char *buffer, size_t nBytes) { while ( nBytes > 0 ) { ssize_t nWrite = write(fdNum, buffer, nBytes); if ( nWrite < 0 ) { if ( errno == EINTR ) continue; return -1; } buffer += nWrite; nBytes -= nWrite; } return 0; } /* * Create a temporary output file and write the existing data buffer there */ static int bpc_fileSwitchToDisk(bpc_attribCache_info *ac, FdInfo *fd) { char tmpFileName[BPC_MAXPATHLEN]; snprintf(tmpFileName, BPC_MAXPATHLEN, "%s/rsyncTmp.%d.%d.%d", ac->backupTopDir, getpid(), am_generator, TmpFileCnt++); fd->tmpFileName = malloc(strlen(tmpFileName) + 1); if ( !fd->tmpFileName ) { bpc_logErrf("bpc_fileSwitchToDisk: can't allocated %lu bytes for temp file name\n", (unsigned long)strlen(tmpFileName) + 1); Stats.ErrorCnt++; return -1; } strcpy(fd->tmpFileName, tmpFileName); if ( (fd->tmpFd = open(fd->tmpFileName, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0 ) { bpc_logErrf("bpc_fileSwitchToDisk: can't open/create %s for writing\n", fd->tmpFileName); Stats.ErrorCnt++; return -1; } if ( fd->fileSize > 0 && bpc_fileWriteBuffer(fd->tmpFd, fd->buffer, fd->fileSize) ) return -1; if ( lseek(fd->tmpFd, fd->posn, SEEK_SET) != fd->posn ) { bpc_logErrf("bpc_fileSwitchToDisk: unable to seek %s to %lu\n", fd->tmpFileName, (unsigned long)fd->posn); Stats.ErrorCnt++; return -1; } return 0; } /* * Open a file and cache the file handle and information. Returns a pointer * to an FdInfo structure, or NULL on error. * * The file is either stored in memory (fh->buffer) or a regular * uncompressed unbuffered read-write file with handle fh->tmpFd. * * The current seek position is fh->posn. * * If you call fileClose() first, then fileOpen() with $write <= 0, you are * guaranteed to get just the read-only BackupPC::FileZIO handle fh->fhRead * or the in-memory fh->buffer. * * The following flags determine behavior: * O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC, O_APPEND */ static FdInfo *bpc_fileOpen(bpc_attribCache_info *ac, char *fileName, int flags) { bpc_attrib_file *file; int fdNum; FdInfo *fd; file = bpc_attribCache_getFile(&acNew, fileName, 0, 0); if ( !file && !(flags & O_CREAT) ) return NULL; if ( (fdNum = bpc_fileDescriptorNew()) < 0 ) return NULL; fd = &Fd[fdNum]; fd->used = 1; fd->posn = 0; fd->fdNum = fdNum; fd->flags = flags; fd->dirty = 0; fd->fileName = malloc(strlen(fileName) + 1); fd->bufferSize = MAX_BUF_SZ; if ( DataBufferFreeList ) { fd->buffer = DataBufferFreeList; DataBufferFreeList = *(void**)DataBufferFreeList; } else { fd->buffer = malloc(fd->bufferSize * sizeof(fd->buffer[0])); } fd->fileSize = 0; if ( !fd->fileName || !fd->buffer ) { if ( !fd->fileName ) { bpc_logErrf("bpc_fileOpen: fatal error: can't allocate %lu bytes for file %s\n", strlen(fileName) + 1, fileName); } if ( !fd->buffer ) { bpc_logErrf("bpc_fileOpen: fatal error: can't allocate %lu bytes for data buffer\n", MAX_BUF_SZ); } bpc_fileDescFree(fd); return NULL; } strcpy(fd->fileName, fileName); if ( file && !(flags & O_TRUNC) && !(file->isTemp && file->size == 0) ) { char fullPath[BPC_MAXPATHLEN]; bpc_fileZIO_fd fdz; /* * need to read existing file */ if ( file->digest.len > 0 || file->size == 0 ) { /* * all non-empty V4+ files have digests, so use the digest to look in the pool */ if ( file->digest.len > 0 ) { bpc_digest_md52path(fullPath, file->compress, &file->digest); } else { strcpy(fullPath, "/dev/null"); } if ( bpc_fileZIO_open(&fdz, fullPath, 0, file->compress) ) { bpc_logErrf("bpc_fileOpen: can't open pool file %s (from %s, %d, %d)\n", fullPath, fd->fileName, file->compress, file->digest.len); Stats.ErrorCnt++; bpc_fileDescFree(fd); return NULL; } } else { /* * either we failed to read the digest (eg, missing inode), or it's a V3 file - look in the backup directory */ bpc_attribCache_getFullMangledPath(&acNew, fullPath, (char*)fileName, file->backupNum); if ( bpc_fileZIO_open(&fdz, fullPath, 0, file->compress) ) { bpc_logErrf("bpc_fileOpen: can't open file %s (from %s, %d, %d, %d)\n", fullPath, fd->fileName, file->compress, file->digest.len, file->nlinks); Stats.ErrorCnt++; bpc_fileDescFree(fd); return NULL; } } fd->fileSize = bpc_fileZIO_read(&fdz, (uchar*)fd->buffer, fd->bufferSize); if ( fd->fileSize >= (off_t)fd->bufferSize ) { off_t nRead; /* * buffer is full - write to flat disk and then copy the rest of the file */ fd->posn = fd->fileSize; if ( bpc_fileSwitchToDisk(ac, fd) ) { bpc_fileDescFree(fd); return NULL; } while ( (nRead = bpc_fileZIO_read(&fdz, (uchar*)fd->buffer, fd->bufferSize)) > 0 ) { if ( bpc_fileWriteBuffer(fd->tmpFd, fd->buffer, nRead) ) { bpc_logErrf("bpc_fileOpen: bpc_fileWriteBuffer(%d, ..., %lu) failed\n", fd->tmpFd, nRead); bpc_fileDescFree(fd); return NULL; } fd->fileSize += nRead; } } bpc_fileZIO_close(&fdz); } if ( fd->tmpFd >= 0 ) { if ( !(flags & O_APPEND) && lseek(fd->tmpFd, 0, SEEK_SET) != 0 ) { bpc_logErrf("bpc_fileOpen: can't seek to start of file %s\n", fd->tmpFileName); Stats.ErrorCnt++; bpc_fileDescFree(fd); return NULL; } } else { if ( (flags & O_APPEND) ) fd->posn = fd->fileSize; } return fd; } static int bpc_fileWrite(bpc_attribCache_info *ac, FdInfo *fd, char *buf, size_t bufLen) { if ( fd->tmpFd < 0 ) { if ( (size_t)fd->posn + bufLen <= fd->bufferSize ) { if ( fd->posn + (off_t)bufLen > fd->fileSize || memcmp(fd->buffer + fd->posn, buf, bufLen) ) { fd->dirty = 1; memcpy(fd->buffer + fd->posn, buf, bufLen); } fd->posn += bufLen; if ( fd->fileSize < fd->posn ) fd->fileSize = fd->posn; return 0; } /* * We would overflow the buffer, so write to a file instead */ if ( bpc_fileSwitchToDisk(ac, fd) ) return -1; } fd->dirty = 1; return bpc_fileWriteBuffer(fd->tmpFd, buf, bufLen); } static int bpc_fileClose(bpc_attribCache_info *ac, FdInfo *fd, int newType, int newMode, char *fileNameLog) { bpc_attrib_file *file; off_t fileSize = 0; static bpc_poolWrite_info pwInfo; bpc_digest digest; int match; off_t poolFileSize; int errorCnt; file = bpc_attribCache_getFile(&acNew, fd->fileName, 0, 0); if ( file && newType < 0 ) newType = file->type; if ( newType < 0 ) newType = BPC_FTYPE_FILE; if ( file && file->size != fd->fileSize && ((fd->flags & O_WRONLY) || (fd->flags & O_RDWR)) ) { fd->dirty = 1; } if ( !fd->dirty ) { if ( (fd->flags & O_WRONLY) || (fd->flags & O_RDWR) ) { fprintf(stderr, "IOdone: same %s\n", fd->fileName); } bpc_fileDescFree(fd); return 0; } if ( fd->tmpFd < 0 ) { fileSize = fd->fileSize; bpc_poolWrite_open(&pwInfo, ac->compress, NULL); bpc_poolWrite_write(&pwInfo, (uchar*)fd->buffer, fileSize); bpc_poolWrite_close(&pwInfo, &match, &digest, &poolFileSize, &errorCnt); } else { off_t nRead; lseek(fd->tmpFd, 0, SEEK_SET); bpc_poolWrite_open(&pwInfo, ac->compress, NULL); while ( (nRead = read(fd->tmpFd, fd->buffer, fd->bufferSize)) > 0 ) { bpc_poolWrite_write(&pwInfo, (uchar*)fd->buffer, nRead); fileSize += nRead; } bpc_poolWrite_close(&pwInfo, &match, &digest, &poolFileSize, &errorCnt); } Stats.ErrorCnt += errorCnt; if ( match ) { Stats.ExistFileCnt++; if ( newType == BPC_FTYPE_FILE || newType == BPC_FTYPE_SYMLINK ) { Stats.ExistFileSize += fileSize; Stats.ExistFileCompSize += poolFileSize; } } else { Stats.NewFileCnt++; if ( newType == BPC_FTYPE_FILE || newType == BPC_FTYPE_SYMLINK ) { Stats.NewFileSize += fileSize; Stats.NewFileCompSize += poolFileSize; } } if ( file && file->digest.len == digest.len && !memcmp(file->digest.digest, digest.digest, digest.len) && file->size == fileSize ) { /* * File is unchanged */ fprintf(stderr, "IOdone: same %s\n", fd->fileName); bpc_fileDescFree(fd); return 0; } if ( file && !file->isTemp ) { if ( acOldUsed && file->inode < Stats.Inode0 && !bpc_attribCache_getFile(&acOld, fd->fileName, 0, 0) ) { if ( file->nlinks > 0 ) { /* * Only write the inode if it doesn't exist in old; * in that case increase the pool reference count */ if ( bpc_attribCache_setFile(&acOld, fd->fileName, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } else { bpc_attribCache_setFile(&acOld, fd->fileName, file, 0); } } else { /* * The current file is new to this backup and will be replaced below, so reduce * the ref count of the existing (old) file. */ bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, -1); } } else if ( acOldUsed && (!file || !file->isTemp) && !bpc_attribCache_getFile(&acOld, fd->fileName, 0, 0) ) { bpc_attrib_file *oldFile = bpc_attribCache_getFile(&acOld, fd->fileName, 1, 0); oldFile->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, fd->fileName, oldFile, 0); } if ( !file ) { file = bpc_attribCache_getFile(&acNew, fd->fileName, 1, 0); file->inode = Stats.InodeCurr; Stats.InodeCurr += 2; file->nlinks = 0; file->mode = fd->mode; } file->compress = ac->compress; file->digest = digest; if ( newType >= 0 ) file->type = newType; if ( newMode >= 0 ) file->mode = newMode; if ( file->type == BPC_FTYPE_FILE || file->type == BPC_FTYPE_SYMLINK ) { file->size = fileSize; } else { file->size = 0; } if ( !file->isTemp ) bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, 1); bpc_attribCache_setFile(&acNew, fd->fileName, file, 0); fprintf(stderr, "IOdone: %s %s\n", match ? "pool" : "new", fileNameLog ? fileNameLog : fd->fileName); bpc_fileDescFree(fd); return 0; } /* * Read an entire file into the buffer, up until the buffer is full. Returns the number * of bytes read, or -1 on error. */ static off_t bpc_fileReadAll(bpc_attribCache_info *ac, char *fileName, char *buffer, size_t bufferSize) { char fullPath[BPC_MAXPATHLEN]; bpc_attrib_file *file; bpc_fileZIO_fd fd; off_t nRead; if ( !(file = bpc_attribCache_getFile(ac, fileName, 0, 0)) ) return -1; if ( file->digest.len > 0 ) { /* * V4+ pool file */ bpc_digest_md52path(fullPath, file->compress, &file->digest); } else { /* * V3 look in the backup directory */ bpc_attribCache_getFullMangledPath(&acNew, fullPath, (char*)fileName, file->backupNum); } if ( bpc_fileZIO_open(&fd, fullPath, 0, file->compress) ) { bpc_logErrf("bpc_fileReadAll: can't open %s (from %s)\n", fullPath, fileName); Stats.ErrorCnt++; return -1; } nRead = bpc_fileZIO_read(&fd, (uchar*)buffer, bufferSize); bpc_fileZIO_close(&fd); return nRead; } /* * Directory handling */ typedef struct { struct dirent dirent; char *entries; ssize_t entrySize; ssize_t entryIdx; } my_DIR; char *bpc_mktemp(char *template) { char *p = template + strlen(template); int i, xCnt = 0; while ( p > template && p[-1] == 'X' ) { p--; xCnt++; } if ( xCnt == 0 ) return NULL; for ( i = 0 ; i < (1 << (4 * xCnt)) ; i++ ) { sprintf(p, "%0*x", xCnt, i); if ( bpc_attribCache_getFile(&acNew, template, 0, 0) || (acOldUsed && bpc_attribCache_getFile(&acOld, template, 0, 0)) ) { continue; } if ( LogLevel >= 7 ) bpc_logMsgf("bpc_mktemp: returning %s\n", template); return template; } if ( LogLevel >= 7 ) bpc_logMsgf("bpc_mktemp: returning NULL\n"); return NULL; } int bpc_mkstemp(char *template, char *origFileName) { char *p = template + strlen(template); bpc_attrib_file *file, *fileOrig = NULL; int i, xCnt = 0; FdInfo *fd; while ( p > template && p[-1] == 'X' ) { p--; xCnt++; } if ( xCnt == 0 ) return -1; for ( i = 0 ; i < (1 << (4 * xCnt)) ; i++ ) { sprintf(p, "%0*x", xCnt, i); if ( bpc_attribCache_getFile(&acNew, template, 0, 0) || (acOldUsed && bpc_attribCache_getFile(&acOld, template, 0, 0)) ) { continue; } file = bpc_attribCache_getFile(&acNew, template, 1, 0); if ( origFileName && (fileOrig = bpc_attribCache_getFile(&acNew, origFileName, 0, 0)) && fileOrig->type == BPC_FTYPE_FILE ) { /* * We have been told that this temp file is an update of origFileName. * If it exists, we copy all the attributes, including the digest, * which is a cheap way to make the temp file look just like * the orig file. */ if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkstemp: copying attribs from %s to %s\n", origFileName, template); bpc_attrib_fileCopy(file, fileOrig); /* * Make sure the pool file exists; otherwise zero out the digest */ if ( file->digest.len > 0 ) { char poolPath[BPC_MAXPATHLEN]; STRUCT_STAT st; bpc_digest_md52path(poolPath, file->compress, &file->digest); if ( stat(poolPath, &st) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkstemp: %s doesn't exist; ignoring digest for %s\n", poolPath, template); file->digest.len = 0; file->size = 0; } } file->nlinks = 0; } else { /* * No orig file, so create new attributes */ file->type = BPC_FTYPE_FILE; file->mode = 0600; file->compress = CompressLevel; file->inode = Stats.InodeCurr; Stats.InodeCurr += 2; } file->isTemp = 1; bpc_attribCache_setFile(&acNew, template, file, 0); if ( !(fd = bpc_fileOpen(&acNew, template, O_RDWR | O_CREAT)) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkstemp: bpc_fileOpen(%s,...) failed, size = %d, digestLen = %d\n", template, file->size, file->digest.len); return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkstemp: returning %s, fd = %d (size = %d, digestLen = %d)\n", template, fd->fdNum, file->size, file->digest.len); return fd->fdNum; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkstemp: returning -1\n"); return -1; } /* * Confirm that fileName exists, has the indicated size and MD5 file_sum. If so, mimic * mkstemp above by creating a temporary file copy, but don't open it. * * The is used to implement an optimization in receiver.c: if we are receiving file deltas, * we check if the deltas show the file is identical. That avoids opening the file * and copying it to the temp file (which involves a lot of processing given the * compression overhead, and disk IO for large files). */ int bpc_sysCall_checkFileMatch(char *fileName, char *tmpName, struct file_struct *rsyncFile, char *file_sum, off_t fileSize) { bpc_attrib_file *fileOrig, *file; char poolPath[BPC_MAXPATHLEN]; if ( !(fileOrig = bpc_attribCache_getFile(&acNew, fileName, 0, 0)) ) { /* * Hmmm. The file doesn't exist, but we got deltas suggesting the file is * unchanged. So that means the generator found a matching pool file. * Let's try the same thing. */ if ( bpc_sysCall_poolFileCheck(fileName, rsyncFile) || !(fileOrig = bpc_attribCache_getFile(&acNew, fileName, 0, 0)) ) { bpc_logErrf("bpc_sysCall_checkFileMatch(%s): file doesn't exist\n", fileName); return -1; } } if ( fileOrig->size != fileSize || fileOrig->digest.len < MD5_DIGEST_LEN || memcmp(file_sum, fileOrig->digest.digest, MD5_DIGEST_LEN) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_checkFileMatch(%s): size/digest don't match (%lu/%lu, %d, 0x%02x%02x.../0x%02x%02x...\n", fileName, (unsigned long)fileOrig->size, (unsigned long)fileSize, fileOrig->digest.len, fileOrig->digest.digest[0], fileOrig->digest.digest[1], ((unsigned)file_sum[0]) & 0xff, ((unsigned)file_sum[1]) & 0xff); return -1; } /* * make sure the pool file exists */ bpc_digest_md52path(poolPath, CompressLevel, &fileOrig->digest); if ( fileSize != 0 ) { STRUCT_STAT st; if ( stat(poolPath, &st) ) { bpc_logErrf("bpc_sysCall_checkFileMatch(%s): got good match, but pool file %s doesn't exist - rewriting\n", fileName, poolPath); return -1; } if ( st.st_mode & S_IXOTH ) { /* * pool file is marked for deletion - safely unmark it since we are going to use it */ if ( bpc_poolWrite_unmarkPendingDelete(poolPath) ) { bpc_logErrf("bpc_sysCall_checkFileMatch(%s): couldn't unmark pool file %s - rewriting\n", fileName, poolPath); return -1; } } } /* * Now mimic bpc_mkstemp() above */ if ( !get_tmpname(tmpName, fileName, 0) || !bpc_mktemp(tmpName) ) { bpc_logErrf("bpc_sysCall_checkFileMatch(%s): tmp name failed\n", fileName); return -1; } file = bpc_attribCache_getFile(&acNew, tmpName, 1, 0); bpc_attrib_fileCopy(file, fileOrig); file->nlinks = 0; file->isTemp = 1; bpc_attribCache_setFile(&acNew, tmpName, file, 0); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_checkFileMatch(%s): good match, made copy in %s\n", fileName, tmpName); fprintf(stderr, "IOdone: same %s\n", tmpName); return 0; } /* * This is called by the generator-side to see if there is a matching pool * file that can be used for the block checksums. This needs to match * mks_temp above to make sure the same basis file is used by each side. * * If there is a match, we create a temp file entry, which will be replaced * when the receiver does the rename. */ int bpc_sysCall_poolFileCheck(char *fileName, struct file_struct *rsyncFile) { bpc_digest digest; char poolPath[BPC_MAXPATHLEN]; unsigned int ext; int foundPoolFile = 0; if ( protocol_version < 30 || !always_checksum ) return -1; digest.len = MD5_DIGEST_LEN; memcpy(digest.digest, F_SUM(rsyncFile), MD5_DIGEST_LEN); /* * find the first non-empty pool file in the chain */ if ( F_LENGTH(rsyncFile) > 0 ) { for ( ext = 0 ; !foundPoolFile ; ext++ ) { STRUCT_STAT st; bpc_digest_append_ext(&digest, ext); bpc_digest_md52path(poolPath, CompressLevel, &digest); if ( stat(poolPath, &st) ) break; if ( st.st_size == 0 ) continue; if ( st.st_mode & S_IXOTH ) { /* * pool file is marked for deletion - safely unmark it since we going to use it */ if ( bpc_poolWrite_unmarkPendingDelete(poolPath) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_poolFileCheck(%s): couldn't unmark potential match %s\n", fileName, poolPath); continue; } } foundPoolFile = 1; } } else { /* * For an empty file there is no corresponding pool file, so just say it matches */ foundPoolFile = 1; poolPath[0] = '\0'; } if ( foundPoolFile ) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, fileName, 1, 0); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_poolFileCheck(%s): potential match %s (len = %lu)\n", fileName, poolPath, (unsigned long)F_LENGTH(rsyncFile)); file->type = BPC_FTYPE_FILE; file->size = F_LENGTH(rsyncFile); file->mode = 0600; file->inode = Stats.InodeCurr; file->compress = CompressLevel; Stats.InodeCurr += 2; file->digest = digest; file->isTemp = 1; return 0; } else { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_sysCall_poolFileCheck(%s): no pool file at %s\n", fileName, poolPath); return -1; } } /* * Print file transfer status for retry and fail */ void bpc_sysCall_printfileStatus(char *fileName, char *status) { fprintf(stderr, "IOdone: %s %s\n", status, fileName); } /* * TODO: do target if symlink? */ int bpc_lchmod(const char *fileName, mode_t mode) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lchmod(%s, 0%o)\n", fileName, mode); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { errno = ENOENT; return -1; } if ( file->mode == mode ) return 0; if ( acOldUsed && !file->isTemp && file->inode < Stats.Inode0 && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1) ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } file->mode = mode; bpc_attribCache_setFile(&acNew, (char*)fileName, file, 0); return 0; } int bpc_fchmod(int filedes, mode_t mode) { if ( filedes < 0 || filedes >= MAX_FD || !Fd[filedes].used ) { errno = EBADF; return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_fchmod(%d (%s), 0%o)\n", filedes, Fd[filedes].fileName, mode); return bpc_lchmod(Fd[filedes].fileName, mode); } int bpc_unlink(const char *fileName) { bpc_attrib_file *file; int deleteInode = 0; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_unlink(%s)\n", fileName); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { /* * See if the file is there, but it's the inode that is missing */ if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 1)) ) { errno = ENOENT; return -1; } /* * Hmmm, this shouldn't happen (file entry is present, but inode wasn't found) */ if ( LogLevel >= 3 ) bpc_logMsgf("bpc_unlink(%s): type %d, size %lu, nlinks %u; inode %u missing; setting nlinks to 0\n", fileName, file->type, file->size, file->nlinks, file->inode); file->nlinks = 0; } if ( file->type == BPC_FTYPE_DIR ) { errno = EISDIR; return -1; } if ( file->nlinks > 0 ) { if ( acOldUsed && !file->isTemp && !bpc_attribCache_getInode(&acOld, file->inode, 0) ) { /* * copy the inode to old */ if ( LogLevel >= 6 ) bpc_logMsgf("bpc_unlink: setting inode in old (inode = %lu, nlinks = %lu)\n", (unsigned long)file->inode, (unsigned long)file->nlinks); bpc_attribCache_setInode(&acOld, file->inode, file); bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } /* * If this file is older than this backup, then move it to old * (don't update the inode, since we know it exists after we just * copied it). */ if ( file && file->inode < Stats.Inode0 && acOldUsed && !file->isTemp && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { if ( LogLevel >= 6 ) bpc_logMsgf("bpc_unlink: setting %s in old (inode = %lu, nlinks = %lu)\n", fileName, (unsigned long)file->inode, (unsigned long)file->nlinks); bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1); } /* * Now reduce the number of links and update the inode * ref count is handled above */ file->nlinks--; if ( file->nlinks <= 0 ) { deleteInode = 1; bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, -1); } else { if ( LogLevel >= 6 ) bpc_logMsgf("bpc_unlink: updating inode in new (inode = %lu, nlinks = %lu)\n", (unsigned long)file->inode, (unsigned long)file->nlinks); bpc_attribCache_setInode(&acNew, file->inode, file); } } else { /* * If this file is older than this backup, then move it * to old. Otherwise just remove it. */ if ( !file->isTemp && file->inode < Stats.Inode0 && acOldUsed ) { bpc_attrib_file *fileOld = bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0); if ( !fileOld ) { if ( LogLevel >= 6 ) bpc_logMsgf("bpc_unlink: setting %s in old (inode = %lu, nlinks = %lu)\n", fileName, (unsigned long)file->inode, (unsigned long)file->nlinks); bpc_attribCache_setFile(&acOld, (char*)fileName, file, 0); bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, -1); } } else if ( !file->isTemp ) { if ( file->digest.len > 0 ) { bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, -1); } } } if ( deleteInode ) { if ( LogLevel >= 6 ) bpc_logMsgf("bpc_unlink: deleting inode in new (inode = %lu)\n", (unsigned long)file->inode); bpc_attribCache_deleteInode(&acNew, file->inode); } bpc_attribCache_deleteFile(&acNew, (char*)fileName); return 0; } int bpc_lstat(const char *fileName, struct stat *buf) { bpc_attrib_file *file; dev_t rdev = 0; /* * must be in order of BPC_FTYPE_* definitions */ static uint fmode[] = { S_IFREG, /* BPC_FTYPE_FILE */ S_IFREG, /* BPC_FTYPE_HARDLINK */ S_IFLNK, /* BPC_FTYPE_SYMLINK */ S_IFCHR, /* BPC_FTYPE_CHARDEV */ S_IFBLK, /* BPC_FTYPE_BLOCKDEV */ S_IFDIR, /* BPC_FTYPE_DIR */ S_IFIFO, /* BPC_FTYPE_FIFO */ S_IFSOCK, /* BPC_FTYPE_SOCKET */ S_IFREG, /* BPC_FTYPE_UNKNOWN */ S_IFREG, /* BPC_FTYPE_DELETED */ }; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lstat(%s)\n", fileName); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { /* * See if the file is there, but it's the inode that is missing */ if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 1)) ) { errno = ENOENT; return -1; } /* * Hmmm, this shouldn't happen (file entry is present, but inode wasn't found) * This entry won't have a digest, so we won't be able to open the file. */ if ( LogLevel >= 3 ) bpc_logMsgf("bpc_lstat(%s): type %d, size %lu, nlinks %u; inode %u missing; setting nlinks to 0\n", fileName, file->type, file->size, file->nlinks, file->inode); file->nlinks = 0; } if ( file->type == BPC_FTYPE_DELETED || file->type == BPC_FTYPE_UNKNOWN || file->type >= BPC_FTYPE_INVALID ) { errno = ENOENT; return -1; } if ( file->type == BPC_FTYPE_CHARDEV || file->type == BPC_FTYPE_BLOCKDEV ) { char data[BPC_MAXPATHLEN]; int minor = 0, major = 0; int nRead = bpc_fileReadAll(&acNew, (char*)fileName, data, sizeof(data) - 1); rdev = 1; if ( nRead >= 0 ) { data[nRead] = '\0'; if ( sscanf(data, "%d,%d", &major, &minor) == 2 ) { rdev = MAKEDEV(major, minor); } } } buf->st_dev = 1; buf->st_ino = file->inode; buf->st_mode = file->mode; buf->st_nlink = file->nlinks == 0 ? 1 : file->nlinks; buf->st_uid = file->uid; buf->st_gid = file->gid; buf->st_rdev = rdev; buf->st_atime = file->mtime; buf->st_mtime = file->mtime; buf->st_ctime = file->mtime; buf->st_size = file->size; buf->st_blocks = (file->size + 1023) / 1024; buf->st_blksize = 1024; if ( file->type < sizeof(fmode) / sizeof(fmode[0]) ) { buf->st_mode |= fmode[file->type]; } return 0; } int bpc_fstat(int filedes, struct stat *buf) { int ret; if ( filedes < 0 || filedes >= MAX_FD || !Fd[filedes].used ) { errno = EBADF; return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_fstat(%d (%s))\n", filedes, Fd[filedes].fileName); ret = bpc_lstat(Fd[filedes].fileName, buf); /* * TODO: needed?? Based on the current write file update the size... */ return ret; } int bpc_stat(const char *fileName, struct stat *buf) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_stat(%s)\n", fileName); if ( (file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) && file->type == BPC_FTYPE_SYMLINK ) { char targetName[BPC_MAXPATHLEN]; int nRead = bpc_fileReadAll(&acNew, (char*)fileName, targetName, sizeof(targetName) - 1); /* * TODO: combine fileName and targetName if targetName is relative * TODO: what happens if $targetName is a symlink? */ if ( nRead <= 0 ) { errno = ENOENT; return -1; } targetName[nRead] = '\0'; return bpc_lstat(targetName, buf); } else { return bpc_lstat(fileName, buf); } } int bpc_file_checksum(char *fileName, char *sum, int checksum_len) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0); char poolPath[BPC_MAXPATHLEN]; STRUCT_STAT st; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_file_checksum(%s)\n", fileName); if ( !file || file->digest.len < checksum_len ) return -2; /* * check the pool file actually exists before returning the digest. */ bpc_digest_md52path(poolPath, file->compress, &file->digest); if ( stat(poolPath, &st) ) return -1; if ( st.st_mode & S_IXOTH ) { /* * pool file is marked for deletion - safely unmark it since we are using it */ if ( bpc_poolWrite_unmarkPendingDelete(poolPath) ) { bpc_logErrf("bpc_file_checksum(%s): couldn't unmark pool file %s - returning no match\n", fileName, poolPath); return -1; } } memcpy(sum, file->digest.digest, checksum_len); return 0; } /* * the link contents (ie: target) are kept in the original client * charset (ie: not converted to utf8). */ int bpc_symlink(const char *fileName, const char *symName) { bpc_attrib_file *file; FdInfo *fd; int ret = 0; char logText[2 * BPC_MAXPATHLEN + 32]; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_symlink(%s, %s)\n", fileName, symName); /* * it's an error if symname exists */ if ( (file = bpc_attribCache_getFile(&acNew, (char*)symName, 0, 0)) ) { errno = EEXIST; return -1; } /* * add delete attribute to old if nothing is in old */ if ( acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)symName, 0, 0) ) { file = bpc_attribCache_getFile(&acOld, (char*)symName, 1, 0); file->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, (char*)symName, file, 0); } if ( !(fd = bpc_fileOpen(&acNew, (char*)symName, O_WRONLY | O_CREAT | O_TRUNC)) ) { bpc_logErrf("bpc_symlink: open/create of %s failed\n", symName); Stats.ErrorCnt++; return -1; } if ( bpc_fileWrite(&acNew, fd, (char*)fileName, strlen(fileName)) ) { bpc_logErrf("bpc_symlink: write failed\n"); ret = -1; Stats.ErrorCnt++; } snprintf(logText, sizeof(logText), "%s -> %s", symName, fileName); if ( bpc_fileClose(&acNew, fd, BPC_FTYPE_SYMLINK, 0777, logText) ) { bpc_logErrf("bpc_symlink: close failed\n"); ret = -1; Stats.ErrorCnt++; } return ret; } int bpc_link(const char *targetName, const char *linkName) { bpc_attrib_file *file; char poolPath[BPC_MAXPATHLEN]; STRUCT_STAT st; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_link(%s, %s)\n", targetName, linkName); if ( bpc_attribCache_getFile(&acNew, (char*)linkName, 0, 0) ) { errno = EEXIST; return -1; } /* * check if the target exists. hardlinks to directories are not supported. */ if ( !(file = bpc_attribCache_getFile(&acNew, (char*)targetName, 0, 0)) || file->type == BPC_FTYPE_DIR ) { errno = ENOENT; return -1; } /* * reference counts are unchanged in each of these cases (first link and additional link) */ if ( file->nlinks == 0 ) { /* * first save the original target file (since it a regular file with no links) */ if ( acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)targetName, 0, 0) ) { bpc_attribCache_setFile(&acOld, (char*)targetName, file, 0); bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } /* * promote the target to a hardlink; both files are identical */ file->nlinks = 2; bpc_attribCache_setFile(&acNew, (char*)targetName, file, 0); bpc_attribCache_setFile(&acNew, (char*)linkName, file, 0); } else { /* * save the inode away since the link count is going to increase */ if ( acOldUsed && !bpc_attribCache_getInode(&acOld, file->inode, 0) ) { bpc_attribCache_setInode(&acOld, file->inode, file); bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } /* * reference count is unchanged since the inode already points at the pool file */ file->nlinks++; bpc_attribCache_setFile(&acNew, (char*)linkName, file, 0); } Stats.ExistFileCnt++; Stats.ExistFileSize += file->size; bpc_digest_md52path(poolPath, file->compress, &file->digest); if ( !stat(poolPath, &st) ) Stats.ExistFileCompSize += st.st_size; if ( acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)linkName, 0, 0) ) { file = bpc_attribCache_getFile(&acOld, (char*)linkName, 1, 0); file->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, (char*)linkName, file, 0); } fprintf(stderr, "IOdone: new %s => %s\n", linkName, targetName); return 0; } /* * check and set the number of links on a file */ int bpc_nlinkSet(const char *targetName, uint32 nlinks) { bpc_attrib_file *file; /* * check if the target exists. */ if ( !(file = bpc_attribCache_getFile(&acNew, (char*)targetName, 0, 0)) ) { errno = ENOENT; return -1; } if ( file->nlinks == nlinks ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_nlinkSet(%s, %u) -> no change\n", targetName, nlinks); return 0; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_nlinkSet(%s, %u) -> was %u\n", targetName, nlinks, file->nlinks); file->nlinks = nlinks;; bpc_attribCache_setFile(&acNew, (char*)targetName, file, 0); return 0; } #ifdef HAVE_LUTIMES int bpc_lutimes(const char *fileName, struct timeval *t) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lutimes(%s)\n", fileName); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { errno = ENOENT; return -1; } if ( file->mtime == t[1].tv_sec ) return 0; if ( file->inode < Stats.Inode0 && acOldUsed && !file->isTemp && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } file->mtime = t[1].tv_sec; bpc_attribCache_setFile(&acNew, (char*)fileName, file, 0); return 0; } #endif #ifdef HAVE_UTIMES int bpc_utimes(const char *fileName, struct timeval *t) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_utimes(%s)\n", fileName); if ( (file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) && file->type == BPC_FTYPE_SYMLINK ) { char targetName[BPC_MAXPATHLEN]; int nRead = bpc_fileReadAll(&acNew, (char*)fileName, targetName, sizeof(targetName) - 1); /* * TODO: combine fileName and targetName if targetName is relative * TODO: what happens if $targetName is a symlink? */ if ( nRead <= 0 ) { errno = ENOENT; return -1; } targetName[nRead] = '\0'; return bpc_lutimes(targetName, t); } else { return bpc_lutimes(fileName, t); } } #endif int bpc_lutime(const char *fileName, time_t mtime) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lutime(%s)\n", fileName); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { errno = ENOENT; return -1; } if ( file->mtime == mtime ) return 0; if ( file->inode < Stats.Inode0 && acOldUsed && !file->isTemp && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } file->mtime = mtime; bpc_attribCache_setFile(&acNew, (char*)fileName, file, 0); return 0; } int bpc_utime(const char *fileName, time_t mtime) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_utime(%s)\n", fileName); if ( (file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) && file->type == BPC_FTYPE_SYMLINK ) { char targetName[BPC_MAXPATHLEN]; int nRead = bpc_fileReadAll(&acNew, (char*)fileName, targetName, sizeof(targetName) - 1); /* * TODO: combine fileName and targetName if targetName is relative * TODO: what happens if $targetName is a symlink? */ if ( nRead <= 0 ) { errno = ENOENT; return -1; } targetName[nRead] = '\0'; return bpc_lutime(targetName, mtime); } else { return bpc_lutime(fileName, mtime); } } int bpc_lchown(const char *fileName, uid_t uid, gid_t gid) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lchown(%s, %lu, %lu)\n", fileName, (unsigned long)uid, (unsigned long)gid); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { errno = ENOENT; return -1; } if ( file->uid == uid && file->gid == gid ) return 0; if ( file->inode < Stats.Inode0 && acOldUsed && !file->isTemp && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } file->uid = uid; file->gid = gid; bpc_attribCache_setFile(&acNew, (char*)fileName, file, 0); return 0; } int bpc_rename(const char *oldName, const char *newName) { bpc_attrib_file *file, *fileNew; int oldIsTemp, fileAttrChanged = 0; if ( !(file = bpc_attribCache_getFile(&acNew, (char*)oldName, 0, 0)) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_rename: %s doesn't exist\n", oldName); errno = ENOENT; return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_rename(%s, %s); oldIsTemp = %d\n", oldName, newName, file->isTemp); if ( !am_generator ) { /* * We don't do renames on the receiver, since it's too hard to keep attribute updates on * both the generator and receiver sycnhronized. Send the attributes to the generator so * it can do the rename. */ static xbuf rename_msg = EMPTY_XBUF; char *bufP, *bufPnew; uint32 oldLen = strlen(oldName) + 1, newLen = strlen(newName) + 1; if ( !rename_msg.size ) { alloc_xbuf(&rename_msg, 4096); } if ( rename_msg.size < 2 * sizeof(uint32) + oldLen + newLen + 1024 ) { realloc_xbuf(&rename_msg, 2 * sizeof(uint32) + oldLen + newLen + 1024); } bufP = rename_msg.buf; SIVAL(bufP, 0, oldLen); bufP += sizeof(uint32); SIVAL(bufP, 0, newLen); bufP += sizeof(uint32); SIVAL(bufP, 0, file->isTemp); bufP += sizeof(uint32); memcpy(bufP, oldName, oldLen); bufP += oldLen; memcpy(bufP, newName, newLen); bufP += newLen; bufPnew = (char*)bpc_attrib_file2buf(file, (uchar*)bufP, (uchar*)rename_msg.buf + rename_msg.size); if ( bufPnew > rename_msg.buf + rename_msg.size ) { ssize_t used = bufP - rename_msg.buf; realloc_xbuf(&rename_msg, (bufPnew - rename_msg.buf) + 4096); bufPnew = (char*)bpc_attrib_file2buf(file, (uchar*)rename_msg.buf + used, (uchar*)rename_msg.buf + rename_msg.size); } if ( LogLevel >= 6 ) bpc_logMsgf("Sending rename request (len=%d)\n", bufPnew - rename_msg.buf); send_msg(MSG_RENAME, rename_msg.buf, bufPnew - rename_msg.buf, 0); bpc_attribCache_setFile(&acNew, (char*)newName, file, 0); bpc_attribCache_deleteFile(&acNew, (char*)oldName); return 0; } oldIsTemp = file->isTemp; file->isTemp = 0; if ( (fileNew = bpc_attribCache_getFile(&acNew, (char*)newName, 0, 0)) ) { /* * If fileNew is a temporary file, just delete it */ if ( fileNew->isTemp ) { bpc_attribCache_deleteFile(&acNew, (char*)newName); fileNew = NULL; } else { /* * If newName exists, and has different attributes, then we unlink the file. */ if ( fileNew->nlinks > 0 ) { /* * We are updating a file with hardlinks. unlink() will break the existing hardlink. * Give the oldName a new inode number, so that the hardlink will be re-established later * if the files are still meant to be linked. */ file->inode = Stats.InodeCurr; Stats.InodeCurr += 2; } if ( (fileAttrChanged = bpc_attrib_fileCompare(file, fileNew)) ) { if ( bpc_unlink(newName) ) return -1; } } } if ( file->type == BPC_FTYPE_DIR ) { char path[BPC_MAXPATHLEN], pathOld[BPC_MAXPATHLEN]; bpc_attribCache_getFullMangledPath(&acNew, path, (char*)newName, file->backupNum); bpc_attribCache_getFullMangledPath(&acNew, pathOld, (char*)oldName, file->backupNum); if ( rename(pathOld, path) ) { bpc_logErrf("bpc_rename: directory rename %s -> %s failed\n", pathOld, path); errno = EACCES; return -1; } } if ( acOldUsed ) { if ( !oldIsTemp && !bpc_attribCache_getFile(&acOld, (char*)oldName, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)oldName, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } if ( !fileNew && !bpc_attribCache_getFile(&acOld, (char*)newName, 0, 0) ) { bpc_attrib_file *fileOld = bpc_attribCache_getFile(&acOld, (char*)newName, 1, 0); fileOld->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, (char*)newName, fileOld, 0); } } if ( !fileNew || fileAttrChanged ) { if ( oldIsTemp ) { bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, 1); } bpc_attribCache_setFile(&acNew, (char*)newName, file, 0); } bpc_attribCache_deleteFile(&acNew, (char*)oldName); fprintf(stderr, "IOrename: %lu %s%s\n", (unsigned long)strlen(oldName), oldName, newName); return 0; } int bpc_rename_request(char *oldName, char *newName, uint32 isTemp, char *bufP, char *bufEnd) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)oldName, 1, 0); if ( (bufP = (char*)bpc_attrib_buf2fileFull(file, (uchar*)bufP, (uchar*)bufEnd)) != bufEnd ) { bpc_logErrf("bpc_rename_request(%s,%s) got to %p vs end = %p\n", oldName, newName, bufP, bufEnd); } file->isTemp = isTemp; return bpc_rename(oldName, newName); } int bpc_mknod(const char *fileName, mode_t mode, dev_t dev) { bpc_attrib_file *file; int type; int ret = 0; FdInfo *fd; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mknod(%s, 0%o, %lu)\n", fileName, mode, (unsigned long)dev); if ( (file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) ) { errno = EEXIST; return -1; } if ( acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)fileName, 0, 0) ) { file = bpc_attribCache_getFile(&acOld, (char*)fileName, 1, 0); file->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, (char*)fileName, file, 0); } type = BPC_FTYPE_FILE; if ( (mode & S_IFMT) == S_IFIFO ) type = BPC_FTYPE_FIFO; if ( (mode & S_IFMT) == S_IFBLK ) type = BPC_FTYPE_BLOCKDEV; if ( (mode & S_IFMT) == S_IFCHR ) type = BPC_FTYPE_CHARDEV; if ( (mode & S_IFMT) == S_IFSOCK ) type = BPC_FTYPE_SOCKET; if ( type == BPC_FTYPE_BLOCKDEV || type == BPC_FTYPE_CHARDEV ) { char data[BPC_MAXPATHLEN]; if ( !(fd = bpc_fileOpen(&acNew, (char*)fileName, O_WRONLY | O_CREAT | O_TRUNC)) ) { bpc_logErrf("bpc_mknod: open/create of %s failed\n", fileName); Stats.ErrorCnt++; return -1; } snprintf(data, sizeof(data), "%lu,%lu", (unsigned long)major(dev), (unsigned long)minor(dev)); if ( bpc_fileWrite(&acNew, fd, data, strlen(data)) ) { bpc_logErrf("bpc_mknod: write failed\n"); ret = -1; Stats.ErrorCnt++; } if ( bpc_fileClose(&acNew, fd, type, mode & ~S_IFMT, (char*)fileName) ) { bpc_logErrf("bpc_mknod: close failed\n"); ret = -1; Stats.ErrorCnt++; } } else { /* * empty file - just write attributes */ file = bpc_attribCache_getFile(&acNew, (char*)fileName, 1, 0); file->type = type; file->mode = mode & ~S_IFMT; file->inode = Stats.InodeCurr; file->size = 0; Stats.InodeCurr += 2; bpc_attribCache_setFile(&acNew, (char*)fileName, file, 0); fprintf(stderr, "IOdone: new %s\n", fileName); } return ret; } int bpc_open(const char *fileName, int flags, mode_t mode) { bpc_attrib_file *file; FdInfo *fd; /* * handle a special case of opening a directory. If a directory * is being replaced by a file, the generator has removed the * directory already, but we (ie: the receiver) don't know * that yet. */ if ( !am_generator && (file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0)) && file->type == BPC_FTYPE_DIR ) { if ( acOldUsed ) bpc_attribCache_setFile(&acOld, (char*)fileName, file, 1); bpc_attribCache_deleteFile(&acNew, (char*)fileName); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_open(%s, 0x%x, 0%o) opening directory -> -1\n", fileName, flags, mode); return -1; } if ( !(fd = bpc_fileOpen(&acNew, (char*)fileName, flags)) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_open(%s, 0x%x, 0%o) -> -1\n", fileName, flags, mode); return -1; } fd->mode = mode; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_open(%s, 0x%x, 0%o) -> %d\n", fileName, flags, mode, fd->fdNum); return fd->fdNum; } int bpc_close(int fdNum) { if ( fdNum < 0 || fdNum >= MAX_FD || !Fd[fdNum].used ) { errno = EBADF; return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_close(%d (%s))\n", fdNum, Fd[fdNum].fileName); return bpc_fileClose(&acNew, &Fd[fdNum], -1, -1, NULL); } off_t bpc_lseek(int fdNum, off_t offset, int whence) { FdInfo *fd; if ( fdNum < 0 || fdNum >= MAX_FD || !Fd[fdNum].used ) { errno = EBADF; return -1; } fd = &Fd[fdNum]; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lseek(%d (%s), %lu, %d)\n", fdNum, fd->fileName, offset, whence); if ( fd->tmpFd < 0 ) { off_t newPosn = -1; if ( whence == SEEK_SET ) newPosn = offset; else if ( whence == SEEK_CUR ) newPosn = fd->posn + offset; else if ( whence == SEEK_END ) newPosn = fd->fileSize + offset; if ( newPosn < 0 ) { errno = EINVAL; return -1; } if ( (size_t)newPosn < fd->bufferSize ) { fd->posn = newPosn; return fd->posn; } /* * We need to seek off the end of our in-memory buffer. * Switch to a file instead. */ if ( bpc_fileSwitchToDisk(&acNew, fd) ) return -1; } return lseek(fd->tmpFd, offset, whence); } off_t bpc_ftruncate(int fdNum, off_t length) { FdInfo *fd; if ( fdNum < 0 || fdNum >= MAX_FD || !Fd[fdNum].used ) { errno = EBADF; return -1; } fd = &Fd[fdNum]; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_ftruncate(%d (%s), %lu)\n", fdNum, fd->fileName, length); if ( fd->tmpFd < 0 ) { if ( length < 0 ) { errno = EINVAL; return -1; } if ( length == fd->fileSize ) { return 0; } if ( (size_t)length < fd->bufferSize ) { fd->dirty = 1; fd->fileSize = length; if ( fd->posn > fd->fileSize ) fd->posn = fd->fileSize; return 0; } /* * We need to make the file larger than the in-memory buffer. * Switch to a file instead. */ if ( bpc_fileSwitchToDisk(&acNew, fd) ) return -1; } fd->dirty = 1; return ftruncate(fd->tmpFd, length); } ssize_t bpc_read(int fdNum, void *buf, size_t readSize) { FdInfo *fd; if ( fdNum < 0 || fdNum >= MAX_FD || !Fd[fdNum].used ) { errno = EBADF; return -1; } fd = &Fd[fdNum]; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_read(%d (%s), buf, %lu) tmpFd = %d\n", fdNum, fd->fileName, readSize, fd->tmpFd); if ( fd->tmpFd < 0 ) { if ( fd->posn >= fd->fileSize || (size_t)fd->posn >= fd->bufferSize ) { bpc_logMsgf("bpc_read: read past EOF; readSize = %lu, posn = %lu, fileSize = %lu, bufferSize = %lu\n", readSize, fd->posn, fd->fileSize, fd->bufferSize); return 0; } if ( readSize > (size_t)fd->fileSize - fd->posn ) readSize = fd->fileSize - fd->posn; if ( readSize > (size_t)fd->bufferSize - fd->posn ) readSize = fd->bufferSize - fd->posn; memcpy(buf, fd->buffer + fd->posn, readSize); fd->posn += readSize; return readSize; } else { return read(fd->tmpFd, buf, readSize); } } ssize_t bpc_write(int fdNum, const void *buf, size_t writeSize) { FdInfo *fd; if ( fdNum < 0 || fdNum >= MAX_FD || !Fd[fdNum].used ) { errno = EBADF; return -1; } fd = &Fd[fdNum]; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_write(%d (%s), buf, %lu)\n", fdNum, fd->fileName, writeSize); if ( bpc_fileWrite(&acNew, fd, (char*)buf, writeSize) ) return -1; return writeSize; } ssize_t bpc_readlink(const char *fileName, char *buffer, size_t bufferSize) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_readlink(%s, buf, %lu)\n", fileName, bufferSize); return bpc_fileReadAll(&acNew, (char*)fileName, buffer, bufferSize); } int bpc_access(const char *fileName, int mode) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)fileName, 0, 0); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_access(%s, %d) -> %d\n", fileName, mode, file ? 0 : -1); if ( !file ) { errno = ENOENT; return -1; } else { return 0; } } void bpc_tmpNameFlagSet(const char *tmpName) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)tmpName, 0, 0); if ( file && !file->isTemp ) { file->isTemp = 1; if ( file->digest.len > 0 ) { bpc_poolRefDeltaUpdate(&DeltaNew, file->compress, &file->digest, -1); } } } int bpc_chdir(const char *dirName) { bpc_attrib_file *file; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_chdir(%s)\n", dirName); if ( !(file = bpc_attribCache_getFile(&acNew, (char*)dirName, 0, 0)) || file->type != BPC_FTYPE_DIR ) { errno = ENOENT; return -1; } bpc_attribCache_setCurrentDirectory(&acNew, (char*)dirName); if ( acOldUsed ) bpc_attribCache_setCurrentDirectory(&acOld, (char*)dirName); return 0; } int bpc_mkdir(const char *dirName, mode_t mode) { char path[BPC_MAXPATHLEN]; bpc_attrib_file *file; int ret; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_mkdir(%s, 0%o)\n", dirName, mode); bpc_attribCache_getFullMangledPath(&acNew, path, (char*)dirName, -1); if ( bpc_attribCache_getFile(&acNew, (char*)dirName, 0, 0) ) { errno = EEXIST; return -1; } if ( acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)dirName, 0, 0) ) { file = bpc_attribCache_getFile(&acOld, (char*)dirName, 1, 0); file->type = BPC_FTYPE_DELETED; bpc_attribCache_setFile(&acOld, (char*)dirName, file, 0); } if ( (ret = bpc_path_create(path)) ) return ret; file = bpc_attribCache_getFile(&acNew, (char*)dirName, 1, 0); file->type = BPC_FTYPE_DIR; file->mode = mode; file->inode = Stats.InodeCurr; Stats.InodeCurr += 2; bpc_attribCache_setFile(&acNew, (char*)dirName, file, 0); if ( !*dirName ) { fprintf(stderr, "IOdone: new .\n"); } else { fprintf(stderr, "IOdone: new %s\n", dirName); } return 0; } int bpc_rmdir(const char *dirName) { char path[BPC_MAXPATHLEN]; bpc_attrib_file *file; STRUCT_STAT st; int statOk, cnt; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_rmdir(%s)\n", dirName); file = bpc_attribCache_getFile(&acNew, (char*)dirName, 0, 0); bpc_attribCache_getFullMangledPath(&acNew, path, (char*)dirName, file->backupNum); statOk = !stat(path, &st); if ( (!file || file->type != BPC_FTYPE_DIR) && (!statOk || !S_ISDIR(st.st_mode)) ) { errno = ENOENT; return -1; } if ( (cnt = bpc_attribCache_getDirEntryCnt(&acNew, (char*)dirName)) > 0 ) { errno = ENOTEMPTY; return -1; } /* * Remove the directory (and update reference counts). We need * to first flush the attrib cache below this directory. * If this directory is older than this backup, then move the * attributes to old. * * TODO: is dirName in the right charset? */ bpc_attribCache_flush(&acNew, 0, (char*)dirName); if ( statOk ) bpc_path_remove(&DeltaNew, path, acNew.compress); if ( file && file->inode < Stats.Inode0 && acOldUsed && !bpc_attribCache_getFile(&acOld, (char*)dirName, 0, 0) ) { bpc_attribCache_setFile(&acOld, (char*)dirName, file, 0); } bpc_attribCache_deleteFile(&acNew, (char*)dirName); return 0; } DIR *bpc_opendir(const char *path) { my_DIR *d; ssize_t entrySize; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_opendir(%s)\n", path); /* * Get the total number of bytes needed to store all the file names and inode numbers */ if ( (entrySize = bpc_attribCache_getDirEntries(&acNew, (char*)path, NULL, 0)) < 0 ) return NULL; if ( !(d = calloc(1, sizeof(my_DIR))) ) return NULL; if ( !(d->entries = malloc(entrySize)) ) { free(d); return NULL; } /* * Now populate entries with all the file names, each NULL terminated, followed by the inode number. */ d->entrySize = entrySize; if ( bpc_attribCache_getDirEntries(&acNew, (char*)path, d->entries, d->entrySize) != d->entrySize ) { free(d); free(d->entries); return NULL; } d->entryIdx = 0; return (DIR*)d; } struct dirent *bpc_readdir(DIR *dir) { my_DIR *d = (my_DIR*)dir; if ( d->entryIdx >= d->entrySize ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_readdir -> NULL\n"); return NULL; } strncpy(d->dirent.d_name, d->entries + d->entryIdx, sizeof(d->dirent.d_name)); d->dirent.d_name[sizeof(d->dirent.d_name)-1] = '\0'; d->entryIdx += strlen(d->entries + d->entryIdx) + 1; memcpy(&d->dirent.d_ino, d->entries + d->entryIdx, sizeof(ino_t)); d->entryIdx += sizeof(ino_t); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_readdir -> %s\n", d->dirent.d_name); return &d->dirent; } int bpc_closedir(DIR *dir) { my_DIR *d = (my_DIR*)dir; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_closedir()\n"); if ( d->entries) free(d->entries); free(d); return 0; } /* * xattr handling */ ssize_t bpc_lgetxattr(const char *path, const char *name, void *value, size_t size) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)path, 0, 0); bpc_attrib_xattr *xattr; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lgetxattr(%s, %s)\n", path, name); if ( !file ) { errno = ENOENT; return -1; } if ( !(xattr = bpc_attrib_xattrGet(file, (char*)name, strlen(name) + 1, 0)) ) { errno = ENOENT; return -1; } if ( !value ) return xattr->valueLen; if ( xattr->valueLen <= size ) { memcpy(value, xattr->value, xattr->valueLen); return xattr->valueLen; } else { memcpy(value, xattr->value, size); return size; } } ssize_t bpc_fgetxattr(int filedes, const char *name, void *value, size_t size) { if ( filedes < 0 || filedes >= MAX_FD || !Fd[filedes].used ) { errno = EBADF; return -1; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_fgetxattr(%d (%s), %s)\n", filedes, Fd[filedes].fileName, name); return bpc_lgetxattr(Fd[filedes].fileName, name, value, size); } int bpc_lsetxattr(const char *path, const char *name, const void *value, size_t size, UNUSED(int flags)) { int ret; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lsetxattr(%s, %s)\n", path, name); bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)path, 0, 0); bpc_attrib_xattr *xattr; if ( !file ) { errno = ENOENT; return -1; } /* * Check if the attribute is unchanged (we can't just call bpc_attribCache_setFile(), * since it updates in place, meaning we then don't have the original version). */ if ( (xattr = bpc_attrib_xattrGet(file, (char*)name, strlen(name) + 1, 0)) ) { if ( xattr->valueLen == size && !memcmp(xattr->value, value, xattr->valueLen) ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lsetxattr(%s, %s) unchanged\n", path, name); return 0; } } /* * Save away the attributes in old if not recently set and not present already */ if ( acOldUsed && !file->isTemp && file->inode < Stats.Inode0 && !bpc_attribCache_getFile(&acOld, (char*)path, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)path, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } /* * now set the new attribute value */ if ( (ret = bpc_attrib_xattrSetValue(file, (char*)name, strlen(name) + 1, (void*)value, size)) < 0 ) { if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lsetxattr(%s, %s) -> return %d\n", path, name, ret); return ret; } if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lsetxattr(%s, %s) -> return %d\n", path, name, 0); return 0; } int bpc_lremovexattr(const char *path, const char *name) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)path, 0, 0); bpc_attrib_xattr *xattr; if ( LogLevel >= 4 ) bpc_logMsgf("bpc_lremovexattr(%s, %s)\n", path, name); if ( !file ) { errno = ENOENT; return -1; } /* * Check if the attribute is exists - if not then quietly return. */ if ( !(xattr = bpc_attrib_xattrGet(file, (char*)name, strlen(name) + 1, 0)) ) return 0; /* * Save away the attributes in old if not recently set and not present already */ if ( acOldUsed && !file->isTemp && file->inode < Stats.Inode0 && !bpc_attribCache_getFile(&acOld, (char*)path, 0, 0) ) { if ( bpc_attribCache_setFile(&acOld, (char*)path, file, 1) > 0 ) { bpc_poolRefDeltaUpdate(&DeltaOld, file->compress, &file->digest, 1); } } /* * now remove the attribute */ return bpc_attrib_xattrDelete(file, (char*)name, strlen(name) + 1); } ssize_t bpc_llistxattr(const char *path, char *list, size_t size) { bpc_attrib_file *file = bpc_attribCache_getFile(&acNew, (char*)path, 0, 0); if ( LogLevel >= 4 ) bpc_logMsgf("bpc_llistxattr(%s)\n", path); if ( !file ) { errno = ENOENT; return -1; } return bpc_attrib_xattrList(file, list, size, 1); } rsync-bpc-3.1.2.1/byteorder.h0000664000047500004750000000621113510756407014700 0ustar craigcraig/* * Simple byteorder handling. * * Copyright (C) 1992-1995 Andrew Tridgell * Copyright (C) 2007-2015 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 #undef AVOID_BYTEORDER_INLINE /* 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 1 #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 #define PVAL(buf,pos) (UVAL(buf,pos)|UVAL(buf,(pos)+1)<<8) #define IVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+2)<<16) #define IVAL64(buf,pos) (IVAL(buf,pos)|(int64)IVAL(buf,(pos)+4)<<32) #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16)) #define SIVAL(buf,pos,val) SIVALX(buf,pos,(uint32)(val)) #define SIVAL64(buf,pos,val) (SIVAL(buf,pos,val),SIVAL(buf,(pos)+4,(val)>>32)) #define IVALu(buf,pos) IVAL(buf,pos) #define SIVALu(buf,pos,val) SIVAL(buf,pos,val) #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. */ # ifdef AVOID_BYTEORDER_INLINE #define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos))) #define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val)) #define IVALu(buf,pos) IVAL(buf,pos) #define SIVALu(buf,pos,val) SIVAL(buf,pos,val) # else /* !AVOID_BYTEORDER_INLINE */ 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 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); } 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 /* !AVOID_BYTEORDER_INLINE */ #endif /* !CAREFUL_ALIGNMENT */ rsync-bpc-3.1.2.1/mkproto.pl0000664000047500004750000000171613510756401014557 0ustar craigcraig# generate prototypes for rsync $old_protos = ''; if (open(IN, 'proto.h')) { $old_protos = join('', ); close IN; } %FN_MAP = ( BOOL => 'BOOL ', CHAR => 'char ', INTEGER => 'int ', STRING => 'char *', ); $inheader = 0; $protos = qq|/* This file is automatically generated with "make proto". DO NOT EDIT */\n\n|; while (<>) { if ($inheader) { if (/[)][ \t]*$/) { $inheader = 0; s/$/;/; } $protos .= $_; } elsif (/^FN_(LOCAL|GLOBAL)_([^(]+)\(([^,()]+)/) { $ret = $FN_MAP{$2}; $func = $3; $arg = $1 eq 'LOCAL' ? 'int module_id' : 'void'; $protos .= "$ret$func($arg);\n"; } elsif (/^static|^extern/ || /[;]/ || !/^[A-Za-z][A-Za-z0-9_]* /) { ; } elsif (/[(].*[)][ \t]*$/) { s/$/;/; $protos .= $_; } elsif (/[(]/) { $inheader = 1; $protos .= $_; } } if ($old_protos ne $protos) { open(OUT, '>proto.h') or die $!; print OUT $protos; close OUT; } open(OUT, '>proto.h-tstamp') and close OUT; rsync-bpc-3.1.2.1/flist.c0000664000047500004750000025644413510756407014034 0ustar craigcraig/* * Generate and receive file lists. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool * Copyright (C) 2002-2015 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 recurse; extern int use_qsort; extern int xfer_dirs; extern int filesfrom_fd; extern int one_file_system; 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 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 unsort_ndx; extern uid_t our_uid; extern struct stats stats; extern char *filesfrom_host; extern char *usermap, *groupmap; extern char curr_dir[MAXPATHLEN]; extern struct chmod_mode_struct *chmod_modes; extern filter_rule_list filter_list; extern filter_rule_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 checksum_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 */ #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 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); } checksum_len = protocol_version < 21 ? 2 : protocol_version < 30 ? MD4_DIGEST_LEN : MD5_DIGEST_LEN; } static int show_filelist_p(void) { return INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse; } static void start_filelist_progress(char *kind) { rprintf(FCLIENT, "%s ... ", kind); output_needs_newline = 1; rflush(FINFO); } static void emit_filelist_progress(int count) { rprintf(FCLIENT, " %d files...\r", count); } static void maybe_emit_filelist_progress(int count) { if (INFO_GTE(FLIST, 2) && show_filelist_p() && (count % 100) == 0) emit_filelist_progress(count); } static void finish_filelist_progress(const struct file_list *flist) { if (INFO_GTE(FLIST, 2)) { /* This overwrites the progress line */ rprintf(FINFO, "%d file%sto consider\n", flist->used, flist->used == 1 ? " " : "s "); } else { output_needs_newline = 0; 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 = bpc_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 is_daemon_excluded(const char *fname, int is_dir) { if (daemon_filter_list.head && check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) { errno = ENOENT; return 1; } return 0; } 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; } /* 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. */ static int is_excluded(const char *fname, int is_dir, int filter_level) { #if 0 /* This currently never happens, so avoid a useless compare. */ if (filter_level == NO_FILTERS) return 0; #endif if (is_daemon_excluded(fname, is_dir)) return 1; if (filter_level != ALL_FILTERS) return 0; if (filter_list.head && check_filter(&filter_list, FINFO, fname, is_dir) < 0) return 1; return 0; } 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 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->malloced != FLIST_START) { 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; if (!flist->files) out_of_memory("flist_expand"); } 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; 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(major(rdev), 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; #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 - 1; if (first_hlink_ndx < 0) { np->data = (void*)(long)(first_ndx + ndx + 1); 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 make sure we don't send a zero flag byte or the * other end will terminate the flist transfer. Note that * the use of XMIT_TOP_DIR on a non-dir has no meaning, so * it's harmless way to add a bit to the first flag byte. */ 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)); if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); 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, checksum_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; 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; int64 file_length; uint32 modtime_nsec; 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_PROTOCOL); } 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; modtime_nsec = F_MOD_NSEC(first); mode = first->mode; 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 = MAKEDEV(DEV_MAJOR(devp), 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; 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_int(f); } if (xflags & XMIT_MOD_NSEC) modtime_nsec = read_varint(f); else modtime_nsec = 0; if (!(xflags & XMIT_SAME_MODE)) mode = from_wire_mode(read_int(f)); 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; #ifdef SUPPORT_HARD_LINKS create_object: if (preserve_hard_links) { if (protocol_version < 28 && S_ISREG(mode)) 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 HAVE_UTIMENSAT 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 (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; if (modtime_nsec) { #ifdef HAVE_UTIMENSAT file->flags |= FLAG_MOD_NSEC; OPT_EXTRA(file, 0)->unum = 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; OPT_EXTRA(file, NSEC_BUMP(file))->unum = (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 (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 - 1; if (ndx < 0) { ndx = cnt++; np->data = (void*)(long)cnt; } F_HL_GNUM(file) = ndx; } } #endif if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) { if (S_ISREG(mode)) 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), checksum_len); } else read_buf(f, bp, checksum_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 (bpc_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 #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 { if (!(bp = new_array(char, alloc_len))) out_of_memory("make_file"); } 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; OPT_EXTRA(file, 0)->unum = 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; OPT_EXTRA(file, NSEC_BUMP(file))->unum = (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 (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, checksum_len); if (unsort_ndx) F_NDX(file) = stats.num_dirs; return file; } /* 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]); 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 = bpc_opendir(fbuf))) { if (errno == ENOENT) { if (am_sender) /* Can abuse this for vanished error w/ENOENT: */ interpret_stat_error(fbuf, True); 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 = bpc_readdir(d); di; errno = 0, di = bpc_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)); } bpc_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) { if (!(relname_list = new0(item_list))) out_of_memory("send_implied_dirs"); memcpy(F_DIR_RELNAMES_P(lastpath_struct), &relname_list, sizeof relname_list); } rnpp = EXPAND_ITEM_LIST(relname_list, relnamecache *, 32); if (!(*rnpp = (relnamecache*)new_array(char, sizeof (relnamecache) + len))) out_of_memory("send_implied_dirs"); (*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); } 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 = dir_ndx; 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_byte(f, 0); else if (use_safe_inc_flist) { write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); write_varint(f, io_error); } else { if (delete_during) fatal_unsafe_io_error(); write_byte(f, 0); } if (need_unsorted_flist) { if (!(flist->sorted = new_array(struct file_struct *, flist->used))) out_of_memory("send_extra_file_list"); memcpy(flist->sorted, flist->files, flist->used * sizeof (struct file_struct*)); } 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_p()) 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"); if (inc_recurse) { dir_flist = flist_new(FLIST_TEMP, "send_file_list"); 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_daemon_excluded(fbuf, S_ISDIR(st.st_mode))) || (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_byte(f, 0); else if (use_safe_inc_flist) { write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); write_varint(f, io_error); } else { if (delete_during && inc_recurse) fatal_unsafe_io_error(); write_byte(f, 0); } #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && protocol_version >= 30 && !inc_recurse) idev_destroy(); #endif if (show_filelist_p()) 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) { if (!(flist->sorted = new_array(struct file_struct *, flist->used))) out_of_memory("send_file_list"); memcpy(flist->sorted, flist->files, flist->used * sizeof (struct file_struct*)); } 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_list(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_p()) 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"); if (inc_recurse) { if (flist->ndx_start == 1) dir_flist = flist_new(FLIST_TEMP, "recv_file_list"); dstart = dir_flist->used; } else { dir_flist = flist; dstart = 0; } while ((flags = read_byte(f)) != 0) { struct file_struct *file; 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_PROTOCOL); } 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_p()) 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). */ if (!(flist->sorted = new_array(struct file_struct *, flist->used))) out_of_memory("recv_file_list"); memcpy(flist->sorted, flist->files, flist->used * sizeof (struct file_struct*)); 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) * sizeof (struct file_struct*)); 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) { struct { /* We have to create a temporary file_struct for the search. */ struct file_struct f; char name_space[MAXPATHLEN]; } t; char fbuf[MAXPATHLEN]; const char *slash = strrchr(fname, '/'); const char *basename = slash ? slash+1 : fname; memset(&t.f, 0, FILE_STRUCT_LEN); memcpy((void *)t.f.basename, basename, strlen(basename)+1); if (slash) { strlcpy(fbuf, fname, slash - fname + 1); t.f.dirname = fbuf; } else t.f.dirname = NULL; t.f.mode = want_dir_match > 0 ? S_IFDIR : S_IFREG; if (want_dir_match < 0) return flist_find_ignore_dirness(flist, &t.f); return flist_find(flist, &t.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. */ struct file_list *flist_new(int flags, char *msg) { struct file_list *flist; if (!(flist = new0(struct file_list))) out_of_memory(msg); 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) { flist->file_pool = pool_create(NORMAL_EXTENT, 0, out_of_memory, POOL_INTERN); if (!flist->file_pool) 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; if (dlen < 0) { dlen = strlcpy(dirbuf, dirname, MAXPATHLEN); if (dlen >= MAXPATHLEN) return NULL; dirname = dirbuf; } dirlist = flist_new(FLIST_TEMP, "get_dirlist"); recurse = 0; xfer_dirs = 1; send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR); 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-bpc-3.1.2.1/hlink.c0000664000047500004750000004336513510756407014014 0ustar craigcraig/* * Routines to support hard-linking. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2004-2015 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 link_dest; 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 struct hashtable *dev_tbl; static struct hashtable *prior_hlinks, *hlink_nlinks; static struct file_list *hlink_flist; void init_hard_links(void) { if (am_sender || protocol_version < 30) dev_tbl = hashtable_create(16, 1); else if (inc_recurse) { prior_hlinks = hashtable_create(1024, 0); hlink_nlinks = hashtable_create(1024, 0); } } struct ht_int64_node *idev_find(int64 dev, int64 ino) { static struct ht_int64_node *dev_node = NULL; struct hashtable *tbl; /* 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, 1); if (!(tbl = dev_node->data)) { tbl = dev_node->data = hashtable_create(512, 1); if (DEBUG_GTE(HLINK, 3)) { rprintf(FINFO, "[%s] created hashtable for dev %s\n", who_am_i(), big_num(dev)); } } } else tbl = dev_node->data; return hashtable_find(tbl, ino, 1); } 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); if ( inc_recurse && prior_hlinks && hlink_nlinks ) { for (from = 0; from < ndx_count; from++) { file = hlink_flist->sorted[ndx_list[from]]; gnum = F_HL_GNUM(file); /* bpc_logMsgf("match_gnums: sort[%d]: gnum = %ld, fileName = %s\n", from, gnum, file->basename); */ if ( (node = hashtable_find(hlink_nlinks, gnum, 1)) ) node->data++; } } 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, 1); if (!node->data) { if (!(node->data = new_array0(char, 5))) out_of_memory("match_gnums"); 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; if (!(ndx_list = new_array(int32, flist->used))) out_of_memory("match_hard_links"); 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) { /* bpc_logMsgf("maybe_hard_link: fname = %s, oldname = %s, statret = %d\n", fname, oldname, statret); */ if (statret == 0) { /* bpc_logMsgf("maybe_hard_link: new ino = %ld, old = %ld; nlink = %u,%u, size = %u,%u\n", sxp->st.st_ino, old_stp->st_ino, sxp->st.st_nlink, old_stp->st_nlink, sxp->st.st_size, old_stp->st_size ); */ if (sxp->st.st_dev == old_stp->st_dev && sxp->st.st_ino == old_stp->st_ino && sxp->st.st_nlink == old_stp->st_nlink && sxp->st.st_size == old_stp->st_size) { 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; bpc_sysCall_statusFileSize(F_LENGTH(file)); fprintf(stderr, "IOdone: same %s\n", fname); 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, 0)) != 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 (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 (!unchanged_file(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_int(MSG_SUCCESS, 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; } bpc_sysCall_statusFileSize(F_LENGTH(file)); 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_int(MSG_SUCCESS, ndx); } if (inc_recurse) { int gnum = F_HL_GNUM(file); struct ht_int32_node *node = hashtable_find(prior_hlinks, gnum, 0); 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); if (!(node->data = strdup(our_name))) out_of_memory("finish_hard_link"); } } 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; } static void hard_link_bpc_update_one_link_count(int64 gnum, struct ht_int32_node *node, UNUSED(void *arg)) { struct ht_int32_node *count; if (!node->data || CVAL(node->data, 0) == 0) { return; } count = hashtable_find(hlink_nlinks, gnum, 0); /* bpc_logMsgf("hard_link_bpc_update_one_link_count: gnum = %u has file = %s, count = %u\n", gnum, (char*)node->data, count ? (uint32)count->data : 0); */ if ( count->data - (void*)NULL > 1 ) { bpc_nlinkSet((char*)node->data, count->data - (void*)NULL); } } /* * For all the hardlinks we transferred, check the BackupPC attribute link count (nlink) and update it * if it isn't correct. */ void hard_link_bpc_update_link_count(void) { if ( inc_recurse && prior_hlinks && hlink_nlinks ) { hashtable_iterate(prior_hlinks, (void*)hard_link_bpc_update_one_link_count, NULL); } } #endif rsync-bpc-3.1.2.1/stunnel-rsync.in0000775000047500004750000000250213510756401015700 0ustar craigcraig#!/bin/bash # This must be called as (note the trailing dot): # # stunnel-rsync HOSTNAME rsync --server --daemon . # # ... which is typically done via the rsync-ssl script, which results in something like this: # # rsync --rsh=stunnel-rsync -aiv HOSTNAME::module [ARGS] # # This SSL setup based on the files by: http://dozzie.jarowit.net/trac/wiki/RsyncSSL # Note that this requires at least version 4.x of stunnel. # The current environment can override using the RSYNC_SSL_* values: if [ x"$RSYNC_SSL_CERT" = x ]; then cert="" else cert="cert = $RSYNC_SSL_CERT" fi if [ x"$RSYNC_SSL_CA_CERT" ]; then cafile="" verify=0 else cafile="CAfile = $RSYNC_SSL_CA_CERT" verify=3 fi port=${RSYNC_SSL_PORT:-874} # 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 [ x"$1" = x"-l" ]; then shift 2 fi hostname=$1 shift if [ x"$hostname" = x -o x"$1" != x"rsync" -o x"$2" != x"--server" -o x"$3" != x"--daemon" ]; then echo "Usage: stunnel-rsync HOSTNAME rsync --server --daemon ." 1>&2 exit 1 fi # devzero@web.de came up with this no-tmpfile calling syntax: @stunnel4@ -fd 10 11<&0 <buf = new_array(char, sz))) out_of_memory("alloc_xbuf"); 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); if (!bf) out_of_memory("realloc_xbuf"); 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) { #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 } rsync-bpc-3.1.2.1/acls.c0000664000047500004750000007030413510756407013622 0ustar craigcraig/* * Handle passing Access Control Lists between systems. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2006-2015 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 hightest 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!"; } #if 0 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; } #endif /* 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); if (!racl) out_of_memory("create_racl"); *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. */ /* * Craig Barratt notes: with rsync on cygwin, this test * fails on directories since racl1->group_obj is also * NO_ENTRY. This causes an extraneous setting via * lsetxattr() of the ACL, which is benign. */ 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; } } #if 0 #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 #endif /* === System ACLs === */ #if 0 /* 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 if (!(racl->names.idas = new_array(id_access, temp_ida_list.count))) out_of_memory("unpack_smb_acl"); 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; } #endif /* 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) #if 0 #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; } #endif 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) { #ifdef SUPPORT_XATTRS /* --fake-super support: load ACLs from an xattr. */ if (1) { 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; if (!(ida = racl->names.idas = new_array(id_access, cnt))) out_of_memory("get_rsync_acl"); 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 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 (0 && am_root >= 0 && access & ~SMB_ACL_VALID_OBJ_BITS) { /* * This error check is disabled because rsync 3.x on cygwin sends * a mask of 0xff instead of 0x7. I haven't looked into cygwin to * see why that is. */ 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); if (count) { if (!(ent->idas = new_array(id_access, count))) out_of_memory("recv_ida_entries"); } else ent->idas = 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, UNUSED(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); /* * rsync 3.x on cygwin sends a mask of 0xff, rather than 0x7. * That gives an error on the client rsync when we do a restore. * So we mask off the right bits here */ if (flags & XMIT_MASK_OBJ) duo_item->racl.mask_obj = recv_acl_access(f, NULL) & SMB_ACL_VALID_OBJ_BITS; 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; #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; } } #if 0 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, UNUSED(stat_x *sxp), UNUSED(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. */ rc = del_def_xattr_acl(fname); #endif if (rc < 0) { rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_delete_def_file(%s)", fname); return -1; } #ifdef SUPPORT_XATTRS } else { /* --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 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); } #endif /* SUPPORT_ACLS */ rsync-bpc-3.1.2.1/testrun.c0000664000047500004750000000260213510756401014372 0ustar craigcraig/* 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-bpc-3.1.2.1/exclude.c0000664000047500004750000011743513510756407014340 0ustar craigcraig/* * The filter include/exclude routines. * * Copyright (C) 1996-2001 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool * Copyright (C) 2003-2015 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_server; extern int am_sender; extern int eol_nulls; extern int io_error; extern int local_server; extern int prune_empty_dirs; extern int ignore_perishable; extern int delete_mode; extern int delete_excluded; extern int cvs_exclude; extern int sanitize_paths; extern int protocol_version; 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]" }; /* 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; /* 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; if (DEBUG_GTE(FILTER, 2)) { rprintf(FINFO, "[%s] add_rule(%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); } /* 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; if (!(rule->pattern = new_array(char, pre_len + pat_len + suf_len + 1))) out_of_memory("add_rule"); 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++; } } 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; } } if (!(lp = new_array0(filter_rule_list, 1))) out_of_memory("add_rule"); 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 (!mergelist_parents) out_of_memory("add_rule"); } 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; } } /* 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)); if (!push) out_of_memory("push_local_filters"); 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_is_dir) { 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) 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_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_is_dir, const char *type) { /* 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 here. */ if (DEBUG_GTE(FILTER, 1)) { static char *actions[2][2] = { {"show", "hid"}, {"risk", "protect"} }; const char *w = who_am_i(); rprintf(code, "[%s] %sing %s %s because of pattern %s%s%s\n", w, actions[*w!='s'][!(ent->rflags & FILTRULE_INCLUDE)], name_is_dir ? "directory" : "file", name, ent->pattern, ent->rflags & FILTRULE_DIRECTORY ? "/" : "", type); } } /* 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_is_dir) { 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_is_dir); if (rc) return rc; continue; } if (ent->rflags & FILTRULE_CVS_IGNORE) { int rc = check_filter(&cvs_filter_list, code, name, name_is_dir); if (rc) return rc; continue; } if (rule_matches(name, ent, name_is_dir)) { report_filter_result(code, name, ent, name_is_dir, 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; if (!(rule = new0(filter_rule))) out_of_memory("parse_rule_tok"); /* 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 ':': 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; } } 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 char default_cvsignore[] = /* These default ignored items come from the CVS manual. */ "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" /* The rest we added to suit ourself. */ " .svn/ .git/ .hg/ .bzr/"; 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; if (!(excl_self = new0(filter_rule))) out_of_memory("parse_filter_str"); /* 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_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, *prev = NULL; 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 ? 1 : -1; if (ent->rflags & FILTRULE_RECEIVER_SIDE) elide = elide ? 0 : am_sender ? -1 : 1; else if (delete_excluded && !elide && (!(ent->rflags & FILTRULE_PERDIR_MERGE) || ent->rflags & FILTRULE_NO_PREFIXES)) elide = am_sender ? 1 : -1; if (elide < 0) { if (prev) prev->next = ent->next; else flp->head = ent->next; } else prev = ent; if (elide > 0) 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, '/'); } flp->tail = prev; } /* 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-bpc-3.1.2.1/rsync.yo0000664000047500004750000053077613510756407014261 0ustar craigcraigmailto(rsync-bugs@samba.org) manpage(rsync)(1)(21 Dec 2015)()() manpagename(rsync)(a fast, versatile, remote (and local) file-copying tool) manpagesynopsis() verb(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. manpagedescription() 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: itemization( it() support for copying links, devices, owners, groups, and permissions it() exclude and exclude-from options similar to GNU tar it() a CVS exclude mode for ignoring the same files that CVS would ignore it() can use any transparent remote shell, including ssh or rsh it() does not require super-user privileges it() pipelining of file transfers to minimize latency costs it() support for anonymous or authenticated rsync daemons (ideal for mirroring) ) manpagesection(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 bf(--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. manpagesection(SETUP) See the file README 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 bf(-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. manpagesection(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: quote(tt(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 commandline (*.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). quote(tt(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. quote(tt(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: quote( tt(rsync -av /src/foo /dest)nl() tt(rsync -av /src/foo/ /dest/foo)nl() ) 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": quote( tt(rsync -av host: /dest)nl() tt(rsync -av host::module /dest)nl() ) 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: quote(tt(rsync somehost.mydomain.com::)) See the following section for more details. manpagesection(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: quote(tt(rsync -av host:file1 :file2 host:file{3,4} /dest/)nl() tt(rsync -av host::modname/file{1,2} host::modname/file3 /dest/)nl() tt(rsync -av host::modname/file1 ::modname/file{3,4})) Older versions of rsync required using quoted spaces in the SRC, like these examples: quote(tt(rsync -av host:'dir1/file1 dir2/file2' /dest)nl() tt(rsync host::'modname/dir1/file1 modname/dir2/file2' /dest)) This word-splitting still works (by default) in the latest rsync, but is not as easy to use as the first method. If you need to transfer a filename that contains whitespace, you can either specify the bf(--protect-args) (bf(-s)) option, or you'll need to escape the whitespace in a way that the remote shell will understand. For instance: quote(tt(rsync -av host:'file\ name\ with\ spaces' /dest)) manpagesection(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: itemization( it() you either use a double colon :: instead of a single colon to separate the hostname from the path, or you use an rsync:// URL. it() the first word of the "path" is actually a module name. it() the remote daemon may print a message of the day when you connect. it() if you specify no path name on the remote daemon then the list of accessible paths on the daemon will be shown. it() if you specify no local destination then a listing of the specified files on the remote daemon is provided. it() you must not specify the bf(--rsh) (bf(-e)) option. ) An example that copies all the files in a remote module named "src": verb( 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 bf(--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 bf(--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: verb( 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). manpagesection(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 bf(--rsh=COMMAND) option. (Setting the RSYNC_RSH in the environment will not turn on this functionality.) For example: verb( 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 bf(--rsh) option: verb( 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". manpagesection(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 bf(rsyncd.conf)(5) man page -- 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. manpagesection(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, and may 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 bf(--delay-updates) (which doesn't affect the sorted transfer order, but does make the final file-updating phase happen much more rapidly). manpagesection(EXAMPLES) Here are some examples of how I use rsync. To backup my wife's home directory, which consists of large MS Word files and mail folders, I use a cron job that runs quote(tt(rsync -Cavz . arvidsjaur:backup)) each night over a PPP connection to a duplicate directory on my machine "arvidsjaur". To synchronize my samba source trees I use the following Makefile targets: verb( get: rsync -avuzb --exclude '*~' samba:samba/ . put: rsync -Cavuzb . samba:samba/ sync: get put) this allows me to sync with a CVS directory at the other end of the connection. I then do CVS operations on the remote machine, which saves a lot of time as the remote CVS protocol isn't very efficient. I mirror a directory between my "old" and "new" ftp sites with the command: tt(rsync -az -e ssh --delete ~ftp/pub/samba nimbus:"~ftp/pub/tridge") This is launched from cron every few hours. manpagesection(OPTIONS SUMMARY) Here is a short summary of the options available in rsync. Please refer to the detailed description below for a complete description. verb( -v, --verbose increase verbosity --info=FLAGS fine-grained informational verbosity --debug=FLAGS fine-grained debug verbosity --msgs2stderr special output handling for debugging -q, --quiet suppress non-error messages --no-motd suppress daemon-mode MOTD (see caveat) -c, --checksum skip based on checksum, not mod-time & size -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X) --no-OPTION turn off an implied OPTION (e.g. --no-D) -r, --recursive recurse into directories -R, --relative use relative path names --no-implied-dirs don't send implied dirs with --relative -b, --backup 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) -u, --update 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 -d, --dirs transfer directories without recursing -l, --links copy symlinks as symlinks -L, --copy-links 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 safer -k, --copy-dirlinks transform symlink to dir into referent dir -K, --keep-dirlinks treat symlinked dir on receiver as dir -H, --hard-links preserve hard links -p, --perms preserve permissions -E, --executability preserve executability --chmod=CHMOD affect file and/or directory permissions -A, --acls preserve ACLs (implies -p) -X, --xattrs preserve extended attributes -o, --owner preserve owner (super-user only) -g, --group preserve group --devices preserve device files (super-user only) --specials preserve special files -D same as --devices --specials -t, --times preserve modification times -O, --omit-dir-times omit directories from --times -J, --omit-link-times omit symlinks from --times --super receiver attempts super-user activities --fake-super store/recover privileged attrs using xattrs -S, --sparse handle sparse files efficiently --preallocate allocate dest files before writing -n, --dry-run perform a trial run with no changes made -W, --whole-file copy files whole (w/o delta-xfer algorithm) -x, --one-file-system don't cross filesystem boundaries -B, --block-size=SIZE force a fixed checksum block-size -e, --rsh=COMMAND 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 --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 -m, --prune-empty-dirs 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 -I, --ignore-times don't skip files that match size and time --size-only skip files that match in size --modify-window=NUM compare mod-times with reduced accuracy -T, --temp-dir=DIR create temporary files in directory DIR -y, --fuzzy find similar file for basis if no dest file --compare-dest=DIR also compare received files relative to DIR --copy-dest=DIR ... and include copies of unchanged files --link-dest=DIR hardlink to files in DIR when unchanged -z, --compress compress file data during the transfer --compress-level=NUM explicitly set compression level --skip-compress=LIST skip compressing files with suffix in LIST -C, --cvs-exclude auto-ignore files in the same way CVS does -f, --filter=RULE 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 -0, --from0 all *from/filter files are delimited by 0s -s, --protect-args no space-splitting; wildcard chars only --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, --8-bit-output leave high-bit chars unescaped in output -h, --human-readable output numbers in a human-readable format --progress show progress during transfer -P same as --partial --progress -i, --itemize-changes output a change-summary for all updates -M, --remote-option=OPTION 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 --list-only list the files instead of copying them --bwlimit=RATE limit socket I/O bandwidth --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) -4, --ipv4 prefer IPv4 -6, --ipv6 prefer IPv6 --version print version number (-h) --help show this help (see below for -h comment)) Rsync can also be run as a daemon, in which case the following options are accepted: verb( --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 -M, --dparam=OVERRIDE 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 -v, --verbose increase verbosity -4, --ipv4 prefer IPv4 -6, --ipv6 prefer IPv6 -h, --help show this help (if used after --daemon)) manpageoptions() 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 or replace the '=' with whitespace. The parameter may need to be quoted in some manner for it to survive the shell's command-line parsing. Keep in mind that a leading tilde (~) in a filename is substituted by your shell, so --option=~/foo will not change the tilde into your home directory (remove the '=' for that). startdit() dit(bf(--help)) Print a short help page describing the options available in rsync and exit. For backward-compatibility with older versions of rsync, the help will also be output if you use the bf(-h) option without any other args. dit(bf(--version)) print the rsync version number and exit. dit(bf(-v, --verbose)) This option increases the amount of information you are given during the transfer. By default, rsync works silently. A single bf(-v) will give you information about what files are being transferred and a brief summary at the end. Two bf(-v) options will give you information on what files are being skipped and slightly more information at the end. More than two bf(-v) options should only be used if you are debugging rsync. In a modern rsync, the bf(-v) option is equivalent to the setting of groups of bf(--info) and bf(--debug) options. You can choose to use these newer options in addition to, or in place of using bf(--verbose), as any fine-grained settings override the implied settings of bf(-v). Both bf(--info) and bf(--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 bf(-vv) will be downgraded to the bf(-vv) level in the daemon's logging. dit(bf(--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 bf(--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: verb( rsync -a --info=progress2 src/ dest/ rsync -avv --info=stats2,misc1,flist0 src/ dest/ ) Note that bf(--info=name)'s output is affected by the bf(--out-format) and bf(--itemize-changes) (bf(-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. dit(bf(--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 bf(--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: verb( rsync -avvv --debug=none src/ dest/ rsync -avA --del --debug=del2,acl src/ dest/ ) Note that some debug messages will only be output when bf(--msgs2stderr) is specified, especially those pertaining to I/O and buffer debugging. 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. dit(bf(--msgs2stderr)) This option changes rsync to send all its output directly to stderr rather than to send messages to the client side via the protocol (which normally outputs info messages via stdout). This is mainly intended for debugging in order to avoid changing the data sent via the protocol, since the extra protocol data can change what is being tested. The option does not affect the remote side of a transfer without using bf(--remote-option) -- e.g. bf(-M--msgs2stderr). Also keep in mind that a daemon connection does not have a stderr channel to send messages back to the client side, so if you are doing any daemon-transfer debugging using this option, you should start up a daemon using bf(--no-detach) so that you can see the stderr output on the daemon side. This option has the side-effect of making stderr output get line-buffered so that the merging of the output of 3 programs happens in a more readable manner. dit(bf(-q, --quiet)) 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. dit(bf(--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. dit(bf(-I, --ignore-times)) 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. dit(bf(--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. dit(bf(--modify-window)) When comparing two timestamps, rsync treats the timestamps as being equal if they differ by no more than the modify-window value. This is normally 0 (for an exact match), but you may find it useful to set this to a larger value in some situations. In particular, when transferring to or from an MS Windows FAT filesystem (which represents times with a 2-second resolution), bf(--modify-window=1) is useful (allowing times to differ by up to 1 second). dit(bf(-c, --checksum)) 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 (and this is prior to any reading that will be done to transfer changed files), so this can slow things down significantly. 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 em(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. For protocol 30 and beyond (first supported in 3.0.0), the checksum used is MD5. For older protocols, the checksum used is MD4. dit(bf(-a, --archive)) This is equivalent to bf(-rlptgoD). It is a quick way of saying you want recursion and want to preserve almost everything (with -H being a notable omission). The only exception to the above equivalence is when bf(--files-from) is specified, in which case bf(-r) is not implied. Note that bf(-a) bf(does not preserve hardlinks), because finding multiply-linked files is expensive. You must separately specify bf(-H). dit(--no-OPTION) You may turn off one or more implied options by prefixing the option name with "no-". Not all options may be prefixed with a "no-": only options that are implied by other options (e.g. bf(--no-D), bf(--no-perms)) or have different defaults in various circumstances (e.g. bf(--no-whole-file), bf(--no-blocking-io), bf(--no-dirs)). You may specify either the short or the long option name after the "no-" prefix (e.g. bf(--no-R) is the same as bf(--no-relative)). For example: if you want to use bf(-a) (bf(--archive)) but don't want bf(-o) (bf(--owner)), instead of converting bf(-a) into bf(-rlptgD), you could specify bf(-a --no-o) (or bf(-a --no-owner)). The order of the options is important: if you specify bf(--no-r -a), the bf(-r) option would end up being turned on, the opposite of bf(-a --no-r). Note also that the side-effects of the bf(--files-from) option are NOT positional, as it affects the default state of several options and slightly changes the meaning of bf(-a) (see the bf(--files-from) option for more details). dit(bf(-r, --recursive)) This tells rsync to copy directories recursively. See also bf(--dirs) (bf(-d)). Beginning with rsync 3.0.0, the recursive algorithm used is now an incremental scan that uses much less memory than before and begins the transfer after the scanning of the first few directories have been completed. This incremental scan only affects our recursion algorithm, and does not change a non-recursive transfer. It is also only possible when both ends of the transfer are at least version 3.0.0. Some options require rsync to know the full file list, so these options disable the incremental recursion mode. These include: bf(--delete-before), bf(--delete-after), bf(--prune-empty-dirs), and bf(--delay-updates). Because of this, the default delete mode when you specify bf(--delete) is now bf(--delete-during) when both ends of the connection are at least 3.0.0 (use bf(--del) or bf(--delete-during) to request this improved deletion mode explicitly). See also the bf(--delete-delay) option that is a better choice than using bf(--delete-after). Incremental recursion can be disabled using the bf(--no-inc-recursive) option or its shorter bf(--no-i-r) alias. dit(bf(-R, --relative)) 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: quote(tt( rsync -av /foo/bar/baz.c remote:/tmp/)) ... this would create a file named baz.c in /tmp/ on the remote machine. If instead you used quote(tt( 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 bf(--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: quote(tt( 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: quote(tt( (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): quote( tt( rsync -avR --rsync-path="cd /foo; rsync" \ )nl() tt( remote:bar/baz.c /tmp/) ) dit(bf(--no-implied-dirs)) This option affects the default behavior of the bf(--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 bf(--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 bf(--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 bf(--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. dit(bf(-b, --backup)) 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 bf(--backup-dir) and bf(--suffix) options. Note that if you don't specify bf(--backup-dir), (1) the bf(--omit-dir-times) option will be implied, and (2) if bf(--delete) is also in effect (without bf(--delete-excluded)), rsync will add a "protect" filter-rule for the backup suffix to the end of all your existing excludes (e.g. bf(-f "P *~")). This will prevent 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). dit(bf(--backup-dir=DIR)) In combination with the bf(--backup) option, this 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 bf(--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. dit(bf(--suffix=SUFFIX)) This option allows you to override the default backup suffix used with the bf(--backup) (bf(-b)) option. The default suffix is a ~ if no -bf(-backup-dir) was specified, otherwise it is an empty string. dit(bf(-u, --update)) 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, not an exclude, so it doesn't affect the data that goes into the file-lists, and thus it doesn't affect deletions. It just limits the files that the receiver requests to be transferred. dit(bf(--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: quote(itemization( it() 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. it() 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). it() 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. it() 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. it() 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 bf(--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 bf(--partial) (since an interrupted transfer does not delete the file), but conflicts with bf(--partial-dir) and bf(--delay-updates). Prior to rsync 2.6.4 bf(--inplace) was also incompatible with bf(--compare-dest) and bf(--link-dest). dit(bf(--append)) This causes rsync to update a file by appending data onto the end of the file, which presumes that the data that already exists on the receiving side is identical with the start of the file on the sending side. If a file needs to be transferred and its size on the receiver is the same or longer than the size on the sender, the file is skipped. 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 non-regular files. Implies bf(--inplace), but does not conflict with bf(--sparse) (since it is always extending a file's length). The use of bf(--append) can be dangerous if you aren't 100% sure that the files that are longer have only grown by the appending of data onto the end. You should thus use include/exclude/filter rules to ensure that such a transfer is only affecting files that you know to be growing via appended data. dit(bf(--append-verify)) This works just like the bf(--append) option, but the existing data on the receiving side is included in the full-file checksum verification step, which will cause a file to be resent if the final verification step fails (rsync uses a normal, non-appending bf(--inplace) transfer for the resend). Note: prior to rsync 3.0.0, the bf(--append) option worked like bf(--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 bf(--append-verify) transfer. dit(bf(-d, --dirs)) Tell the sending side to include any directories that are encountered. Unlike bf(--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 bf(--recursive) option, rsync will skip all directories it encounters (and output a message to that effect for each one). If you specify both bf(--dirs) and bf(--recursive), bf(--recursive) takes precedence. The bf(--dirs) option is implied by the bf(--files-from) option or the bf(--list-only) option (including an implied bf(--list-only) usage) if bf(--recursive) wasn't specified (so that directories are seen in the listing). Specify bf(--no-dirs) (or bf(--no-d)) if you want to turn this off. There is also a backward-compatibility helper option, bf(--old-dirs) (or bf(--old-d)) that tells rsync to use a hack of "-r --exclude='/*/*'" to get an older rsync to list a single directory without recursing. dit(bf(-l, --links)) When symlinks are encountered, recreate the symlink on the destination. dit(bf(-L, --copy-links)) When symlinks are encountered, the item that they point to (the referent) is copied, rather than the symlink. In older versions of rsync, this option also had the side-effect of telling the receiving side to follow symlinks, such as symlinks to directories. In a modern rsync such as this one, you'll need to specify bf(--keep-dirlinks) (bf(-K)) to get this extra behavior. The only exception is when sending files to an rsync that is too old to understand bf(-K) -- in that case, the bf(-L) option will still have the side-effect of bf(-K) on that older receiving rsync. dit(bf(--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 bf(--relative) is used. This option has no additional effect if bf(--copy-links) was also specified. dit(bf(--safe-links)) This tells rsync to ignore any symbolic links which point outside the copied tree. All absolute symlinks are also ignored. Using this option in conjunction with bf(--relative) may give unexpected results. dit(bf(--munge-links)) This option tells rsync to (1) modify all symlinks on the receiving side in a way that makes them unusable but recoverable (see below), or (2) to unmunge symlinks on the sending side that had been stored in a munged state. This is useful if you don't quite trust the source of the data to not try to slip in a symlink to a unexpected place. 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 option is enabled, rsync will refuse to run if that path is a directory or a symlink to a directory. The option only affects the client side of the transfer, so if you need it to affect the server, specify it via bf(--remote-option). (Note that in a local transfer, the client side is the sender.) This option has no affect on a daemon, since the daemon configures whether it wants munged symlinks via its "munge symlinks" parameter. See also the "munge-symlinks" perl script in the support directory of the source code. dit(bf(-k, --copy-dirlinks)) 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 bf(--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 bf(--force) or bf(--delete) is in effect). See also bf(--keep-dirlinks) for an analogous option for the receiving side. bf(--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 bf(--relative) to make the paths match up right. For example: quote(tt(rsync -r --relative src/./ src/./follow-me/ dest/)) This works because rsync calls bf(lstat)(2) on the source arg as given, and the trailing slash makes bf(lstat)(2) follow the symlink, giving rise to a directory in the file-list which overrides the symlink found during the scan of "src/./". dit(bf(-K, --keep-dirlinks)) 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 bf(--keep-dirlinks), the receiver deletes symlink "foo", recreates it as a directory, and receives the file into the new directory. With bf(--keep-dirlinks), the receiver keeps the symlink and "file" ends up in "bar". One note of caution: if you use bf(--keep-dirlinks), you must trust all the symlinks in the copy! If it is possible for an untrusted user to create their own symlink to any 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 bf(--copy-dirlinks) for an analogous option for the sending side. dit(bf(-H, --hard-links)) 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: quote(itemization( it() 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 bf(--inplace) option). it() If you specify a bf(--link-dest) directory that contains hard links, the linking of the destination files against the bf(--link-dest) files can cause some paths in the destination to become linked together due to the bf(--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 bf(--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 bf(--inplace) option for more caveats). If incremental recursion is active (see bf(--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 bf(--no-inc-recursive) option. dit(bf(-p, --perms)) This option causes the receiving rsync to set the destination permissions to be the same as the source permissions. (See also the bf(--chmod) option for a way to modify what rsync considers to be the source permissions.) When this option is em(off), permissions are set as follows: quote(itemization( it() Existing files (including updated files) retain their existing permissions, though the bf(--executability) option might change just the execute permission for the file. it() 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 bf(--perms) and bf(--executability) are both disabled, rsync's behavior is the same as that of other file-copy utilities, such as bf(cp)(1) and bf(tar)(1). In summary: to give destination files (both old and new) the source permissions, use bf(--perms). To give new files the destination-default permissions (while leaving existing files unchanged), make sure that the bf(--perms) option is off and use bf(--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 bf(-Z) option, and includes --no-g to use the default group of the destination dir): quote(tt( rsync alias -Z --no-p --no-g --chmod=ugo=rwX)) You could then use this new option in a command such as this one: quote(tt( rsync -avZ src/ dest/)) (Caveat: make sure that bf(-a) does not follow bf(-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 bf(--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 bf(--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.) dit(bf(-E, --executability)) This option causes rsync to preserve the executability (or non-executability) of regular files when bf(--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: quote(itemization( it() To make a file non-executable, rsync turns off all its 'x' permissions. it() To make a file executable, rsync turns on each 'x' permission that has a corresponding 'r' permission enabled. )) If bf(--perms) is enabled, this option is ignored. dit(bf(-A, --acls)) This option causes rsync to update the destination ACLs to be the same as the source ACLs. The option also implies bf(--perms). The source and destination systems must have compatible ACL entries for this option to work properly. See the bf(--fake-super) option for a way to backup and restore ACLs that are not compatible. dit(bf(-X, --xattrs)) 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 bf(--fake-super) option. Note that this option does not copy rsyncs special xattr values (e.g. those used by bf(--fake-super)) unless you repeat the option (e.g. -XX). This "copy all xattrs" mode cannot be used with bf(--fake-super). dit(bf(--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 bf(--perms) is not enabled. In addition to the normal parsing rules specified in the bf(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: quote(--chmod=Dg+s,ug+w,Fo-w,+X) Using octal mode numbers is also allowed: quote(--chmod=D2775,F664) It is also legal to specify multiple bf(--chmod) options, as each additional option is just appended to the list of changes to make. See the bf(--perms) and bf(--executability) options for how the resulting permission value can be applied to the files in the transfer. dit(bf(-o, --owner)) 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 bf(--super) and bf(--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 bf(--numeric-ids) option for a full discussion). dit(bf(-g, --group)) 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 bf(--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 bf(--numeric-ids) option for a full discussion). dit(bf(--devices)) This option causes rsync to transfer character and block device files to the remote system to recreate these devices. This option has no effect if the receiving rsync is not run as the super-user (see also the bf(--super) and bf(--fake-super) options). dit(bf(--specials)) This option causes rsync to transfer special files such as named sockets and fifos. dit(bf(-D)) The bf(-D) option is equivalent to bf(--devices) bf(--specials). dit(bf(-t, --times)) 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 bf(-t) or bf(-a) will cause the next transfer to behave as if it used bf(-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 bf(-t)). dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when it is preserving modification times (see bf(--times)). If NFS is sharing the directories on the receiving side, it is a good idea to use bf(-O). This option is inferred if you use bf(--backup) without bf(--backup-dir). This option also has the side-effect of avoiding early creation of directories in incremental recursion copies. The default bf(--inc-recursive) copying normally does an early-create pass of all the sub-directories in a parent directory in order for it to be able to then set the modify time of the parent directory right away (without having to delay that until a bunch of recursive copying has finished). This early-create idiom is not necessary if directory modify times are not being preserved, so it is skipped. Since early-create directories don't have accurate mode, mtime, or ownership, the use of this option can help when someone wants to avoid these partially-finished directories. dit(bf(-J, --omit-link-times)) This tells rsync to omit symlinks when it is preserving modification times (see bf(--times)). dit(bf(--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 bf(--owner) option, preserving all groups (not just the current user's groups) via the bf(--groups) option, and copying devices via the bf(--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 bf(--no-super). dit(bf(--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 bf(--acls) was specified) and non-user extended attributes (if bf(--xattrs) was specified). This is a good way to backup data without using a super-user, and to store ACLs from incompatible systems. The bf(--fake-super) option only affects the side where the option is used. To affect the remote side of a remote-shell connection, use the bf(--remote-option) (bf(-M)) option: quote(tt( 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 bf(-M--fake-super). If you wish a local copy to enable this option just for the source files, combine bf(--fake-super) with bf(-M--super). This option is overridden by both bf(--super) and bf(--no-super). See also the "fake super" setting in the daemon's rsyncd.conf file. dit(bf(-S, --sparse)) Try to handle sparse files efficiently so they take up less space on the destination. Conflicts with bf(--inplace) because it's not possible to overwrite data in a sparse fashion. dit(bf(--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 bf(fallocate)(2) system call or Cygwin's bf(posix_fallocate)(3), not the slow glibc implementation that writes a zero 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. dit(bf(-n, --dry-run)) 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 bf(-v, --verbose) and/or bf(-i, --itemize-changes) options to see what an rsync command is going to do before one actually runs it. The output of bf(--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 bf(--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. dit(bf(-W, --whole-file)) With this option rsync's delta-transfer algorithm is not used and the whole file is sent as-is instead. 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. dit(bf(-x, --one-file-system)) 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 bf(--copy-links) or bf(--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. dit(bf(--existing, --ignore-non-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 bf(--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, not an exclude, so it doesn't affect the data that goes into the file-lists, and thus it doesn't affect deletions. It just limits the files that the receiver requests to be transferred. dit(bf(--ignore-existing)) This tells rsync to skip updating files that already exist on the destination (this does em(not) ignore existing directories, or nothing would get done). See also bf(--existing). This option is a transfer rule, not an exclude, so it doesn't affect the data that goes into the file-lists, and thus it doesn't affect deletions. It just limits the files that the receiver requests to be transferred. This option can be useful for those doing backups using the bf(--link-dest) option when they need to continue a backup run that got interrupted. Since a bf(--link-dest) run is copied into a new directory hierarchy (when it is used properly), using bf(--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. dit(bf(--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 bf(--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. dit(bf(--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 bf(--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 bf(--recursive) was enabled. Beginning with 2.6.7, deletions will also occur when bf(--dirs) (bf(-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 bf(--dry-run) option (bf(-n)) 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 bf(--ignore-errors) option. The bf(--delete) option may be combined with one of the --delete-WHEN options without conflict, as well as bf(--delete-excluded). However, if none of the --delete-WHEN options are specified, rsync will choose the bf(--delete-during) algorithm when talking to rsync 3.0.0 or newer, and the bf(--delete-before) algorithm when talking to an older rsync. See also bf(--delete-delay) and bf(--delete-after). dit(bf(--delete-before)) Request that the file-deletions on the receiving side be done before the transfer starts. See bf(--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 bf(--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 bf(--recursive)). dit(bf(--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 bf(--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 bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--delete-delay)) Request that the file-deletions on the receiving side be computed during the transfer (like bf(--delete-during)), and then removed after the transfer completes. This is useful when combined with bf(--delay-updates) and/or bf(--fuzzy), and is more efficient than using bf(--delete-after) (but can behave differently, since bf(--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 bf(--delete-after) (which it cannot do if bf(--recursive) is doing an incremental scan). See bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--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 bf(--recursive)). See bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--delete-excluded)) In addition to deleting the files on the receiving side that are not on the sending side, this tells rsync to also delete any files on the receiving side that are excluded (see bf(--exclude)). See the FILTER RULES section for a way to make individual exclusions behave this way on the receiver, and for a way to protect files from bf(--delete-excluded). See bf(--delete) (which is implied) for more details on file-deletion. dit(bf(--ignore-missing-args)) When rsync is first processing the explicitly requested source files (e.g. command-line arguments or bf(--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. dit(bf(--delete-missing-args)) This option takes the behavior of (the implied) bf(--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 bf(--list-only) output. dit(bf(--ignore-errors)) Tells bf(--delete) to go ahead and delete files even when there are I/O errors. dit(bf(--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 bf(--delete) for details). Note for older rsync versions: bf(--force) used to still be required when using bf(--delete-after), and it used to be non-functional unless the bf(--recursive) option was also enabled. dit(bf(--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 bf(--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 bf(--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). dit(bf(--max-size=SIZE)) This tells rsync to avoid transferring any file that is larger than the specified SIZE. The SIZE value can be suffixed with a string to indicate a size multiplier, and may be a fractional value (e.g. "bf(--max-size=1.5m)"). This option is a transfer rule, not an exclude, so it doesn't affect the data that goes into the file-lists, and thus it doesn't affect deletions. It just limits the files that the receiver requests to be transferred. The suffixes are as follows: "K" (or "KiB") is a kibibyte (1024), "M" (or "MiB") is a mebibyte (1024*1024), and "G" (or "GiB") is a gibibyte (1024*1024*1024). If you want the multiplier to be 1000 instead of 1024, use "KB", "MB", or "GB". (Note: lower-case is also accepted for all values.) Finally, if the suffix ends in either "+1" or "-1", the value will be offset by one byte in the indicated direction. 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 bf(--max-size=0). dit(bf(--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 bf(--max-size) option for a description of SIZE and other information. Note that rsync versions prior to 3.1.0 did not allow bf(--min-size=0). dit(bf(-B, --block-size=BLOCKSIZE)) 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. dit(bf(-e, --rsh=COMMAND)) 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 bf([user@]host::module/path), then the remote shell em(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 section "USING RSYNC-DAEMON FEATURES VIA A REMOTE-SHELL CONNECTION" above. 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: quote( tt( -e 'ssh -p 2234')nl() tt( -e 'ssh -o "ProxyCommand nohup ssh firewall nc -w1 %h %p"')nl() ) (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 bf(-e). See also the bf(--blocking-io) option which is affected by this option. dit(bf(--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 bf(--relative) option. For instance: quote(tt( rsync -avR --rsync-path="cd /a/b && rsync" host:c/d /e/)) dit(bf(-M, --remote-option=OPTION)) 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 bf(--log-file=FILE) and bf(--fake-super) to the remote system, specify it like this: quote(tt( 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: quote(tt( 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 it is best to use a separate bf(--remote-option) for each option you want to pass. This makes your useage compatible with the bf(--protect-args) option. If that option is off, any spaces in your remote options will be split by the remote shell unless you take steps to protect them. 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. tt(-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. dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a broad range of files that you often don't want to transfer between systems. It uses a similar algorithm to CVS to determine if 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): quote(quote(tt(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 bf(cvs)(1) manual for more information. If you're combining bf(-C) with your own bf(--filter) rules, you should note that these CVS excludes are appended at the end of your own rules, regardless of where the bf(-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 bf(-C) as a command-line option and use a combination of bf(--filter=:C) and bf(--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. dit(bf(-f, --filter=RULE)) 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 bf(--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. dit(bf(-F)) The bf(-F) option is a shorthand for adding two bf(--filter) rules to your command. The first time it is used is a shorthand for this rule: quote(tt( --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 bf(-F) is repeated, it is a shorthand for this rule: quote(tt( --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. dit(bf(--exclude=PATTERN)) This option is a simplified form of the bf(--filter) option that defaults to an exclude rule and does not allow the full rule-parsing syntax of normal filter rules. See the FILTER RULES section for detailed information on this option. dit(bf(--exclude-from=FILE)) This option is related to the bf(--exclude) option, but it specifies a FILE that contains exclude patterns (one per line). Blank lines in the file and lines starting with ';' or '#' are ignored. If em(FILE) is bf(-), the list will be read from standard input. dit(bf(--include=PATTERN)) This option is a simplified form of the bf(--filter) option that defaults to an include rule and does not allow the full rule-parsing syntax of normal filter rules. See the FILTER RULES section for detailed information on this option. dit(bf(--include-from=FILE)) This option is related to the bf(--include) option, but it specifies a FILE that contains include patterns (one per line). Blank lines in the file and lines starting with ';' or '#' are ignored. If em(FILE) is bf(-), the list will be read from standard input. dit(bf(--files-from=FILE)) Using this option allows you to specify the exact list of files to transfer (as read from the specified FILE or bf(-) for standard input). It also tweaks the default behavior of rsync to make transferring just the specified files and directories easier: quote(itemization( it() The bf(--relative) (bf(-R)) option is implied, which preserves the path information that is specified for each item in the file (use bf(--no-relative) or bf(--no-R) if you want to turn that off). it() The bf(--dirs) (bf(-d)) option is implied, which will create directories specified in the list on the destination rather than noisily skipping them (use bf(--no-dirs) or bf(--no-d) if you want to turn that off). it() The bf(--archive) (bf(-a)) option's behavior does not imply bf(--recursive) (bf(-r)), so specify it explicitly, if you want it. it() These side-effects change the default state of rsync, so the position of the bf(--files-from) option on the command-line has no bearing on how other options are parsed (e.g. bf(-a) works the same before or after bf(--files-from), as does bf(--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: quote(tt( 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 bf(-r) option was enabled, that dir's entire hierarchy would also be transferred (keep in mind that bf(-r) needs to be specified explicitly with bf(--files-from), since it is not implied by bf(-a)). Also note that the effect of the (enabled by default) bf(--relative) 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 bf(--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: quote(tt( 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 bf(--iconv) and bf(--protect-args) options are specified and the bf(--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. dit(bf(-0, --from0)) 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 bf(--exclude-from), bf(--include-from), bf(--files-from), and any merged files specified in a bf(--filter) rule. It does not affect bf(--cvs-exclude) (since all names read from a .cvsignore file are split on whitespace). dit(bf(-s, --protect-args)) This option sends all filenames and most options to the remote rsync without allowing the remote shell to interpret them. This means that spaces are not split in names, and any non-wildcard special characters are not translated (such as ~, $, ;, &, etc.). Wildcards are expanded on the remote host by rsync (instead of the shell doing it). If you use this option with bf(--iconv), the args related to the remote side will also be translated from the local to the remote character-set. The translation happens before wild-cards are expanded. See also the bf(--files-from) option. You may also control this option via the RSYNC_PROTECT_ARGS environment variable. If this variable has a non-zero value, this option 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 bf(--no-s) and bf(--no-protect-args) are the negative versions). Since this option was first introduced in 3.0.0, you'll need to make sure it's disabled if you ever need to interact with a remote rsync that is older than that. Rsync can also be configured (at build time) to have this option enabled by default (with is overridden by both the environment and the command-line). This option will eventually become a new default setting at some as-yet-undetermined point in the future. dit(bf(-T, --temp-dir=DIR)) 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 bf(--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 bf(--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 bf(--partial-dir) with an absolute path does not have this side-effect.) dit(bf(-y, --fuzzy)) 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 bf(--compare-dest), bf(--copy-dest), or bf(--link-dest). Note that the use of the bf(--delete) option might get rid of any potential fuzzy-match files, so either use bf(--delete-after) or specify some filename exclusions if you need to prevent this. dit(bf(--compare-dest=DIR)) This option instructs rsync to use em(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 em(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 bf(--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 em(DIR)s will be selected to try to speed up the transfer. If em(DIR) is a relative path, it is relative to the destination directory. See also bf(--copy-dest) and bf(--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). dit(bf(--copy-dest=DIR)) This option behaves like bf(--compare-dest), but rsync will also copy unchanged files found in em(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 bf(--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 em(DIR)s will be selected to try to speed up the transfer. If em(DIR) is a relative path, it is relative to the destination directory. See also bf(--compare-dest) and bf(--link-dest). dit(bf(--link-dest=DIR)) This option behaves like bf(--copy-dest), but unchanged files are hard linked from em(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: quote(tt( rsync -av --link-dest=$PWD/prior_dir host:src_dir/ new_dir/)) If file's 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 bf(--link-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 em(DIR)s 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 bf(--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 em(DIR) is a relative path, it is relative to the destination directory. See also bf(--compare-dest) and bf(--copy-dest). Note that rsync versions prior to 2.6.1 had a bug that could prevent bf(--link-dest) from working properly for a non-super-user when bf(-o) was specified (or implied by bf(-a)). You can work-around this bug by avoiding the bf(-o) option when sending to an old rsync. dit(bf(-z, --compress)) 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. Note that this option typically achieves better compression ratios than can be achieved by using a compressing remote shell or a compressing transport because it takes advantage of the implicit information in the matching data blocks that are not explicitly sent over the connection. This matching-data compression comes at a cost of CPU, though, and can be disabled by repeating the bf(-z) option, but only if both sides are at least version 3.1.1. Note that if your version of rsync was compiled with an external zlib (instead of the zlib that comes packaged with rsync) then it will not support the old-style compression, only the new-style (repeated-option) compression. In the future this new-style compression will likely become the default. The client rsync requests new-style compression on the server via the bf(--new-compress) option, so if you see that option rejected it means that the server is not new enough to support bf(-zz). Rsync also accepts the bf(--old-compress) option for a future time when new-style compression becomes the default. See the bf(--skip-compress) option for the default list of file suffixes that will not be compressed. dit(bf(--compress-level=NUM)) Explicitly set the compression level to use (see bf(--compress)) instead of letting it default. If NUM is non-zero, the bf(--compress) option is implied. dit(bf(--skip-compress=LIST)) Override the list of file suffixes that will not be compressed. The bf(LIST) should be one or more file suffixes (without the dot) separated by slashes (/). You may specify an empty string to indicate that no file 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): verb( --skip-compress=gz/jpg/mp[34]/7z/bz2) The default list of suffixes that will not be compressed is this (in this version of rsync): bf(7z) bf(ace) bf(avi) bf(bz2) bf(deb) bf(gpg) bf(gz) bf(iso) bf(jpeg) bf(jpg) bf(lz) bf(lzma) bf(lzo) bf(mov) bf(mp3) bf(mp4) bf(ogg) bf(png) bf(rar) bf(rpm) bf(rzip) bf(tbz) bf(tgz) bf(tlz) bf(txz) bf(xz) bf(z) bf(zip) This list will be replaced by your bf(--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). dit(bf(--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 bf(--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 comments on the "use chroot" setting in the rsyncd.conf manpage for information 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. dit(bf(--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 bf(STRING) is one or more bf(FROM):bf(TO) pairs of values separated by commas. Any matching bf(FROM) value from the sender is replaced with a bf(TO) value from the receiver. You may specify usernames or user IDs for the bf(FROM) and bf(TO) values, and the bf(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: verb( --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 bf(--usermap) option, and/or all your group mappings using a single bf(--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 bf(FROM) names match those in use on the sending side. All bf(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: verb( --usermap=:nobody --groupmap=*:nobody) When the bf(--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 bf(FROM) values if you want to map these nameless IDs to different values. For the bf(--usermap) option to have any effect, the bf(-o) (bf(--owner)) option must be used (or implied), and the receiver will need to be running as a super-user (see also the bf(--fake-super) option). For the bf(--groupmap) option to have any effect, the bf(-g) (bf(--groups)) option must be used (or implied), and the receiver will need to have permissions to set that group. dit(bf(--chown=USER:GROUP)) This option forces all files to be owned by USER with group GROUP. This is a simpler interface than using bf(--usermap) and bf(--groupmap) directly, but it is implemented using those options internally, so you cannot mix them. 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. dit(bf(--timeout=TIMEOUT)) 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. dit(bf(--contimeout)) 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. dit(bf(--address)) By default rsync will bind to the wildcard address when connecting to an rsync daemon. The bf(--address) option allows you to specify a specific IP address (or hostname) to bind to. See also this option in the bf(--daemon) mode section. dit(bf(--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 this option in the bf(--daemon) mode section. dit(bf(--sockopts)) 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 man page for the code(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. This option also exists in the bf(--daemon) mode section. dit(bf(--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.) dit(bf(--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. dit(bf(-i, --itemize-changes)) 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 bf(--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 bf(-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 bf(YXcstpoguax), where bf(Y) is replaced by the type of update being done, bf(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 bf(Y) are as follows: quote(itemization( it() A bf(<) means that a file is being transferred to the remote host (sent). it() A bf(>) means that a file is being transferred to the local host (received). it() A bf(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.). it() A bf(h) means that the item is a hard link to another item (requires bf(--hard-links)). it() A bf(.) means that the item is not being updated (though it might have attributes that are being modified). it() A bf(*) means that the rest of the itemized-output area contains a message (e.g. "deleting"). )) The file-types that replace the bf(X) are: bf(f) for a file, a bf(d) for a directory, an bf(L) for a symlink, a bf(D) for a device, and a bf(S) for a special file (e.g. named sockets and fifos). The other letters in the string above are the actual letters that will be output if the associated attribute for the item is being updated or a "." for no change. Three exceptions to this are: (1) a newly created item replaces each letter with a "+", (2) an identical item replaces the dots with spaces, and (3) an unknown attribute replaces each letter with a "?" (this can happen when talking to an older rsync). The attribute that is associated with each letter is as follows: quote(itemization( it() A bf(c) means either that a regular file has a different checksum (requires bf(--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. it() A bf(s) means the size of a regular file is different and will be updated by the file transfer. it() A bf(t) means the modification time is different and is being updated to the sender's value (requires bf(--times)). An alternate value of bf(T) means that the modification time will be set to the transfer time, which happens when a file/symlink/device is updated without bf(--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 bf(s) flag combined with bf(t) instead of the proper bf(T) flag for this time-setting failure.) it() A bf(p) means the permissions are different and are being updated to the sender's value (requires bf(--perms)). it() An bf(o) means the owner is different and is being updated to the sender's value (requires bf(--owner) and super-user privileges). it() A bf(g) means the group is different and is being updated to the sender's value (requires bf(--group) and the authority to set the group). it() The bf(u) slot is reserved for future use. it() The bf(a) means that the ACL information changed. it() The bf(x) means that the extended attribute information 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). dit(bf(--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 bf(--info=name) or bf(-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 bf(--out-format) option implies the bf(--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 bf(--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 bf(--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 bf(--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). dit(bf(--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 bf(--log-file-format) option if you wish to override this. Here's a example command that requests the remote side to log what is happening: verb( 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. dit(bf(--log-file-format=FORMAT)) This allows you to specify exactly what per-update logging is put into the file specified by the bf(--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 bf(--log-file) is specified and this option is not is '%i %n%L'. dit(bf(--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 bf(--info=stats2) if combined with 0 or 1 bf(-v) options, or bf(--info=stats3) if combined with 2 or more bf(-v) options. The current statistics are as follows: quote(itemization( it() bf(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. it() bf(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). it() bf(Number of deleted 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). 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). it() bf(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. it() bf(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. it() bf(Total transferred file size) is the total sum of all files sizes for just the transferred files. it() bf(Literal data) is how much unmatched file-update data we had to send to the receiver for it to recreate the updated files. it() bf(Matched data) is how much data the receiver got locally when recreating the updated files. it() bf(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. it() bf(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. it() bf(File list transfer time) is the number of seconds that the sender spent sending the file list to the receiver. it() bf(Total bytes sent) is the count of all the bytes that rsync sent from the client side to the server side. it() bf(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. )) dit(bf(-8, --8-bit-output)) 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). dit(bf(-h, --human-readable)) 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 bf(-h) option increases the level by one. You can take the level down to 0 (to output numbers as pure digits) by specifing the bf(--no-human-readable) (bf(--no-h)) option. The unit letters that are appended in levels 2 and 3 are: K (kilo), M (mega), G (giga), or T (tera). 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 bf(-h) options will behave in a comparable manner in old and new versions as long as you didn't specify a bf(--no-h) option prior to one or more bf(-h) options. See the bf(--list-only) option for one difference. dit(bf(--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 bf(--partial) option tells rsync to keep the partial file which should make a subsequent transfer of the rest of the file much faster. dit(bf(--partial-dir=DIR)) A better way to keep partial files than the bf(--partial) option is to specify a em(DIR) that will be used to hold the partial data (instead of writing it 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 bf(--whole-file) is specified (or implied), any partial-dir file that is 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 em(DIR) if it is missing (just the last dir -- not the whole path). This makes it easy to use a relative path (such as "bf(--partial-dir=.rsync-partial)") to have rsync create the partial-directory in the destination file's directory when needed, and then remove it again when the partial file is deleted. 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 bf(--partial-dir) option would add the equivalent of "bf(-f '-p .rsync-partial/')" at the end of any other filter rules. 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 bf(--delete-after) and add a "risk" filter rule, e.g. bf(-f 'R .rsync-partial/'). (Avoid using bf(--delete-before) or bf(--delete-during) unless you don't need rsync to use any of the left-over partial-dir data during the current run.) IMPORTANT: the bf(--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 bf(--partial) to be enabled, but rather it affects where partial files go when bf(--partial) is specified. For instance, instead of using bf(--partial-dir=.rsync-tmp) along with bf(--progress), you could set RSYNC_PARTIAL_DIR=.rsync-tmp in your environment and then just use the bf(-P) option to turn on the use of the .rsync-tmp dir for partial transfers. The only times that the bf(--partial) option does not look for this environment value are (1) when bf(--inplace) was specified (since bf(--inplace) conflicts with bf(--partial-dir)), and (2) when bf(--delay-updates) was specified (see below). For the purposes of the daemon-config's "refuse options" setting, bf(--partial-dir) does em(not) imply bf(--partial). This is so that a refusal of the bf(--partial) option can be used to disallow the overwriting of destination files with a partial transfer, while still allowing the safer idiom provided by bf(--partial-dir). dit(bf(--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 bf(--partial-dir) option, that directory will be used instead. See the comments in the bf(--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 bf(--inplace) and bf(--append). 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 bf(--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" perl script in the "support" subdir for an update algorithm that is even more atomic (it uses bf(--link-dest) and a parallel hierarchy of files). dit(bf(-m, --prune-empty-dirs)) 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. Note that the use of transfer rules, such as the bf(--min-size) option, does not affect what goes into the file list, and thus does not leave directories empty, even if none of the files in a directory match the transfer rule. 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: quote( --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): quote( 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 "bf(--include='*/' --exclude='*')" would work fine in place of the hide-filter (if that is more natural to you). dit(bf(--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 bf(--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: verb( 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: verb( 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). dit(bf(-P)) The bf(-P) option is equivalent to bf(--partial) bf(--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 bf(--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 bf(-v) or specify bf(--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 bf(--progress) option in order to use bf(--info=progress2).) dit(bf(--password-file=FILE)) This option allows you to provide a password for accessing an rsync daemon via a file or via standard input if bf(FILE) is bf(-). The file should contain just the password on the first line (all other lines are ignored). Rsync will exit with an error if bf(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). dit(bf(--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 list such an arg without using this option. For example: verb( rsync -av --list-only foo* dest/) Starting with rsync 3.1.0, the sizes output by bf(--list-only) are affected by the bf(--human-readable) option. By default they will contain digit separators, but higher levels of readability will output the sizes with unit suffixes. Note also that the column width for the size output has increased from 11 to 14 characters for all human-readable levels. Use bf(--no-h) if you want just digits in the sizes, and the old column width of 11 characters. 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 bf(--dirs) option w/o bf(--recursive), and older rsyncs don't have that option. To avoid this problem, either specify the bf(--no-dirs) option (if you don't need to expand a directory's content), or turn on recursion and exclude the content of subdirectories: bf(-r --exclude='/*/*'). dit(bf(--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. "bf(--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 bf(--max-size) option for a description of all the available suffixes. A value of zero 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 bf(--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. dit(bf(--write-batch=FILE)) Record a file that can later be applied to another identical destination with bf(--read-batch). See the "BATCH MODE" section for details, and also the bf(--only-write-batch) option. dit(bf(--only-write-batch=FILE)) Works like bf(--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 bf(--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). dit(bf(--read-batch=FILE)) Apply all of the changes stored in FILE, a file previously generated by bf(--write-batch). If em(FILE) is bf(-), the batch data will be read from standard input. See the "BATCH MODE" section for details. dit(bf(--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 bf(--write-batch) option, but rsync 2.6.3 is what will be used to run the bf(--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). dit(bf(--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 bf(--iconv=LOCAL,REMOTE), e.g. bf(--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 bf(--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 bf(--protect-args) option (bf(-s)), rsync will translate the filenames you specify on the command-line that are being sent to the remote host. See also the bf(--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 bf(--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. bf(--iconv=utf8)). dit(bf(-4, --ipv4) or bf(-6, --ipv6)) Tells rsync to prefer IPv4/IPv6 when creating sockets. This only affects sockets that rsync has direct control over, such as the outgoing socket when directly contacting an rsync daemon. See also these options in the bf(--daemon) mode section. If rsync was complied without support for IPv6, the bf(--ipv6) option will have no effect. The bf(--version) output will tell you if this is the case. dit(bf(--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 code(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 code(time()) for checksum seed. enddit() manpagesection(DAEMON OPTIONS) The options allowed when starting an rsync daemon are as follows: startdit() dit(bf(--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 bf(host::module) or bf(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 bf(rsyncd.conf)(5) man page for more details. dit(bf(--address)) By default rsync will bind to the wildcard address when run as a daemon with the bf(--daemon) option. The bf(--address) option allows you to specify a specific IP address (or hostname) to bind to. This makes virtual hosting possible in conjunction with the bf(--config) option. See also the "address" global option in the rsyncd.conf manpage. dit(bf(--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 bf(--bwlimit) value, but no larger value will be allowed. See the client version of this option (above) for some extra details. dit(bf(--config=FILE)) This specifies an alternate config file than the default. This is only relevant when bf(--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). dit(bf(-M, --dparam=OVERRIDE)) 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: verb( rsync --daemon -M pidfile=/path/rsync.pid ) dit(bf(--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 bf(daemontools) or AIX's bf(System Resource Controller). bf(--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. dit(bf(--port=PORT)) This specifies an alternate TCP port number for the daemon to listen on rather than the default of 873. See also the "port" global option in the rsyncd.conf manpage. dit(bf(--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. dit(bf(--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. dit(bf(--sockopts)) This overrides the bf(socket options) setting in the rsyncd.conf file and has the same syntax. dit(bf(-v, --verbose)) 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. dit(bf(-4, --ipv4) or bf(-6, --ipv6)) 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 bf(--ipv6) or bf(--ipv4) when starting the daemon). If rsync was complied without support for IPv6, the bf(--ipv6) option will have no effect. The bf(--version) output will tell you if this is the case. dit(bf(-h, --help)) When specified after bf(--daemon), print a short help page describing the options available for starting an rsync daemon. enddit() manpagesection(FILTER RULES) The filter rules allow for flexible selection of which files to transfer (include) and which files to skip (exclude). The rules either directly specify include/exclude patterns or they specify a way to acquire more include/exclude patterns (e.g. to read them from a file). As the list of files/directories to transfer is built, rsync checks each name to be transferred against the list of include/exclude patterns in turn, and the first matching pattern is acted on: if it is an exclude pattern, then that file is skipped; if it is an include pattern then that filename is not skipped; if no matching pattern is found, then the filename is not skipped. Rsync builds an ordered list of filter rules as specified on the command-line. Filter rules have the following syntax: quote( tt(RULE [PATTERN_OR_FILENAME])nl() tt(RULE,MODIFIERS [PATTERN_OR_FILENAME])nl() ) 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 (_). Here are the available rule prefixes: quote( bf(exclude, -) specifies an exclude pattern. nl() bf(include, +) specifies an include pattern. nl() bf(merge, .) specifies a merge-file to read for more rules. nl() bf(dir-merge, :) specifies a per-directory merge-file. nl() bf(hide, H) specifies a pattern for hiding files from the transfer. nl() bf(show, S) files that match the pattern are not hidden. nl() bf(protect, P) specifies a pattern for protecting files from deletion. nl() bf(risk, R) files that match the pattern are not protected. nl() bf(clear, !) clears the current include/exclude list (takes no arg) nl() ) When rules are being read from a file, empty lines are ignored, as are comment lines that start with a "#". Note that the bf(--include)/bf(--exclude) command-line options do not allow the full range of rule parsing as described above -- they only allow the specification of include/exclude patterns plus a "!" token to clear the list (and the normal comment parsing when rules are read from a file). If a pattern does not begin with "- " (dash, space) or "+ " (plus, space), then the rule will be interpreted as if "+ " (for an include option) or "- " (for an exclude option) were prefixed to the string. A bf(--filter) option, on the other hand, must always contain either a short or long rule name at the start of the rule. Note also that the bf(--filter), bf(--include), and bf(--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 bf(--filter) option, or the bf(--include-from)/bf(--exclude-from) options. manpagesection(INCLUDE/EXCLUDE PATTERN RULES) You can include and exclude files by specifying patterns using the "+", "-", etc. filter rules (as introduced in the FILTER RULES section above). The include/exclude rules each specify a pattern that is matched against the names of the files that are going to be transferred. These patterns can take several forms: itemization( it() if the pattern starts with a / then it is anchored to a particular spot in the hierarchy of files, otherwise it is matched against the end of the pathname. This is similar to a leading ^ in regular expressions. Thus "/foo" would match a name of "foo" at either the "root of the transfer" (for a global rule) or in the merge-file's directory (for a per-directory rule). An unqualified "foo" would match a name of "foo" anywhere in the tree because the algorithm is applied recursively from the top down; it behaves as if each path component gets a turn at being the end of the filename. Even the unanchored "sub/foo" would match at any point in the hierarchy where a "foo" was found within a directory named "sub". 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. it() if the pattern ends with a / then it will only match a directory, not a regular file, symlink, or device. it() rsync chooses between doing a simple string match and wildcard matching by checking if the pattern contains one of these three wildcard characters: '*', '?', and '[' . it() a '*' matches any path component, but it stops at slashes. it() use '**' to match anything, including slashes. it() a '?' matches any character except a slash (/). it() a '[' introduces a character class, such as [a-z] or [[:alpha:]]. it() in a wildcard pattern, a backslash can be used to escape a wildcard character, but it is matched literally when no wildcards are present. This means that there is an extra level of backslash removal when a pattern contains wildcard characters compared to a pattern that has none. e.g. if you add a wildcard to "foo\bar" (which matches the backslash) you would need to use "foo\\bar*" to avoid the "\b" becoming just "b". it() if the pattern contains a / (not counting a trailing /) or a "**", then it is matched against the full pathname, including any leading directories. If the pattern doesn't contain a / or a "**", then it is matched only against the final component of the filename. (Remember that the algorithm is applied recursively so "full filename" can actually be any portion of a path from the starting directory on down.) it() a trailing "dir_name/***" will match both the directory (as if "dir_name/" had been specified) and everything in the directory (as if "dir_name/**" had been specified). This behavior was added in version 2.6.7. ) Note that, when using the bf(--recursive) (bf(-r)) option (which is implied by bf(-a)), every subcomponent of every path is visited from the top down, so include/exclude patterns get applied recursively to each subcomponent's full name (e.g. to include "/foo/bar/baz" the subcomponents "/foo" and "/foo/bar" must not be excluded). The exclude patterns actually short-circuit the directory traversal stage when rsync finds the files to send. If a pattern excludes a particular parent directory, it can render a deeper include pattern ineffectual because rsync did not descend through that excluded section of the hierarchy. This is particularly important when using a trailing '*' rule. For instance, this won't work: quote( tt(+ /some/path/this-file-will-not-be-found)nl() tt(+ /file-is-included)nl() tt(- *)nl() ) This fails because the parent directory "some" is excluded by the '*' rule, so rsync never visits any of the files in the "some" or "some/path" directories. One solution is to ask for all directories in the hierarchy to be included by using a single rule: "+ */" (put it somewhere before the "- *" rule), and perhaps use the bf(--prune-empty-dirs) option. Another solution is to add specific include rules for all the parent dirs that need to be visited. For instance, this set of rules works fine: quote( tt(+ /some/)nl() tt(+ /some/path/)nl() tt(+ /some/path/this-file-is-found)nl() tt(+ /file-also-included)nl() tt(- *)nl() ) Here are some examples of exclude/include matching: itemization( it() "- *.o" would exclude all names matching *.o it() "- /foo" would exclude a file (or directory) named foo in the transfer-root directory it() "- foo/" would exclude any directory named foo it() "- /foo/*/bar" would exclude any file named bar which is at two levels below a directory named foo in the transfer-root directory it() "- /foo/**/bar" would exclude any file named bar two or more levels below a directory named foo in the transfer-root directory it() The combination of "+ */", "+ *.c", and "- *" would include all directories and C source files but nothing else (see also the bf(--prune-empty-dirs) option) it() The combination of "+ foo/", "+ foo/bar.c", and "- *" would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "*") ) The following modifiers are accepted after a "+" or "-": itemization( it() A bf(/) specifies that the include/exclude rule should be matched against the absolute pathname of the current item. For example, "-/ /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. it() A bf(!) specifies that the include/exclude should take effect if the pattern fails to match. For instance, "-! */" would exclude all non-directories. it() A bf(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. it() An bf(s) is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it prevents files from being transferred. The default is for a rule to affect both sides unless bf(--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. it() An bf(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 bf(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. it() A bf(p) indicates that a rule is perishable, meaning that it is ignored in directories that are being deleted. For instance, the bf(-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. ) manpagesection(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: quote( tt(merge /etc/rsync/default.rules)nl() tt(. /etc/rsync/default.rules)nl() tt(dir-merge .per-dir-filter)nl() tt(dir-merge,n- .non-inherited-per-dir-excludes)nl() tt(:n- .non-inherited-per-dir-excludes)nl() ) The following modifiers are accepted after a merge or dir-merge rule: itemization( it() A bf(-) specifies that the file should consist of only exclude patterns, with no other rule-parsing except for in-file comments. it() A bf(+) specifies that the file should consist of only include patterns, with no other rule-parsing except for in-file comments. it() A bf(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. it() A bf(e) will exclude the merge-file name from the transfer; e.g. "dir-merge,e .rules" is like "dir-merge .rules" and "- .rules". it() An bf(n) specifies that the rules are not inherited by subdirectories. it() A bf(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). it() 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 bf(!) 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 bf(s) or bf(r) modifier or both), then the rules in the file must not specify sides (via a modifier or a rule prefix such as bf(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 bf(--filter=". file":) quote( tt(merge /home/user/.global-filter)nl() tt(- *.gz)nl() tt(dir-merge .rules)nl() tt(+ *.[ch])nl() tt(- *.o)nl() ) 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 bf(-F)): quote(tt(--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: quote( tt(rsync -avF /src/path/ /dest/dir)nl() tt(rsync -av --filter=': ../../.rsync-filter' /src/path/ /dest/dir)nl() tt(rsync -av --filter=': .rsync-filter' /src/path/ /dest/dir)nl() ) 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 bf(--cvs-exclude) (bf(-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: quote( tt(cat < 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 bf(-vv) option. At this level of verbosity rsync will show why each individual file is included or excluded. manpagesection(EXIT VALUES) startdit() dit(bf(0)) Success dit(bf(1)) Syntax or usage error dit(bf(2)) Protocol incompatibility dit(bf(3)) Errors selecting input/output files, dirs dit(bf(4)) Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server. dit(bf(5)) Error starting client-server protocol dit(bf(6)) Daemon unable to append to log-file dit(bf(10)) Error in socket I/O dit(bf(11)) Error in file I/O dit(bf(12)) Error in rsync protocol data stream dit(bf(13)) Errors with program diagnostics dit(bf(14)) Error in IPC code dit(bf(20)) Received SIGUSR1 or SIGINT dit(bf(21)) Some error returned by code(waitpid()) dit(bf(22)) Error allocating core memory buffers dit(bf(23)) Partial transfer due to error dit(bf(24)) Partial transfer due to vanished source files dit(bf(25)) The --max-delete limit stopped deletions dit(bf(30)) Timeout in data send/receive dit(bf(35)) Timeout waiting for daemon connection enddit() manpagesection(ENVIRONMENT VARIABLES) startdit() dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any ignore patterns in .cvsignore files. See the bf(--cvs-exclude) option for more details. dit(bf(RSYNC_ICONV)) Specify a default bf(--iconv) setting using this environment variable. (First supported in 3.0.0.) dit(bf(RSYNC_PROTECT_ARGS)) Specify a non-zero numeric value if you want the bf(--protect-args) option to be enabled by default, or a zero value to make sure that it is disabled by default. (First supported in 3.1.0.) dit(bf(RSYNC_RSH)) The RSYNC_RSH 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 bf(-e) option. dit(bf(RSYNC_PROXY)) The RSYNC_PROXY environment variable allows you to redirect your rsync client to use a web proxy when connecting to a rsync daemon. You should set RSYNC_PROXY to a hostname:port pair. dit(bf(RSYNC_PASSWORD)) Setting RSYNC_PASSWORD to the required password allows you to run authenticated rsync connections to an rsync daemon without user intervention. Note that this 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. dit(bf(USER) or bf(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". dit(bf(HOME)) The HOME environment variable is used to find the user's default .cvsignore file. enddit() manpagefiles() /etc/rsyncd.conf or rsyncd.conf manpageseealso() bf(rsyncd.conf)(5) manpagebugs() times are transferred as *nix time_t values When transferring to FAT filesystems rsync may re-sync unmodified files. See the comments on the bf(--modify-window) option. file permissions, devices, etc. are transferred as native numerical values see also the comments on the bf(--delete) option Please report bugs! See the web site at url(http://rsync.samba.org/)(http://rsync.samba.org/) manpagesection(VERSION) This man page is current for version 3.1.2 of rsync. manpagesection(INTERNAL OPTIONS) The options bf(--server) and bf(--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. manpagesection(CREDITS) rsync is distributed under the GNU General Public License. See the file COPYING for details. A WEB site is available at url(http://rsync.samba.org/)(http://rsync.samba.org/). The site includes an FAQ-O-Matic which may cover questions unanswered by this manual page. The primary ftp site for rsync is url(ftp://rsync.samba.org/pub/rsync)(ftp://rsync.samba.org/pub/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. manpagesection(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. manpageauthor() 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 url(http://lists.samba.org)(lists.samba.org) rsync-bpc-3.1.2.1/zlib/0000775000047500004750000000000013510756401013462 5ustar craigcraigrsync-bpc-3.1.2.1/zlib/compress.c0000664000047500004750000000474113510756401015467 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/inffast.h0000664000047500004750000000065313510756401015271 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/trees.h0000664000047500004750000002043013510756401014754 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/crc32.c0000664000047500004750000003156613510756401014555 0ustar craigcraig/* 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; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; 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-bpc-3.1.2.1/zlib/zutil.h0000664000047500004750000001505713510756401015012 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/zlib.h0000664000047500004750000025354313510756401014607 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/zutil.c0000664000047500004750000001706013510756401015001 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/deflate.h0000664000047500004750000003074613510756401015251 0ustar craigcraig/* 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 *l_buf; /* buffer for literals or 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 last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ 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->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (length); \ ush dist = (distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #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-bpc-3.1.2.1/zlib/ChangeLog0000664000047500004750000022516213510756401015244 0ustar craigcraig 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-bpc-3.1.2.1/zlib/adler32.c0000664000047500004750000001155013510756401015064 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/inffast.c0000664000047500004750000003221713510756401015265 0ustar craigcraig/* 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 /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* 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 - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; 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)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(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)); PUP(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)(PUP(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)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(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)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(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 { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(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 { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(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 { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(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 + OFF; strm->next_out = out + OFF; 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-bpc-3.1.2.1/zlib/dummy.in0000664000047500004750000000014613510756401015146 0ustar craigcraigThis is a dummy file to ensure that the lib directory gets created by configure when a VPATH is used. rsync-bpc-3.1.2.1/zlib/zconf.h0000664000047500004750000003622413510756401014761 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/trees.c0000664000047500004750000012633713510756401014764 0ustar craigcraig/* 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->last_lit = 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->last_lit)); 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->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)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++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * 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 lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; 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 d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); 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-bpc-3.1.2.1/zlib/README.rsync0000664000047500004750000000255513510756401015506 0ustar craigcraigREAD 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-bpc-3.1.2.1/zlib/inflate.c0000664000047500004750000015140613510756401015257 0ustar craigcraig/* 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; 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; case COPY_: state->mode = COPY; /* FALL THROUGH */ 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 (0UL - 1) << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } rsync-bpc-3.1.2.1/zlib/gzguts.h0000664000047500004750000001463013510756401015162 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/README0000664000047500004750000001210113510756401014335 0ustar craigcraigZLIB 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-bpc-3.1.2.1/zlib/inftrees.c0000664000047500004750000003134413510756401015452 0ustar craigcraig/* 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 */ int end; /* use base and extra for symbol > end */ 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 */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* 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 ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } 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-bpc-3.1.2.1/zlib/deflate.c0000664000047500004750000021460513510756401015242 0ustar craigcraig/* 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; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ 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 */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); 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->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; 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 ((Bytef *)(s->d_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; ushf *overlay; 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)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; 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->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*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->last_lit) 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->last_lit) 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->last_lit) 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->last_lit) FLUSH_BLOCK(s, 0); return block_done; } rsync-bpc-3.1.2.1/zlib/inflate.h0000664000047500004750000001445313510756401015264 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/inffixed.h0000664000047500004750000001427413510756401015437 0ustar craigcraig /* 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-bpc-3.1.2.1/zlib/crc32.h0000664000047500004750000007354213510756401014562 0ustar craigcraig/* 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-bpc-3.1.2.1/zlib/inftrees.h0000664000047500004750000000556013510756401015460 0ustar craigcraig/* 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-bpc-3.1.2.1/rsync-ssl.in0000775000047500004750000000051613510756401015014 0ustar craigcraig#!/bin/bash # This script supports using stunnel to secure an rsync daemon connection. # Note that this requires at least version 4.x of stunnel. case "$@" in *rsync://*) ;; *::*) ;; *) echo "You must use rsync-ssl with a daemon-style hostname." 0>&1 exit 1 ;; esac exec @bindir@/rsync --rsh=@bindir@/stunnel-rsync "${@}" rsync-bpc-3.1.2.1/csprotocol.txt0000664000047500004750000000617113510756401015457 0ustar craigcraigThis 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 greeting @RSYNCD: . where is the numeric version (see PROTOCOL_VERSION in rsync.h) '.' is a literal period, and is the numeric subprotocol version (see SUBPROTOCOL_VERSION -- it will be 0 for final releases). Protocols prior to 30 only output alone. The daemon expects to see a similar greeting back from the client. For protocols prior to 30, an absent "." value is assumed to be 0. For protocol 30, an absent value is a fatal error. The daemon then follows this 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 where is the username they claim to be, and is the base64 form of the MD4 hash of challenge+password. 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 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-bpc-3.1.2.1/main.c0000664000047500004750000013241713510756407013630 0ustar craigcraig/* * 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-2015 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 "io.h" #if defined CONFIG_LOCALE && defined HAVE_LOCALE_H #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 need_messages_from_generator; extern int kluge_around_eof; extern int got_xfer_error; 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 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 shutting_down; extern int backup_dir_len; extern int basis_dir_cnt; extern struct stats stats; extern char *stdout_format; extern char *logfile_format; extern char *filesfrom_host; extern char *partial_dir; extern char *dest_option; extern char *rsync_path; extern char *shell_cmd; extern char *batch_name; extern char *password_file; extern char *backup_dir; 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; 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_over_rsh = 0; mode_t orig_umask = 0; int batch_gen_fd = -1; int sender_keeps_checksum = 0; /* 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; } /* 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); } /* 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 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), human_dnum((total_written + total_read)/(0.5 + (endtime - starttime)), 2)); 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 HAVE_MALLINFO struct mallinfo mi; mi = mallinfo(); 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()); rprintf(FINFO, " arena: %10ld (bytes from sbrk)\n", (long)mi.arena); rprintf(FINFO, " ordblks: %10ld (chunks not in use)\n", (long)mi.ordblks); rprintf(FINFO, " smblks: %10ld\n", (long)mi.smblks); rprintf(FINFO, " hblks: %10ld (chunks from mmap)\n", (long)mi.hblks); rprintf(FINFO, " hblkhd: %10ld (bytes from mmap)\n", (long)mi.hblkhd); rprintf(FINFO, " allmem: %10ld (bytes from sbrk + mmap)\n", (long)mi.arena + mi.hblkhd); rprintf(FINFO, " usmblks: %10ld\n", (long)mi.usmblks); rprintf(FINFO, " fsmblks: %10ld\n", (long)mi.fsmblks); rprintf(FINFO, " uordblks: %10ld (bytes used)\n", (long)mi.uordblks); rprintf(FINFO, " fordblks: %10ld (bytes free)\n", (long)mi.fordblks); rprintf(FINFO, " keepcost: %10ld (bytes in releasable chunk)\n", (long)mi.keepcost); #endif /* HAVE_MALLINFO */ } /* 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); if (!cmd) goto oom; 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'; } /* 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_over_rsh && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } #else if (user && !(daemon_over_rsh && dash_l_set)) { args[argc++] = "-l"; args[argc++] = user; } args[argc++] = machine; #endif args[argc++] = rsync_path; if (blocking_io < 0) { char *cp; if ((cp = strrchr(cmd, '/')) != NULL) cp++; else cp = cmd; if (strcmp(cp, "rsh") == 0 || strcmp(cp, "remsh") == 0) blocking_io = 1; } server_options(args,&argc); if (argc >= MAX_ARGS - 2) goto arg_overflow; } args[argc++] = "."; if (!daemon_over_rsh) { while (remote_argc > 0) { if (argc >= MAX_ARGS - 1) { arg_overflow: rprintf(FERROR, "internal: args[] overflowed in do_cmd()\n"); exit_cleanup(RERR_SYNTAX); } if (**remote_argv == '-') { if (asprintf(args + argc++, "./%s", *remote_argv++) < 0) out_of_memory("do_cmd"); } else args[argc++] = *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_over_rsh) send_protected_args(*f_out_p, args); } if (need_to_free) free(need_to_free); return pid; oom: out_of_memory("do_cmd"); return 0; /* not reached */ } /* 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; 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; /* Treat an empty string as a copy into the current directory. */ if (!*dest_path) dest_path = "."; 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. */ if ((statret = do_stat(dest_path, &st)) == 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); } cp = strrchr(dest_path, '/'); /* 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 || (cp && !cp[1])) { /* Lop off the final slash (if any). */ if (cp && !cp[1]) *cp = '\0'; if (statret == 0) { rprintf(FERROR, "ERROR: destination path is not a directory\n"); exit_cleanup(RERR_SYNTAX); } if (do_mkdir(dest_path, ACCESSPERMS) != 0) { 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)) 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 (!new) out_of_memory("check_alt_basis_dirs"); 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", dest_option, bdir); else if (!S_ISDIR(st.st_mode)) rprintf(FWARNING, "%s arg is not a dir: %s\n", dest_option, 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 = argv[0]; 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); return; } 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); return; } 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); } 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] = '/'; } 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; bpc_am_generator(am_generator, pid); 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); bpc_sysCall_cleanup(); 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; bpc_am_generator(am_generator, pid); 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 && 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; } 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); 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); } 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 int copy_argv(char *argv[]) { int i; for (i = 0; argv[i]; i++) { if (!(argv[i] = strdup(argv[i]))) { rprintf (FERROR, "out of memory at %s(%d)\n", __FILE__, __LINE__); return RERR_MALLOC; } } return 0; } /* 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; 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. */ if ((ret = copy_argv(argv)) != 0) return ret; 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_over_rsh = shell_cmd ? 1 : -1; } else { /* source is local, check dest arg */ am_sender = 1; if (argc > 1) { p = argv[--argc]; 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; } else { /* hostspec was found, so dest is remote */ argv[argc] = path; if (rsync_port) daemon_over_rsh = 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; } 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; /* For local source, extra source args must not have hostspec. */ for (i = 1; i < argc; i++) { 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; /* 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; } } if (daemon_over_rsh < 0) return start_socket_client(shell_machine, remote_argc, remote_argv, argc, argv); if (password_file && !daemon_over_rsh) { 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])); } 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_over_rsh) { 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)) { 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); } 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; else 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 = system(cmd_buf); if (ret) _exit(ret); } #endif int main(int argc,char *argv[]) { int ret; int orig_argc = argc; char **orig_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 starttime = time(NULL); our_uid = MY_UID(); our_gid = MY_GID(); am_root = our_uid == 0; memset(&stats, 0, sizeof(stats)); 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, ""); #endif if (!parse_arguments(&argc, (const char ***) &argv)) { /* FIXME: We ought to call the same error-handling * code here, rather than relying on getopt. */ option_error(); exit_cleanup(RERR_SYNTAX); } 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 { /* * BackupPC initialization */ extern char *bpc_top_dir; extern char *bpc_host_name; extern char *bpc_share_name; extern int bpc_backup_num; extern int bpc_backup_compress; extern int bpc_backup_prev_num; extern int bpc_backup_prev_compress; extern char *bpc_merge_bkup_info; extern int bpc_backup_inode0; extern int bpc_backup_attrib_new; extern int bpc_log_level; bpc_sysCall_init(bpc_top_dir, bpc_host_name, bpc_share_name, bpc_backup_num, bpc_backup_compress, bpc_backup_prev_num, bpc_backup_prev_compress, bpc_merge_bkup_info, bpc_backup_inode0, bpc_backup_attrib_new, bpc_log_level); } /* 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); init_flist(); if ((write_batch || read_batch) && !am_server) { if (write_batch) write_batch_shell_file(orig_argc, orig_argv, argc); if (read_batch && strcmp(batch_name, "-") == 0) batch_fd = STDIN_FILENO; else { batch_fd = do_open(batch_name, write_batch ? O_WRONLY | O_CREAT | O_TRUNC : 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); } 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-bpc-3.1.2.1/log.c0000664000047500004750000005537313510756407013472 0ustar craigcraig/* * Logging and utility functions. * * Copyright (C) 1998-2001 Andrew Tridgell * Copyright (C) 2000-2001 Martin Pool * Copyright (C) 2003-2015 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 checksum_len; extern int allow_8bit_chars; extern int protocol_version; extern int always_checksum; extern int preserve_times; 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[]; 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() { static int been_here = 0; int options = LOG_PID; if (been_here) return; been_here = 1; #ifdef LOG_NDELAY options |= LOG_NDELAY; #endif #ifdef LOG_DAEMON openlog("rsyncd", options, lp_syslog_facility(module_id)); #else openlog("rsyncd", 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"); } } void log_init(int restart) { if (log_initialised) { if (!restart) return; 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)) 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(); } 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 *buf, int len, int use_isprint, int trailing_CR_or_NL) { const char *s, *end = buf + len; for (s = buf; s < end; s++) { if ((s < end - 4 && *s == '\\' && s[1] == '#' && isDigit(s + 2) && isDigit(s + 3) && isDigit(s + 4)) || (*s != '\t' && ((use_isprint && !isPrint(s)) || *(uchar*)s < ' '))) { if (s != buf && fwrite(buf, s - buf, 1, f) != 1) exit_cleanup(RERR_MESSAGEIO); fprintf(f, "\\#%03o", *(uchar*)s); buf = s + 1; } } if ( trailing_CR_or_NL ) end++; if (buf != end && fwrite(buf, end - buf, 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) { int trailing_CR_or_NL; FILE *f = msgs2stderr ? 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) { if (!am_daemon) { if (code == FLOG) return; goto output_msg; } if (code == FCLIENT) return; 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; if (quiet && code == FINFO) return; if (am_server) { 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) { /* TODO: can we send the error to the user somehow? */ return; } f = stderr; } output_msg: switch (code) { case FERROR_XFER: got_xfer_error = 1; /* FALL THROUGH */ case FERROR: case FERROR_UTF8: case FERROR_SOCKET: case FWARNING: case FINFO: f = stderr; break; case FLOG: case FCLIENT: break; default: fprintf(stderr, "Unknown logcode in rwrite(): %d [%s]\n", (int)code, who_am_i()); exit_cleanup(RERR_MESSAGEIO); } 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); if ( trailing_CR_or_NL ) { INIT_XBUF(inbuf, (char*)buf, len + 1, (size_t)-1); } else { 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) { if ( trailing_CR_or_NL ) { filtered_fwrite(f, convbuf, outbuf.len - 1, 0, trailing_CR_or_NL); } else { filtered_fwrite(f, convbuf, outbuf.len, 0, trailing_CR_or_NL); } outbuf.len = 0; } if (!ierrno || ierrno == E2BIG) continue; fprintf(f, "\\#%03o", CVAL(inbuf.buf, inbuf.pos++)); inbuf.len--; } } else #endif filtered_fwrite(f, buf, len, !allow_8bit_chars, trailing_CR_or_NL); } /* 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; strlcpy(buf, RSYNC_NAME ": ", sizeof buf); len = (sizeof RSYNC_NAME ": ") - 1; 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 = stderr; 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': if (protocol_version >= 30 && (iflags & ITEM_TRANSFER || (always_checksum && S_ISREG(file->mode)))) { const char *sum = iflags & ITEM_TRANSFER ? sender_file_sum : F_SUM(file); n = sum_as_hex(sum); } else { memset(buf2, ' ', checksum_len*2); buf2[checksum_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_times || !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_times ? '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) ? '.' : 'u'; 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 { union file_extras ex[4]; /* just in case... */ struct file_struct file; } x; /* Zero-initialized due to static declaration. */ int len = strlen(fname); const char *fmt; x.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.", &x.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.", &x.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) { if (code == 0) { 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)); } else if (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, file, line, who_am_i(), RSYNC_VERSION); } else { rprintf(FERROR, "rsync error: %s (code %d) at %s(%d) [%s=%s]\n", name, code, file, line, who_am_i(), RSYNC_VERSION); } } } rsync-bpc-3.1.2.1/io.h0000664000047500004750000000241413510756407013311 0ustar craigcraig/* * Copyright (C) 2007-2015 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-bpc-3.1.2.1/rounding.c0000664000047500004750000000234113510756407014521 0ustar craigcraig/* * A pre-compilation helper program to aid in the creation of rounding.h. * * Copyright (C) 2007-2015 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]; struct file_struct file; }; #define ACTUAL_SIZE SIZEOF(struct test) #define EXPECTED_SIZE (SIZEOF(union file_extras) * ARRAY_LEN + SIZEOF(struct file_struct)) 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-bpc-3.1.2.1/config.guess0000664000047500004750000013014513510756401015043 0ustar craigcraig#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-05-16' # 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. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -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-2013 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 trap 'exit 1' 1 2 15 # 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. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { 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) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; 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 ; set_cc_for_build= ;' # 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) >/dev/null 2>&1 ; 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 eval $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'` ;; 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=`(/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 ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $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 # 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/[-_].*/\./'` ;; 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}" 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 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} 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 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; 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.*:*) eval $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) eval $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 eval $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/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` 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:BSD:*) 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 eval $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 eval $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:*:*) eval $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 ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 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 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-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 '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-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` 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:*:*) eval $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 ;; 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 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32: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 ;; 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:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} 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.*:* | i*86:SYSTEM_V: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 configury 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 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc 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 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 ;; *: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. 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 ;; esac eval $set_cc_for_build cat >$dummy.c < # include #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 (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #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 printf ("vax-dec-ultrix\n"); exit (0); # 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; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp 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` /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 exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsync-bpc-3.1.2.1/prepare-source0000775000047500004750000000227013510756401015405 0ustar craigcraig#!/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 config files # fetchgen fetch all the latest dev generated files # 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 -a x"$dir" != x.; then cd "$dir" fi if test $# = 0; then set -- build fi for action in "${@}"; do case "$action" in build|make) make -f prepare-source.mak ;; fetch) if perl --version >/dev/null 2>/dev/null; then files='[ca]*' else files='[cap]*' fi rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/"$files" . ;; fetchgen) rsync -pvz rsync://rsync.samba.org/rsyncftp/generated-files/'*' . ;; fetchSRC) rsync -pvrz --exclude=/.git/ rsync://rsync.samba.org/ftp/pub/unpacked/rsync/ . ;; *) echo "Unknown action: $action" exit 1 esac if test $? = 0; then exit fi done exit 1 rsync-bpc-3.1.2.1/configure.sh0000775000047500004750000105342413510756407015061 0ustar craigcraig#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for rsync_bpc 3.1.2.1. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 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 if test -n "${ZSH_VERSION+set}" && (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 case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; 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 # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # 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 test -z "$as_dir" && as_dir=. 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # 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'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_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="if test -n \"\${ZSH_VERSION+set}\" && (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 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 exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || 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_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else 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 test -z "$as_dir" && as_dir=. 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_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS 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'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: http://rsync.samba.org/bugzilla.html about your system, $0: 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_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=`$as_echo "$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 || $as_echo 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_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_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # 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 $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$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 || $as_echo 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" || { $as_echo "$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 } 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 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-bpc' PACKAGE_TARNAME='rsync-bpc' PACKAGE_VERSION='3.1.2.1' PACKAGE_STRING='rsync_bpc 3.1.2.1' PACKAGE_BUGREPORT='https://github.com/backuppc/rsync-bpc/issues' PACKAGE_URL='' ac_unique_file="byteorder.h" ac_config_libobj_dir=lib # Factoring default headers for most tests. ac_includes_default="\ #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_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_list= ac_subst_vars='LTLIBOBJS STUNNEL4 STUNNEL MAKE_MAN BUILD_ZLIB BUILD_POPT CC_SHOBJ_FLAG OBJ_RESTORE OBJ_SAVE ALLOCA LIBOBJS FAKEROOT_PATH SHELL_PATH HAVE_YODL2MAN HAVE_REMSH PERL MKDIR_P INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM EGREP GREP CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build RSYNC_VERSION 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 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_maintainer_mode with_included_popt with_included_zlib with_protected_args with_rsync_path with_rsyncd_conf with_rsh with_nobody_group enable_largefile enable_ipv6 enable_locale 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' # 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' 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 # Accept the important Cygnus configure options, so we can diagnose typos. 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=`$as_echo "$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=`$as_echo "$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 ;; -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=`$as_echo "$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=`$as_echo "$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. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$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" ;; *) $as_echo "$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 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 || $as_echo 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_bpc 3.1.2.1 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] --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_bpc 3.1.2.1:";; 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 debugging symbols and features --enable-profile turn on CPU profiling --enable-maintainer-mode turn on extra debug features --disable-largefile omit support for large files --disable-ipv6 do not even try to use IPv6 --disable-locale disable locale features --disable-iconv-open disable all use of iconv_open() function --disable-iconv disable rsync's --iconv option --disable-acl-support disable ACL support --disable-xattr-support disable extended attributes Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-included-popt use bundled popt library, not from system --with-included-zlib use bundled zlib library, not from system --with-protected-args make --protected-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-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 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=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$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 guested configure. 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 $as_echo "$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_bpc configure 3.1.2.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 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 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\"" $as_echo "$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 $as_echo "$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_echo "$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_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\"" $as_echo "$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 $as_echo "$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_echo "$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_c_try_run LINENO # ---------------------- # Try to link 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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$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_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$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\"" $as_echo "$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 $as_echo "$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_echo "$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_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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else 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 eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## --------------------------------------------------- ## ## Report this to http://rsync.samba.org/bugzilla.html ## ## --------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # 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 () { 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 () { 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_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.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { 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 () { 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_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.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext 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 () { 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_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext 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 () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { 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 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { 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 () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { 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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { 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 eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else 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. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #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 () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func 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_bpc $as_me 3.1.2.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _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 test -z "$as_dir" && as_dir=. $as_echo "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=`$as_echo "$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=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## 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_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$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 $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$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 $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi as_fn_append ac_header_list " utime.h" # 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,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$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=`$as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`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_config_headers="$ac_config_headers config.h" RSYNC_VERSION=$PACKAGE_VERSION { $as_echo "$as_me:${as_lineno-$LINENO}: Configuring rsync_bpc $PACKAGE_VERSION" >&5 $as_echo "$as_me: Configuring rsync_bpc $PACKAGE_VERSION" >&6;} cat >>confdefs.h <<_ACEOF #define RSYNC_VERSION "$PACKAGE_VERSION" _ACEOF LDFLAGS=${LDFLAGS-""} ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$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. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include debugging symbols" >&5 $as_echo_n "checking whether to include debugging symbols... " >&6; } # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi if test x"$enable_debug" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ac_cv_prog_cc_g=no else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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. $as_echo "$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\"" $as_echo "$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 $as_echo "$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 () { ; 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$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+set}" = set && 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 ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$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_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$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 () { 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$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 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; 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\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$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_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; 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.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*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 don't provoke an error unfortunately, instead are silently treated as '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's necessary to write '\x00'==0 to get something that's 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 **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _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 test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "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 ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-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. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # 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. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # 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 # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$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. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # 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. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # 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 # 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_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. 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+set}" = set; 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$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' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. 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 (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ '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+set}" = set; 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } case $ac_cv_prog_cc_stdc in #( no) : ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __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 your preprocessor is broken; #endif #if BIG_OK #else 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 void 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; float fnumber; 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); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. 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[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 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 test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*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 don't provoke an error unfortunately, instead are silently treated as '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's necessary to write '\x00'==0 to get something that's 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 **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _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 test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 else ac_cv_prog_cc_stdc=no fi fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5 $as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; } if ${ac_cv_prog_cc_stdc+:} false; then : $as_echo_n "(cached) " >&6 fi case $ac_cv_prog_cc_stdc in #( no) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; #( '') : { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5 $as_echo "$ac_cv_prog_cc_stdc" >&6; } ;; esac # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PERL+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 $as_echo "$PERL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi $as_echo "#define _GNU_SOURCE 1" >>confdefs.h if test x"$ac_cv_prog_cc_stdc" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: rsync requires an ANSI C compiler and you do not seem to have one" >&5 $as_echo "$as_me: WARNING: rsync requires an ANSI C compiler and you do not seem to have one" >&2;} fi # Check whether --enable-profile was given. if test "${enable_profile+set}" = set; then : enableval=$enable_profile; fi if test x"$enable_profile" = x"yes"; then CFLAGS="$CFLAGS -pg" fi # Specifically, this turns on panic_action handling. # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; 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-included-popt was given. if test "${with_included_popt+set}" = set; then : withval=$with_included_popt; fi # Check whether --with-included-zlib was given. if test "${with_included_zlib+set}" = set; then : withval=$with_included_zlib; fi # Check whether --with-protected-args was given. if test "${with_protected_args+set}" = set; then : withval=$with_protected_args; fi if test x"$with_protected_args" = x"yes"; then cat >>confdefs.h <<_ACEOF #define RSYNC_USE_PROTECTED_ARGS 1 _ACEOF fi # Check whether --with-rsync-path was given. if test "${with_rsync_path+set}" = set; then : withval=$with_rsync_path; RSYNC_PATH="$with_rsync_path" else RSYNC_PATH="rsync_bpc" fi cat >>confdefs.h <<_ACEOF #define RSYNC_PATH "$RSYNC_PATH" _ACEOF # Check whether --with-rsyncd-conf was given. if test "${with_rsyncd_conf+set}" = set; 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 RSYNCD_SYSCONF="/etc/rsyncd.conf" fi cat >>confdefs.h <<_ACEOF #define RSYNCD_SYSCONF "$RSYNCD_SYSCONF" _ACEOF # Check whether --with-rsh was given. if test "${with_rsh+set}" = set; 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_HAVE_REMSH+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_REMSH" >&5 $as_echo "$HAVE_REMSH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test x$HAVE_REMSH = x1; then $as_echo "#define HAVE_REMSH 1" >>confdefs.h fi if test x"$with_rsh" != x; then RSYNC_RSH="$with_rsh" else RSYNC_RSH="ssh" fi cat >>confdefs.h <<_ACEOF #define RSYNC_RSH "$RSYNC_RSH" _ACEOF # Extract the first word of "yodl2man", so it can be a program name with args. set dummy yodl2man; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_HAVE_YODL2MAN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$HAVE_YODL2MAN"; then ac_cv_prog_HAVE_YODL2MAN="$HAVE_YODL2MAN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. 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_YODL2MAN="1" $as_echo "$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_YODL2MAN" && ac_cv_prog_HAVE_YODL2MAN="0" fi fi HAVE_YODL2MAN=$ac_cv_prog_HAVE_YODL2MAN if test -n "$HAVE_YODL2MAN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_YODL2MAN" >&5 $as_echo "$HAVE_YODL2MAN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SHELL_PATH+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SHELL_PATH" >&5 $as_echo "$SHELL_PATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fakeroot", so it can be a program name with args. set dummy fakeroot; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_FAKEROOT_PATH+:} false; then : $as_echo_n "(cached) " >&6 else 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 test -z "$as_dir" && as_dir=. 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" $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FAKEROOT_PATH" >&5 $as_echo "$FAKEROOT_PATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --with-nobody-group was given. if test "${with_nobody_group+set}" = set; then : withval=$with_nobody_group; NOBODY_GROUP="$with_nobody_group" fi if test x"$with_nobody_group" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking the group for user \"nobody\"" >&5 $as_echo_n "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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NOBODY_GROUP" >&5 $as_echo "$NOBODY_GROUP" >&6; } fi cat >>confdefs.h <<_ACEOF #define NOBODY_USER "nobody" _ACEOF cat >>confdefs.h <<_ACEOF #define NOBODY_GROUP "$NOBODY_GROUP" _ACEOF # arrgh. libc in some old debian version screwed up the largefile # stuff, getting byte range locking wrong { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken largefile support" >&5 $as_echo_n "checking for broken largefile support... " >&6; } if ${rsync_cv_HAVE_BROKEN_LARGEFILE+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_HAVE_BROKEN_LARGEFILE=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include 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); exit(WEXITSTATUS(status)); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_HAVE_BROKEN_LARGEFILE=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_BROKEN_LARGEFILE" >&5 $as_echo "$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+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext 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 break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { ; 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.$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 () { ; 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.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { ; 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.$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 () { ; 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.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi fi ipv6type=unknown ipv6lib=none ipv6trylibc=yes # Check whether --enable-ipv6 was given. if test "${enable_ipv6+set}" = set; then : enableval=$enable_ipv6; fi if test x"$enable_ipv6" != x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking ipv6 stack type" >&5 $as_echo_n "checking ipv6 stack type... " >&6; } for i in inria kame linux-glibc linux-inet6 solaris toshiba v6d zeta cygwin; do case $i in inria) # http://www.kame.net/ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef IPV6_INRIA_VERSION yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; kame) # http://www.kame.net/ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef __KAME__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; linux-glibc) # http://www.v6.linux.or.jp/ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; linux-inet6) # http://www.v6.linux.or.jp/ if test -d /usr/inet6 -o -f /usr/inet6/lib/libinet6.a; then ipv6type=$i ipv6lib=inet6 ipv6libdir=/usr/inet6/lib ipv6trylibc=yes; $as_echo "#define INET6 1" >>confdefs.h CFLAGS="-I/usr/inet6/include $CFLAGS" fi ;; solaris) # http://www.sun.com cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef __sun yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; toshiba) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef _TOSHIBA_INET6 yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; v6d) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef __V6D__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; ipv6lib=v6; ipv6libdir=/usr/local/v6/lib; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; zeta) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef _ZETA_MINAMI_INET6 yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; ipv6lib=inet6; ipv6libdir=/usr/local/v6/lib; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; cygwin) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef _CYGWIN_IN6_H yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : ipv6type=$i; $as_echo "#define INET6 1" >>confdefs.h fi rm -f conftest* ;; esac if test "$ipv6type" != "unknown"; then break fi done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ipv6type" >&5 $as_echo "$ipv6type" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getaddrinfo" >&5 $as_echo_n "checking for library containing getaddrinfo... " >&6; } if ${ac_cv_search_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo (); int main () { return getaddrinfo (); ; return 0; } _ACEOF for ac_lib in '' inet6; 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_getaddrinfo=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getaddrinfo+:} false; then : break fi done if ${ac_cv_search_getaddrinfo+:} false; then : else ac_cv_search_getaddrinfo=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getaddrinfo" >&5 $as_echo "$ac_cv_search_getaddrinfo" >&6; } ac_res=$ac_cv_search_getaddrinfo if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi # Check whether --enable-locale was given. if test "${enable_locale+set}" = set; then : enableval=$enable_locale; fi if test x"$enable_locale" != x"no"; then $as_echo "#define CONFIG_LOCALE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to call shutdown on all sockets" >&5 $as_echo_n "checking whether to call shutdown on all sockets... " >&6; } case $host_os in *cygwin* ) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define SHUTDOWN_ALL_SOCKETS 1" >>confdefs.h ;; * ) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; };; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=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 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else 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.$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 () { #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 () { #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 ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext 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 () { #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 () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext 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. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; 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 () { 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.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#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=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { 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$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { 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$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { 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 ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi for ac_header in sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \ unistd.h utime.h grp.h compat.h sys/param.h ctype.h sys/wait.h \ sys/ioctl.h sys/filio.h string.h stdlib.h sys/socket.h sys/mode.h \ sys/un.h sys/attr.h mcheck.h arpa/inet.h arpa/nameser.h locale.h \ netdb.h malloc.h float.h limits.h iconv.h libcharset.h langinfo.h \ sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h \ popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netinet/ip.h \ zlib.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 $as_echo_n "checking whether sys/types.h defines makedev... " >&6; } if ${ac_cv_header_sys_types_h_makedev+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { return makedev(0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_header_sys_types_h_makedev=yes else ac_cv_header_sys_types_h_makedev=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 $as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } if test $ac_cv_header_sys_types_h_makedev = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : $as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h fi if test $ac_cv_header_sys_mkdev_h = no; then ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : $as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if makedev takes 3 args" >&5 $as_echo_n "checking if makedev takes 3 args... " >&6; } if ${rsync_cv_MAKEDEV_TAKES_3_ARGS+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_MAKEDEV_TAKES_3_ARGS=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #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) exit(1); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_MAKEDEV_TAKES_3_ARGS=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MAKEDEV_TAKES_3_ARGS" >&5 $as_echo "$rsync_cv_MAKEDEV_TAKES_3_ARGS" >&6; } if test x"$rsync_cv_MAKEDEV_TAKES_3_ARGS" = x"yes"; then $as_echo "#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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : else if test "$ac_cv_type_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 $as_echo "$ac_cv_sizeof_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 $as_echo "$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 $as_echo "$ac_cv_sizeof_long_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : else if test "$ac_cv_type_short" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 $as_echo "$ac_cv_sizeof_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int16_t" >&5 $as_echo_n "checking size of int16_t... " >&6; } if ${ac_cv_sizeof_int16_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int16_t))" "ac_cv_sizeof_int16_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int16_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int16_t" >&5 $as_echo "$ac_cv_sizeof_int16_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT16_T $ac_cv_sizeof_int16_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint16_t" >&5 $as_echo_n "checking size of uint16_t... " >&6; } if ${ac_cv_sizeof_uint16_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint16_t))" "ac_cv_sizeof_uint16_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint16_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint16_t" >&5 $as_echo "$ac_cv_sizeof_uint16_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT16_T $ac_cv_sizeof_uint16_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int32_t" >&5 $as_echo_n "checking size of int32_t... " >&6; } if ${ac_cv_sizeof_int32_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int32_t))" "ac_cv_sizeof_int32_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int32_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int32_t" >&5 $as_echo "$ac_cv_sizeof_int32_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT32_T $ac_cv_sizeof_int32_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of uint32_t" >&5 $as_echo_n "checking size of uint32_t... " >&6; } if ${ac_cv_sizeof_uint32_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (uint32_t))" "ac_cv_sizeof_uint32_t" "$ac_includes_default"; then : else if test "$ac_cv_type_uint32_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_uint32_t" >&5 $as_echo "$ac_cv_sizeof_uint32_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_UINT32_T $ac_cv_sizeof_uint32_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int64_t" >&5 $as_echo_n "checking size of int64_t... " >&6; } if ${ac_cv_sizeof_int64_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int64_t))" "ac_cv_sizeof_int64_t" "$ac_includes_default"; then : else if test "$ac_cv_type_int64_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int64_t" >&5 $as_echo "$ac_cv_sizeof_int64_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT64_T $ac_cv_sizeof_int64_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off_t" >&5 $as_echo_n "checking size of off_t... " >&6; } if ${ac_cv_sizeof_off_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off_t))" "ac_cv_sizeof_off_t" "$ac_includes_default"; then : else if test "$ac_cv_type_off_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off_t" >&5 $as_echo "$ac_cv_sizeof_off_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_OFF_T $ac_cv_sizeof_off_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of off64_t" >&5 $as_echo_n "checking size of off64_t... " >&6; } if ${ac_cv_sizeof_off64_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (off64_t))" "ac_cv_sizeof_off64_t" "$ac_includes_default"; then : else if test "$ac_cv_type_off64_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_off64_t" >&5 $as_echo "$ac_cv_sizeof_off64_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_OFF64_T $ac_cv_sizeof_off64_t _ACEOF # 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5 $as_echo_n "checking size of time_t... " >&6; } if ${ac_cv_sizeof_time_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t" "$ac_includes_default"; then : else if test "$ac_cv_type_time_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5 $as_echo "$ac_cv_sizeof_time_t" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_TIME_T $ac_cv_sizeof_time_t _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else 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 () {return 0; } $ac_kw foo_t foo () {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.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5 $as_echo_n "checking for long double with more range or precision than double... " >&6; } if ${ac_cv_type_long_double_wider+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { 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 ac_cv_type_long_double_wider=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double_wider" >&5 $as_echo "$ac_cv_type_long_double_wider" >&6; } if test $ac_cv_type_long_double_wider = yes; then $as_echo "#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 $as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if ${ac_cv_type_uid_t+:} false; then : $as_echo_n "(cached) " >&6 else 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 ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then $as_echo "#define uid_t int" >>confdefs.h $as_echo "#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 : cat >>confdefs.h <<_ACEOF #define HAVE_MODE_T 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_OFF_T 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_SIZE_T 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_PID_T 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_ID_T 1 _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5 $as_echo_n "checking type of array argument to getgroups... " >&6; } if ${ac_cv_type_getgroups+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_type_getgroups=cross else 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 () { 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 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 ac_cv_type_getgroups=int fi rm -f conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_getgroups" >&5 $as_echo "$ac_cv_type_getgroups" >&6; } cat >>confdefs.h <<_ACEOF #define GETGROUPS_T $ac_cv_type_getgroups _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_RDEV 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 _ACEOF 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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 _ACEOF 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_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t equivalent" >&5 $as_echo_n "checking for socklen_t equivalent... " >&6; } if ${rsync_cv_socklen_t_equiv+:} false; then : $as_echo_n "(cached) " >&6 else # 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 () { $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.$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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_socklen_t_equiv" >&5 $as_echo "$rsync_cv_socklen_t_equiv" >&6; } cat >>confdefs.h <<_ACEOF #define socklen_t $rsync_cv_socklen_t_equiv _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for errno in errno.h" >&5 $as_echo_n "checking for errno in errno.h... " >&6; } if ${rsync_cv_errno+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int i = errno ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : rsync_cv_errno=yes else rsync_cv_have_errno_decl=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_errno" >&5 $as_echo "$rsync_cv_errno" >&6; } if test x"$rsync_cv_errno" = x"yes"; then $as_echo "#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. for ac_func in connect do : ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CONNECT 1 _ACEOF fi done if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl_s" >&5 $as_echo_n "checking for printf in -lnsl_s... " >&6; } if ${ac_cv_lib_nsl_s_printf+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char printf (); int main () { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_s_printf=yes else ac_cv_lib_nsl_s_printf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_s_printf" >&5 $as_echo "$ac_cv_lib_nsl_s_printf" >&6; } if test "x$ac_cv_lib_nsl_s_printf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL_S 1 _ACEOF LIBS="-lnsl_s $LIBS" fi ;; esac case "$LIBS" in *-lnsl*) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl" >&5 $as_echo_n "checking for printf in -lnsl... " >&6; } if ${ac_cv_lib_nsl_printf+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char printf (); int main () { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_printf=yes else ac_cv_lib_nsl_printf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_printf" >&5 $as_echo "$ac_cv_lib_nsl_printf" >&6; } if test "x$ac_cv_lib_nsl_printf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi ;; esac case "$LIBS" in *-lsocket*) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi ;; esac case "$LIBS" in *-linet*) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -linet" >&5 $as_echo_n "checking for connect in -linet... " >&6; } if ${ac_cv_lib_inet_connect+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_inet_connect=yes else ac_cv_lib_inet_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_connect" >&5 $as_echo "$ac_cv_lib_inet_connect" >&6; } if test "x$ac_cv_lib_inet_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBINET 1 _ACEOF 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 $as_echo "#define HAVE_CONNECT 1" >>confdefs.h fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_ntop" >&5 $as_echo_n "checking for library containing inet_ntop... " >&6; } if ${ac_cv_search_inet_ntop+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char inet_ntop (); int main () { 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$ac_exeext if ${ac_cv_search_inet_ntop+:} false; then : break fi done if ${ac_cv_search_inet_ntop+:} false; then : else ac_cv_search_inet_ntop=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_ntop" >&5 $as_echo "$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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing iconv_open" >&5 $as_echo_n "checking for library containing iconv_open... " >&6; } if ${ac_cv_search_iconv_open+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char iconv_open (); int main () { 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$ac_exeext if ${ac_cv_search_iconv_open+:} false; then : break fi done if ${ac_cv_search_iconv_open+:} false; then : else ac_cv_search_iconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_iconv_open" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing libiconv_open" >&5 $as_echo_n "checking for library containing libiconv_open... " >&6; } if ${ac_cv_search_libiconv_open+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char libiconv_open (); int main () { 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$ac_exeext if ${ac_cv_search_libiconv_open+:} false; then : break fi done if ${ac_cv_search_libiconv_open+:} false; then : else ac_cv_search_libiconv_open=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_libiconv_open" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 $as_echo_n "checking for iconv declaration... " >&6; } if ${am_cv_proto_iconv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #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 () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_cv_proto_iconv_arg1="" else am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext 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 -e 's/( /(/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_t:- }$am_cv_proto_iconv" >&5 $as_echo "${ac_t:- }$am_cv_proto_iconv" >&6; } cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF ac_fn_c_check_func "$LINENO" "inet_ntop" "ac_cv_func_inet_ntop" if test "x$ac_cv_func_inet_ntop" = xyes; then : $as_echo "#define HAVE_INET_NTOP 1" >>confdefs.h else 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 : $as_echo "#define HAVE_INET_PTON 1" >>confdefs.h else case " $LIBOBJS " in *" inet_pton.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS inet_pton.$ac_objext" ;; esac fi cv=`echo "struct addrinfo" | sed 'y%./+- %__p__%'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct addrinfo" >&5 $as_echo_n "checking for struct addrinfo... " >&6; } if eval \${ac_cv_type_$cv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include int main () { struct addrinfo foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ac_cv_type_$cv=yes" else eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 $as_echo "$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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_ADDRINFO 1 _ACEOF fi fi cat >>confdefs.h <<_ACEOF #define $ac_tr_hdr 1 _ACEOF fi cv=`echo "struct sockaddr_storage" | sed 'y%./+- %__p__%'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5 $as_echo_n "checking for struct sockaddr_storage... " >&6; } if eval \${ac_cv_type_$cv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include #include int main () { struct sockaddr_storage foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ac_cv_type_$cv=yes" else eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 $as_echo "$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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_SOCKADDR_STORAGE 1 _ACEOF fi fi cat >>confdefs.h <<_ACEOF #define $ac_tr_hdr 1 _ACEOF fi # Irix 6.5 has getaddrinfo but not the corresponding defines, so use # builtin getaddrinfo if one of the defines don't exist { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether defines needed by getaddrinfo exist" >&5 $as_echo_n "checking whether defines needed by getaddrinfo exist... " >&6; } if ${rsync_cv_HAVE_GETADDR_DEFINES+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #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 rsync_cv_HAVE_GETADDR_DEFINES=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_GETADDR_DEFINES" >&5 $as_echo "$rsync_cv_HAVE_GETADDR_DEFINES" >&6; } if test x"$rsync_cv_HAVE_GETADDR_DEFINES" = x"yes" -a 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 : cat >>confdefs.h <<_ACEOF #define HAVE_GETADDRINFO 1 _ACEOF else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo by including " >&5 $as_echo_n "checking for getaddrinfo by including ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { getaddrinfo(NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } case " $LIBOBJS " in *" getaddrinfo.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext" ;; esac fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi done else 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" " #include #include " if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : $as_echo "#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" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_in_sin_len" = xyes; then : $as_echo "#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" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes; then : $as_echo "#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" " #include #include #include " if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes; then : $as_echo "#define HAVE_SOCKADDR_IN6_SCOPE_ID 1" >>confdefs.h fi cv=`echo "struct stat64" | sed 'y%./+- %__p__%'` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 $as_echo_n "checking for struct stat64... " >&6; } if eval \${ac_cv_type_$cv+:} false; then : $as_echo_n "(cached) " >&6 else 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 () { struct stat64 foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "ac_cv_type_$cv=yes" else eval "ac_cv_type_$cv=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_foo=`eval echo \\$ac_cv_type_$cv` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_foo" >&5 $as_echo "$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 : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT64 1 _ACEOF fi fi cat >>confdefs.h <<_ACEOF #define $ac_tr_hdr 1 _ACEOF fi # if we can't find strcasecmp, look in -lresolv (for Unixware at least) # for ac_func in strcasecmp do : ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRCASECMP 1 _ACEOF fi done if test x"$ac_cv_func_strcasecmp" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lresolv" >&5 $as_echo_n "checking for strcasecmp in -lresolv... " >&6; } if ${ac_cv_lib_resolv_strcasecmp+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char strcasecmp (); int main () { return strcasecmp (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_resolv_strcasecmp=yes else ac_cv_lib_resolv_strcasecmp=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_strcasecmp" >&5 $as_echo "$ac_cv_lib_resolv_strcasecmp" >&6; } if test "x$ac_cv_lib_resolv_strcasecmp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi fi for ac_func in aclsort do : ac_fn_c_check_func "$LINENO" "aclsort" "ac_cv_func_aclsort" if test "x$ac_cv_func_aclsort" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ACLSORT 1 _ACEOF fi done if test x"$ac_cv_func_aclsort" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for aclsort in -lsec" >&5 $as_echo_n "checking for aclsort in -lsec... " >&6; } if ${ac_cv_lib_sec_aclsort+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char aclsort (); int main () { return aclsort (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sec_aclsort=yes else ac_cv_lib_sec_aclsort=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sec_aclsort" >&5 $as_echo "$ac_cv_lib_sec_aclsort" >&6; } if test "x$ac_cv_lib_sec_aclsort" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSEC 1 _ACEOF LIBS="-lsec $LIBS" fi fi for ac_header in $ac_header_list do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether utime accepts a null argument" >&5 $as_echo_n "checking whether utime accepts a null argument... " >&6; } if ${ac_cv_func_utime_null+:} false; then : $as_echo_n "(cached) " >&6 else 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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifdef HAVE_UTIME_H # include #endif int main () { 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_utime_null" >&5 $as_echo "$ac_cv_func_utime_null" >&6; } if test "x$ac_cv_func_utime_null" != xno; then ac_cv_func_utime_null=yes $as_echo "#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 cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } if ${ac_cv_working_alloca_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { 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 ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 $as_echo "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 $as_echo_n "checking for alloca... " >&6; } if ${ac_cv_func_alloca_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (size_t); # endif # endif # endif # endif #endif int main () { 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 ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then $as_echo "#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 $as_echo "#define C_ALLOCA 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } if ${ac_cv_os_cray+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined CRAY && ! defined CRAY2 webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then : ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 $as_echo "$ac_cv_os_cray" >&6; } if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 $as_echo_n "checking stack direction for C alloca... " >&6; } if ${ac_cv_c_stack_direction+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_c_stack_direction=0 else 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 $as_echo "$ac_cv_c_stack_direction" >&6; } cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi for ac_func in waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \ fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \ memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \ strlcat strlcpy strtol mallinfo 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 usleep do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done 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; $as_echo "#define HAVE_ICONV_OPEN 1" >>confdefs.h fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for useable fallocate" >&5 $as_echo_n "checking for useable fallocate... " >&6; } if ${rsync_cv_have_fallocate+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { fallocate(0, 0, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : rsync_cv_have_fallocate=yes else rsync_cv_have_fallocate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_have_fallocate" >&5 $as_echo "$rsync_cv_have_fallocate" >&6; } if test x"$rsync_cv_have_fallocate" = x"yes"; then $as_echo "#define HAVE_FALLOCATE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYS_fallocate" >&5 $as_echo_n "checking for SYS_fallocate... " >&6; } if ${rsync_cv_have_sys_fallocate+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { 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 rsync_cv_have_sys_fallocate=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_have_sys_fallocate" >&5 $as_echo "$rsync_cv_have_sys_fallocate" >&6; } if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then $as_echo "#define HAVE_SYS_FALLOCATE 1" >>confdefs.h fi if test x"$ac_cv_func_posix_fallocate" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_fallocate is efficient" >&5 $as_echo_n "checking whether posix_fallocate is efficient... " >&6; } case $host_os in *cygwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_EFFICIENT_POSIX_FALLOCATE 1" >>confdefs.h ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi for ac_func in getpgrp tcgetpgrp do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test $ac_cv_func_getpgrp = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether getpgrp requires zero arguments" >&5 $as_echo_n "checking whether getpgrp requires zero arguments... " >&6; } if ${ac_cv_func_getpgrp_void+:} false; then : $as_echo_n "(cached) " >&6 else # Use it with a single arg. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { getpgrp (0); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_getpgrp_void=no else ac_cv_func_getpgrp_void=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_getpgrp_void" >&5 $as_echo "$ac_cv_func_getpgrp_void" >&6; } if test $ac_cv_func_getpgrp_void = yes; then $as_echo "#define GETPGRP_VOID 1" >>confdefs.h fi fi # Check whether --enable-iconv-open was given. if test "${enable_iconv_open+set}" = set; then : enableval=$enable_iconv_open; else enable_iconv_open=$ac_cv_func_iconv_open fi if test x"$enable_iconv_open" != x"no"; then $as_echo "#define USE_ICONV_OPEN 1" >>confdefs.h fi # Check whether --enable-iconv was given. if test "${enable_iconv+set}" = set; then : enableval=$enable_iconv; else enable_iconv=$enable_iconv_open fi if test x"$enable_iconv" != x"no"; then if test x"$enable_iconv" = x"yes"; then $as_echo "#define ICONV_OPTION NULL" >>confdefs.h else cat >>confdefs.h <<_ACEOF #define ICONV_OPTION "$enable_iconv" _ACEOF fi $as_echo "#define UTF8_CHARSET \"UTF-8\"" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether chown() modifies symlinks" >&5 $as_echo_n "checking whether chown() modifies symlinks... " >&6; } if ${rsync_cv_chown_modifies_symlink+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_chown_modifies_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif #include #include main() { 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) exit(1); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_chown_modifies_symlink=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_chown_modifies_symlink" >&5 $as_echo "$rsync_cv_chown_modifies_symlink" >&6; } if test $rsync_cv_chown_modifies_symlink = yes; then $as_echo "#define CHOWN_MODIFIES_SYMLINK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether link() can hard-link symlinks" >&5 $as_echo_n "checking whether link() can hard-link symlinks... " >&6; } if ${rsync_cv_can_hardlink_symlink+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_can_hardlink_symlink=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif #include #include #define FILENAME "conftest.dangle" main() { unlink(FILENAME); if (symlink("conftest.no-such", FILENAME) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) exit(1); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_can_hardlink_symlink=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_can_hardlink_symlink" >&5 $as_echo "$rsync_cv_can_hardlink_symlink" >&6; } if test $rsync_cv_can_hardlink_symlink = yes; then $as_echo "#define CAN_HARDLINK_SYMLINK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether link() can hard-link special files" >&5 $as_echo_n "checking whether link() can hard-link special files... " >&6; } if ${rsync_cv_can_hardlink_special+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_can_hardlink_special=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include #endif #include #include #define FILENAME "conftest.fifi" main() { unlink(FILENAME); if (mkfifo(FILENAME, 0777) < 0) abort(); unlink(FILENAME "2"); if (link(FILENAME, FILENAME "2") < 0) exit(1); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_can_hardlink_special=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_can_hardlink_special" >&5 $as_echo "$rsync_cv_can_hardlink_special" >&6; } if test $rsync_cv_can_hardlink_special = yes; then $as_echo "#define CAN_HARDLINK_SPECIAL 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working socketpair" >&5 $as_echo_n "checking for working socketpair... " >&6; } if ${rsync_cv_HAVE_SOCKETPAIR+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_HAVE_SOCKETPAIR=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include main() { int fd[2]; exit((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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_SOCKETPAIR" >&5 $as_echo "$rsync_cv_HAVE_SOCKETPAIR" >&6; } if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then $as_echo "#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 : $as_echo "#define HAVE_GETPASS 1" >>confdefs.h else case " $LIBOBJS " in *" getpass.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getpass.$ac_objext" ;; esac fi if test x"$with_included_popt" != x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for poptGetContext in -lpopt" >&5 $as_echo_n "checking for poptGetContext in -lpopt... " >&6; } if ${ac_cv_lib_popt_poptGetContext+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char poptGetContext (); int main () { return poptGetContext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_popt_poptGetContext=yes else ac_cv_lib_popt_poptGetContext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_popt_poptGetContext" >&5 $as_echo "$ac_cv_lib_popt_poptGetContext" >&6; } if test "x$ac_cv_lib_popt_poptGetContext" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPOPT 1 _ACEOF LIBS="-lpopt $LIBS" else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use included libpopt" >&5 $as_echo_n "checking whether to use included libpopt... " >&6; } if test x"$with_included_popt" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $srcdir/popt" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&5 $as_echo "$as_me: WARNING: included libpopt will use malloc, not alloca (which wastes a small amount of memory)" >&2;} fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for deflateParams in -lz" >&5 $as_echo_n "checking for deflateParams in -lz... " >&6; } if ${ac_cv_lib_z_deflateParams+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char deflateParams (); int main () { return deflateParams (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_deflateParams=yes else ac_cv_lib_z_deflateParams=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflateParams" >&5 $as_echo "$ac_cv_lib_z_deflateParams" >&6; } if test "x$ac_cv_lib_z_deflateParams" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" else with_included_zlib=yes fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use included zlib" >&5 $as_echo_n "checking whether to use included zlib... " >&6; } if test x"$with_included_zlib" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $srcdir/zlib" >&5 $as_echo "$srcdir/zlib" >&6; } BUILD_ZLIB='$(zlib_OBJS)' CFLAGS="-I$srcdir/zlib $CFLAGS" else $as_echo "#define EXTERNAL_ZLIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned char" >&5 $as_echo_n "checking for unsigned char... " >&6; } if ${rsync_cv_SIGNED_CHAR_OK+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { signed char *s = "" ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : rsync_cv_SIGNED_CHAR_OK=yes else rsync_cv_SIGNED_CHAR_OK=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_SIGNED_CHAR_OK" >&5 $as_echo "$rsync_cv_SIGNED_CHAR_OK" >&6; } if test x"$rsync_cv_SIGNED_CHAR_OK" = x"yes"; then $as_echo "#define SIGNED_CHAR_OK 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken readdir" >&5 $as_echo_n "checking for broken readdir... " >&6; } if ${rsync_cv_HAVE_BROKEN_READDIR+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_HAVE_BROKEN_READDIR=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include main() { 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) exit(0); exit(1);} _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_HAVE_BROKEN_READDIR=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_BROKEN_READDIR" >&5 $as_echo "$rsync_cv_HAVE_BROKEN_READDIR" >&6; } if test x"$rsync_cv_HAVE_BROKEN_READDIR" = x"yes"; then $as_echo "#define HAVE_BROKEN_READDIR 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utimbuf" >&5 $as_echo_n "checking for utimbuf... " >&6; } if ${rsync_cv_HAVE_STRUCT_UTIMBUF+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; exit(utime("foo.c",&tbuf)); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : rsync_cv_HAVE_STRUCT_UTIMBUF=yes else rsync_cv_HAVE_STRUCT_UTIMBUF=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_STRUCT_UTIMBUF" >&5 $as_echo "$rsync_cv_HAVE_STRUCT_UTIMBUF" >&6; } if test x"$rsync_cv_HAVE_STRUCT_UTIMBUF" = x"yes"; then $as_echo "#define HAVE_STRUCT_UTIMBUF 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if gettimeofday takes tz argument" >&5 $as_echo_n "checking if gettimeofday takes tz argument... " >&6; } if ${rsync_cv_HAVE_GETTIMEOFDAY_TZ+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct timeval tv; exit(gettimeofday(&tv, NULL)); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : rsync_cv_HAVE_GETTIMEOFDAY_TZ=yes else rsync_cv_HAVE_GETTIMEOFDAY_TZ=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&5 $as_echo "$rsync_cv_HAVE_GETTIMEOFDAY_TZ" >&6; } if test x"$rsync_cv_HAVE_GETTIMEOFDAY_TZ" != x"no"; then $as_echo "#define HAVE_GETTIMEOFDAY_TZ 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 vsnprintf" >&5 $as_echo_n "checking for C99 vsnprintf... " >&6; } if ${rsync_cv_HAVE_C99_VSNPRINTF+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_HAVE_C99_VSNPRINTF=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include void foo(const char *format, ...) { va_list ap; int len; char buf[5]; 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); exit(0); } main() { foo("hello"); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_HAVE_C99_VSNPRINTF=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_C99_VSNPRINTF" >&5 $as_echo "$rsync_cv_HAVE_C99_VSNPRINTF" >&6; } if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then $as_echo "#define HAVE_C99_VSNPRINTF 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for secure mkstemp" >&5 $as_echo_n "checking for secure mkstemp... " >&6; } if ${rsync_cv_HAVE_SECURE_MKSTEMP+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_HAVE_SECURE_MKSTEMP=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include main() { struct stat st; char tpl[20]="/tmp/test.XXXXXX"; int fd = mkstemp(tpl); if (fd == -1) exit(1); unlink(tpl); if (fstat(fd, &st) != 0) exit(1); if ((st.st_mode & 0777) != 0600) exit(1); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rsync_cv_HAVE_SECURE_MKSTEMP=yes else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_HAVE_SECURE_MKSTEMP" >&5 $as_echo "$rsync_cv_HAVE_SECURE_MKSTEMP" >&6; } if test x"$rsync_cv_HAVE_SECURE_MKSTEMP" = x"yes"; then case $host_os in hpux*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Skipping broken HP-UX mkstemp() -- using mktemp() instead" >&5 $as_echo "$as_me: WARNING: Skipping broken HP-UX mkstemp() -- using mktemp() instead" >&2;} ;; *) $as_echo "#define HAVE_SECURE_MKSTEMP 1" >>confdefs.h ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if mknod creates FIFOs" >&5 $as_echo_n "checking if mknod creates FIFOs... " >&6; } if ${rsync_cv_MKNOD_CREATES_FIFOS+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_MKNOD_CREATES_FIFOS=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include main() { 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MKNOD_CREATES_FIFOS" >&5 $as_echo "$rsync_cv_MKNOD_CREATES_FIFOS" >&6; } if test x"$rsync_cv_MKNOD_CREATES_FIFOS" = x"yes"; then $as_echo "#define MKNOD_CREATES_FIFOS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if mknod creates sockets" >&5 $as_echo_n "checking if mknod creates sockets... " >&6; } if ${rsync_cv_MKNOD_CREATES_SOCKETS+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : rsync_cv_MKNOD_CREATES_SOCKETS=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include main() { 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_cv_MKNOD_CREATES_SOCKETS" >&5 $as_echo "$rsync_cv_MKNOD_CREATES_SOCKETS" >&6; } if test x"$rsync_cv_MKNOD_CREATES_SOCKETS" = x"yes"; then $as_echo "#define MKNOD_CREATES_SOCKETS 1" >>confdefs.h fi # # The following test was mostly taken from the tcl/tk plus patches # { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -c -o works" >&5 $as_echo_n "checking whether -c -o works... " >&6; } if ${rsync_cv_DASHC_WORKS_WITH_DASHO+:} false; then : $as_echo_n "(cached) " >&6 else rm -rf conftest* cat > conftest.$ac_ext <&5 $as_echo "$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 # Extract the first word of "stunnel", so it can be a program name with args. set dummy stunnel; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_STUNNEL+:} false; then : $as_echo_n "(cached) " >&6 else case $STUNNEL in [\\/]* | ?:[\\/]*) ac_cv_path_STUNNEL="$STUNNEL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. 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_STUNNEL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$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_STUNNEL" && ac_cv_path_STUNNEL="stunnel" ;; esac fi STUNNEL=$ac_cv_path_STUNNEL if test -n "$STUNNEL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STUNNEL" >&5 $as_echo "$STUNNEL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "stunnel4", so it can be a program name with args. set dummy stunnel4; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_STUNNEL4+:} false; then : $as_echo_n "(cached) " >&6 else case $STUNNEL4 in [\\/]* | ?:[\\/]*) ac_cv_path_STUNNEL4="$STUNNEL4" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. 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_STUNNEL4="$as_dir/$ac_word$ac_exec_ext" $as_echo "$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_STUNNEL4" && ac_cv_path_STUNNEL4="$STUNNEL" ;; esac fi STUNNEL4=$ac_cv_path_STUNNEL4 if test -n "$STUNNEL4"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STUNNEL4" >&5 $as_echo "$STUNNEL4" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi for ac_func in _acl __acl _facl __facl do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ################################################# # check for ACL support { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support ACLs" >&5 $as_echo_n "checking whether to support ACLs... " >&6; } # Check whether --enable-acl-support was given. if test "${enable_acl_support+set}" = set; then : enableval=$enable_acl_support; fi if test x"$enable_acl_support" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else case "$host_os" in *sysv5*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using UnixWare ACLs" >&5 $as_echo "Using UnixWare ACLs" >&6; } $as_echo "#define HAVE_UNIXWARE_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; solaris*|*cygwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using solaris ACLs" >&5 $as_echo "Using solaris ACLs" >&6; } $as_echo "#define HAVE_SOLARIS_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; *hpux*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using HPUX ACLs" >&5 $as_echo "Using HPUX ACLs" >&6; } $as_echo "#define HAVE_HPUX_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; *irix*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using IRIX ACLs" >&5 $as_echo "Using IRIX ACLs" >&6; } $as_echo "#define HAVE_IRIX_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; *aix*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using AIX ACLs" >&5 $as_echo "Using AIX ACLs" >&6; } $as_echo "#define HAVE_AIX_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; *osf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using Tru64 ACLs" >&5 $as_echo "Using Tru64 ACLs" >&6; } $as_echo "#define HAVE_TRU64_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h LIBS="$LIBS -lpacl" ;; darwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using OS X ACLs" >&5 $as_echo "Using OS X ACLs" >&6; } $as_echo "#define HAVE_OSX_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: running tests:" >&5 $as_echo "running tests:" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lacl" >&5 $as_echo_n "checking for acl_get_file in -lacl... " >&6; } if ${ac_cv_lib_acl_acl_get_file+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char acl_get_file (); int main () { return acl_get_file (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_acl_acl_get_file=yes else ac_cv_lib_acl_acl_get_file=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_acl_acl_get_file" >&5 $as_echo "$ac_cv_lib_acl_acl_get_file" >&6; } if test "x$ac_cv_lib_acl_acl_get_file" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBACL 1 _ACEOF LIBS="-lacl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ACL support" >&5 $as_echo_n "checking for ACL support... " >&6; } if ${samba_cv_HAVE_POSIX_ACLS+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { 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 samba_cv_HAVE_POSIX_ACLS=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_POSIX_ACLS" >&5 $as_echo "$samba_cv_HAVE_POSIX_ACLS" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking ACL test results" >&5 $as_echo_n "checking ACL test results... " >&6; } if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using posix ACLs" >&5 $as_echo "Using posix ACLs" >&6; } $as_echo "#define HAVE_POSIX_ACLS 1" >>confdefs.h $as_echo "#define SUPPORT_ACLS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_perm_np" >&5 $as_echo_n "checking for acl_get_perm_np... " >&6; } if ${samba_cv_HAVE_ACL_GET_PERM_NP+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { 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 samba_cv_HAVE_ACL_GET_PERM_NP=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $samba_cv_HAVE_ACL_GET_PERM_NP" >&5 $as_echo "$samba_cv_HAVE_ACL_GET_PERM_NP" >&6; } if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then $as_echo "#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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: No ACL support found" >&5 $as_echo "No ACL support found" >&6; } fi fi ;; esac fi ################################################# # check for extended attribute support { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support extended attributes" >&5 $as_echo_n "checking whether to support extended attributes... " >&6; } # Check whether --enable-xattr-support was given. if test "${enable_xattr_support+set}" = set; then : enableval=$enable_xattr_support; else 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else case "$host_os" in *linux*|*netbsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using Linux xattrs" >&5 $as_echo "Using Linux xattrs" >&6; } $as_echo "#define HAVE_LINUX_XATTRS 1" >>confdefs.h $as_echo "#define SUPPORT_XATTRS 1" >>confdefs.h $as_echo "#define NO_SYMLINK_USER_XATTRS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getxattr in -lattr" >&5 $as_echo_n "checking for getxattr in -lattr... " >&6; } if ${ac_cv_lib_attr_getxattr+:} false; then : $as_echo_n "(cached) " >&6 else 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. */ #ifdef __cplusplus extern "C" #endif char getxattr (); int main () { return getxattr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_attr_getxattr=yes else ac_cv_lib_attr_getxattr=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_getxattr" >&5 $as_echo "$ac_cv_lib_attr_getxattr" >&6; } if test "x$ac_cv_lib_attr_getxattr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBATTR 1 _ACEOF LIBS="-lattr $LIBS" fi ;; darwin*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using OS X xattrs" >&5 $as_echo "Using OS X xattrs" >&6; } $as_echo "#define HAVE_OSX_XATTRS 1" >>confdefs.h $as_echo "#define SUPPORT_XATTRS 1" >>confdefs.h $as_echo "#define NO_DEVICE_XATTRS 1" >>confdefs.h $as_echo "#define NO_SPECIAL_XATTRS 1" >>confdefs.h ;; freebsd*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using FreeBSD extattrs" >&5 $as_echo "Using FreeBSD extattrs" >&6; } $as_echo "#define HAVE_FREEBSD_XATTRS 1" >>confdefs.h $as_echo "#define SUPPORT_XATTRS 1" >>confdefs.h ;; solaris*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using Solaris xattrs" >&5 $as_echo "Using Solaris xattrs" >&6; } $as_echo "#define HAVE_SOLARIS_XATTRS 1" >>confdefs.h $as_echo "#define SUPPORT_XATTRS 1" >>confdefs.h $as_echo "#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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: No extended attribute support found" >&5 $as_echo "No extended attribute support found" >&6; } fi ;; esac fi if test x"$enable_acl_support" = x"no" -o x"$enable_xattr_support" = x"no" -o x"$enable_iconv" = x"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-parameter" >&5 $as_echo_n "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 () { printf("hello\n"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : rsync_warn_flag=yes else rsync_warn_flag=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rsync_warn_flag" >&5 $as_echo "$rsync_warn_flag" >&6; } if test x"$rsync_warn_flag" = x"no"; then CFLAGS="$OLD_CFLAGS" fi fi case "$CC" in ' checker'*|checker*) $as_echo "#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_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$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+set}" = set || &/ 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 { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$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=`$as_echo "$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" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$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 if test -n "${ZSH_VERSION+set}" && (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 case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; 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 # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # 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 test -z "$as_dir" && as_dir=. 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # 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 $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$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_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_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 || $as_echo 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 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 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=`$as_echo "$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 || $as_echo 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_bpc $as_me 3.1.2.1, which was generated by GNU Autoconf 2.69. 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 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ rsync_bpc config.status 3.1.2.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 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' 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 ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$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=`$as_echo "$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 ) $as_echo "$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 \$as_echo "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 $as_echo "$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+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || 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=`$as_echo "$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 '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$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 || $as_echo 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=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$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@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$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"; } && { $as_echo "$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 $as_echo "$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 { $as_echo "/* $configure_input */" \ && 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 { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$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 $as_echo "/* $configure_input */" \ && 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 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 $as_echo "" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: rsync_bpc ${RSYNC_VERSION} configuration successful" >&5 $as_echo " rsync_bpc ${RSYNC_VERSION} configuration successful" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 $as_echo "" >&6; } rsync-bpc-3.1.2.1/t_stub.c0000664000047500004750000000445013510756407014177 0ustar craigcraig/* * 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-2015 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 modify_window = 0; int preallocate_files = 0; int protect_args = 0; int module_id = -1; int checksum_len = 0; int relative_paths = 0; int module_dirlen = 0; int preserve_acls = 0; int preserve_times = 0; int preserve_xattrs = 0; 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"; } rsync-bpc-3.1.2.1/compat.c0000664000047500004750000002346013510756407014164 0ustar craigcraig/* * Compatibility routines for older rsync protocol versions. * * Copyright (C) Andrew Tridgell 1996 * Copyright (C) Paul Mackerras 1996 * Copyright (C) 2004-2015 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 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; 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 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_acls; extern int preserve_xattrs; extern int need_messages_from_generator; extern int delete_mode, delete_before, delete_during, delete_after; extern char *shell_cmd; extern char *partial_dir; extern char *dest_option; extern char *files_from; extern char *filesfrom_host; 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 /* These index values are for the file-list's extra-attribute array. */ int 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 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) 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; #if SUBPROTOCOL_VERSION != 0 int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; #else int our_sub = 0; #endif /* 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) { client_info = shell_cmd ? shell_cmd : ""; 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 && !local_server && (strchr(client_info, 'i') == NULL)) allow_inc_recurse = 0; } void setup_protocol(int f_out,int f_in) { if (am_sender) file_extra_cnt += PTR_EXTRA_CNT; else 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 man page 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(); #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", dest_option, 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", dest_option, 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 (local_server || strchr(client_info, 'f') != NULL) compat_flags |= CF_SAFE_FLIST; if (local_server || strchr(client_info, 'x') != NULL) compat_flags |= CF_AVOID_XATTR_OPTIM; if (local_server || strchr(client_info, 'C') != NULL) compat_flags |= CF_CHKSUM_SEED_FIX; write_byte(f_out, compat_flags); } else compat_flags = read_byte(f_in); /* 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; 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 ? local_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; #ifdef CAN_SET_SYMLINK_TIMES } else if (!am_sender) { receiver_symlink_times = 1; #endif } 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 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); } } rsync-bpc-3.1.2.1/configure0000775000047500004750000000135513510756401014435 0ustar craigcraig#!/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` realconfigure="$dir/configure.sh" if test ! -f "$realconfigure"; then if test -f "$HOME/build_farm/build_test.fns"; then # Test the included popt set -- --with-included-popt "${@}" # Allow the build farm to grab latest files via rsync. actions='build fetch' else actions='build' fi if "$dir/prepare-source" $actions; then : else echo 'Failed to build configure.sh and/or config.h.in -- giving up.' >&2 rm -f "$realconfigure" exit 1 fi fi exec "$realconfigure" "${@}" rsync-bpc-3.1.2.1/rsync.c0000664000047500004750000005225413510756407014042 0ustar craigcraig/* * Routines common to more than one of the rsync processes. * * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2003-2015 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_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 inc_recurse; extern int inplace; extern int flist_eof; extern int file_old_total; extern int keep_dirlinks; extern int make_backups; 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 #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); } 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; } 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; } sxp->st.st_uid = uid; sxp->st.st_gid = gid; 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)); } } updated = 1; } #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 (!preserve_times || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode))) flags |= ATTRS_SKIP_MTIME; if (!(flags & ATTRS_SKIP_MTIME) && (sxp->st.st_mtime != file->modtime #ifdef ST_MTIME_NSEC || (NSEC_BUMP(file) && (uint32)sxp->st.ST_MTIME_NSEC != F_MOD_NSEC(file)) #endif )) { int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode); 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 = 1; else 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 = 1; } #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 = 1; } #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) { static int first = 1; if ( first && am_generator ) { /* * Try to kill the receiver, so it can flush it's settings * for us to read. We'll cleanup after the receiver exits. */ kill_all(SIGUSR1); first = 0; return; } first = 0; /* 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; 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 succcess 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) return 1; 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 ? 0 : ATTRS_SKIP_MTIME); /* 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 ? 0 : ATTRS_SKIP_MTIME); 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 */ }