Commit c710c6b8 authored by Niels Möller's avatar Niels Möller
Browse files

* src/rsync/send.c (rsync_send_init): Rewrote. Allocates a

slightly larger buffer.
(rsync_send_eof): New function.
(rsync_send_copy_in): Deleted th dst argument. Update sum_md5 and
size.
(rsync_send_read): New function.
(rsync_send_search): New function.
(rsync_send_flush): New function.
(rsync_send_write): New function.
(rsync_send): Rewrote and simplified. Now uses fewer states,
simpler eof handling, and calls several smaller functions.

* src/rsync/generate.c, src/rsync/receive.c, src/rsync/send.c,
src/rsync/rsync.h: Changed return types from int to enum
rsync_result_t.

Rev: src/rsync/send.c:1.5
parent 20b6d7b8
......@@ -76,7 +76,7 @@ rsync_add_entry(struct rsync_table *table,
b = READ_UINT16(input + 2);
node->sum_weak = COMBINE_SUM(a, b);
memcpy(node->sum_md5, input + 4, RSYNC_SUM_LENGTH);
memcpy(node->sum_md5, input + 4, RSYNC_SUM_SIZE);
h = HASH_SUM(a, b);
node->next = table->hash[h];
......@@ -101,7 +101,7 @@ rsync_lookup_2(struct rsync_node *n, UINT32 weak,
/* FIXME: This could be speeded up slightly if the hash lists were
* kept sorted on weak_sum. */
while (n && ( (n->sum_weak != weak)
|| memcmp(n->sum_md5, digest, RSYNC_SUM_LENGTH)))
|| memcmp(n->sum_md5, digest, RSYNC_SUM_SIZE)))
n = n->next;
return n;
......@@ -134,7 +134,7 @@ rsync_lookup_block(struct rsync_send_state *s,
md5_final(&m);
md5_digest(&m, digest);
if (!memcmp(s->guess->sum_md5, digest, RSYNC_SUM_LENGTH))
if (!memcmp(s->guess->sum_md5, digest, RSYNC_SUM_SIZE))
{
/* Correct guess! */
n = s->guess;
......@@ -186,7 +186,7 @@ rsync_lookup_block(struct rsync_send_state *s,
md5_final(&m);
md5_digest(&m, digest);
if (!memcmp(n->sum_md5, digest, RSYNC_SUM_LENGTH))
if (!memcmp(n->sum_md5, digest, RSYNC_SUM_SIZE))
return n;
}
}
......@@ -195,7 +195,7 @@ rsync_lookup_block(struct rsync_send_state *s,
}
int
enum rsync_result_t
rsync_read_table(struct rsync_read_table_state *s,
UINT32 length, UINT8 *input)
{
......@@ -284,14 +284,298 @@ rsync_read_table(struct rsync_read_table_state *s,
}
/* While searching, we have to keep a buffer of previous block of
* data. Our buffer BUF consists of SIZE octets starting at start. The
* currently hashed data starts at position I in the buffer.
* data. Our buffer BUF consists of SIZE octets starting after the header space.
*
* We may have less than one block of data available, in that case we
* must collect more data before we can start searching. If we collect
* more than buf_size (usually twice the block size), we output a
* literal. */
#define BUFFER_HEADER RSYNC_TOKEN_SIZE
#define BUFFER_TRAILER (RSYNC_TOKEN_SIZE + RSYNC_SUM_SIZE)
enum rsync_result_t
rsync_send_init(struct rsync_send_state *s,
struct rsync_table *table)
{
assert(table->block_size <= 0xffffffffU/2);
/* The buffer must be at least twice the block size. */
s->buf_size = table->block_size * 3;
s->table = table;
s->buf = malloc(s->buf_size + BUFFER_HEADER + BUFFER_TRAILER);
if (!s->buf)
return RSYNC_MEMORY;
s->size = 0;
s->sum_a = s->sum_b = 0;
md5_init(&s->sum_md5);
s->state = RSYNC_SEND_READING;
s->final = 0;
return RSYNC_PROGRESS;
}
static void
rsync_send_eof(struct rsync_send_state *s)
{
/* FIXME: Try matching the final block. */
UINT32 end = 0;
/* If buffer is non-empty, add a literal. */
if (s->size)
{
WRITE_UINT32(s->buf, s->size);
end = s->size + 4;
}
/* Write EOF marker */
WRITE_UINT32(s->buf + end, 0);
end += 4;
/* And final hash of the entire file */
md5_final(&s->sum_md5);
md5_digest(&s->sum_md5, s->buf + end);
end += RSYNC_SUM_SIZE;
s->size = 0;
s->i = 0;
s->out_end = end;
s->final = 1;
s->state = RSYNC_SEND_WRITING;
}
/* The start of the input buffer */
#define BUF (s->buf + BUFFER_HEADER)
/* Copy from input buffer, and update md5 sum. */
static void
rsync_send_copy_in(struct rsync_send_state *s,
UINT32 length)
{
assert(length <= s->avail_in);
md5_update(&s->sum_md5, s->next_in, length);
memcpy(BUF + s->size, s->next_in, length);
s->next_in += length;
s->avail_in -= length;
s->size += length;
}
static void
rsync_send_read(struct rsync_send_state *s, UINT32 left)
{
/* The current hash does not include a complete block. We need more data. */
struct rsync_node *n;
UINT32 avail = MIN(left, s->avail_in);
assert(avail);
/* Update weak sum */
rsync_update_1(&s->sum_a, &s->sum_b, avail, s->next_in);
rsync_send_copy_in(s, avail);
if (s->size < s->table->block_size)
return;
/* We have a complete block. Check if we have a match already. */
n = rsync_lookup_block(s, 0, s->size);
if (n)
{
/* We have a match! */
UINT32 token = ~(n - s->table->all_nodes);
WRITE_UINT32(s->buf, token);
s->size = 0;
s->i = 0;
s->out_end = RSYNC_TOKEN_SIZE;
s->state = RSYNC_SEND_WRITING;
}
}
static void
rsync_send_search(struct rsync_send_state *s)
{
UINT32 avail;
UINT32 done;
struct rsync_node *n;
assert(s->size >= s->table->block_size);
assert(s->size < s->buf_size);
avail = MIN(s->avail_in, s->buf_size - s->size);
n = rsync_search(&s->sum_a, &s->sum_b, s->table->block_size,
avail,
BUF + s->size - s->table->block_size,
s->next_in,
&done, s->table->hash);
/* done should be non-zero */
assert(done);
if (n)
{
/* The block
*
* BUF[size + done - block_size...size] + next_in[0...done]
*
* might match */
UINT32 weak = COMBINE_SUM(s->sum_a, s->sum_b);
n = rsync_lookup_1(n, weak);
if (n)
{
struct md5_ctx m;
UINT8 digest[MD5_DIGESTSIZE];
UINT32 start = s->size + done - s->table->block_size;
assert(start);
/* NOTE: Don't bother examining our guess. */
md5_init(&m);
md5_update(&m, BUF + start,
s->table->block_size - done);
md5_update(&m, s->next_in, done);
md5_final(&m);
md5_digest(&m, digest);
n = rsync_lookup_2(n, weak, digest);
if (n)
{
/* Match found! */
/* Token is one-complement of the index */
UINT32 token = ~(n - s->table->all_nodes);
/* Hash input before we discard it */
md5_update(&s->sum_md5, s->next_in, done);
s->next_in += done;
s->avail_in -= done;
/* Length of literal */
WRITE_UINT32(s->buf, start);
/* Block reference, written after the literal data. */
WRITE_UINT32(BUF + start, token);
s->size = 0;
s->i = 0;
s->out_end = start + (2 * RSYNC_TOKEN_SIZE);
s->state = RSYNC_SEND_WRITING;
return;
}
}
}
/* No match so far. Copy the data up to the apparent match, or all
* available if there were no apparent match. */
rsync_send_copy_in(s, done);
}
static void
rsync_send_flush(struct rsync_send_state *s)
{
/* Entire buffer filled, but no match. Make a literal
* out of all but the last block in the buffer */
UINT32 length = s->size - s->table->block_size;
WRITE_UINT32(s->buf, length);
s->size = s->table->block_size;
s->i = 0;
s->out_end = length + RSYNC_TOKEN_SIZE;
s->state = RSYNC_SEND_WRITING;
}
static int
rsync_send_write(struct rsync_send_state *s)
{
/* Trassmits octets between I and OUT_END */
UINT32 left = s->out_end - s->i;
if (left <= s->avail_out)
{
memcpy(s->next_out, s->buf + s->i, left);
s->next_out += left;
s->avail_out -= left;
s->state = RSYNC_SEND_READING;
return 1;
}
else
{
memcpy(s->next_out, s->buf + s->i, s->avail_out);
s->next_out += s->avail_out;
s->i += s->avail_out;
s->avail_out = 0;
return 0;
}
}
enum rsync_result_t
rsync_send(struct rsync_send_state *s, int flush)
{
enum rsync_result_t result = RSYNC_BUF_ERROR;
for (;;)
{
switch (s->state)
{
case RSYNC_SEND_READING:
assert(!s->final);
assert(s->size <= s->buf_size);
if (!s->avail_in)
{
if (!flush)
return result;
rsync_send_eof(s);
continue;
}
if (s->size == s->buf_size)
rsync_send_flush(s);
else
{
result = RSYNC_PROGRESS;
if (s->size < s->table->block_size)
rsync_send_read(s, s->table->block_size - s->size);
else
rsync_send_search(s);
}
break;
case RSYNC_SEND_WRITING:
if (!s->avail_out)
return result;
if (rsync_send_write(s) && s->final)
return RSYNC_DONE;
else
result = RSYNC_PROGRESS;
}
}
}
#if 0
/* When output is generated, one of the following states is entered:
*
* Pending output Data left in the buffer
......@@ -337,29 +621,6 @@ enum rsync_send_mode
};
int
rsync_send_init(struct rsync_send_state *s,
struct rsync_table *table)
{
assert(table->block_size <= 0xffffffffU/2);
/* THe buffer must be at least twice the block size. */
s->buf_size = table->block_size * 3;
s->table = table;
s->buf = malloc(s->buf_size);
if (!s->buf)
return RSYNC_MEMORY;
s->size = 0;
s->sum_a = s->sum_b = 0;
s->state = STATE_INITIAL;
return RSYNC_PROGRESS;
}
#define MIN3(a,b,c) (MIN(MIN((a),(b)),(c)))
#define MIN4(a,b,c,d) (MIN(MIN((a),(b)),MIN((c),(d))))
......@@ -1337,3 +1598,4 @@ int rsync_send(struct rsync_send_state *s, int flush)
}
}
#endif
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment