2 * Copyright (c) 2008-2009, Ulf Lilleengen <lulf@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/types.h>
41 #include "rsyncfile.h"
43 #define MINBLOCKSIZE 1024
44 #define MAXBLOCKSIZE (16 * 1024)
45 #define RECEIVEBUFFERSIZE (15 * 1024)
46 #define BLOCKINFOSIZE 26
47 #define SEARCHREGION 10
48 #define MAXBLOCKS (RECEIVEBUFFERSIZE / BLOCKINFOSIZE)
63 char blockmd5[MD5_DIGEST_SIZE];
64 char rsumstr[RSUM_SIZE];
68 static size_t rsync_chooseblocksize(size_t);
69 static uint32_t rsync_rollsum(char *, size_t);
71 /* Open a file and initialize variable for rsync operation. */
73 rsync_open(char *path, size_t blocksize, int rdonly)
79 rf = xmalloc(sizeof(*rf));
80 error = stat(path, &st);
85 rf->fsize = st.st_size;
87 rf->fd = open(path, rdonly ? O_RDONLY : O_RDWR);
92 rf->buf = mmap(0, rf->fsize, PROT_READ, MAP_SHARED, rf->fd, 0);
93 if (rf->buf == MAP_FAILED) {
98 rf->end = rf->buf + rf->fsize;
99 rf->blocksize = (blocksize == 0 ? rsync_chooseblocksize(rf->fsize) :
101 rf->blockptr = rf->buf;
106 /* Close and free all resources related to an rsync file transfer. */
108 rsync_close(struct rsyncfile *rf)
112 error = munmap(rf->buf, rf->fsize);
121 * Choose the most appropriate block size for an rsync transfer. Modeled
122 * algorithm after cvsup.
125 rsync_chooseblocksize(size_t fsize)
127 size_t bestrem, blocksize, bs, hisearch, losearch, rem;
129 blocksize = fsize / MAXBLOCKS;
130 losearch = blocksize - SEARCHREGION;
131 hisearch = blocksize + SEARCHREGION;
133 if (losearch < MINBLOCKSIZE) {
134 losearch = MINBLOCKSIZE;
135 hisearch = losearch + (2 * SEARCHREGION);
136 } else if (hisearch > MAXBLOCKSIZE) {
137 hisearch = MAXBLOCKSIZE;
138 losearch = hisearch - (2 * SEARCHREGION);
141 bestrem = MAXBLOCKSIZE;
142 for (bs = losearch; bs <= hisearch; bs++) {
152 /* Get the next rsync block of a file. */
154 rsync_nextblock(struct rsyncfile *rf)
159 if (rf->blockptr >= rf->end)
161 blocksize = min((size_t)(rf->end - rf->blockptr), rf->blocksize);
162 /* Calculate MD5 of the block. */
164 MD5_Update(&ctx, rf->blockptr, blocksize);
165 MD5_End(rf->blockmd5, &ctx);
167 rf->rsum = rsync_rollsum(rf->blockptr, blocksize);
168 snprintf(rf->rsumstr, RSUM_SIZE, "%x", rf->rsum);
170 rf->blockptr += blocksize;
174 /* Get the rolling checksum of a file. */
176 rsync_rollsum(char *buf, size_t len)
185 while (ptr < limit) {
186 a += *ptr + CHAR_OFFSET;
190 return ((b << 16) | a);
193 /* Get running sum so far. */
195 rsync_rsum(struct rsyncfile *rf)
198 return (rf->rsumstr);
201 /* Get MD5 of current block. */
203 rsync_blockmd5(struct rsyncfile *rf)
206 return (rf->blockmd5);
209 /* Accessor for blocksize. */
211 rsync_blocksize(struct rsyncfile *rf)
214 return (rf->blocksize);
217 /* Accessor for filesize. */
219 rsync_filesize(struct rsyncfile *rf)