/** * \brief Apply a \ref gloss_delta to a \ref gloss_basis to recreate * the new file. * * This gives you back a ::rs_job_t object, which can be cranked by * calling rs_job_iter() and updating the stream pointers. When * finished, call rs_job_finish() to dispose of it. * * \param stream Contains pointers to input and output buffers, to be * adjusted by caller on each iteration. * * \param copy_cb Callback used to retrieve content from the basis * file. * * \param copy_arg Opaque environment pointer passed through to the * callback. * * \todo As output is produced, accumulate the MD4 checksum of the * output. Then if we find a CHECKSUM command we can check it's * contents against the output. * * \todo Implement COPY commands. * * \sa rs_patch_file() */ rs_job_t * rs_patch_begin(rs_copy_cb *copy_cb, void *copy_arg) { rs_job_t *job = rs_job_new("patch", rs_patch_s_header); job->copy_cb = copy_cb; job->copy_arg = copy_arg; rs_mdfour_begin(&job->output_md4); return job; }
void DLL_EXPORT get_file_digest (file_reader & reader , uchar_t digest[DIGEST_BYTES]) { const int buf_len = XDELTA_BUFFER_LEN; // four times of block. char_buffer <uchar_t> buf (XDELTA_BUFFER_LEN); rs_mdfour_t ctx; rs_mdfour_begin(&ctx); while (true) { int size = reader.read_file (buf.begin (), buf_len); if (size <= 0) break; rs_mdfour_update(&ctx, buf.begin (), size); } rs_mdfour_result (&ctx, digest); }
int32_t multiround_hash_table::_haser_first_round (file_reader & reader , hasher_stream & stream , std::set<hole_t> & holes) const { if (!holes.empty ()) { std::string errmsg = fmt_string ("Holes must be empty."); THROW_XDELTA_EXCEPTION (errmsg); } hole_t hole; hole.offset = 0; bool round = true; try { reader.open_file (); // sometimes this will throw. hole.length = reader.get_file_size (); holes.insert (hole); } catch (...) { round = false; } if (!round) { hash_table::hash_it (reader, stream); return -1; } int32_t blk_len = (uint32_t)(hole.length / multiround_base ()); if (blk_len > MULTIROUND_MAX_BLOCK_SIZE) blk_len = MULTIROUND_MAX_BLOCK_SIZE; if (blk_len < XDELTA_BLOCK_SIZE) blk_len = XDELTA_BLOCK_SIZE; stream.start_hash_stream (reader.get_fname (), blk_len); rs_mdfour_t ctx; rs_mdfour_begin(&ctx); read_and_hash (reader, stream, hole.length, blk_len, hole.offset, &ctx); uchar_t file_hash[DIGEST_BYTES]; memset (&file_hash, 0, sizeof (file_hash)); rs_mdfour_result (&ctx, file_hash); bool neednextround = stream.end_first_round (file_hash); return (neednextround ? blk_len : -1); }
// // used the hash_table object receive from remote host // and send a hash stream to the remote host. // void hash_table::hash_it (file_reader & reader, hasher_stream & stream) const { rs_mdfour_t ctx; rs_mdfour_begin(&ctx); uint64_t filsize = 0; try { int32_t f_blk_len = 0; if (reader.exist_file ()) { try { reader.open_file (); // sometimes this will throw. filsize = reader.get_file_size (); f_blk_len = get_xdelta_block_size (filsize); } catch (...) { stream.start_hash_stream (reader.get_fname (), 0); throw; } stream.start_hash_stream (reader.get_fname (), f_blk_len); } else { std::string mesg = fmt_string ("File %s not exists." , reader.get_fname ().c_str ()); stream.start_hash_stream (reader.get_fname (), 0); stream.on_error (mesg, ENOENT); goto end; } read_and_hash (reader, stream, filsize, f_blk_len, 0, &ctx); } catch (xdelta_exception &e) { stream.on_error (e.what (), e.get_errno ()); } end: uchar_t file_hash[DIGEST_BYTES]; memset (file_hash, 0, sizeof (file_hash)); rs_mdfour_result (&ctx, file_hash); reader.close_file (); stream.end_hash_stream (file_hash, filsize); return; }