1 #include "blob.h"
2 #include "util.h"
3 
4 #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
5 #include "clinic/blob.c.h"
6 #undef clinic_state
7 
8 /*[clinic input]
9 module _sqlite3
10 class _sqlite3.Blob "pysqlite_Blob *" "clinic_state()->BlobType"
11 [clinic start generated code]*/
12 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=908d3e16a45f8da7]*/
13 
14 static void
close_blob(pysqlite_Blob * self)15 close_blob(pysqlite_Blob *self)
16 {
17     if (self->blob) {
18         sqlite3_blob *blob = self->blob;
19         self->blob = NULL;
20 
21         Py_BEGIN_ALLOW_THREADS
22         sqlite3_blob_close(blob);
23         Py_END_ALLOW_THREADS
24     }
25 }
26 
27 static int
blob_traverse(pysqlite_Blob * self,visitproc visit,void * arg)28 blob_traverse(pysqlite_Blob *self, visitproc visit, void *arg)
29 {
30     Py_VISIT(Py_TYPE(self));
31     Py_VISIT(self->connection);
32     return 0;
33 }
34 
35 static int
blob_clear(pysqlite_Blob * self)36 blob_clear(pysqlite_Blob *self)
37 {
38     Py_CLEAR(self->connection);
39     return 0;
40 }
41 
42 static void
blob_dealloc(pysqlite_Blob * self)43 blob_dealloc(pysqlite_Blob *self)
44 {
45     PyTypeObject *tp = Py_TYPE(self);
46     PyObject_GC_UnTrack(self);
47 
48     close_blob(self);
49 
50     if (self->in_weakreflist != NULL) {
51         PyObject_ClearWeakRefs((PyObject*)self);
52     }
53     tp->tp_clear((PyObject *)self);
54     tp->tp_free(self);
55     Py_DECREF(tp);
56 }
57 
58 // Return 1 if the blob object is usable, 0 if not.
59 static int
check_blob(pysqlite_Blob * self)60 check_blob(pysqlite_Blob *self)
61 {
62     if (!pysqlite_check_connection(self->connection) ||
63         !pysqlite_check_thread(self->connection)) {
64         return 0;
65     }
66     if (self->blob == NULL) {
67         pysqlite_state *state = self->connection->state;
68         PyErr_SetString(state->ProgrammingError,
69                         "Cannot operate on a closed blob.");
70         return 0;
71     }
72     return 1;
73 }
74 
75 
76 /*[clinic input]
77 _sqlite3.Blob.close as blob_close
78 
79 Close the blob.
80 [clinic start generated code]*/
81 
82 static PyObject *
blob_close_impl(pysqlite_Blob * self)83 blob_close_impl(pysqlite_Blob *self)
84 /*[clinic end generated code: output=848accc20a138d1b input=7bc178a402a40bd8]*/
85 {
86     if (!pysqlite_check_connection(self->connection) ||
87         !pysqlite_check_thread(self->connection))
88     {
89         return NULL;
90     }
91     close_blob(self);
92     Py_RETURN_NONE;
93 };
94 
95 void
pysqlite_close_all_blobs(pysqlite_Connection * self)96 pysqlite_close_all_blobs(pysqlite_Connection *self)
97 {
98     for (int i = 0; i < PyList_GET_SIZE(self->blobs); i++) {
99         PyObject *weakref = PyList_GET_ITEM(self->blobs, i);
100         PyObject *blob = PyWeakref_GetObject(weakref);
101         if (!Py_IsNone(blob)) {
102             close_blob((pysqlite_Blob *)blob);
103         }
104     }
105 }
106 
107 static void
blob_seterror(pysqlite_Blob * self,int rc)108 blob_seterror(pysqlite_Blob *self, int rc)
109 {
110     assert(self->connection != NULL);
111 #if SQLITE_VERSION_NUMBER < 3008008
112     // SQLite pre 3.8.8 does not set this blob error on the connection
113     if (rc == SQLITE_ABORT) {
114         PyErr_SetString(self->connection->OperationalError,
115                         "Cannot operate on an expired blob handle");
116         return;
117     }
118 #endif
119     _pysqlite_seterror(self->connection->state, self->connection->db);
120 }
121 
122 static PyObject *
read_single(pysqlite_Blob * self,Py_ssize_t offset)123 read_single(pysqlite_Blob *self, Py_ssize_t offset)
124 {
125     unsigned char buf = 0;
126     int rc;
127     Py_BEGIN_ALLOW_THREADS
128     rc = sqlite3_blob_read(self->blob, (void *)&buf, 1, (int)offset);
129     Py_END_ALLOW_THREADS
130 
131     if (rc != SQLITE_OK) {
132         blob_seterror(self, rc);
133         return NULL;
134     }
135     return PyLong_FromUnsignedLong((unsigned long)buf);
136 }
137 
138 static PyObject *
read_multiple(pysqlite_Blob * self,Py_ssize_t length,Py_ssize_t offset)139 read_multiple(pysqlite_Blob *self, Py_ssize_t length, Py_ssize_t offset)
140 {
141     assert(length <= sqlite3_blob_bytes(self->blob));
142     assert(offset < sqlite3_blob_bytes(self->blob));
143 
144     PyObject *buffer = PyBytes_FromStringAndSize(NULL, length);
145     if (buffer == NULL) {
146         return NULL;
147     }
148 
149     char *raw_buffer = PyBytes_AS_STRING(buffer);
150     int rc;
151     Py_BEGIN_ALLOW_THREADS
152     rc = sqlite3_blob_read(self->blob, raw_buffer, (int)length, (int)offset);
153     Py_END_ALLOW_THREADS
154 
155     if (rc != SQLITE_OK) {
156         Py_DECREF(buffer);
157         blob_seterror(self, rc);
158         return NULL;
159     }
160     return buffer;
161 }
162 
163 
164 /*[clinic input]
165 _sqlite3.Blob.read as blob_read
166 
167     length: int = -1
168         Read length in bytes.
169     /
170 
171 Read data at the current offset position.
172 
173 If the end of the blob is reached, the data up to end of file will be returned.
174 When length is not specified, or is negative, Blob.read() will read until the
175 end of the blob.
176 [clinic start generated code]*/
177 
178 static PyObject *
blob_read_impl(pysqlite_Blob * self,int length)179 blob_read_impl(pysqlite_Blob *self, int length)
180 /*[clinic end generated code: output=1fc99b2541360dde input=f2e4aa4378837250]*/
181 {
182     if (!check_blob(self)) {
183         return NULL;
184     }
185 
186     /* Make sure we never read past "EOB". Also read the rest of the blob if a
187      * negative length is specified. */
188     int blob_len = sqlite3_blob_bytes(self->blob);
189     int max_read_len = blob_len - self->offset;
190     if (length < 0 || length > max_read_len) {
191         length = max_read_len;
192     }
193 
194     assert(length >= 0);
195     if (length == 0) {
196         return PyBytes_FromStringAndSize(NULL, 0);
197     }
198 
199     PyObject *buffer = read_multiple(self, length, self->offset);
200     if (buffer == NULL) {
201         return NULL;
202     }
203     self->offset += length;
204     return buffer;
205 };
206 
207 static int
inner_write(pysqlite_Blob * self,const void * buf,Py_ssize_t len,Py_ssize_t offset)208 inner_write(pysqlite_Blob *self, const void *buf, Py_ssize_t len,
209             Py_ssize_t offset)
210 {
211     Py_ssize_t blob_len = sqlite3_blob_bytes(self->blob);
212     Py_ssize_t remaining_len = blob_len - offset;
213     if (len > remaining_len) {
214         PyErr_SetString(PyExc_ValueError, "data longer than blob length");
215         return -1;
216     }
217 
218     assert(offset <= blob_len);
219     int rc;
220     Py_BEGIN_ALLOW_THREADS
221     rc = sqlite3_blob_write(self->blob, buf, (int)len, (int)offset);
222     Py_END_ALLOW_THREADS
223 
224     if (rc != SQLITE_OK) {
225         blob_seterror(self, rc);
226         return -1;
227     }
228     return 0;
229 }
230 
231 
232 /*[clinic input]
233 _sqlite3.Blob.write as blob_write
234 
235     data: Py_buffer
236     /
237 
238 Write data at the current offset.
239 
240 This function cannot change the blob length.  Writing beyond the end of the
241 blob will result in an exception being raised.
242 [clinic start generated code]*/
243 
244 static PyObject *
blob_write_impl(pysqlite_Blob * self,Py_buffer * data)245 blob_write_impl(pysqlite_Blob *self, Py_buffer *data)
246 /*[clinic end generated code: output=b34cf22601b570b2 input=a84712f24a028e6d]*/
247 {
248     if (!check_blob(self)) {
249         return NULL;
250     }
251 
252     int rc = inner_write(self, data->buf, data->len, self->offset);
253     if (rc < 0) {
254         return NULL;
255     }
256     self->offset += (int)data->len;
257     Py_RETURN_NONE;
258 }
259 
260 
261 /*[clinic input]
262 _sqlite3.Blob.seek as blob_seek
263 
264     offset: int
265     origin: int = 0
266     /
267 
268 Set the current access position to offset.
269 
270 The origin argument defaults to os.SEEK_SET (absolute blob positioning).
271 Other values for origin are os.SEEK_CUR (seek relative to the current position)
272 and os.SEEK_END (seek relative to the blob's end).
273 [clinic start generated code]*/
274 
275 static PyObject *
blob_seek_impl(pysqlite_Blob * self,int offset,int origin)276 blob_seek_impl(pysqlite_Blob *self, int offset, int origin)
277 /*[clinic end generated code: output=854c5a0e208547a5 input=5da9a07e55fe6bb6]*/
278 {
279     if (!check_blob(self)) {
280         return NULL;
281     }
282 
283     int blob_len = sqlite3_blob_bytes(self->blob);
284     switch (origin) {
285         case SEEK_SET:
286             break;
287         case SEEK_CUR:
288             if (offset > INT_MAX - self->offset) {
289                 goto overflow;
290             }
291             offset += self->offset;
292             break;
293         case SEEK_END:
294             if (offset > INT_MAX - blob_len) {
295                 goto overflow;
296             }
297             offset += blob_len;
298             break;
299         default:
300             PyErr_SetString(PyExc_ValueError,
301                             "'origin' should be os.SEEK_SET, os.SEEK_CUR, or "
302                             "os.SEEK_END");
303             return NULL;
304     }
305 
306     if (offset < 0 || offset > blob_len) {
307         PyErr_SetString(PyExc_ValueError, "offset out of blob range");
308         return NULL;
309     }
310 
311     self->offset = offset;
312     Py_RETURN_NONE;
313 
314 overflow:
315     PyErr_SetString(PyExc_OverflowError, "seek offset results in overflow");
316     return NULL;
317 }
318 
319 
320 /*[clinic input]
321 _sqlite3.Blob.tell as blob_tell
322 
323 Return the current access position for the blob.
324 [clinic start generated code]*/
325 
326 static PyObject *
blob_tell_impl(pysqlite_Blob * self)327 blob_tell_impl(pysqlite_Blob *self)
328 /*[clinic end generated code: output=3d3ba484a90b3a99 input=7e34057aa303612c]*/
329 {
330     if (!check_blob(self)) {
331         return NULL;
332     }
333     return PyLong_FromLong(self->offset);
334 }
335 
336 
337 /*[clinic input]
338 _sqlite3.Blob.__enter__ as blob_enter
339 
340 Blob context manager enter.
341 [clinic start generated code]*/
342 
343 static PyObject *
blob_enter_impl(pysqlite_Blob * self)344 blob_enter_impl(pysqlite_Blob *self)
345 /*[clinic end generated code: output=4fd32484b071a6cd input=fe4842c3c582d5a7]*/
346 {
347     if (!check_blob(self)) {
348         return NULL;
349     }
350     return Py_NewRef(self);
351 }
352 
353 
354 /*[clinic input]
355 _sqlite3.Blob.__exit__ as blob_exit
356 
357     type: object
358     val: object
359     tb: object
360     /
361 
362 Blob context manager exit.
363 [clinic start generated code]*/
364 
365 static PyObject *
blob_exit_impl(pysqlite_Blob * self,PyObject * type,PyObject * val,PyObject * tb)366 blob_exit_impl(pysqlite_Blob *self, PyObject *type, PyObject *val,
367                PyObject *tb)
368 /*[clinic end generated code: output=fc86ceeb2b68c7b2 input=575d9ecea205f35f]*/
369 {
370     if (!check_blob(self)) {
371         return NULL;
372     }
373     close_blob(self);
374     Py_RETURN_FALSE;
375 }
376 
377 static Py_ssize_t
blob_length(pysqlite_Blob * self)378 blob_length(pysqlite_Blob *self)
379 {
380     if (!check_blob(self)) {
381         return -1;
382     }
383     return sqlite3_blob_bytes(self->blob);
384 };
385 
386 static Py_ssize_t
get_subscript_index(pysqlite_Blob * self,PyObject * item)387 get_subscript_index(pysqlite_Blob *self, PyObject *item)
388 {
389     Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
390     if (i == -1 && PyErr_Occurred()) {
391         return -1;
392     }
393     int blob_len = sqlite3_blob_bytes(self->blob);
394     if (i < 0) {
395         i += blob_len;
396     }
397     if (i < 0 || i >= blob_len) {
398         PyErr_SetString(PyExc_IndexError, "Blob index out of range");
399         return -1;
400     }
401     return i;
402 }
403 
404 static PyObject *
subscript_index(pysqlite_Blob * self,PyObject * item)405 subscript_index(pysqlite_Blob *self, PyObject *item)
406 {
407     Py_ssize_t i = get_subscript_index(self, item);
408     if (i < 0) {
409         return NULL;
410     }
411     return read_single(self, i);
412 }
413 
414 static int
get_slice_info(pysqlite_Blob * self,PyObject * item,Py_ssize_t * start,Py_ssize_t * stop,Py_ssize_t * step,Py_ssize_t * slicelen)415 get_slice_info(pysqlite_Blob *self, PyObject *item, Py_ssize_t *start,
416                Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelen)
417 {
418     if (PySlice_Unpack(item, start, stop, step) < 0) {
419         return -1;
420     }
421     int len = sqlite3_blob_bytes(self->blob);
422     *slicelen = PySlice_AdjustIndices(len, start, stop, *step);
423     return 0;
424 }
425 
426 static PyObject *
subscript_slice(pysqlite_Blob * self,PyObject * item)427 subscript_slice(pysqlite_Blob *self, PyObject *item)
428 {
429     Py_ssize_t start, stop, step, len;
430     if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
431         return NULL;
432     }
433 
434     if (step == 1) {
435         return read_multiple(self, len, start);
436     }
437     PyObject *blob = read_multiple(self, stop - start, start);
438     if (blob == NULL) {
439         return NULL;
440     }
441     PyObject *result = PyBytes_FromStringAndSize(NULL, len);
442     if (result != NULL) {
443         char *blob_buf = PyBytes_AS_STRING(blob);
444         char *res_buf = PyBytes_AS_STRING(result);
445         for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
446             res_buf[i] = blob_buf[j];
447         }
448         Py_DECREF(blob);
449     }
450     return result;
451 }
452 
453 static PyObject *
blob_subscript(pysqlite_Blob * self,PyObject * item)454 blob_subscript(pysqlite_Blob *self, PyObject *item)
455 {
456     if (!check_blob(self)) {
457         return NULL;
458     }
459 
460     if (PyIndex_Check(item)) {
461         return subscript_index(self, item);
462     }
463     if (PySlice_Check(item)) {
464         return subscript_slice(self, item);
465     }
466 
467     PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
468     return NULL;
469 }
470 
471 static int
ass_subscript_index(pysqlite_Blob * self,PyObject * item,PyObject * value)472 ass_subscript_index(pysqlite_Blob *self, PyObject *item, PyObject *value)
473 {
474     if (value == NULL) {
475         PyErr_SetString(PyExc_TypeError,
476                         "Blob doesn't support item deletion");
477         return -1;
478     }
479     if (!PyLong_Check(value)) {
480         PyErr_Format(PyExc_TypeError,
481                      "'%s' object cannot be interpreted as an integer",
482                      Py_TYPE(value)->tp_name);
483         return -1;
484     }
485     Py_ssize_t i = get_subscript_index(self, item);
486     if (i < 0) {
487         return -1;
488     }
489 
490     long val = PyLong_AsLong(value);
491     if (val == -1 && PyErr_Occurred()) {
492         PyErr_Clear();
493         val = -1;
494     }
495     if (val < 0 || val > 255) {
496         PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
497         return -1;
498     }
499     // Downcast to avoid endianness problems.
500     unsigned char byte = (unsigned char)val;
501     return inner_write(self, (const void *)&byte, 1, i);
502 }
503 
504 static int
ass_subscript_slice(pysqlite_Blob * self,PyObject * item,PyObject * value)505 ass_subscript_slice(pysqlite_Blob *self, PyObject *item, PyObject *value)
506 {
507     if (value == NULL) {
508         PyErr_SetString(PyExc_TypeError,
509                         "Blob doesn't support slice deletion");
510         return -1;
511     }
512 
513     Py_ssize_t start, stop, step, len;
514     if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
515         return -1;
516     }
517 
518     if (len == 0) {
519         return 0;
520     }
521 
522     Py_buffer vbuf;
523     if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) {
524         return -1;
525     }
526 
527     int rc = -1;
528     if (vbuf.len != len) {
529         PyErr_SetString(PyExc_IndexError,
530                         "Blob slice assignment is wrong size");
531     }
532     else if (step == 1) {
533         rc = inner_write(self, vbuf.buf, len, start);
534     }
535     else {
536         PyObject *blob_bytes = read_multiple(self, stop - start, start);
537         if (blob_bytes != NULL) {
538             char *blob_buf = PyBytes_AS_STRING(blob_bytes);
539             for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
540                 blob_buf[j] = ((char *)vbuf.buf)[i];
541             }
542             rc = inner_write(self, blob_buf, stop - start, start);
543             Py_DECREF(blob_bytes);
544         }
545     }
546     PyBuffer_Release(&vbuf);
547     return rc;
548 }
549 
550 static int
blob_ass_subscript(pysqlite_Blob * self,PyObject * item,PyObject * value)551 blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value)
552 {
553     if (!check_blob(self)) {
554         return -1;
555     }
556 
557     if (PyIndex_Check(item)) {
558         return ass_subscript_index(self, item, value);
559     }
560     if (PySlice_Check(item)) {
561         return ass_subscript_slice(self, item, value);
562     }
563 
564     PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
565     return -1;
566 }
567 
568 
569 static PyMethodDef blob_methods[] = {
570     BLOB_CLOSE_METHODDEF
571     BLOB_ENTER_METHODDEF
572     BLOB_EXIT_METHODDEF
573     BLOB_READ_METHODDEF
574     BLOB_SEEK_METHODDEF
575     BLOB_TELL_METHODDEF
576     BLOB_WRITE_METHODDEF
577     {NULL, NULL}
578 };
579 
580 static struct PyMemberDef blob_members[] = {
581     {"__weaklistoffset__", T_PYSSIZET, offsetof(pysqlite_Blob, in_weakreflist), READONLY},
582     {NULL},
583 };
584 
585 static PyType_Slot blob_slots[] = {
586     {Py_tp_dealloc, blob_dealloc},
587     {Py_tp_traverse, blob_traverse},
588     {Py_tp_clear, blob_clear},
589     {Py_tp_methods, blob_methods},
590     {Py_tp_members, blob_members},
591 
592     // Mapping protocol
593     {Py_mp_length, blob_length},
594     {Py_mp_subscript, blob_subscript},
595     {Py_mp_ass_subscript, blob_ass_subscript},
596     {0, NULL},
597 };
598 
599 static PyType_Spec blob_spec = {
600     .name = MODULE_NAME ".Blob",
601     .basicsize = sizeof(pysqlite_Blob),
602     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
603               Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
604     .slots = blob_slots,
605 };
606 
607 int
pysqlite_blob_setup_types(PyObject * mod)608 pysqlite_blob_setup_types(PyObject *mod)
609 {
610     PyObject *type = PyType_FromModuleAndSpec(mod, &blob_spec, NULL);
611     if (type == NULL) {
612         return -1;
613     }
614     pysqlite_state *state = pysqlite_get_state(mod);
615     state->BlobType = (PyTypeObject *)type;
616     return 0;
617 }
618