Compare commits

...

38 Commits

Author SHA1 Message Date
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
rsync-bugs
79a51e7ee6 preparing for release of 2.0.14 1998-05-29 02:29:33 +00:00
Andrew Tridgell
cad2bba7d8 fixed a bug in the flist sending code that caused the flist sending to
get out of sync.
1998-05-29 02:28:33 +00:00
Andrew Tridgell
fe8c0a9824 use Realloc instead of realloc 1998-05-28 06:40:25 +00:00
Andrew Tridgell
6cdc6b1344 fix realloc call for systems that don't handle realloc(NULL, ...) 1998-05-28 06:29:57 +00:00
Andrew Tridgell
05848a2cc7 don't do recursive deletion if the recurse option is not selected. 1998-05-28 05:05:26 +00:00
Andrew Tridgell
528bfcd79a cosmetic fix. don't display a EOF error when displaying just the motd
from a rsync server
1998-05-28 01:58:33 +00:00
rsync-bugs
a1e13a937c preparing for release of 2.0.13 1998-05-27 13:54:41 +00:00
Andrew Tridgell
e3fe383aaa reduce IO_BUFFER_SIZE by 4 bytes so when then length word gets added
it is a power of 2.
1998-05-27 13:47:34 +00:00
Andrew Tridgell
43bd68e5dd added new include/exclude options to man page 1998-05-27 13:39:40 +00:00
Andrew Tridgell
ea2111d10a - always flush the IO write buffer when reading
- handle start of line in exclude properly
1998-05-27 13:05:05 +00:00
Andrew Tridgell
4c36ddbeec heaps of cleanup in the io code.
we no longer use non-blocking IO, instead it uses select a lot more,
being careful to always allow for reading whenever a valid read fd is
available and chcking timeouts.

also split the file io calls into fileio.c
1998-05-27 12:37:22 +00:00
Andrew Tridgell
2b6b4d539b added support for --include, --include-from and the +/- syntax 1998-05-27 11:02:33 +00:00
Andrew Tridgell
35f69d8ad9 new test code from Phil 1998-05-27 06:31:37 +00:00
Andrew Tridgell
7b1ce0d746 fixed a race condition in the --delete handling code. The bug led to
spurious error messages about not be able to delete some files.

this fix also makes --delete processing more efficient
1998-05-27 06:30:50 +00:00
29 changed files with 1455 additions and 1073 deletions

View File

@@ -25,7 +25,7 @@ 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 exclude.o util.o md4.o main.o checksum.o match.o syscall.o log.o
OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.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)

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

@@ -174,7 +174,7 @@ static int rsync_module(int fd, int i)
}
p = lp_exclude_from(i);
add_exclude_file(p, 1);
add_exclude_file(p, 1, 0);
p = lp_exclude(i);
add_exclude_line(p);
@@ -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

@@ -44,10 +44,8 @@ void setup_protocol(int f_out,int f_in)
if (am_server) {
remote_version = read_int(f_in);
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
} else {
write_int(f_out,PROTOCOL_VERSION);
write_flush(f_out);
remote_version = read_int(f_in);
}
}

View File

