Compare commits

...

42 Commits

Author SHA1 Message Date
rsync-bugs
a90da9985a preparing for release of 1.7.0 1998-03-26 04:53:37 +00:00
Andrew Tridgell
8a24eece38 updated README and man page ready for the new release 1998-03-26 04:43:10 +00:00
Andrew Tridgell
6ba9279fb2 - added an internal io_error flag. Whenever an io error occurs (such
as not being able to open a directory) this flag is set and propogated
to the other end. When this flag is set the --delete code is
disabled. This prevents the problem that io or permission errors could
cause files to be incorrectly deleted on the destination.

- added a --timeout option. This allows you to set an IO timeout in
seconds. If no io occurs in that time then rsync exits with a timeout
error.

- changed some FERROR fds to FINFO
1998-03-26 04:18:47 +00:00
Andrew Tridgell
5fb543d587 if rsync fails to update the group of a file but nothing else then
don't report a problem. On most OSes non-root users can't change the
group of a file.
1998-03-26 00:32:51 +00:00
Andrew Tridgell
0c5f37d9db when using -x to stop at filesystem boundaries, include the mount
points but not their contents.

I did this by calling stat() on the directory above the current
directory and checking to see if it has the correct st_dev. Hopefully
this will work for most systems.

Note that the permissions and ownership on the mount point cannot be
copied correctly as they are unavailable while the filesystem is
mounted. Instead rsync will set the permissions and ownership to those
of the root directory of the mounted filesystem (ie. the apparent
permissions/ownership of the directory)
1998-03-26 00:11:50 +00:00
Andrew Tridgell
42849e9202 add the dummy file to .cvsignore 1998-03-25 11:28:35 +00:00
Andrew Tridgell
a746eb9de0 - fixed a bug in the utimbuf test
- rebuilt prototypes
1998-03-25 11:26:20 +00:00
Andrew Tridgell
71c4617611 - on systems (such as intel linux) where off_t is 32 bits but "long long"
is 64 bits use long long to get the totals right when transferring
  more than 2^32 bytes of data.

- use inline on flist_up if the compiler supports it
1998-03-25 11:08:32 +00:00
Andrew Tridgell
3cb6f5d6cb added a --force option.
This options tells rsync to delete directories even if they are not
empty. This applies to both the --delete option and to cases where
rsync tries to copy a normal file but the destination contains a
directory of the same name. Normally rsync will refuse to do a
recursive directory deletion in such cases, by using --force the
recursive deletion will be done.
1998-03-25 06:05:47 +00:00
Andrew Tridgell
366bd9056c changes to make VPATH work correctly, thanks to patl@cag.lcs.mit.edu 1998-03-25 04:14:18 +00:00
Andrew Tridgell
ac71984aae added this so the lib directory gets created when using VPATH 1998-03-25 04:13:17 +00:00
Andrew Tridgell
649d65edf3 - fixed a bug wth the handling of duplicate names with the new fist
structures

- send intermediate directories when using --relative to ensure the
  permissions are set correctly
1998-03-25 03:34:52 +00:00
Andrew Tridgell
7796395a0a don't show basedir in printed path (a aesthetic change only) 1998-03-25 01:59:23 +00:00
Andrew Tridgell
76076c4bbd fixed the problem where you couldn't specify multiple remote
filenames. The fix will need some testing.
1998-03-25 00:40:47 +00:00
Andrew Tridgell
f92ef572b9 check a few HAVE_* macros 1998-03-24 06:42:11 +00:00
Andrew Tridgell
7308bd66e0 added chmod() and chown() to syscall.c 1998-03-24 06:39:16 +00:00
Andrew Tridgell
0d0e2e93e8 test for "long long" and %lld in configure. 1998-03-23 14:46:03 +00:00
Andrew Tridgell
31e125226d added wrappers around all the system calls that can change what is on
disk. The wrappers check for dry_run.
1998-03-23 13:25:30 +00:00
Andrew Tridgell
3a6a366fc5 finished 64 bit file offset support. Hopefully rsync can now transfer
files up to 2^64 bytes in size. Now I just need to find enough disk
space to test this :-)

The 64 bit offset code only works if off_t is 64 bits (or bigger!) on
both ends of the link. If one end tries to send a file greater than
2^31 in size and the other end doesn't support it then rsync will
abort.

This commit also cleans up some static declarations so they are in a
unitinitialised segment to save load time.
1998-03-23 12:52:57 +00:00
Andrew Tridgell
0b91056090 started to add some 64 bit file offset support - not complete yet 1998-03-23 08:49:48 +00:00
Andrew Tridgell
a76a0039fc label this version 1.7.0alpha 1998-03-23 07:26:14 +00:00
Andrew Tridgell
2d0bb8eb0f save some more memory by only allocating the checksum when needed 1998-03-23 07:25:21 +00:00
Andrew Tridgell
e7ebc36c70 if the file changes during transfer then don't loop forever trying to
update it
1998-03-23 07:11:51 +00:00
Andrew Tridgell
1aa71c8d57 don't adapt the block size to above half the chunk size 1998-03-23 06:26:08 +00:00
Andrew Tridgell
bd39e9d263 prototype update 1998-03-23 04:47:40 +00:00
Andrew Tridgell
3ba62a8308 - keep a list of pids and send them a SIGUSR1 for cleanup rather than
using setpgrp()

- adapt the block size for really large files to reduce the checksum
  size and memory overheads
1998-03-23 04:44:44 +00:00
Andrew Tridgell
feaa89c410 for systems with a broken select use u_sleep() to ensure the write
process doesn't chew too much cpu time.
1998-03-23 04:14:21 +00:00
Andrew Tridgell
3ec4dd9781 a large change to make rsync much more memory efficient. This is done
in 3 ways:

1) the realloc is done on a list of pointers, not a list of structures
2) only the basename of the file is now kept in the file struct an a
   util function f_name() is now used to access the full name when
   required.
3) pointers to directory names are re-used

hopefully I haven't broken anything. This will need lots of testing.
1998-03-23 03:45:02 +00:00
Andrew Tridgell
ec0e5ac001 compatibility functions now split into their own file 1998-02-24 11:54:10 +00:00
Andrew Tridgell
1e9f155ade *** empty log message *** 1998-01-27 17:51:37 +00:00
Andrew Tridgell
6bbbc08b83 *** empty log message *** 1998-01-13 19:25:59 +00:00
Andrew Tridgell
13dc412d76 *** empty log message *** 1998-01-13 19:19:48 +00:00
Andrew Tridgell
950ab32d38 *** empty log message *** 1998-01-13 18:35:10 +00:00
Andrew Tridgell
d0390cd384 *** empty log message *** 1998-01-13 17:16:14 +00:00
Andrew Tridgell
f6c347425a *** empty log message *** 1998-01-13 15:57:26 +00:00
Andrew Tridgell
3b3a2fbcf0 *** empty log message *** 1998-01-06 16:53:52 +00:00
Andrew Tridgell
95a38e8684 cosmetic changes only
- minor correction to --update docs
- don't print "building file list" stuff when building a local file
list for use in the --delete code.
- remove some spaces at the end of lines in Makefile.in
1998-01-05 23:30:44 +00:00
Andrew Tridgell
c778aaa048 *** empty log message *** 1998-01-01 15:53:05 +00:00
Andrew Tridgell
3fac9b6e93 removed the read_write() call, it's not used anywhere 1997-12-31 16:48:11 +00:00
Andrew Tridgell
964ca2eca5 simplified the logic of whether to skip a file or not. The -c
(always_checksum) option is probably now more useful.
1997-12-31 16:39:34 +00:00
Andrew Tridgell
684b4e3113 buffer overflow patches from mhpower@mit.edu (Matt Power) 1997-12-30 17:36:58 +00:00
Andrew Tridgell
dc7a947853 fixed the --suffix option. It wasn't being propogated to the remote
end in the server_options() function.
1997-12-30 10:54:47 +00:00
22 changed files with 2269 additions and 1293 deletions

View File

@@ -7,32 +7,36 @@ INSTALL_BIN=$(exec_prefix)/bin
INSTALL_MAN=$(prefix)/man
LIBS=@LIBS@
CC=@CC@
CC=@CC@
CFLAGS=@CFLAGS@
INSTALLCMD=@INSTALL@
SRC=@srcdir@
VPATH=@srcdir@
srcdir=@srcdir@
SHELL=/bin/sh
.SUFFIXES:
.SUFFIXES: .c .o
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o
OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o
OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o $(LIBOBJ)
LIBOBJ=lib/getopt.o lib/fnmatch.o lib/zlib.o lib/compat.o
OBJS1=rsync.o exclude.o util.o md4.o main.o checksum.o match.o syscall.o
OBJS=$(OBJS1) flist.o io.o compat.o hlink.o token.o uidlist.o $(LIBOBJ)
# note that the -I. is needed to handle config.h when using VPATH
.c.o:
$(CC) $(CFLAGS) -c $*.c -o $*.o
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@
all: rsync
install: all
-mkdir -p ${INSTALL_BIN}
${INSTALLCMD} -m 755 rsync ${INSTALL_BIN}
${INSTALLCMD} -m 644 rsync.1 ${INSTALL_MAN}/man1
-mkdir -p ${INSTALL_MAN}/man1
${INSTALLCMD} -m 644 $(srcdir)/rsync.1 ${INSTALL_MAN}/man1
rsync: $(OBJS)
rsync: $(OBJS)
$(CC) $(CFLAGS) -o rsync $(OBJS) $(LIBS)
proto:
@@ -41,7 +45,7 @@ proto:
clean:
rm -f *~ $(OBJS) rsync config.cache config.log config.status
dist:
dist:
tar --exclude-from .ignore -czf dist.tar.gz .
-mkdir rsync-$(VERSION)
(cd rsync-$(VERSION) ; tar xzf ../dist.tar.gz)

10
README
View File

@@ -47,7 +47,11 @@ Options:
--rsync-path PATH specify path to rsync on the remote machine
-C, --cvs-exclude auto ignore files in the same way CVS does
--delete delete files that don't exist on the sending side
--force force deletion of directories even if not empty
--numeric-ids don't map uid/gid values by user/group name
--timeout TIME set IO timeout in seconds
-I, --ignore-times don't exclude files that match length and time
-T --temp-dir DIR create temporary files in directory DIR
-z, --compress compress file data
--exclude FILE exclude file FILE
--exclude-from FILE exclude files listed in FILE
@@ -89,7 +93,7 @@ BUG REPORTS
-----------
If you have web access then please look at
http://samba.anu.edu.au/cgi-bin/rsync
http://samba.anu.edu.au/rsync/
This will give you access to the bug tracking system used by the
developers of rsync and will allow you to look at other bug reports or
@@ -119,9 +123,9 @@ COPYRIGHT
---------
Rsync was written by Andrew Tridgell and Paul Mackerras, and is
available under the GPL.
available under the Gnu Public License.
Andrew.Tridgell@anu.edu.au
tridge@samba.anu.edu.au
paulus@cs.anu.edu.au

View File

