Coverage Report

Created: 2025-07-04 07:01

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