@@ -40,8 +40,8 @@ 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(memmove getopt_long lchown setlinebuf vsnprintf setsid glob)
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"
AC_TRY_RUN([#include <fnmatch.h>

325
exclude.c
View File

@@ -17,160 +17,229 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
a lot of this stuff was derived from GNU tar
*/
/* a lot of this stuff was originally derived from GNU tar, although
it has now changed so much that it is hard to tell :) */
#include "rsync.h"
extern int verbose;
static char **exclude_list;
static struct exclude_struct **exclude_list;
static int is_regex(char *str)
/* build an exclude structure given a exclude pattern */
static struct exclude_struct *make_exclude(char *pattern, int include)
{
return strchr(str, '*') || strchr(str, '[') || strchr(str, '?');
struct exclude_struct *ret;
ret = (struct exclude_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("make_exclude");
memset(ret, 0, sizeof(*ret));
ret->orig = strdup(pattern);
if (strncmp(pattern,"- ",2) == 0) {
pattern += 2;
} else if (strncmp(pattern,"+ ",2) == 0) {
ret->include = 1;
pattern += 2;
} else {
ret->include = include;
}
ret->pattern = strdup(pattern);
if (!ret->orig || !ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) ret->regular_exp = 1;
if (strlen(pattern) > 1 && pattern[strlen(pattern)-1] == '/') {
ret->pattern[strlen(pattern)-1] = 0;
ret->directory = 1;
}
if (!strchr(ret->pattern,'/')) {
ret->local = 1;
}
return ret;
}
static void free_exclude(struct exclude_struct *ex)
{
free(ex->orig);
free(ex->pattern);
memset(ex,0,sizeof(*ex));
free(ex);
}
static int check_one_exclude(char *name,struct exclude_struct *ex,
STRUCT_STAT *st)
{
char *p;
int match_start=0;
char *pattern = ex->pattern;
if (ex->local && (p=strrchr(name,'/')))
name = p+1;
if (!name[0]) return 0;
if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
if (*pattern == '/' && *name != '/') {
match_start = 1;
pattern++;
}
if (ex->regular_exp) {
if (fnmatch(pattern, name, 0) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || (!match_start && name[l1-(l2+1)] == '/')))
return 1;
}
return 0;
}
static int check_one_exclude(char *name,char *pattern)
int check_exclude(char *name,struct exclude_struct **local_exclude_list,
STRUCT_STAT *st)
{
char *p;
int n;
if (!strchr(pattern,'/') && (p=strrchr(name,'/')))
name = p+1;
if (exclude_list) {
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n],st))
return !exclude_list[n]->include;
}
if (!name[0]) return 0;
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n],st))
return !local_exclude_list[n]->include;
}
if (*pattern == '/' && *name != '/') pattern++;
if (is_regex(pattern)) {
if (fnmatch(pattern, name, 0) == 0)
return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
(l1==l2 || name[l1-(l2+1)] == '/'))
return 1;
}
return 0;
return 0;
}
int check_exclude(char *name,char **local_exclude_list)
void add_exclude_list(char *pattern,struct exclude_struct ***list, int include)
{
int n;
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (exclude_list) {
for (n=0; exclude_list[n]; n++)
if (check_one_exclude(name,exclude_list[n]))
return 1;
}
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--) {
free_exclude((*list)[len]);
}
free((*list));
*list = NULL;
return;
}
if (local_exclude_list) {
for (n=0; local_exclude_list[n]; n++)
if (check_one_exclude(name,local_exclude_list[n]))
return 1;
}
*list = (struct exclude_struct **)Realloc(*list,sizeof(struct exclude_struct *)*(len+2));
if (!*list || !((*list)[len] = make_exclude(pattern, include)))
out_of_memory("add_exclude");
if (verbose > 2)
rprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}
return 0;
void add_exclude(char *pattern, int include)
{
add_exclude_list(pattern,&exclude_list, include);
}
struct exclude_struct **make_exclude_list(char *fname,
struct exclude_struct **list1,
int fatal, int include)
{
struct exclude_struct **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(1);
}
return list;
}
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0]) add_exclude_list(line,&list,include);
}
fclose(f);
return list;
}
void add_exclude_list(char *pattern,char ***list)
{
int len=0;
if (list && *list)
for (; (*list)[len]; len++) ;
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
rprintf(FINFO,"clearing exclude list\n");
while ((len)--)
free((*list)[len]);
free((*list));
*list = NULL;
return;
}
if (!*list) {
*list = (char **)malloc(sizeof(char *)*2);
} else {
*list = (char **)realloc(*list,sizeof(char *)*(len+2));
}
if (!*list || !((*list)[len] = strdup(pattern)))
out_of_memory("add_exclude");
if (verbose > 2)
rprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}
void add_exclude(char *pattern)
{
add_exclude_list(pattern,&exclude_list);
}
char **make_exclude_list(char *fname,char **list1,int fatal)
{
char **list=list1;
FILE *f = fopen(fname,"r");
char line[MAXPATHLEN];
if (!f) {
if (fatal) {
rprintf(FERROR,"%s : %s\n",fname,strerror(errno));
exit_cleanup(1);
}
return list;
}
while (fgets(line,MAXPATHLEN,f)) {
int l = strlen(line);
if (l && line[l-1] == '\n') l--;
line[l] = 0;
if (line[0]) add_exclude_list(line,&list);
}
fclose(f);
return list;
}
void add_exclude_file(char *fname,int fatal)
void add_exclude_file(char *fname,int fatal,int include)
{
if (!fname || !*fname) return;
exclude_list = make_exclude_list(fname,exclude_list,fatal);
exclude_list = make_exclude_list(fname,exclude_list,fatal,include);
}
void send_exclude_list(int f)
{
int i;
if (exclude_list)
for (i=0;exclude_list[i];i++) {
int l = strlen(exclude_list[i]);
if (l == 0) continue;
write_int(f,l);
write_buf(f,exclude_list[i],l);
}
write_int(f,0);
int i;
extern int remote_version;
if (!exclude_list) {
write_int(f,0);
return;
}
for (i=0;exclude_list[i];i++) {
char *pattern = exclude_list[i]->orig;
int l;
if (remote_version < 19) {
if (strncmp(pattern,"+ ", 2)==0) {
rprintf(FERROR,"remote rsync does not support include syntax - aborting\n");
exit_cleanup(1);
}
if (strncmp(pattern,"- ", 2) == 0) {
pattern += 2;
}
}
l = strlen(pattern);
if (l == 0) continue;
write_int(f,l);
write_buf(f,pattern,l);
}
write_int(f,0);
}
void recv_exclude_list(int f)
{
char line[MAXPATHLEN];
int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line);
}
char line[MAXPATHLEN];
int l;
while ((l=read_int(f))) {
if (l >= MAXPATHLEN) overflow("recv_exclude_list");
read_sbuf(f,line,l);
add_exclude(line,0);
}
}
@@ -181,7 +250,7 @@ void add_exclude_line(char *p)
p = strdup(p);
if (!p) out_of_memory("add_exclude_line");
for (tok=strtok(p," "); tok; tok=strtok(NULL," "))
add_exclude(tok);
add_exclude(tok, 0);
free(p);
}
@@ -197,17 +266,17 @@ static char *cvs_ignore_list[] = {
void add_cvs_excludes(void)
{
char fname[MAXPATHLEN];
char *p;
int i;
char fname[MAXPATHLEN];
char *p;
int i;
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i]);
for (i=0; cvs_ignore_list[i]; i++)
add_exclude(cvs_ignore_list[i], 0);
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
slprintf(fname,sizeof(fname)-1, "%s/.cvsignore",p);
add_exclude_file(fname,0);
}
if ((p=getenv("HOME")) && strlen(p) < (MAXPATHLEN-12)) {
slprintf(fname,sizeof(fname)-1, "%s/.cvsignore",p);
add_exclude_file(fname,0,0);
}
add_exclude_line(getenv("CVSIGNORE"));
add_exclude_line(getenv("CVSIGNORE"));
}

218
fileio.c Normal file
View File

