rpm/librsync/mksum.c

156 lines
4.4 KiB
C

/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*-
*
* librsync -- library for network deltas
* Id: mksum.c,v 1.33 2001/03/18 11:01:01 mbp Exp
*
* 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.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;
}