Coverage Report

Created: 2025-08-28 07:10

/src/libfsntfs/libfsntfs/libfsntfs_cluster_block_stream.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Cluster block 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 <types.h>
24
25
#include "libfsntfs_buffer_data_handle.h"
26
#include "libfsntfs_cluster_block_data.h"
27
#include "libfsntfs_cluster_block_stream.h"
28
#include "libfsntfs_compressed_block_data_handle.h"
29
#include "libfsntfs_compressed_data_handle.h"
30
#include "libfsntfs_definitions.h"
31
#include "libfsntfs_io_handle.h"
32
#include "libfsntfs_libcerror.h"
33
#include "libfsntfs_libfdata.h"
34
#include "libfsntfs_mft_attribute.h"
35
36
/* Creates cluster block stream from a buffer of data
37
 * Make sure the value cluster_block_stream is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsntfs_cluster_block_stream_initialize_from_data(
41
     libfdata_stream_t **cluster_block_stream,
42
     const uint8_t *data,
43
     size_t data_size,
44
     libcerror_error_t **error )
45
1.64k
{
46
1.64k
  libfdata_stream_t *safe_data_stream         = NULL;
47
1.64k
  libfsntfs_buffer_data_handle_t *data_handle = NULL;
48
1.64k
  static char *function                       = "libfsntfs_cluster_block_stream_initialize_from_data";
49
1.64k
  int segment_index                           = 0;
50
51
1.64k
  if( cluster_block_stream == NULL )
52
0
  {
53
0
    libcerror_error_set(
54
0
     error,
55
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
56
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
57
0
     "%s: invalid cluster block stream.",
58
0
     function );
59
60
0
    return( -1 );
61
0
  }
62
1.64k
  if( libfsntfs_buffer_data_handle_initialize(
63
1.64k
       &data_handle,
64
1.64k
       data,
65
1.64k
       data_size,
66
1.64k
       error ) != 1 )
67
0
  {
68
0
    libcerror_error_set(
69
0
     error,
70
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
71
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
72
0
     "%s: unable to create buffer data handle.",
73
0
     function );
74
75
0
    goto on_error;
76
0
  }
77
1.64k
  if( libfdata_stream_initialize(
78
1.64k
       &safe_data_stream,
79
1.64k
       (intptr_t *) data_handle,
80
1.64k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_buffer_data_handle_free,
81
1.64k
       NULL,
82
1.64k
       NULL,
83
1.64k
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_buffer_data_handle_read_segment_data,
84
1.64k
       NULL,
85
1.64k
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsntfs_buffer_data_handle_seek_segment_offset,
86
1.64k
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
87
1.64k
       error ) != 1 )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
92
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
93
0
     "%s: unable to create data stream.",
94
0
     function );
95
96
0
    goto on_error;
97
0
  }
98
1.64k
  data_handle = NULL;
99
100
1.64k
  if( libfdata_stream_append_segment(
101
1.64k
       safe_data_stream,
102
1.64k
       &segment_index,
103
1.64k
       0,
104
1.64k
       0,
105
1.64k
       (size64_t) data_size,
106
1.64k
       0,
107
1.64k
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
113
0
     "%s: unable to append data stream segment.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
1.64k
  *cluster_block_stream = safe_data_stream;
119
120
1.64k
  return( 1 );
121
122
0
on_error:
123
0
  if( safe_data_stream != NULL )
124
0
  {
125
0
    libfdata_stream_free(
126
0
     &safe_data_stream,
127
0
     NULL );
128
0
  }
129
0
  if( data_handle != NULL )
130
0
  {
131
0
    libfsntfs_buffer_data_handle_free(
132
0
     &data_handle,
133
0
     NULL );
134
0
  }
135
0
  return( -1 );
136
1.64k
}
137
138
/* Creates cluster block stream from data runs
139
 * Make sure the value data_stream is referencing, is set to NULL
140
 * Returns 1 if successful or -1 on error
141
 */
142
int libfsntfs_cluster_block_stream_initialize_from_data_runs(
143
     libfdata_stream_t **cluster_block_stream,
144
     libfsntfs_io_handle_t *io_handle,
145
     libfsntfs_mft_attribute_t *data_attribute,
146
     size64_t data_size,
147
     libcerror_error_t **error )
148
1.13k
{
149
1.13k
  libfdata_stream_t *safe_data_stream          = NULL;
150
1.13k
  libfsntfs_data_run_t *data_run               = NULL;
151
1.13k
  static char *function                        = "libfsntfs_cluster_block_stream_initialize_from_data_runs";
152
1.13k
  size64_t attribute_data_vcn_size             = 0;
153
1.13k
  size64_t calculated_allocated_data_size      = 0;
154
1.13k
  size64_t data_segment_size                   = 0;
155
1.13k
  size64_t stored_allocated_data_size          = 0;
156
1.13k
  size64_t valid_data_size                     = 0;
157
1.13k
  off64_t attribute_data_vcn_offset            = 0;
158
1.13k
  off64_t calculated_attribute_data_vcn_offset = 0;
159
1.13k
  off64_t data_segment_offset                  = 0;
160
1.13k
  uint16_t attribute_data_flags                = 0;
161
1.13k
  int attribute_index                          = 0;
162
1.13k
  int data_run_index                           = 0;
163
1.13k
  int number_of_data_runs                      = 0;
164
1.13k
  int segment_index                            = 0;
165
166
1.13k
  if( cluster_block_stream == NULL )
167
0
  {
168
0
    libcerror_error_set(
169
0
     error,
170
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
171
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
172
0
     "%s: invalid data stream.",
173
0
     function );
174
175
0
    return( -1 );
176
0
  }
177
1.13k
  if( io_handle == NULL )
178
0
  {
179
0
    libcerror_error_set(
180
0
     error,
181
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
182
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
183
0
     "%s: invalid IO handle.",
184
0
     function );
185
186
0
    return( -1 );
187
0
  }
188
1.13k
  if( io_handle->cluster_block_size == 0 )
189
0
  {
190
0
    libcerror_error_set(
191
0
     error,
192
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
193
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
194
0
     "%s: invalid IO handle - cluster block size value out of bounds.",
195
0
     function );
196
197
0
    return( -1 );
198
0
  }
199
1.13k
  if( libfsntfs_mft_attribute_get_valid_data_size(
200
1.13k
       data_attribute,
201
1.13k
       &valid_data_size,
202
1.13k
       error ) != 1 )
203
0
  {
204
0
    libcerror_error_set(
205
0
     error,
206
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
207
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
208
0
     "%s: unable to retrieve valid data size.",
209
0
     function );
210
211
0
    goto on_error;
212
0
  }
213
1.13k
  if( libfsntfs_mft_attribute_get_data_flags(
214
1.13k
       data_attribute,
215
1.13k
       &attribute_data_flags,
216
1.13k
       error ) != 1 )
217
0
  {
218
0
    libcerror_error_set(
219
0
     error,
220
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
221
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
222
0
     "%s: unable to retrieve attribute data flags.",
223
0
     function );
224
225
0
    goto on_error;
226
0
  }
227
1.13k
  if( ( attribute_data_flags & LIBFSNTFS_ATTRIBUTE_FLAG_COMPRESSION_MASK ) != 0 )
228
0
  {
229
0
    libcerror_error_set(
230
0
     error,
231
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
232
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
233
0
     "%s: unsupported compressed attribute data.",
234
0
     function );
235
236
0
    goto on_error;
237
0
  }
238
1.13k
  if( libfsntfs_mft_attribute_get_allocated_data_size(
239
1.13k
       data_attribute,
240
1.13k
       &stored_allocated_data_size,
241
1.13k
       error ) != 1 )
242
0
  {
243
0
    libcerror_error_set(
244
0
     error,
245
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
246
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
247
0
     "%s: unable to retrieve attribute allocated data size.",
248
0
     function );
249
250
0
    goto on_error;
251
0
  }
252
1.13k
  if( libfdata_stream_initialize(
253
1.13k
       &safe_data_stream,
254
1.13k
       NULL,
255
1.13k
       NULL,
256
1.13k
       NULL,
257
1.13k
       NULL,
258
1.13k
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_cluster_block_data_read_segment_data,
259
1.13k
       NULL,
260
1.13k
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsntfs_cluster_block_data_seek_segment_offset,
261
1.13k
       0,
262
1.13k
       error ) != 1 )
263
0
  {
264
0
    libcerror_error_set(
265
0
     error,
266
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
267
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
268
0
     "%s: unable to create data stream.",
269
0
     function );
270
271
0
    goto on_error;
272
0
  }
273
2.01k
  while( data_attribute != NULL )
274
1.30k
  {
275
1.30k
    if( libfsntfs_mft_attribute_get_data_vcn_range(
276
1.30k
         data_attribute,
277
1.30k
         (uint64_t *) &attribute_data_vcn_offset,
278
1.30k
         (uint64_t *) &attribute_data_vcn_size,
279
1.30k
         error ) != 1 )
280
2
    {
281
2
      libcerror_error_set(
282
2
       error,
283
2
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
284
2
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
285
2
       "%s: unable to retrieve attribute data VCN range.",
286
2
       function );
287
288
2
      goto on_error;
289
2
    }
290
1.29k
    if( attribute_data_vcn_size != 0xffffffffffffffffULL )
291
1.01k
    {
292
1.01k
      if( (uint64_t) attribute_data_vcn_offset > (uint64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
293
88
      {
294
88
        libcerror_error_set(
295
88
         error,
296
88
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
297
88
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
298
88
         "%s: invalid attribute data first VCN value out of bounds.",
299
88
         function );
300
301
88
        goto on_error;
302
88
      }
303
930
      if( attribute_data_vcn_size > (size64_t) ( ( INT64_MAX / io_handle->cluster_block_size ) - 1 ) )
304
173
      {
305
173
        libcerror_error_set(
306
173
         error,
307
173
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
308
173
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
309
173
         "%s: invalid attribute data last VCN value out of bounds.",
310
173
         function );
311
312
173
        goto on_error;
313
173
      }
314
757
      if( attribute_data_vcn_offset > (off64_t) attribute_data_vcn_size )
315
109
      {
316
109
        libcerror_error_set(
317
109
         error,
318
109
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
319
109
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
320
109
         "%s: invalid attribute data first VCN value exceeds last VCN value.",
321
109
         function );
322
323
109
        goto on_error;
324
109
      }
325
648
      attribute_data_vcn_size   += 1;
326
648
      attribute_data_vcn_size   -= attribute_data_vcn_offset;
327
648
      attribute_data_vcn_offset *= io_handle->cluster_block_size;
328
648
      attribute_data_vcn_size   *= io_handle->cluster_block_size;
329
330
648
      if( ( calculated_attribute_data_vcn_offset != 0 )
331
648
       && ( calculated_attribute_data_vcn_offset != attribute_data_vcn_offset ) )
332
0
      {
333
0
        libcerror_error_set(
334
0
         error,
335
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
337
0
         "%s: invalid attribute data VCN offset value out of bounds.",
338
0
         function );
339
340
0
        goto on_error;
341
0
      }
342
648
      calculated_attribute_data_vcn_offset = attribute_data_vcn_offset + (off64_t) attribute_data_vcn_size;
343
648
    }
344
929
    if( libfsntfs_mft_attribute_get_number_of_data_runs(
345
929
         data_attribute,
346
929
         &number_of_data_runs,
347
929
         error ) != 1 )
348
0
    {
349
0
      libcerror_error_set(
350
0
       error,
351
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
352
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
353
0
       "%s: unable to retrieve attribute: %d number of data runs.",
354
0
       function,
355
0
       attribute_index );
356
357
0
      goto on_error;
358
0
    }
359
929
    for( data_run_index = 0;
360
42.0k
         data_run_index < number_of_data_runs;
361
41.1k
         data_run_index++ )
362
41.2k
    {
363
41.2k
      if( libfsntfs_mft_attribute_get_data_run_by_index(
364
41.2k
           data_attribute,
365
41.2k
           data_run_index,
366
41.2k
           &data_run,
367
41.2k
           error ) != 1 )
368
0
      {
369
0
        libcerror_error_set(
370
0
         error,
371
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
372
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
373
0
         "%s: unable to retrieve attribute: %d data run: %d.",
374
0
         function,
375
0
         attribute_index,
376
0
         data_run_index );
377
378
0
        goto on_error;
379
0
      }
380
41.2k
      if( data_run == NULL )
381
0
      {
382
0
        libcerror_error_set(
383
0
         error,
384
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
385
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
386
0
         "%s: missing attribute: %d data run: %d.",
387
0
         function,
388
0
         attribute_index,
389
0
         data_run_index );
390
391
0
        goto on_error;
392
0
      }
393
41.2k
      if( data_run->size > ( valid_data_size - data_segment_offset ) )
394
38.2k
      {
395
38.2k
        data_segment_size = valid_data_size - data_segment_offset;
396
38.2k
      }
397
2.93k
      else
398
2.93k
      {
399
2.93k
        data_segment_size = data_run->size;
400
2.93k
      }
401
41.2k
      if( (size64_t) data_segment_offset < valid_data_size )
402
3.30k
      {
403
3.30k
        if( libfdata_stream_append_segment(
404
3.30k
             safe_data_stream,
405
3.30k
             &segment_index,
406
3.30k
             0,
407
3.30k
             data_run->start_offset,
408
3.30k
             data_segment_size,
409
3.30k
             data_run->range_flags,
410
3.30k
             error ) != 1 )
411
54
        {
412
54
          libcerror_error_set(
413
54
           error,
414
54
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
415
54
           LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
416
54
           "%s: unable to append attribute: %d data run: %d data stream segment.",
417
54
           function,
418
54
           attribute_index,
419
54
           data_run_index );
420
421
54
          goto on_error;
422
54
        }
423
3.24k
        data_segment_offset += data_segment_size;
424
3.24k
      }
425
41.1k
      calculated_allocated_data_size += data_run->size;
426
41.1k
    }
427
875
    attribute_index++;
428
429
875
    if( libfsntfs_mft_attribute_get_next_attribute(
430
875
         data_attribute,
431
875
         &data_attribute,
432
875
         error ) != 1 )
433
0
    {
434
0
      libcerror_error_set(
435
0
       error,
436
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
437
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
438
0
       "%s: unable to retrieve next MFT attribute: %d.",
439
0
       function,
440
0
       attribute_index );
441
442
0
      goto on_error;
443
0
    }
444
875
  }
445
711
  if( calculated_allocated_data_size != stored_allocated_data_size )
446
141
  {
447
141
    libcerror_error_set(
448
141
     error,
449
141
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
450
141
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
451
141
     "%s: size of data runs: %" PRIu64 " does not match allocated data size: %" PRIu64 ".",
452
141
     function,
453
141
     calculated_allocated_data_size,
454
141
     stored_allocated_data_size );
455
456
141
    goto on_error;
457
141
  }
458
570
  if( (size64_t) data_segment_offset < data_size )
459
451
  {
460
451
    if( libfdata_stream_append_segment(
461
451
         safe_data_stream,
462
451
         &segment_index,
463
451
         0,
464
451
         0,
465
451
         data_size - data_segment_offset,
466
451
         LIBFDATA_RANGE_FLAG_IS_SPARSE,
467
451
         error ) != 1 )
468
134
    {
469
134
      libcerror_error_set(
470
134
       error,
471
134
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
472
134
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
473
134
       "%s: unable to append sparse data stream segment.",
474
134
       function );
475
476
134
      goto on_error;
477
134
    }
478
451
  }
479
436
  *cluster_block_stream = safe_data_stream;
480
481
436
  return( 1 );
482
483
701
on_error:
484
701
  if( safe_data_stream != NULL )
485
701
  {
486
701
    libfdata_stream_free(
487
701
     &safe_data_stream,
488
701
     NULL );
489
701
  }
490
701
  return( -1 );
491
570
}
492
493
/* Creates cluster block stream from compressed data runs
494
 * Make sure the value data_stream is referencing, is set to NULL
495
 * Returns 1 if successful or -1 on error
496
 */
497
int libfsntfs_cluster_block_stream_initialize_from_compressed_data_runs(
498
     libfdata_stream_t **cluster_block_stream,
499
     libfsntfs_io_handle_t *io_handle,
500
     libfsntfs_mft_attribute_t *data_attribute,
501
     size64_t data_size,
502
     libcerror_error_t **error )
503
2.11k
{
504
2.11k
  libfdata_stream_t *safe_data_stream                   = NULL;
505
2.11k
  libfsntfs_compressed_block_data_handle_t *data_handle = NULL;
506
2.11k
  static char *function                                 = "libfsntfs_cluster_block_stream_initialize_from_compressed_data_runs";
507
2.11k
  size64_t valid_data_size                              = 0;
508
2.11k
  int segment_index                                     = 0;
509
510
2.11k
  if( cluster_block_stream == NULL )
511
0
  {
512
0
    libcerror_error_set(
513
0
     error,
514
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
515
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
516
0
     "%s: invalid data stream.",
517
0
     function );
518
519
0
    return( -1 );
520
0
  }
521
2.11k
  if( libfsntfs_mft_attribute_get_valid_data_size(
522
2.11k
       data_attribute,
523
2.11k
       &valid_data_size,
524
2.11k
       error ) != 1 )
525
0
  {
526
0
    libcerror_error_set(
527
0
     error,
528
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
529
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
530
0
     "%s: unable to retrieve valid data size.",
531
0
     function );
532
533
0
    goto on_error;
534
0
  }
535
2.11k
  if( valid_data_size == 0 )
536
163
  {
537
163
    valid_data_size = data_size;
538
163
  }
539
2.11k
  if( libfsntfs_compressed_block_data_handle_initialize(
540
2.11k
       &data_handle,
541
2.11k
       io_handle,
542
2.11k
       data_attribute,
543
2.11k
       error ) != 1 )
544
828
  {
545
828
    libcerror_error_set(
546
828
     error,
547
828
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
548
828
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
549
828
     "%s: unable to create data handle.",
550
828
     function );
551
552
828
    goto on_error;
553
828
  }
554
1.29k
  if( libfdata_stream_initialize(
555
1.29k
       &safe_data_stream,
556
1.29k
       (intptr_t *) data_handle,
557
1.29k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compressed_block_data_handle_free,
558
1.29k
       NULL,
559
1.29k
       NULL,
560
1.29k
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_compressed_block_data_handle_read_segment_data,
561
1.29k
       NULL,
562
1.29k
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsntfs_compressed_block_data_handle_seek_segment_offset,
563
1.29k
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
564
1.29k
       error ) != 1 )
565
0
  {
566
0
    libcerror_error_set(
567
0
     error,
568
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
569
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
570
0
     "%s: unable to create data stream.",
571
0
     function );
572
573
0
    goto on_error;
574
0
  }
575
1.29k
  data_handle = NULL;
576
577
1.29k
  if( libfdata_stream_append_segment(
578
1.29k
       safe_data_stream,
579
1.29k
       &segment_index,
580
1.29k
       0,
581
1.29k
       0,
582
1.29k
       valid_data_size,
583
1.29k
       0,
584
1.29k
       error ) != 1 )
585
2
  {
586
2
    libcerror_error_set(
587
2
     error,
588
2
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
589
2
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
590
2
     "%s: unable to append data stream segment.",
591
2
     function );
592
593
2
    goto on_error;
594
2
  }
595
1.28k
  if( valid_data_size < data_size )
596
1.13k
  {
597
1.13k
    if( libfdata_stream_append_segment(
598
1.13k
         safe_data_stream,
599
1.13k
         &segment_index,
600
1.13k
         0,
601
1.13k
         0,
602
1.13k
         data_size - valid_data_size,
603
1.13k
         LIBFDATA_RANGE_FLAG_IS_SPARSE,
604
1.13k
         error ) != 1 )
605
125
    {
606
125
      libcerror_error_set(
607
125
       error,
608
125
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
609
125
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
610
125
       "%s: unable to append sparse data stream segment.",
611
125
       function );
612
613
125
      goto on_error;
614
125
    }
615
1.13k
  }
616
1.16k
  *cluster_block_stream = safe_data_stream;
617
618
1.16k
  return( 1 );
619
620
955
on_error:
621
955
  if( safe_data_stream != NULL )
622
127
  {
623
127
    libfdata_stream_free(
624
127
     &safe_data_stream,
625
127
     NULL );
626
127
  }
627
955
  if( data_handle != NULL )
628
0
  {
629
0
    libfsntfs_compressed_block_data_handle_free(
630
0
     &data_handle,
631
0
     NULL );
632
0
  }
633
955
  return( -1 );
634
1.28k
}
635
636
/* Creates cluster block stream from a compressed stream
637
 * Make sure the value data_stream is referencing, is set to NULL
638
 * Returns 1 if successful or -1 on error
639
 */
640
int libfsntfs_cluster_block_stream_initialize_from_compressed_stream(
641
     libfdata_stream_t **cluster_block_stream,
642
     libfdata_stream_t *compressed_data_stream,
643
     libfsntfs_mft_attribute_t *data_attribute,
644
     uint32_t compression_method,
645
     libcerror_error_t **error )
646
0
{
647
0
  libfdata_stream_t *safe_data_stream             = NULL;
648
0
  libfsntfs_compressed_data_handle_t *data_handle = NULL;
649
0
  static char *function                           = "libfsntfs_cluster_block_stream_initialize_from_compressed_stream";
650
0
  size64_t data_size                              = 0;
651
0
  size64_t valid_data_size                        = 0;
652
0
  int segment_index                               = 0;
653
654
0
  if( cluster_block_stream == NULL )
655
0
  {
656
0
    libcerror_error_set(
657
0
     error,
658
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
659
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
660
0
     "%s: invalid data stream.",
661
0
     function );
662
663
0
    return( -1 );
664
0
  }
665
0
  if( libfsntfs_mft_attribute_get_data_size(
666
0
       data_attribute,
667
0
       &data_size,
668
0
       error ) != 1 )
669
0
  {
670
0
    libcerror_error_set(
671
0
     error,
672
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
673
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
674
0
     "%s: unable to retrieve data size.",
675
0
     function );
676
677
0
    goto on_error;
678
0
  }
679
0
  if( libfsntfs_mft_attribute_get_valid_data_size(
680
0
       data_attribute,
681
0
       &valid_data_size,
682
0
       error ) != 1 )
683
0
  {
684
0
    libcerror_error_set(
685
0
     error,
686
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
687
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
688
0
     "%s: unable to retrieve valid data size.",
689
0
     function );
690
691
0
    goto on_error;
692
0
  }
693
0
  if( valid_data_size == 0 )
694
0
  {
695
0
    valid_data_size = data_size;
696
0
  }
697
0
  if( libfsntfs_compressed_data_handle_initialize(
698
0
       &data_handle,
699
0
       compressed_data_stream,
700
0
       compression_method,
701
0
       valid_data_size,
702
0
       error ) != 1 )
703
0
  {
704
0
    libcerror_error_set(
705
0
     error,
706
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
707
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
708
0
     "%s: unable to create data handle.",
709
0
     function );
710
711
0
    goto on_error;
712
0
  }
713
0
  if( libfdata_stream_initialize(
714
0
       &safe_data_stream,
715
0
       (intptr_t *) data_handle,
716
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsntfs_compressed_data_handle_free,
717
0
       NULL,
718
0
       NULL,
719
0
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsntfs_compressed_data_handle_read_segment_data,
720
0
       NULL,
721
0
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsntfs_compressed_data_handle_seek_segment_offset,
722
0
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
723
0
       error ) != 1 )
724
0
  {
725
0
    libcerror_error_set(
726
0
     error,
727
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
728
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
729
0
     "%s: unable to create data stream.",
730
0
     function );
731
732
0
    goto on_error;
733
0
  }
734
0
  data_handle = NULL;
735
736
0
  if( libfdata_stream_append_segment(
737
0
       safe_data_stream,
738
0
       &segment_index,
739
0
       0,
740
0
       0,
741
0
       valid_data_size,
742
0
       0,
743
0
       error ) != 1 )
744
0
  {
745
0
    libcerror_error_set(
746
0
     error,
747
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
748
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
749
0
     "%s: unable to append data stream segment.",
750
0
     function );
751
752
0
    goto on_error;
753
0
  }
754
0
  if( valid_data_size < data_size )
755
0
  {
756
0
    if( libfdata_stream_append_segment(
757
0
         safe_data_stream,
758
0
         &segment_index,
759
0
         0,
760
0
         0,
761
0
         data_size - valid_data_size,
762
0
         LIBFDATA_RANGE_FLAG_IS_SPARSE,
763
0
         error ) != 1 )
764
0
    {
765
0
      libcerror_error_set(
766
0
       error,
767
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
768
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
769
0
       "%s: unable to append sparse data stream segment.",
770
0
       function );
771
772
0
      goto on_error;
773
0
    }
774
0
  }
775
0
  *cluster_block_stream = safe_data_stream;
776
777
0
  return( 1 );
778
779
0
on_error:
780
0
  if( safe_data_stream != NULL )
781
0
  {
782
0
    libfdata_stream_free(
783
0
     &safe_data_stream,
784
0
     NULL );
785
0
  }
786
0
  if( data_handle != NULL )
787
0
  {
788
0
    libfsntfs_compressed_data_handle_free(
789
0
     &data_handle,
790
0
     NULL );
791
0
  }
792
0
  return( -1 );
793
0
}
794
795
/* Creates a cluster block stream
796
 * Make sure the value cluster_block_stream is referencing, is set to NULL
797
 * Returns 1 if successful or -1 on error
798
 */
799
int libfsntfs_cluster_block_stream_initialize(
800
     libfdata_stream_t **cluster_block_stream,
801
     libfsntfs_io_handle_t *io_handle,
802
     libfsntfs_mft_attribute_t *data_attribute,
803
     libfsntfs_mft_attribute_t *wof_compressed_data_attribute,
804
     uint32_t compression_method,
805
     libcerror_error_t **error )
806
4.90k
{
807
4.90k
  libfdata_stream_t *safe_cluster_block_stream = NULL;
808
4.90k
  libfsntfs_mft_attribute_t *mft_attribute     = NULL;
809
4.90k
  uint8_t *resident_data                       = NULL;
810
4.90k
  static char *function                        = "libfsntfs_cluster_block_stream_initialize";
811
4.90k
  size64_t data_size                           = 0;
812
4.90k
  size_t resident_data_size                    = 0;
813
4.90k
  uint16_t data_flags                          = 0;
814
4.90k
  int result                                   = 0;
815
816
4.90k
  if( cluster_block_stream == NULL )
817
0
  {
818
0
    libcerror_error_set(
819
0
     error,
820
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
821
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
822
0
     "%s: invalid cluster block stream.",
823
0
     function );
824
825
0
    return( -1 );
826
0
  }
827
4.90k
  if( wof_compressed_data_attribute == NULL )
828
4.90k
  {
829
4.90k
    mft_attribute = data_attribute;
830
4.90k
  }
831
0
  else
832
0
  {
833
0
    mft_attribute = wof_compressed_data_attribute;
834
0
  }
835
4.90k
  if( libfsntfs_mft_attribute_get_data_size(
836
4.90k
       mft_attribute,
837
4.90k
       &data_size,
838
4.90k
       error ) != 1 )
839
0
  {
840
0
    libcerror_error_set(
841
0
     error,
842
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
843
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
844
0
     "%s: unable to retrieve data size.",
845
0
     function );
846
847
0
    goto on_error;
848
0
  }
849
4.90k
  result = libfsntfs_mft_attribute_data_is_resident(
850
4.90k
            mft_attribute,
851
4.90k
            error );
852
853
4.90k
  if( result == -1 )
854
0
  {
855
0
    libcerror_error_set(
856
0
     error,
857
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
858
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
859
0
     "%s: unable to determine if attribute data is resident.",
860
0
     function );
861
862
0
    goto on_error;
863
0
  }
864
4.90k
  else if( result != 0 )
865
1.63k
  {
866
1.63k
    if( libfsntfs_mft_attribute_get_resident_data(
867
1.63k
         mft_attribute,
868
1.63k
         &resident_data,
869
1.63k
         &resident_data_size,
870
1.63k
         error ) != 1 )
871
0
    {
872
0
      libcerror_error_set(
873
0
       error,
874
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
875
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
876
0
       "%s: unable to retrieve resident data from attribute.",
877
0
       function );
878
879
0
      goto on_error;
880
0
    }
881
1.63k
  }
882
4.90k
  if( libfsntfs_mft_attribute_get_data_flags(
883
4.90k
       mft_attribute,
884
4.90k
       &data_flags,
885
4.90k
       error ) != 1 )
886
0
  {
887
0
    libcerror_error_set(
888
0
     error,
889
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
890
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
891
0
     "%s: unable to retrieve data flags from attribute.",
892
0
     function );
893
894
0
    goto on_error;
895
0
  }
896
4.90k
  if( ( resident_data != NULL )
897
4.90k
   || ( data_size == 0 ) )
898
1.64k
  {
899
1.64k
    if( data_size != (size64_t) resident_data_size )
900
0
    {
901
0
      libcerror_error_set(
902
0
       error,
903
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
904
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
905
0
       "%s: unuspported data size value out of bounds.",
906
0
       function );
907
908
0
      goto on_error;
909
0
    }
910
1.64k
    result = libfsntfs_cluster_block_stream_initialize_from_data(
911
1.64k
              &safe_cluster_block_stream,
912
1.64k
              resident_data,
913
1.64k
              resident_data_size,
914
1.64k
              error );
915
1.64k
  }
916
3.25k
  else if( ( data_flags & LIBFSNTFS_ATTRIBUTE_FLAG_COMPRESSION_MASK ) != 0 )
917
2.11k
  {
918
2.11k
    result = libfsntfs_cluster_block_stream_initialize_from_compressed_data_runs(
919
2.11k
              &safe_cluster_block_stream,
920
2.11k
              io_handle,
921
2.11k
              mft_attribute,
922
2.11k
              data_size,
923
2.11k
              error );
924
2.11k
  }
925
1.13k
  else
926
1.13k
  {
927
1.13k
    result = libfsntfs_cluster_block_stream_initialize_from_data_runs(
928
1.13k
              &safe_cluster_block_stream,
929
1.13k
              io_handle,
930
1.13k
              mft_attribute,
931
1.13k
              data_size,
932
1.13k
              error );
933
1.13k
  }
934
4.90k
  if( result != 1 )
935
1.65k
  {
936
1.65k
    libcerror_error_set(
937
1.65k
     error,
938
1.65k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
939
1.65k
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
940
1.65k
     "%s: unable to create cluster block stream.",
941
1.65k
     function );
942
943
1.65k
    goto on_error;
944
1.65k
  }
945
3.24k
  if( wof_compressed_data_attribute == NULL )
946
3.24k
  {
947
3.24k
    *cluster_block_stream = safe_cluster_block_stream;
948
3.24k
  }
949
0
  else
950
0
  {
951
0
    if( libfsntfs_cluster_block_stream_initialize_from_compressed_stream(
952
0
         cluster_block_stream,
953
0
         safe_cluster_block_stream,
954
0
         data_attribute,
955
0
         compression_method,
956
0
         error ) != 1 )
957
0
    {
958
0
      libcerror_error_set(
959
0
       error,
960
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
961
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
962
0
       "%s: unable to create cluster block stream.",
963
0
       function );
964
965
0
      goto on_error;
966
0
    }
967
0
  }
968
3.24k
  return( 1 );
969
970
1.65k
on_error:
971
1.65k
  if( safe_cluster_block_stream != NULL )
972
0
  {
973
0
    libfdata_stream_free(
974
0
     &safe_cluster_block_stream,
975
0
     NULL );
976
0
  }
977
1.65k
  return( -1 );
978
3.24k
}
979