added CHAR_OFFSET
[rsync/rsync.git] / checksum.c
1 /* 
2    Copyright (C) Andrew Tridgell 1996
3    Copyright (C) Paul Mackerras 1996
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "rsync.h"
21
22 int csum_length=2; /* initial value */
23
24 #define CSUM_CHUNK 64
25
26 int checksum_seed = 0;
27 extern int remote_version;
28
29 /*
30   a simple 32 bit checksum that can be upadted from either end
31   (inspired by Mark Adler's Adler-32 checksum)
32   */
33 uint32 get_checksum1(char *buf,int len)
34 {
35     int i;
36     uint32 s1, s2;
37
38     s1 = s2 = 0;
39     for (i = 0; i < (len-4); i+=4) {
40         s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 
41           10*CHAR_OFFSET;
42         s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET); 
43     }
44     for (; i < len; i++) {
45         s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
46     }
47     return (s1 & 0xffff) + (s2 << 16);
48 }
49
50
51 static void sum_put(MDstruct *md,char *sum)
52 {
53   SIVAL(sum,0,md->buffer[0]);
54   if (csum_length <= 4) return;
55   SIVAL(sum,4,md->buffer[1]);
56   if (csum_length <= 8) return;
57   SIVAL(sum,8,md->buffer[2]);
58   if (csum_length <= 12) return;
59   SIVAL(sum,12,md->buffer[3]);
60 }
61
62
63 void get_checksum2(char *buf,int len,char *sum)
64 {
65   int i;
66   MDstruct MD;
67   static char *buf1 = NULL;
68   static int len1 = 0;
69
70   if (len > len1) {
71     if (buf1) free(buf1);
72     buf1 = (char *)malloc(len+4);
73     len1 = len;
74     if (!buf1) out_of_memory("get_checksum2");
75   }
76
77   MDbegin(&MD);
78
79   bcopy(buf,buf1,len);
80   if (checksum_seed) {
81     SIVAL(buf1,len,checksum_seed);
82     len += 4;
83   }
84
85   for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
86     MDupdate(&MD, buf1+i, CSUM_CHUNK*8);
87   }
88   if (len - i > 0)
89     MDupdate(&MD, buf1+i, (len-i)*8);
90
91   sum_put(&MD,sum);
92 }
93
94
95 void file_checksum(char *fname,char *sum,off_t size)
96 {
97   int i;
98   MDstruct MD;
99   struct map_struct *buf;
100   int fd;
101   int len = size;
102   char tmpchunk[CSUM_CHUNK];
103
104   bzero(sum,csum_length);
105
106   fd = open(fname,O_RDONLY);
107   if (fd == -1) return;
108
109   buf = map_file(fd,size);
110
111   MDbegin(&MD);
112
113   for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
114     bcopy(map_ptr(buf,i,CSUM_CHUNK),tmpchunk,CSUM_CHUNK);
115     MDupdate(&MD, tmpchunk, CSUM_CHUNK*8);
116   }
117
118   if (len - i > 0) {
119     bcopy(map_ptr(buf,i,len-i),tmpchunk,len-i);
120     MDupdate(&MD, tmpchunk, (len-i)*8);
121   }
122
123   sum_put(&MD,sum);
124
125   close(fd);
126   unmap_file(buf);
127 }
128
129
130 void checksum_init(void)
131 {
132   if (remote_version >= 14)
133     csum_length = 2; /* adaptive */
134   else
135     csum_length = SUM_LENGTH;
136 }
137
138
139
140 static MDstruct sumMD;
141 static int sumresidue;
142 static char sumrbuf[CSUM_CHUNK];
143
144 void sum_init(void)
145 {
146   char s[4];
147   MDbegin(&sumMD);  
148   sumresidue=0;
149   SIVAL(s,0,checksum_seed);
150   sum_update(s,4);
151 }
152
153 void sum_update(char *p,int len)
154 {
155   int i;
156   if (len + sumresidue < CSUM_CHUNK) {
157     bcopy(p,sumrbuf+sumresidue,len);
158     sumresidue += len;
159     return;
160   }
161
162   if (sumresidue) {
163     i = MIN(CSUM_CHUNK-sumresidue,len);
164     bcopy(p,sumrbuf+sumresidue,i);
165     MDupdate(&sumMD, sumrbuf, (i+sumresidue)*8);
166     len -= i;
167     p += i;
168   }
169
170   for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
171     bcopy(p+i,sumrbuf,CSUM_CHUNK);
172     MDupdate(&sumMD, sumrbuf, CSUM_CHUNK*8);
173   }
174
175   if (len - i > 0) {
176     sumresidue = len-i;
177     bcopy(p+i,sumrbuf,sumresidue);
178   } else {
179     sumresidue = 0;    
180   }
181 }
182
183 void sum_end(char *sum)
184 {
185   if (sumresidue)
186     MDupdate(&sumMD, sumrbuf, sumresidue*8);
187
188   SIVAL(sum,0,sumMD.buffer[0]);
189   SIVAL(sum,4,sumMD.buffer[1]);
190   SIVAL(sum,8,sumMD.buffer[2]);
191   SIVAL(sum,12,sumMD.buffer[3]);  
192 }
193
194