Compare commits

..

26 Commits

Author SHA1 Message Date
rsync-bugs
b58ad6c569 preparing for release of 2.0.18 1998-06-18 13:06:00 +00:00
Andrew Tridgell
22b1933287 fixed a race condition in rsync that opened a security hole. The
temporary files were being created with the same permissions as the
original file. So if the file was setuid but not owned by the user
doing the transfer then there was a window of opportunity for a
malicious user to execute it with the wrong permissions while it was
being transferred.

Thanks to snabb@epipe.fi for pointing this out.
1998-06-18 12:17:23 +00:00
rsync-bugs
5a03f68a5a preparing for release of 2.0.17 1998-06-18 10:30:48 +00:00
Andrew Tridgell
e81da93e86 if as non-root we failed to update the group of a file then don't
print the file name.
1998-06-18 10:03:44 +00:00
Andrew Tridgell
f578043391 for consistency use memcpy/memset everywhere instead of bcopy/bzero 1998-06-18 09:51:44 +00:00
Andrew Tridgell
e8f5b936ad move include of compat.h after other includes. 1998-06-18 09:37:21 +00:00
Andrew Tridgell
667e72a195 change the order of chmod and chown calls so that setuid bits don't
get removed by chown calls.
1998-06-18 09:36:24 +00:00
Andrew Tridgell
e1b3d5c4be set network file descriptors non-blocking before starting main rsync
algorithm.
1998-06-18 09:34:56 +00:00
Andrew Tridgell
f7b9377863 handle non-blocking file descriptors for both read and write. Add a
workaround for buggy systems that say there is space to write when
there isn't.
1998-06-18 09:33:46 +00:00
Andrew Tridgell
a5343e765b put set_nonblocking() code back in. 1998-06-18 09:32:45 +00:00
Andrew Tridgell
704f908eae --help changes suggested by Francois 1998-06-18 09:31:42 +00:00
Andrew Tridgell
de2fd20eb7 manpage updates, mostly suggested by Francois 1998-06-18 09:30:51 +00:00
Andrew Tridgell
100e5241b0 the tag table should be of type int* not tag*.
This bug resulted in rsync being much less efficient that it could be
for files with more than 64k blocks. With the adaptive block size code
giving a maximum block size of 16k this means that files larger than
1GB were handled very inefficiently. The transfer was still accurate,
just slow.
1998-06-03 02:47:52 +00:00
Andrew Tridgell
ddecf7060b if the user passes a block size on the command line then don't adapt
the block size.
1998-06-03 02:35:51 +00:00
Andrew Tridgell
56cdbccb92 added note to docs saying that --stats doesn't work unless -v is used 1998-06-02 12:50:23 +00:00
Andrew Tridgell
fc8a6b9705 added some fflush() calls to make sure the statistics lines are
printed when redirecting output to a file.
1998-06-02 12:46:46 +00:00
rsync-bugs
143384f367 preparing for release of 2.0.16 1998-06-01 13:49:12 +00:00
Andrew Tridgell
8c3b04730b added some notes to test.sh 1998-06-01 13:44:06 +00:00
Andrew Tridgell
aa9b77a56c replace calls to strcmp() with a u_strcmp() function that uses only
unsigned comparisons. Transferring files between two machines that
treated strcmp() differently led to the files being given the wrong
name at the destination if the filenames had characters > 128 (such as
Kanji characters) and the source and destination machines treated
strcmp() differently (ie. one treated strings as signed and the other
as unsigned).

We now treat all string comparisons for file list sorting as unsigned.
1998-06-01 13:39:54 +00:00
Andrew Tridgell
b72f24c719 updated the usage info 1998-06-01 10:38:24 +00:00
Andrew Tridgell
a800434a82 added --stats option for verbose stats on the file transfer 1998-06-01 03:42:14 +00:00
rsync-bugs
3b3c3d4390 preparing for release of 2.0.15 1998-05-30 02:10:18 +00:00
Andrew Tridgell
d846b09874 replace BAD with zBAD so it compiles on AIX 1998-05-30 02:07:36 +00:00
Andrew Tridgell
1d3754aede cosmetic fix.
reset offset to 0 at the start of each loop so the filenames get
printed correctly when sending directories followed by local names.
1998-05-30 02:03:29 +00:00
Andrew Tridgell
e44f9a12c4 make sure that io_flush() doesn't call writefd_unbuffered from within
a writefd_unbuffered call!

this should fix the "decompressor lost sync" bug
1998-05-30 02:02:23 +00:00
Andrew Tridgell
5243c216d6 replaced chdir and getcwd calls with push_dir/pop_dir functions. These
are faster and don't cause problems in a chrooted environment on any
systems.
1998-05-29 14:36:39 +00:00
23 changed files with 764 additions and 488 deletions

View File

@@ -77,7 +77,7 @@ void get_checksum2(char *buf,int len,char *sum)
MDbegin(&MD);
bcopy(buf,buf1,len);
memcpy(buf1,buf,len);
if (checksum_seed) {
SIVAL(buf1,len,checksum_seed);
len += 4;
@@ -102,7 +102,7 @@ void file_checksum(char *fname,char *sum,OFF_T size)
OFF_T len = size;
char tmpchunk[CSUM_CHUNK];
bzero(sum,csum_length);
memset(sum,0,csum_length);
fd = open(fname,O_RDONLY);
if (fd == -1) return;
@@ -112,12 +112,12 @@ void file_checksum(char *fname,char *sum,OFF_T size)
MDbegin(&MD);
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(map_ptr(buf,i,CSUM_CHUNK),tmpchunk,CSUM_CHUNK);
memcpy(tmpchunk, map_ptr(buf,i,CSUM_CHUNK), CSUM_CHUNK);
MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
}
if (len - i > 0) {
bcopy(map_ptr(buf,i,len-i),tmpchunk,len-i);
memcpy(tmpchunk, map_ptr(buf,i,len-i), len-i);
MDupdate(&MD, tmpchunk, (len-i)*8);
}
@@ -155,27 +155,27 @@ void sum_update(char *p,int len)
{
int i;
if (len + sumresidue < CSUM_CHUNK) {
bcopy(p,sumrbuf+sumresidue,len);
memcpy(sumrbuf+sumresidue, p, len);
sumresidue += len;
return;
}
if (sumresidue) {
i = MIN(CSUM_CHUNK-sumresidue,len);
bcopy(p,sumrbuf+sumresidue,i);
memcpy(sumrbuf+sumresidue,p,i);
MDupdate(&sumMD, sumrbuf, (i+sumresidue)*8);
len -= i;
p += i;
}
for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
bcopy(p+i,sumrbuf,CSUM_CHUNK);
memcpy(sumrbuf,p+i,CSUM_CHUNK);
MDupdate(&sumMD, sumrbuf, CSUM_CHUNK*8);
}
if (len - i > 0) {
sumresidue = len-i;
bcopy(p+i,sumrbuf,sumresidue);
memcpy(sumrbuf,p+i,sumresidue);
} else {
sumresidue = 0;
}

View File

