156 lines
4.4 KiB
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;
|
|
}
|