@@ -0,0 +1,218 @@
/*
Copyright (C) Andrew Tridgell 1998
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.
*/
/*
File IO utilities used in rsync
*/
#include "rsync.h"
static char last_byte;
static int last_sparse;
extern int sparse_files;
int sparse_end(int f)
{
if (last_sparse) {
do_lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
static int write_sparse(int f,char *buf,int len)
{
int l1=0,l2=0;
int ret;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0)
do_lseek(f,l1,SEEK_CUR);
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
}
int write_file(int f,char *buf,int len)
{
int ret = 0;
if (!sparse_files)
return write(f,buf,len);
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0) return ret;
return r1;
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
}
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *ret;
ret = (struct map_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("map_file");
ret->map = NULL;
ret->fd = fd;
ret->size = len;
ret->p = NULL;
ret->p_size = 0;
ret->p_offset = 0;
ret->p_len = 0;
#ifdef USE_MMAP
len = MIN(len, MAX_MAP_SIZE);
ret->map = (char *)do_mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
if (ret->map == (char *)-1) {
ret->map = NULL;
} else {
ret->p_len = len;
}
#endif
return ret;
}
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int nread;
if (len == 0)
return NULL;
if (len > (map->size-offset))
len = map->size-offset;
#ifdef USE_MMAP
if (map->map) {
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->map + (offset - map->p_offset));
}
if (munmap(map->map, map->p_len) != 0) {
rprintf(FERROR,"munmap failed : %s\n", strerror(errno));
exit_cleanup(1);
}
/* align the mmap region on a nice boundary back a bit from
where it is asked for to allow for some seeking */
if (offset > 2*CHUNK_SIZE) {
map->p_offset = offset - 2*CHUNK_SIZE;
map->p_offset &= ~((OFF_T)(CHUNK_SIZE-1));
} else {
map->p_offset = 0;
}
/* map up to MAX_MAP_SIZE */
map->p_len = MAX(len, MAX_MAP_SIZE);
map->p_len = MIN(map->p_len, map->size - map->p_offset);
map->map = (char *)do_mmap(NULL,map->p_len,PROT_READ,
MAP_SHARED,map->fd,map->p_offset);
if (map->map == (char *)-1) {
map->map = NULL;
map->p_len = 0;
map->p_offset = 0;
} else {
return (map->map + (offset - map->p_offset));
}
}
#endif
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
len = MAX(len,CHUNK_SIZE);
if (len > (map->size-offset))
len = map->size-offset;
if (len > map->p_size) {
if (map->p) free(map->p);
map->p = (char *)malloc(len);
if (!map->p) out_of_memory("map_ptr");
map->p_size = len;
}
map->p_offset = offset;
map->p_len = len;
if (do_lseek(map->fd,offset,SEEK_SET) != offset) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(1);
}
if ((nread=read(map->fd,map->p,len)) != len) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+nread, 0, len - nread);
}
return map->p;
}
void unmap_file(struct map_struct *map)
{
#ifdef USE_MMAP
if (map->map) {
munmap(map->map,map->p_len);
map->map = NULL;
}
#endif
if (map->p) {
free(map->p);
map->p = NULL;
}
memset(map, 0, sizeof(*map));
free(map);
}

117
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;
@@ -46,7 +47,7 @@ extern int copy_links;
extern int remote_version;
extern int io_error;
static char **local_exclude_list;
static struct exclude_struct **local_exclude_list;
int link_stat(const char *Path, STRUCT_STAT *Buffer)
{
@@ -67,7 +68,7 @@ int link_stat(const char *Path, STRUCT_STAT *Buffer)
*/
static int match_file_name(char *fname,STRUCT_STAT *st)
{
if (check_exclude(fname,local_exclude_list)) {
if (check_exclude(fname,local_exclude_list,st)) {
if (verbose > 2)
rprintf(FINFO,"excluding file %s\n",fname);
return 0;
@@ -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)
{
@@ -169,6 +127,11 @@ void send_file_entry(struct file_struct *file,int f,unsigned base_flags)
if (l1 > 0) flags |= SAME_NAME;
if (l2 > 255) flags |= LONG_NAME;
/* we must make sure we don't send a zero flags byte or the other
end will terminate the flist transfer */
if (flags == 0 && !S_ISDIR(file->mode)) flags |= FLAG_DELETE;
if (flags == 0) flags |= LONG_NAME;
write_byte(f,flags);
if (flags & SAME_NAME)
write_byte(f,l1);
@@ -248,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");
@@ -362,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;
@@ -389,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;
@@ -459,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;
}
@@ -493,10 +456,10 @@ static void send_file_name(int f,struct file_list *flist,char *fname,
}
if (S_ISDIR(file->mode) && recursive) {
char **last_exclude_list = local_exclude_list;
send_directory(f,flist,f_name(file));
local_exclude_list = last_exclude_list;
return;
struct exclude_struct **last_exclude_list = local_exclude_list;
send_directory(f,flist,f_name(file));
local_exclude_list = last_exclude_list;
return;
}
}
@@ -535,7 +498,7 @@ static void send_directory(int f,struct file_list *flist,char *dir)
if (cvs_exclude) {
if (strlen(fname) + strlen(".cvsignore") <= MAXPATHLEN-1) {
strcpy(p,".cvsignore");
local_exclude_list = make_exclude_list(fname,NULL,0);
local_exclude_list = make_exclude_list(fname,NULL,0,0);
} else {
io_error = 1;
rprintf(FINFO,"cannot cvs-exclude in long-named directory %s\n",fname);
@@ -548,7 +511,7 @@ static void send_directory(int f,struct file_list *flist,char *dir)
strcmp(dname,"..")==0)
continue;
strlcpy(p,dname,MAXPATHLEN-(l+1));
send_file_name(f,flist,fname,recurse,FLAG_DELETE);
send_file_name(f,flist,fname,recurse,0);
}
closedir(d);
@@ -561,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");
@@ -641,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;
@@ -691,7 +655,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
if (f != -1) {
io_end_buffering(f);
write_flush(f);
stats.flist_size = stats.total_written - start_write;
stats.num_files = flist->count;
}
if (verbose > 2)
@@ -705,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;
@@ -741,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++;
@@ -772,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:
@@ -786,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));
}
@@ -823,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));
}
@@ -837,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]),

