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, 2005 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 2 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, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 23#include "rsync.h" 24 25int csum_length=2; /* initial value */ 26 27#define CSUM_CHUNK 64 28 29extern int checksum_seed; 30extern int protocol_version; 31 32/* 33 a simple 32 bit checksum that can be upadted from either end 34 (inspired by Mark Adler's Adler-32 checksum) 35 */ 36uint32 get_checksum1(char *buf1, int32 len) 37{ 38 int32 i; 39 uint32 s1, s2; 40 schar *buf = (schar *)buf1; 41 42 s1 = s2 = 0; 43 for (i = 0; i < (len-4); i+=4) { 44 s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] + 45 10*CHAR_OFFSET; 46 s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET); 47 } 48 for (; i < len; i++) { 49 s1 += (buf[i]+CHAR_OFFSET); s2 += s1; 50 } 51 return (s1 & 0xffff) + (s2 << 16); 52} 53 54 55void get_checksum2(char *buf, int32 len, char *sum) 56{ 57 int32 i; 58 static char *buf1; 59 static int32 len1; 60 struct mdfour m; 61 62 if (len > len1) { 63 if (buf1) 64 free(buf1); 65 buf1 = new_array(char, len+4); 66 len1 = len; 67 if (!buf1) 68 out_of_memory("get_checksum2"); 69 } 70 71 mdfour_begin(&m); 72 73 memcpy(buf1,buf,len); 74 if (checksum_seed) { 75 SIVAL(buf1,len,checksum_seed); 76 len += 4; 77 } 78 79 for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) { 80 mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK); 81 } 82 /* 83 * Prior to version 27 an incorrect MD4 checksum was computed 84 * by failing to call mdfour_tail() for block sizes that 85 * are multiples of 64. This is fixed by calling mdfour_update() 86 * even when there are no more bytes. 87 */ 88 if (len - i > 0 || protocol_version >= 27) { 89 mdfour_update(&m, (uchar *)(buf1+i), (len-i)); 90 } 91 92 mdfour_result(&m, (uchar *)sum); 93} 94 95 96void file_checksum(char *fname,char *sum,OFF_T size) 97{ 98 OFF_T i; 99 struct map_struct *buf; 100 int fd; 101 OFF_T len = size; 102 struct mdfour m; 103 104 memset(sum,0,MD4_SUM_LENGTH); 105 106 fd = do_open(fname, O_RDONLY, 0); 107 if (fd == -1) 108 return; 109 110 buf = map_file(fd, size, MAX_MAP_SIZE, CSUM_CHUNK); 111 112 mdfour_begin(&m); 113 114 for(i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) { 115 mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK), 116 CSUM_CHUNK); 117 } 118 119 /* Prior to version 27 an incorrect MD4 checksum was computed 120 * by failing to call mdfour_tail() for block sizes that 121 * are multiples of 64. This is fixed by calling mdfour_update() 122 * even when there are no more bytes. */ 123 if (len - i > 0 || protocol_version >= 27) 124 mdfour_update(&m, (uchar *)map_ptr(buf, i, len-i), len-i); 125 126 mdfour_result(&m, (uchar *)sum); 127 128 close(fd); 129 unmap_file(buf); 130} 131 132 133static int32 sumresidue; 134static char sumrbuf[CSUM_CHUNK]; 135static struct mdfour md; 136 137void sum_init(int seed) 138{ 139 char s[4]; 140 mdfour_begin(&md); 141 sumresidue = 0; 142 SIVAL(s, 0, seed); 143 sum_update(s, 4); 144} 145 146/** 147 * Feed data into an MD4 accumulator, md. The results may be 148 * retrieved using sum_end(). md is used for different purposes at 149 * different points during execution. 150 * 151 * @todo Perhaps get rid of md and just pass in the address each time. 152 * Very slightly clearer and slower. 153 **/ 154void sum_update(char *p, int32 len) 155{ 156 if (len + sumresidue < CSUM_CHUNK) { 157 memcpy(sumrbuf + sumresidue, p, len); 158 sumresidue += len; 159 return; 160 } 161 162 if (sumresidue) { 163 int32 i = CSUM_CHUNK - sumresidue; 164 memcpy(sumrbuf + sumresidue, p, i); 165 mdfour_update(&md, (uchar *)sumrbuf, CSUM_CHUNK); 166 len -= i; 167 p += i; 168 } 169 170 while (len >= CSUM_CHUNK) { 171 mdfour_update(&md, (uchar *)p, CSUM_CHUNK); 172 len -= CSUM_CHUNK; 173 p += CSUM_CHUNK; 174 } 175 176 sumresidue = len; 177 if (sumresidue) 178 memcpy(sumrbuf, p, sumresidue); 179} 180 181void sum_end(char *sum) 182{ 183 if (sumresidue || protocol_version >= 27) 184 mdfour_update(&md, (uchar *)sumrbuf, sumresidue); 185 186 mdfour_result(&md, (uchar *)sum); 187} 188