Fix Werrors with GCC-14.1.0
[platform/upstream/rpm.git] / python / rpmarchive-py.c
1 #include "rpmsystem-py.h"
2
3 #include <rpm/rpmtypes.h>
4 #include <rpm/rpmpgp.h>
5
6 #include "header-py.h"
7 #include "rpmfi-py.h"
8 #include "rpmfd-py.h"
9 #include "rpmfiles-py.h"
10 #include "rpmarchive-py.h"
11 #include "rpmstrpool-py.h"
12
13 struct rpmarchiveObject_s {
14     PyObject_HEAD
15     PyObject *md_dict;
16     rpmfi archive;
17     rpmfiles files;
18 };
19
20 static void rpmarchive_dealloc(rpmarchiveObject * s)
21 {
22     rpmfilesFree(s->files);
23     rpmfiArchiveClose(s->archive);
24     rpmfiFree(s->archive);
25     Py_TYPE(s)->tp_free((PyObject *)s);
26 }
27
28 static PyObject *rpmarchive_error(int rc)
29 {
30     PyErr_SetObject(PyExc_IOError,
31                     Py_BuildValue("(is)", rc, rpmfileStrerror(rc)));
32     return NULL;
33 }
34
35 static PyObject *rpmarchive_closed(void)
36 {
37     PyErr_SetString(PyExc_IOError, "I/O operation on closed archive");
38     return NULL;
39 }
40
41 static PyObject *rpmarchive_tell(rpmarchiveObject *s)
42 {
43     return PyLong_FromLongLong(rpmfiArchiveTell(s->archive));
44 }
45
46 static PyObject *rpmarchive_close(rpmarchiveObject *s)
47 {
48     if (s->archive) {
49         int rc = rpmfiArchiveClose(s->archive);
50         s->archive = rpmfiFree(s->archive);
51         if (rc)
52             return rpmarchive_error(rc);
53     }
54     Py_RETURN_NONE;
55 }
56
57 static PyObject *rpmarchive_has_content(rpmarchiveObject *s)
58 {
59     return PyLong_FromLong(rpmfiArchiveHasContent(s->archive));
60 }
61
62 static PyObject *rpmarchive_read(rpmarchiveObject *s,
63                                  PyObject *args, PyObject *kwds)
64 {
65     char *kwlist[] = { "size", NULL };
66     char buf[BUFSIZ];
67     ssize_t chunksize = sizeof(buf);
68     ssize_t left = -1;
69     ssize_t nb = 0;
70     PyObject *res = NULL;
71     
72     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", kwlist, &left))
73         return NULL;
74
75     if (s->archive == NULL)
76         return rpmarchive_closed();
77
78     /* ConcatAndDel() doesn't work on NULL string, meh */
79     res = PyBytes_FromStringAndSize(NULL, 0);
80     do {
81         if (left >= 0 && left < chunksize)
82             chunksize = left;
83
84         Py_BEGIN_ALLOW_THREADS 
85         nb = rpmfiArchiveRead(s->archive, buf, chunksize);
86         Py_END_ALLOW_THREADS 
87
88         if (nb > 0) {
89             PyObject *tmp = PyBytes_FromStringAndSize(buf, nb);
90             PyBytes_ConcatAndDel(&res, tmp);
91             left -= nb;
92         }
93     } while (nb > 0);
94
95     if (nb < 0) {
96         Py_XDECREF(res);
97         return rpmarchive_error(nb);
98     } else {
99         return res;
100     }
101 }
102
103 static PyObject *rpmarchive_write(rpmarchiveObject *s,
104                                  PyObject *args, PyObject *kwds)
105 {
106     const char *buf = NULL;
107     ssize_t size = 0;
108     char *kwlist[] = { "buffer", NULL };
109     ssize_t rc = 0;
110
111     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &buf, &size)) {
112         return NULL;
113     }
114
115     if (s->archive == NULL)
116         return rpmarchive_closed();
117
118     Py_BEGIN_ALLOW_THREADS 
119     rc = rpmfiArchiveWrite(s->archive, buf, size);
120     Py_END_ALLOW_THREADS 
121
122     if (rc < 0)
123         return rpmarchive_error(rc);
124     else
125         return Py_BuildValue("n", rc);
126 }
127
128 static PyObject *rpmarchive_readto(rpmarchiveObject *s,
129                                  PyObject *args, PyObject *kwds)
130 {
131     rpmfdObject *fdo = NULL;
132     int nodigest = 0;
133     int rc;
134     char *kwlist[] = { "fd", "nodigest", NULL };
135
136     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
137                                  rpmfdFromPyObject, &fdo, &nodigest)) {
138         return NULL;
139     }
140
141     if (s->archive == NULL)
142         return rpmarchive_closed();
143
144     Py_BEGIN_ALLOW_THREADS
145     rc = rpmfiArchiveReadToFile(s->archive, rpmfdGetFd(fdo), nodigest);
146     Py_END_ALLOW_THREADS
147
148     if (rc)
149         return rpmarchive_error(rc);
150     
151     Py_RETURN_NONE;
152 }
153
154 static PyObject *rpmarchive_writeto(rpmarchiveObject *s,
155                                  PyObject *args, PyObject *kwds)
156 {
157     rpmfdObject *fdo = NULL;
158     int rc;
159     char *kwlist[] = { "fd", NULL };
160
161     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
162                                  rpmfdFromPyObject, &fdo)) {
163         return NULL;
164     }
165
166     if (s->archive == NULL)
167         return rpmarchive_closed();
168
169     Py_BEGIN_ALLOW_THREADS
170     rc = rpmfiArchiveWriteFile(s->archive, rpmfdGetFd(fdo));
171     Py_END_ALLOW_THREADS
172
173     if (rc)
174         return rpmarchive_error(rc);
175
176     Py_RETURN_NONE;
177 }
178
179 static struct PyMethodDef rpmarchive_methods[] = {
180     { "tell",   (PyCFunction)rpmarchive_tell,           METH_NOARGS,
181       "archive.tell() -- Return current position in archive." },
182     { "close",  (PyCFunction)rpmarchive_close,          METH_NOARGS,
183       "archive.close() -- Close archive and do final consistency checks."},
184     { "read",   (PyCFunction)rpmarchive_read,   METH_VARARGS|METH_KEYWORDS,
185       "archive.read(size=None) -- Read next size bytes from current file.\n\n"
186       "Returns bytes\n"},
187     { "write",  (PyCFunction)rpmarchive_write,  METH_VARARGS|METH_KEYWORDS,
188       "archive.write(buffer) -- Write buffer to current file." },
189     { "readto", (PyCFunction)rpmarchive_readto, METH_VARARGS|METH_KEYWORDS,
190       "archive.readto(fd, nodigest=None) -- Read content of fd\n"
191       "and write as content of the current file to archive." },
192     { "writeto", (PyCFunction)rpmarchive_writeto,METH_VARARGS|METH_KEYWORDS,
193       "archive.writeto(fd) -- Write content of current file in archive\n to fd." },
194     { "hascontent", (PyCFunction)rpmarchive_has_content, METH_NOARGS,
195       "archive.hascontent() -- Return if current file has a content.\n\n"
196       "Returns false for non regular and all but one of hardlinked files."},
197     { NULL, NULL, 0, NULL }
198 };
199
200 static char rpmarchive_doc[] =
201 "Gives access to the payload of an rpm package.\n\n"
202 "Is returned by .archive() method of an rpm.files instance.\n"
203 "All methods can raise an IOError exception.";
204
205 static PyObject *rpmarchive_iternext(rpmarchiveObject *s)
206 {
207     PyObject *next = NULL;
208     int fx = rpmfiNext(s->archive);
209
210     if (fx >= 0) {
211         next = rpmfile_Wrap(s->files, fx);
212     } else if (fx < -1) {
213         next = rpmarchive_error(fx);
214     } else {
215         /* end of iteration, nothing to do */
216     }
217     
218     return next;
219 }
220
221 PyTypeObject rpmarchive_Type = {
222         PyVarObject_HEAD_INIT(&PyType_Type, 0)
223         "rpm.archive",                  /* tp_name */
224         sizeof(rpmarchiveObject),               /* tp_basicsize */
225         0,                              /* tp_itemsize */
226         (destructor) rpmarchive_dealloc,        /* tp_dealloc */
227         0,                              /* tp_print */
228         0,                              /* tp_getattr */
229         0,                              /* tp_setattr */
230         0,                              /* tp_compare */
231         0,                              /* tp_repr */
232         0,                              /* tp_as_number */
233         0,              /* tp_as_sequence */
234         0,              /* tp_as_mapping */
235         0,                              /* tp_hash */
236         0,                              /* tp_call */
237         0,                              /* tp_str */
238         PyObject_GenericGetAttr,        /* tp_getattro */
239         PyObject_GenericSetAttr,        /* tp_setattro */
240         0,                              /* tp_as_buffer */
241         Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
242         rpmarchive_doc,                 /* tp_doc */
243         0,                              /* tp_traverse */
244         0,                              /* tp_clear */
245         0,                              /* tp_richcompare */
246         0,                              /* tp_weaklistoffset */
247         PyObject_SelfIter,              /* tp_iter */
248         (iternextfunc) rpmarchive_iternext,             /* tp_iternext */
249         rpmarchive_methods,             /* tp_methods */
250         0,                              /* tp_members */
251         0,                              /* tp_getset */
252         0,                              /* tp_base */
253         0,                              /* tp_dict */
254         0,                              /* tp_descr_get */
255         0,                              /* tp_descr_set */
256         0,                              /* tp_dictoffset */
257         0,                              /* tp_init */
258         0,                              /* tp_alloc */
259         0,                              /* tp_new */
260         0,                              /* tp_free */
261         0,                              /* tp_is_gc */
262 };
263
264 PyObject * rpmarchive_Wrap(PyTypeObject *subtype,
265                            rpmfiles files, rpmfi archive)
266 {
267     rpmarchiveObject *s = (rpmarchiveObject *)subtype->tp_alloc(subtype, 0);
268     if (s == NULL) return NULL;
269
270     s->files = rpmfilesLink(files);
271     s->archive = archive;
272
273     return (PyObject *) s;
274 }
275