433
io.c
View File

@@ -24,34 +24,20 @@
*/
#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;
static int multiplex_out_fd;
static time_t last_io;
static int eof_error=1;
extern int verbose;
extern int sparse_files;
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;
void setup_nonblocking(int f_in,int f_out)
void setup_readbuffer(int f_in)
{
set_blocking(f_out,0);
buffer_f_in = f_in;
}
@@ -80,45 +66,86 @@ 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
a number <= 0 */
static int read_timeout(int fd, char *buf, int len)
{
int n, ret=0;
io_flush();
while (ret == 0) {
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL,
io_timeout?&tv:NULL) != 1) {
check_timeout();
continue;
}
n = read(fd, buf, len);
if (n > 0) {
stats.total_read += n;
buf += n;
len -= n;
ret += n;
if (io_timeout)
last_io = time(NULL);
continue;
}
if (n == -1 && errno == EINTR) {
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");
}
exit_cleanup(1);
}
rprintf(FERROR,"read error: %s\n", strerror(errno));
exit_cleanup(1);
}
return ret;
}
/* continue trying to read len bytes - don't return until len
has been read */
static void read_loop(int fd, char *buf, int len)
{
while (len) {
int n = read(fd, buf, len);
if (n > 0) {
buf += n;
len -= n;
}
if (n == 0) {
rprintf(FERROR,"EOF in read_loop\n");
exit_cleanup(1);
}
if (n == -1) {
fd_set fds;
struct timeval tv;
int n = read_timeout(fd, buf, len);
if (errno != EAGAIN && errno != EWOULDBLOCK) {
rprintf(FERROR,"io error: %s\n",
strerror(errno));
exit_cleanup(1);
}
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL,
io_timeout?&tv:NULL) != 1) {
check_timeout();
}
}
buf += n;
len -= n;
}
}
/* read from the file descriptor handling multiplexing -
return number of bytes read
never return <= 0 */
static int read_unbuffered(int fd, char *buf, int len)
{
static int remaining;
@@ -127,7 +154,7 @@ static int read_unbuffered(int fd, char *buf, int len)
char line[1024];
if (!io_multiplexing_in || fd != multiplex_in_fd)
return read(fd, buf, len);
return read_timeout(fd, buf, len);
while (ret == 0) {
if (remaining) {
@@ -170,12 +197,13 @@ static int read_unbuffered(int fd, char *buf, int len)
}
/* This function was added to overcome a deadlock problem when using
* ssh. It looks like we can't allow our receive queue to get full or
* ssh will clag up. Uggh. */
static void read_check(int f)
{
int n;
int n = 8192;
if (f == -1) return;
@@ -183,12 +211,6 @@ static void read_check(int f)
read_buffer_p = read_buffer;
}
if ((n=num_waiting(f)) <= 0)
return;
/* things could deteriorate if we read in really small chunks */
if (n < 10) n = 1024;
if (n > MAX_READ_BUFFER/4)
n = MAX_READ_BUFFER/4;
@@ -199,28 +221,26 @@ static void read_check(int f)
if (n > (read_buffer_size - read_buffer_len)) {
read_buffer_size += n;
if (!read_buffer)
read_buffer = (char *)malloc(read_buffer_size);
else
read_buffer = (char *)realloc(read_buffer,read_buffer_size);
read_buffer = (char *)Realloc(read_buffer,read_buffer_size);
if (!read_buffer) out_of_memory("read check");
read_buffer_p = read_buffer;
}
n = read_unbuffered(f,read_buffer+read_buffer_len,n);
if (n > 0) {
read_buffer_len += n;
}
read_buffer_len += n;
}
static int readfd(int fd,char *buffer,int N)
/* do a buffered read from fd. don't return until all N bytes
have been read. If all N can't be read then exit with an error */
static void readfd(int fd,char *buffer,int N)
{
int ret;
int total=0;
struct timeval tv;
if (read_buffer_len < N)
if (read_buffer_len < N && N < 1024) {
read_check(buffer_f_in);
}
while (total < N) {
if (read_buffer_len > 0 && buffer_f_in == fd) {
@@ -234,45 +254,17 @@ static int readfd(int fd,char *buffer,int N)
io_flush();
while ((ret = read_unbuffered(fd,buffer + total,N-total)) == -1) {
fd_set fds;
if (errno != EAGAIN && errno != EWOULDBLOCK)
return -1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL,
io_timeout?&tv:NULL) != 1) {
check_timeout();
}
}
if (ret <= 0)
return total;
ret = read_unbuffered(fd,buffer + total,N-total);
total += ret;
}
if (io_timeout)
last_io = time(NULL);
return total;
}
int32 read_int(int f)
{
int ret;
char b[4];
if ((ret=readfd(f,b,4)) != 4) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_int: Error reading %d bytes : %s\n",
getpid(),4,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 4;
return IVAL(b,0);
char b[4];
readfd(f,b,4);
return IVAL(b,0);
}
int64 read_longint(int f)
@@ -289,13 +281,7 @@ int64 read_longint(int f)
exit_cleanup(1);
#else
if (remote_version >= 16) {
if ((ret=readfd(f,b,8)) != 8) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_longint: Error reading %d bytes : %s\n",
getpid(),8,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 8;
readfd(f,b,8);
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
@@ -305,14 +291,7 @@ int64 read_longint(int f)
void read_buf(int f,char *buf,int len)
{
int ret;
if ((ret=readfd(f,buf,len)) != len) {
if (verbose > 1)
rprintf(FERROR,"(%d) read_buf: Error reading %d bytes : %s\n",
getpid(),len,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += len;
readfd(f,buf,len);
}
void read_sbuf(int f,char *buf,int len)
@@ -323,149 +302,88 @@ void read_sbuf(int f,char *buf,int len)
unsigned char read_byte(int f)
{
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
}
static char last_byte;
static int last_sparse;
int sparse_end(int f)
{
if (last_sparse) {
do_lseek(f,-1,SEEK_CUR);
return (write(f,&last_byte,1) == 1 ? 0 : -1);
}
last_sparse = 0;
return 0;
}
static int write_sparse(int f,char *buf,int len)
{
int l1=0,l2=0;
int ret;
for (l1=0;l1<len && buf[l1]==0;l1++) ;
for (l2=0;l2<(len-l1) && buf[len-(l2+1)]==0;l2++) ;
last_byte = buf[len-1];
if (l1 == len || l2 > 0)
last_sparse=1;
if (l1 > 0)
do_lseek(f,l1,SEEK_CUR);
if (l1 == len)
return len;
if ((ret=write(f,buf+l1,len-(l1+l2))) != len-(l1+l2)) {
if (ret == -1 || ret == 0) return ret;
return (l1+ret);
}
if (l2 > 0)
do_lseek(f,l2,SEEK_CUR);
return len;
unsigned char c;
read_buf(f,(char *)&c,1);
return c;
}
int write_file(int f,char *buf,int len)
{
int ret = 0;
if (!sparse_files)
return write(f,buf,len);
while (len>0) {
int len1 = MIN(len, SPARSE_WRITE_SIZE);
int r1 = write_sparse(f, buf, len1);
if (r1 <= 0) {
if (ret > 0) return ret;
return r1;
}
len -= r1;
buf += r1;
ret += r1;
}
return ret;
}
static int writefd_unbuffered(int fd,char *buf,int len)
/* write len bytes to fd, possibly reading from buffer_f_in if set
in order to unclog the pipe. don't return until all len
bytes have been written */
static void writefd_unbuffered(int fd,char *buf,int len)
{
int total = 0;
fd_set w_fds, r_fds;
int fd_count, count, got_select=0;
int fd_count, count;
struct timeval tv;
int reading;
no_flush++;
reading = (buffer_f_in != -1 && read_buffer_len < MAX_READ_BUFFER);
while (total < len) {
int ret = write(fd,buf+total,len-total);
if (ret == 0) return total;
if (ret == -1 && !(errno == EWOULDBLOCK || errno == EAGAIN))
return -1;
if (ret == -1 && got_select) {
/* hmmm, we got a write select on the fd and
then failed to write. Why doesn't that
mean that the fd is dead? It doesn't on
some systems it seems (eg. IRIX) */
u_sleep(1000);
}
got_select = 0;
if (ret != -1) {
total += ret;
continue;
}
if (read_buffer_len < MAX_READ_BUFFER && buffer_f_in != -1)
read_check(buffer_f_in);
fd_count = fd+1;
FD_ZERO(&w_fds);
FD_ZERO(&r_fds);
FD_SET(fd,&w_fds);
if (buffer_f_in != -1) {
fd_count = fd+1;
if (reading) {
FD_SET(buffer_f_in,&r_fds);
if (buffer_f_in > fd)
fd_count = buffer_f_in+1;
}
tv.tv_sec = BLOCKING_TIMEOUT;
tv.tv_sec = io_timeout;
tv.tv_usec = 0;
count = select(fd_count,buffer_f_in == -1? NULL: &r_fds,
&w_fds,NULL,&tv);
if (count == -1 && errno != EINTR) {
if (verbose > 1)
rprintf(FERROR,"select error: %s\n", strerror(errno));
exit_cleanup(1);
}
if (count == 0) {
count = select(fd_count,
reading?&r_fds:NULL,
&w_fds,NULL,
io_timeout?&tv:NULL);
if (count <= 0) {
check_timeout();
continue;
}
if (FD_ISSET(fd, &w_fds)) {
got_select = 1;
int ret = write(fd,buf+total,len-total);
if (ret == -1 && errno == EINTR) {
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;
}
if (reading && FD_ISSET(buffer_f_in, &r_fds)) {
read_check(buffer_f_in);
}
}
if (io_timeout)
last_io = time(NULL);
return total;
no_flush--;
}
@@ -487,21 +405,13 @@ 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);
if (writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4) !=
io_buffer_count+4) {
rprintf(FERROR,"write failed\n");
exit_cleanup(1);
}
writefd_unbuffered(fd, io_buffer-4, io_buffer_count+4);
} else {
if (writefd_unbuffered(fd, io_buffer, io_buffer_count) !=
io_buffer_count) {
rprintf(FERROR,"write failed\n");
exit_cleanup(1);
}
writefd_unbuffered(fd, io_buffer, io_buffer_count);
}
io_buffer_count = 0;
}
@@ -515,11 +425,12 @@ void io_end_buffering(int fd)
}
}
static int writefd(int fd,char *buf,int len1)
static void writefd(int fd,char *buf,int len)
{
int len = len1;
if (!io_buffer) return writefd_unbuffered(fd, buf, len);
if (!io_buffer) {
writefd_unbuffered(fd, buf, len);
return;
}
while (len) {
int n = MIN(len, IO_BUFFER_SIZE-io_buffer_count);
@@ -532,29 +443,20 @@ static int writefd(int fd,char *buf,int len1)
if (io_buffer_count == IO_BUFFER_SIZE) io_flush();
}
return len1;
}
void write_int(int f,int32 x)
{
int ret;
char b[4];
SIVAL(b,0,x);
if ((ret=writefd(f,b,4)) != 4) {
rprintf(FERROR,"write_int failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 4;
writefd(f,b,4);
}
void write_longint(int f, int64 x)
{
extern int remote_version;
char b[8];
int ret;
if (remote_version < 16 || x <= 0x7FFFFFFF) {
write_int(f, (int)x);
@@ -565,23 +467,12 @@ void write_longint(int f, int64 x)
SIVAL(b,0,(x&0xFFFFFFFF));
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
if ((ret=writefd(f,b,8)) != 8) {
rprintf(FERROR,"write_longint failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 8;
writefd(f,b,8);
}
void write_buf(int f,char *buf,int len)
{
int ret;
if ((ret=writefd(f,buf,len)) != len) {
rprintf(FERROR,"write_buf failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += len;
writefd(f,buf,len);
}
/* write a string to the connection */
@@ -596,15 +487,14 @@ void write_byte(int f,unsigned char c)
write_buf(f,(char *)&c,1);
}
void write_flush(int f)
{
}
int read_line(int f, char *buf, int maxlen)
{
eof_error = 0;
while (maxlen) {
buf[0] = 0;
read_buf(f, buf, 1);
if (buf[0] == 0) return 0;
if (buf[0] == '\n') {
buf[0] = 0;
break;
@@ -618,6 +508,9 @@ int read_line(int f, char *buf, int maxlen)
*buf = 0;
return 0;
}
eof_error = 1;
return 1;
}

View File

@@ -54,7 +54,25 @@ 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
#ifndef HAVE_STRPBRK
/* Find the first ocurrence in S of any character in ACCEPT.
derived from glibc
*/
char *strpbrk(const char *s, const char *accept)
{
while (*s != '\0') {
const char *a = accept;
while (*a != '\0') {
if (*a++ == *s) return (char *)s;
}
++s;
}
return NULL;
}
#endif

View File

@@ -47,7 +47,6 @@
#define BOOL int
#define False 0
#define True 1
#define Realloc realloc
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
#define strequal(a,b) (strcasecmp(a,b)==0)
#define BOOLSTR(b) ((b) ? "Yes" : "No")
@@ -330,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);
}
@@ -368,6 +367,7 @@ static int add_a_service(service *pservice, char *name)
i = iNumServices;
ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
if (ServicePtrs)
pSERVICE(iNumServices) = (service *)malloc(sizeof(service));

104
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,27 +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_flush(f);
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);
}
@@ -150,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);
}
@@ -177,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);
}
@@ -199,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--;
@@ -225,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();
@@ -253,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);
@@ -266,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();
@@ -290,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);
}
@@ -356,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)
@@ -390,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;
@@ -477,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;
}
@@ -498,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);

