File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / checksum.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:54:32 2016 UTC (7 years, 7 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_1_2p5, HEAD
rsync 3.1.2

    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-2015 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: extern int proper_seed_order;
   27: 
   28: /*
   29:   a simple 32 bit checksum that can be upadted from either end
   30:   (inspired by Mark Adler's Adler-32 checksum)
   31:   */
   32: uint32 get_checksum1(char *buf1, int32 len)
   33: {
   34:     int32 i;
   35:     uint32 s1, s2;
   36:     schar *buf = (schar *)buf1;
   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: void get_checksum2(char *buf, int32 len, char *sum)
   52: {
   53: 	md_context m;
   54: 
   55: 	if (protocol_version >= 30) {
   56: 		uchar seedbuf[4];
   57: 		md5_begin(&m);
   58: 		if (proper_seed_order) {
   59: 			if (checksum_seed) {
   60: 				SIVALu(seedbuf, 0, checksum_seed);
   61: 				md5_update(&m, seedbuf, 4);
   62: 			}
   63: 			md5_update(&m, (uchar *)buf, len);
   64: 		} else {
   65: 			md5_update(&m, (uchar *)buf, len);
   66: 			if (checksum_seed) {
   67: 				SIVALu(seedbuf, 0, checksum_seed);
   68: 				md5_update(&m, seedbuf, 4);
   69: 			}
   70: 		}
   71: 		md5_result(&m, (uchar *)sum);
   72: 	} else {
   73: 		int32 i;
   74: 		static char *buf1;
   75: 		static int32 len1;
   76: 
   77: 		mdfour_begin(&m);
   78: 
   79: 		if (len > len1) {
   80: 			if (buf1)
   81: 				free(buf1);
   82: 			buf1 = new_array(char, len+4);
   83: 			len1 = len;
   84: 			if (!buf1)
   85: 				out_of_memory("get_checksum2");
   86: 		}
   87: 
   88: 		memcpy(buf1, buf, len);
   89: 		if (checksum_seed) {
   90: 			SIVAL(buf1,len,checksum_seed);
   91: 			len += 4;
   92: 		}
   93: 
   94: 		for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
   95: 			mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
   96: 
   97: 		/*
   98: 		 * Prior to version 27 an incorrect MD4 checksum was computed
   99: 		 * by failing to call mdfour_tail() for block sizes that
  100: 		 * are multiples of 64.  This is fixed by calling mdfour_update()
  101: 		 * even when there are no more bytes.
  102: 		 */
  103: 		if (len - i > 0 || protocol_version >= 27)
  104: 			mdfour_update(&m, (uchar *)(buf1+i), len-i);
  105: 
  106: 		mdfour_result(&m, (uchar *)sum);
  107: 	}
  108: }
  109: 
  110: void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
  111: {
  112: 	struct map_struct *buf;
  113: 	OFF_T i, len = st_p->st_size;
  114: 	md_context m;
  115: 	int32 remainder;
  116: 	int fd;
  117: 
  118: 	memset(sum, 0, MAX_DIGEST_LEN);
  119: 
  120: 	fd = do_open(fname, O_RDONLY, 0);
  121: 	if (fd == -1)
  122: 		return;
  123: 
  124: 	buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
  125: 
  126: 	if (protocol_version >= 30) {
  127: 		md5_begin(&m);
  128: 
  129: 		for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
  130: 			md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
  131: 				   CSUM_CHUNK);
  132: 		}
  133: 
  134: 		remainder = (int32)(len - i);
  135: 		if (remainder > 0)
  136: 			md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
  137: 
  138: 		md5_result(&m, (uchar *)sum);
  139: 	} else {
  140: 		mdfour_begin(&m);
  141: 
  142: 		for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
  143: 			mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
  144: 				      CSUM_CHUNK);
  145: 		}
  146: 
  147: 		/* Prior to version 27 an incorrect MD4 checksum was computed
  148: 		 * by failing to call mdfour_tail() for block sizes that
  149: 		 * are multiples of 64.  This is fixed by calling mdfour_update()
  150: 		 * even when there are no more bytes. */
  151: 		remainder = (int32)(len - i);
  152: 		if (remainder > 0 || protocol_version >= 27)
  153: 			mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
  154: 
  155: 		mdfour_result(&m, (uchar *)sum);
  156: 	}
  157: 
  158: 	close(fd);
  159: 	unmap_file(buf);
  160: }
  161: 
  162: static int32 sumresidue;
  163: static md_context md;
  164: 
  165: void sum_init(int seed)
  166: {
  167: 	char s[4];
  168: 
  169: 	if (protocol_version >= 30)
  170: 		md5_begin(&md);
  171: 	else {
  172: 		mdfour_begin(&md);
  173: 		sumresidue = 0;
  174: 		SIVAL(s, 0, seed);
  175: 		sum_update(s, 4);
  176: 	}
  177: }
  178: 
  179: /**
  180:  * Feed data into an MD4 accumulator, md.  The results may be
  181:  * retrieved using sum_end().  md is used for different purposes at
  182:  * different points during execution.
  183:  *
  184:  * @todo Perhaps get rid of md and just pass in the address each time.
  185:  * Very slightly clearer and slower.
  186:  **/
  187: void sum_update(const char *p, int32 len)
  188: {
  189: 	if (protocol_version >= 30) {
  190: 		md5_update(&md, (uchar *)p, len);
  191: 		return;
  192: 	}
  193: 
  194: 	if (len + sumresidue < CSUM_CHUNK) {
  195: 		memcpy(md.buffer + sumresidue, p, len);
  196: 		sumresidue += len;
  197: 		return;
  198: 	}
  199: 
  200: 	if (sumresidue) {
  201: 		int32 i = CSUM_CHUNK - sumresidue;
  202: 		memcpy(md.buffer + sumresidue, p, i);
  203: 		mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
  204: 		len -= i;
  205: 		p += i;
  206: 	}
  207: 
  208: 	while (len >= CSUM_CHUNK) {
  209: 		mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
  210: 		len -= CSUM_CHUNK;
  211: 		p += CSUM_CHUNK;
  212: 	}
  213: 
  214: 	sumresidue = len;
  215: 	if (sumresidue)
  216: 		memcpy(md.buffer, p, sumresidue);
  217: }
  218: 
  219: int sum_end(char *sum)
  220: {
  221: 	if (protocol_version >= 30) {
  222: 		md5_result(&md, (uchar *)sum);
  223: 		return MD5_DIGEST_LEN;
  224: 	}
  225: 
  226: 	if (sumresidue || protocol_version >= 27)
  227: 		mdfour_update(&md, (uchar *)md.buffer, sumresidue);
  228: 
  229: 	mdfour_result(&md, (uchar *)sum);
  230: 
  231: 	return MD4_DIGEST_LEN;
  232: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>