#include "rsync.h"
-extern int csum_length;
+int csum_length=SUM_LENGTH;
+
+#define CSUM_CHUNK 64
+
+static char *tmpchunk = NULL;
+
/*
a simple 32 bit checksum that can be upadted from either end
uint32 s1, s2;
s1 = s2 = 0;
- for (i = 0; i < len; i++) {
- s1 += buf[i];
- s2 += s1;
+ for (i = 0; i < (len-4); i+=4) {
+ s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3];
+ s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3]);
+ }
+ for (; i < len; i++) {
+ s1 += buf[i]; s2 += s1;
}
return (s1 & 0xffff) + (s2 << 16);
}
+static void sum_put(MDstruct *md,char *sum)
+{
+ SIVAL(sum,0,md->buffer[0]);
+ if (csum_length <= 4) return;
+ SIVAL(sum,4,md->buffer[1]);
+ if (csum_length <= 8) return;
+ SIVAL(sum,8,md->buffer[2]);
+ if (csum_length <= 12) return;
+ SIVAL(sum,12,md->buffer[3]);
+}
+
+
void get_checksum2(char *buf,int len,char *sum)
{
- char buf2[64];
int i;
MDstruct MD;
MDbegin(&MD);
- for(i = 0; i + 64 <= len; i += 64) {
- bcopy(buf+i,buf2,64);
- MDupdate(&MD, buf2, 512);
+
+ for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
+ bcopy(buf+i,tmpchunk,CSUM_CHUNK);
+ MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
}
- bcopy(buf+i,buf2,len-i);
- MDupdate(&MD, buf2, (len-i)*8);
- SIVAL(sum,0,MD.buffer[0]);
- if (csum_length <= 4) return;
- SIVAL(sum,4,MD.buffer[1]);
- if (csum_length <= 8) return;
- SIVAL(sum,8,MD.buffer[2]);
- if (csum_length <= 12) return;
- SIVAL(sum,12,MD.buffer[3]);
+
+ bcopy(buf+i,tmpchunk,len-i);
+ MDupdate(&MD, tmpchunk, (len-i)*8);
+
+ sum_put(&MD,sum);
}
+
void file_checksum(char *fname,char *sum,off_t size)
{
+ int i;
+ MDstruct MD;
char *buf;
int fd;
+ int len = size;
+
bzero(sum,csum_length);
fd = open(fname,O_RDONLY);
if (fd == -1) return;
buf = map_file(fd,size);
- if (!buf) {
- close(fd);
- return;
+
+ MDbegin(&MD);
+
+ for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
+ bcopy(map_ptr(buf,i,CSUM_CHUNK),tmpchunk,CSUM_CHUNK);
+ MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
}
- get_checksum2(buf,size,sum);
+ bcopy(map_ptr(buf,i,len-i),tmpchunk,len-i);
+ MDupdate(&MD, tmpchunk, (len-i)*8);
+
+ sum_put(&MD,sum);
+
close(fd);
unmap_file(buf,size);
}
+
+
+void checksum_init(void)
+{
+ tmpchunk = (char *)malloc(CSUM_CHUNK);
+ if (!tmpchunk) out_of_memory("checksum_init");
+}
+
+
+#ifdef CHECKSUM_MAIN
+ int main(int argc,char *argv[])
+{
+ char sum[SUM_LENGTH];
+ int i,j;
+
+ checksum_init();
+
+ for (i=1;i<argc;i++) {
+ struct stat st;
+ if (stat(argv[i],&st) == 0) {
+ file_checksum(argv[i],sum,st.st_size);
+ for (j=0;j<SUM_LENGTH;j++)
+ printf("%02X",(unsigned char)sum[j]);
+ printf(" %s\n",argv[i]);
+ }
+ }
+}
+#endif
if (!f) {
if (fatal) {
fprintf(stderr,"%s : %s\n",fname,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
return list;
}
if (dir && *dir) {
if (getcwd(dbuf,MAXPATHLEN-1) == NULL) {
fprintf(stderr,"getwd : %s\n",strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
if (chdir(dir) != 0) {
fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno));
flist_dir = NULL;
if (chdir(dbuf) != 0) {
fprintf(stderr,"chdir %s : %s\n",dbuf,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
continue;
}
if (verbose > 1)
fprintf(stderr,"Error reading %d bytes : %s\n",
4,ret==-1?strerror(errno):"EOF");
- exit(1);
+ exit_cleanup(1);
}
total_read += 4;
return IVAL(b,0);
if (verbose > 1)
fprintf(stderr,"Error reading %d bytes : %s\n",
len,ret==-1?strerror(errno):"EOF");
- exit(1);
+ exit_cleanup(1);
}
total_read += len;
}
int read_write(int fd_in,int fd_out,int size)
{
static char *buf=NULL;
- static int bufsize = WRITE_BLOCK_SIZE;
+ static int bufsize = CHUNK_SIZE;
int total=0;
if (!buf) {
if ((ret=writefd(f,b,4)) != 4) {
fprintf(stderr,"write_int failed : %s\n",
ret==-1?strerror(errno):"EOF");
- exit(1);
+ exit_cleanup(1);
}
total_written += 4;
}
if ((ret=writefd(f,buf,len)) != len) {
fprintf(stderr,"write_buf failed : %s\n",
ret==-1?strerror(errno):"EOF");
- exit(1);
+ exit_cleanup(1);
}
total_written += len;
}
int delete_mode=0;
int one_file_system=0;
int remote_version=0;
-int csum_length=SUM_LENGTH;
+extern int csum_length;
int am_server = 0;
static int sender = 0;
if (S_ISDIR(st.st_mode)) {
if (chdir(name) != 0) {
fprintf(stderr,"chdir %s : %s\n",name,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
return NULL;
}
if (flist->count > 1) {
fprintf(stderr,"ERROR: destination must be a directory when copying more than 1 file\n");
- exit(1);
+ exit_cleanup(1);
}
return name;
}
if (mkdir(name,0777) != 0) {
fprintf(stderr,"mkdir %s : %s\n",name,strerror(errno));
- exit(1);
+ exit_cleanup(1);
} else {
fprintf(am_server?stderr:stdout,"created directory %s\n",name);
}
if (chdir(name) != 0) {
fprintf(stderr,"chdir %s : %s\n",name,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
return NULL;
if (chdir(dir) != 0) {
fprintf(stderr,"chdir %s: %s\n",dir,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
argc--;
argv++;
flist = send_file_list(STDOUT_FILENO,recurse,argc,argv);
send_files(flist,STDOUT_FILENO,STDIN_FILENO);
report(STDOUT_FILENO);
- exit(0);
+ exit_cleanup(0);
}
argv++;
if (chdir(dir) != 0) {
fprintf(stderr,"chdir %s : %s\n",dir,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
}
flist = recv_file_list(STDIN_FILENO);
if (!flist || flist->count == 0) {
fprintf(stderr,"nothing to do\n");
- exit(1);
+ exit_cleanup(1);
}
if (argc > 0) {
recv_files(STDIN_FILENO,flist,local_name);
if (verbose > 2)
fprintf(stderr,"receiver read %d\n",read_total());
- exit(0);
+ exit_cleanup(0);
}
generate_files(STDOUT_FILENO,flist,local_name);
waitpid(pid, &status, 0);
- exit(status);
+ exit_cleanup(status);
}
starttime = time(NULL);
+ checksum_init();
+
while ((opt = getopt_long(argc, argv,
short_options, long_options, &option_index))
!= -1) {
case OPT_VERSION:
printf("rsync version %s protocol version %d\n",
VERSION,PROTOCOL_VERSION);
- exit(0);
+ exit_cleanup(0);
case OPT_SUFFIX:
backup_suffix = optarg;
case 'h':
usage(stdout);
- exit(0);
+ exit_cleanup(0);
case 'b':
make_backups=1;
preserve_uid=1;
} else {
fprintf(stderr,"-o only allowed for root\n");
- exit(1);
+ exit_cleanup(1);
}
break;
preserve_devices=1;
} else {
fprintf(stderr,"-D only allowed for root\n");
- exit(1);
+ exit_cleanup(1);
}
break;
case OPT_SENDER:
if (!am_server) {
usage(stderr);
- exit(1);
+ exit_cleanup(1);
}
sender = 1;
break;
default:
fprintf(stderr,"bad option -%c\n",opt);
- exit(1);
+ exit_cleanup(1);
}
}
if (remote_version < MIN_PROTOCOL_VERSION ||
remote_version > MAX_PROTOCOL_VERSION) {
fprintf(stderr,"protocol version mismatch - is your shell clean?\n");
- exit(1);
+ exit_cleanup(1);
}
write_int(STDOUT_FILENO,PROTOCOL_VERSION);
write_flush(STDOUT_FILENO);
} else {
do_server_recv(argc,argv);
}
- exit(0);
+ exit_cleanup(0);
}
if (argc < 2) {
usage(stderr);
- exit(1);
+ exit_cleanup(1);
}
p = strchr(argv[0],':');
if (!sender && argc != 1) {
usage(stderr);
- exit(1);
+ exit_cleanup(1);
}
pid = do_cmd(shell_cmd,shell_machine,shell_user,shell_path,&f_in,&f_out);
if (remote_version < MIN_PROTOCOL_VERSION ||
remote_version > MAX_PROTOCOL_VERSION) {
fprintf(stderr,"protocol version mismatch - is your shell clean?\n");
- exit(1);
+ exit_cleanup(1);
}
}
fprintf(stderr,"waiting on %d\n",pid);
waitpid(pid, &status, 0);
report(-1);
- exit(status);
+ exit_cleanup(status);
}
send_exclude_list(f_out);
flist = recv_file_list(f_in);
if (!flist || flist->count == 0) {
fprintf(stderr,"nothing to do\n");
- exit(0);
+ exit_cleanup(0);
}
local_name = get_local_name(flist,argv[0]);
recv_files(f_in,flist,local_name);
if (verbose > 1)
fprintf(stderr,"receiver read %d\n",read_total());
- exit(0);
+ exit_cleanup(0);
}
generate_files(f_out,flist,local_name);
int l = 0;
write_int(f,n);
while (l < n) {
- int n1 = MIN(WRITE_BLOCK_SIZE,n-l);
+ int n1 = MIN(CHUNK_SIZE,n-l);
write_buf(f,map_ptr(buf,last_match+l,n1),n1);
l += n1;
}
if (read_write(f_in,fd,i) != i) {
fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
offset += i;
} else {
if (write_sparse(fd,map_ptr(buf,offset2,len),len) != len) {
fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
offset += len;
}
if (offset > 0 && sparse_end(fd) != 0) {
fprintf(stderr,"write failed on %s : %s\n",fname,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
}
static char *cleanup_fname = NULL;
-void sig_int(void)
+void exit_cleanup(int code)
{
if (cleanup_fname)
unlink(cleanup_fname);
- exit(1);
+ exit(code);
+}
+
+void sig_int(void)
+{
+ exit_cleanup(1);
}
sprintf(fnamebak,"%s%s",fname,backup_suffix);
if (rename(fname,fnamebak) != 0 && errno != ENOENT) {
fprintf(stderr,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
}
#define MIN_PROTOCOL_VERSION 10
#define MAX_PROTOCOL_VERSION 20
-/* block size to write files in */
-#define WRITE_BLOCK_SIZE (32*1024)
+#define CHUNK_SIZE (32*1024)
#define MAX_MAP_SIZE (4*1024*1024)
#define BLOCKING_TIMEOUT 10
return (p + (offset - p_offset));
}
- len = MAX(len,WRITE_BLOCK_SIZE);
+ len = MAX(len,CHUNK_SIZE);
len = MIN(len,map_size - offset);
if (len > p_size) {
if (lseek(map_fd,offset,SEEK_SET) != offset ||
read(map_fd,p,len) != len) {
fprintf(stderr,"EOF in map_ptr!\n");
- exit(1);
+ exit_cleanup(1);
}
p_offset = offset;
if (pipe(to_child_pipe) < 0 ||
pipe(from_child_pipe) < 0) {
fprintf(stderr,"pipe: %s\n",strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
pid = fork();
if (pid < 0) {
fprintf(stderr,"fork: %s\n",strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
if (pid == 0)
close(from_child_pipe[0]) < 0 ||
dup2(from_child_pipe[1], STDOUT_FILENO) < 0) {
fprintf(stderr,"Failed to dup/close : %s\n",strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
execvp(command[0], command);
fprintf(stderr,"Failed to exec %s : %s\n",
command[0],strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
if (close(from_child_pipe[1]) < 0 ||
close(to_child_pipe[0]) < 0) {
fprintf(stderr,"Failed to close : %s\n",strerror(errno));
- exit(1);
+ exit_cleanup(1);
}
*f_in = from_child_pipe[0];
void out_of_memory(char *str)
{
fprintf(stderr,"out of memory in %s\n",str);
- exit(1);
+ exit_cleanup(1);
}