File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / checksum.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    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>