24
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,11 +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 (n > 0)
write_flush(f);
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);
@@ -276,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)
@@ -285,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);
}

119
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,55 +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," --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_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT,
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
@@ -135,6 +150,8 @@ static struct option long_options[] = {
{"numeric-ids", 0, 0, OPT_NUMERIC_IDS},
{"exclude", 1, 0, OPT_EXCLUDE},
{"exclude-from",1, 0, OPT_EXCLUDE_FROM},
{"include", 1, 0, OPT_INCLUDE},
{"include-from",1, 0, OPT_INCLUDE_FROM},
{"rsync-path", 1, 0, OPT_RSYNC_PATH},
{"one-file-system",0, 0, 'x'},
{"ignore-times",0, 0, 'I'},
@@ -165,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}};
@@ -180,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:
@@ -213,11 +232,19 @@ void parse_arguments(int argc, char *argv[])
break;
case OPT_EXCLUDE:
add_exclude(optarg);
add_exclude(optarg, 0);
break;
case OPT_INCLUDE:
add_exclude(optarg, 1);
break;
case OPT_EXCLUDE_FROM:
add_exclude_file(optarg,1);
add_exclude_file(optarg,1, 0);
break;
case OPT_INCLUDE_FROM:
add_exclude_file(optarg,1, 1);
break;
case 'h':
@@ -351,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.12
Version: 2.0.17
Release: 1
Copyright: GPL
Group: Applications/Networking
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.0.12.tar.gz
Source: ftp://samba.anu.edu.au/pub/rsync/rsync-2.0.17.tar.gz
URL: http://samba.anu.edu.au/rsync/
Packager: Andrew Tridgell <tridge@samba.anu.edu.au>
BuildRoot: /tmp/rsync

View File

@@ -77,7 +77,6 @@
#define BOOL int
#define False 0
#define True 1
#define Realloc realloc
/* -------------------------------------------------------------------------- **
* Constants...

554
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
@@ -74,6 +75,7 @@ static int delete_file(char *fname)
extern int force_delete;
STRUCT_STAT st;
int ret;
extern int recurse;
if (do_unlink(fname) == 0 || errno == ENOENT) return 0;
@@ -93,7 +95,8 @@ static int delete_file(char *fname)
}
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
if (!force_delete || (errno != ENOTEMPTY && errno != EEXIST)) {
if (!force_delete || !recurse ||
(errno != ENOTEMPTY && errno != EEXIST)) {
rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
@@ -147,7 +150,6 @@ static void send_sums(struct sum_struct *s,int f_out)
write_int(f_out,s->sums[i].sum1);
write_buf(f_out,s->sums[i].sum2,csum_length);
}
write_flush(f_out);
}
@@ -265,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;
}
@@ -354,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;
@@ -528,7 +536,6 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
write_int(f_out,i);
send_sums(s,f_out);
write_flush(f_out);
close(fd);
if (buf) unmap_file(buf);
@@ -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);
@@ -638,11 +648,7 @@ static void add_delete_entry(struct file_struct *file)
{
if (dlist_len == dlist_alloc_len) {
dlist_alloc_len += 1024;
if (!delete_list) {
delete_list = (struct delete_list *)malloc(sizeof(delete_list[0])*dlist_alloc_len);
} else {
delete_list = (struct delete_list *)realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len);
}
delete_list = (struct delete_list *)Realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len);
if (!delete_list) out_of_memory("add_delete_entry");
}
@@ -696,7 +702,8 @@ static void delete_files(struct file_list *flist)
if (!S_ISDIR(flist->files[j]->mode) ||
!(flist->files[j]->flags & FLAG_DELETE)) continue;
if (delete_already_done(flist, j)) continue;
if (remote_version < 19 &&
delete_already_done(flist, j)) continue;
name = strdup(f_name(flist->files[j]));
@@ -710,7 +717,8 @@ static void delete_files(struct file_list *flist)
for (i=local_file_list->count-1;i>=0;i--) {
if (!local_file_list->files[i]->basename) continue;
if (S_ISDIR(local_file_list->files[i]->mode))
if (remote_version < 19 &&
S_ISDIR(local_file_list->files[i]->mode))
add_delete_entry(local_file_list->files[i]);
if (-1 == flist_find(flist,local_file_list->files[i])) {
delete_one(local_file_list->files[i]);
@@ -741,216 +749,237 @@ 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);
write_flush(f_gen);
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;
}
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;
}
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;
}
@@ -965,21 +994,21 @@ 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");
setup_nonblocking(f_in,f_out);
setup_readbuffer(f_in);
while (1) {
int offset=0;
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
phase++;
csum_length = SUM_LENGTH;
write_int(f_out,-1);
write_flush(f_out);
if (verbose > 2)
rprintf(FINFO,"send_files phase=%d\n",phase);
continue;
@@ -987,8 +1016,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);
@@ -1061,7 +1099,6 @@ void send_files(struct file_list *flist,int f_out,int f_in)
printf("%s\n",fname+offset);
match_sums(f_out,s,buf,st.st_size);
write_flush(f_out);
if (buf) unmap_file(buf);
close(fd);
@@ -1078,7 +1115,6 @@ void send_files(struct file_list *flist,int f_out,int f_in)
match_report();
write_int(f_out,-1);
write_flush(f_out);
}
@@ -1118,7 +1154,6 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_flush(f);
/* we expect to just sit around now, so don't exit on a timeout. If we
really get a timeout then the other process should exit */
@@ -1138,12 +1173,7 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
rprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_flush(f);
}
if (verbose > 2)
rprintf(FINFO,"generator wrote %ld\n",(long)write_total());
}

