1 /*
2  * Data block functions
3  *
4  * Copyright (C) 2012-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 <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26 
27 #include "libmodi_compression.h"
28 #include "libmodi_data_block.h"
29 #include "libmodi_definitions.h"
30 #include "libmodi_io_handle.h"
31 #include "libmodi_libbfio.h"
32 #include "libmodi_libcerror.h"
33 #include "libmodi_libcnotify.h"
34 #include "libmodi_libfdata.h"
35 #include "libmodi_unused.h"
36 
37 /* Creates a data block
38  * Make sure the value data_block is referencing, is set to NULL
39  * Returns 1 if successful or -1 on error
40  */
libmodi_data_block_initialize(libmodi_data_block_t ** data_block,size_t data_size,libcerror_error_t ** error)41 int libmodi_data_block_initialize(
42      libmodi_data_block_t **data_block,
43      size_t data_size,
44      libcerror_error_t **error )
45 {
46 	static char *function = "libmodi_data_block_initialize";
47 
48 	if( data_block == NULL )
49 	{
50 		libcerror_error_set(
51 		 error,
52 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 		 "%s: invalid data block.",
55 		 function );
56 
57 		return( -1 );
58 	}
59 	if( *data_block != NULL )
60 	{
61 		libcerror_error_set(
62 		 error,
63 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 		 "%s: invalid data block value already set.",
66 		 function );
67 
68 		return( -1 );
69 	}
70 	if( ( data_size == 0 )
71 	 || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
72 	{
73 		libcerror_error_set(
74 		 error,
75 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
77 		 "%s: invalid data size value out of bounds.",
78 		 function );
79 
80 		return( -1 );
81 	}
82 	*data_block = memory_allocate_structure(
83 	               libmodi_data_block_t );
84 
85 	if( *data_block == NULL )
86 	{
87 		libcerror_error_set(
88 		 error,
89 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
90 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91 		 "%s: unable to create data block.",
92 		 function );
93 
94 		goto on_error;
95 	}
96 	if( memory_set(
97 	     *data_block,
98 	     0,
99 	     sizeof( libmodi_data_block_t ) ) == NULL )
100 	{
101 		libcerror_error_set(
102 		 error,
103 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
104 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
105 		 "%s: unable to clear data block.",
106 		 function );
107 
108 		memory_free(
109 		 *data_block );
110 
111 		*data_block = NULL;
112 
113 		return( -1 );
114 	}
115 	( *data_block )->data = (uint8_t *) memory_allocate(
116 	                                     sizeof( uint8_t ) * data_size );
117 
118 	if( ( *data_block )->data == NULL )
119 	{
120 		libcerror_error_set(
121 		 error,
122 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
123 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
124 		 "%s: unable to create data.",
125 		 function );
126 
127 		goto on_error;
128 	}
129 	( *data_block )->data_size = data_size;
130 
131 	return( 1 );
132 
133 on_error:
134 	if( *data_block != NULL )
135 	{
136 		memory_free(
137 		 *data_block );
138 
139 		*data_block = NULL;
140 	}
141 	return( -1 );
142 }
143 
144 /* Frees a data block
145  * Returns 1 if successful or -1 on error
146  */
libmodi_data_block_free(libmodi_data_block_t ** data_block,libcerror_error_t ** error)147 int libmodi_data_block_free(
148      libmodi_data_block_t **data_block,
149      libcerror_error_t **error )
150 {
151 	static char *function = "libmodi_data_block_free";
152 	int result            = 1;
153 
154 	if( data_block == NULL )
155 	{
156 		libcerror_error_set(
157 		 error,
158 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
159 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
160 		 "%s: invalid data block.",
161 		 function );
162 
163 		return( -1 );
164 	}
165 	if( *data_block != NULL )
166 	{
167 		memory_free(
168 		 ( *data_block )->data );
169 
170 		memory_free(
171 		 *data_block );
172 
173 		*data_block = NULL;
174 	}
175 	return( result );
176 }
177 
178 /* Clears a data block
179  * Returns 1 if successful or -1 on error
180  */
libmodi_data_block_clear(libmodi_data_block_t * data_block,libcerror_error_t ** error)181 int libmodi_data_block_clear(
182      libmodi_data_block_t *data_block,
183      libcerror_error_t **error )
184 {
185 	static char *function = "libmodi_data_block_clear";
186 
187 	if( data_block == NULL )
188 	{
189 		libcerror_error_set(
190 		 error,
191 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
192 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
193 		 "%s: invalid data block.",
194 		 function );
195 
196 		return( -1 );
197 	}
198 	if( data_block->data == NULL )
199 	{
200 		libcerror_error_set(
201 		 error,
202 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
204 		 "%s: invalid data block - missing data.",
205 		 function );
206 
207 		return( -1 );
208 	}
209 	if( memory_set(
210 	     data_block->data,
211 	     0,
212 	     data_block->data_size ) == NULL )
213 	{
214 		libcerror_error_set(
215 		 error,
216 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
217 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
218 		 "%s: unable to clear data block data.",
219 		 function );
220 
221 		return( -1 );
222 	}
223 	return( 1 );
224 }
225 
226 /* Reads data block
227  * Returns 1 if successful or -1 on error
228  */
libmodi_data_block_read_file_io_handle(libmodi_data_block_t * data_block,libbfio_handle_t * file_io_handle,off64_t data_block_offset,libcerror_error_t ** error)229 int libmodi_data_block_read_file_io_handle(
230      libmodi_data_block_t *data_block,
231      libbfio_handle_t *file_io_handle,
232      off64_t data_block_offset,
233      libcerror_error_t **error )
234 {
235 	static char *function = "libmodi_data_block_read_file_io_handle";
236 	ssize_t read_count    = 0;
237 
238 	if( data_block == NULL )
239 	{
240 		libcerror_error_set(
241 		 error,
242 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
243 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
244 		 "%s: invalid data block.",
245 		 function );
246 
247 		return( -1 );
248 	}
249 #if defined( HAVE_DEBUG_OUTPUT )
250 	if( libcnotify_verbose != 0 )
251 	{
252 		libcnotify_printf(
253 		 "%s: reading data block at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
254 		 function,
255 		 data_block_offset,
256 		 data_block_offset );
257 	}
258 #endif
259 	read_count = libbfio_handle_read_buffer_at_offset(
260 	              file_io_handle,
261 	              data_block->data,
262 	              data_block->data_size,
263 	              data_block_offset,
264 	              error );
265 
266 	if( read_count != (ssize_t) data_block->data_size )
267 	{
268 		libcerror_error_set(
269 		 error,
270 		 LIBCERROR_ERROR_DOMAIN_IO,
271 		 LIBCERROR_IO_ERROR_READ_FAILED,
272 		 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
273 		 function,
274 		 data_block_offset,
275 		 data_block_offset );
276 
277 		return( -1 );
278 	}
279 #if defined( HAVE_DEBUG_OUTPUT )
280 	if( libcnotify_verbose != 0 )
281 	{
282 		libcnotify_printf(
283 		 "%s: data block:\n",
284 		 function );
285 		libcnotify_print_data(
286 		 data_block->data,
287 		 data_block->data_size,
288 		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
289 	}
290 #endif
291 	return( 1 );
292 }
293 
294 /* Reads a data block
295  * Callback function for the block chunks list
296  * Returns 1 if successful or -1 on error
297  */
libmodi_data_block_read_list_element_data(libmodi_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_list_element_t * element,libfdata_cache_t * cache,int element_data_file_index LIBMODI_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags,uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,libcerror_error_t ** error)298 int libmodi_data_block_read_list_element_data(
299      libmodi_io_handle_t *io_handle,
300      libbfio_handle_t *file_io_handle,
301      libfdata_list_element_t *element,
302      libfdata_cache_t *cache,
303      int element_data_file_index LIBMODI_ATTRIBUTE_UNUSED,
304      off64_t element_data_offset,
305      size64_t element_data_size,
306      uint32_t element_data_flags,
307      uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,
308      libcerror_error_t **error )
309 {
310 	libmodi_data_block_t *data_block = NULL;
311 	static char *function            = "libmodi_data_block_read_list_element_data";
312 	uint8_t *compressed_data         = NULL;
313 	size64_t mapped_size             = 0;
314 	size_t uncompressed_data_size    = 0;
315 	ssize_t read_count               = 0;
316 
317 	LIBMODI_UNREFERENCED_PARAMETER( element_data_file_index )
318 	LIBMODI_UNREFERENCED_PARAMETER( read_flags )
319 
320 	if( io_handle == NULL )
321 	{
322 		libcerror_error_set(
323 		 error,
324 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
325 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
326 		 "%s: invalid IO handle.",
327 		 function );
328 
329 		return( -1 );
330 	}
331 	if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
332 	{
333 		if( ( element_data_size == 0 )
334 		 || ( element_data_size > (size64_t) SSIZE_MAX ) )
335 		{
336 			libcerror_error_set(
337 			 error,
338 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
339 			 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
340 			 "%s: invalid element data size value out of bounds.",
341 			 function );
342 
343 			return( -1 );
344 		}
345 	}
346 	if( libfdata_list_element_get_mapped_size(
347 	     element,
348 	     &mapped_size,
349 	     error ) != 1 )
350 	{
351 		libcerror_error_set(
352 		 error,
353 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
354 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
355 		 "%s: unable to retrieve mapped size from element.",
356 		 function );
357 
358 		goto on_error;
359 	}
360 	if( ( mapped_size == 0 )
361 	 || ( mapped_size > (size64_t) SSIZE_MAX ) )
362 	{
363 		libcerror_error_set(
364 		 error,
365 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
366 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
367 		 "%s: invalid block chunk data size value out of bounds.",
368 		 function );
369 
370 		goto on_error;
371 	}
372 	if( libmodi_data_block_initialize(
373 	     &data_block,
374 	     (size_t) mapped_size,
375 	     error ) != 1 )
376 	{
377 		libcerror_error_set(
378 		 error,
379 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
380 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
381 		 "%s: unable to create data block.",
382 		 function );
383 
384 		goto on_error;
385 	}
386 	if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
387 	{
388 		if( memory_set(
389 		     data_block->data,
390 		     0,
391 		     data_block->data_size ) == NULL )
392 		{
393 			libcerror_error_set(
394 			 error,
395 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
396 			 LIBCERROR_MEMORY_ERROR_SET_FAILED,
397 			 "%s: unable to clear data block.",
398 			 function );
399 
400 			goto on_error;
401 		}
402 	}
403 	else if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_COMPRESSED ) != 0 )
404 	{
405 #if defined( HAVE_DEBUG_OUTPUT )
406 		if( libcnotify_verbose != 0 )
407 		{
408 			libcnotify_printf(
409 			 "%s: reading compressed block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
410 			 function,
411 			 element_data_offset,
412 			 element_data_offset );
413 		}
414 #endif
415 		compressed_data = (uint8_t *) memory_allocate(
416 		                               sizeof( uint8_t ) * element_data_size );
417 
418 		if( compressed_data == NULL )
419 		{
420 			libcerror_error_set(
421 			 error,
422 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
423 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
424 			 "%s: unable to create compressed data.",
425 			 function );
426 
427 			goto on_error;
428 		}
429 		read_count = libbfio_handle_read_buffer_at_offset(
430 		              file_io_handle,
431 		              compressed_data,
432 		              element_data_size,
433 		              element_data_offset,
434 		              error );
435 
436 		if( read_count != (ssize_t) element_data_size )
437 		{
438 			libcerror_error_set(
439 			 error,
440 			 LIBCERROR_ERROR_DOMAIN_IO,
441 			 LIBCERROR_IO_ERROR_READ_FAILED,
442 			 "%s: unable to read compressed block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ").",
443 			 function,
444 			 element_data_offset,
445 			 element_data_offset );
446 
447 			goto on_error;
448 		}
449 		uncompressed_data_size = data_block->data_size;
450 
451 		if( libmodi_decompress_data(
452 		     compressed_data,
453 		     (size_t) read_count,
454 		     io_handle->compression_method,
455 		     data_block->data,
456 		     &uncompressed_data_size,
457 		     error ) != 1 )
458 		{
459 			libcerror_error_set(
460 			 error,
461 			 LIBCERROR_ERROR_DOMAIN_ENCRYPTION,
462 			 LIBCERROR_ENCRYPTION_ERROR_GENERIC,
463 			 "%s: unable to decompress block chunk at offset: %" PRIi64 " (0x%08" PRIx64 ").",
464 			 function,
465 			 element_data_offset,
466 			 element_data_offset );
467 
468 			goto on_error;
469 		}
470 		memory_free(
471 		 compressed_data );
472 
473 		compressed_data = NULL;
474 	}
475 	else
476 	{
477 		if( libmodi_data_block_read_file_io_handle(
478 		     data_block,
479 		     file_io_handle,
480 		     element_data_offset,
481 		     error ) != 1 )
482 		{
483 			libcerror_error_set(
484 			 error,
485 			 LIBCERROR_ERROR_DOMAIN_IO,
486 			 LIBCERROR_IO_ERROR_READ_FAILED,
487 			 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
488 			 function,
489 			 element_data_offset,
490 			 element_data_offset );
491 
492 			goto on_error;
493 		}
494 	}
495 	if( libfdata_list_element_set_element_value(
496 	     element,
497 	     (intptr_t *) file_io_handle,
498 	     cache,
499 	     (intptr_t *) data_block,
500 	     (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_data_block_free,
501 	     LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
502 	     error ) != 1 )
503 	{
504 		libcerror_error_set(
505 		 error,
506 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
507 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
508 		 "%s: unable to set data block as element value.",
509 		 function );
510 
511 		goto on_error;
512 	}
513 	return( 1 );
514 
515 on_error:
516 	if( compressed_data != NULL )
517 	{
518 		memory_free(
519 		 compressed_data );
520 	}
521 	if( data_block != NULL )
522 	{
523 		libmodi_data_block_free(
524 		 &data_block,
525 		 NULL );
526 	}
527 	return( -1 );
528 }
529 
530 /* Reads a data block
531  * Callback function for the data block vector
532  * Returns 1 if successful or -1 on error
533  */
libmodi_data_block_read_vector_element_data(libmodi_io_handle_t * io_handle,intptr_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags,uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,libcerror_error_t ** error)534 int libmodi_data_block_read_vector_element_data(
535      libmodi_io_handle_t *io_handle,
536      intptr_t *file_io_handle,
537      libfdata_vector_t *vector,
538      libfdata_cache_t *cache,
539      int element_index,
540      int element_data_file_index,
541      off64_t element_data_offset,
542      size64_t element_data_size,
543      uint32_t element_data_flags,
544      uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,
545      libcerror_error_t **error )
546 {
547 	libbfio_handle_t *bfio_handle    = NULL;
548 	libmodi_data_block_t *data_block = NULL;
549 	static char *function            = "libmodi_data_block_read_vector_element_data";
550 
551 	LIBMODI_UNREFERENCED_PARAMETER( read_flags );
552 
553 	if( io_handle == NULL )
554 	{
555 		libcerror_error_set(
556 		 error,
557 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
558 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
559 		 "%s: invalid IO handle.",
560 		 function );
561 
562 		return( -1 );
563 	}
564 	if( ( io_handle->image_type != LIBMODI_IMAGE_TYPE_SPARSE_BUNDLE )
565 	 && ( element_data_file_index != 0 ) )
566 	{
567 		libcerror_error_set(
568 		 error,
569 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
570 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
571 		 "%s: invalid element data file index value out of bounds.",
572 		 function );
573 
574 		return( -1 );
575 	}
576 	if( ( element_data_size == 0 )
577 	 || ( element_data_size > (size64_t) SSIZE_MAX ) )
578 	{
579 		libcerror_error_set(
580 		 error,
581 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
582 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
583 		 "%s: invalid element data size value out of bounds.",
584 		 function );
585 
586 		return( -1 );
587 	}
588 	if( libmodi_data_block_initialize(
589 	     &data_block,
590 	     (size_t) element_data_size,
591 	     error ) != 1 )
592 	{
593 		libcerror_error_set(
594 		 error,
595 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
596 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
597 		 "%s: unable to create data block.",
598 		 function );
599 
600 		goto on_error;
601 	}
602 	if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
603 	{
604 		if( memory_set(
605 		     data_block->data,
606 		     0,
607 		     data_block->data_size ) == NULL )
608 		{
609 			libcerror_error_set(
610 			 error,
611 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
612 			 LIBCERROR_MEMORY_ERROR_SET_FAILED,
613 			 "%s: unable to clear data block.",
614 			 function );
615 
616 			goto on_error;
617 		}
618 	}
619 	else
620 	{
621 		if( io_handle->image_type != LIBMODI_IMAGE_TYPE_SPARSE_BUNDLE )
622 		{
623 			bfio_handle = (libbfio_handle_t *) file_io_handle;
624 		}
625 		else if( libbfio_pool_get_handle(
626 		          (libbfio_pool_t *) file_io_handle,
627 		          element_data_file_index,
628 		          &bfio_handle,
629 		          error ) != 1 )
630 		{
631 			libcerror_error_set(
632 			 error,
633 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
634 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
635 			 "%s: unable to retrieve handle: %d from file IO pool.",
636 			 function,
637 			 element_data_file_index );
638 
639 			goto on_error;
640 		}
641 		if( libmodi_data_block_read_file_io_handle(
642 		     data_block,
643 		     bfio_handle,
644 		     element_data_offset,
645 		     error ) != 1 )
646 		{
647 			libcerror_error_set(
648 			 error,
649 			 LIBCERROR_ERROR_DOMAIN_IO,
650 			 LIBCERROR_IO_ERROR_READ_FAILED,
651 			 "%s: unable to read data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
652 			 function,
653 			 element_data_offset,
654 			 element_data_offset );
655 
656 			goto on_error;
657 		}
658 	}
659 	if( libfdata_vector_set_element_value_by_index(
660 	     vector,
661 	     (intptr_t *) file_io_handle,
662 	     cache,
663 	     element_index,
664 	     (intptr_t *) data_block,
665 	     (int (*)(intptr_t **, libcerror_error_t **)) &libmodi_data_block_free,
666 	     LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
667 	     error ) != 1 )
668 	{
669 		libcerror_error_set(
670 		 error,
671 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
672 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
673 		 "%s: unable to set data block as element value.",
674 		 function );
675 
676 		goto on_error;
677 	}
678 	return( 1 );
679 
680 on_error:
681 	if( data_block != NULL )
682 	{
683 		libmodi_data_block_free(
684 		 &data_block,
685 		 NULL );
686 	}
687 	return( -1 );
688 }
689 
690