1
/* ----------------------------------------------------------------------- *
3
* Copyright 2002 Ben Escoto
5
* This file is part of rdiff-backup.
7
* rdiff-backup is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License as
9
* published by the Free Software Foundation, Inc., 675 Mass Ave,
10
* Cambridge MA 02139, USA; either version 2 of the License, or (at
11
* your option) any later version; incorporated herein by reference.
13
* ----------------------------------------------------------------------- */
17
#define RS_JOB_BLOCKSIZE 65536
19
static PyObject *librsyncError;
21
/* Sets python error string from result */
23
_librsync_seterror(rs_result result, char *location)
25
char error_string[200];
26
sprintf(error_string, "librsync error %d while in %s", result, location);
27
PyErr_SetString(librsyncError, error_string);
31
/* --------------- SigMaker Object for incremental signatures */
32
staticforward PyTypeObject _librsync_SigMakerType;
38
} _librsync_SigMakerObject;
41
_librsync_new_sigmaker(PyObject* self, PyObject* args)
43
_librsync_SigMakerObject* sm;
45
if (!PyArg_ParseTuple(args,":new_sigmaker"))
48
sm = PyObject_New(_librsync_SigMakerObject, &_librsync_SigMakerType);
49
if (sm == NULL) return NULL;
52
sm->sig_job = rs_sig_begin((size_t)RS_DEFAULT_BLOCK_LEN,
53
(size_t)RS_DEFAULT_STRONG_LEN);
58
_librsync_sigmaker_dealloc(PyObject* self)
60
rs_job_free(((_librsync_SigMakerObject *)self)->sig_job);
64
/* Take an input string, and generate a signature from it. The output
65
will be a triple (done, bytes_used, signature_string), where done
66
is true iff there is no more data coming and bytes_used is the
67
number of bytes of the input string processed.
70
_librsync_sigmaker_cycle(_librsync_SigMakerObject *self, PyObject *args)
72
char *inbuf, outbuf[RS_JOB_BLOCKSIZE];
77
if (!PyArg_ParseTuple(args, "s#:cycle", &inbuf, &inbuf_length))
81
buf.avail_in = (size_t)inbuf_length;
82
buf.next_out = outbuf;
83
buf.avail_out = (size_t)RS_JOB_BLOCKSIZE;
84
buf.eof_in = (inbuf_length == 0);
86
result = rs_job_iter(self->sig_job, &buf);
88
if (result != RS_DONE && result != RS_BLOCKED) {
89
_librsync_seterror(result, "signature cycle");
93
return Py_BuildValue("(ils#)", (result == RS_DONE),
94
inbuf_length - (long)buf.avail_in,
95
outbuf, RS_JOB_BLOCKSIZE - (long)buf.avail_out);
98
static PyMethodDef _librsync_sigmaker_methods[] = {
99
{"cycle", (PyCFunction)_librsync_sigmaker_cycle, METH_VARARGS},
100
{NULL, NULL, 0, NULL} /* sentinel */
104
_librsync_sigmaker_getattr(_librsync_SigMakerObject *sm,
107
if (sm->x_attr != NULL) {
108
PyObject *v = PyDict_GetItemString(sm->x_attr, name);
114
return Py_FindMethod(_librsync_sigmaker_methods, (PyObject *)sm, name);
118
_librsync_sigmaker_setattr(_librsync_SigMakerObject *sm,
119
char *name, PyObject *v)
121
if (sm->x_attr == NULL) {
122
sm->x_attr = PyDict_New();
123
if (sm->x_attr == NULL) return -1;
126
int rv = PyDict_DelItemString(sm->x_attr, name);
128
PyErr_SetString(PyExc_AttributeError,
129
"delete non-existing sigmaker attribute");
132
else return PyDict_SetItemString(sm->x_attr, name, v);
135
static PyTypeObject _librsync_SigMakerType = {
136
PyObject_HEAD_INIT(NULL)
139
sizeof(_librsync_SigMakerObject),
141
_librsync_sigmaker_dealloc, /*tp_dealloc*/
143
(getattrfunc)_librsync_sigmaker_getattr, /*tp_getattr*/
144
(setattrfunc)_librsync_sigmaker_setattr, /*tp_setattr*/
148
0, /*tp_as_sequence*/
154
/* --------------- DeltaMaker Object for incremental deltas */
156
staticforward PyTypeObject _librsync_DeltaMakerType;
162
rs_signature_t *sig_ptr;
163
} _librsync_DeltaMakerObject;
165
/* Call with the entire signature loaded into one big string */
167
_librsync_new_deltamaker(PyObject* self, PyObject* args)
169
_librsync_DeltaMakerObject* dm;
170
char *sig_string, outbuf[RS_JOB_BLOCKSIZE];
172
rs_job_t *sig_loader;
173
rs_signature_t *sig_ptr;
177
if (!PyArg_ParseTuple(args,"s#:new_deltamaker", &sig_string, &sig_length))
180
dm = PyObject_New(_librsync_DeltaMakerObject, &_librsync_DeltaMakerType);
181
if (dm == NULL) return NULL;
184
/* Put signature at sig_ptr and build hash */
185
sig_loader = rs_loadsig_begin(&sig_ptr);
186
buf.next_in = sig_string;
187
buf.avail_in = (size_t)sig_length;
188
buf.next_out = outbuf;
189
buf.avail_out = (size_t)RS_JOB_BLOCKSIZE;
191
result = rs_job_iter(sig_loader, &buf);
192
rs_job_free(sig_loader);
193
if (result != RS_DONE) {
194
_librsync_seterror(result, "delta rs_signature_t builder");
197
if ((result = rs_build_hash_table(sig_ptr)) != RS_DONE) {
198
_librsync_seterror(result, "delta rs_build_hash_table");
202
dm->sig_ptr = sig_ptr;
203
dm->delta_job = rs_delta_begin(sig_ptr);
204
return (PyObject*)dm;
208
_librsync_deltamaker_dealloc(PyObject* self)
210
_librsync_DeltaMakerObject *dm = (_librsync_DeltaMakerObject *)self;
211
rs_signature_t *sig_ptr = dm->sig_ptr;
213
rs_free_sumset(sig_ptr);
214
rs_job_free(dm->delta_job);
218
/* Take a chunk of the new file in an input string, and return a
219
triple (done bytes_used, delta_string), where done is true iff no
220
more data is coming and bytes_used is the number of bytes of the
221
input string processed.
224
_librsync_deltamaker_cycle(_librsync_DeltaMakerObject *self, PyObject *args)
226
char *inbuf, outbuf[RS_JOB_BLOCKSIZE];
231
if (!PyArg_ParseTuple(args, "s#:cycle", &inbuf, &inbuf_length))
235
buf.avail_in = (size_t)inbuf_length;
236
buf.next_out = outbuf;
237
buf.avail_out = (size_t)RS_JOB_BLOCKSIZE;
238
buf.eof_in = (inbuf_length == 0);
240
result = rs_job_iter(self->delta_job, &buf);
241
if (result != RS_DONE && result != RS_BLOCKED) {
242
_librsync_seterror(result, "delta cycle");
246
return Py_BuildValue("(ils#)", (result == RS_DONE),
247
inbuf_length - (long)buf.avail_in,
248
outbuf, RS_JOB_BLOCKSIZE - (long)buf.avail_out);
251
static PyMethodDef _librsync_deltamaker_methods[] = {
252
{"cycle", (PyCFunction)_librsync_deltamaker_cycle, METH_VARARGS},
253
{NULL, NULL, 0, NULL} /* sentinel */
257
_librsync_deltamaker_getattr(_librsync_DeltaMakerObject *dm, char *name)
259
if (dm->x_attr != NULL) {
260
PyObject *v = PyDict_GetItemString(dm->x_attr, name);
266
return Py_FindMethod(_librsync_deltamaker_methods, (PyObject *)dm, name);
270
_librsync_deltamaker_setattr(_librsync_DeltaMakerObject *dm,
271
char *name, PyObject *v)
273
if (dm->x_attr == NULL) {
274
dm->x_attr = PyDict_New();
275
if (dm->x_attr == NULL) return -1;
278
int rv = PyDict_DelItemString(dm->x_attr, name);
280
PyErr_SetString(PyExc_AttributeError,
281
"delete non-existing deltamaker attribute");
284
else return PyDict_SetItemString(dm->x_attr, name, v);
287
static PyTypeObject _librsync_DeltaMakerType = {
288
PyObject_HEAD_INIT(NULL)
291
sizeof(_librsync_DeltaMakerObject),
293
_librsync_deltamaker_dealloc, /*tp_dealloc*/
295
(getattrfunc)_librsync_deltamaker_getattr, /*tp_getattr*/
296
(setattrfunc)_librsync_deltamaker_setattr, /*tp_setattr*/
300
0, /*tp_as_sequence*/
306
/* --------------- PatchMaker Object for incremental patching */
309
staticforward PyTypeObject _librsync_PatchMakerType;
315
PyObject *basis_file;
316
} _librsync_PatchMakerObject;
318
/* Call with the basis file */
320
_librsync_new_patchmaker(PyObject* self, PyObject* args)
322
_librsync_PatchMakerObject* pm;
323
PyObject *python_file;
326
if (!PyArg_ParseTuple(args, "O:new_patchmaker", &python_file))
328
if (!PyFile_Check(python_file)) {
329
PyErr_SetString(PyExc_TypeError, "Need true file object");
332
Py_INCREF(python_file);
334
pm = PyObject_New(_librsync_PatchMakerObject, &_librsync_PatchMakerType);
335
if (pm == NULL) return NULL;
338
pm->basis_file = python_file;
339
cfile = PyFile_AsFile(python_file);
340
pm->patch_job = rs_patch_begin(rs_file_copy_cb, cfile);
342
return (PyObject*)pm;
346
_librsync_patchmaker_dealloc(PyObject* self)
348
_librsync_PatchMakerObject *pm = (_librsync_PatchMakerObject *)self;
349
Py_DECREF(pm->basis_file);
350
rs_job_free(pm->patch_job);
354
/* Take a chunk of the delta file in an input string, and return a
355
triple (done, bytes_used, patched_string), where done is true iff
356
there is no more data coming out and bytes_used is the number of
357
bytes of the input string processed.
360
_librsync_patchmaker_cycle(_librsync_PatchMakerObject *self, PyObject *args)
362
char *inbuf, outbuf[RS_JOB_BLOCKSIZE];
367
if (!PyArg_ParseTuple(args, "s#:cycle", &inbuf, &inbuf_length))
371
buf.avail_in = (size_t)inbuf_length;
372
buf.next_out = outbuf;
373
buf.avail_out = (size_t)RS_JOB_BLOCKSIZE;
374
buf.eof_in = (inbuf_length == 0);
376
result = rs_job_iter(self->patch_job, &buf);
377
if (result != RS_DONE && result != RS_BLOCKED) {
378
_librsync_seterror(result, "patch cycle");
382
return Py_BuildValue("(ils#)", (result == RS_DONE),
383
inbuf_length - (long)buf.avail_in,
384
outbuf, RS_JOB_BLOCKSIZE - (long)buf.avail_out);
387
static PyMethodDef _librsync_patchmaker_methods[] = {
388
{"cycle", (PyCFunction)_librsync_patchmaker_cycle, METH_VARARGS},
389
{NULL, NULL, 0, NULL} /* sentinel */
393
_librsync_patchmaker_getattr(_librsync_PatchMakerObject *pm, char *name)
395
if (pm->x_attr != NULL) {
396
PyObject *v = PyDict_GetItemString(pm->x_attr, name);
402
return Py_FindMethod(_librsync_patchmaker_methods, (PyObject *)pm, name);
406
_librsync_patchmaker_setattr(_librsync_PatchMakerObject *pm,
407
char *name, PyObject *v)
409
if (pm->x_attr == NULL) {
410
pm->x_attr = PyDict_New();
411
if (pm->x_attr == NULL) return -1;
414
int rv = PyDict_DelItemString(pm->x_attr, name);
416
PyErr_SetString(PyExc_AttributeError,
417
"delete non-existing patchmaker attribute");
420
else return PyDict_SetItemString(pm->x_attr, name, v);
423
static PyTypeObject _librsync_PatchMakerType = {
424
PyObject_HEAD_INIT(NULL)
427
sizeof(_librsync_PatchMakerObject),
429
_librsync_patchmaker_dealloc, /*tp_dealloc*/
431
(getattrfunc)_librsync_patchmaker_getattr, /*tp_getattr*/
432
(setattrfunc)_librsync_patchmaker_setattr, /*tp_setattr*/
436
0, /*tp_as_sequence*/
442
/* --------------- _librsync module definition */
444
static PyMethodDef _librsyncMethods[] = {
445
{"new_sigmaker", _librsync_new_sigmaker, METH_VARARGS,
446
"Return a sigmaker object, for finding the signature of an object"},
447
{"new_deltamaker", _librsync_new_deltamaker, METH_VARARGS,
448
"Return a deltamaker object, for computing deltas"},
449
{"new_patchmaker", _librsync_new_patchmaker, METH_VARARGS,
450
"Return a patchmaker object, for patching basis files"},
451
{NULL, NULL, 0, NULL}
454
void init_librsync(void)
458
_librsync_SigMakerType.ob_type = &PyType_Type;
459
_librsync_DeltaMakerType.ob_type = &PyType_Type;
460
m = Py_InitModule("_librsync", _librsyncMethods);
461
d = PyModule_GetDict(m);
462
librsyncError = PyErr_NewException("_librsync.librsyncError", NULL, NULL);
463
PyDict_SetItemString(d, "librsyncError", librsyncError);
464
PyDict_SetItemString(d, "RS_JOB_BLOCKSIZE",
465
Py_BuildValue("l", (long)RS_JOB_BLOCKSIZE));
466
PyDict_SetItemString(d, "RS_DEFAULT_BLOCK_LEN",
467
Py_BuildValue("l", (long)RS_DEFAULT_BLOCK_LEN));