@@ -65,8 +65,8 @@ void get_checksum2(char *buf,int len,char *sum)
{
int i;
MDstruct MD;
static char *buf1 = NULL;
static int len1 = 0;
static char *buf1;
static int len1;
if (len > len1) {
if (buf1) free(buf1);
@@ -95,11 +95,11 @@ void get_checksum2(char *buf,int len,char *sum)
void file_checksum(char *fname,char *sum,off_t size)
{
int i;
off_t i;
MDstruct MD;
struct map_struct *buf;
int fd;
int len = size;
off_t len = size;
char tmpchunk[CSUM_CHUNK];
bzero(sum,csum_length);

157
compat.c
View File

@@ -36,152 +36,7 @@ extern int checksum_seed;
extern int remote_version;
void (*send_file_entry)(struct file_struct *file,int f) = NULL;
void (*receive_file_entry)(struct file_struct *file,
unsigned char flags,int f) = NULL;
void send_file_entry_v10(struct file_struct *file,int f)
{
unsigned char flags;
static mode_t last_mode=0;
static dev_t last_rdev=0;
static uid_t last_uid=0;
static gid_t last_gid=0;
static char lastdir[MAXPATHLEN]="";
char *p=NULL;
if (f == -1) return;
if (!file) {
write_byte(f,0);
return;
}
flags = FILE_VALID;
if (file->mode == last_mode) flags |= SAME_MODE;
if (file->rdev == last_rdev) flags |= SAME_RDEV;
if (file->uid == last_uid) flags |= SAME_UID;
if (file->gid == last_gid) flags |= SAME_GID;
if (strncmp(file->name,lastdir,strlen(lastdir)) == 0) {
flags |= SAME_DIR;
p = file->name + strlen(lastdir);
} else {
p = file->name;
}
write_byte(f,flags);
if (flags & SAME_DIR)
write_byte(f,strlen(p));
else
write_int(f,strlen(p));
write_buf(f,p,strlen(p));
write_int(f,(int)file->modtime);
write_int(f,(int)file->length);
if (!(flags & SAME_MODE))
write_int(f,(int)file->mode);
if (preserve_uid && !(flags & SAME_UID))
write_int(f,(int)file->uid);
if (preserve_gid && !(flags & SAME_GID))
write_int(f,(int)file->gid);
if (preserve_devices && IS_DEVICE(file->mode) && !(flags & SAME_RDEV))
write_int(f,(int)file->rdev);
#if SUPPORT_LINKS
if (preserve_links && S_ISLNK(file->mode)) {
write_int(f,strlen(file->link));
write_buf(f,file->link,strlen(file->link));
}
#endif
if (always_checksum) {
write_buf(f,file->sum,csum_length);
}
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
p = strrchr(file->name,'/');
if (p) {
int l = (int)(p - file->name) + 1;
strncpy(lastdir,file->name,l);
lastdir[l] = 0;
} else {
strcpy(lastdir,"");
}
}
void receive_file_entry_v10(struct file_struct *file,
unsigned char flags,int f)
{
static mode_t last_mode=0;
static dev_t last_rdev=0;
static uid_t last_uid=0;
static gid_t last_gid=0;
static char lastdir[MAXPATHLEN]="";
char *p=NULL;
int l1,l2;
if (flags & SAME_DIR) {
l1 = read_byte(f);
l2 = strlen(lastdir);
} else {
l1 = read_int(f);
l2 = 0;
}
file->name = (char *)malloc(l1+l2+1);
if (!file->name) out_of_memory("receive_file_entry");
strncpy(file->name,lastdir,l2);
read_buf(f,file->name+l2,l1);
file->name[l1+l2] = 0;
file->modtime = (time_t)read_int(f);
file->length = (off_t)read_int(f);
file->mode = (flags & SAME_MODE) ? last_mode : (mode_t)read_int(f);
if (preserve_uid)
file->uid = (flags & SAME_UID) ? last_uid : (uid_t)read_int(f);
if (preserve_gid)
file->gid = (flags & SAME_GID) ? last_gid : (gid_t)read_int(f);
if (preserve_devices && IS_DEVICE(file->mode))
file->rdev = (flags & SAME_RDEV) ? last_rdev : (dev_t)read_int(f);
#if SUPPORT_LINKS
if (preserve_links && S_ISLNK(file->mode)) {
int l = read_int(f);
file->link = (char *)malloc(l+1);
if (!file->link) out_of_memory("receive_file_entry");
read_buf(f,file->link,l);
file->link[l] = 0;
}
#endif
if (always_checksum)
read_buf(f,file->sum,csum_length);
last_mode = file->mode;
last_rdev = file->rdev;
last_uid = file->uid;
last_gid = file->gid;
p = strrchr(file->name,'/');
if (p) {
int l = (int)(p - file->name) + 1;
strncpy(lastdir,file->name,l);
lastdir[l] = 0;
} else {
strcpy(lastdir,"");
}
}
extern int verbose;
void setup_protocol(int f_out,int f_in)
{
@@ -201,13 +56,9 @@ void setup_protocol(int f_out,int f_in)
exit_cleanup(1);
}
if (remote_version == 10) {
send_file_entry = send_file_entry_v10;
receive_file_entry = receive_file_entry_v10;
} else {
send_file_entry = send_file_entry_v11;
receive_file_entry = receive_file_entry_v11;
}
if (verbose > 2)
fprintf(FINFO, "local_version=%d remote_version=%d\n",
PROTOCOL_VERSION, remote_version);
if (remote_version >= 12) {
if (am_server) {

View File

@@ -52,4 +52,17 @@ main() { exit(fnmatch("*.o", "x.o", 0) == 0? 0: 1); }],
echo yes;AC_DEFINE(HAVE_FNMATCH),
echo no)
AC_OUTPUT(Makefile)
echo $ac_n "checking for long long... $ac_c"
AC_TRY_RUN([#include <stdio.h>
main() { long long x = 1000000000000; char b[20]; sprintf(b,"%lld", x); exit(strcmp("1000000000000", b) == 0? 0: 1); }],
echo yes;AC_DEFINE(HAVE_LONGLONG),
echo no)
echo $ac_n "checking for utimbuf ... $ac_c"
AC_TRY_COMPILE([#include <sys/types.h>
#include <utime.h>],
[struct utimbuf tbuf; tbuf.actime = 0; tbuf.modtime = 1; return utime("foo.c",&tbuf);],
echo yes;AC_DEFINE(HAVE_UTIMBUF),
echo no)
AC_OUTPUT(Makefile lib/dummy)

View File

@@ -24,8 +24,9 @@
#include "rsync.h"
extern int verbose;
extern int am_server;
static char **exclude_list = NULL;
static char **exclude_list;
static int is_regex(char *str)
{
@@ -86,7 +87,7 @@ void add_exclude_list(char *pattern,char ***list)
if (strcmp(pattern,"!") == 0) {
if (verbose > 2)
fprintf(FERROR,"clearing exclude list\n");
fprintf(FINFO,"clearing exclude list\n");
while ((len)--)
free((*list)[len]);
free((*list));
@@ -104,7 +105,7 @@ void add_exclude_list(char *pattern,char ***list)
out_of_memory("add_exclude");
if (verbose > 2)
fprintf(FERROR,"add_exclude(%s)\n",pattern);
fprintf(FINFO,"add_exclude(%s)\n",pattern);
(*list)[len+1] = NULL;
}

1267
flist.c
View File

File diff suppressed because it is too large Load Diff

35
hlink.c
View File

@@ -31,17 +31,17 @@ static int hlink_compare(struct file_struct *f1,struct file_struct *f2)
if (!S_ISREG(f2->mode)) return 1;
if (f1->dev != f2->dev)
return (f1->dev - f2->dev);
return (int)(f1->dev - f2->dev);
if (f1->inode != f2->inode)
return (f1->inode - f2->inode);
return file_compare(f1,f2);
return file_compare(&f1,&f2);
}
static struct file_struct *hlink_list = NULL;
static int hlink_count=0;
static struct file_struct *hlink_list;
static int hlink_count;
#endif
void init_hard_links(struct file_list *flist)
@@ -80,7 +80,10 @@ int check_hard_link(struct file_struct *file)
while (low != high) {
int mid = (low+high)/2;
ret = hlink_compare(&hlink_list[mid],file);
if (ret == 0) break;
if (ret == 0) {
low = mid;
break;
}
if (ret > 0)
high=mid;
else
@@ -111,35 +114,35 @@ void do_hard_links(struct file_list *flist)
for (i=1;i<hlink_count;i++) {
if (S_ISREG(hlink_list[i].mode) &&
S_ISREG(hlink_list[i-1].mode) &&
hlink_list[i].name && hlink_list[i-1].name &&
hlink_list[i].basename && hlink_list[i-1].basename &&
hlink_list[i].dev == hlink_list[i-1].dev &&
hlink_list[i].inode == hlink_list[i-1].inode) {
struct stat st1,st2;
if (link_stat(hlink_list[i-1].name,&st1) != 0) continue;
if (link_stat(hlink_list[i].name,&st2) != 0) {
if (!dry_run && link(hlink_list[i-1].name,hlink_list[i].name) != 0) {
if (link_stat(f_name(&hlink_list[i-1]),&st1) != 0) continue;
if (link_stat(f_name(&hlink_list[i]),&st2) != 0) {
if (do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
hlink_list[i].name,
hlink_list[i-1].name,strerror(errno));
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
}
} else {
if (st2.st_dev == st1.st_dev && st2.st_ino == st1.st_ino) continue;
if (!dry_run && (unlink(hlink_list[i].name) != 0 ||
link(hlink_list[i-1].name,hlink_list[i].name) != 0)) {
if (do_unlink(f_name(&hlink_list[i])) != 0 ||
do_link(f_name(&hlink_list[i-1]),f_name(&hlink_list[i])) != 0) {
if (verbose > 0)
fprintf(FINFO,"link %s => %s : %s\n",
hlink_list[i].name,
hlink_list[i-1].name,strerror(errno));
f_name(&hlink_list[i]),
f_name(&hlink_list[i-1]),strerror(errno));
continue;
}
}
if (verbose > 0)
fprintf(FINFO,"%s => %s\n",
hlink_list[i].name,hlink_list[i-1].name);
f_name(&hlink_list[i]),f_name(&hlink_list[i-1]));
}
}
#endif

183
io.c
View File

@@ -24,18 +24,19 @@
*/
#include "rsync.h"
static int total_written = 0;
static int total_read = 0;
static int64 total_written;
static int64 total_read;
extern int verbose;
extern int sparse_files;
extern int io_timeout;
int write_total(void)
int64 write_total(void)
{
return total_written;
}
int read_total(void)
int64 read_total(void)
{
return total_read;
}
@@ -49,10 +50,10 @@ void setup_nonblocking(int f_in,int f_out)
}
static char *read_buffer = NULL;
static char *read_buffer_p = NULL;
static int read_buffer_len = 0;
static int read_buffer_size = 0;
static char *read_buffer;
static char *read_buffer_p;
static int read_buffer_len;
static int read_buffer_size;
/* This function was added to overcome a deadlock problem when using
@@ -95,39 +96,70 @@ static void read_check(int f)
}
}
static time_t last_io;
static void check_timeout(void)
{
time_t t;
if (!io_timeout) return;
if (!last_io) {
last_io = time(NULL);
return;
}
t = time(NULL);
if (last_io && io_timeout && (t-last_io)>io_timeout) {
fprintf(FERROR,"read timeout after %d second - exiting\n",
(int)(t-last_io));
exit_cleanup(1);
}
}
static int readfd(int fd,char *buffer,int N)
{
int ret;
int total=0;
int ret;
int total=0;
struct timeval tv;
if (read_buffer_len < N)
read_check(buffer_f_in);
while (total < N) {
if (read_buffer_len > 0 && buffer_f_in == fd) {
ret = MIN(read_buffer_len,N-total);
memcpy(buffer+total,read_buffer_p,ret);
read_buffer_p += ret;
read_buffer_len -= ret;
continue;
}
if (read_buffer_len < N)
read_check(buffer_f_in);
while (total < N)
{
if (read_buffer_len > 0 && buffer_f_in == fd) {
ret = MIN(read_buffer_len,N-total);
memcpy(buffer+total,read_buffer_p,ret);
read_buffer_p += ret;
read_buffer_len -= ret;
} else {
while ((ret = read(fd,buffer + total,N - total)) == -1) {
fd_set fds;
while ((ret = read(fd,buffer + total,N-total)) == -1) {
fd_set fds;
if (errno != EAGAIN && errno != EWOULDBLOCK)
return -1;
FD_ZERO(&fds);
FD_SET(fd, &fds);
select(fd+1, &fds, NULL, NULL, NULL);
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, &tv) != 1) {
check_timeout();
}
}
if (ret <= 0)
return total;
total += ret;
}
}
if (ret <= 0)
if (io_timeout)
last_io = time(NULL);
return total;
total += ret;
}
return total;
}
@@ -145,6 +177,34 @@ int read_int(int f)
return IVAL(b,0);
}
int64 read_longint(int f)
{
extern int remote_version;
int64 ret;
char b[8];
ret = read_int(f);
if (ret != -1) return ret;
#ifndef HAVE_LONGLONG
fprintf(FERROR,"Integer overflow - attempted 64 bit offset\n");
exit_cleanup(1);
#else
if (remote_version >= 16) {
if ((ret=readfd(f,b,8)) != 8) {
if (verbose > 1)
fprintf(FERROR,"(%d) Error reading %d bytes : %s\n",
getpid(),8,ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_read += 8;
ret = IVAL(b,0) | (((int64)IVAL(b,4))<<32);
}
#endif
return ret;
}
void read_buf(int f,char *buf,int len)
{
int ret;
@@ -165,8 +225,8 @@ unsigned char read_byte(int f)
}
static char last_byte=0;
static int last_sparse = 0;
static char last_byte;
static int last_sparse;
int sparse_end(int f)
{
@@ -211,27 +271,6 @@ int write_sparse(int f,char *buf,int len)
return len;
}
int read_write(int fd_in,int fd_out,int size)
{
static char *buf=NULL;
int bufsize = sparse_files?SPARSE_WRITE_SIZE:WRITE_SIZE;
int total=0;
if (!buf) {
buf = (char *)malloc(bufsize);
if (!buf) out_of_memory("read_write");
}
while (total < size) {
int n = MIN(size-total,bufsize);
read_buf(fd_in,buf,n);
if (write_sparse(fd_out,buf,n) != n)
return total;
total += n;
}
return total;
}
static int writefd(int fd,char *buf,int len)
{
@@ -255,6 +294,7 @@ static int writefd(int fd,char *buf,int len)
/* 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);
#if 0
fprintf(FERROR,"write exception\n");
exit_cleanup(1);
@@ -287,7 +327,10 @@ static int writefd(int fd,char *buf,int len)
exit_cleanup(1);
}
if (count == 0) continue;
if (count == 0) {
check_timeout();
continue;
}
if (FD_ISSET(fd, &w_fds)) {
got_select = 1;
@@ -297,6 +340,9 @@ static int writefd(int fd,char *buf,int len)
}
}
if (io_timeout)
last_io = time(NULL);
return total;
}
@@ -315,6 +361,29 @@ void write_int(int f,int x)
total_written += 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);
return;
}
write_int(f, -1);
SIVAL(b,0,(x&0xFFFFFFFF));
SIVAL(b,4,((x>>32)&0xFFFFFFFF));
if ((ret=writefd(f,b,8)) != 8) {
fprintf(FERROR,"write_longint failed : %s\n",
ret==-1?strerror(errno):"EOF");
exit_cleanup(1);
}
total_written += 8;
}
void write_buf(int f,char *buf,int len)
{
int ret;

View File

@@ -7,6 +7,7 @@ config.h
config.log
config.status
dist.tar.gz
dummy
rsync
rsync-0.1
rsync-0.1
@@ -30,6 +31,13 @@ rsync-0.5
rsync-0.5
rsync-0.5
rsync-0.5.tar.gz
rsync-0.6
rsync-0.7
rsync-0.7
rsync-0.8
rsync-0.8
rsync-0.8
rsync-0.8
rsync-ERSION
rsync.aux
rsync.dvi
@@ -39,10 +47,3 @@ tech_report.dvi
tech_report.log
tech_report.ps
test
rsync-0.6
rsync-0.7
rsync-0.7
rsync-0.8
rsync-0.8
rsync-0.8
rsync-0.8

52
lib/compat.c Normal file
View File

@@ -0,0 +1,52 @@
/*
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.
*/
/*
compatibility functions - replacing functions for platforms that don't
have them.
*/
#include "rsync.h"
#ifndef HAVE_STRDUP
char *strdup(char *s)
{
int l = strlen(s) + 1;
char *ret = (char *)malloc(l);
if (ret)
strcpy(ret,s);
return ret;
}
#endif
#ifndef HAVE_GETCWD
char *getcwd(char *buf, int size)
{
return getwd(buf);
}
#endif
#ifndef HAVE_WAITPID
pid_t waitpid(pid_t pid, int *statptr, int options)
{
return wait4(pid, statptr, options, NULL);
}
#endif

2
lib/dummy.in Normal file
View File

@@ -0,0 +1,2 @@
This is a dummy file to ensure that the lib directory gets created
by configure when a VPATH is used.

194
main.c
View File

@@ -22,10 +22,11 @@
int verbose = 0;
int always_checksum = 0;
time_t starttime;
off_t total_size = 0;
int64 total_size = 0;
int block_size=BLOCK_SIZE;
char *backup_suffix = BACKUP_SUFFIX;
char *tmpdir = NULL;
static char *rsync_path = RSYNC_NAME;
@@ -52,26 +53,30 @@ int do_compression=0;
int am_root=0;
int orig_umask=0;
int relative_paths=0;
int numeric_ids = 0;
int force_delete = 0;
int io_timeout = 0;
int io_error = 0;
extern int csum_length;
int am_server = 0;
static int sender = 0;
static int sender;
int recurse = 0;
static void usage(FILE *f);
static void report(int f)
{
int in,out,tsize;
int64 in,out,tsize;
time_t t = time(NULL);
if (!verbose) return;
if (am_server && sender) {
write_int(f,read_total());
write_int(f,write_total());
write_int(f,total_size);
write_longint(f,read_total());
write_longint(f,write_total());
write_longint(f,total_size);
write_flush(f);
return;
}
@@ -79,17 +84,24 @@ static void report(int f)
if (sender) {
in = read_total();
out = write_total();
tsize = (int)total_size;
tsize = total_size;
} else {
in = read_int(f);
out = read_int(f);
tsize = read_int(f);
in = read_longint(f);
out = read_longint(f);
tsize = read_longint(f);
}
printf("wrote %d bytes read %d bytes %g bytes/sec\n",
out,in,(in+out)/(0.5 + (t-starttime)));
printf("total size is %d speedup is %g\n",
tsize,(1.0*tsize)/(in+out));
#if HAVE_LONGLONG
printf("wrote %lld bytes read %lld bytes %g bytes/sec\n",
(long long)out,(long long)in,(in+out)/(0.5 + (t-starttime)));
printf("total size is %lld speedup is %g\n",
(long long)tsize,(1.0*tsize)/(in+out));
#else
printf("wrote %ld bytes read %ld bytes %g bytes/sec\n",
(long)out,(long)in,(in+out)/(0.5 + (t-starttime)));
printf("total size is %ld speedup is %g\n",
(long)tsize,(1.0*tsize)/(in+out));
#endif
}
@@ -98,6 +110,7 @@ static void server_options(char **args,int *argc)
int ac = *argc;
static char argstr[50];
static char bsize[30];
static char iotime[30];
int i, x;
args[ac++] = "--server";
@@ -158,9 +171,30 @@ static void server_options(char **args,int *argc)
args[ac++] = bsize;
}
if (io_timeout) {
sprintf(iotime,"--timeout=%d",io_timeout);
args[ac++] = iotime;
}
if (strcmp(backup_suffix, BACKUP_SUFFIX)) {
args[ac++] = "--suffix";
args[ac++] = backup_suffix;
}
if (delete_mode)
args[ac++] = "--delete";
if (force_delete)
args[ac++] = "--force";
if (numeric_ids)
args[ac++] = "--numeric-ids";
if (tmpdir) {
args[ac++] = "--temp-dir";
args[ac++] = tmpdir;
}
*argc = ac;
}
@@ -170,7 +204,7 @@ static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f
{
char *args[100];
int i,argc=0, ret;
char *tok,*p,*dir=NULL;
char *tok,*dir=NULL;
if (!local_server) {
if (!cmd)
@@ -205,31 +239,18 @@ static int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f
server_options(args,&argc);
if (path && *path) {
dir = strdup(path);
p = strrchr(dir,'/');
if (p && !relative_paths) {
*p = 0;
if (!dir[0])
args[argc++] = "/";
else
args[argc++] = dir;
p++;
} else {
args[argc++] = ".";
p = dir;
}
if (p[0])
args[argc++] = path;
}
args[argc++] = ".";
if (path && *path)
args[argc++] = path;
args[argc] = NULL;
if (verbose > 3) {
fprintf(FERROR,"cmd=");
fprintf(FINFO,"cmd=");
for (i=0;i<argc;i++)
fprintf(FERROR,"%s ",args[i]);
fprintf(FERROR,"\n");
fprintf(FINFO,"%s ",args[i]);
fprintf(FINFO,"\n");
}
ret = piped_child(args,f_in,f_out);
@@ -291,31 +312,31 @@ static char *get_local_name(struct file_list *flist,char *name)
void do_server_sender(int argc,char *argv[])
{
int i;
char *dir = argv[0];
struct file_list *flist;
char *dir = argv[0];
if (verbose > 2)
fprintf(FERROR,"server_sender starting pid=%d\n",(int)getpid());
fprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid());
if (!relative_paths && chdir(dir) != 0) {
fprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
exit_cleanup(1);
fprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
exit_cleanup(1);
}
argc--;
argv++;
if (strcmp(dir,".")) {
int l = strlen(dir);
if (strcmp(dir,"/") == 0)
l = 0;
for (i=0;i<argc;i++)
argv[i] += l+1;
int l = strlen(dir);
if (strcmp(dir,"/") == 0)
l = 0;
for (i=0;i<argc;i++)
argv[i] += l+1;
}
if (argc == 0 && recurse) {
argc=1;
argv--;
argv[0] = ".";
argc=1;
argv--;
argv[0] = ".";
}
@@ -341,10 +362,10 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
}
if ((pid=fork()) == 0) {
if ((pid=do_fork()) == 0) {
recv_files(f_in,flist,local_name,recv_pipe[1]);
if (verbose > 2)
fprintf(FERROR,"receiver read %d\n",read_total());
fprintf(FINFO,"receiver read %ld\n",(long)read_total());
exit_cleanup(0);
}
@@ -359,21 +380,22 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
void do_server_recv(int argc,char *argv[])
{
int status;
char *dir = NULL;
struct file_list *flist;
char *local_name=NULL;
char *dir = NULL;
if (verbose > 2)
fprintf(FERROR,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
fprintf(FINFO,"server_recv(%d) starting pid=%d\n",argc,(int)getpid());
if (argc > 0) {
dir = argv[0];
argc--;
argv++;
if (chdir(dir) != 0) {
fprintf(FERROR,"chdir %s : %s (4)\n",dir,strerror(errno));
exit_cleanup(1);
}
dir = argv[0];
argc--;
argv++;
if (chdir(dir) != 0) {
fprintf(FERROR,"chdir %s : %s (4)\n",
dir,strerror(errno));
exit_cleanup(1);
}
}
if (delete_mode)
@@ -386,11 +408,11 @@ void do_server_recv(int argc,char *argv[])
}
if (argc > 0) {
if (strcmp(dir,".")) {
argv[0] += strlen(dir);
if (argv[0][0] == '/') argv[0]++;
}
local_name = get_local_name(flist,argv[0]);
if (strcmp(dir,".")) {
argv[0] += strlen(dir);
if (argv[0][0] == '/') argv[0]++;
}
local_name = get_local_name(flist,argv[0]);
}
status = do_recv(STDIN_FILENO,STDOUT_FILENO,flist,local_name);
@@ -429,7 +451,11 @@ static void usage(FILE *f)
fprintf(f," --rsync-path PATH specify path to rsync on the remote machine\n");
fprintf(f,"-C, --cvs-exclude auto ignore files in the same way CVS does\n");
fprintf(f," --delete delete files that don't exist on the sending side\n");
fprintf(f," --force force deletion of directories even if not empty\n");
fprintf(f," --numeric-ids don't map uid/gid values by user/group name\n");
fprintf(f," --timeout TIME set IO timeout in seconds\n");
fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n");
fprintf(f,"-T --temp-dir DIR create temporary files in directory DIR\n");
fprintf(f,"-z, --compress compress file data\n");
fprintf(f," --exclude FILE exclude file FILE\n");
fprintf(f," --exclude-from FILE exclude files listed in FILE\n");
@@ -442,15 +468,18 @@ static void usage(FILE *f)
}
enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH};
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
OPT_FORCE,OPT_TIMEOUT};
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:z";
static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
static struct option long_options[] = {
{"version", 0, 0, OPT_VERSION},
{"server", 0, 0, OPT_SERVER},
{"sender", 0, 0, OPT_SENDER},
{"delete", 0, 0, OPT_DELETE},
{"force", 0, 0, OPT_FORCE},
{"numeric-ids", 0, 0, OPT_NUMERIC_IDS},
{"exclude", 1, 0, OPT_EXCLUDE},
{"exclude-from",1, 0, OPT_EXCLUDE_FROM},
{"rsync-path", 1, 0, OPT_RSYNC_PATH},
@@ -479,6 +508,8 @@ static struct option long_options[] = {
{"rsh", 1, 0, 'e'},
{"suffix", 1, 0, OPT_SUFFIX},
{"block-size", 1, 0, 'B'},
{"timeout", 1, 0, OPT_TIMEOUT},
{"temp-dir", 1, 0, 'T'},
{"compress", 0, 0, 'z'},
{0,0,0,0}};
@@ -500,11 +531,6 @@ int main(int argc,char *argv[])
struct file_list *flist;
char *local_name = NULL;
#ifdef SETPGRP_VOID
setpgrp();
#else
setpgrp(0,0);
#endif
signal(SIGUSR1, sigusr1_handler);
starttime = time(NULL);
@@ -512,7 +538,7 @@ int main(int argc,char *argv[])
/* we set a 0 umask so that correct file permissions can be
carried across */
orig_umask = umask(0);
orig_umask = (int)umask(0);
while ((opt = getopt_long(argc, argv,
short_options, long_options, &option_index))
@@ -544,6 +570,14 @@ int main(int argc,char *argv[])
delete_mode = 1;
break;
case OPT_FORCE:
force_delete = 1;
break;
case OPT_NUMERIC_IDS:
numeric_ids = 1;
break;
case OPT_EXCLUDE:
add_exclude(optarg);
break;
@@ -667,6 +701,14 @@ int main(int argc,char *argv[])
block_size = atoi(optarg);
break;
case OPT_TIMEOUT:
io_timeout = atoi(optarg);
break;
case 'T':
tmpdir = optarg;
break;
case 'z':
do_compression = 1;
break;
@@ -754,7 +796,7 @@ int main(int argc,char *argv[])
}
if (verbose > 3) {
fprintf(FERROR,"cmd=%s machine=%s user=%s path=%s\n",
fprintf(FINFO,"cmd=%s machine=%s user=%s path=%s\n",
shell_cmd?shell_cmd:"",
shell_machine?shell_machine:"",
shell_user?shell_user:"",
@@ -776,7 +818,7 @@ int main(int argc,char *argv[])
#endif
if (verbose > 3)
fprintf(FERROR,"parent=%d child=%d sender=%d recurse=%d\n",
fprintf(FINFO,"parent=%d child=%d sender=%d recurse=%d\n",
(int)getpid(),pid,sender,recurse);
if (sender) {
@@ -786,10 +828,10 @@ int main(int argc,char *argv[])
send_exclude_list(f_out);
flist = send_file_list(f_out,argc,argv);
if (verbose > 3)
fprintf(FERROR,"file list sent\n");
fprintf(FINFO,"file list sent\n");
send_files(flist,f_out,f_in);
if (verbose > 3)
fprintf(FERROR,"waiting on %d\n",pid);
fprintf(FINFO,"waiting on %d\n",pid);
waitpid(pid, &status, 0);
report(-1);
exit_cleanup(status);
@@ -799,7 +841,7 @@ int main(int argc,char *argv[])
flist = recv_file_list(f_in);
if (!flist || flist->count == 0) {
fprintf(FERROR,"nothing to do\n");
fprintf(FINFO,"nothing to do\n");
exit_cleanup(0);
}

316
match.c
View File

@@ -36,10 +36,10 @@ static int tag_hits;
static int matches;
static int data_transfer;
static int total_false_alarms=0;
static int total_tag_hits=0;
static int total_matches=0;
static int total_data_transfer=0;
static int total_false_alarms;
static int total_tag_hits;
static int total_matches;
static int64 total_data_transfer;
struct target {
@@ -47,9 +47,9 @@ struct target {
int i;
};
static struct target *targets=NULL;
static struct target *targets;
static tag *tag_table = NULL;
static tag *tag_table;
#define gettag2(s1,s2) (((s1) + (s2)) & 0xFFFF)
#define gettag(sum) gettag2((sum)&0xFFFF,(sum)>>16)
@@ -91,187 +91,191 @@ static off_t last_match;
static void matched(int f,struct sum_struct *s,struct map_struct *buf,
int offset,int i)
off_t offset,int i)
{
int n = offset - last_match;
int j;
off_t n = offset - last_match;
int j;
if (verbose > 2)
if (i != -1)
fprintf(FERROR,"match at %d last_match=%d j=%d len=%d n=%d\n",
(int)offset,(int)last_match,i,(int)s->sums[i].len,n);
if (verbose > 2 && i >= 0)
fprintf(FINFO,"match at %d last_match=%d j=%d len=%d n=%d\n",
(int)offset,(int)last_match,i,(int)s->sums[i].len,(int)n);
send_token(f,i,buf,last_match,n,i==-1?0:s->sums[i].len);
data_transfer += n;
send_token(f,i,buf,last_match,n,i==-1?0:s->sums[i].len);
data_transfer += n;
if (n > 0)
write_flush(f);
if (n > 0)
write_flush(f);
if (i != -1)
n += s->sums[i].len;
if (i >= 0)
n += s->sums[i].len;
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
sum_update(map_ptr(buf,last_match+j,n1),n1);
}
for (j=0;j<n;j+=CHUNK_SIZE) {
int n1 = MIN(CHUNK_SIZE,n-j);
sum_update(map_ptr(buf,last_match+j,n1),n1);
}
if (i != -1)
last_match = offset + s->sums[i].len;
if (i >= 0)
last_match = offset + s->sums[i].len;
else
last_match = offset;
}
static void hash_search(int f,struct sum_struct *s,
struct map_struct *buf,off_t len)
{
int offset,j,k;
int end;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
signed char *map;
off_t offset;
int j,k;
int end;
char sum2[SUM_LENGTH];
uint32 s1, s2, sum;
signed char *map;
if (verbose > 2)
fprintf(FERROR,"hash search b=%d len=%d\n",s->n,(int)len);
if (verbose > 2)
fprintf(FINFO,"hash search b=%d len=%d\n",s->n,(int)len);
k = MIN(len, s->n);
k = MIN(len, s->n);
map = (signed char *)map_ptr(buf,0,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
fprintf(FINFO, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3)
fprintf(FINFO,"hash search s->n=%d len=%d count=%d\n",
s->n,(int)len,s->count);
do {
tag t = gettag2(s1,s2);
int done_csum2 = 0;
j = tag_table[t];
if (verbose > 4)
fprintf(FINFO,"offset=%d sum=%08x\n",(int)offset,sum);
if (j == NULL_TAG) {
goto null_tag;
}
map = (signed char *)map_ptr(buf,0,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
if (verbose > 3)
fprintf(FERROR, "sum=%.8x k=%d\n", sum, k);
offset = 0;
end = len + 1 - s->sums[s->count-1].len;
if (verbose > 3)
fprintf(FERROR,"hash search s->n=%d len=%d count=%d\n",
s->n,(int)len,s->count);
do {
tag t = gettag2(s1,s2);
j = tag_table[t];
if (verbose > 4)
fprintf(FERROR,"offset=%d sum=%08x\n",
offset,sum);
if (j != NULL_TAG) {
int done_csum2 = 0;
sum = (s1 & 0xffff) | (s2 << 16);
tag_hits++;
do {
int i = targets[j].i;
if (sum == s->sums[i].sum1) {
if (verbose > 3)
fprintf(FERROR,"potential match at %d target=%d %d sum=%08x\n",
offset,j,i,sum);
if (!done_csum2) {
int l = MIN(s->n,len-offset);
map = (signed char *)map_ptr(buf,offset,l);
get_checksum2((char *)map,l,sum2);
done_csum2 = 1;
}
if (memcmp(sum2,s->sums[i].sum2,csum_length) == 0) {
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
k = MIN((len-offset), s->n);
map = (signed char *)map_ptr(buf,offset,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
++matches;
break;
} else {
false_alarms++;
}
}
j++;
} while (j<s->count && targets[j].t == t);
}
/* Trim off the first byte from the checksum */
map = (signed char *)map_ptr(buf,offset,k+1);
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
/* Add on the next byte (if there is one) to the checksum */
if (k < (len-offset)) {
s1 += (map[k]+CHAR_OFFSET);
s2 += s1;
} else {
--k;
}
} while (++offset < end);
matched(f,s,buf,len,-1);
map_ptr(buf,len-1,1);
sum = (s1 & 0xffff) | (s2 << 16);
tag_hits++;
for (; j<s->count && targets[j].t == t; j++) {
int i = targets[j].i;
if (sum != s->sums[i].sum1) continue;
if (verbose > 3)
fprintf(FINFO,"potential match at %d target=%d %d sum=%08x\n",
(int)offset,j,i,sum);
if (!done_csum2) {
int l = MIN(s->n,len-offset);
map = (signed char *)map_ptr(buf,offset,l);
get_checksum2((char *)map,l,sum2);
done_csum2 = 1;
}
if (memcmp(sum2,s->sums[i].sum2,csum_length) != 0) {
false_alarms++;
continue;
}
matched(f,s,buf,offset,i);
offset += s->sums[i].len - 1;
k = MIN((len-offset), s->n);
map = (signed char *)map_ptr(buf,offset,k);
sum = get_checksum1((char *)map, k);
s1 = sum & 0xFFFF;
s2 = sum >> 16;
matches++;
break;
}
null_tag:
/* Trim off the first byte from the checksum */
map = (signed char *)map_ptr(buf,offset,k+1);
s1 -= map[0] + CHAR_OFFSET;
s2 -= k * (map[0]+CHAR_OFFSET);
/* Add on the next byte (if there is one) to the checksum */
if (k < (len-offset)) {
s1 += (map[k]+CHAR_OFFSET);
s2 += s1;
} else {
--k;
}
} while (++offset < end);
matched(f,s,buf,len,-1);
map_ptr(buf,len-1,1);
}
void match_sums(int f,struct sum_struct *s,struct map_struct *buf,off_t len)
{
char file_sum[MD4_SUM_LENGTH];
char file_sum[MD4_SUM_LENGTH];
last_match = 0;
false_alarms = 0;
tag_hits = 0;
matches=0;
data_transfer=0;
last_match = 0;
false_alarms = 0;
tag_hits = 0;
matches=0;
data_transfer=0;
sum_init();
sum_init();
if (len > 0 && s->count>0) {
build_hash_table(s);
if (len > 0 && s->count>0) {
build_hash_table(s);
if (verbose > 2)
fprintf(FINFO,"built hash table\n");
hash_search(f,s,buf,len);
if (verbose > 2)
fprintf(FINFO,"done hash search\n");
} else {
matched(f,s,buf,len,-1);
}
if (verbose > 2)
fprintf(FERROR,"built hash table\n");
sum_end(file_sum);
hash_search(f,s,buf,len);
if (remote_version >= 14) {
if (verbose > 2)
fprintf(FINFO,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
}
if (verbose > 2)
fprintf(FERROR,"done hash search\n");
} else {
matched(f,s,buf,len,-1);
}
sum_end(file_sum);
if (remote_version >= 14) {
if (verbose > 2)
fprintf(FERROR,"sending file_sum\n");
write_buf(f,file_sum,MD4_SUM_LENGTH);
}
if (targets) {
free(targets);
targets=NULL;
}
if (verbose > 2)
fprintf(FERROR, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
total_data_transfer += data_transfer;
if (targets) {
free(targets);
targets=NULL;
}
if (verbose > 2)
fprintf(FINFO, "false_alarms=%d tag_hits=%d matches=%d\n",
false_alarms, tag_hits, matches);
total_tag_hits += tag_hits;
total_false_alarms += false_alarms;
total_matches += matches;
total_data_transfer += data_transfer;
}
void match_report(void)
{
if (verbose <= 1)
return;
if (verbose <= 1)
return;
fprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%d\n",
total_matches,total_tag_hits,
total_false_alarms,total_data_transfer);
fprintf(FINFO,
"total: matches=%d tag_hits=%d false_alarms=%d data=%ld\n",
total_matches,total_tag_hits,
total_false_alarms,(long)total_data_transfer);
}

View File

@@ -23,7 +23,7 @@ BEGIN {
next;
}
!/^off_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
!/^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^struct|^BOOL|^void|^time/ {
next;
}

604
rsync.c
View File

@@ -29,6 +29,7 @@ extern time_t starttime;
extern int remote_version;
extern char *backup_suffix;
extern char *tmpdir;
extern int whole_file;
extern int block_size;
@@ -48,6 +49,8 @@ extern int delete_mode;
extern int cvs_exclude;
extern int am_root;
extern int relative_paths;
extern int io_timeout;
extern int io_error;
/*
free a sums struct
@@ -59,6 +62,75 @@ static void free_sums(struct sum_struct *s)
}
/*
* delete a file or directory. If force_delet is set then delete
* recursively
*/
static int delete_file(char *fname)
{
DIR *d;
struct dirent *di;
char buf[MAXPATHLEN];
extern int force_delete;
struct stat st;
int ret;
if (do_unlink(fname) == 0 || errno == ENOENT) return 0;
#if SUPPORT_LINKS
ret = lstat(fname, &st);
#else
ret = stat(fname, &st);
#endif
if (ret) {
fprintf(FERROR,"stat(%s) : %s\n", fname, strerror(errno));
return -1;
}
if (!S_ISDIR(st.st_mode)) {
fprintf(FERROR,"unlink(%s) : %s\n", fname, strerror(errno));
return -1;
}
if (do_rmdir(fname) == 0 || errno == ENOENT) return 0;
if (!force_delete || errno != ENOTEMPTY) {
fprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
/* now we do a recsursive delete on the directory ... */
d = opendir(fname);
if (!d) {
fprintf(FERROR,"opendir(%s): %s\n",
fname,strerror(errno));
return -1;
}
for (di=readdir(d); di; di=readdir(d)) {
if (strcmp(di->d_name,".")==0 ||
strcmp(di->d_name,"..")==0)
continue;
strncpy(buf, fname, (MAXPATHLEN-strlen(di->d_name))-2);
strcat(buf, "/");
strcat(buf, di->d_name);
buf[MAXPATHLEN-1] = 0;
if (verbose > 0)
fprintf(FINFO,"deleting %s\n", buf);
if (delete_file(buf) != 0) {
closedir(d);
return -1;
}
}
closedir(d);
if (do_rmdir(fname) != 0) {
fprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno));
return -1;
}
return 0;
}
/*
send a sums struct down a fd
@@ -111,7 +183,7 @@ static struct sum_struct *generate_sums(struct map_struct *buf,off_t len,int n)
}
if (verbose > 3)
fprintf(FERROR,"count=%d rem=%d n=%d flength=%d\n",
fprintf(FINFO,"count=%d rem=%d n=%d flength=%d\n",
s->count,s->remainder,s->n,(int)s->flength);
s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
@@ -129,7 +201,7 @@ static struct sum_struct *generate_sums(struct map_struct *buf,off_t len,int n)
s->sums[i].i = i;
if (verbose > 3)
fprintf(FERROR,"chunk[%d] offset=%d len=%d sum1=%08x\n",
fprintf(FINFO,"chunk[%d] offset=%d len=%d sum1=%08x\n",
i,(int)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
len -= n1;
@@ -158,7 +230,7 @@ static struct sum_struct *receive_sums(int f)
s->sums = NULL;
if (verbose > 3)
fprintf(FERROR,"count=%d n=%d rem=%d\n",
fprintf(FINFO,"count=%d n=%d rem=%d\n",
s->count,s->n,s->remainder);
if (s->count == 0)
@@ -182,7 +254,7 @@ static struct sum_struct *receive_sums(int f)
offset += s->sums[i].len;
if (verbose > 3)
fprintf(FERROR,"chunk[%d] len=%d offset=%d sum1=%08x\n",
fprintf(FINFO,"chunk[%d] len=%d offset=%d sum1=%08x\n",
i,s->sums[i].len,(int)s->sums[i].offset,s->sums[i].sum1);
}
@@ -222,7 +294,7 @@ static int set_perms(char *fname,struct file_struct *file,struct stat *st,
if (preserve_perms && !S_ISLNK(st->st_mode) &&
st->st_mode != file->mode) {
updated = 1;
if (chmod(fname,file->mode) != 0) {
if (do_chmod(fname,file->mode) != 0) {
fprintf(FERROR,"failed to set permissions on %s : %s\n",
fname,strerror(errno));
return 0;
@@ -232,45 +304,81 @@ static int set_perms(char *fname,struct file_struct *file,struct stat *st,
if ((am_root && preserve_uid && st->st_uid != file->uid) ||
(preserve_gid && st->st_gid != file->gid)) {
updated = 1;
if (lchown(fname,
(am_root&&preserve_uid)?file->uid:-1,
preserve_gid?file->gid:-1) != 0) {
if (verbose>1 || preserve_uid)
fprintf(FERROR,"chown %s : %s\n",fname,strerror(errno));
return updated;
}
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)
fprintf(FERROR,"chown %s : %s\n",
fname,strerror(errno));
return updated;
}
updated = 1;
}
if (verbose > 1 && report) {
if (updated)
fprintf(FINFO,"%s\n",fname);
else
fprintf(FINFO,"%s is uptodate\n",fname);
if (updated)
fprintf(FINFO,"%s\n",fname);
else
fprintf(FINFO,"%s is uptodate\n",fname);
}
return updated;
}
/* choose whether to skip a particular file */
static int skip_file(char *fname,
struct file_struct *file, struct stat *st)
{
if (st->st_size != file->length) {
return 0;
}
/* if always checksum is set then we use the checksum instead
of the file time to determine whether to sync */
if (always_checksum && S_ISREG(st->st_mode)) {
char sum[MD4_SUM_LENGTH];
file_checksum(fname,sum,st->st_size);
return (memcmp(sum,file->sum,csum_length) == 0);
}
if (ignore_times) {
return 0;
}
return (st->st_mtime == file->modtime);
}
/* 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 */
ret = ret & ~15; /* multiple of 16 */
if (ret < bsize) ret = bsize;
if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
return ret;
}
void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
{
int fd;
struct stat st;
struct map_struct *buf;
struct sum_struct *s;
char sum[MD4_SUM_LENGTH];
int statret;
struct file_struct *file = &flist->files[i];
struct file_struct *file = flist->files[i];
if (verbose > 2)
fprintf(FERROR,"recv_generator(%s,%d)\n",fname,i);
fprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
statret = link_stat(fname,&st);
if (S_ISDIR(file->mode)) {
if (dry_run) return;
if (statret == 0 && !S_ISDIR(st.st_mode)) {
if (unlink(fname) != 0) {
if (do_unlink(fname) != 0) {
fprintf(FERROR,"unlink %s : %s\n",fname,strerror(errno));
return;
}
@@ -303,8 +411,8 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
}
}
}
if (!dry_run) unlink(fname);
if (!dry_run && symlink(file->link,fname) != 0) {
delete_file(fname);
if (do_symlink(file->link,fname) != 0) {
fprintf(FERROR,"link %s -> %s : %s\n",
fname,file->link,strerror(errno));
} else {
@@ -322,12 +430,11 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
if (statret != 0 ||
st.st_mode != file->mode ||
st.st_rdev != file->rdev) {
if (!dry_run) unlink(fname);
delete_file(fname);
if (verbose > 2)
fprintf(FERROR,"mknod(%s,0%o,0x%x)\n",
fprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
fname,(int)file->mode,(int)file->rdev);
if (!dry_run &&
mknod(fname,file->mode,file->rdev) != 0) {
if (do_mknod(fname,file->mode,file->rdev) != 0) {
fprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
@@ -343,12 +450,12 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
if (preserve_hard_links && check_hard_link(file)) {
if (verbose > 1)
fprintf(FINFO,"%s is a hard link\n",file->name);
fprintf(FINFO,"%s is a hard link\n",f_name(file));
return;
}
if (!S_ISREG(file->mode)) {
fprintf(FERROR,"skipping non-regular file %s\n",fname);
fprintf(FINFO,"skipping non-regular file %s\n",fname);
return;
}
@@ -364,15 +471,7 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
}
if (!S_ISREG(st.st_mode)) {
/* its not a regular file on the receiving end, but it is on the
sending end. If its a directory then skip it (too dangerous to
do a recursive deletion??) otherwise try to unlink it */
if (S_ISDIR(st.st_mode)) {
fprintf(FERROR,"ERROR: %s is a directory\n",fname);
return;
}
if (unlink(fname) != 0) {
fprintf(FERROR,"%s : not a regular file (generator)\n",fname);
if (delete_file(fname) != 0) {
return;
}
@@ -382,20 +481,13 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
return;
}
if (update_only && st.st_mtime >= file->modtime) {
if (update_only && st.st_mtime > file->modtime) {
if (verbose > 1)
fprintf(FERROR,"%s is newer\n",fname);
fprintf(FINFO,"%s is newer\n",fname);
return;
}
if (always_checksum && S_ISREG(st.st_mode)) {
file_checksum(fname,sum,st.st_size);
}
if (st.st_size == file->length &&
((!ignore_times && st.st_mtime == file->modtime) ||
(always_checksum && S_ISREG(st.st_mode) &&
memcmp(sum,file->sum,csum_length) == 0))) {
if (skip_file(fname, file, &st)) {
set_perms(fname,file,&st,1);
return;
}
@@ -427,12 +519,12 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
}
if (verbose > 3)
fprintf(FERROR,"gen mapped %s of size %d\n",fname,(int)st.st_size);
fprintf(FINFO,"gen mapped %s of size %d\n",fname,(int)st.st_size);
s = generate_sums(buf,st.st_size,block_size);
s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
if (verbose > 2)
fprintf(FERROR,"sending sums for %d\n",i);
fprintf(FINFO,"sending sums for %d\n",i);
write_int(f_out,i);
send_sums(s,f_out);
@@ -465,7 +557,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
if (i > 0) {
if (verbose > 3)
fprintf(FERROR,"data recv %d at %d\n",i,(int)offset);
fprintf(FINFO,"data recv %d at %d\n",i,(int)offset);
sum_update(data,i);
@@ -482,7 +574,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
len = remainder;
if (verbose > 3)
fprintf(FERROR,"chunk[%d] of size %d at %d offset=%d\n",
fprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n",
i,len,(int)offset2,(int)offset);
map = map_ptr(buf,offset2,len);
@@ -508,7 +600,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
if (remote_version >= 14) {
read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
if (verbose > 2)
fprintf(FERROR,"got file_sum\n");
fprintf(FINFO,"got file_sum\n");
if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0)
return 0;
}
@@ -519,22 +611,77 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname)
static void delete_one(struct file_struct *f)
{
if (!S_ISDIR(f->mode)) {
if (!dry_run && unlink(f->name) != 0) {
fprintf(FERROR,"unlink %s : %s\n",f->name,strerror(errno));
if (do_unlink(f_name(f)) != 0) {
fprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
fprintf(FERROR,"deleting %s\n",f->name);
fprintf(FINFO,"deleting %s\n",f_name(f));
}
} else {
if (!dry_run && rmdir(f->name) != 0) {
if (do_rmdir(f_name(f)) != 0) {
if (errno != ENOTEMPTY)
fprintf(FERROR,"rmdir %s : %s\n",f->name,strerror(errno));
fprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
} else if (verbose) {
fprintf(FERROR,"deleting directory %s\n",f->name);
fprintf(FINFO,"deleting directory %s\n",f_name(f));
}
}
}
/* yuck! This function wouldn't have been necessary if I had the sorting
algorithm right. Unfortunately fixing the sorting algorithm would introduce
a backward incompatibility as file list indexes are sent over the link.
The aim is to see if a directory has already had the deletion algorithm applied
to it (due to recursion), and if so to skip it. The bisection is to
prevent this being an n^2 algorithm */
static int delete_already_done(struct file_list *flist,int j)
{
int low=0,high=j-1;
char *name;
char *p;
if (j == 0) return 0;
name = strdup(f_name(flist->files[j]));
if (!name) {
fprintf(FERROR,"out of memory in delete_already_done");
exit_cleanup(1);
}
p = strrchr(name,'/');
if (!p) {
free(name);
return 0;
}
*p = 0;
while (low != high) {
int mid = (low+high)/2;
int ret = strcmp(f_name(flist->files[flist_up(flist, mid)]),name);
if (ret == 0) {
free(name);
return 1;
}
if (ret > 0) {
high=mid;
} else {
low=mid+1;
}
}
low = flist_up(flist, low);
if (strcmp(f_name(flist->files[low]),name) == 0) {
free(name);
return 1;
}
free(name);
return 0;
}
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
@@ -542,46 +689,47 @@ static void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *last_name=NULL;
if (cvs_exclude)
add_cvs_excludes();
if (io_error) {
fprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
for (j=0;j<flist->count;j++) {
if (!S_ISDIR(flist->files[j].mode)) continue;
if (strcmp(flist->files[j].name,".")==0) continue;
if (last_name &&
flist->files[j].name[strlen(last_name)] == '/' &&
strncmp(flist->files[j].name,last_name, strlen(last_name))==0)
continue;
last_name = flist->files[j].name;
if (!(local_file_list = send_file_list(-1,1,&last_name)))
char *name = f_name(flist->files[j]);
if (!S_ISDIR(flist->files[j]->mode)) continue;
if (delete_already_done(flist, j)) continue;
if (!(local_file_list = send_file_list(-1,1,&name)))
continue;
if (verbose > 1)
fprintf(FINFO,"deleting in %s\n", last_name);
fprintf(FINFO,"deleting in %s\n", name);
for (i=local_file_list->count-1;i>=0;i--) {
if (!local_file_list->files[i].name) continue;
if (-1 == flist_find(flist,&local_file_list->files[i])) {
delete_one(&local_file_list->files[i]);
if (!local_file_list->files[i]->basename) continue;
if (-1 == flist_find(flist,local_file_list->files[i])) {
delete_one(local_file_list->files[i]);
}
}
flist_free(local_file_list);
}
}
static char *cleanup_fname = NULL;
static char *cleanup_fname;
void exit_cleanup(int code)
{
if (cleanup_fname)
unlink(cleanup_fname);
do_unlink(cleanup_fname);
signal(SIGUSR1, SIG_IGN);
if (code) {
#ifdef GETPGRP_VOID
kill(-getpgrp(), SIGUSR1);
#else
kill(-getpgrp(getpid()), SIGUSR1);
#endif
kill_all(SIGUSR1);
}
exit(code);
}
@@ -605,7 +753,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
int recv_ok;
if (verbose > 2) {
fprintf(FERROR,"recv_files(%d) starting\n",flist->count);
fprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (recurse && delete_mode && !local_name && flist->count>0) {
@@ -620,7 +768,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
fprintf(FERROR,"recv_files phase=%d\n",phase);
fprintf(FINFO,"recv_files phase=%d\n",phase);
write_int(f_gen,-1);
write_flush(f_gen);
continue;
@@ -628,8 +776,8 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
break;
}
file = &flist->files[i];
fname = file->name;
file = flist->files[i];
fname = f_name(file);
if (local_name)
fname = local_name;
@@ -641,7 +789,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
}
if (verbose > 2)
fprintf(FERROR,"recv_files(%s)\n",fname);
fprintf(FINFO,"recv_files(%s)\n",fname);
/* open the file */
fd1 = open(fname,O_RDONLY);
@@ -663,7 +811,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
if (fd1 != -1 && st.st_size > 0) {
buf = map_file(fd1,st.st_size);
if (verbose > 2)
fprintf(FERROR,"recv mapped %s of size %d\n",fname,(int)st.st_size);
fprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size);
} else {
buf = NULL;
}
@@ -671,10 +819,21 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
/* open tmp file */
if (strlen(fname) > (MAXPATHLEN-8)) {
fprintf(FERROR,"filename too long\n");
if (buf) unmap_file(buf);
close(fd1);
continue;
}
sprintf(fnametmp,"%s.XXXXXX",fname);
if (tmpdir) {
char *f;
f = strrchr(fname,'/');
if (f == NULL)
f = fname;
else
f++;
sprintf(fnametmp,"%s/%s.XXXXXX",tmpdir,f);
} else {
sprintf(fnametmp,"%s.XXXXXX",fname);
}
if (NULL == mktemp(fnametmp)) {
fprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL);
@@ -682,10 +841,10 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
close(fd1);
continue;
}
fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
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 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
}
if (fd2 == -1) {
fprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
@@ -703,14 +862,14 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
/* recv file data */
recv_ok = receive_data(f_in,buf,fd2,fname);
if (buf) unmap_file(buf);
if (fd1 != -1) {
if (buf) unmap_file(buf);
close(fd1);
}
close(fd2);
if (verbose > 2)
fprintf(FERROR,"renaming %s to %s\n",fnametmp,fname);
fprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
if (make_backups) {
char fnamebak[MAXPATHLEN];
@@ -727,21 +886,37 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
/* move tmp file over real file */
if (rename(fnametmp,fname) != 0) {
fprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
unlink(fnametmp);
if (errno == EXDEV) {
/* rename failed on cross-filesystem link.
Copy the file instead. */
if (copy_file(fnametmp,fname, file->mode)) {
fprintf(FERROR,"copy %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
} else {
set_perms(fname,file,NULL,0);
}
do_unlink(fnametmp);
} else {
fprintf(FERROR,"rename %s -> %s : %s\n",
fnametmp,fname,strerror(errno));
do_unlink(fnametmp);
}
} else {
set_perms(fname,file,NULL,0);
}
cleanup_fname = NULL;
set_perms(fname,file,NULL,0);
if (!recv_ok) {
if (verbose > 1)
fprintf(FERROR,"redoing %s(%d)\n",fname,i);
if (csum_length == SUM_LENGTH)
fprintf(FERROR,"ERROR: file corruption in %s\n",fname);
write_int(f_gen,i);
if (csum_length == SUM_LENGTH) {
fprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n",
fname);
} else {
if (verbose > 1)
fprintf(FINFO,"redoing %s(%d)\n",fname,i);
write_int(f_gen,i);
}
}
}
@@ -751,137 +926,144 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
/* now we need to fix any directory permissions that were
modified during the transfer */
for (i = 0; i < flist->count; i++) {
struct file_struct *file = &flist->files[i];
if (!file->name || !S_ISDIR(file->mode)) continue;
recv_generator(file->name,flist,i,-1);
struct file_struct *file = flist->files[i];
if (!file->basename || !S_ISDIR(file->mode)) continue;
recv_generator(f_name(file),flist,i,-1);
}
if (verbose > 2)
fprintf(FERROR,"recv_files finished\n");
fprintf(FINFO,"recv_files finished\n");
return 0;
}
off_t send_files(struct file_list *flist,int f_out,int f_in)
void send_files(struct file_list *flist,int f_out,int f_in)
{
int fd;
struct sum_struct *s;
struct map_struct *buf;
struct stat st;
char fname[MAXPATHLEN];
off_t total=0;
int i;
struct file_struct *file;
int phase = 0;
int offset=0;
if (verbose > 2)
fprintf(FERROR,"send_files starting\n");
fprintf(FINFO,"send_files starting\n");
setup_nonblocking(f_in,f_out);
while (1)
{
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);
while (1) {
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)
fprintf(FINFO,"send_files phase=%d\n",phase);
continue;
}
break;
}
file = flist->files[i];
fname[0] = 0;
if (file->basedir) {
strncpy(fname,file->basedir,MAXPATHLEN-1);
fname[MAXPATHLEN-1] = 0;
if (strlen(fname) == MAXPATHLEN-1) {
io_error = 1;
fprintf(FERROR, "send_files failed on long-named directory %s\n",
fname);
return;
}
strcat(fname,"/");
offset = strlen(file->basedir)+1;
}
strncat(fname,f_name(file),MAXPATHLEN-strlen(fname));
if (verbose > 2)
fprintf(FINFO,"send_files(%d,%s)\n",i,fname);
if (dry_run) {
if (!am_server && verbose)
printf("%s\n",fname);
write_int(f_out,i);
continue;
}
s = receive_sums(f_in);
if (!s) {
io_error = 1;
fprintf(FERROR,"receive_sums failed\n");
return;
}
fd = open(fname,O_RDONLY);
if (fd == -1) {
io_error = 1;
fprintf(FERROR,"send_files failed to open %s: %s\n",
fname,strerror(errno));
free_sums(s);
continue;
}
/* map the local file */
if (fstat(fd,&st) != 0) {
io_error = 1;
fprintf(FERROR,"fstat failed : %s\n",strerror(errno));
free_sums(s);
close(fd);
return;
}
if (st.st_size > 0) {
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 2)
fprintf(FERROR,"send_files phase=%d\n",phase);
continue;
}
break;
}
file = &flist->files[i];
fname[0] = 0;
if (file->dir) {
strncpy(fname,file->dir,MAXPATHLEN-1);
fname[MAXPATHLEN-1] = 0;
strcat(fname,"/");
}
strncat(fname,file->name,MAXPATHLEN-strlen(fname));
if (verbose > 2)
fprintf(FERROR,"send_files(%d,%s)\n",i,fname);
if (dry_run) {
if (!am_server && verbose)
printf("%s\n",fname);
write_int(f_out,i);
continue;
}
s = receive_sums(f_in);
if (!s) {
fprintf(FERROR,"receive_sums failed\n");
return -1;
}
fd = open(fname,O_RDONLY);
if (fd == -1) {
fprintf(FERROR,"send_files failed to open %s: %s\n",
fname,strerror(errno));
continue;
}
/* map the local file */
if (fstat(fd,&st) != 0) {
fprintf(FERROR,"fstat failed : %s\n",strerror(errno));
close(fd);
return -1;
}
if (st.st_size > 0) {
buf = map_file(fd,st.st_size);
} else {
buf = NULL;
}
if (verbose > 2)
fprintf(FERROR,"send_files mapped %s of size %d\n",
fname,(int)st.st_size);
write_int(f_out,i);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
if (verbose > 2)
fprintf(FERROR,"calling match_sums %s\n",fname);
if (!am_server && verbose)
printf("%s\n",fname);
match_sums(f_out,s,buf,st.st_size);
write_flush(f_out);
if (buf) unmap_file(buf);
close(fd);
free_sums(s);
if (verbose > 2)
fprintf(FERROR,"sender finished %s\n",fname);
total += st.st_size;
}
fprintf(FINFO,"send_files mapped %s of size %d\n",
fname,(int)st.st_size);
write_int(f_out,i);
write_int(f_out,s->count);
write_int(f_out,s->n);
write_int(f_out,s->remainder);
if (verbose > 2)
fprintf(FINFO,"calling match_sums %s\n",fname);
if (!am_server && verbose)
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);
free_sums(s);
if (verbose > 2)
fprintf(FINFO,"sender finished %s\n",fname);
}
if (verbose > 2)
fprintf(FERROR,"send files finished\n");
fprintf(FINFO,"send files finished\n");
match_report();
write_int(f_out,-1);
write_flush(f_out);
return total;
}
@@ -892,13 +1074,13 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
int phase=0;
if (verbose > 2)
fprintf(FERROR,"generator starting pid=%d count=%d\n",
fprintf(FINFO,"generator starting pid=%d count=%d\n",
(int)getpid(),flist->count);
for (i = 0; i < flist->count; i++) {
struct file_struct *file = &flist->files[i];
struct file_struct *file = flist->files[i];
mode_t saved_mode = file->mode;
if (!file->name) continue;
if (!file->basename) continue;
/* we need to ensure that any directories we create have writeable
permissions initially so that we can create the files within
@@ -907,7 +1089,7 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
file->mode |= S_IWUSR; /* user write */
}
recv_generator(local_name?local_name:file->name,
recv_generator(local_name?local_name:f_name(file),
flist,i,f);
file->mode = saved_mode;
@@ -918,23 +1100,27 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
ignore_times=1;
if (verbose > 2)
fprintf(FERROR,"generate_files phase=%d\n",phase);
fprintf(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 */
io_timeout = 0;
if (remote_version >= 13) {
/* in newer versions of the protocol the files can cycle through
the system more than once to catch initial checksum errors */
for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
struct file_struct *file = &flist->files[i];
recv_generator(local_name?local_name:file->name,
struct file_struct *file = flist->files[i];
recv_generator(local_name?local_name:f_name(file),
flist,i,f);
}
phase++;
if (verbose > 2)
fprintf(FERROR,"generate_files phase=%d\n",phase);
fprintf(FINFO,"generate_files phase=%d\n",phase);
write_int(f,-1);
write_flush(f);
@@ -942,7 +1128,7 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
if (verbose > 2)
fprintf(FERROR,"generator wrote %d\n",write_total());
fprintf(FINFO,"generator wrote %ld\n",(long)write_total());
}

73
rsync.h
View File

@@ -39,9 +39,9 @@
#define SAME_TIME (1<<7)
/* update this if you make incompatible changes */
#define PROTOCOL_VERSION 14
#define MIN_PROTOCOL_VERSION 10
#define MAX_PROTOCOL_VERSION 20
#define PROTOCOL_VERSION 17
#define MIN_PROTOCOL_VERSION 11
#define MAX_PROTOCOL_VERSION 30
#define SPARSE_WRITE_SIZE (4*1024)
#define WRITE_SIZE (32*1024)
@@ -163,6 +163,10 @@
#include "lib/getopt.h"
#endif
/* these are needed for the uid/gid mapping code */
#include <pwd.h>
#include <grp.h>
#ifndef S_IFLNK
#define S_IFLNK 0120000
#endif
@@ -189,6 +193,11 @@
#define uint32 unsigned int32
#endif
#ifdef HAVE_LONGLONG
#define int64 long long
#else
#define int64 off_t
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
@@ -207,24 +216,25 @@
#endif
struct file_struct {
time_t modtime;
off_t length;
mode_t mode;
ino_t inode;
dev_t dev;
dev_t rdev;
uid_t uid;
gid_t gid;
char *name;
char *dir;
char *link;
char sum[MD4_SUM_LENGTH];
time_t modtime;
off_t length;
mode_t mode;
ino_t inode;
dev_t dev;
dev_t rdev;
uid_t uid;
gid_t gid;
char *basename;
char *dirname;
char *basedir;
char *link;
char *sum;
};
struct file_list {
int count;
int malloced;
struct file_struct *files;
struct file_struct **files;
};
struct sum_buf {
@@ -244,10 +254,21 @@ struct sum_struct {
};
struct map_struct {
char *map,*p;
int fd,size,p_size,p_offset,p_len;
char *map,*p;
int fd,p_size,p_len;
off_t size, p_offset;
};
/* 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 */
static inline int flist_up(struct file_list *flist, int i)
{
while (!flist->files[i]->basename) i++;
return i;
}
#include "byteorder.h"
#include "version.h"
#include "proto.h"
@@ -319,5 +340,21 @@ extern int errno;
#define S_IWUSR 0200
#endif
#ifndef S_ISBLK
#define S_ISBLK(mode) (((mode) & (_S_IFMT)) == (_S_IFBLK))
#endif
#ifndef S_ISCHR
#define S_ISCHR(mode) (((mode) & (_S_IFMT)) == (_S_IFCHR))
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR))
#endif
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif
#define IS_DEVICE(mode) (S_ISCHR(mode) || S_ISBLK(mode))

79
syscall.c Normal file
View File

@@ -0,0 +1,79 @@
/*
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.
*/
/*
syscall wrappers to ensure that nothing gets done in dry_run mode
*/
#include "rsync.h"
extern int dry_run;
int do_unlink(char *fname)
{
if (dry_run) return 0;
return unlink(fname);
}
int do_symlink(char *fname1, char *fname2)
{
if (dry_run) return 0;
return symlink(fname1, fname2);
}
#if HAVE_LINK
int do_link(char *fname1, char *fname2)
{
if (dry_run) return 0;
return link(fname1, fname2);
}
#endif
int do_lchown(const char *path, uid_t owner, gid_t group)
{
if (dry_run) return 0;
return lchown(path, owner, group);
}
#if HAVE_MKNOD
int do_mknod(char *pathname, mode_t mode, dev_t dev)
{
if (dry_run) return 0;
return mknod(pathname, mode, dev);
}
#endif
int do_rmdir(char *pathname)
{
if (dry_run) return 0;
return rmdir(pathname);
}
int do_open(char *pathname, int flags, mode_t mode)
{
if (dry_run) return -1;
return open(pathname, flags, mode);
}
#if HAVE_CHMOD
int do_chmod(const char *path, mode_t mode)
{
if (dry_run) return 0;
return chmod(path, mode);
}
#endif

10
token.c
View File

@@ -26,8 +26,8 @@ extern int do_compression;
/* non-compressing recv token */
static int simple_recv_token(int f,char **data)
{
static int residue = 0;
static char *buf = NULL;
static int residue;
static char *buf;
int n;
if (!buf) {
@@ -99,7 +99,7 @@ static int last_run_end;
static z_stream tx_strm;
/* Output buffer */
static char *obuf = NULL;
static char *obuf;
/* Send a deflated token */
static void
@@ -220,8 +220,8 @@ static int
recv_deflated_token(int f, char **data)
{
int n, r, flag;
static int init_done = 0;
static int saved_flag = 0;
static int init_done;
static int saved_flag;
for (;;) {
switch (recv_state) {

310
uidlist.c Normal file
View File

@@ -0,0 +1,310 @@
/*
Copyright (C) Andrew Tridgell 1996
Copyright (C) Paul Mackerras 1996
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.
*/
/* handle the mapping of uid/gid and user/group names between systems.
If the source username/group does not exist on the target then use
the numeric ids. Never do any mapping for uid=0 or gid=0 as these
are special.
*/
#include "rsync.h"
extern int preserve_uid;
extern int preserve_gid;
extern int numeric_ids;
struct idlist {
struct idlist *next;
int id, id2;
char *name;
};
static struct idlist *uidlist;
static struct idlist *gidlist;
static struct idlist *add_list(int id, char *name)
{
struct idlist *list = (struct idlist *)malloc(sizeof(list[0]));
if (!list) out_of_memory("add_list");
list->next = NULL;
list->name = strdup(name);
if (!list->name) out_of_memory("add_list");
list->id = (int)id;
return list;
}
/* turn a uid into a user name */
static char *uid_to_name(uid_t uid)
{
struct passwd *pass = getpwuid(uid);
if (pass) return(pass->pw_name);
return NULL;
}
/* turn a gid into a group name */
static char *gid_to_name(gid_t gid)
{
struct group *grp = getgrgid(gid);
if (grp) return(grp->gr_name);
return NULL;
}
/* turn a user name into a uid */
static uid_t name_to_uid(char *name)
{
struct passwd *pass;
if (!name || !*name) return 0;
pass = getpwnam(name);
if (pass) return(pass->pw_uid);
return 0;
}
/* turn a group name into a gid */
static gid_t name_to_gid(char *name)
{
struct group *grp;
if (!name || !*name) return 0;
grp = getgrnam(name);
if (grp) return(grp->gr_gid);
return 0;
}
static int map_uid(int id, char *name)
{
uid_t uid = name_to_uid(name);
if (uid != 0) return uid;
return id;
}
static int map_gid(int id, char *name)
{
gid_t gid = name_to_gid(name);
if (gid != 0) return gid;
return id;
}
/* this function is a definate candidate for a faster algorithm */
static uid_t match_uid(uid_t uid)
{
static uid_t last_in, last_out;
struct idlist *list = uidlist;
if (uid == last_in) return last_out;
last_in = uid;
while (list) {
if (list->id == (int)uid) {
last_out = (uid_t)list->id2;
return last_out;
}
list = list->next;
}
last_out = uid;
return last_out;
}
static gid_t match_gid(gid_t gid)
{
static gid_t last_in, last_out;
struct idlist *list = gidlist;
if (gid == last_in) return last_out;
last_in = gid;
while (list) {
if (list->id == (int)gid) {
last_out = (gid_t)list->id2;
return last_out;
}
list = list->next;
}
last_out = gid;
return last_out;
}
/* add a uid to the list of uids */
void add_uid(uid_t uid)
{
struct idlist *list = uidlist;
char *name;
if (numeric_ids) return;
/* don't map root */
if (uid==0) return;
if (!list) {
if (!(name = uid_to_name(uid))) return;
uidlist = add_list((int)uid, name);
return;
}
while (list->next) {
if (list->id == (int)uid) return;
list = list->next;
}
if (list->id == (int)uid) return;
if (!(name = uid_to_name(uid))) return;
list->next = add_list((int)uid, name);
}
/* add a gid to the list of gids */
void add_gid(gid_t gid)
{
struct idlist *list = gidlist;
char *name;
if (numeric_ids) return;
/* don't map root */
if (gid==0) return;
if (!list) {
if (!(name = gid_to_name(gid))) return;
gidlist = add_list((int)gid, name);
return;
}
while (list->next) {
if (list->id == (int)gid) return;
list = list->next;
}
if (list->id == (int)gid) return;
if (!(name = gid_to_name(gid))) return;
list->next = add_list((int)gid, name);
}
/* send a complete uid/gid mapping to the peer */
void send_uid_list(int f)
{
struct idlist *list;
if (numeric_ids) return;
if (preserve_uid) {
/* we send sequences of uid/byte-length/name */
list = uidlist;
while (list) {
int len = strlen(list->name);
write_int(f, list->id);
write_byte(f, len);
write_buf(f, list->name, len);
list = list->next;
}
/* terminate the uid list with a 0 uid. We explicitly exclude
0 from the list */
write_int(f, 0);
}
if (preserve_gid) {
list = gidlist;
while (list) {
int len = strlen(list->name);
write_int(f, list->id);
write_byte(f, len);
write_buf(f, list->name, len);
list = list->next;
}
write_int(f, 0);
}
}
/* recv a complete uid/gid mapping from the peer and map the uid/gid
in the file list to local names */
void recv_uid_list(int f, struct file_list *flist)
{
int id, i;
char *name;
struct idlist *list;
if (numeric_ids) return;
if (preserve_uid) {
/* read the uid list */
list = uidlist;
id = read_int(f);
while (id != 0) {
int len = read_byte(f);
name = (char *)malloc(len);
if (!name) out_of_memory("recv_uid_list");
read_buf(f, name, len);
if (!list) {
uidlist = add_list(id, name);
list = uidlist;
} else {
list->next = add_list(id, name);
list = list->next;
}
list->id2 = map_uid(id, name);
free(name);
id = read_int(f);
}
}
if (preserve_gid) {
/* and the gid list */
list = gidlist;
id = read_int(f);
while (id != 0) {
int len = read_byte(f);
name = (char *)malloc(len);
if (!name) out_of_memory("recv_uid_list");
read_buf(f, name, len);
if (!list) {
gidlist = add_list(id, name);
list = gidlist;
} else {
list->next = add_list(id, name);
list = list->next;
}
list->id2 = map_gid(id, name);
free(name);
id = read_int(f);
}
}
if (!uidlist && !gidlist) return;
/* now convert the uid/gid of all files in the list to the mapped
uid/gid */
for (i=0;i<flist->count;i++) {
if (preserve_uid && flist->files[i]->uid != 0) {
flist->files[i]->uid = match_uid(flist->files[i]->uid);
}
if (preserve_gid && flist->files[i]->gid != 0) {
flist->files[i]->gid = match_gid(flist->files[i]->gid);
}
}
}

197
util.c
View File

@@ -53,6 +53,7 @@ struct map_struct *map_file(int fd,off_t len)
return ret;
}
char *map_ptr(struct map_struct *map,off_t offset,int len)
{
int nread = -2;
@@ -63,7 +64,8 @@ char *map_ptr(struct map_struct *map,off_t offset,int len)
if (len == 0)
return NULL;
len = MIN(len,map->size-offset);
if (len > (map->size-offset))
len = map->size-offset;
if (offset >= map->p_offset &&
offset+len <= map->p_offset+map->p_len) {
@@ -71,7 +73,8 @@ char *map_ptr(struct map_struct *map,off_t offset,int len)
}
len = MAX(len,CHUNK_SIZE);
len = MIN(len,map->size - offset);
if (len > (map->size-offset))
len = map->size-offset;
if (len > map->p_size) {
if (map->p) free(map->p);
@@ -82,9 +85,9 @@ char *map_ptr(struct map_struct *map,off_t offset,int len)
if (lseek(map->fd,offset,SEEK_SET) != offset ||
(nread=read(map->fd,map->p,len)) != len) {
fprintf(FERROR,"EOF in map_ptr! (offset=%d len=%d nread=%d errno=%d)\n",
(int)offset, len, nread, errno);
exit_cleanup(1);
fprintf(FERROR,"EOF in map_ptr! (offset=%d len=%d nread=%d errno=%d)\n",
(int)offset, len, nread, errno);
exit_cleanup(1);
}
map->p_offset = offset;
@@ -119,7 +122,7 @@ int piped_child(char **command,int *f_in,int *f_out)
}
pid = fork();
pid = do_fork();
if (pid < 0) {
fprintf(FERROR,"fork: %s\n",strerror(errno));
exit_cleanup(1);
@@ -164,38 +167,31 @@ void out_of_memory(char *str)
}
#ifndef HAVE_STRDUP
char *strdup(char *s)
{
int l = strlen(s) + 1;
char *ret = (char *)malloc(l);
if (ret)
strcpy(ret,s);
return ret;
}
#endif
int set_modtime(char *fname,time_t modtime)
{
#ifdef HAVE_UTIME_H
struct utimbuf tbuf;
tbuf.actime = time(NULL);
tbuf.modtime = modtime;
return utime(fname,&tbuf);
extern int dry_run;
if (dry_run) return 0;
{
#ifdef HAVE_UTIMBUF
struct utimbuf tbuf;
tbuf.actime = time(NULL);
tbuf.modtime = modtime;
return utime(fname,&tbuf);
#elif defined(HAVE_UTIME)
time_t t[2];
t[0] = time(NULL);
t[1] = modtime;
return utime(fname,t);
time_t t[2];
t[0] = time(NULL);
t[1] = modtime;
return utime(fname,t);
#else
struct timeval t[2];
t[0].tv_sec = time(NULL);
t[0].tv_usec = 0;
t[1].tv_sec = modtime;
t[1].tv_usec = 0;
return utimes(fname,t);
struct timeval t[2];
t[0].tv_sec = time(NULL);
t[0].tv_usec = 0;
t[1].tv_sec = modtime;
t[1].tv_usec = 0;
return utimes(fname,t);
#endif
}
}
@@ -251,3 +247,140 @@ int create_directory_path(char *fname)
}
return 0;
}
/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
Return LEN upon success, write's (negative) error code otherwise.
derived from GNU C's cccp.c.
*/
int full_write(int desc, char *ptr, int len)
{
int total_written;
total_written = 0;
while (len > 0) {
int written = write (desc, ptr, len);
if (written < 0) {
#ifdef EINTR
if (errno == EINTR)
continue;
#endif
return written;
}
total_written += written;
ptr += written;
len -= written;
}
return total_written;
}
/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
Return the actual number of bytes read, zero for EOF, or negative
for an error.
derived from GNU C's cccp.c. */
int safe_read(int desc, char *ptr, int len)
{
int n_chars;
if (len <= 0)
return len;
#ifdef EINTR
do {
n_chars = read(desc, ptr, len);
} while (n_chars < 0 && errno == EINTR);
#else
n_chars = read(desc, ptr, len);
#endif
return n_chars;
}
/* copy a file - this is used in conjunction with the --temp-dir option */
int copy_file(char *source, char *dest, mode_t mode)
{
int ifd;
int ofd;
char buf[1024 * 8];
int len; /* Number of bytes read into `buf'. */
ifd = open(source, O_RDONLY);
if (ifd == -1) {
fprintf(FERROR,"open %s: %s\n",
source,strerror(errno));
return -1;
}
if (do_unlink(dest) && errno != ENOENT) {
fprintf(FERROR,"unlink %s: %s\n",
dest,strerror(errno));
return -1;
}
ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
if (ofd < 0) {
fprintf(FERROR,"open %s: %s\n",
dest,strerror(errno));
close(ifd);
return -1;
}
while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
if (full_write(ofd, buf, len) < 0) {
fprintf(FERROR,"write %s: %s\n",
dest,strerror(errno));
close(ifd);
close(ofd);
return -1;
}
}
close(ifd);
close(ofd);
if (len < 0) {
fprintf(FERROR,"read %s: %s\n",
source,strerror(errno));
return -1;
}
return 0;
}
/* sleep for a while via select */
void u_sleep(int usec)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = usec;
select(0, NULL, NULL, NULL, &tv);
}
static pid_t all_pids[10];
static int num_pids;
/* fork and record the pid of the child */
pid_t do_fork(void)
{
pid_t newpid = fork();
if (newpid) {
all_pids[num_pids++] = newpid;
}
return newpid;
}
/* kill all children */
void kill_all(int sig)
{
int i;
for (i=0;i<num_pids;i++) {
if (all_pids[i] != getpid())
kill(all_pids[i], sig);
}
}

View File

@@ -1 +1 @@
#define VERSION "1.6.8"
#define VERSION "1.7.0"