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