81
rsync.h
View File

@@ -41,7 +41,7 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 18
#define PROTOCOL_VERSION 19
#define MIN_PROTOCOL_VERSION 11
#define MAX_PROTOCOL_VERSION 30
@@ -51,13 +51,11 @@
#define WRITE_SIZE (32*1024)
#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (1*1024*1024)
#define IO_BUFFER_SIZE (4096)
#define IO_BUFFER_SIZE (4092)
#define MAX_READ_BUFFER (1024*1024)
#define MAX_ARGS 1000
#define BLOCKING_TIMEOUT 10
#define MPLEX_BASE 7
#define FERROR 1
#define FINFO 2
@@ -93,10 +91,6 @@
#include <string.h>
#endif
#ifdef HAVE_COMPAT_H
#include <compat.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
@@ -189,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
@@ -282,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 {
@@ -309,6 +323,28 @@ struct map_struct {
OFF_T size, p_offset;
};
struct exclude_struct {
char *orig;
char *pattern;
int regular_exp;
int include;
int directory;
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
without breaking existing versions */
@@ -318,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"
@@ -352,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

127
rsync.yo
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
@@ -337,23 +340,30 @@ environment variable.
dit(bf(--rsync-path PATH)) Use this to specify the path to the copy of
rsync on the remote machine. Useful when its not in your path.
dit(bf(--exclude FILE)) This option allows you to selectively exclude
dit(bf(--exclude pattern)) This option allows you to selectively exclude
certain files from the list of files to be transferred. This is most
useful in combination with a recursive transfer.
The option FILE can either be a file name or a shell wildcard
expression. If it is a directory name then rsync will not recurse into
directories of that name.
You may use as many --exclude options on the command line as you like
to build up the list of files to exclude.
If the filename is a single ! then the exclude list is reset.
See the section of exclude patterns for information on the syntax of
this option.
dit(bf(--exclude-from FILE)) This option is similar to the --exclude
option, but instead it adds all filenames listed in the file FILE to
the exclude list.
dit(bf(--include pattern)) This option tells rsync to not exclude the
specified pattern of filenames. This is useful as it allows you to
build up quite complex exclude/include rules.
See the section of exclude patterns for information on the syntax of
this option.
dit(bf(--include-from FILE)) This specifies a list of include patterns
from a file.
dit(bf(-C, --cvs-exclude)) This is a useful shorthand for excluding a
broad range of files that you often don't want to transfer between
systems. It uses the same algorithm that CVS uses to determine if
@@ -378,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.
@@ -388,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
@@ -415,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
@@ -434,6 +449,96 @@ 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)
The exclude and include patterns specified to rsync allow for flexible
selection of what files to transfer and what files to skip.
rsync build a ordered list of include/exclude options as specified on
the command line. When a filename is encountered rsync then checks the
name against each exclude/include pattern in turn. The first matching
pattern is acted on. If it is an exclude pattern than that file is
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.
The patterns themselves can take several forms. The rules are:
itemize(
it() if the pattern starts with a / then it is matched against the
start of the filename, otherwise it is matched against the end of
the filename. Thus /foo would match a file called foo
at the base of the tree whereas foo would match any file
called foo anywhere in the tree.
it() if the pattern ends with a / then it will only match a
directory, not a file, link or device.
it() if the pattern contains a wildcard character from the set
*?[ then regular expression matching is applied using the
normal shell filename matching rules. Otherwise a simple string
match is used.
it() if the pattern contains a / (not counting a trailing /) then it
is matched against the full filename, including any leading
directory. If the pattern doesn't contain a / then it is matched
only against the final component of the filename.
it() if the pattern starts with "+ " (a plus followed by a space)
then it is always considered a include pattern, even if specified as
part of an exclude option. The "+ " part is discarded before matching.
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
single exclude list that contains both include and exclude options.
Here are some examples:
itemize(
it() --exclude "*.o" would exclude all filenames matching *.o
it() --exclude "/foo" would exclude a file in the base directory called foo
it() --exclude "foo/" would exclude any directory called foo
it() --include "*/" --include "*.c" --exclude "*" would include all
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()

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;

20
test.sh
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
@@ -98,14 +106,21 @@ cp ${FROM}/${F1} ${TO}/ThisShouldGo
checkit "rsync --delete -avH ${FROM}/ ${TO}" ${FROM}/ ${TO} \
5 " --delete"
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"
if type ssh >/dev/null ; then
rm -rf ${TO}
checkit "rsync -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO} \
6 "ssh: basic test"
7 "ssh: basic test"
mv ${TO}/${F1} ${TO}/ThisShouldGo
checkit "rsync --delete -avH -e ssh ${FROM}/ localhost:${TO}" ${FROM}/ ${TO}\
7 "ssh: renamed file"
8 "ssh: renamed file"
else
echo ""
echo "**** Skipping SSH tests because ssh is not in the path ****"
@@ -113,4 +128,3 @@ else
fi
checkforlogs ${LOG}.?

295
util.c
View File

@@ -24,137 +24,30 @@
*/
#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);
}
struct map_struct *map_file(int fd,OFF_T len)
{
struct map_struct *ret;
ret = (struct map_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("map_file");
ret->map = NULL;
ret->fd = fd;
ret->size = len;
ret->p = NULL;
ret->p_size = 0;
ret->p_offset = 0;
ret->p_len = 0;
#ifdef USE_MMAP
len = MIN(len, MAX_MAP_SIZE);
ret->map = (char *)do_mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0);
if (ret->map == (char *)-1) {
ret->map = NULL;
} else {
ret->p_len = 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
return ret;
}
char *map_ptr(struct map_struct *map,OFF_T offset,int len)
{
int nread;
if (len == 0)
return NULL;
if (len > (map->size-offset))
len = map->size-offset;
#ifdef USE_MMAP
if (map->map) {
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->map + (offset - map->p_offset));
}
if (munmap(map->map, map->p_len) != 0) {
rprintf(FERROR,"munmap failed : %s\n", strerror(errno));
exit_cleanup(1);
}
/* align the mmap region on a nice boundary back a bit from
where it is asked for to allow for some seeking */
if (offset > 2*CHUNK_SIZE) {
map->p_offset = offset - 2*CHUNK_SIZE;
map->p_offset &= ~((OFF_T)(CHUNK_SIZE-1));
} else {
map->p_offset = 0;
}
/* map up to MAX_MAP_SIZE */
map->p_len = MAX(len, MAX_MAP_SIZE);
map->p_len = MIN(map->p_len, map->size - map->p_offset);
map->map = (char *)do_mmap(NULL,map->p_len,PROT_READ,
MAP_SHARED,map->fd,map->p_offset);
if (map->map == (char *)-1) {
map->map = NULL;
map->p_len = 0;
map->p_offset = 0;
} else {
return (map->map + (offset - map->p_offset));
}
}
#endif
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
return (map->p + (offset - map->p_offset));
}
len = MAX(len,CHUNK_SIZE);
if (len > (map->size-offset))
len = map->size-offset;
if (len > map->p_size) {
if (map->p) free(map->p);
map->p = (char *)malloc(len);
if (!map->p) out_of_memory("map_ptr");
map->p_size = len;
}
map->p_offset = offset;
map->p_len = len;
if (do_lseek(map->fd,offset,SEEK_SET) != offset) {
rprintf(FERROR,"lseek failed in map_ptr\n");
exit_cleanup(1);
}
if ((nread=read(map->fd,map->p,len)) != len) {
if (nread < 0) nread = 0;
/* the best we can do is zero the buffer - the file
has changed mid transfer! */
memset(map->p+nread, 0, len - nread);
}
return map->p;
}
void unmap_file(struct map_struct *map)
{
#ifdef USE_MMAP
if (map->map) {
munmap(map->map,map->p_len);
map->map = NULL;
}
#endif
if (map->p) {
free(map->p);
map->p = NULL;
}
memset(map, 0, sizeof(*map));
free(map);
if((val = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
@@ -302,36 +195,6 @@ int set_modtime(char *fname,time_t modtime)
}
/****************************************************************************
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
else
if SYSV use O_NDELAY
if BSD use FNDELAY
****************************************************************************/
int set_blocking(int fd, int set)
{
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;
if(set) /* Turn blocking on - ie. clear nonblock flag */
val &= ~FLAG_TO_SET;
else
val |= FLAG_TO_SET;
return fcntl( fd, F_SETFL, val);
#undef FLAG_TO_SET
}
/****************************************************************************
create any necessary directories in fname. Unfortunately we don't know
what perms to give the directory when this is called so we need to rely
@@ -361,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;
@@ -708,3 +571,117 @@ int slprintf(char *str, int n, char *format, ...)
return ret;
}
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.12"
#define VERSION "2.0.17"

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 */

View File

@@ -200,11 +200,6 @@ void zcfree (voidpf opaque, voidpf ptr)
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
extern voidp calloc OF((uInt items, uInt size));
extern void free OF((voidpf ptr));
#endif
voidpf zcalloc (opaque, items, size)
voidpf opaque;
unsigned items;