1 /*
2 * Data stream functions
3 *
4 * Copyright (C) 2010-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 "libfsntfs_attribute.h"
27 #include "libfsntfs_cluster_block_stream.h"
28 #include "libfsntfs_data_extent.h"
29 #include "libfsntfs_data_stream.h"
30 #include "libfsntfs_definitions.h"
31 #include "libfsntfs_io_handle.h"
32 #include "libfsntfs_libbfio.h"
33 #include "libfsntfs_libcdata.h"
34 #include "libfsntfs_libcerror.h"
35 #include "libfsntfs_libcthreads.h"
36 #include "libfsntfs_libfdata.h"
37 #include "libfsntfs_mft_attribute.h"
38 #include "libfsntfs_types.h"
39
40 /* Creates a data stream
41 * Make sure the value data_stream is referencing, is set to NULL
42 * Returns 1 if successful or -1 on error
43 */
libfsntfs_data_stream_initialize(libfsntfs_data_stream_t ** data_stream,libbfio_handle_t * file_io_handle,libfsntfs_io_handle_t * io_handle,libfsntfs_mft_attribute_t * data_attribute,libcerror_error_t ** error)44 int libfsntfs_data_stream_initialize(
45 libfsntfs_data_stream_t **data_stream,
46 libbfio_handle_t *file_io_handle,
47 libfsntfs_io_handle_t *io_handle,
48 libfsntfs_mft_attribute_t *data_attribute,
49 libcerror_error_t **error )
50 {
51 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
52 static char *function = "libfsntfs_data_stream_initialize";
53
54 if( data_stream == NULL )
55 {
56 libcerror_error_set(
57 error,
58 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60 "%s: invalid data stream.",
61 function );
62
63 return( -1 );
64 }
65 if( *data_stream != NULL )
66 {
67 libcerror_error_set(
68 error,
69 LIBCERROR_ERROR_DOMAIN_RUNTIME,
70 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
71 "%s: invalid data stream value already set.",
72 function );
73
74 return( -1 );
75 }
76 if( data_attribute == NULL )
77 {
78 libcerror_error_set(
79 error,
80 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
81 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
82 "%s: invalid data attribute.",
83 function );
84
85 return( -1 );
86 }
87 internal_data_stream = memory_allocate_structure(
88 libfsntfs_internal_data_stream_t );
89
90 if( internal_data_stream == NULL )
91 {
92 libcerror_error_set(
93 error,
94 LIBCERROR_ERROR_DOMAIN_RUNTIME,
95 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
96 "%s: unable to create data stream.",
97 function );
98
99 goto on_error;
100 }
101 if( memory_set(
102 internal_data_stream,
103 0,
104 sizeof( libfsntfs_internal_data_stream_t ) ) == NULL )
105 {
106 libcerror_error_set(
107 error,
108 LIBCERROR_ERROR_DOMAIN_MEMORY,
109 LIBCERROR_MEMORY_ERROR_SET_FAILED,
110 "%s: unable to clear data stream.",
111 function );
112
113 memory_free(
114 internal_data_stream );
115
116 return( -1 );
117 }
118 if( libfsntfs_mft_attribute_get_data_extents_array(
119 data_attribute,
120 io_handle,
121 &( internal_data_stream->extents_array ),
122 error ) != 1 )
123 {
124 libcerror_error_set(
125 error,
126 LIBCERROR_ERROR_DOMAIN_RUNTIME,
127 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
128 "%s: unable to determine extents array.",
129 function );
130
131 goto on_error;
132 }
133 if( libfsntfs_cluster_block_stream_initialize(
134 &( internal_data_stream->data_cluster_block_stream ),
135 io_handle,
136 data_attribute,
137 NULL,
138 0,
139 error ) != 1 )
140 {
141 libcerror_error_set(
142 error,
143 LIBCERROR_ERROR_DOMAIN_RUNTIME,
144 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
145 "%s: unable to create data cluster block stream.",
146 function );
147
148 goto on_error;
149 }
150 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
151 if( libcthreads_read_write_lock_initialize(
152 &( internal_data_stream->read_write_lock ),
153 error ) != 1 )
154 {
155 libcerror_error_set(
156 error,
157 LIBCERROR_ERROR_DOMAIN_RUNTIME,
158 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
159 "%s: unable to initialize read/write lock.",
160 function );
161
162 goto on_error;
163 }
164 #endif
165 internal_data_stream->file_io_handle = file_io_handle;
166 internal_data_stream->data_attribute = data_attribute;
167
168 *data_stream = (libfsntfs_data_stream_t *) internal_data_stream;
169
170 return( 1 );
171
172 on_error:
173 if( internal_data_stream != NULL )
174 {
175 if( internal_data_stream->data_cluster_block_stream != NULL )
176 {
177 libfdata_stream_free(
178 &( internal_data_stream->data_cluster_block_stream ),
179 NULL );
180 }
181 if( internal_data_stream->extents_array != NULL )
182 {
183 libcdata_array_free(
184 &( internal_data_stream->extents_array ),
185 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_data_extent_free,
186 NULL );
187 }
188 memory_free(
189 internal_data_stream );
190 }
191 return( -1 );
192 }
193
194 /* Frees a data stream
195 * Returns 1 if successful or -1 on error
196 */
libfsntfs_data_stream_free(libfsntfs_data_stream_t ** data_stream,libcerror_error_t ** error)197 int libfsntfs_data_stream_free(
198 libfsntfs_data_stream_t **data_stream,
199 libcerror_error_t **error )
200 {
201 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
202 static char *function = "libfsntfs_data_stream_free";
203 int result = 1;
204
205 if( data_stream == NULL )
206 {
207 libcerror_error_set(
208 error,
209 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
210 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
211 "%s: invalid data stream.",
212 function );
213
214 return( -1 );
215 }
216 if( *data_stream != NULL )
217 {
218 internal_data_stream = (libfsntfs_internal_data_stream_t *) *data_stream;
219 *data_stream = NULL;
220
221 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
222 if( libcthreads_read_write_lock_free(
223 &( internal_data_stream->read_write_lock ),
224 error ) != 1 )
225 {
226 libcerror_error_set(
227 error,
228 LIBCERROR_ERROR_DOMAIN_RUNTIME,
229 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
230 "%s: unable to free read/write lock.",
231 function );
232
233 result = -1;
234 }
235 #endif
236 /* The file_io_handle and data_attribute references are freed elsewhere
237 */
238 if( internal_data_stream->data_cluster_block_stream != NULL )
239 {
240 if( libfdata_stream_free(
241 &( internal_data_stream->data_cluster_block_stream ),
242 error ) != 1 )
243 {
244 libcerror_error_set(
245 error,
246 LIBCERROR_ERROR_DOMAIN_RUNTIME,
247 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
248 "%s: unable to free data cluster block stream.",
249 function );
250
251 result = -1;
252 }
253 }
254 if( libcdata_array_free(
255 &( internal_data_stream->extents_array ),
256 (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_data_extent_free,
257 error ) != 1 )
258 {
259 libcerror_error_set(
260 error,
261 LIBCERROR_ERROR_DOMAIN_RUNTIME,
262 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
263 "%s: unable to free extents array.",
264 function );
265
266 result = -1;
267 }
268 memory_free(
269 internal_data_stream );
270 }
271 return( result );
272 }
273
274 /* Retrieves the size of the UTF-8 encoded name
275 * The returned size includes the end of string character
276 * Returns 1 if successful or -1 on error
277 */
libfsntfs_data_stream_get_utf8_name_size(libfsntfs_data_stream_t * data_stream,size_t * utf8_string_size,libcerror_error_t ** error)278 int libfsntfs_data_stream_get_utf8_name_size(
279 libfsntfs_data_stream_t *data_stream,
280 size_t *utf8_string_size,
281 libcerror_error_t **error )
282 {
283 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
284 static char *function = "libfsntfs_data_stream_get_utf8_name_size";
285 int result = 1;
286
287 if( data_stream == NULL )
288 {
289 libcerror_error_set(
290 error,
291 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
292 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
293 "%s: invalid data stream.",
294 function );
295
296 return( -1 );
297 }
298 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
299
300 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
301 if( libcthreads_read_write_lock_grab_for_read(
302 internal_data_stream->read_write_lock,
303 error ) != 1 )
304 {
305 libcerror_error_set(
306 error,
307 LIBCERROR_ERROR_DOMAIN_RUNTIME,
308 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
309 "%s: unable to grab read/write lock for reading.",
310 function );
311
312 return( -1 );
313 }
314 #endif
315 if( libfsntfs_mft_attribute_get_utf8_name_size(
316 internal_data_stream->data_attribute,
317 utf8_string_size,
318 error ) != 1 )
319 {
320 libcerror_error_set(
321 error,
322 LIBCERROR_ERROR_DOMAIN_RUNTIME,
323 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
324 "%s: unable to retrieve size of UTF-8 name from data stream.",
325 function );
326
327 result = -1;
328 }
329 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
330 if( libcthreads_read_write_lock_release_for_read(
331 internal_data_stream->read_write_lock,
332 error ) != 1 )
333 {
334 libcerror_error_set(
335 error,
336 LIBCERROR_ERROR_DOMAIN_RUNTIME,
337 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
338 "%s: unable to release read/write lock for reading.",
339 function );
340
341 return( -1 );
342 }
343 #endif
344 return( result );
345 }
346
347 /* Retrieves the UTF-8 encoded name
348 * The size should include the end of string character
349 * Returns 1 if successful or -1 on error
350 */
libfsntfs_data_stream_get_utf8_name(libfsntfs_data_stream_t * data_stream,uint8_t * utf8_string,size_t utf8_string_size,libcerror_error_t ** error)351 int libfsntfs_data_stream_get_utf8_name(
352 libfsntfs_data_stream_t *data_stream,
353 uint8_t *utf8_string,
354 size_t utf8_string_size,
355 libcerror_error_t **error )
356 {
357 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
358 static char *function = "libfsntfs_data_stream_get_utf8_name";
359 int result = 1;
360
361 if( data_stream == NULL )
362 {
363 libcerror_error_set(
364 error,
365 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
366 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
367 "%s: invalid data stream.",
368 function );
369
370 return( -1 );
371 }
372 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
373
374 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
375 if( libcthreads_read_write_lock_grab_for_read(
376 internal_data_stream->read_write_lock,
377 error ) != 1 )
378 {
379 libcerror_error_set(
380 error,
381 LIBCERROR_ERROR_DOMAIN_RUNTIME,
382 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
383 "%s: unable to grab read/write lock for reading.",
384 function );
385
386 return( -1 );
387 }
388 #endif
389 if( libfsntfs_mft_attribute_get_utf8_name(
390 internal_data_stream->data_attribute,
391 utf8_string,
392 utf8_string_size,
393 error ) != 1 )
394 {
395 libcerror_error_set(
396 error,
397 LIBCERROR_ERROR_DOMAIN_RUNTIME,
398 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
399 "%s: unable to retrieve UTF-8 name from data stream.",
400 function );
401
402 result = -1;
403 }
404 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
405 if( libcthreads_read_write_lock_release_for_read(
406 internal_data_stream->read_write_lock,
407 error ) != 1 )
408 {
409 libcerror_error_set(
410 error,
411 LIBCERROR_ERROR_DOMAIN_RUNTIME,
412 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
413 "%s: unable to release read/write lock for reading.",
414 function );
415
416 return( -1 );
417 }
418 #endif
419 return( result );
420 }
421
422 /* Retrieves the size of the UTF-16 encoded name
423 * The returned size includes the end of string character
424 * Returns 1 if successful or -1 on error
425 */
libfsntfs_data_stream_get_utf16_name_size(libfsntfs_data_stream_t * data_stream,size_t * utf16_string_size,libcerror_error_t ** error)426 int libfsntfs_data_stream_get_utf16_name_size(
427 libfsntfs_data_stream_t *data_stream,
428 size_t *utf16_string_size,
429 libcerror_error_t **error )
430 {
431 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
432 static char *function = "libfsntfs_data_stream_get_utf16_name_size";
433 int result = 1;
434
435 if( data_stream == NULL )
436 {
437 libcerror_error_set(
438 error,
439 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
440 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
441 "%s: invalid data stream.",
442 function );
443
444 return( -1 );
445 }
446 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
447
448 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
449 if( libcthreads_read_write_lock_grab_for_read(
450 internal_data_stream->read_write_lock,
451 error ) != 1 )
452 {
453 libcerror_error_set(
454 error,
455 LIBCERROR_ERROR_DOMAIN_RUNTIME,
456 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
457 "%s: unable to grab read/write lock for reading.",
458 function );
459
460 return( -1 );
461 }
462 #endif
463 if( libfsntfs_mft_attribute_get_utf16_name_size(
464 internal_data_stream->data_attribute,
465 utf16_string_size,
466 error ) != 1 )
467 {
468 libcerror_error_set(
469 error,
470 LIBCERROR_ERROR_DOMAIN_RUNTIME,
471 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
472 "%s: unable to retrieve size of UTF-16 name from data stream.",
473 function );
474
475 result = -1;
476 }
477 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
478 if( libcthreads_read_write_lock_release_for_read(
479 internal_data_stream->read_write_lock,
480 error ) != 1 )
481 {
482 libcerror_error_set(
483 error,
484 LIBCERROR_ERROR_DOMAIN_RUNTIME,
485 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
486 "%s: unable to release read/write lock for reading.",
487 function );
488
489 return( -1 );
490 }
491 #endif
492 return( result );
493 }
494
495 /* Retrieves the UTF-16 encoded name
496 * The size should include the end of string character
497 * Returns 1 if successful or -1 on error
498 */
libfsntfs_data_stream_get_utf16_name(libfsntfs_data_stream_t * data_stream,uint16_t * utf16_string,size_t utf16_string_size,libcerror_error_t ** error)499 int libfsntfs_data_stream_get_utf16_name(
500 libfsntfs_data_stream_t *data_stream,
501 uint16_t *utf16_string,
502 size_t utf16_string_size,
503 libcerror_error_t **error )
504 {
505 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
506 static char *function = "libfsntfs_data_stream_get_utf16_name";
507 int result = 1;
508
509 if( data_stream == NULL )
510 {
511 libcerror_error_set(
512 error,
513 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
514 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
515 "%s: invalid data stream.",
516 function );
517
518 return( -1 );
519 }
520 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
521
522 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
523 if( libcthreads_read_write_lock_grab_for_read(
524 internal_data_stream->read_write_lock,
525 error ) != 1 )
526 {
527 libcerror_error_set(
528 error,
529 LIBCERROR_ERROR_DOMAIN_RUNTIME,
530 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
531 "%s: unable to grab read/write lock for reading.",
532 function );
533
534 return( -1 );
535 }
536 #endif
537 if( libfsntfs_mft_attribute_get_utf16_name(
538 internal_data_stream->data_attribute,
539 utf16_string,
540 utf16_string_size,
541 error ) != 1 )
542 {
543 libcerror_error_set(
544 error,
545 LIBCERROR_ERROR_DOMAIN_RUNTIME,
546 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
547 "%s: unable to retrieve UTF-16 name from data stream.",
548 function );
549
550 result = -1;
551 }
552 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
553 if( libcthreads_read_write_lock_release_for_read(
554 internal_data_stream->read_write_lock,
555 error ) != 1 )
556 {
557 libcerror_error_set(
558 error,
559 LIBCERROR_ERROR_DOMAIN_RUNTIME,
560 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
561 "%s: unable to release read/write lock for reading.",
562 function );
563
564 return( -1 );
565 }
566 #endif
567 return( result );
568 }
569
570 /* Reads data at the current offset
571 * Returns the number of bytes read or -1 on error
572 */
libfsntfs_data_stream_read_buffer(libfsntfs_data_stream_t * data_stream,void * buffer,size_t buffer_size,libcerror_error_t ** error)573 ssize_t libfsntfs_data_stream_read_buffer(
574 libfsntfs_data_stream_t *data_stream,
575 void *buffer,
576 size_t buffer_size,
577 libcerror_error_t **error )
578 {
579 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
580 static char *function = "libfsntfs_data_stream_read_buffer";
581 ssize_t read_count = 0;
582
583 if( data_stream == NULL )
584 {
585 libcerror_error_set(
586 error,
587 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
588 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
589 "%s: invalid data stream.",
590 function );
591
592 return( -1 );
593 }
594 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
595
596 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
597 if( libcthreads_read_write_lock_grab_for_write(
598 internal_data_stream->read_write_lock,
599 error ) != 1 )
600 {
601 libcerror_error_set(
602 error,
603 LIBCERROR_ERROR_DOMAIN_RUNTIME,
604 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
605 "%s: unable to grab read/write lock for writing.",
606 function );
607
608 return( -1 );
609 }
610 #endif
611 read_count = libfdata_stream_read_buffer(
612 internal_data_stream->data_cluster_block_stream,
613 (intptr_t *) internal_data_stream->file_io_handle,
614 buffer,
615 buffer_size,
616 0,
617 error );
618
619 if( read_count < 0 )
620 {
621 libcerror_error_set(
622 error,
623 LIBCERROR_ERROR_DOMAIN_IO,
624 LIBCERROR_IO_ERROR_READ_FAILED,
625 "%s: unable to read from data cluster block stream.",
626 function );
627
628 read_count = -1;
629 }
630 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
631 if( libcthreads_read_write_lock_release_for_write(
632 internal_data_stream->read_write_lock,
633 error ) != 1 )
634 {
635 libcerror_error_set(
636 error,
637 LIBCERROR_ERROR_DOMAIN_RUNTIME,
638 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
639 "%s: unable to release read/write lock for writing.",
640 function );
641
642 return( -1 );
643 }
644 #endif
645 return( read_count );
646 }
647
648 /* Reads data at a specific offset
649 * Returns the number of bytes read or -1 on error
650 */
libfsntfs_data_stream_read_buffer_at_offset(libfsntfs_data_stream_t * data_stream,void * buffer,size_t buffer_size,off64_t offset,libcerror_error_t ** error)651 ssize_t libfsntfs_data_stream_read_buffer_at_offset(
652 libfsntfs_data_stream_t *data_stream,
653 void *buffer,
654 size_t buffer_size,
655 off64_t offset,
656 libcerror_error_t **error )
657 {
658 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
659 static char *function = "libfsntfs_data_stream_read_buffer_at_offset";
660 ssize_t read_count = 0;
661
662 if( data_stream == NULL )
663 {
664 libcerror_error_set(
665 error,
666 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
667 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
668 "%s: invalid data stream.",
669 function );
670
671 return( -1 );
672 }
673 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
674
675 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
676 if( libcthreads_read_write_lock_grab_for_write(
677 internal_data_stream->read_write_lock,
678 error ) != 1 )
679 {
680 libcerror_error_set(
681 error,
682 LIBCERROR_ERROR_DOMAIN_RUNTIME,
683 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
684 "%s: unable to grab read/write lock for writing.",
685 function );
686
687 return( -1 );
688 }
689 #endif
690 read_count = libfdata_stream_read_buffer_at_offset(
691 internal_data_stream->data_cluster_block_stream,
692 (intptr_t *) internal_data_stream->file_io_handle,
693 buffer,
694 buffer_size,
695 offset,
696 0,
697 error );
698
699 if( read_count < 0 )
700 {
701 libcerror_error_set(
702 error,
703 LIBCERROR_ERROR_DOMAIN_IO,
704 LIBCERROR_IO_ERROR_READ_FAILED,
705 "%s: unable to read from data cluster block stream.",
706 function );
707
708 read_count = -1;
709 }
710 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
711 if( libcthreads_read_write_lock_release_for_write(
712 internal_data_stream->read_write_lock,
713 error ) != 1 )
714 {
715 libcerror_error_set(
716 error,
717 LIBCERROR_ERROR_DOMAIN_RUNTIME,
718 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
719 "%s: unable to release read/write lock for writing.",
720 function );
721
722 return( -1 );
723 }
724 #endif
725 return( read_count );
726 }
727
728 /* Seeks a certain offset
729 * Returns the offset if seek is successful or -1 on error
730 */
libfsntfs_data_stream_seek_offset(libfsntfs_data_stream_t * data_stream,off64_t offset,int whence,libcerror_error_t ** error)731 off64_t libfsntfs_data_stream_seek_offset(
732 libfsntfs_data_stream_t *data_stream,
733 off64_t offset,
734 int whence,
735 libcerror_error_t **error )
736 {
737 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
738 static char *function = "libfsntfs_data_stream_seek_offset";
739
740 if( data_stream == NULL )
741 {
742 libcerror_error_set(
743 error,
744 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
745 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
746 "%s: invalid data stream.",
747 function );
748
749 return( -1 );
750 }
751 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
752
753 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
754 if( libcthreads_read_write_lock_grab_for_write(
755 internal_data_stream->read_write_lock,
756 error ) != 1 )
757 {
758 libcerror_error_set(
759 error,
760 LIBCERROR_ERROR_DOMAIN_RUNTIME,
761 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
762 "%s: unable to grab read/write lock for writing.",
763 function );
764
765 return( -1 );
766 }
767 #endif
768 offset = libfdata_stream_seek_offset(
769 internal_data_stream->data_cluster_block_stream,
770 offset,
771 whence,
772 error );
773
774 if( offset == -1 )
775 {
776 libcerror_error_set(
777 error,
778 LIBCERROR_ERROR_DOMAIN_IO,
779 LIBCERROR_IO_ERROR_SEEK_FAILED,
780 "%s: unable to seek offset in data cluster block stream.",
781 function );
782
783 offset = -1;
784 }
785 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
786 if( libcthreads_read_write_lock_release_for_write(
787 internal_data_stream->read_write_lock,
788 error ) != 1 )
789 {
790 libcerror_error_set(
791 error,
792 LIBCERROR_ERROR_DOMAIN_RUNTIME,
793 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
794 "%s: unable to release read/write lock for writing.",
795 function );
796
797 return( -1 );
798 }
799 #endif
800 return( offset );
801 }
802
803 /* Retrieves the current offset
804 * Returns the offset if successful or -1 on error
805 */
libfsntfs_data_stream_get_offset(libfsntfs_data_stream_t * data_stream,off64_t * offset,libcerror_error_t ** error)806 int libfsntfs_data_stream_get_offset(
807 libfsntfs_data_stream_t *data_stream,
808 off64_t *offset,
809 libcerror_error_t **error )
810 {
811 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
812 static char *function = "libfsntfs_data_stream_get_offset";
813 int result = 1;
814
815 if( data_stream == NULL )
816 {
817 libcerror_error_set(
818 error,
819 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
820 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
821 "%s: invalid data stream.",
822 function );
823
824 return( -1 );
825 }
826 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
827
828 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
829 if( libcthreads_read_write_lock_grab_for_read(
830 internal_data_stream->read_write_lock,
831 error ) != 1 )
832 {
833 libcerror_error_set(
834 error,
835 LIBCERROR_ERROR_DOMAIN_RUNTIME,
836 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
837 "%s: unable to grab read/write lock for reading.",
838 function );
839
840 return( -1 );
841 }
842 #endif
843 if( libfdata_stream_get_offset(
844 internal_data_stream->data_cluster_block_stream,
845 offset,
846 error ) != 1 )
847 {
848 libcerror_error_set(
849 error,
850 LIBCERROR_ERROR_DOMAIN_RUNTIME,
851 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
852 "%s: unable to retrieve offset from data cluster block stream.",
853 function );
854
855 result = -1;
856 }
857 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
858 if( libcthreads_read_write_lock_release_for_read(
859 internal_data_stream->read_write_lock,
860 error ) != 1 )
861 {
862 libcerror_error_set(
863 error,
864 LIBCERROR_ERROR_DOMAIN_RUNTIME,
865 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
866 "%s: unable to release read/write lock for reading.",
867 function );
868
869 return( -1 );
870 }
871 #endif
872 return( result );
873 }
874
875 /* Retrieves the size
876 * Returns 1 if successful or -1 on error
877 */
libfsntfs_data_stream_get_size(libfsntfs_data_stream_t * data_stream,size64_t * size,libcerror_error_t ** error)878 int libfsntfs_data_stream_get_size(
879 libfsntfs_data_stream_t *data_stream,
880 size64_t *size,
881 libcerror_error_t **error )
882 {
883 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
884 static char *function = "libfsntfs_data_stream_get_size";
885 int result = 1;
886
887 if( data_stream == NULL )
888 {
889 libcerror_error_set(
890 error,
891 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
892 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
893 "%s: invalid data stream.",
894 function );
895
896 return( -1 );
897 }
898 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
899
900 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
901 if( libcthreads_read_write_lock_grab_for_read(
902 internal_data_stream->read_write_lock,
903 error ) != 1 )
904 {
905 libcerror_error_set(
906 error,
907 LIBCERROR_ERROR_DOMAIN_RUNTIME,
908 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
909 "%s: unable to grab read/write lock for reading.",
910 function );
911
912 return( -1 );
913 }
914 #endif
915 if( libfdata_stream_get_size(
916 internal_data_stream->data_cluster_block_stream,
917 size,
918 error ) != 1 )
919 {
920 libcerror_error_set(
921 error,
922 LIBCERROR_ERROR_DOMAIN_RUNTIME,
923 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
924 "%s: unable to retrieve data attribute data size.",
925 function );
926
927 result = -1;
928 }
929 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
930 if( libcthreads_read_write_lock_release_for_read(
931 internal_data_stream->read_write_lock,
932 error ) != 1 )
933 {
934 libcerror_error_set(
935 error,
936 LIBCERROR_ERROR_DOMAIN_RUNTIME,
937 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
938 "%s: unable to release read/write lock for reading.",
939 function );
940
941 return( -1 );
942 }
943 #endif
944 return( result );
945 }
946
947 /* Retrieves the number of extents (decoded data runs)
948 * Returns 1 if successful or -1 on error
949 */
libfsntfs_data_stream_get_number_of_extents(libfsntfs_data_stream_t * data_stream,int * number_of_extents,libcerror_error_t ** error)950 int libfsntfs_data_stream_get_number_of_extents(
951 libfsntfs_data_stream_t *data_stream,
952 int *number_of_extents,
953 libcerror_error_t **error )
954 {
955 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
956 static char *function = "libfsntfs_data_stream_get_number_of_extents";
957 int result = 1;
958
959 if( data_stream == NULL )
960 {
961 libcerror_error_set(
962 error,
963 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
964 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
965 "%s: invalid data stream.",
966 function );
967
968 return( -1 );
969 }
970 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
971
972 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
973 if( libcthreads_read_write_lock_grab_for_read(
974 internal_data_stream->read_write_lock,
975 error ) != 1 )
976 {
977 libcerror_error_set(
978 error,
979 LIBCERROR_ERROR_DOMAIN_RUNTIME,
980 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
981 "%s: unable to grab read/write lock for reading.",
982 function );
983
984 return( -1 );
985 }
986 #endif
987 if( libcdata_array_get_number_of_entries(
988 internal_data_stream->extents_array,
989 number_of_extents,
990 error ) != 1 )
991 {
992 libcerror_error_set(
993 error,
994 LIBCERROR_ERROR_DOMAIN_RUNTIME,
995 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
996 "%s: unable to retrieve number of extents.",
997 function );
998
999 result = -1;
1000 }
1001 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
1002 if( libcthreads_read_write_lock_release_for_read(
1003 internal_data_stream->read_write_lock,
1004 error ) != 1 )
1005 {
1006 libcerror_error_set(
1007 error,
1008 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1009 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1010 "%s: unable to release read/write lock for reading.",
1011 function );
1012
1013 return( -1 );
1014 }
1015 #endif
1016 return( result );
1017 }
1018
1019 /* Retrieves a specific extent (decoded data run)
1020 * Returns 1 if successful or -1 on error
1021 */
libfsntfs_data_stream_get_extent_by_index(libfsntfs_data_stream_t * data_stream,int extent_index,off64_t * extent_offset,size64_t * extent_size,uint32_t * extent_flags,libcerror_error_t ** error)1022 int libfsntfs_data_stream_get_extent_by_index(
1023 libfsntfs_data_stream_t *data_stream,
1024 int extent_index,
1025 off64_t *extent_offset,
1026 size64_t *extent_size,
1027 uint32_t *extent_flags,
1028 libcerror_error_t **error )
1029 {
1030 libfsntfs_data_extent_t *data_extent = NULL;
1031 libfsntfs_internal_data_stream_t *internal_data_stream = NULL;
1032 static char *function = "libfsntfs_data_stream_get_extent_by_index";
1033 int result = 1;
1034
1035 if( data_stream == NULL )
1036 {
1037 libcerror_error_set(
1038 error,
1039 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1040 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1041 "%s: invalid data stream.",
1042 function );
1043
1044 return( -1 );
1045 }
1046 internal_data_stream = (libfsntfs_internal_data_stream_t *) data_stream;
1047
1048 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
1049 if( libcthreads_read_write_lock_grab_for_read(
1050 internal_data_stream->read_write_lock,
1051 error ) != 1 )
1052 {
1053 libcerror_error_set(
1054 error,
1055 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1056 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1057 "%s: unable to grab read/write lock for reading.",
1058 function );
1059
1060 return( -1 );
1061 }
1062 #endif
1063 if( libcdata_array_get_entry_by_index(
1064 internal_data_stream->extents_array,
1065 extent_index,
1066 (intptr_t **) &data_extent,
1067 error ) != 1 )
1068 {
1069 libcerror_error_set(
1070 error,
1071 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1072 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1073 "%s: unable to retrieve extent: %d.",
1074 function,
1075 extent_index );
1076
1077 result = -1;
1078 }
1079 else if( libfsntfs_data_extent_get_values(
1080 data_extent,
1081 extent_offset,
1082 extent_size,
1083 extent_flags,
1084 error ) != 1 )
1085 {
1086 libcerror_error_set(
1087 error,
1088 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1089 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1090 "%s: unable to retrieve extent: %d values.",
1091 function,
1092 extent_index );
1093
1094 result = -1;
1095 }
1096 #if defined( HAVE_LIBFSNTFS_MULTI_THREAD_SUPPORT )
1097 if( libcthreads_read_write_lock_release_for_read(
1098 internal_data_stream->read_write_lock,
1099 error ) != 1 )
1100 {
1101 libcerror_error_set(
1102 error,
1103 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1104 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1105 "%s: unable to release read/write lock for reading.",
1106 function );
1107
1108 return( -1 );
1109 }
1110 #endif
1111 return( result );
1112 }
1113
1114