callback-based interface
Martin Pool <[email protected]> Thu, 8 Apr 2004 12:55:55 +1000
| Newsgroups | gmane.network.librsync.devel |
|---|---|
| Message-ID | <[email protected]> |
--Signature=_Thu__8_Apr_2004_12_55_55_+1000_yv/UZCSVG7cPH3=i Content-Type: multipart/mixed; boundary="Multipart=_Thu__8_Apr_2004_12_55_55_+1000_4U5WNa/J7.MM0mnf" --Multipart=_Thu__8_Apr_2004_12_55_55_+1000_4U5WNa/J7.MM0mnf Content-Type: text/plain; charset=US-ASCII Content-Disposition: inline Content-Transfer-Encoding: 7bit I have done a bit of work on changing librsync to use only callbacks to move data in and out of the library, rather than the rs_buffers in 0.9. I haven't finished the conversion, and I am not yet sure that this is the right way to go. But I am pretty happy with the way this simplifies the interface, documentation and the implementation. I am thinking about switching the interface for a future 0.10 release. -- Martin --Multipart=_Thu__8_Apr_2004_12_55_55_+1000_4U5WNa/J7.MM0mnf Content-Type: text/x-chdr; name="librsync.h" Content-Disposition: attachment; filename="librsync.h" Content-Transfer-Encoding: 7bit /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- * * librsync -- library for network deltas * * Copyright (C) 2000, 2001, 04 by Martin Pool <[email protected]> * Copyright (C) 2003 by Donovan Baarda <[email protected]> * * 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. */ /* | You should never wear your best | trousers when you go out to fight for | freedom and liberty. | -- Henrik Ibsen */ /* librsync.h -- Main public interface to librsync. */ /* TODO: Perhaps make the trace settings per-job? But then how would * callbacks log their information? Probably not justified. */ /* TODO: Perhaps add functions to customize the input and output * buffer sizes. */ #ifndef _RSYNC_H #define _RSYNC_H #ifdef __cplusplus # define BEGIN_C extern "C" { # define END_C } #else # define BEGIN_C # define END_C #endif BEGIN_C /* librsync needs a 64-bit type. By default we'll rely on the C99 * stdint.h file. If there are target systems that don't have that, * we might need to try something else. */ #include <sys/types.h> #include <stdint.h> typedef uint64_t rs_long_t; extern char const *rs_librsync_version; extern char const *rs_licence_string; struct rs_job; typedef struct rs_job rs_job_t; /* Length in bytes of MD4 hash. This is a good default for the strong * sum length. */ #define RS_MD4_LENGTH 16 /** * \brief Log severity levels. * * These are the same as syslog, at least in glibc. * * \sa rs_trace_set_level() */ typedef enum { RS_LOG_EMERG = 0, /**< System is unusable */ RS_LOG_ALERT = 1, /**< Action must be taken immediately */ RS_LOG_CRIT = 2, /**< Critical conditions */ RS_LOG_ERR = 3, /**< Error conditions */ RS_LOG_WARNING = 4, /**< Warning conditions */ RS_LOG_NOTICE = 5, /**< Normal but significant condition */ RS_LOG_INFO = 6, /**< Informational */ RS_LOG_DEBUG = 7 /**< Debug-level messages */ } rs_loglevel; /** * \typedef rs_trace_fn_t * \brief Callback to write out log messages. * \param level a syslog level. * \param msg message to be logged. */ typedef void rs_trace_fn_t(int level, char const *msg); void rs_trace_set_level(rs_loglevel level); /** Set trace callback. */ void rs_trace_to(rs_trace_fn_t *); /** Default trace callback that writes to stderr. Implements * ::rs_trace_fn_t, and may be passed to rs_trace_to(). */ void rs_trace_stderr(int level, char const *msg); /** Check whether the library was compiled with debugging trace * suport. */ int rs_supports_trace(void); /** * Convert FROM_LEN bytes at FROM_BUF into a hex representation in * TO_BUF, which must be twice as long plus one byte for the null * terminator. */ void rs_hexify(char *to_buf, void const *from_buf, int from_len); /** * Decode a base64 buffer in place. \return the number of binary * bytes. */ size_t rs_unbase64(char *s); /** * Encode a buffer as base64. */ void rs_base64(unsigned char const *buf, int n, char *out); /** * \brief Return codes from nonblocking rsync operations. */ typedef enum { RS_DONE = 0, /**< Completed successfully. */ RS_BLOCKED = 1, /**< Blocked waiting for more data. */ RS_RUNNING = 2, /**< Not yet finished or blocked. * This value should never be returned * to the caller. */ /* 77 matches the value used in autoconf tests. Maybe it has some * other significance? */ RS_TEST_SKIPPED = 77, /**< Test neither passed or failed. */ RS_IO_ERROR = 100, /**< Error in file or network IO. */ RS_SYNTAX_ERROR = 101, /**< Command line syntax error. */ RS_MEM_ERROR = 102, /**< Out of memory. */ RS_INPUT_ENDED = 103, /**< End of input file, possibly unexpected. */ RS_BAD_MAGIC = 104, /**< Bad magic number at start of stream. Probably not a librsync file, or possibly the wrong kind of file or from an incompatible library version. */ RS_UNIMPLEMENTED = 105, /**< Author is lazy. */ RS_CORRUPT = 106, /**< Unbelievable value in stream. */ RS_INTERNAL_ERROR = 107, /**< Probably a library bug. */ RS_PARAM_ERROR = 108, /**< Bad value passed in to library, * probably an application bug. */ RS_EOF = 109 } rs_result; typedef rs_result rs_result_t; /* FIXME: Pick either 'rs_result' or 'rs_result_t' */ /* Return a brief English description of an rs_result, such as "IO error". */ char const *rs_strerror(rs_result); /* Return the symbolic name for a result */ const char *rs_result_str(rs_result); /** * \brief Performance statistics from a librsync encoding or decoding * operation. * * \sa rs_format_stats(), rs_log_stats() */ typedef struct rs_stats { char const *op; /**< Human-readable name of current * operation. For example, "delta". */ int lit_cmds; /**< Number of literal commands. */ rs_long_t lit_bytes; /**< Number of literal bytes. */ rs_long_t lit_cmdbytes; /**< Number of bytes used in literal * command headers. */ rs_long_t copy_cmds, copy_bytes, copy_cmdbytes; rs_long_t sig_cmds, sig_bytes; int false_matches; rs_long_t sig_blocks; /**< Number of blocks described by the signature. */ size_t block_len; rs_long_t in_bytes; /**< Total bytes read from input. */ rs_long_t out_bytes; /**< Total bytes written to output. */ } rs_stats_t; int rs_log_stats(rs_stats_t const *stats); typedef struct rs_signature rs_signature_t; void rs_free_sumset(rs_signature_t *); void rs_sumset_dump(rs_signature_t const *); /* Callback types for doing IO. These can return RS_DONE on success, * RS_BLOCKED if they cannot proceed at the moment, or an error code. * If they return an error, the overall operation fails. If they * return RS_BLOCKED, then the operation is suspended and it can be * retried later. * * If the read routines have hit EOF, they return RS_EOF. * * These callbacks write data into or read data from a buffer provided * by librsync. Obviously they must never write past the end of the * buffer or try other such tricks. * * The callbacks *may* decline to process the whole buffer. That is, * reads can return before completely filling the buffer, and writes * need not accept all the output data. Callbacks ought to make * progress if they can, but they do not need to double-copy data into * their own buffer. If they cannot handle it when they're called, it * is OK to just leave it there. * * In general the callback interface is a lot like way Unix IO works * on sockets. * * The first parameter is an opaque pointer for the use of the * callback. Typically this is a pointer to a file descriptor or some * similar context. */ typedef rs_result rs_cb_read(void *, char *buf, size_t buf_len, size_t *bytes_read); typedef rs_result rs_cb_pread(void *, char *buf, size_t buf_len, off_t offset, size_t *bytes_read); typedef rs_result rs_cb_write(void *, const char *buf, size_t buf_len, size_t *bytes_written); /* The top-level operation: calculate a signature, load a signature, * calculate a delta, apply a delta. * * These functions just set up the job. To actually do the work, call * rs_job_iter. * * All these take callbacks which they use to do IO. */ rs_result rs_sig_begin(rs_job_t **, size_t block_len, size_t strong_sum_len); rs_result rs_loadsig_begin(rs_job_t **, rs_signature_t **); rs_result rs_delta_begin(rs_job_t **, const rs_signature_t *); rs_result rs_patch_begin(rs_job_t **); /* Set the callbacks to be used for an operation. */ rs_result rs_job_set_input(rs_job_t *, rs_cb_read *, void *); rs_result rs_job_set_output(rs_job_t *, rs_cb_write *, void *); /* TODO: Perhaps set the IO routines somewhere else, rather than * duplicating them in all these parameters? */ /* TODO: Make an MD4 calculator that works similarly? */ /* The IO callbacks will be called any number of times, until the * input returns EOF and everything has been written out. (Or until * an error occurs.) If the callbacks block, this function will also * return RS_BLOCKED. When you think there will be more input * available or more output space (e.g. after select() returns), call * rs_job_iter again. * * When done, call rs_job_free(). */ rs_result_t rs_job_run(rs_job_t *); const rs_stats_t * rs_job_statistics(rs_job_t *job); rs_result_t rs_job_free(rs_job_t *); int rs_accum_value(rs_job_t *, char *sum, size_t sum_len); #ifndef RSYNC_NO_STDIO_INTERFACE /* * Buffer sizes for file IO. * * You probably only need to change these in testing. */ extern int rs_inbuflen, rs_outbuflen; #include <stdio.h> rs_result rs_mdfour_file(FILE *in_file, char *result); rs_result rs_sig_file(FILE *old_file, FILE *sig_file, size_t block_len, size_t strong_len, rs_stats_t *); rs_result rs_loadsig_file(FILE *, rs_signature_t **, rs_stats_t *); rs_result rs_file_copy_cb(void *arg, rs_long_t pos, size_t *len, void **buf); rs_result rs_delta_file(rs_signature_t *, FILE *new_file, FILE *delta_file, rs_stats_t *); rs_result rs_patch_file(FILE *basis_file, FILE *delta_file, FILE *new_file, rs_stats_t *); /* IO callbacks using stdio */ rs_cb_read rs_cb_read_stdio; rs_cb_write rs_cb_write_stdio; rs_cb_pread rs_cb_pread_stdio; #endif /* ! RSYNC_NO_STDIO_INTERFACE */ /* ====================================================================== * * Unix-style IO callbacks. * * These map into calls to read(2), write(2), etc. */ rs_cb_read rs_cb_read_uio; rs_cb_write rs_cb_write_uio; rs_cb_pread rs_cb_pread_uio; rs_result rs_uio_open(const char *file, int mode, int *fd_out); END_C #endif /* ! _RSYNC_H */ --Multipart=_Thu__8_Apr_2004_12_55_55_+1000_4U5WNa/J7.MM0mnf-- --Signature=_Thu__8_Apr_2004_12_55_55_+1000_yv/UZCSVG7cPH3=i Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (GNU/Linux) iD8DBQFAdL87PGPKP6Cz6IsRAhaxAJ0eT+zSF9/56ffzo6W3d5uDYewv2ACgyI/W NhWCAY8FWb7tN/sTEf0KYu0= =/bBD -----END PGP SIGNATURE----- --Signature=_Thu__8_Apr_2004_12_55_55_+1000_yv/UZCSVG7cPH3=i-- ------------------------------------------------------- This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click