@@ -362,6 +362,11 @@ int daemon_main(void)
{
extern char *config_file;
/* this ensures that we don't call getcwd after the chroot,
which doesn't work on platforms that use popen("pwd","r")
for getcwd */
push_dir("/", 0);
if (is_a_socket(STDIN_FILENO)) {
/* we are running via inetd */
return start_daemon(STDIN_FILENO);

View File

@@ -40,7 +40,7 @@ echo no)
AC_FUNC_MEMCMP
AC_FUNC_UTIME_NULL
AC_CHECK_FUNCS(mmap munmap waitpid getcwd strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr bcopy bzero readlink link utime utimes)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes)
AC_CHECK_FUNCS(memmove getopt_long lchown setlinebuf vsnprintf setsid glob strpbrk)
echo $ac_n "checking for working fnmatch... $ac_c"

95
flist.c
View File

@@ -21,12 +21,13 @@
#include "rsync.h"
extern struct stats stats;
extern int csum_length;
extern int verbose;
extern int am_server;
extern int always_checksum;
extern int64 total_size;
extern int cvs_exclude;
@@ -90,49 +91,6 @@ static void send_directory(int f,struct file_list *flist,char *dir);
static char *flist_dir;
static void clean_fname(char *name)
{
char *p;
int l;
int modified = 1;
if (!name) return;
while (modified) {
modified = 0;
if ((p=strstr(name,"/./"))) {
modified = 1;
while (*p) {
p[0] = p[2];
p++;
}
}
if ((p=strstr(name,"//"))) {
modified = 1;
while (*p) {
p[0] = p[1];
p++;
}
}
if (strncmp(p=name,"./",2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
l = strlen(p=name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
}
}
}
void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
{
@@ -253,7 +211,7 @@ static void receive_file_entry(struct file_struct **fptr,
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("receive_file_entry");
bzero((char *)file,sizeof(*file));
memset((char *)file, 0, sizeof(*file));
(*fptr) = file;
if (l2 >= MAXPATHLEN-l1) overflow("receive_file_entry");
@@ -367,7 +325,7 @@ static struct file_struct *make_file(char *fname)
clean_fname(cleaned_name);
fname = cleaned_name;
bzero(sum,SUM_LENGTH);
memset(sum,0,SUM_LENGTH);
if (link_stat(fname,&st) != 0) {
io_error = 1;
@@ -394,7 +352,7 @@ static struct file_struct *make_file(char *fname)
file = (struct file_struct *)malloc(sizeof(*file));
if (!file) out_of_memory("make_file");
bzero((char *)file,sizeof(*file));
memset((char *)file,0,sizeof(*file));
if ((p = strrchr(fname,'/'))) {
static char *lastdir;
@@ -464,7 +422,7 @@ static struct file_struct *make_file(char *fname)
}
if (!S_ISDIR(st.st_mode))
total_size += st.st_size;
stats.total_size += st.st_size;
return file;
}
@@ -566,15 +524,17 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
int i,l;
STRUCT_STAT st;
char *p,*dir;
char dbuf[MAXPATHLEN];
char lastpath[MAXPATHLEN]="";
struct file_list *flist;
int64 start_write;
if (verbose && recurse && !am_server && f != -1) {
rprintf(FINFO,"building file list ... ");
rflush(FINFO);
}
start_write = stats.total_written;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist) out_of_memory("send_file_list");
@@ -646,24 +606,23 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
fname = ".";
if (dir && *dir) {
if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
rprintf(FERROR,"getwd : %s\n",strerror(errno));
exit_cleanup(1);
}
if (chdir(dir) != 0) {
char *olddir = push_dir(dir, 1);
if (!olddir) {
io_error=1;
rprintf(FERROR,"chdir %s : %s\n",
rprintf(FERROR,"push_dir %s : %s\n",
dir,strerror(errno));
continue;
}
flist_dir = dir;
if (one_file_system)
set_filesystem(fname);
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
flist_dir = NULL;
if (chdir(dbuf) != 0) {
rprintf(FERROR,"chdir %s : %s\n",
dbuf,strerror(errno));
if (pop_dir(olddir) != 0) {
rprintf(FERROR,"pop_dir %s : %s\n",
dir,strerror(errno));
exit_cleanup(1);
}
continue;
@@ -696,6 +655,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (f != -1) {
io_end_buffering(f);
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->count;
}
if (verbose > 2)
@@ -709,12 +670,15 @@ struct file_list *recv_file_list(int f)
{
struct file_list *flist;
unsigned char flags;
int64 start_read;
if (verbose && recurse && !am_server) {
rprintf(FINFO,"receiving file list ... ");
rflush(FINFO);
}
start_read = stats.total_read;
flist = (struct file_list *)malloc(sizeof(flist[0]));
if (!flist)
goto oom;
@@ -745,7 +709,7 @@ struct file_list *recv_file_list(int f)
receive_file_entry(&flist->files[i],flags,f);
if (S_ISREG(flist->files[i]->mode))
total_size += flist->files[i]->length;
stats.total_size += flist->files[i]->length;
flist->count++;
@@ -776,6 +740,9 @@ struct file_list *recv_file_list(int f)
if (verbose > 2)
rprintf(FINFO,"recv_file_list done\n");
stats.flist_size = stats.total_read - start_read;
stats.num_files = flist->count;
return flist;
oom:
@@ -790,8 +757,8 @@ int file_compare(struct file_struct **f1,struct file_struct **f2)
if (!(*f1)->basename) return -1;
if (!(*f2)->basename) return 1;
if ((*f1)->dirname == (*f2)->dirname)
return strcmp((*f1)->basename, (*f2)->basename);
return strcmp(f_name(*f1),f_name(*f2));
return u_strcmp((*f1)->basename, (*f2)->basename);
return u_strcmp(f_name(*f1),f_name(*f2));
}
@@ -827,7 +794,7 @@ static void free_file(struct file_struct *file)
if (file->basename) free(file->basename);
if (file->link) free(file->link);
if (file->sum) free(file->sum);
bzero((char *)file, sizeof(*file));
memset((char *)file, 0, sizeof(*file));
}
@@ -841,9 +808,9 @@ void flist_free(struct file_list *flist)
free_file(flist->files[i]);
free(flist->files[i]);
}
bzero((char *)flist->files, sizeof(flist->files[0])*flist->count);
memset((char *)flist->files, 0, sizeof(flist->files[0])*flist->count);
free(flist->files);
bzero((char *)flist, sizeof(*flist));
memset((char *)flist, 0, sizeof(*flist));
free(flist);
}

View File

@@ -56,7 +56,7 @@ void init_hard_links(struct file_list *flist)
out_of_memory("init_hard_links");
for (i = 0; i < flist->count; i++)
bcopy(flist->files[i], &hlink_list[i], sizeof(hlink_list[0]));
memcpy(&hlink_list[i], flist->files[i], sizeof(hlink_list[0]));
qsort(hlink_list,flist->count,
sizeof(hlink_list[0]),

49
io.c
View File

@@ -24,9 +24,6 @@
*/
#include "rsync.h"
static int64 total_written;
static int64 total_read;
static int io_multiplexing_out;
static int io_multiplexing_in;
static int multiplex_in_fd;
@@ -35,17 +32,7 @@ static time_t last_io;
static int eof_error=1;
extern int verbose;
extern int io_timeout;
int64 write_total(void)
{
return total_written;
}
int64 read_total(void)
{
return total_read;
}
extern struct stats stats;
static int buffer_f_in = -1;
@@ -79,6 +66,7 @@ static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
static int no_flush;
/* read from a socket with IO timeout. return the number of
bytes read. If no bytes can be read then exit, never return
@@ -107,6 +95,7 @@ static int read_timeout(int fd, char *buf, int len)
n = read(fd, buf, len);
if (n > 0) {
stats.total_read += n;
buf += n;
len -= n;
ret += n;
@@ -119,6 +108,15 @@ static int read_timeout(int fd, char *buf, int len)
continue;
}
if (n == -1 &&
(errno == EAGAIN || errno == EWOULDBLOCK)) {
/* this shouldn't happen, if it does then
sleep for a short time to prevent us
chewing too much CPU */
u_sleep(100);
continue;
}
if (n == 0) {
if (eof_error) {
rprintf(FERROR,"EOF in read_timeout\n");
@@ -266,7 +264,6 @@ int32 read_int(int f)
{
char b[4];
readfd(f,b,4);
total_read += 4;
return IVAL(b,0);
}
@@ -285,7 +282,6 @@ int64 read_longint(int f)
#else
if (remote_version >= 16) {
readfd(f,b,8);
total_read += 8;
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
@@ -296,7 +292,6 @@ int64 read_longint(int f)
void read_buf(int f,char *buf,int len)
{
readfd(f,buf,len);
total_read += len;
}
void read_sbuf(int f,char *buf,int len)
@@ -325,6 +320,8 @@ static void writefd_unbuffered(int fd,char *buf,int len)
struct timeval tv;
int reading;
no_flush++;
reading = (buffer_f_in != -1 && read_buffer_len < MAX_READ_BUFFER);
while (total < len) {
@@ -359,12 +356,23 @@ static void writefd_unbuffered(int fd,char *buf,int len)
continue;
}
if (ret == -1 &&
(errno == EAGAIN || errno == EWOULDBLOCK)) {
/* this shouldn't happen, if it does then
sleep for a short time to prevent us
chewing too much CPU */
u_sleep(100);
continue;
}
if (ret <= 0) {
rprintf(FERROR,"erroring writing %d bytes - exiting\n", len);
exit_cleanup(1);
}
total += ret;
stats.total_written += ret;
if (io_timeout)
last_io = time(NULL);
continue;
@@ -374,6 +382,8 @@ static void writefd_unbuffered(int fd,char *buf,int len)
read_check(buffer_f_in);
}
}
no_flush--;
}
@@ -395,7 +405,7 @@ void io_start_buffering(int fd)
void io_flush(void)
{
int fd = multiplex_out_fd;
if (!io_buffer_count) return;
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
SIVAL(io_buffer-4, 0, (MPLEX_BASE<<24) + io_buffer_count);
@@ -441,7 +451,6 @@ void write_int(int f,int32 x)
char b[4];
SIVAL(b,0,x);
writefd(f,b,4);
total_written += 4;
}
void write_longint(int f, int64 x)
@@ -459,13 +468,11 @@ void write_longint(int f, int64 x)
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
writefd(f,b,8);
total_written += 8;
}
void write_buf(int f,char *buf,int len)
{
writefd(f,buf,len);
total_written += len;
}
/* write a string to the connection */

View File

@@ -54,7 +54,7 @@ pid_t waitpid(pid_t pid, int *statptr, int options)
#ifndef HAVE_MEMMOVE
void *memmove(void *dest, const void *src, size_t n)
{
bcopy(src, dest, n);
memcpy(dest, src, n);
return dest;
}
#endif

View File

@@ -329,7 +329,7 @@ initialise a service to the defaults
***************************************************************************/
static void init_service(service *pservice)
{
bzero((char *)pservice,sizeof(service));
memset((char *)pservice,0,sizeof(service));
copy_service(pservice,&sDefault);
}

103
main.c
View File

@@ -20,7 +20,8 @@
#include "rsync.h"
time_t starttime = 0;
int64 total_size = 0;
struct stats stats;
extern int csum_length;
@@ -28,16 +29,17 @@ extern int verbose;
static void report(int f)
{
int64 in,out,tsize;
time_t t = time(NULL);
extern int am_server;
extern int am_sender;
extern int am_daemon;
extern int do_stats;
if (am_daemon) {
syslog(LOG_INFO,"wrote %.0f bytes read %.0f bytes total size %.0f\n",
(double)write_total(),(double)read_total(),
(double)total_size);
(double)stats.total_written,
(double)stats.total_read,
(double)stats.total_size);
if (f == -1 || !am_sender) return;
}
@@ -46,26 +48,49 @@ static void report(int f)
if (am_server && !am_sender) return;
if (am_server && am_sender) {
write_longint(f,read_total());
write_longint(f,write_total());
write_longint(f,total_size);
write_longint(f,stats.total_read);
write_longint(f,stats.total_written);
write_longint(f,stats.total_size);
return;
}
if (am_sender) {
in = read_total();
out = write_total();
tsize = total_size;
} else {
out = read_longint(f);
in = read_longint(f);
tsize = read_longint(f);
if (!am_sender) {
int64 r;
stats.total_written = read_longint(f);
r = read_longint(f);
stats.total_size = read_longint(f);
stats.total_read = r;
}
if (do_stats) {
printf("\nNumber of files: %d\n", stats.num_files);
printf("Number of files transferred: %d\n",
stats.num_transferred_files);
printf("Total file size: %.0f bytes\n",
(double)stats.total_size);
printf("Total transferred file size: %.0f bytes\n",
(double)stats.total_transferred_size);
printf("Literal data: %.0f bytes\n",
(double)stats.literal_data);
printf("Matched data: %.0f bytes\n",
(double)stats.matched_data);
printf("File list size: %d\n", stats.flist_size);
printf("Total bytes written: %.0f\n",
(double)stats.total_written);
printf("Total bytes read: %.0f\n\n",
(double)stats.total_read);
}
printf("wrote %.0f bytes read %.0f bytes %.2f bytes/sec\n",
(double)out,(double)in,(in+out)/(0.5 + (t-starttime)));
(double)stats.total_written,
(double)stats.total_read,
(stats.total_written+stats.total_read)/(0.5 + (t-starttime)));
printf("total size is %.0f speedup is %.2f\n",
(double)tsize,(1.0*tsize)/(in+out));
(double)stats.total_size,
(1.0*stats.total_size)/(stats.total_written+stats.total_read));
fflush(stdout);
fflush(stderr);
}
@@ -149,8 +174,8 @@ static char *get_local_name(struct file_list *flist,char *name)
if (do_stat(name,&st) == 0) {
if (S_ISDIR(st.st_mode)) {
if (chdir(name) != 0) {
rprintf(FERROR,"chdir %s : %s (1)\n",
if (!push_dir(name, 0)) {
rprintf(FERROR,"push_dir %s : %s (1)\n",
name,strerror(errno));
exit_cleanup(1);
}
@@ -176,8 +201,9 @@ static char *get_local_name(struct file_list *flist,char *name)
rprintf(FINFO,"created directory %s\n",name);
}
if (chdir(name) != 0) {
rprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno));
if (!push_dir(name, 0)) {
rprintf(FERROR,"push_dir %s : %s (2)\n",
name,strerror(errno));
exit_cleanup(1);
}
@@ -198,8 +224,8 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
if (verbose > 2)
rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
if (!relative_paths && chdir(dir) != 0) {
rprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
if (!relative_paths && !push_dir(dir, 0)) {
rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno));
exit_cleanup(1);
}
argc--;
@@ -224,6 +250,10 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
exit_cleanup(0);
}
set_nonblocking(f_out);
if (f_in != f_out)
set_nonblocking(f_in);
send_files(flist,f_out,f_in);
report(f_out);
io_flush();
@@ -252,6 +282,8 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
close(recv_pipe[0]);
if (f_in != f_out) close(f_out);
set_nonblocking(f_in);
recv_files(f_in,flist,local_name,recv_pipe[1]);
report(f_in);
@@ -265,6 +297,9 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
close(recv_pipe[1]);
io_close_input(f_in);
if (f_in != f_out) close(f_in);
set_nonblocking(f_out);
generate_files(f_out,flist,local_name,recv_pipe[0]);
io_flush();
@@ -289,8 +324,8 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
dir = argv[0];
argc--;
argv++;
if (!am_daemon && chdir(dir) != 0) {
rprintf(FERROR,"chdir %s : %s (4)\n",
if (!am_daemon && !push_dir(dir, 0)) {
rprintf(FERROR,"push_dir %s : %s (4)\n",
dir,strerror(errno));
exit_cleanup(1);
}
@@ -355,6 +390,11 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
rprintf(FINFO,"file list sent\n");
set_nonblocking(f_out);
if (f_in != f_out)
set_nonblocking(f_in);
send_files(flist,f_out,f_in);
if (pid != -1) {
if (verbose > 3)
@@ -389,13 +429,13 @@ int client_run(int f_in, int f_out, int pid, int argc, char *argv[])
}
int start_client(int argc, char *argv[])
static int start_client(int argc, char *argv[])
{
char *p;
char *shell_machine = NULL;
char *shell_path = NULL;
char *shell_user = NULL;
int pid;
int pid, ret;
int f_in,f_out;
extern int local_server;
extern int am_sender;
@@ -476,7 +516,12 @@ int start_client(int argc, char *argv[])
setlinebuf(stderr);
#endif
return client_run(f_in, f_out, pid, argc, argv);
ret = client_run(f_in, f_out, pid, argc, argv);
fflush(stdout);
fflush(stderr);
return ret;
}
@@ -497,6 +542,8 @@ int main(int argc,char *argv[])
starttime = time(NULL);
am_root = (getuid() == 0);
memset(&stats, 0, sizeof(stats));
if (argc < 2) {
usage(FERROR);
exit_cleanup(1);

21
match.c
View File

@@ -29,18 +29,18 @@ extern int remote_version;
typedef unsigned short tag;
#define TABLESIZE (1<<16)
#define NULL_TAG ((tag)-1)
#define NULL_TAG (-1)
static int false_alarms;
static int tag_hits;
static int matches;
static int data_transfer;
static int64 data_transfer;
static int total_false_alarms;
static int total_tag_hits;
static int total_matches;
static int64 total_data_transfer;
extern struct stats stats;
struct target {
tag t;
@@ -49,7 +49,7 @@ struct target {
static struct target *targets;
static tag *tag_table;
static int *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
@@ -65,7 +65,7 @@ static void build_hash_table(struct sum_struct *s)
int i;
if (!tag_table)
tag_table = (tag *)malloc(sizeof(tag)*TABLESIZE);
tag_table = (int *)malloc(sizeof(tag_table[0])*TABLESIZE);
targets = (struct target *)malloc(sizeof(targets[0])*s->count);
if (!tag_table || !targets)
@@ -103,8 +103,10 @@ static void matched(int f,struct sum_struct *s,struct map_struct *buf,
send_token(f,i,buf,last_match,n,i<0?0:s->sums[i].len);
data_transfer += n;
if (i >= 0)
if (i >= 0) {
stats.matched_data += s->sums[i].len;
n += s->sums[i].len;
}
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
@@ -273,7 +275,7 @@ void match_sums(int f,struct sum_struct *s,struct map_struct *buf,OFF_T len)
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
total_data_transfer += data_transfer;
stats.literal_data += data_transfer;
}
void match_report(void)
@@ -282,7 +284,8 @@ void match_report(void)
return;
rprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%ld\n",
"total: matches=%d tag_hits=%d false_alarms=%d data=%.0f\n",
total_matches,total_tag_hits,
total_false_alarms,(long)total_data_transfer);
total_false_alarms,
(double)stats.literal_data);
}

106
options.c
View File

@@ -55,6 +55,7 @@ int am_sender=0;
int recurse = 0;
int am_daemon=0;
int am_client=0;
int do_stats=0;
int block_size=BLOCK_SIZE;
@@ -74,58 +75,69 @@ void usage(int F)
{
rprintf(F,"rsync version %s Copyright Andrew Tridgell and Paul Mackerras\n\n",
VERSION);
rprintf(F,"Usage:\t%s [options] src user@host:dest\nOR",RSYNC_NAME);
rprintf(F,"\t%s [options] user@host:src dest\n\n",RSYNC_NAME);
rprintf(F,"Options:\n");
rprintf(F,"-v, --verbose increase verbosity\n");
rprintf(F,"-c, --checksum always checksum\n");
rprintf(F,"-a, --archive archive mode (same as -rlptDog)\n");
rprintf(F,"-r, --recursive recurse into directories\n");
rprintf(F,"-R, --relative use relative path names\n");
rprintf(F,"-b, --backup make backups (default ~ extension)\n");
rprintf(F,"-u, --update update only (don't overwrite newer files)\n");
rprintf(F,"-l, --links preserve soft links\n");
rprintf(F,"-L, --copy-links treat soft links like regular files\n");
rprintf(F,"-H, --hard-links preserve hard links\n");
rprintf(F,"-p, --perms preserve permissions\n");
rprintf(F,"-o, --owner preserve owner (root only)\n");
rprintf(F,"-g, --group preserve group\n");
rprintf(F,"-D, --devices preserve devices (root only)\n");
rprintf(F,"-t, --times preserve times\n");
rprintf(F,"-S, --sparse handle sparse files efficiently\n");
rprintf(F,"-n, --dry-run show what would have been transferred\n");
rprintf(F,"-W, --whole-file copy whole files, no incremental checks\n");
rprintf(F,"-x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F,"-B, --block-size SIZE checksum blocking size\n");
rprintf(F,"-e, --rsh COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path PATH specify path to rsync on the remote machine\n");
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," --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");
rprintf(F," --timeout TIME set IO timeout in seconds\n");
rprintf(F,"-I, --ignore-times don't exclude files that match length and time\n");
rprintf(F,"-T --temp-dir DIR create temporary files in directory DIR\n");
rprintf(F,"-z, --compress compress file data\n");
rprintf(F," --exclude FILE exclude file FILE\n");
rprintf(F," --exclude-from FILE exclude files listed in FILE\n");
rprintf(F," --include FILE don't exclude file FILE\n");
rprintf(F," --include-from FILE don't exclude files listed in FILE\n");
rprintf(F," --suffix SUFFIX override backup suffix\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\n");
rprintf(F," --config FILE specify alternate rsyncd.conf file\n");
rprintf(F," --port PORT specify alternate rsyncd port number\n");
rprintf(F,"rsync is a file transfer program capable of efficient remote update\nvia a fast differencing algorithm.\n\n");
rprintf(F,"Usage: rsync [OPTION]... SRC [USER@]HOST:DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST:SRC DEST\n");
rprintf(F," or rsync [OPTION]... SRC DEST\n");
rprintf(F," or rsync [OPTION]... [USER@]HOST::SRC DEST\n");
rprintf(F," or rsync [OPTION]... SRC [USER@]HOST::DEST\n");
rprintf(F,"\nOptions\n");
rprintf(F," -v, --verbose increase verbosity\n");
rprintf(F," -c, --checksum always checksum\n");
rprintf(F," -a, --archive archive mode\n");
rprintf(F," -r, --recursive recurse into directories\n");
rprintf(F," -R, --relative use relative path names\n");
rprintf(F," -b, --backup make backups (default ~ extension)\n");
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
rprintf(F," -l, --links preserve soft links\n");
rprintf(F," -L, --copy-links treat soft links like regular files\n");
rprintf(F," -H, --hard-links preserve hard links\n");
rprintf(F," -p, --perms preserve permissions\n");
rprintf(F," -o, --owner preserve owner (root only)\n");
rprintf(F," -g, --group preserve group\n");
rprintf(F," -D, --devices preserve devices (root only)\n");
rprintf(F," -t, --times preserve times\n");
rprintf(F," -S, --sparse handle sparse files efficiently\n");
rprintf(F," -n, --dry-run show what would have been transferred\n");
rprintf(F," -W, --whole-file copy whole files, no incremental checks\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
rprintf(F," -B, --block-size=SIZE checksum blocking size\n");
rprintf(F," -e, --rsh=COMMAND specify rsh replacement\n");
rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n");
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," --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");
rprintf(F," --timeout=TIME set IO timeout in seconds\n");
rprintf(F," -I, --ignore-times don't exclude files that match length and time\n");
rprintf(F," -T --temp-dir=DIR create temporary files in directory DIR\n");
rprintf(F," -z, --compress compress file data\n");
rprintf(F," --exclude=PATTERN exclude file FILE\n");
rprintf(F," --exclude-from=PATTERN exclude files listed in FILE\n");
rprintf(F," --include=PATTERN don't exclude file FILE\n");
rprintf(F," --include-from=PATTERN don't exclude files listed in FILE\n");
rprintf(F," --suffix=SUFFIX override backup suffix\n");
rprintf(F," --version print version number\n");
rprintf(F," --daemon run as a rsync daemon\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");
rprintf(F," -h, --help show this help screen\n");
rprintf(F,"\n");
rprintf(F,"the backup suffix defaults to %s\n",BACKUP_SUFFIX);
rprintf(F,"the block size defaults to %d\n",BLOCK_SIZE);
rprintf(F,"\nPlease see the rsync(1) and rsyncd.conf(5) man pages for full documentation\n");
rprintf(F,"See http://samba.anu.edu.au/rsync/ for updates and bug reports\n");
}
enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT,
OPT_INCLUDE, OPT_INCLUDE_FROM};
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
@@ -170,6 +182,7 @@ static struct option long_options[] = {
{"temp-dir", 1, 0, 'T'},
{"compress", 0, 0, 'z'},
{"daemon", 0, 0, OPT_DAEMON},
{"stats", 0, 0, OPT_STATS},
{"config", 1, 0, OPT_CONFIG},
{"port", 1, 0, OPT_PORT},
{0,0,0,0}};
@@ -185,8 +198,9 @@ void parse_arguments(int argc, char *argv[])
switch (opt)
{
case OPT_VERSION:
printf("rsync version %s protocol version %d\n",
printf("rsync version %s protocol version %d\n\n",
VERSION,PROTOCOL_VERSION);
printf("Written by Andrew Tridgell and Paul Mackerras\n");
exit_cleanup(0);
case OPT_SUFFIX:
@@ -364,6 +378,10 @@ void parse_arguments(int argc, char *argv[])
am_daemon = 1;
break;
case OPT_STATS:
do_stats = 1;
break;
case OPT_CONFIG:
config_file = optarg;
break;

View File

@@ -1,10 +1,10 @@
Summary: Program for efficient remote updates of files.
Name: rsync
Version: 2.0.14
Version: 2.0.18
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.0.14.tar.gz
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.0.18.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync

536
rsync.c
View File

@@ -51,6 +51,7 @@ extern int am_root;
extern int relative_paths;
extern int io_timeout;
extern int io_error;
extern struct stats stats;
/*
free a sums struct
@@ -266,65 +267,67 @@ static struct sum_struct *receive_sums(int f)
static int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
{
int updated = 0;
STRUCT_STAT st2;
extern int am_daemon;
int updated = 0;
STRUCT_STAT st2;
extern int am_daemon;
if (dry_run) return 0;
if (dry_run) return 0;
if (!st) {
if (link_stat(fname,&st2) != 0) {
rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
return 0;
}
st = &st2;
}
if (!st) {
if (link_stat(fname,&st2) != 0) {
rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
return 0;
}
st = &st2;
}
if (preserve_times && !S_ISLNK(st->st_mode) &&
st->st_mtime != file->modtime) {
updated = 1;
if (set_modtime(fname,file->modtime) != 0) {
rprintf(FERROR,"failed to set times on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
if (preserve_times && !S_ISLNK(st->st_mode) &&
st->st_mtime != file->modtime) {
updated = 1;
if (set_modtime(fname,file->modtime) != 0) {
rprintf(FERROR,"failed to set times on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
if ((am_root || !am_daemon) &&
((am_root && preserve_uid && st->st_uid != file->uid) ||
(preserve_gid && st->st_gid != file->gid))) {
if (do_lchown(fname,
(am_root&&preserve_uid)?file->uid:-1,
preserve_gid?file->gid:-1) != 0) {
if (preserve_uid && st->st_uid != file->uid)
updated = 1;
if (verbose>1 || preserve_uid) {
rprintf(FERROR,"chown %s : %s\n",
fname,strerror(errno));
return 0;
}
} else {
updated = 1;
}
}
#ifdef HAVE_CHMOD
if (preserve_perms && !S_ISLNK(st->st_mode) &&
st->st_mode != file->mode) {
updated = 1;
if (do_chmod(fname,file->mode) != 0) {
rprintf(FERROR,"failed to set permissions on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
if (preserve_perms && !S_ISLNK(st->st_mode) &&
st->st_mode != file->mode) {
updated = 1;
if (do_chmod(fname,file->mode) != 0) {
rprintf(FERROR,"failed to set permissions on %s : %s\n",
fname,strerror(errno));
return 0;
}
}
#endif
if ((am_root || !am_daemon) &&
((am_root && preserve_uid && st->st_uid != file->uid) ||
(preserve_gid && st->st_gid != file->gid))) {
if (do_lchown(fname,
(am_root&&preserve_uid)?file->uid:-1,
preserve_gid?file->gid:-1) != 0) {
if (preserve_uid && st->st_uid != file->uid)
updated = 1;
if (verbose>1 || preserve_uid)
rprintf(FERROR,"chown %s : %s\n",
fname,strerror(errno));
return updated;
}
updated = 1;
}
if (verbose > 1 && report) {
if (updated)
rprintf(FINFO,"%s\n",fname);
else
rprintf(FINFO,"%s is uptodate\n",fname);
}
return updated;
if (verbose > 1 && report) {
if (updated)
rprintf(FINFO,"%s\n",fname);
else
rprintf(FINFO,"%s is uptodate\n",fname);
}
return updated;
}
@@ -355,7 +358,11 @@ static int skip_file(char *fname,
/* use a larger block size for really big files */
int adapt_block_size(struct file_struct *file, int bsize)
{
int ret = file->length / (10000); /* rough heuristic */
int ret;
if (bsize != BLOCK_SIZE) return bsize;
ret = file->length / (10000); /* rough heuristic */
ret = ret & ~15; /* multiple of 16 */
if (ret < bsize) ret = bsize;
if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
@@ -559,6 +566,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
if (verbose > 3)
rprintf(FINFO,"data recv %d at %d\n",i,(int)offset);
stats.literal_data += i;
sum_update(data,i);
if (fd != -1 && write_file(fd,data,i) != i) {
@@ -573,6 +581,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
if (i == count-1 && remainder != 0)
len = remainder;
stats.matched_data += len;
if (verbose > 3)
rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
@@ -739,215 +749,245 @@ void sig_int(void)
}
static int get_tmpname(char *fnametmp, char *fname)
{
char *f;
/* open tmp file */
if (tmpdir) {
f = strrchr(fname,'/');
if (f == NULL)
f = fname;
else
f++;
if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
slprintf(fnametmp,MAXPATHLEN-1, "%s/.%s.XXXXXX",tmpdir,f);
return 1;
}
f = strrchr(fname,'/');
if (strlen(fname)+9 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
return 0;
}
if (f) {
*f = 0;
slprintf(fnametmp,MAXPATHLEN-1,"%s/.%s.XXXXXX",
fname,f+1);
*f = '/';
} else {
slprintf(fnametmp,MAXPATHLEN-1,".%s.XXXXXX",fname);
}
return 1;
}
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
while (1)
{
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
write_int(f_gen,-1);
continue;
int fd1,fd2;
STRUCT_STAT st;
char *fname;
char fnametmp[MAXPATHLEN];
struct map_struct *buf;
int i;
struct file_struct *file;
int phase=0;
int recv_ok;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
break;
}
file = flist->files[i];
fname = f_name(file);
if (recurse && delete_mode && !local_name && flist->count>0) {
delete_files(flist);
}
if (local_name)
fname = local_name;
while (1) {
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
rprintf(FINFO,"recv_files phase=%d\n",phase);
write_int(f_gen,-1);
continue;
}
break;
}
if (dry_run) {
if (!am_server && verbose)
printf("%s\n",fname);
continue;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n",
i, flist->count);
exit_cleanup(1);
}
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
file = flist->files[i];
fname = f_name(file);
/* open the file */
fd1 = open(fname,O_RDONLY);
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno));
receive_data(f_in,NULL,-1,NULL);
close(fd1);
continue;
}
if (local_name)
fname = local_name;
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fname);
receive_data(f_in,NULL,-1,NULL);
close(fd1);
continue;
}
if (dry_run) {
if (!am_server && verbose)
printf("%s\n",fname);
continue;
}
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size);
} else {
buf = NULL;
}
if (verbose > 2)
rprintf(FINFO,"recv_files(%s)\n",fname);
/* open tmp file */
if (tmpdir) {
char *f;
f = strrchr(fname,'/');
if (f == NULL)
f = fname;
else
f++;
if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
if (buf) unmap_file(buf);
close(fd1);
continue;
}
slprintf(fnametmp,sizeof(fnametmp)-1, "%s/.%s.XXXXXX",tmpdir,f);
} else {
char *f = strrchr(fname,'/');
/* open the file */
fd1 = open(fname,O_RDONLY);
if (strlen(fname)+9 > MAXPATHLEN) {
rprintf(FERROR,"filename too long\n");
if (buf) unmap_file(buf);
close(fd1);
continue;
}
if (fd1 != -1 && do_fstat(fd1,&st) != 0) {
rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno));
receive_data(f_in,NULL,-1,NULL);
close(fd1);
continue;
}
if (f) {
*f = 0;
slprintf(fnametmp,sizeof(fnametmp)-1,"%s/.%s.XXXXXX",fname,f+1);
*f = '/';
} else {
slprintf(fnametmp,sizeof(fnametmp)-1,".%s.XXXXXX",fname);
}
}
if (NULL == do_mktemp(fnametmp)) {
rprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL);
if (buf) unmap_file(buf);
close(fd1);
continue;
}
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
}
if (fd2 == -1) {
rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
receive_data(f_in,buf,-1,NULL);
if (buf) unmap_file(buf);
close(fd1);
continue;
}
if (fd1 != -1 && !S_ISREG(st.st_mode)) {
rprintf(FERROR,"%s : not a regular file (recv_files)\n",fname);
receive_data(f_in,NULL,-1,NULL);
close(fd1);
continue;
}
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
rprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size);
} else {
buf = NULL;
}
if (!get_tmpname(fnametmp,fname)) {
if (buf) unmap_file(buf);
close(fd1);
continue;
}
if (NULL == do_mktemp(fnametmp)) {
rprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL);
if (buf) unmap_file(buf);
close(fd1);
continue;
}
/* we initially set the perms without the
setuid/setgid bits to ensure that there is no race
condition. They are then correctly updated after
the lchown. Thanks to snabb@epipe.fi for pointing
this out */
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & ACCESSPERMS);
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
file->mode & ACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
receive_data(f_in,buf,-1,NULL);
if (buf) unmap_file(buf);
close(fd1);
continue;
}
cleanup_fname = fnametmp;
cleanup_fname = fnametmp;
if (!am_server && verbose)
printf("%s\n",fname);
if (!am_server && verbose)
printf("%s\n",fname);
/* recv file data */
recv_ok = receive_data(f_in,buf,fd2,fname);
if (buf) unmap_file(buf);
if (fd1 != -1) {
close(fd1);
}
close(fd2);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
if (make_backups) {
char fnamebak[MAXPATHLEN];
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
rprintf(FERROR,"backup filename too long\n");
continue;
}
slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix);
if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) {
rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
continue;
}
}
/* recv file data */
recv_ok = receive_data(f_in,buf,fd2,fname);
/* move tmp file over real file */
if (do_rename(fnametmp,fname) != 0) {
if (errno == EXDEV) {
/* rename failed on cross-filesystem link.
Copy the file instead. */
if (copy_file(fnametmp,fname, file->mode)) {
rprintf(FERROR,"copy %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
}
do_unlink(fnametmp);
} else {
rprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
do_unlink(fnametmp);
}
} else {
set_perms(fname,file,NULL,0);
}
if (buf) unmap_file(buf);
if (fd1 != -1) {
close(fd1);
}
close(fd2);
cleanup_fname = NULL;
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
if (make_backups) {
char fnamebak[MAXPATHLEN];
if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
rprintf(FERROR,"backup filename too long\n");
continue;
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
fname);
} else {
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix);
if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) {
rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
continue;
if (preserve_hard_links)
do_hard_links(flist);
/* now we need to fix any directory permissions that were
modified during the transfer */
for (i = 0; i < flist->count; i++) {
file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
recv_generator(f_name(file),flist,i,-1);
}
}
/* move tmp file over real file */
if (do_rename(fnametmp,fname) != 0) {
if (errno == EXDEV) {
/* rename failed on cross-filesystem link.
Copy the file instead. */
if (copy_file(fnametmp,fname, file->mode)) {
rprintf(FERROR,"copy %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
}
do_unlink(fnametmp);
} else {
rprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
do_unlink(fnametmp);
}
} else {
set_perms(fname,file,NULL,0);
}
cleanup_fname = NULL;
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {
rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
fname);
} else {
if (verbose > 1)
rprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
if (preserve_hard_links)
do_hard_links(flist);
/* now we need to fix any directory permissions that were
modified during the transfer */
for (i = 0; i < flist->count; i++) {
file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
recv_generator(f_name(file),flist,i,-1);
}
if (verbose > 2)
rprintf(FINFO,"recv_files finished\n");
return 0;
if (verbose > 2)
rprintf(FINFO,"recv_files finished\n");
return 0;
}
@@ -962,7 +1002,6 @@ void send_files(struct file_list *flist,int f_out,int f_in)
int i;
struct file_struct *file;
int phase = 0;
int offset=0;
if (verbose > 2)
rprintf(FINFO,"send_files starting\n");
@@ -970,6 +1009,8 @@ void send_files(struct file_list *flist,int f_out,int f_in)
setup_readbuffer(f_in);
while (1) {
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
@@ -983,8 +1024,17 @@ void send_files(struct file_list *flist,int f_out,int f_in)
break;
}
if (i < 0 || i >= flist->count) {
rprintf(FERROR,"Invalid file index %d (count=%d)\n",
i, flist->count);
exit_cleanup(1);
}
file = flist->files[i];
stats.num_transferred_files++;
stats.total_transferred_size += file->length;
fname[0] = 0;
if (file->basedir) {
strlcpy(fname,file->basedir,MAXPATHLEN-1);
@@ -1132,10 +1182,6 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
write_int(f,-1);
}
if (verbose > 2)
rprintf(FINFO,"generator wrote %ld\n",(long)write_total());
}

