summaryrefslogtreecommitdiff
path: root/rsync/mksum.c
Side-by-side diff
Diffstat (limited to 'rsync/mksum.c') (more/less context) (ignore whitespace changes)
-rw-r--r--rsync/mksum.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/rsync/mksum.c b/rsync/mksum.c
new file mode 100644
index 0000000..d55bcfb
--- a/dev/null
+++ b/rsync/mksum.c
@@ -0,0 +1,155 @@
+/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
+ *
+ * librsync -- library for network deltas
+ * $Id$
+ *
+ * Copyright (C) 1999, 2000, 2001 by Martin Pool <mbp@samba.org>
+ * Copyright (C) 1999 by Andrew Tridgell <tridge@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * mksum.c -- Generate file signatures.
+ *
+ * Generating checksums is pretty easy, since we can always just
+ * process whatever data is available. When a whole block has
+ * arrived, or we've reached the end of the file, we write the
+ * checksum out.
+ */
+
+/* TODO: Perhaps force blocks to be a multiple of 64 bytes, so that we
+ * can be sure checksum generation will be more efficient. I guess it
+ * will be OK at the moment, though, because tails are only used if
+ * necessary. */
+
+#include <config_rsync.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "rsync.h"
+#include "stream.h"
+#include "util.h"
+#include "sumset.h"
+#include "job.h"
+#include "protocol.h"
+#include "netint.h"
+#include "trace.h"
+#include "checksum.h"
+
+
+/* Possible state functions for signature generation. */
+static rs_result rs_sig_s_header(rs_job_t *);
+static rs_result rs_sig_s_generate(rs_job_t *);
+
+
+
+/**
+ * State of trying to send the signature header.
+ */
+static rs_result rs_sig_s_header(rs_job_t *job)
+{
+ rs_squirt_n4(job, RS_SIG_MAGIC);
+ rs_squirt_n4(job, job->block_len);
+ rs_squirt_n4(job, job->strong_sum_len);
+ rs_trace("sent header (magic %#x, block len = %d, strong sum len = %d)",
+ RS_SIG_MAGIC, (int) job->block_len, (int) job->strong_sum_len);
+ job->stats.block_len = job->block_len;
+
+ job->statefn = rs_sig_s_generate;
+ return RS_RUNNING;
+}
+
+
+/**
+ * Generate the checksums for a block and write it out. Called when
+ * we already know we have enough data in memory at \p block.
+ */
+static rs_result
+rs_sig_do_block(rs_job_t *job, const void *block, size_t len)
+{
+ unsigned int weak_sum;
+ rs_strong_sum_t strong_sum;
+
+ weak_sum = rs_calc_weak_sum(block, len);
+
+ rs_calc_strong_sum(block, len, &strong_sum);
+
+ rs_squirt_n4(job, weak_sum);
+ rs_tube_write(job, strong_sum, job->strong_sum_len);
+
+ if (rs_trace_enabled()) {
+ char strong_sum_hex[RS_MD4_LENGTH * 2 + 1];
+ rs_hexify(strong_sum_hex, strong_sum, job->strong_sum_len);
+ rs_trace("sent weak sum 0x%08x and strong sum %s", weak_sum,
+ strong_sum_hex);
+ }
+
+ job->stats.sig_blocks++;
+
+ return RS_RUNNING;
+}
+
+
+/*
+ * State of reading a block and trying to generate its sum.
+ */
+static rs_result
+rs_sig_s_generate(rs_job_t *job)
+{
+ rs_result result;
+ size_t len;
+ void *block;
+
+ /* must get a whole block, otherwise try again */
+ len = job->block_len;
+ result = rs_scoop_read(job, len, &block);
+
+ /* unless we're near eof, in which case we'll accept
+ * whatever's in there */
+ if ((result == RS_BLOCKED && rs_job_input_is_ending(job))) {
+ result = rs_scoop_read_rest(job, &len, &block);
+ } else if (result == RS_INPUT_ENDED) {
+ return RS_DONE;
+ } else if (result != RS_DONE) {
+ rs_trace("generate stopped: %s", rs_strerror(result));
+ return result;
+ }
+
+ rs_trace("got %d byte block", len);
+
+ return rs_sig_do_block(job, block, len);
+}
+
+
+/** \brief Set up a new encoding job.
+ *
+ * \sa rs_sig_file()
+ */
+rs_job_t * rs_sig_begin(size_t new_block_len, size_t strong_sum_len)
+{
+ rs_job_t *job;
+
+ job = rs_job_new("signature", rs_sig_s_header);
+ job->block_len = new_block_len;
+
+ assert(strong_sum_len > 0 && strong_sum_len <= RS_MD4_LENGTH);
+ job->strong_sum_len = strong_sum_len;
+
+ return job;
+}