1 /*
2 * Python file object IO handle functions
3 *
4 * Copyright (C) 2008-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25
26 #include "pyolecf_error.h"
27 #include "pyolecf_file_object_io_handle.h"
28 #include "pyolecf_integer.h"
29 #include "pyolecf_libbfio.h"
30 #include "pyolecf_libcerror.h"
31 #include "pyolecf_python.h"
32
33 /* Creates a file object IO handle
34 * Make sure the value file_object_io_handle is referencing, is set to NULL
35 * Returns 1 if successful or -1 on error
36 */
pyolecf_file_object_io_handle_initialize(pyolecf_file_object_io_handle_t ** file_object_io_handle,PyObject * file_object,libcerror_error_t ** error)37 int pyolecf_file_object_io_handle_initialize(
38 pyolecf_file_object_io_handle_t **file_object_io_handle,
39 PyObject *file_object,
40 libcerror_error_t **error )
41 {
42 static char *function = "pyolecf_file_object_io_handle_initialize";
43
44 if( file_object_io_handle == NULL )
45 {
46 libcerror_error_set(
47 error,
48 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50 "%s: invalid file object IO handle.",
51 function );
52
53 return( -1 );
54 }
55 if( *file_object_io_handle != NULL )
56 {
57 libcerror_error_set(
58 error,
59 LIBCERROR_ERROR_DOMAIN_RUNTIME,
60 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
61 "%s: invalid file object IO handle value already set.",
62 function );
63
64 return( -1 );
65 }
66 if( file_object == NULL )
67 {
68 libcerror_error_set(
69 error,
70 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
71 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
72 "%s: invalid file object.",
73 function );
74
75 return( -1 );
76 }
77 *file_object_io_handle = (pyolecf_file_object_io_handle_t *) PyMem_Malloc(
78 sizeof( pyolecf_file_object_io_handle_t ) );
79
80 if( *file_object_io_handle == NULL )
81 {
82 libcerror_error_set(
83 error,
84 LIBCERROR_ERROR_DOMAIN_MEMORY,
85 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
86 "%s: unable to create file object IO handle.",
87 function );
88
89 goto on_error;
90 }
91 if( memory_set(
92 *file_object_io_handle,
93 0,
94 sizeof( pyolecf_file_object_io_handle_t ) ) == NULL )
95 {
96 libcerror_error_set(
97 error,
98 LIBCERROR_ERROR_DOMAIN_MEMORY,
99 LIBCERROR_MEMORY_ERROR_SET_FAILED,
100 "%s: unable to clear file object IO handle.",
101 function );
102
103 goto on_error;
104 }
105 ( *file_object_io_handle )->file_object = file_object;
106
107 Py_IncRef(
108 ( *file_object_io_handle )->file_object );
109
110 return( 1 );
111
112 on_error:
113 if( *file_object_io_handle != NULL )
114 {
115 PyMem_Free(
116 *file_object_io_handle );
117
118 *file_object_io_handle = NULL;
119 }
120 return( -1 );
121 }
122
123 /* Initializes the file object IO handle
124 * Returns 1 if successful or -1 on error
125 */
pyolecf_file_object_initialize(libbfio_handle_t ** handle,PyObject * file_object,libcerror_error_t ** error)126 int pyolecf_file_object_initialize(
127 libbfio_handle_t **handle,
128 PyObject *file_object,
129 libcerror_error_t **error )
130 {
131 pyolecf_file_object_io_handle_t *file_object_io_handle = NULL;
132 static char *function = "pyolecf_file_object_initialize";
133
134 if( handle == NULL )
135 {
136 libcerror_error_set(
137 error,
138 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
139 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
140 "%s: invalid handle.",
141 function );
142
143 return( -1 );
144 }
145 if( *handle != NULL )
146 {
147 libcerror_error_set(
148 error,
149 LIBCERROR_ERROR_DOMAIN_RUNTIME,
150 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
151 "%s: invalid handle value already set.",
152 function );
153
154 return( -1 );
155 }
156 if( pyolecf_file_object_io_handle_initialize(
157 &file_object_io_handle,
158 file_object,
159 error ) != 1 )
160 {
161 libcerror_error_set(
162 error,
163 LIBCERROR_ERROR_DOMAIN_RUNTIME,
164 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
165 "%s: unable to create file object IO handle.",
166 function );
167
168 goto on_error;
169 }
170 if( libbfio_handle_initialize(
171 handle,
172 (intptr_t *) file_object_io_handle,
173 (int (*)(intptr_t **, libcerror_error_t **)) pyolecf_file_object_io_handle_free,
174 (int (*)(intptr_t **, intptr_t *, libcerror_error_t **)) pyolecf_file_object_io_handle_clone,
175 (int (*)(intptr_t *, int, libcerror_error_t **)) pyolecf_file_object_io_handle_open,
176 (int (*)(intptr_t *, libcerror_error_t **)) pyolecf_file_object_io_handle_close,
177 (ssize_t (*)(intptr_t *, uint8_t *, size_t, libcerror_error_t **)) pyolecf_file_object_io_handle_read,
178 (ssize_t (*)(intptr_t *, const uint8_t *, size_t, libcerror_error_t **)) pyolecf_file_object_io_handle_write,
179 (off64_t (*)(intptr_t *, off64_t, int, libcerror_error_t **)) pyolecf_file_object_io_handle_seek_offset,
180 (int (*)(intptr_t *, libcerror_error_t **)) pyolecf_file_object_io_handle_exists,
181 (int (*)(intptr_t *, libcerror_error_t **)) pyolecf_file_object_io_handle_is_open,
182 (int (*)(intptr_t *, size64_t *, libcerror_error_t **)) pyolecf_file_object_io_handle_get_size,
183 LIBBFIO_FLAG_IO_HANDLE_MANAGED | LIBBFIO_FLAG_IO_HANDLE_CLONE_BY_FUNCTION,
184 error ) != 1 )
185 {
186 libcerror_error_set(
187 error,
188 LIBCERROR_ERROR_DOMAIN_RUNTIME,
189 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
190 "%s: unable to create handle.",
191 function );
192
193 goto on_error;
194 }
195 return( 1 );
196
197 on_error:
198 if( file_object_io_handle != NULL )
199 {
200 pyolecf_file_object_io_handle_free(
201 &file_object_io_handle,
202 NULL );
203 }
204 return( -1 );
205 }
206
207 /* Frees a file object IO handle
208 * Returns 1 if succesful or -1 on error
209 */
pyolecf_file_object_io_handle_free(pyolecf_file_object_io_handle_t ** file_object_io_handle,libcerror_error_t ** error)210 int pyolecf_file_object_io_handle_free(
211 pyolecf_file_object_io_handle_t **file_object_io_handle,
212 libcerror_error_t **error )
213 {
214 static char *function = "pyolecf_file_object_io_handle_free";
215 PyGILState_STATE gil_state = 0;
216
217 if( file_object_io_handle == NULL )
218 {
219 libcerror_error_set(
220 error,
221 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
222 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
223 "%s: invalid file object IO handle.",
224 function );
225
226 return( -1 );
227 }
228 if( *file_object_io_handle != NULL )
229 {
230 gil_state = PyGILState_Ensure();
231
232 Py_DecRef(
233 ( *file_object_io_handle )->file_object );
234
235 PyGILState_Release(
236 gil_state );
237
238 PyMem_Free(
239 *file_object_io_handle );
240
241 *file_object_io_handle = NULL;
242 }
243 return( 1 );
244 }
245
246 /* Clones (duplicates) the file object IO handle and its attributes
247 * Returns 1 if succesful or -1 on error
248 */
pyolecf_file_object_io_handle_clone(pyolecf_file_object_io_handle_t ** destination_file_object_io_handle,pyolecf_file_object_io_handle_t * source_file_object_io_handle,libcerror_error_t ** error)249 int pyolecf_file_object_io_handle_clone(
250 pyolecf_file_object_io_handle_t **destination_file_object_io_handle,
251 pyolecf_file_object_io_handle_t *source_file_object_io_handle,
252 libcerror_error_t **error )
253 {
254 static char *function = "pyolecf_file_object_io_handle_clone";
255
256 if( destination_file_object_io_handle == NULL )
257 {
258 libcerror_error_set(
259 error,
260 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
261 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
262 "%s: invalid destination file object IO handle.",
263 function );
264
265 return( -1 );
266 }
267 if( *destination_file_object_io_handle != NULL )
268 {
269 libcerror_error_set(
270 error,
271 LIBCERROR_ERROR_DOMAIN_RUNTIME,
272 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
273 "%s: destination file object IO handle already set.",
274 function );
275
276 return( -1 );
277 }
278 if( source_file_object_io_handle == NULL )
279 {
280 *destination_file_object_io_handle = NULL;
281
282 return( 1 );
283 }
284 if( pyolecf_file_object_io_handle_initialize(
285 destination_file_object_io_handle,
286 source_file_object_io_handle->file_object,
287 error ) != 1 )
288 {
289 libcerror_error_set(
290 error,
291 LIBCERROR_ERROR_DOMAIN_RUNTIME,
292 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
293 "%s: unable to create file object IO handle.",
294 function );
295
296 return( -1 );
297 }
298 if( *destination_file_object_io_handle == NULL )
299 {
300 libcerror_error_set(
301 error,
302 LIBCERROR_ERROR_DOMAIN_RUNTIME,
303 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
304 "%s: missing destination file object IO handle.",
305 function );
306
307 return( -1 );
308 }
309 return( 1 );
310 }
311
312 /* Opens the file object IO handle
313 * Returns 1 if successful or -1 on error
314 */
pyolecf_file_object_io_handle_open(pyolecf_file_object_io_handle_t * file_object_io_handle,int access_flags,libcerror_error_t ** error)315 int pyolecf_file_object_io_handle_open(
316 pyolecf_file_object_io_handle_t *file_object_io_handle,
317 int access_flags,
318 libcerror_error_t **error )
319 {
320 static char *function = "pyolecf_file_object_io_handle_open";
321
322 if( file_object_io_handle == NULL )
323 {
324 libcerror_error_set(
325 error,
326 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
327 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
328 "%s: invalid file object IO handle.",
329 function );
330
331 return( -1 );
332 }
333 if( file_object_io_handle->file_object == NULL )
334 {
335 libcerror_error_set(
336 error,
337 LIBCERROR_ERROR_DOMAIN_RUNTIME,
338 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
339 "%s: invalid file object IO handle - missing file object.",
340 function );
341
342 return( -1 );
343 }
344 if( ( ( access_flags & LIBBFIO_ACCESS_FLAG_READ ) != 0 )
345 && ( ( access_flags & LIBBFIO_ACCESS_FLAG_WRITE ) != 0 ) )
346 {
347 libcerror_error_set(
348 error,
349 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
350 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
351 "%s: unsupported access flags.",
352 function );
353
354 return( -1 );
355 }
356 if( ( access_flags & LIBBFIO_ACCESS_FLAG_WRITE ) != 0 )
357 {
358 libcerror_error_set(
359 error,
360 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
361 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
362 "%s: write access currently not supported.",
363 function );
364
365 return( -1 );
366 }
367 /* No need to do anything here, because the file object is already open
368 */
369 file_object_io_handle->access_flags = access_flags;
370
371 return( 1 );
372 }
373
374 /* Closes the file object IO handle
375 * Returns 0 if successful or -1 on error
376 */
pyolecf_file_object_io_handle_close(pyolecf_file_object_io_handle_t * file_object_io_handle,libcerror_error_t ** error)377 int pyolecf_file_object_io_handle_close(
378 pyolecf_file_object_io_handle_t *file_object_io_handle,
379 libcerror_error_t **error )
380 {
381 static char *function = "pyolecf_file_object_io_handle_close";
382
383 if( file_object_io_handle == NULL )
384 {
385 libcerror_error_set(
386 error,
387 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
388 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
389 "%s: invalid file object IO handle.",
390 function );
391
392 return( -1 );
393 }
394 if( file_object_io_handle->file_object == NULL )
395 {
396 libcerror_error_set(
397 error,
398 LIBCERROR_ERROR_DOMAIN_RUNTIME,
399 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
400 "%s: invalid file object IO handle - missing file object.",
401 function );
402
403 return( -1 );
404 }
405 /* Do not close the file object, have Python deal with it
406 */
407 file_object_io_handle->access_flags = 0;
408
409 return( 0 );
410 }
411
412 /* Reads a buffer from the file object
413 * Make sure to hold the GIL state before calling this function
414 * Returns the number of bytes read if successful, or -1 on error
415 */
pyolecf_file_object_read_buffer(PyObject * file_object,uint8_t * buffer,size_t size,libcerror_error_t ** error)416 ssize_t pyolecf_file_object_read_buffer(
417 PyObject *file_object,
418 uint8_t *buffer,
419 size_t size,
420 libcerror_error_t **error )
421 {
422 PyObject *argument_size = NULL;
423 PyObject *method_name = NULL;
424 PyObject *method_result = NULL;
425 static char *function = "pyolecf_file_object_read_buffer";
426 char *safe_buffer = NULL;
427 Py_ssize_t safe_read_count = 0;
428 ssize_t read_count = 0;
429 int result = 0;
430
431 if( file_object == NULL )
432 {
433 libcerror_error_set(
434 error,
435 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
436 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
437 "%s: invalid file object.",
438 function );
439
440 return( -1 );
441 }
442 if( buffer == NULL )
443 {
444 libcerror_error_set(
445 error,
446 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
447 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
448 "%s: invalid buffer.",
449 function );
450
451 return( -1 );
452 }
453 if( size > (size_t) SSIZE_MAX )
454 {
455 libcerror_error_set(
456 error,
457 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
458 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
459 "%s: invalid size value exceeds maximum.",
460 function );
461
462 return( -1 );
463 }
464 if( size > 0 )
465 {
466 #if PY_MAJOR_VERSION >= 3
467 method_name = PyUnicode_FromString(
468 "read" );
469 #else
470 method_name = PyString_FromString(
471 "read" );
472 #endif
473 argument_size = PyLong_FromSize_t(
474 size );
475
476 PyErr_Clear();
477
478 method_result = PyObject_CallMethodObjArgs(
479 file_object,
480 method_name,
481 argument_size,
482 NULL );
483
484 if( PyErr_Occurred() )
485 {
486 pyolecf_error_fetch(
487 error,
488 LIBCERROR_ERROR_DOMAIN_IO,
489 LIBCERROR_IO_ERROR_READ_FAILED,
490 "%s: unable to read from file object.",
491 function );
492
493 goto on_error;
494 }
495 if( method_result == NULL )
496 {
497 libcerror_error_set(
498 error,
499 LIBCERROR_ERROR_DOMAIN_RUNTIME,
500 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
501 "%s: missing method result.",
502 function );
503
504 goto on_error;
505 }
506 #if PY_MAJOR_VERSION >= 3
507 result = PyObject_IsInstance(
508 method_result,
509 (PyObject *) &PyBytes_Type );
510 #else
511 result = PyObject_IsInstance(
512 method_result,
513 (PyObject *) &PyString_Type );
514 #endif
515 if( result == -1 )
516 {
517 libcerror_error_set(
518 error,
519 LIBCERROR_ERROR_DOMAIN_RUNTIME,
520 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
521 "%s: unable to determine if method result is a binary string object.",
522 function );
523
524 goto on_error;
525 }
526 else if( result == 0 )
527 {
528 libcerror_error_set(
529 error,
530 LIBCERROR_ERROR_DOMAIN_RUNTIME,
531 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
532 "%s: invalid method result value is not a binary string object.",
533 function );
534
535 goto on_error;
536 }
537 #if PY_MAJOR_VERSION >= 3
538 result = PyBytes_AsStringAndSize(
539 method_result,
540 &safe_buffer,
541 &safe_read_count );
542 #else
543 result = PyString_AsStringAndSize(
544 method_result,
545 &safe_buffer,
546 &safe_read_count );
547 #endif
548 if( result == -1 )
549 {
550 pyolecf_error_fetch(
551 error,
552 LIBCERROR_ERROR_DOMAIN_IO,
553 LIBCERROR_IO_ERROR_READ_FAILED,
554 "%s: unable to read from file object.",
555 function );
556
557 goto on_error;
558 }
559 if( safe_read_count > (Py_ssize_t) SSIZE_MAX )
560 {
561 libcerror_error_set(
562 error,
563 LIBCERROR_ERROR_DOMAIN_RUNTIME,
564 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
565 "%s: invalid read count value exceeds maximum.",
566 function );
567
568 goto on_error;
569 }
570 read_count = (ssize_t) safe_read_count;
571
572 if( memory_copy(
573 buffer,
574 safe_buffer,
575 read_count ) == NULL )
576 {
577 libcerror_error_set(
578 error,
579 LIBCERROR_ERROR_DOMAIN_MEMORY,
580 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
581 "%s: unable to data to buffer.",
582 function );
583
584 goto on_error;
585 }
586 Py_DecRef(
587 method_result );
588
589 Py_DecRef(
590 argument_size );
591
592 Py_DecRef(
593 method_name );
594 }
595 return( read_count );
596
597 on_error:
598 if( method_result != NULL )
599 {
600 Py_DecRef(
601 method_result );
602 }
603 if( argument_size != NULL )
604 {
605 Py_DecRef(
606 argument_size );
607 }
608 if( method_name != NULL )
609 {
610 Py_DecRef(
611 method_name );
612 }
613 return( -1 );
614 }
615
616 /* Reads a buffer from the file object IO handle
617 * Returns the number of bytes read if successful, or -1 on error
618 */
pyolecf_file_object_io_handle_read(pyolecf_file_object_io_handle_t * file_object_io_handle,uint8_t * buffer,size_t size,libcerror_error_t ** error)619 ssize_t pyolecf_file_object_io_handle_read(
620 pyolecf_file_object_io_handle_t *file_object_io_handle,
621 uint8_t *buffer,
622 size_t size,
623 libcerror_error_t **error )
624 {
625 static char *function = "pyolecf_file_object_io_handle_read";
626 PyGILState_STATE gil_state = 0;
627 ssize_t read_count = 0;
628
629 if( file_object_io_handle == NULL )
630 {
631 libcerror_error_set(
632 error,
633 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
634 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
635 "%s: invalid file object IO handle.",
636 function );
637
638 return( -1 );
639 }
640 gil_state = PyGILState_Ensure();
641
642 read_count = pyolecf_file_object_read_buffer(
643 file_object_io_handle->file_object,
644 buffer,
645 size,
646 error );
647
648 if( read_count == -1 )
649 {
650 libcerror_error_set(
651 error,
652 LIBCERROR_ERROR_DOMAIN_IO,
653 LIBCERROR_IO_ERROR_READ_FAILED,
654 "%s: unable to read from file object.",
655 function );
656
657 goto on_error;
658 }
659 PyGILState_Release(
660 gil_state );
661
662 return( read_count );
663
664 on_error:
665 PyGILState_Release(
666 gil_state );
667
668 return( -1 );
669 }
670
671 /* Writes a buffer to the file object
672 * Make sure to hold the GIL state before calling this function
673 * Returns the number of bytes written if successful, or -1 on error
674 */
pyolecf_file_object_write_buffer(PyObject * file_object,const uint8_t * buffer,size_t size,libcerror_error_t ** error)675 ssize_t pyolecf_file_object_write_buffer(
676 PyObject *file_object,
677 const uint8_t *buffer,
678 size_t size,
679 libcerror_error_t **error )
680 {
681 PyObject *argument_string = NULL;
682 PyObject *method_name = NULL;
683 PyObject *method_result = NULL;
684 static char *function = "pyolecf_file_object_write_buffer";
685
686 if( file_object == NULL )
687 {
688 libcerror_error_set(
689 error,
690 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
691 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
692 "%s: invalid file object.",
693 function );
694
695 return( -1 );
696 }
697 if( buffer == NULL )
698 {
699 libcerror_error_set(
700 error,
701 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
702 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
703 "%s: invalid buffer.",
704 function );
705
706 return( -1 );
707 }
708 #if SIZEOF_SIZE_T > SIZEOF_INT
709 if( size > (size_t) INT_MAX )
710 #else
711 if( size > (size_t) SSIZE_MAX )
712 #endif
713 {
714 libcerror_error_set(
715 error,
716 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
717 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
718 "%s: invalid size value exceeds maximum.",
719 function );
720
721 return( -1 );
722 }
723 if( size > 0 )
724 {
725 #if PY_MAJOR_VERSION >= 3
726 method_name = PyUnicode_FromString(
727 "write" );
728 #else
729 method_name = PyString_FromString(
730 "write" );
731 #endif
732 #if PY_MAJOR_VERSION >= 3
733 argument_string = PyBytes_FromStringAndSize(
734 (char *) buffer,
735 size );
736 #else
737 argument_string = PyString_FromStringAndSize(
738 (char *) buffer,
739 size );
740 #endif
741 PyErr_Clear();
742
743 method_result = PyObject_CallMethodObjArgs(
744 file_object,
745 method_name,
746 argument_string,
747 NULL );
748
749 if( PyErr_Occurred() )
750 {
751 pyolecf_error_fetch(
752 error,
753 LIBCERROR_ERROR_DOMAIN_IO,
754 LIBCERROR_IO_ERROR_WRITE_FAILED,
755 "%s: unable to write to file object.",
756 function );
757
758 goto on_error;
759 }
760 if( method_result == NULL )
761 {
762 libcerror_error_set(
763 error,
764 LIBCERROR_ERROR_DOMAIN_RUNTIME,
765 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
766 "%s: missing method result.",
767 function );
768
769 goto on_error;
770 }
771 Py_DecRef(
772 method_result );
773
774 Py_DecRef(
775 argument_string );
776
777 Py_DecRef(
778 method_name );
779 }
780 return( (ssize_t) size );
781
782 on_error:
783 if( method_result != NULL )
784 {
785 Py_DecRef(
786 method_result );
787 }
788 if( argument_string != NULL )
789 {
790 Py_DecRef(
791 argument_string );
792 }
793 if( method_name != NULL )
794 {
795 Py_DecRef(
796 method_name );
797 }
798 return( -1 );
799 }
800
801 /* Writes a buffer to the file object IO handle
802 * Returns the number of bytes written if successful, or -1 on error
803 */
pyolecf_file_object_io_handle_write(pyolecf_file_object_io_handle_t * file_object_io_handle,const uint8_t * buffer,size_t size,libcerror_error_t ** error)804 ssize_t pyolecf_file_object_io_handle_write(
805 pyolecf_file_object_io_handle_t *file_object_io_handle,
806 const uint8_t *buffer,
807 size_t size,
808 libcerror_error_t **error )
809 {
810 static char *function = "pyolecf_file_object_io_handle_write";
811 PyGILState_STATE gil_state = 0;
812 ssize_t write_count = 0;
813
814 if( file_object_io_handle == NULL )
815 {
816 libcerror_error_set(
817 error,
818 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
819 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
820 "%s: invalid file object IO handle.",
821 function );
822
823 return( -1 );
824 }
825 gil_state = PyGILState_Ensure();
826
827 write_count = pyolecf_file_object_write_buffer(
828 file_object_io_handle->file_object,
829 buffer,
830 size,
831 error );
832
833 if( write_count == -1 )
834 {
835 libcerror_error_set(
836 error,
837 LIBCERROR_ERROR_DOMAIN_IO,
838 LIBCERROR_IO_ERROR_WRITE_FAILED,
839 "%s: unable to write from file object.",
840 function );
841
842 goto on_error;
843 }
844 PyGILState_Release(
845 gil_state );
846
847 return( write_count );
848
849 on_error:
850 PyGILState_Release(
851 gil_state );
852
853 return( -1 );
854 }
855
856 /* Seeks a certain offset within the file object
857 * Make sure to hold the GIL state before calling this function
858 * Returns 1 if successful or -1 on error
859 */
pyolecf_file_object_seek_offset(PyObject * file_object,off64_t offset,int whence,libcerror_error_t ** error)860 int pyolecf_file_object_seek_offset(
861 PyObject *file_object,
862 off64_t offset,
863 int whence,
864 libcerror_error_t **error )
865 {
866 PyObject *argument_offset = NULL;
867 PyObject *argument_whence = NULL;
868 PyObject *method_name = NULL;
869 PyObject *method_result = NULL;
870 static char *function = "pyolecf_file_object_seek_offset";
871
872 if( file_object == NULL )
873 {
874 libcerror_error_set(
875 error,
876 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
877 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
878 "%s: invalid file object.",
879 function );
880
881 return( -1 );
882 }
883 #if defined( HAVE_LONG_LONG )
884 if( offset > (off64_t) INT64_MAX )
885 #else
886 if( offset > (off64_t) LONG_MAX )
887 #endif
888 {
889 libcerror_error_set(
890 error,
891 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
892 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
893 "%s: invalid offset value exceeds maximum.",
894 function );
895
896 return( -1 );
897 }
898 if( ( whence != SEEK_CUR )
899 && ( whence != SEEK_END )
900 && ( whence != SEEK_SET ) )
901 {
902 libcerror_error_set(
903 error,
904 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
905 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
906 "%s: unsupported whence.",
907 function );
908
909 return( -1 );
910 }
911 #if PY_MAJOR_VERSION >= 3
912 method_name = PyUnicode_FromString(
913 "seek" );
914 #else
915 method_name = PyString_FromString(
916 "seek" );
917 #endif
918 #if defined( HAVE_LONG_LONG )
919 argument_offset = PyLong_FromLongLong(
920 (PY_LONG_LONG) offset );
921 #else
922 argument_offset = PyLong_FromLongLong(
923 (long) offset );
924 #endif
925 #if PY_MAJOR_VERSION >= 3
926 argument_whence = PyLong_FromLong(
927 (long) whence );
928 #else
929 argument_whence = PyInt_FromLong(
930 (long) whence );
931 #endif
932 PyErr_Clear();
933
934 method_result = PyObject_CallMethodObjArgs(
935 file_object,
936 method_name,
937 argument_offset,
938 argument_whence,
939 NULL );
940
941 if( PyErr_Occurred() )
942 {
943 pyolecf_error_fetch(
944 error,
945 LIBCERROR_ERROR_DOMAIN_IO,
946 LIBCERROR_IO_ERROR_SEEK_FAILED,
947 "%s: unable to seek in file object.",
948 function );
949
950 goto on_error;
951 }
952 if( method_result == NULL )
953 {
954 libcerror_error_set(
955 error,
956 LIBCERROR_ERROR_DOMAIN_RUNTIME,
957 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
958 "%s: missing method result.",
959 function );
960
961 goto on_error;
962 }
963 Py_DecRef(
964 method_result );
965
966 Py_DecRef(
967 argument_whence );
968
969 Py_DecRef(
970 argument_offset );
971
972 Py_DecRef(
973 method_name );
974
975 return( 1 );
976
977 on_error:
978 if( method_result != NULL )
979 {
980 Py_DecRef(
981 method_result );
982 }
983 if( argument_whence != NULL )
984 {
985 Py_DecRef(
986 argument_whence );
987 }
988 if( argument_offset != NULL )
989 {
990 Py_DecRef(
991 argument_offset );
992 }
993 if( method_name != NULL )
994 {
995 Py_DecRef(
996 method_name );
997 }
998 return( -1 );
999 }
1000
1001 /* Retrieves the current offset within the file object
1002 * Make sure to hold the GIL state before calling this function
1003 * Returns 1 if successful or -1 on error
1004 */
pyolecf_file_object_get_offset(PyObject * file_object,off64_t * offset,libcerror_error_t ** error)1005 int pyolecf_file_object_get_offset(
1006 PyObject *file_object,
1007 off64_t *offset,
1008 libcerror_error_t **error )
1009 {
1010 PyObject *method_name = NULL;
1011 PyObject *method_result = NULL;
1012 static char *function = "pyolecf_file_object_get_offset";
1013 int result = 0;
1014
1015 if( file_object == NULL )
1016 {
1017 libcerror_error_set(
1018 error,
1019 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1020 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1021 "%s: invalid file object.",
1022 function );
1023
1024 return( -1 );
1025 }
1026 if( offset == NULL )
1027 {
1028 libcerror_error_set(
1029 error,
1030 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1031 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1032 "%s: invalid offset.",
1033 function );
1034
1035 return( -1 );
1036 }
1037 #if PY_MAJOR_VERSION >= 3
1038 method_name = PyUnicode_FromString(
1039 "get_offset" );
1040 #else
1041 method_name = PyString_FromString(
1042 "get_offset" );
1043 #endif
1044 PyErr_Clear();
1045
1046 /* Determine if the file object has the get_offset method
1047 */
1048 result = PyObject_HasAttr(
1049 file_object,
1050 method_name );
1051
1052 if( result == 0 )
1053 {
1054 Py_DecRef(
1055 method_name );
1056
1057 /* Fall back to the tell method
1058 */
1059 #if PY_MAJOR_VERSION >= 3
1060 method_name = PyUnicode_FromString(
1061 "tell" );
1062 #else
1063 method_name = PyString_FromString(
1064 "tell" );
1065 #endif
1066 }
1067 PyErr_Clear();
1068
1069 method_result = PyObject_CallMethodObjArgs(
1070 file_object,
1071 method_name,
1072 NULL );
1073
1074 if( PyErr_Occurred() )
1075 {
1076 pyolecf_error_fetch(
1077 error,
1078 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1079 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1080 "%s: unable to retrieve current offset in file object.",
1081 function );
1082
1083 goto on_error;
1084 }
1085 if( method_result == NULL )
1086 {
1087 libcerror_error_set(
1088 error,
1089 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1090 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1091 "%s: missing method result.",
1092 function );
1093
1094 goto on_error;
1095 }
1096 if( pyolecf_integer_signed_copy_to_64bit(
1097 method_result,
1098 offset,
1099 error ) != 1 )
1100 {
1101 libcerror_error_set(
1102 error,
1103 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1104 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1105 "%s: unable to convert method result into current offset of file object.",
1106 function );
1107
1108 goto on_error;
1109 }
1110 Py_DecRef(
1111 method_result );
1112
1113 Py_DecRef(
1114 method_name );
1115
1116 return( 1 );
1117
1118 on_error:
1119 if( method_result != NULL )
1120 {
1121 Py_DecRef(
1122 method_result );
1123 }
1124 if( method_name != NULL )
1125 {
1126 Py_DecRef(
1127 method_name );
1128 }
1129 return( -1 );
1130 }
1131
1132 /* Seeks a certain offset within the file object IO handle
1133 * Returns the offset if the seek is successful or -1 on error
1134 */
pyolecf_file_object_io_handle_seek_offset(pyolecf_file_object_io_handle_t * file_object_io_handle,off64_t offset,int whence,libcerror_error_t ** error)1135 off64_t pyolecf_file_object_io_handle_seek_offset(
1136 pyolecf_file_object_io_handle_t *file_object_io_handle,
1137 off64_t offset,
1138 int whence,
1139 libcerror_error_t **error )
1140 {
1141 static char *function = "pyolecf_file_object_io_handle_seek_offset";
1142 PyGILState_STATE gil_state = 0;
1143
1144 if( file_object_io_handle == NULL )
1145 {
1146 libcerror_error_set(
1147 error,
1148 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1149 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1150 "%s: invalid file object IO handle.",
1151 function );
1152
1153 return( -1 );
1154 }
1155 gil_state = PyGILState_Ensure();
1156
1157 if( pyolecf_file_object_seek_offset(
1158 file_object_io_handle->file_object,
1159 offset,
1160 whence,
1161 error ) != 1 )
1162 {
1163 libcerror_error_set(
1164 error,
1165 LIBCERROR_ERROR_DOMAIN_IO,
1166 LIBCERROR_IO_ERROR_SEEK_FAILED,
1167 "%s: unable to seek in file object.",
1168 function );
1169
1170 goto on_error;
1171 }
1172 if( pyolecf_file_object_get_offset(
1173 file_object_io_handle->file_object,
1174 &offset,
1175 error ) != 1 )
1176 {
1177 libcerror_error_set(
1178 error,
1179 LIBCERROR_ERROR_DOMAIN_IO,
1180 LIBCERROR_IO_ERROR_SEEK_FAILED,
1181 "%s: unable to retrieve current offset in file object.",
1182 function );
1183
1184 goto on_error;
1185 }
1186 PyGILState_Release(
1187 gil_state );
1188
1189 return( offset );
1190
1191 on_error:
1192 PyGILState_Release(
1193 gil_state );
1194
1195 return( -1 );
1196 }
1197
1198 /* Function to determine if a file exists
1199 * Returns 1 if file exists, 0 if not or -1 on error
1200 */
pyolecf_file_object_io_handle_exists(pyolecf_file_object_io_handle_t * file_object_io_handle,libcerror_error_t ** error)1201 int pyolecf_file_object_io_handle_exists(
1202 pyolecf_file_object_io_handle_t *file_object_io_handle,
1203 libcerror_error_t **error )
1204 {
1205 static char *function = "pyolecf_file_object_io_handle_exists";
1206
1207 if( file_object_io_handle == NULL )
1208 {
1209 libcerror_error_set(
1210 error,
1211 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1212 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1213 "%s: invalid file object IO handle.",
1214 function );
1215
1216 return( -1 );
1217 }
1218 if( file_object_io_handle->file_object == NULL )
1219 {
1220 return( 0 );
1221 }
1222 return( 1 );
1223 }
1224
1225 /* Check if the file is open
1226 * Returns 1 if open, 0 if not or -1 on error
1227 */
pyolecf_file_object_io_handle_is_open(pyolecf_file_object_io_handle_t * file_object_io_handle,libcerror_error_t ** error)1228 int pyolecf_file_object_io_handle_is_open(
1229 pyolecf_file_object_io_handle_t *file_object_io_handle,
1230 libcerror_error_t **error )
1231 {
1232 static char *function = "pyolecf_file_object_io_handle_is_open";
1233
1234 if( file_object_io_handle == NULL )
1235 {
1236 libcerror_error_set(
1237 error,
1238 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1239 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1240 "%s: invalid file object IO handle.",
1241 function );
1242
1243 return( -1 );
1244 }
1245 if( file_object_io_handle->file_object == NULL )
1246 {
1247 libcerror_error_set(
1248 error,
1249 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1250 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1251 "%s: invalid file object IO handle - missing file object.",
1252 function );
1253
1254 return( -1 );
1255 }
1256 /* As far as BFIO is concerned the file object is always open
1257 */
1258 return( 1 );
1259 }
1260
1261 /* Retrieves the size of the file object
1262 * Make sure to hold the GIL state before calling this function
1263 * Returns 1 if successful or -1 on error
1264 */
pyolecf_file_object_get_size(PyObject * file_object,size64_t * size,libcerror_error_t ** error)1265 int pyolecf_file_object_get_size(
1266 PyObject *file_object,
1267 size64_t *size,
1268 libcerror_error_t **error )
1269 {
1270 PyObject *method_name = NULL;
1271 PyObject *method_result = NULL;
1272 static char *function = "pyolecf_file_object_get_size";
1273
1274 if( file_object == NULL )
1275 {
1276 libcerror_error_set(
1277 error,
1278 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1279 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1280 "%s: invalid file object.",
1281 function );
1282
1283 return( -1 );
1284 }
1285 if( size == NULL )
1286 {
1287 libcerror_error_set(
1288 error,
1289 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1290 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1291 "%s: invalid size.",
1292 function );
1293
1294 return( -1 );
1295 }
1296 #if PY_MAJOR_VERSION >= 3
1297 method_name = PyUnicode_FromString(
1298 "get_size" );
1299 #else
1300 method_name = PyString_FromString(
1301 "get_size" );
1302 #endif
1303 PyErr_Clear();
1304
1305 method_result = PyObject_CallMethodObjArgs(
1306 file_object,
1307 method_name,
1308 NULL );
1309
1310 if( PyErr_Occurred() )
1311 {
1312 pyolecf_error_fetch(
1313 error,
1314 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1315 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1316 "%s: unable to retrieve size of file object.",
1317 function );
1318
1319 goto on_error;
1320 }
1321 if( method_result == NULL )
1322 {
1323 libcerror_error_set(
1324 error,
1325 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1326 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1327 "%s: missing method result.",
1328 function );
1329
1330 goto on_error;
1331 }
1332 if( pyolecf_integer_unsigned_copy_to_64bit(
1333 method_result,
1334 size,
1335 error ) != 1 )
1336 {
1337 libcerror_error_set(
1338 error,
1339 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1340 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1341 "%s: unable to convert method result into size of file object.",
1342 function );
1343
1344 goto on_error;
1345 }
1346 Py_DecRef(
1347 method_result );
1348
1349 Py_DecRef(
1350 method_name );
1351
1352 return( 1 );
1353
1354 on_error:
1355 if( method_result != NULL )
1356 {
1357 Py_DecRef(
1358 method_result );
1359 }
1360 if( method_name != NULL )
1361 {
1362 Py_DecRef(
1363 method_name );
1364 }
1365 return( -1 );
1366 }
1367
1368 /* Retrieves the file size
1369 * Returns 1 if successful or -1 on error
1370 */
pyolecf_file_object_io_handle_get_size(pyolecf_file_object_io_handle_t * file_object_io_handle,size64_t * size,libcerror_error_t ** error)1371 int pyolecf_file_object_io_handle_get_size(
1372 pyolecf_file_object_io_handle_t *file_object_io_handle,
1373 size64_t *size,
1374 libcerror_error_t **error )
1375 {
1376 PyObject *method_name = NULL;
1377 static char *function = "pyolecf_file_object_io_handle_get_size";
1378 PyGILState_STATE gil_state = 0;
1379 off64_t current_offset = 0;
1380 int result = 0;
1381
1382 if( file_object_io_handle == NULL )
1383 {
1384 libcerror_error_set(
1385 error,
1386 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1387 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1388 "%s: invalid file object IO handle.",
1389 function );
1390
1391 return( -1 );
1392 }
1393 if( file_object_io_handle->file_object == NULL )
1394 {
1395 libcerror_error_set(
1396 error,
1397 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1398 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1399 "%s: invalid file object IO handle - missing file object.",
1400 function );
1401
1402 return( -1 );
1403 }
1404 gil_state = PyGILState_Ensure();
1405
1406 #if PY_MAJOR_VERSION >= 3
1407 method_name = PyUnicode_FromString(
1408 "get_size" );
1409 #else
1410 method_name = PyString_FromString(
1411 "get_size" );
1412 #endif
1413 PyErr_Clear();
1414
1415 /* Determine if the file object has the get_size method
1416 */
1417 result = PyObject_HasAttr(
1418 file_object_io_handle->file_object,
1419 method_name );
1420
1421 if( result != 0 )
1422 {
1423 if( pyolecf_file_object_get_size(
1424 file_object_io_handle->file_object,
1425 size,
1426 error ) != 1 )
1427 {
1428 libcerror_error_set(
1429 error,
1430 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1431 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1432 "%s: unable to retrieve size of file object.",
1433 function );
1434
1435 goto on_error;
1436 }
1437 }
1438 else
1439 {
1440 if( pyolecf_file_object_get_offset(
1441 file_object_io_handle->file_object,
1442 ¤t_offset,
1443 error ) != 1 )
1444 {
1445 libcerror_error_set(
1446 error,
1447 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1448 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1449 "%s: unable to retrieve current offset in file object.",
1450 function );
1451
1452 goto on_error;
1453 }
1454 if( pyolecf_file_object_seek_offset(
1455 file_object_io_handle->file_object,
1456 0,
1457 SEEK_END,
1458 error ) != 1 )
1459 {
1460 libcerror_error_set(
1461 error,
1462 LIBCERROR_ERROR_DOMAIN_IO,
1463 LIBCERROR_IO_ERROR_SEEK_FAILED,
1464 "%s: unable to seek end of file object.",
1465 function );
1466
1467 goto on_error;
1468 }
1469 if( pyolecf_file_object_get_offset(
1470 file_object_io_handle->file_object,
1471 (off64_t *) size,
1472 error ) != 1 )
1473 {
1474 libcerror_error_set(
1475 error,
1476 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1477 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1478 "%s: unable to retrieve end offset in file object.",
1479 function );
1480
1481 pyolecf_file_object_seek_offset(
1482 file_object_io_handle->file_object,
1483 current_offset,
1484 SEEK_SET,
1485 NULL );
1486
1487 goto on_error;
1488 }
1489 if( pyolecf_file_object_seek_offset(
1490 file_object_io_handle->file_object,
1491 current_offset,
1492 SEEK_SET,
1493 error ) != 1 )
1494 {
1495 libcerror_error_set(
1496 error,
1497 LIBCERROR_ERROR_DOMAIN_IO,
1498 LIBCERROR_IO_ERROR_SEEK_FAILED,
1499 "%s: unable to seek current offset in file object.",
1500 function );
1501
1502 goto on_error;
1503 }
1504 }
1505 Py_DecRef(
1506 method_name );
1507
1508 PyGILState_Release(
1509 gil_state );
1510
1511 return( 1 );
1512
1513 on_error:
1514 if( method_name != NULL )
1515 {
1516 Py_DecRef(
1517 method_name );
1518 }
1519 PyGILState_Release(
1520 gil_state );
1521
1522 return( 1 );
1523 }
1524
1525