68
rsync.h
View File

@@ -91,10 +91,6 @@
#include <string.h>
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
@@ -187,6 +183,26 @@
#include <syslog.h>
#include <sys/file.h>
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
@@ -280,9 +296,9 @@ struct file_struct {
};
struct file_list {
int count;
int malloced;
struct file_struct **files;
int count;
int malloced;
struct file_struct **files;
};
struct sum_buf {
@@ -316,6 +332,18 @@ struct exclude_struct {
int local;
};
struct stats {
int64 total_size;
int64 total_transferred_size;
int64 total_written;
int64 total_read;
int64 literal_data;
int64 matched_data;
int flist_size;
int num_files;
int num_transferred_files;
};
/* we need this function because of the silly way in which duplicate
entries are handled in the file lists - we can't change this
@@ -326,21 +354,6 @@ static inline int flist_up(struct file_list *flist, int i)
return i;
}
#if HAVE_DIRENT_H
# include <dirent.h>
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#include "byteorder.h"
#include "version.h"
#include "proto.h"
@@ -360,14 +373,6 @@ extern char *sys_errlist[];
extern int errno;
#endif
#ifndef HAVE_BCOPY
#define bcopy(src,dest,n) memcpy(dest,src,n)
#endif
#ifndef HAVE_BZERO
#define bzero(buf,n) memset(buf,0,n)
#endif
#define SUPPORT_LINKS HAVE_READLINK
#define SUPPORT_HARD_LINKS HAVE_LINK
@@ -432,3 +437,6 @@ extern int errno;
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode) || S_ISSOCK(mode) || S_ISFIFO(mode))
#ifndef ACCESSPERMS
#define ACCESSPERMS 0777
#endif

View File

@@ -217,9 +217,12 @@ explicitly checked on the receiver and any files of the same name
which already exist and have the same checksum and size on the
receiver are skipped. This option can be quite slow.
dit(bf(-a, --archive)) This is equivalent to -rlptDog. It is a quick way
dit(bf(-a, --archive)) This is equivalent to -rlptDg. It is a quick way
of saying I want recursion and want to preserve everything.
Note: if the user launching rsync is root then the -o option (preserve
uid) is also implied.
dit(bf(-r, --recursive)) This tells rsync to copy directories recursively
dit(bf(-R, --relative)) Use relative paths. This means that the full path
@@ -385,7 +388,7 @@ dit(bf(--csum-length LENGTH)) By default the primary checksum used in
rsync is a very strong 16 byte MD4 checksum. In most cases you will
find that a truncated version of this checksum is quite efficient, and
this will decrease the size of the checksum data sent over the link,
making things faster.
making things faster.
You can choose the number of bytes in the truncated checksum using the
--csum-length option. Any value less than or equal to 16 is valid.
@@ -395,6 +398,11 @@ with an incorrect target file. The risk with a value of 16 is
microscopic and can be safely ignored (the universe will probably end
before it fails) but with smaller values the risk is higher.
Current versions of rsync actually use an adaptive algorithm for the
checksum length by default, using a 16 byte file checksum to determine
if a 2nd pass is required with a longer block checksum. Only use this
option if you have read the source code and know what you are doing.
dit(bf(-T, --temp-dir DIR)) This options instructs rsync to use DIR as a
scratch directory when creating a temporary copies of the files
transferred on the receiving side. The default behavior is to create
@@ -422,9 +430,9 @@ option is not specified.
If a user or group name does not exist on the destination system then
the numeric id from the source system is used instead.
dit(bf(--timeout)) This option allows you to set a maximum IO 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(--timeout=TIMEOUT)) This option allows you to set a maximum IO
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(--daemon)) This tells rsync that it is to run as a rsync
daemon. If standard input is a socket then rsync will assume that it
@@ -441,6 +449,11 @@ specified.
dit(bf(--port PORT)) This specifies an alternate TCP port number to use
rather than the default port 873.
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. This option only works in conjunction with
the -v (verbose) option.
enddit()
manpagesection(EXCLUDE PATTERNS)
@@ -485,6 +498,9 @@ itemize(
it() if the pattern starts with "- " (a minus followed by a space)
then it is always considered a exclude pattern, even if specified as
part of an include option. The "- " part is discarded before matching.
it() if the pattern is a single exclamation mark ! then the current
exclude list is reset, removing all previous exclude patterns.
)
The +/- rules are most useful in exclude lists, allowing you to have a
@@ -500,6 +516,31 @@ itemize(
directories and C source files.
)
manpagesection(ENVIRONMENT VARIABLES)
startdit()
dit(bf(CVSIGNORE)) The CVSIGNORE environment variable supplements any
ignore patterns in .cvsignore files. See the --cvs-exclude option for
more details.
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_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
password to a shell transport such as ssh.
dit(bf(USER) or bf(LOGNAME)) The USER or LOGNAME environment variables
are used to determine the default username sent to a rsync server.
dit(bf(HOME)) The HOME environment variable is used to find the users
default .cvsignore file.
enddit()
manpagefiles()
/etc/rsyncd.conf

View File

@@ -225,7 +225,7 @@ connect.
The default is no "hosts allow" option, which means all hosts can connect.
dit(bf(hosts allow)) The "hosts deny" option allows you to specify a
dit(bf(hosts deny)) The "hosts deny" option 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" option for more information.

View File

@@ -81,7 +81,7 @@ static int open_socket_in(int type, int port)
return -1;
}
bzero((char *)&sock,sizeof(sock));
memset((char *)&sock,0,sizeof(sock));
memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length);
sock.sin_port = htons(port);
sock.sin_family = hp->h_addrtype;

View File

@@ -10,6 +10,14 @@
#
#
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
TMP=/tmp/rsync-test.$$
FROM=${TMP}/from

138
util.c
View File

@@ -24,15 +24,33 @@
*/
#include "rsync.h"
int num_waiting(int fd)
/****************************************************************************
Set a fd into nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
int set_nonblocking(int fd)
{
int len=0;
ioctl(fd,FIONREAD,&len);
return(len);
int val;
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
#endif
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
/* this is taken from CVS */
int piped_child(char **command,int *f_in,int *f_out)
{
@@ -206,7 +224,7 @@ int create_directory_path(char *fname)
derived from GNU C's cccp.c.
*/
int full_write(int desc, char *ptr, int len)
static int full_write(int desc, char *ptr, int len)
{
int total_written;
@@ -559,3 +577,111 @@ void *Realloc(void *p, int size)
if (!p) return (void *)malloc(size);
return (void *)realloc(p, size);
}
void clean_fname(char *name)
{
char *p;
int l;
int modified = 1;
if (!name) return;
while (modified) {
modified = 0;
if ((p=strstr(name,"/./"))) {
modified = 1;
while (*p) {
p[0] = p[2];
p++;
}
}
if ((p=strstr(name,"//"))) {
modified = 1;
while (*p) {
p[0] = p[1];
p++;
}
}
if (strncmp(p=name,"./",2) == 0) {
modified = 1;
do {
p[0] = p[2];
} while (*p++);
}
l = strlen(p=name);
if (l > 1 && p[l-1] == '/') {
modified = 1;
p[l-1] = 0;
}
}
}
static char curr_dir[MAXPATHLEN];
/* like chdir() but can be reversed with pop_dir() if save is set. It
is also much faster as it remembers where we have been */
char *push_dir(char *dir, int save)
{
char *ret = curr_dir;
static int initialised;
if (!initialised) {
initialised = 1;
getcwd(curr_dir, sizeof(curr_dir)-1);
}
if (chdir(dir)) return NULL;
if (save) {
ret = strdup(curr_dir);
}
if (*dir == '/') {
strlcpy(curr_dir, dir, sizeof(curr_dir)-1);
} else {
strlcat(curr_dir,"/", sizeof(curr_dir)-1);
strlcat(curr_dir,dir, sizeof(curr_dir)-1);
}
clean_fname(curr_dir);
return ret;
}
/* reverse a push_dir call */
int pop_dir(char *dir)
{
int ret;
ret = chdir(dir);
if (ret) {
free(dir);
return ret;
}
strlcpy(curr_dir, dir, sizeof(curr_dir)-1);
free(dir);
return 0;
}
/* we need to supply our own strcmp function for file list comparisons
to ensure that signed/unsigned usage is consistent between machines. */
int u_strcmp(const char *cs1, const char *cs2)
{
const uchar *s1 = (uchar *)cs1;
const uchar *s2 = (uchar *)cs2;
while (*s1 && *s2 && (*s1 == *s2)) {
s1++; s2++;
}
return (int)*s1 - (int)*s2;
}

View File

@@ -1 +1 @@
#define VERSION "2.0.14"
#define VERSION "2.0.18"

View File

@@ -176,7 +176,7 @@ int r;
break;
case 3: /* illegal */
DUMPBITS(3)
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid block type";
r = Z_DATA_ERROR;
LEAVE
@@ -186,7 +186,7 @@ int r;
NEEDBITS(32)
if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
{
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid stored block lengths";
r = Z_DATA_ERROR;
LEAVE
@@ -219,7 +219,7 @@ int r;
#ifndef PKZIP_BUG_WORKAROUND
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
{
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"too many length or distance symbols";
r = Z_DATA_ERROR;
LEAVE
@@ -252,7 +252,7 @@ int r;
ZFREE(z, s->sub.trees.blens);
r = t;
if (r == Z_DATA_ERROR)
s->mode = BAD;
s->mode = zBAD;
LEAVE
}
s->sub.trees.index = 0;
@@ -289,7 +289,7 @@ int r;
(c == 16 && i < 1))
{
ZFREE(z, s->sub.trees.blens);
s->mode = BAD;
s->mode = zBAD;
z->msg = (char*)"invalid bit length repeat";
r = Z_DATA_ERROR;
LEAVE
@@ -317,7 +317,7 @@ int r;
if (t != Z_OK)
{
if (t == (uInt)Z_DATA_ERROR)
s->mode = BAD;
s->mode = zBAD;
r = t;
LEAVE
}
@@ -361,7 +361,7 @@ int r;
case DONE:
r = Z_STREAM_END;
LEAVE
case BAD:
case zBAD:
r = Z_DATA_ERROR;
LEAVE
default:

View File

@@ -22,7 +22,7 @@ typedef enum {
CHECK2, /* two check bytes to go */
CHECK1, /* one check byte to go */
DONE, /* finished check, done */
BAD} /* got an error--stay here */
zBAD} /* got an error--stay here */
inflate_mode;
/* inflate private state */
@@ -38,7 +38,7 @@ struct internal_state {
uLong was; /* computed check value */
uLong need; /* stream check value */
} check; /* if CHECK, check values to compare */
uInt marker; /* if BAD, inflateSync's marker bytes count */
uInt marker; /* if zBAD, inflateSync's marker bytes count */
} sub; /* submode */
/* mode independent information */
@@ -164,14 +164,14 @@ int f;
NEEDBYTE
if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"unknown compression method";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
}
if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"invalid window size";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -182,7 +182,7 @@ int f;
b = NEXTBYTE;
if (((z->state->sub.method << 8) + b) % 31)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"incorrect header check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -213,7 +213,7 @@ int f;
z->state->mode = DICT0;
return Z_NEED_DICT;
case DICT0:
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"need dictionary";
z->state->sub.marker = 0; /* can try inflateSync */
return Z_STREAM_ERROR;
@@ -221,7 +221,7 @@ int f;
r = inflate_blocks(z->state->blocks, z, r);
if (r == Z_DATA_ERROR)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->state->sub.marker = 0; /* can try inflateSync */
break;
}
@@ -255,7 +255,7 @@ int f;
if (z->state->sub.check.was != z->state->sub.check.need)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->msg = (char*)"incorrect data check";
z->state->sub.marker = 5; /* can't try inflateSync */
break;
@@ -264,7 +264,7 @@ int f;
z->state->mode = DONE;
case DONE:
return Z_STREAM_END;
case BAD:
case zBAD:
return Z_DATA_ERROR;
default:
return Z_STREAM_ERROR;
@@ -310,9 +310,9 @@ z_streamp z;
/* set up */
if (z == Z_NULL || z->state == Z_NULL)
return Z_STREAM_ERROR;
if (z->state->mode != BAD)
if (z->state->mode != zBAD)
{
z->state->mode = BAD;
z->state->mode = zBAD;
z->state->sub.marker = 0;
}
if ((n = z->avail_in) == 0)

View File

@@ -21,7 +21,7 @@ typedef enum {
CODES, /* processing fixed or dynamic block */
DRY, /* output remaining window bytes */
DONE, /* finished last block, done */
BAD} /* got a data error--stuck here */
zBAD} /* got a data error--stuck here */
inflate_block_mode;
/* inflate blocks semi-private state */