mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-05-25 07:15:35 -04:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
290b615a16 | ||
|
|
57df171bc0 | ||
|
|
f08baea3dd | ||
|
|
2fb139c11b | ||
|
|
3420c8e6e0 | ||
|
|
b17bc22bb3 | ||
|
|
3adffb52e6 | ||
|
|
4df9f36841 | ||
|
|
5c9730a46c | ||
|
|
d9fcc198cf | ||
|
|
c831379436 | ||
|
|
d73ee7b70e | ||
|
|
cda2ae84b3 | ||
|
|
e7d6e0aa0c | ||
|
|
8c9fd200f9 | ||
|
|
79f118d859 | ||
|
|
7b10f91d8f | ||
|
|
3d19b4c83e | ||
|
|
79452d4693 | ||
|
|
cb13abfed0 | ||
|
|
0503f06089 | ||
|
|
f855a7d01a | ||
|
|
4c3b4b2557 |
@@ -24,7 +24,7 @@ LIBOBJ=lib/getopt.o lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o
|
||||
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
|
||||
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
|
||||
zlib/zutil.o zlib/adler32.o
|
||||
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o
|
||||
OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o checksum.o match.o syscall.o log.o backup.o
|
||||
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o fileio.o
|
||||
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
|
||||
OBJS=$(OBJS1) $(OBJS2) $(DAEMON_OBJ) $(LIBOBJ) $(ZLIBOBJ)
|
||||
|
||||
46
backup.c
Normal file
46
backup.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (C) Andrew Tridgell 1999
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* backup handling code */
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
extern int verbose;
|
||||
extern char *backup_suffix;
|
||||
|
||||
|
||||
int make_backup(char *fname)
|
||||
{
|
||||
char fnamebak[MAXPATHLEN];
|
||||
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
|
||||
rprintf(FERROR,"backup filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
slprintf(fnamebak,sizeof(fnamebak),"%s%s",fname,backup_suffix);
|
||||
if (do_rename(fname,fnamebak) != 0) {
|
||||
/* cygwin (at least version b19) reports EINVAL */
|
||||
if (errno != ENOENT && errno != EINVAL) {
|
||||
rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -91,9 +91,9 @@ void file_checksum(char *fname,char *sum,OFF_T size)
|
||||
char tmpchunk[CSUM_CHUNK];
|
||||
struct mdfour m;
|
||||
|
||||
memset(sum,0,csum_length);
|
||||
memset(sum,0,MD4_SUM_LENGTH);
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) return;
|
||||
|
||||
buf = map_file(fd,size);
|
||||
|
||||
@@ -25,6 +25,7 @@ extern int read_only;
|
||||
extern int verbose;
|
||||
extern int rsync_port;
|
||||
char *auth_user;
|
||||
int sanitize_paths = 0;
|
||||
|
||||
int start_socket_client(char *host, char *path, int argc, char *argv[])
|
||||
{
|
||||
@@ -221,6 +222,7 @@ static int rsync_module(int fd, int i)
|
||||
io_printf(fd,"@ERROR: chdir failed\n");
|
||||
return -1;
|
||||
}
|
||||
sanitize_paths = 1;
|
||||
}
|
||||
|
||||
if (am_root) {
|
||||
@@ -262,7 +264,7 @@ static int rsync_module(int fd, int i)
|
||||
request = strdup(p);
|
||||
start_glob++;
|
||||
}
|
||||
glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
|
||||
glob_expand(name, argv, &argc, MAX_ARGS);
|
||||
} else {
|
||||
argc++;
|
||||
}
|
||||
@@ -276,7 +278,7 @@ static int rsync_module(int fd, int i)
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_chroot) {
|
||||
if (sanitize_paths) {
|
||||
/*
|
||||
* Note that this is applied to all parameters, whether or not
|
||||
* they are filenames, but no other legal parameters contain
|
||||
@@ -285,7 +287,7 @@ static int rsync_module(int fd, int i)
|
||||
* and which aren't.
|
||||
*/
|
||||
for (i = 1; i < argc; i++) {
|
||||
sanitize_path(argv[i]);
|
||||
sanitize_path(argv[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
compat.c
2
compat.c
@@ -23,8 +23,6 @@
|
||||
|
||||
extern int am_server;
|
||||
|
||||
extern int csum_length;
|
||||
|
||||
extern int preserve_links;
|
||||
extern int preserve_perms;
|
||||
extern int preserve_devices;
|
||||
|
||||
@@ -53,11 +53,12 @@ AC_FUNC_UTIME_NULL
|
||||
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod)
|
||||
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
|
||||
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf setsid glob strpbrk)
|
||||
AC_CHECK_FUNCS(strlcat strlcpy)
|
||||
AC_CHECK_FUNCS(strlcat strlcpy inet_aton)
|
||||
|
||||
AC_CACHE_CHECK([for working fnmatch],rsync_cv_HAVE_FNMATCH,[
|
||||
AC_TRY_RUN([#include <fnmatch.h>
|
||||
main() { exit(fnmatch("*.o", "x.o", FNM_PATHNAME) == 0? 0: 1); }],
|
||||
main() { exit((fnmatch("*.o", "x.o", FNM_PATHNAME) == 0 &&
|
||||
fnmatch("a/b/*", "a/b/c/d", FNM_PATHNAME) != 0) ? 0: 1); }],
|
||||
rsync_cv_HAVE_FNMATCH=yes,rsync_cv_HAVE_FNMATCH=no,rsync_cv_HAVE_FNMATCH=cross)])
|
||||
if test x"$rsync_cv_HAVE_FNMATCH" = x"yes"; then
|
||||
AC_DEFINE(HAVE_FNMATCH)
|
||||
|
||||
@@ -270,8 +270,11 @@ void send_exclude_list(int f)
|
||||
}
|
||||
|
||||
for (i=0;exclude_list[i];i++) {
|
||||
char *pattern = exclude_list[i]->pattern;
|
||||
int l;
|
||||
char pattern[MAXPATHLEN];
|
||||
|
||||
strlcpy(pattern,exclude_list[i]->pattern,sizeof(pattern));
|
||||
if (exclude_list[i]->directory) strlcat(pattern,"/", sizeof(pattern));
|
||||
|
||||
l = strlen(pattern);
|
||||
if (l == 0) continue;
|
||||
|
||||
35
flist.c
35
flist.c
@@ -23,8 +23,6 @@
|
||||
|
||||
extern struct stats stats;
|
||||
|
||||
extern int csum_length;
|
||||
|
||||
extern int verbose;
|
||||
extern int am_server;
|
||||
extern int always_checksum;
|
||||
@@ -47,6 +45,7 @@ extern int copy_links;
|
||||
extern int copy_unsafe_links;
|
||||
extern int remote_version;
|
||||
extern int io_error;
|
||||
extern int sanitize_paths;
|
||||
|
||||
static char topsrcname[MAXPATHLEN];
|
||||
|
||||
@@ -254,7 +253,11 @@ static void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
|
||||
#endif
|
||||
|
||||
if (always_checksum) {
|
||||
write_buf(f,file->sum,csum_length);
|
||||
if (remote_version < 21) {
|
||||
write_buf(f,file->sum,2);
|
||||
} else {
|
||||
write_buf(f,file->sum,MD4_SUM_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
last_mode = file->mode;
|
||||
@@ -307,6 +310,10 @@ static void receive_file_entry(struct file_struct **fptr,
|
||||
|
||||
clean_fname(thisname);
|
||||
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(thisname, NULL);
|
||||
}
|
||||
|
||||
if ((p = strrchr(thisname,'/'))) {
|
||||
static char *lastdir;
|
||||
*p = 0;
|
||||
@@ -341,6 +348,9 @@ static void receive_file_entry(struct file_struct **fptr,
|
||||
file->link = (char *)malloc(l+1);
|
||||
if (!file->link) out_of_memory("receive_file_entry 2");
|
||||
read_sbuf(f,file->link,l);
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(file->link, file->dirname);
|
||||
}
|
||||
}
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
@@ -353,7 +363,11 @@ static void receive_file_entry(struct file_struct **fptr,
|
||||
if (always_checksum) {
|
||||
file->sum = (char *)malloc(MD4_SUM_LENGTH);
|
||||
if (!file->sum) out_of_memory("md4 sum");
|
||||
read_buf(f,file->sum,csum_length);
|
||||
if (remote_version < 21) {
|
||||
read_buf(f,file->sum,2);
|
||||
} else {
|
||||
read_buf(f,file->sum,MD4_SUM_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
last_mode = file->mode;
|
||||
@@ -408,6 +422,9 @@ static struct file_struct *make_file(int f, char *fname)
|
||||
strlcpy(cleaned_name, fname, MAXPATHLEN);
|
||||
cleaned_name[MAXPATHLEN-1] = 0;
|
||||
clean_fname(cleaned_name);
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(cleaned_name, NULL);
|
||||
}
|
||||
fname = cleaned_name;
|
||||
|
||||
memset(sum,0,SUM_LENGTH);
|
||||
@@ -752,7 +769,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
|
||||
|
||||
/* if protocol version is >= 17 then send the io_error flag */
|
||||
if (f != -1 && remote_version >= 17) {
|
||||
write_int(f, io_error);
|
||||
extern int module_id;
|
||||
write_int(f, lp_ignore_errors(module_id)? 0 : io_error);
|
||||
}
|
||||
|
||||
if (f != -1) {
|
||||
@@ -837,7 +855,12 @@ struct file_list *recv_file_list(int f)
|
||||
|
||||
/* if protocol version is >= 17 then recv the io_error flag */
|
||||
if (f != -1 && remote_version >= 17) {
|
||||
io_error |= read_int(f);
|
||||
extern int module_id;
|
||||
if (lp_ignore_errors(module_id)) {
|
||||
read_int(f);
|
||||
} else {
|
||||
io_error |= read_int(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_only) {
|
||||
|
||||
36
generator.c
36
generator.c
@@ -50,7 +50,11 @@ static int skip_file(char *fname,
|
||||
if (always_checksum && S_ISREG(st->st_mode)) {
|
||||
char sum[MD4_SUM_LENGTH];
|
||||
file_checksum(fname,sum,st->st_size);
|
||||
return (memcmp(sum,file->sum,csum_length) == 0);
|
||||
if (remote_version < 21) {
|
||||
return (memcmp(sum,file->sum,2) == 0);
|
||||
} else {
|
||||
return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (size_only) {
|
||||
@@ -86,17 +90,19 @@ static int adapt_block_size(struct file_struct *file, int bsize)
|
||||
static void send_sums(struct sum_struct *s,int f_out)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* tell the other guy how many we are going to be doing and how many
|
||||
bytes there are in the last chunk */
|
||||
|
||||
/* tell the other guy how many we are going to be doing and how many
|
||||
bytes there are in the last chunk */
|
||||
write_int(f_out,s?s->count:0);
|
||||
write_int(f_out,s?s->n:block_size);
|
||||
write_int(f_out,s?s->remainder:0);
|
||||
if (s)
|
||||
for (i=0;i<s->count;i++) {
|
||||
write_int(f_out,s->sums[i].sum1);
|
||||
write_buf(f_out,s->sums[i].sum2,csum_length);
|
||||
}
|
||||
|
||||
if (!s) return;
|
||||
|
||||
for (i=0;i<s->count;i++) {
|
||||
write_int(f_out,s->sums[i].sum1);
|
||||
write_buf(f_out,s->sums[i].sum2,csum_length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -171,6 +177,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
char fnamecmpbuf[MAXPATHLEN];
|
||||
extern char *compare_dest;
|
||||
extern int list_only;
|
||||
extern int preserve_perms;
|
||||
|
||||
if (list_only) return;
|
||||
|
||||
@@ -179,6 +186,15 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
|
||||
statret = link_stat(fname,&st);
|
||||
|
||||
if (statret == 0 &&
|
||||
!preserve_perms &&
|
||||
(S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
|
||||
/* if the file exists already and we aren't perserving
|
||||
presmissions then act as though the remote end sent
|
||||
us the file permissions we already have */
|
||||
file->mode = st.st_mode;
|
||||
}
|
||||
|
||||
if (S_ISDIR(file->mode)) {
|
||||
if (dry_run) return;
|
||||
if (statret == 0 && !S_ISDIR(st.st_mode)) {
|
||||
@@ -334,7 +350,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
|
||||
}
|
||||
|
||||
/* open the file */
|
||||
fd = open(fnamecmp,O_RDONLY);
|
||||
fd = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if (fd == -1) {
|
||||
rprintf(FERROR,"failed to open %s : %s\n",fnamecmp,strerror(errno));
|
||||
|
||||
16
lib/compat.c
16
lib/compat.c
@@ -145,3 +145,19 @@
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *inp)
|
||||
{
|
||||
if (strcmp(cp, "255.255.255.255") == 0) {
|
||||
inp->s_addr = (unsigned) -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
inp->s_addr = inet_addr(cp);
|
||||
if (inp->s_addr == (unsigned) -1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -48,9 +48,13 @@ extern "C" {
|
||||
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
|
||||
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
|
||||
|
||||
#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
|
||||
#ifndef FNM_FILE_NAME
|
||||
#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
|
||||
#endif
|
||||
#ifndef FNM_LEADING_DIR
|
||||
#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
|
||||
#endif
|
||||
#ifndef FNM_CASEFOLD
|
||||
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ typedef struct
|
||||
BOOL list;
|
||||
BOOL use_chroot;
|
||||
BOOL transfer_logging;
|
||||
BOOL ignore_errors;
|
||||
char *uid;
|
||||
char *gid;
|
||||
char *hosts_allow;
|
||||
@@ -147,6 +148,7 @@ static service sDefault =
|
||||
True, /* list */
|
||||
True, /* use chroot */
|
||||
False, /* transfer logging */
|
||||
False, /* ignore errors */
|
||||
"nobody",/* uid */
|
||||
"nobody",/* gid */
|
||||
NULL, /* hosts allow */
|
||||
@@ -272,6 +274,7 @@ static struct parm_struct parm_table[] =
|
||||
{"include", P_STRING, P_LOCAL, &sDefault.include, NULL, 0},
|
||||
{"include from", P_STRING, P_LOCAL, &sDefault.include_from,NULL, 0},
|
||||
{"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
|
||||
{"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors,NULL,0},
|
||||
{"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL, 0},
|
||||
{"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options,NULL, 0},
|
||||
{"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress,NULL, 0},
|
||||
@@ -336,6 +339,7 @@ FN_LOCAL_BOOL(lp_read_only, read_only)
|
||||
FN_LOCAL_BOOL(lp_list, list)
|
||||
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
|
||||
FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
|
||||
FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
|
||||
FN_LOCAL_STRING(lp_uid, uid)
|
||||
FN_LOCAL_STRING(lp_gid, gid)
|
||||
FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
|
||||
|
||||
2
main.c
2
main.c
@@ -23,8 +23,6 @@ time_t starttime = 0;
|
||||
|
||||
struct stats stats;
|
||||
|
||||
extern int csum_length;
|
||||
|
||||
extern int verbose;
|
||||
|
||||
static void report(int f)
|
||||
|
||||
34
options.c
34
options.c
@@ -62,6 +62,7 @@ int safe_symlinks=0;
|
||||
int copy_unsafe_links=0;
|
||||
int block_size=BLOCK_SIZE;
|
||||
int size_only=0;
|
||||
int delete_after=0;
|
||||
|
||||
char *backup_suffix = BACKUP_SUFFIX;
|
||||
char *tmpdir = NULL;
|
||||
@@ -78,6 +79,8 @@ int quiet = 0;
|
||||
int always_checksum = 0;
|
||||
int list_only = 0;
|
||||
|
||||
struct in_addr socket_address = {INADDR_ANY};
|
||||
|
||||
void usage(int F)
|
||||
{
|
||||
rprintf(F,"rsync version %s Copyright Andrew Tridgell and Paul Mackerras\n\n",
|
||||
@@ -124,6 +127,7 @@ void usage(int F)
|
||||
rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n");
|
||||
rprintf(F," --delete delete files that don't exist on the sending side\n");
|
||||
rprintf(F," --delete-excluded also delete excluded files on the receiving side\n");
|
||||
rprintf(F," --delete-after delete after transferring, not before\n");
|
||||
rprintf(F," --partial keep partially transferred files\n");
|
||||
rprintf(F," --force force deletion of directories even if not empty\n");
|
||||
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
|
||||
@@ -132,6 +136,7 @@ void usage(int F)
|
||||
rprintf(F," --size-only only use file size when determining if a file should be transferred\n");
|
||||
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
|
||||
rprintf(F," --compare-dest=DIR also compare destination files relative to DIR\n");
|
||||
rprintf(F," -P equivalent to --partial --progress\n");
|
||||
rprintf(F," -z, --compress compress file data\n");
|
||||
rprintf(F," --exclude=PATTERN exclude files matching PATTERN\n");
|
||||
rprintf(F," --exclude-from=FILE exclude patterns listed in FILE\n");
|
||||
@@ -139,6 +144,7 @@ void usage(int F)
|
||||
rprintf(F," --include-from=FILE don't exclude patterns listed in FILE\n");
|
||||
rprintf(F," --version print version number\n");
|
||||
rprintf(F," --daemon run as a rsync daemon\n");
|
||||
rprintf(F," --address bind to the specified address\n");
|
||||
rprintf(F," --config=FILE specify alternate rsyncd.conf file\n");
|
||||
rprintf(F," --port=PORT specify alternate rsyncd port number\n");
|
||||
rprintf(F," --stats give some file transfer stats\n");
|
||||
@@ -158,9 +164,10 @@ enum {OPT_VERSION, OPT_SUFFIX, OPT_SENDER, OPT_SERVER, OPT_EXCLUDE,
|
||||
OPT_RSYNC_PATH, OPT_FORCE, OPT_TIMEOUT, OPT_DAEMON, OPT_CONFIG, OPT_PORT,
|
||||
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
|
||||
OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST,
|
||||
OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY};
|
||||
OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
|
||||
OPT_DELETE_AFTER};
|
||||
|
||||
static char *short_options = "oblLWHpguDCtcahvqrRIxnSe:B:T:z";
|
||||
static char *short_options = "oblLWHpguDCtcahvqrRIxnSe:B:T:zP";
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"version", 0, 0, OPT_VERSION},
|
||||
@@ -213,9 +220,11 @@ static struct option long_options[] = {
|
||||
{"stats", 0, 0, OPT_STATS},
|
||||
{"progress", 0, 0, OPT_PROGRESS},
|
||||
{"partial", 0, 0, OPT_PARTIAL},
|
||||
{"delete-after",0, 0, OPT_DELETE_AFTER},
|
||||
{"config", 1, 0, OPT_CONFIG},
|
||||
{"port", 1, 0, OPT_PORT},
|
||||
{"log-format", 1, 0, OPT_LOG_FORMAT},
|
||||
{"address", 1, 0, OPT_ADDRESS},
|
||||
{0,0,0,0}};
|
||||
|
||||
|
||||
@@ -311,6 +320,10 @@ int parse_arguments(int argc, char *argv[], int frommain)
|
||||
delete_mode = 1;
|
||||
break;
|
||||
|
||||
case OPT_DELETE_AFTER:
|
||||
delete_after = 1;
|
||||
break;
|
||||
|
||||
case OPT_DELETE_EXCLUDED:
|
||||
delete_excluded = 1;
|
||||
delete_mode = 1;
|
||||
@@ -500,6 +513,11 @@ int parse_arguments(int argc, char *argv[], int frommain)
|
||||
keep_partial = 1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
do_progress = 1;
|
||||
keep_partial = 1;
|
||||
break;
|
||||
|
||||
case OPT_CONFIG:
|
||||
config_file = optarg;
|
||||
break;
|
||||
@@ -512,6 +530,15 @@ int parse_arguments(int argc, char *argv[], int frommain)
|
||||
log_format = optarg;
|
||||
break;
|
||||
|
||||
case OPT_ADDRESS:
|
||||
{
|
||||
struct in_addr *ia;
|
||||
if ((ia = ip_address(optarg))) {
|
||||
socket_address = *ia;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
slprintf(err_buf,sizeof(err_buf),"unrecognised option\n");
|
||||
return 0;
|
||||
@@ -613,6 +640,9 @@ void server_options(char **args,int *argc)
|
||||
if (force_delete)
|
||||
args[ac++] = "--force";
|
||||
|
||||
if (delete_after)
|
||||
args[ac++] = "--delete-after";
|
||||
|
||||
if (copy_unsafe_links)
|
||||
args[ac++] = "--copy-unsafe-links";
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Summary: Program for efficient remote updates of files.
|
||||
Name: rsync
|
||||
Version: 2.3.1
|
||||
Version: 2.3.2
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Applications/Networking
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.3.1.tar.gz
|
||||
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.3.2.tar.gz
|
||||
URL: http://samba.anu.edu.au/rsync/
|
||||
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
|
||||
BuildRoot: /tmp/rsync
|
||||
|
||||
28
receiver.c
28
receiver.c
@@ -109,11 +109,12 @@ static void delete_files(struct file_list *flist)
|
||||
struct file_list *local_file_list;
|
||||
int i, j;
|
||||
char *name;
|
||||
extern int module_id;
|
||||
|
||||
if (cvs_exclude)
|
||||
add_cvs_excludes();
|
||||
|
||||
if (io_error) {
|
||||
if (io_error && !lp_ignore_errors(module_id)) {
|
||||
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
|
||||
return;
|
||||
}
|
||||
@@ -302,14 +303,18 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
int phase=0;
|
||||
int recv_ok;
|
||||
extern struct stats stats;
|
||||
extern int preserve_perms;
|
||||
extern int delete_after;
|
||||
struct stats initial_stats;
|
||||
|
||||
if (verbose > 2) {
|
||||
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
|
||||
}
|
||||
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
if (!delete_after) {
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
@@ -358,14 +363,14 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
fnamecmp = fname;
|
||||
|
||||
/* open the file */
|
||||
fd1 = open(fnamecmp,O_RDONLY);
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
|
||||
if ((fd1 == -1) && (compare_dest != NULL)) {
|
||||
/* try the file at compare_dest instead */
|
||||
slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
|
||||
compare_dest,fname);
|
||||
fnamecmp = fnamecmpbuf;
|
||||
fd1 = open(fnamecmp,O_RDONLY);
|
||||
fd1 = do_open(fnamecmp, O_RDONLY, 0);
|
||||
}
|
||||
|
||||
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
|
||||
@@ -382,6 +387,13 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && !preserve_perms) {
|
||||
/* if the file exists already and we aren't perserving
|
||||
presmissions then act as though the remote end sent
|
||||
us the file permissions we already have */
|
||||
file->mode = st.st_mode;
|
||||
}
|
||||
|
||||
if (fd1 != -1 && st.st_size > 0) {
|
||||
buf = map_file(fd1,st.st_size);
|
||||
if (verbose > 2)
|
||||
@@ -469,6 +481,12 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_after) {
|
||||
if (recurse && delete_mode && !local_name && flist->count>0) {
|
||||
delete_files(flist);
|
||||
}
|
||||
}
|
||||
|
||||
if (preserve_hard_links)
|
||||
do_hard_links(flist);
|
||||
|
||||
|
||||
29
rsync.c
29
rsync.c
@@ -30,7 +30,6 @@ extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_perms;
|
||||
extern int make_backups;
|
||||
extern char *backup_suffix;
|
||||
|
||||
|
||||
/*
|
||||
@@ -201,14 +200,9 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
|
||||
|
||||
#ifdef HAVE_CHMOD
|
||||
if (!S_ISLNK(st->st_mode)) {
|
||||
int file_mode;
|
||||
if (preserve_perms)
|
||||
file_mode = file->mode;
|
||||
else
|
||||
file_mode = file->mode & ACCESSPERMS;
|
||||
if (st->st_mode != file->mode) {
|
||||
updated = 1;
|
||||
if (do_chmod(fname,file_mode) != 0) {
|
||||
if (do_chmod(fname,file->mode) != 0) {
|
||||
rprintf(FERROR,"failed to set permissions on %s : %s\n",
|
||||
fname,strerror(errno));
|
||||
return 0;
|
||||
@@ -232,27 +226,6 @@ void sig_int(void)
|
||||
exit_cleanup(RERR_SIGNAL);
|
||||
}
|
||||
|
||||
int make_backup(char *fname)
|
||||
{
|
||||
char fnamebak[MAXPATHLEN];
|
||||
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
|
||||
rprintf(FERROR,"backup filename too long\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
slprintf(fnamebak,sizeof(fnamebak),"%s%s",fname,backup_suffix);
|
||||
if (do_rename(fname,fnamebak) != 0) {
|
||||
/* cygwin (at least version b19) reports EINVAL */
|
||||
if (errno != ENOENT && errno != EINVAL) {
|
||||
rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
} else if (verbose > 1) {
|
||||
rprintf(FINFO,"backed up %s to %s\n",fname,fnamebak);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* finish off a file transfer, renaming the file and setting the permissions
|
||||
and ownership */
|
||||
|
||||
2
rsync.h
2
rsync.h
@@ -47,7 +47,7 @@
|
||||
#define SAME_TIME (1<<7)
|
||||
|
||||
/* update this if you make incompatible changes */
|
||||
#define PROTOCOL_VERSION 20
|
||||
#define PROTOCOL_VERSION 21
|
||||
#define MIN_PROTOCOL_VERSION 11
|
||||
#define MAX_PROTOCOL_VERSION 30
|
||||
|
||||
|
||||
58
rsync.yo
58
rsync.yo
@@ -139,6 +139,11 @@ It is also possible to use rsync without using rsh or ssh as the
|
||||
transport. In this case you will connect to a remote rsync server
|
||||
running on TCP port 873.
|
||||
|
||||
You may establish the connetcion 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 must allow proxying to port
|
||||
873, this must be configured in your proxy servers ruleset.
|
||||
|
||||
Using rsync in this way is the same as using it with rsh or ssh except
|
||||
that:
|
||||
|
||||
@@ -259,6 +264,7 @@ Options
|
||||
--size-only only use file size when determining if a file should be transferred
|
||||
-T --temp-dir=DIR create temporary files in directory DIR
|
||||
--compare-dest=DIR also compare destination files relative to DIR
|
||||
-P equivalent to --partial --progress
|
||||
-z, --compress compress file data
|
||||
--exclude=PATTERN exclude files matching PATTERN
|
||||
--exclude-from=FILE exclude patterns listed in FILE
|
||||
@@ -266,6 +272,7 @@ Options
|
||||
--include-from=FILE don't exclude patterns listed in FILE
|
||||
--version print version number
|
||||
--daemon run as a rsync daemon
|
||||
--address bind to the specified address
|
||||
--config=FILE specify alternate rsyncd.conf file
|
||||
--port=PORT specify alternate rsyncd port number
|
||||
--stats give some file transfer stats
|
||||
@@ -386,12 +393,6 @@ dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm
|
||||
is not used and the whole file is sent as-is instead. This may be
|
||||
useful when using rsync with a local machine.
|
||||
|
||||
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
|
||||
--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(-p, --perms)) This option causes rsync to update the remote
|
||||
permissions to be the same as the local permissions.
|
||||
|
||||
@@ -442,15 +443,6 @@ This option can be dangerous if used incorrectly! It is a very good idea
|
||||
to run first using the dry run option (-n) to see what files would be
|
||||
deleted to make sure important files aren't listed.
|
||||
|
||||
rsync 1.6.4 changed the behavior of --delete to make it less
|
||||
dangerous. rsync now only scans directories on the receiving side
|
||||
that are explicitly transferred from the sending side. Only files in
|
||||
these directories are deleted.
|
||||
|
||||
Still, it is probably easy to get burnt with this option. The moral
|
||||
of the story is to use the -n option until you get used to the
|
||||
behavior of --delete.
|
||||
|
||||
If the sending side detects any IO 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
|
||||
@@ -461,6 +453,11 @@ 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 --exclude).
|
||||
|
||||
dit(bf(--delete-after)) By default rsync does file deletions before
|
||||
transferring files to try to ensure that there is sufficient space on
|
||||
the receiving filesystem. If you want to delete after transferring
|
||||
then use the --delete-after switch.
|
||||
|
||||
dit(bf(--force)) This options tells rsync to delete directories even if
|
||||
they are not empty. This applies to both the --delete option and to
|
||||
cases where rsync tries to copy a normal file but the destination
|
||||
@@ -481,7 +478,9 @@ You can also choose the remote shell program using the RSYNC_RSH
|
||||
environment variable.
|
||||
|
||||
dit(bf(--rsync-path=PATH)) Use this to specify the path to the copy of
|
||||
rsync on the remote machine. Useful when it's not in your path.
|
||||
rsync on the remote machine. Useful when it's not in your path. Note
|
||||
that this is the full path to the binary, not just the directory that
|
||||
the binary is in.
|
||||
|
||||
dit(bf(--exclude=PATTERN)) This option allows you to selectively exclude
|
||||
certain files from the list of files to be transferred. This is most
|
||||
@@ -596,6 +595,12 @@ config file (/etc/rsyncd.conf) on each connect made by a client and
|
||||
respond to requests accordingly. See the 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 --daemon option. The --address option
|
||||
allows you to specify a specific IP address (or hostname) to bind
|
||||
to. This makes virtual hosting possible in conjunction with the
|
||||
--config option.
|
||||
|
||||
dit(bf(--config=FILE)) This specifies an alternate config file than
|
||||
the default /etc/rsyncd.conf. This is only relevant when --daemon is
|
||||
specified.
|
||||
@@ -612,10 +617,23 @@ dit(bf(--stats)) This tells rsync to print a verbose set of statistics
|
||||
on the file transfer, allowing you to tell how effective the rsync
|
||||
algorithm is for your data.
|
||||
|
||||
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
|
||||
--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(--progress)) This option tells rsync to print information
|
||||
showing the progress of the transfer. This gives a bored user
|
||||
something to watch.
|
||||
|
||||
This option is normally combined with -v. Using this option without
|
||||
the -v option will produce weird results on your display.
|
||||
|
||||
dit(bf(-P)) The -P option is equivalent to --partial --progress. I
|
||||
found myself typing that combination quite often so I created an
|
||||
option to make it easier.
|
||||
|
||||
dit(bf(--password-file)) This option allows you to provide a password
|
||||
in a file for accessing a remote rsync server. Note that this option
|
||||
is only useful when accessing a rsync server using the built in
|
||||
@@ -637,6 +655,10 @@ skipped. If it is an include pattern then that filename is not
|
||||
skipped. If no matching include/exclude pattern is found then the
|
||||
filename is not skipped.
|
||||
|
||||
Note that the --include and --exclude options take one pattern
|
||||
each. To add multiple patterns use the --include-from and
|
||||
--exclude-from options or multiple --include and --exclude options.
|
||||
|
||||
The patterns can take several forms. The rules are:
|
||||
|
||||
itemize(
|
||||
@@ -727,6 +749,10 @@ dit(bf(RSYNC_RSH)) The RSYNC_RSH environment variable allows you to
|
||||
override the default shell used as the transport for rsync. This can
|
||||
be used instead of the -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 a rsync
|
||||
daemon without user intervention. Note that this does not supply a
|
||||
|
||||
@@ -58,8 +58,9 @@ and a single line something like this to /etc/inetd.conf:
|
||||
|
||||
quote(rsync stream tcp nowait root /usr/bin/rsync rsyncd --daemon)
|
||||
|
||||
You will then need to send inetd a HUP signal to tell it to reread its
|
||||
config file.
|
||||
Replace "/usr/bin/rsync" with the path to where you have rsync installed on
|
||||
your system. You will then need to send inetd a HUP signal to tell it to
|
||||
reread its config file.
|
||||
|
||||
Note that you should not send the rsync server a HUP signal to force
|
||||
it to reread the tt(/etc/rsyncd.conf). The file is re-read on each client
|
||||
@@ -273,6 +274,14 @@ rejected. See the "hosts allow" option for more information.
|
||||
|
||||
The default is no "hosts deny" option, which means all hosts can connect.
|
||||
|
||||
dit(bf(ignore errors)) The "ignore errors" option tells rsyncd to
|
||||
ignore IO errors on the server when deciding whether to run the delete
|
||||
phase of the transfer. Normally rsync skips the --delete step if any
|
||||
IO errors have occurred in order to prevent disasterous deletion due
|
||||
to a temporary resource shortage or other IO error. In some cases this
|
||||
test is counter productive so you can use this option to turn off this
|
||||
behaviour.
|
||||
|
||||
dit(bf(transfer logging)) The "transfer logging" option enables per-file
|
||||
logging of downloads and uploads in a format somewhat similar to that
|
||||
used by ftp daemons. If you want to customize the log formats look at
|
||||
|
||||
2
sender.c
2
sender.c
@@ -160,7 +160,7 @@ void send_files(struct file_list *flist,int f_out,int f_in)
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
fd = do_open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
io_error = 1;
|
||||
rprintf(FERROR,"send_files failed to open %s: %s\n",
|
||||
|
||||
155
socket.c
155
socket.c
@@ -23,34 +23,128 @@
|
||||
|
||||
#include "rsync.h"
|
||||
|
||||
|
||||
/* establish a proxy connection on an open socket to a web roxy by using the CONNECT
|
||||
method */
|
||||
static int establish_proxy_connection(int fd, char *host, int port)
|
||||
{
|
||||
char buffer[1024];
|
||||
char *cp;
|
||||
|
||||
slprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
|
||||
if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
|
||||
rprintf(FERROR, "failed to write to proxy - %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
|
||||
if (read(fd, cp, 1) != 1) {
|
||||
rprintf(FERROR, "failed to read from proxy\n");
|
||||
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) {
|
||||
rprintf(FERROR, "failed to read from proxy\n");
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n')
|
||||
break;
|
||||
}
|
||||
if ((cp > buffer) && (*cp == '\n'))
|
||||
cp--;
|
||||
if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* open a socket to a tcp remote host with the specified port
|
||||
based on code from Warren */
|
||||
based on code from Warren
|
||||
proxy support by Stephen Rothwell */
|
||||
int open_socket_out(char *host, int port)
|
||||
{
|
||||
int type = SOCK_STREAM;
|
||||
struct sockaddr_in sock_out;
|
||||
int res;
|
||||
struct hostent *hp;
|
||||
|
||||
char *h;
|
||||
unsigned p;
|
||||
int proxied = 0;
|
||||
char buffer[1024];
|
||||
char *cp;
|
||||
|
||||
/* if we have a RSYNC_PROXY env variable then redirect our connetcion via a web proxy
|
||||
at the given address. The format is hostname:port */
|
||||
h = getenv("RSYNC_PROXY");
|
||||
proxied = (h != NULL) && (*h != '\0');
|
||||
|
||||
if (proxied) {
|
||||
strlcpy(buffer, h, sizeof(buffer));
|
||||
cp = strchr(buffer, ':');
|
||||
if (cp == NULL) {
|
||||
rprintf(FERROR, "invalid proxy specification\n");
|
||||
return -1;
|
||||
}
|
||||
*cp++ = '\0';
|
||||
p = atoi(cp);
|
||||
h = buffer;
|
||||
} else {
|
||||
h = host;
|
||||
p = port;
|
||||
}
|
||||
|
||||
res = socket(PF_INET, type, 0);
|
||||
if (res == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hp = gethostbyname(host);
|
||||
hp = gethostbyname(h);
|
||||
if (!hp) {
|
||||
rprintf(FERROR,"unknown host: %s\n", host);
|
||||
rprintf(FERROR,"unknown host: %s\n", h);
|
||||
close(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length);
|
||||
sock_out.sin_port = htons(port);
|
||||
sock_out.sin_port = htons(p);
|
||||
sock_out.sin_family = PF_INET;
|
||||
|
||||
if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
|
||||
rprintf(FERROR,"failed to connect to %s - %s\n", h, strerror(errno));
|
||||
close(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (proxied && establish_proxy_connection(res, host, port) != 0) {
|
||||
close(res);
|
||||
rprintf(FERROR,"failed to connect to %s - %s\n", host, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -63,7 +157,7 @@ int open_socket_out(char *host, int port)
|
||||
/****************************************************************************
|
||||
open a socket of the specified type, port and address for incoming data
|
||||
****************************************************************************/
|
||||
static int open_socket_in(int type, int port)
|
||||
static int open_socket_in(int type, int port, struct in_addr *address)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct sockaddr_in sock;
|
||||
@@ -87,7 +181,11 @@ static int open_socket_in(int type, int port)
|
||||
memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
|
||||
sock.sin_port = htons(port);
|
||||
sock.sin_family = hp->h_addrtype;
|
||||
sock.sin_addr.s_addr = INADDR_ANY;
|
||||
if (address) {
|
||||
sock.sin_addr = *address;
|
||||
} else {
|
||||
sock.sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
res = socket(hp->h_addrtype, type, 0);
|
||||
if (res == -1) {
|
||||
rprintf(FERROR,"socket failed\n");
|
||||
@@ -121,9 +219,10 @@ int is_a_socket(int fd)
|
||||
void start_accept_loop(int port, int (*fn)(int ))
|
||||
{
|
||||
int s;
|
||||
extern struct in_addr socket_address;
|
||||
|
||||
/* open an incoming socket */
|
||||
s = open_socket_in(SOCK_STREAM, port);
|
||||
s = open_socket_in(SOCK_STREAM, port, &socket_address);
|
||||
if (s == -1)
|
||||
exit_cleanup(RERR_SOCKETIO);
|
||||
|
||||
@@ -161,7 +260,7 @@ void start_accept_loop(int port, int (*fn)(int ))
|
||||
but I have had reports that on Digital Unix zombies
|
||||
are produced, so this ensures that they are reaped */
|
||||
#ifdef WNOHANG
|
||||
waitpid(-1, NULL, WNOHANG);
|
||||
while (waitpid(-1, NULL, WNOHANG) > 0);
|
||||
#endif
|
||||
|
||||
if (fork()==0) {
|
||||
@@ -386,3 +485,39 @@ char *client_name(int fd)
|
||||
|
||||
return name_buf;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
convert a string to an IP address. The string can be a name or
|
||||
dotted decimal number
|
||||
******************************************************************/
|
||||
struct in_addr *ip_address(const char *str)
|
||||
{
|
||||
static struct in_addr ret;
|
||||
struct hostent *hp;
|
||||
|
||||
/* try as an IP address */
|
||||
if (inet_aton(str, &ret) != 0) {
|
||||
return &ret;
|
||||
}
|
||||
|
||||
/* otherwise assume it's a network name of some sort and use
|
||||
gethostbyname */
|
||||
if ((hp = gethostbyname(str)) == 0) {
|
||||
rprintf(FERROR, "gethostbyname: Unknown host. %s\n",str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hp->h_addr == NULL) {
|
||||
rprintf(FERROR, "gethostbyname: host address is invalid for host %s\n",str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hp->h_length > sizeof(ret)) {
|
||||
rprintf(FERROR, "gethostbyname: host address is too large\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&ret.s_addr, hp->h_addr, hp->h_length);
|
||||
|
||||
return(&ret);
|
||||
}
|
||||
|
||||
@@ -76,12 +76,14 @@ int do_rmdir(char *pathname)
|
||||
|
||||
int do_open(char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
if (dry_run) return -1;
|
||||
if (flags != O_RDONLY) {
|
||||
if (dry_run) return -1;
|
||||
CHECK_RO
|
||||
}
|
||||
#ifdef O_BINARY
|
||||
/* for Windows */
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
CHECK_RO
|
||||
return open(pathname, flags, mode);
|
||||
}
|
||||
|
||||
|
||||
102
test.sh
102
test.sh
@@ -1,7 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright (C) 1998 Philip Hands <http://www.hands.com/~phil/>
|
||||
# Copyright (C) 1998,1999 Philip Hands <phil@hands.com>
|
||||
#
|
||||
# This program is distributable under the terms of the GNU GPL (see COPYING)
|
||||
#
|
||||
@@ -10,15 +9,33 @@
|
||||
#
|
||||
#
|
||||
|
||||
cat <<EOF
|
||||
# check if we are running under debian-test, and change behaviour to suit
|
||||
if test -n "${DEBIANTEST_LIB}" ; then
|
||||
# make sure rsync is installed
|
||||
test -e /usr/bin/rsync || exit 0
|
||||
|
||||
. ${DEBIANTEST_LIB}/functions.sh
|
||||
Debian=1
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
This set of tests is not completely portable. It is intended for developers
|
||||
not for end users. You may experience failures on some platforms that
|
||||
do not indicate a problem with rsync.
|
||||
|
||||
EOF
|
||||
export PATH=.:$PATH
|
||||
runtest() {
|
||||
echo -n "Test $1: "
|
||||
eval "$2"
|
||||
}
|
||||
printmsg() {
|
||||
echo ""
|
||||
echo "**** ${1}^G ****"
|
||||
echo ""
|
||||
}
|
||||
fi
|
||||
|
||||
export PATH=.:$PATH
|
||||
TMP=/tmp/rsync-test.$$
|
||||
FROM=${TMP}/from
|
||||
TO=${TMP}/to
|
||||
@@ -38,10 +55,15 @@ ln -s nolf ${FROM}/nolf-symlink
|
||||
cat /etc/inittab /etc/services /etc/resolv.conf > ${FROM}/${F1}
|
||||
mkdir ${FROM}/dir
|
||||
cp ${FROM}/${F1} ${FROM}/dir
|
||||
mkdir ${FROM}/dir/subdir
|
||||
mkdir ${FROM}/dir/subdir/subsubdir
|
||||
ls -ltr /etc > ${FROM}/dir/subdir/subsubdir/etc-ltr-list
|
||||
mkdir ${FROM}/dir/subdir/subsubdir2
|
||||
ls -lt /bin > ${FROM}/dir/subdir/subsubdir2/bin-lt-list
|
||||
|
||||
checkit() {
|
||||
echo -n "Test $4: $5:"
|
||||
log=${LOG}.$4
|
||||
testnum=`expr 0${testnum} + 1`
|
||||
log=${LOG}.${testnum}
|
||||
failed=
|
||||
echo "Running: \"$1\"" >${log}
|
||||
echo "">>${log}
|
||||
@@ -50,22 +72,33 @@ checkit() {
|
||||
echo "-------------">>${log}
|
||||
echo "check how the files compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
diff -ur $2 $3 >>${log} || failed=YES
|
||||
diff -ur $2 $3 >>${log} 2>&1 || failed=YES
|
||||
echo "-------------">>${log}
|
||||
echo "check how the directory listings compare with diff:">>${log}
|
||||
echo "">>${log}
|
||||
ls -la $2 > ${TMP}/ls-from
|
||||
ls -la $3 > ${TMP}/ls-to
|
||||
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} || failed=YES
|
||||
( cd $2 ; ls -laR ) > ${TMP}/ls-from 2>>${log}
|
||||
( cd $3 ; ls -laR ) > ${TMP}/ls-to 2>>${log}
|
||||
diff -u ${TMP}/ls-from ${TMP}/ls-to >>${log} 2>&1 || failed=YES
|
||||
if [ -z "${failed}" ] ; then
|
||||
echo " done."
|
||||
test -z "${Debian}" && echo " done."
|
||||
rm $log
|
||||
return 0
|
||||
else
|
||||
echo " FAILED."
|
||||
if test -n "${Debian}" ; then
|
||||
cat ${log}
|
||||
rm ${log}
|
||||
else
|
||||
echo " FAILED (test # ${testnum})."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
checkforlogs() {
|
||||
# skip it if we're under debian-test
|
||||
if test -n "${Debian}" ; then return 0 ; fi
|
||||
|
||||
if [ -f $1 ] ; then
|
||||
cat <<EOF
|
||||
|
||||
@@ -87,44 +120,45 @@ EOF
|
||||
|
||||
# Main script starts here
|
||||
|
||||
checkit "rsync -av ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
1 "basic operation"
|
||||
runtest "basic operation" 'checkit "rsync -av ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
ln ${FROM}/pslist ${FROM}/dir
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
2 "hard links"
|
||||
runtest "hard links" 'checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
rm ${TO}/${F1}
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
3 "one file"
|
||||
runtest "one file" 'checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
echo "extra line" >> ${TO}/${F1}
|
||||
checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
4 "extra data"
|
||||
runtest "extra data" 'checkit "rsync -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
cp ${FROM}/${F1} ${TO}/ThisShouldGo
|
||||
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
5 " --delete"
|
||||
runtest " --delete" 'checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
LONGDIR=${FROM}/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job/This-is-a-directory-with-a-stupidly-long-name-created-in-an-attempt-to-provoke-an-error-found-in-2.0.11-that-should-hopefully-never-appear-again-if-this-test-does-its-job
|
||||
mkdir -p ${LONGDIR}
|
||||
date > ${LONGDIR}/1
|
||||
ls -la / > ${LONGDIR}/2
|
||||
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
|
||||
6 "long paths"
|
||||
runtest "long paths" 'checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
if type ssh >/dev/null ; then
|
||||
rm -rf ${TO}
|
||||
checkit "rsync -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO} \
|
||||
7 "ssh: basic test"
|
||||
if type ssh >/dev/null 2>&1; then
|
||||
if [ "`ssh -o'BatchMode yes' localhost echo yes 2>/dev/null`" = "yes" ]; then
|
||||
rm -rf ${TO}
|
||||
runtest "ssh: basic test" 'checkit "rsync -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
checkit "rsync --delete -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}\
|
||||
8 "ssh: renamed file"
|
||||
mv ${TO}/${F1} ${TO}/ThisShouldGo
|
||||
runtest "ssh: renamed file" 'checkit "rsync --delete -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}'
|
||||
else
|
||||
printmsg "Skipping SSH tests because ssh conection to localhost not authorised"
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
echo "**** Skipping SSH tests because ssh is not in the path ****"
|
||||
echo ""
|
||||
printmsg "Skipping SSH tests because ssh is not in the path"
|
||||
fi
|
||||
|
||||
rm -rf ${TO}
|
||||
mkdir -p ${FROM}2/dir/subdir
|
||||
cp -a ${FROM}/dir/subdir/subsubdir ${FROM}2/dir/subdir
|
||||
cp ${FROM}/dir/* ${FROM}2/dir 2>/dev/null
|
||||
runtest "excludes" 'checkit "rsync -vv -Hlrt --delete --include /dir/ --include /dir/\* --include /dir/\*/subsubdir --include /dir/\*/subsubdir/\*\* --exclude \*\* ${FROM}/dir ${TO}" ${FROM}2/ ${TO}'
|
||||
rm -r ${FROM}2
|
||||
|
||||
checkforlogs ${LOG}.?
|
||||
|
||||
107
util.c
107
util.c
@@ -282,7 +282,7 @@ int copy_file(char *source, char *dest, mode_t mode)
|
||||
char buf[1024 * 8];
|
||||
int len; /* Number of bytes read into `buf'. */
|
||||
|
||||
ifd = open(source, O_RDONLY);
|
||||
ifd = do_open(source, O_RDONLY, 0);
|
||||
if (ifd == -1) {
|
||||
rprintf(FERROR,"open %s: %s\n",
|
||||
source,strerror(errno));
|
||||
@@ -477,7 +477,7 @@ int lock_range(int fd, int offset, int len)
|
||||
}
|
||||
|
||||
|
||||
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sanitize_paths)
|
||||
static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
|
||||
{
|
||||
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
|
||||
if (!*s) s = ".";
|
||||
@@ -485,14 +485,16 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sa
|
||||
(*argc)++;
|
||||
return;
|
||||
#else
|
||||
extern int sanitize_paths;
|
||||
glob_t globbuf;
|
||||
int i;
|
||||
|
||||
if (!*s) s = ".";
|
||||
|
||||
s = strdup(s);
|
||||
sanitize_path(s);
|
||||
argv[*argc] = s;
|
||||
argv[*argc] = strdup(s);
|
||||
if (sanitize_paths) {
|
||||
sanitize_path(argv[*argc], NULL);
|
||||
}
|
||||
|
||||
memset(&globbuf, 0, sizeof(globbuf));
|
||||
glob(argv[*argc], 0, NULL, &globbuf);
|
||||
@@ -511,7 +513,7 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sa
|
||||
#endif
|
||||
}
|
||||
|
||||
void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_paths)
|
||||
void glob_expand(char *base1, char **argv, int *argc, int maxargs)
|
||||
{
|
||||
char *s = argv[*argc];
|
||||
char *p, *q;
|
||||
@@ -535,11 +537,11 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_
|
||||
while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
|
||||
/* split it at this point */
|
||||
*p = 0;
|
||||
glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
|
||||
glob_expand_one(q, argv, argc, maxargs);
|
||||
q = p+strlen(base);
|
||||
}
|
||||
|
||||
if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
|
||||
if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
|
||||
|
||||
free(s);
|
||||
free(base);
|
||||
@@ -635,19 +637,37 @@ void clean_fname(char *name)
|
||||
/*
|
||||
* Make path appear as if a chroot had occurred:
|
||||
* 1. remove leading "/" (or replace with "." if at end)
|
||||
* 2. remove leading ".." components
|
||||
* 2. remove leading ".." components (except those allowed by "reldir")
|
||||
* 3. delete any other "<dir>/.." (recursively)
|
||||
* Can only shrink paths, so sanitizes in place.
|
||||
* While we're at it, remove double slashes and "." components like
|
||||
* clean_fname does(), but DON'T remove a trailing slash because that
|
||||
* is sometimes significant on command line arguments.
|
||||
* Can only shrink paths, so sanitizes in place.
|
||||
* If "reldir" is non-null, it is a sanitized directory that the path will be
|
||||
* relative to, so allow as many ".." at the beginning of the path as
|
||||
* there are components in reldir. This is used for symbolic link targets.
|
||||
* If reldir is non-null and the path began with "/", to be completely like
|
||||
* a chroot we should add in depth levels of ".." at the beginning of the
|
||||
* path, but that would blow the assumption that the path doesn't grow and
|
||||
* it is not likely to end up being a valid symlink anyway, so just do
|
||||
* the normal removal of the leading "/" instead.
|
||||
* Contributed by Dave Dykstra <dwd@bell-labs.com>
|
||||
*/
|
||||
|
||||
void sanitize_path(char *p)
|
||||
void sanitize_path(char *p, char *reldir)
|
||||
{
|
||||
char *start, *sanp;
|
||||
int depth = 0;
|
||||
int allowdotdot = 0;
|
||||
|
||||
if (reldir) {
|
||||
depth++;
|
||||
while (*reldir) {
|
||||
if (*reldir++ == '/') {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
start = p;
|
||||
sanp = p;
|
||||
while (*p == '/') {
|
||||
@@ -665,36 +685,55 @@ void sanitize_path(char *p)
|
||||
/* skip following slashes */
|
||||
;
|
||||
}
|
||||
} else if ((*p == '.') && (*(p+1) == '.') &&
|
||||
continue;
|
||||
}
|
||||
allowdotdot = 0;
|
||||
if ((*p == '.') && (*(p+1) == '.') &&
|
||||
((*(p+2) == '/') || (*(p+2) == '\0'))) {
|
||||
/* skip ".." component followed by slash or end */
|
||||
p += 2;
|
||||
if (*p == '/')
|
||||
p++;
|
||||
if (sanp != start) {
|
||||
/* back up sanp one level */
|
||||
--sanp; /* now pointing at slash */
|
||||
while ((sanp > start) && (*(sanp - 1) != '/')) {
|
||||
/* skip back up to slash */
|
||||
sanp--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
/* copy one component through next slash */
|
||||
*sanp++ = *p++;
|
||||
if ((*p == '\0') || (*(p-1) == '/')) {
|
||||
while (*p == '/') {
|
||||
/* skip multiple slashes */
|
||||
p++;
|
||||
/* ".." component followed by slash or end */
|
||||
if ((depth > 0) && (sanp == start)) {
|
||||
/* allow depth levels of .. at the beginning */
|
||||
--depth;
|
||||
allowdotdot = 1;
|
||||
} else {
|
||||
p += 2;
|
||||
if (*p == '/')
|
||||
p++;
|
||||
if (sanp != start) {
|
||||
/* back up sanp one level */
|
||||
--sanp; /* now pointing at slash */
|
||||
while ((sanp > start) && (*(sanp - 1) != '/')) {
|
||||
/* skip back up to slash */
|
||||
sanp--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
/* copy one component through next slash */
|
||||
*sanp++ = *p++;
|
||||
if ((*p == '\0') || (*(p-1) == '/')) {
|
||||
while (*p == '/') {
|
||||
/* skip multiple slashes */
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allowdotdot) {
|
||||
/* move the virtual beginning to leave the .. alone */
|
||||
start = sanp;
|
||||
}
|
||||
}
|
||||
if (sanp == start) {
|
||||
if ((sanp == start) && !allowdotdot) {
|
||||
/* ended up with nothing, so put in "." component */
|
||||
/*
|
||||
* note that the !allowdotdot doesn't prevent this from
|
||||
* happening in all allowed ".." situations, but I didn't
|
||||
* think it was worth putting in an extra variable to ensure
|
||||
* it since an extra "." won't hurt in those situations.
|
||||
*/
|
||||
*sanp++ = '.';
|
||||
}
|
||||
*sanp = '\0';
|
||||
|
||||
Reference in New Issue
Block a user