Annotation of embedaddon/rsync/checksum.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Routines to support checksumming of bytes.
3: *
4: * Copyright (C) 1996 Andrew Tridgell
5: * Copyright (C) 1996 Paul Mackerras
6: * Copyright (C) 2004-2009 Wayne Davison
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
23:
24: extern int checksum_seed;
25: extern int protocol_version;
26:
27: /*
28: a simple 32 bit checksum that can be upadted from either end
29: (inspired by Mark Adler's Adler-32 checksum)
30: */
31: uint32 get_checksum1(char *buf1, int32 len)
32: {
33: int32 i;
34: uint32 s1, s2;
35: schar *buf = (schar *)buf1;
36:
37: s1 = s2 = 0;
38: for (i = 0; i < (len-4); i+=4) {
39: s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
40: 10*CHAR_OFFSET;
41: s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
42: }
43: for (; i < len; i++) {
44: s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
45: }
46: return (s1 & 0xffff) + (s2 << 16);
47: }
48:
49:
50: void get_checksum2(char *buf, int32 len, char *sum)
51: {
52: md_context m;
53:
54: if (protocol_version >= 30) {
55: uchar seedbuf[4];
56: md5_begin(&m);
57: md5_update(&m, (uchar *)buf, len);
58: if (checksum_seed) {
59: SIVALu(seedbuf, 0, checksum_seed);
60: md5_update(&m, seedbuf, 4);
61: }
62: md5_result(&m, (uchar *)sum);
63: } else {
64: int32 i;
65: static char *buf1;
66: static int32 len1;
67:
68: mdfour_begin(&m);
69:
70: if (len > len1) {
71: if (buf1)
72: free(buf1);
73: buf1 = new_array(char, len+4);
74: len1 = len;
75: if (!buf1)
76: out_of_memory("get_checksum2");
77: }
78:
79: memcpy(buf1, buf, 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: mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
87:
88: /*
89: * Prior to version 27 an incorrect MD4 checksum was computed
90: * by failing to call mdfour_tail() for block sizes that
91: * are multiples of 64. This is fixed by calling mdfour_update()
92: * even when there are no more bytes.
93: */
94: if (len - i > 0 || protocol_version >= 27)
95: mdfour_update(&m, (uchar *)(buf1+i), len-i);
96:
97: mdfour_result(&m, (uchar *)sum);
98: }
99: }
100:
101: void file_checksum(char *fname, char *sum, OFF_T size)
102: {
103: struct map_struct *buf;
104: OFF_T i, len = size;
105: md_context m;
106: int32 remainder;
107: int fd;
108:
109: memset(sum, 0, MAX_DIGEST_LEN);
110:
111: fd = do_open(fname, O_RDONLY, 0);
112: if (fd == -1)
113: return;
114:
115: buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK);
116:
117: if (protocol_version >= 30) {
118: md5_begin(&m);
119:
120: for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
121: md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
122: CSUM_CHUNK);
123: }
124:
125: remainder = (int32)(len - i);
126: if (remainder > 0)
127: md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
128:
129: md5_result(&m, (uchar *)sum);
130: } else {
131: mdfour_begin(&m);
132:
133: for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
134: mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
135: CSUM_CHUNK);
136: }
137:
138: /* Prior to version 27 an incorrect MD4 checksum was computed
139: * by failing to call mdfour_tail() for block sizes that
140: * are multiples of 64. This is fixed by calling mdfour_update()
141: * even when there are no more bytes. */
142: remainder = (int32)(len - i);
143: if (remainder > 0 || protocol_version >= 27)
144: mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
145:
146: mdfour_result(&m, (uchar *)sum);
147: }
148:
149: close(fd);
150: unmap_file(buf);
151: }
152:
153: static int32 sumresidue;
154: static md_context md;
155:
156: void sum_init(int seed)
157: {
158: char s[4];
159:
160: if (protocol_version >= 30)
161: md5_begin(&md);
162: else {
163: mdfour_begin(&md);
164: sumresidue = 0;
165: SIVAL(s, 0, seed);
166: sum_update(s, 4);
167: }
168: }
169:
170: /**
171: * Feed data into an MD4 accumulator, md. The results may be
172: * retrieved using sum_end(). md is used for different purposes at
173: * different points during execution.
174: *
175: * @todo Perhaps get rid of md and just pass in the address each time.
176: * Very slightly clearer and slower.
177: **/
178: void sum_update(const char *p, int32 len)
179: {
180: if (protocol_version >= 30) {
181: md5_update(&md, (uchar *)p, len);
182: return;
183: }
184:
185: if (len + sumresidue < CSUM_CHUNK) {
186: memcpy(md.buffer + sumresidue, p, len);
187: sumresidue += len;
188: return;
189: }
190:
191: if (sumresidue) {
192: int32 i = CSUM_CHUNK - sumresidue;
193: memcpy(md.buffer + sumresidue, p, i);
194: mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
195: len -= i;
196: p += i;
197: }
198:
199: while (len >= CSUM_CHUNK) {
200: mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
201: len -= CSUM_CHUNK;
202: p += CSUM_CHUNK;
203: }
204:
205: sumresidue = len;
206: if (sumresidue)
207: memcpy(md.buffer, p, sumresidue);
208: }
209:
210: int sum_end(char *sum)
211: {
212: if (protocol_version >= 30) {
213: md5_result(&md, (uchar *)sum);
214: return MD5_DIGEST_LEN;
215: }
216:
217: if (sumresidue || protocol_version >= 27)
218: mdfour_update(&md, (uchar *)md.buffer, sumresidue);
219:
220: mdfour_result(&md, (uchar *)sum);
221:
222: return MD4_DIGEST_LEN;
223: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>