Coverage Report

Created: 2025-06-22 07:35

/src/libfshfs/libfshfs/libfshfs_data_stream.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Data stream functions
3
 *
4
 * Copyright (C) 2009-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 "libfshfs_allocation_block_stream.h"
27
#include "libfshfs_data_stream.h"
28
#include "libfshfs_definitions.h"
29
#include "libfshfs_extent.h"
30
#include "libfshfs_file_system.h"
31
#include "libfshfs_fork_descriptor.h"
32
#include "libfshfs_io_handle.h"
33
#include "libfshfs_libbfio.h"
34
#include "libfshfs_libcdata.h"
35
#include "libfshfs_libcerror.h"
36
#include "libfshfs_libcthreads.h"
37
#include "libfshfs_libfdata.h"
38
#include "libfshfs_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
 */
44
int libfshfs_data_stream_initialize(
45
     libfshfs_data_stream_t **data_stream,
46
     libfshfs_io_handle_t *io_handle,
47
     libbfio_handle_t *file_io_handle,
48
     libfshfs_file_system_t *file_system,
49
     uint32_t identifier,
50
     libfshfs_fork_descriptor_t *fork_descriptor,
51
     uint8_t fork_type,
52
     libcerror_error_t **error )
53
0
{
54
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
55
0
  static char *function                                 = "libfshfs_data_stream_initialize";
56
57
0
  if( data_stream == NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
62
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
63
0
     "%s: invalid data stream.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
0
  if( *data_stream != NULL )
69
0
  {
70
0
    libcerror_error_set(
71
0
     error,
72
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
73
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
74
0
     "%s: invalid data stream value already set.",
75
0
     function );
76
77
0
    return( -1 );
78
0
  }
79
0
  if( ( fork_type != LIBFSHFS_FORK_TYPE_DATA )
80
0
   && ( fork_type != LIBFSHFS_FORK_TYPE_RESOURCE ) )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
85
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
86
0
     "%s: unsupported fork type.",
87
0
     function );
88
89
0
    return( -1 );
90
0
  }
91
0
  internal_data_stream = memory_allocate_structure(
92
0
                          libfshfs_internal_data_stream_t );
93
94
0
  if( internal_data_stream == NULL )
95
0
  {
96
0
    libcerror_error_set(
97
0
     error,
98
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
99
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
100
0
     "%s: unable to create data stream.",
101
0
     function );
102
103
0
    goto on_error;
104
0
  }
105
0
  if( memory_set(
106
0
       internal_data_stream,
107
0
       0,
108
0
       sizeof( libfshfs_internal_data_stream_t ) ) == NULL )
109
0
  {
110
0
    libcerror_error_set(
111
0
     error,
112
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
113
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
114
0
     "%s: unable to clear data stream.",
115
0
     function );
116
117
0
    memory_free(
118
0
     internal_data_stream );
119
120
0
    return( -1 );
121
0
  }
122
0
  if( libfshfs_file_system_get_extents(
123
0
       file_system,
124
0
       file_io_handle,
125
0
       identifier,
126
0
       fork_type,
127
0
       fork_descriptor,
128
0
       &( internal_data_stream->extents_array ),
129
0
       error ) != 1 )
130
0
  {
131
0
    libcerror_error_set(
132
0
     error,
133
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
134
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
135
0
     "%s: unable to retrieve extents of data stream.",
136
0
     function );
137
138
0
    goto on_error;
139
0
  }
140
0
  if( libfshfs_allocation_block_stream_initialize_from_extents(
141
0
       &( internal_data_stream->allocation_block_stream ),
142
0
       io_handle,
143
0
       internal_data_stream->extents_array,
144
0
       (size64_t) fork_descriptor->size,
145
0
       error ) != 1 )
146
0
  {
147
0
    libcerror_error_set(
148
0
     error,
149
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
150
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
151
0
     "%s: unable to create data stream.",
152
0
     function );
153
154
0
    goto on_error;
155
0
  }
156
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
157
0
  if( libcthreads_read_write_lock_initialize(
158
0
       &( internal_data_stream->read_write_lock ),
159
0
       error ) != 1 )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
164
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
165
0
     "%s: unable to initialize read/write lock.",
166
0
     function );
167
168
0
    goto on_error;
169
0
  }
170
0
#endif
171
0
  internal_data_stream->io_handle      = io_handle;
172
0
  internal_data_stream->file_io_handle = file_io_handle;
173
174
0
  *data_stream = (libfshfs_data_stream_t *) internal_data_stream;
175
176
0
  return( 1 );
177
178
0
on_error:
179
0
  if( internal_data_stream != NULL )
180
0
  {
181
0
    if( internal_data_stream->allocation_block_stream != NULL )
182
0
    {
183
0
      libfdata_stream_free(
184
0
       &( internal_data_stream->allocation_block_stream ),
185
0
       NULL );
186
0
    }
187
0
    if( internal_data_stream->extents_array != NULL )
188
0
    {
189
0
      libcdata_array_free(
190
0
       &( internal_data_stream->extents_array ),
191
0
       (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_extent_free,
192
0
       NULL );
193
0
    }
194
0
    memory_free(
195
0
     internal_data_stream );
196
0
  }
197
0
  return( -1 );
198
0
}
199
200
/* Frees a data stream
201
 * Returns 1 if successful or -1 on error
202
 */
203
int libfshfs_data_stream_free(
204
     libfshfs_data_stream_t **data_stream,
205
     libcerror_error_t **error )
206
0
{
207
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
208
0
  static char *function                                 = "libfshfs_data_stream_free";
209
0
  int result                                            = 1;
210
211
0
  if( data_stream == NULL )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
217
0
     "%s: invalid data stream.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
222
0
  if( *data_stream != NULL )
223
0
  {
224
0
    internal_data_stream = (libfshfs_internal_data_stream_t *) *data_stream;
225
0
    *data_stream         = NULL;
226
227
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
228
0
    if( libcthreads_read_write_lock_free(
229
0
         &( internal_data_stream->read_write_lock ),
230
0
         error ) != 1 )
231
0
    {
232
0
      libcerror_error_set(
233
0
       error,
234
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
235
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
236
0
       "%s: unable to free read/write lock.",
237
0
       function );
238
239
0
      result = -1;
240
0
    }
241
0
#endif
242
    /* The file_io_handle reference is freed elsewhere
243
     */
244
0
    if( libfdata_stream_free(
245
0
         &( internal_data_stream->allocation_block_stream ),
246
0
         error ) != 1 )
247
0
    {
248
0
      libcerror_error_set(
249
0
       error,
250
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
251
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
252
0
       "%s: unable to free allocation block stream.",
253
0
       function );
254
255
0
      result = -1;
256
0
    }
257
0
    if( libcdata_array_free(
258
0
         &( internal_data_stream->extents_array ),
259
0
         (int (*)(intptr_t **, libcerror_error_t **)) &libfshfs_extent_free,
260
0
         error ) != 1 )
261
0
    {
262
0
      libcerror_error_set(
263
0
       error,
264
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
265
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
266
0
       "%s: unable to free extents array.",
267
0
       function );
268
269
0
      result = -1;
270
0
    }
271
0
    memory_free(
272
0
     internal_data_stream );
273
0
  }
274
0
  return( result );
275
0
}
276
277
/* Reads data at the current offset
278
 * Returns the number of bytes read or -1 on error
279
 */
280
ssize_t libfshfs_data_stream_read_buffer(
281
         libfshfs_data_stream_t *data_stream,
282
         void *buffer,
283
         size_t buffer_size,
284
         libcerror_error_t **error )
285
0
{
286
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
287
0
  static char *function                                 = "libfshfs_data_stream_read_buffer";
288
0
  ssize_t read_count                                    = 0;
289
290
0
  if( data_stream == NULL )
291
0
  {
292
0
    libcerror_error_set(
293
0
     error,
294
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
295
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
296
0
     "%s: invalid data stream.",
297
0
     function );
298
299
0
    return( -1 );
300
0
  }
301
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
302
303
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
304
0
  if( libcthreads_read_write_lock_grab_for_write(
305
0
       internal_data_stream->read_write_lock,
306
0
       error ) != 1 )
307
0
  {
308
0
    libcerror_error_set(
309
0
     error,
310
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
311
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
312
0
     "%s: unable to grab read/write lock for writing.",
313
0
     function );
314
315
0
    return( -1 );
316
0
  }
317
0
#endif
318
0
  read_count = libfdata_stream_read_buffer(
319
0
                internal_data_stream->allocation_block_stream,
320
0
                (intptr_t *) internal_data_stream->file_io_handle,
321
0
                buffer,
322
0
                buffer_size,
323
0
                0,
324
0
                error );
325
326
0
  if( read_count < 0 )
327
0
  {
328
0
    libcerror_error_set(
329
0
     error,
330
0
     LIBCERROR_ERROR_DOMAIN_IO,
331
0
     LIBCERROR_IO_ERROR_READ_FAILED,
332
0
     "%s: unable to read from allocation block stream.",
333
0
     function );
334
335
0
    read_count = -1;
336
0
  }
337
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
338
0
  if( libcthreads_read_write_lock_release_for_write(
339
0
       internal_data_stream->read_write_lock,
340
0
       error ) != 1 )
341
0
  {
342
0
    libcerror_error_set(
343
0
     error,
344
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
345
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
346
0
     "%s: unable to release read/write lock for writing.",
347
0
     function );
348
349
0
    return( -1 );
350
0
  }
351
0
#endif
352
0
  return( read_count );
353
0
}
354
355
/* Reads data at a specific offset
356
 * Returns the number of bytes read or -1 on error
357
 */
358
ssize_t libfshfs_data_stream_read_buffer_at_offset(
359
         libfshfs_data_stream_t *data_stream,
360
         void *buffer,
361
         size_t buffer_size,
362
         off64_t offset,
363
         libcerror_error_t **error )
364
0
{
365
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
366
0
  static char *function                                 = "libfshfs_data_stream_read_buffer_at_offset";
367
0
  ssize_t read_count                                    = 0;
368
369
0
  if( data_stream == NULL )
370
0
  {
371
0
    libcerror_error_set(
372
0
     error,
373
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
374
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
375
0
     "%s: invalid data stream.",
376
0
     function );
377
378
0
    return( -1 );
379
0
  }
380
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
381
382
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
383
0
  if( libcthreads_read_write_lock_grab_for_write(
384
0
       internal_data_stream->read_write_lock,
385
0
       error ) != 1 )
386
0
  {
387
0
    libcerror_error_set(
388
0
     error,
389
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
390
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
391
0
     "%s: unable to grab read/write lock for writing.",
392
0
     function );
393
394
0
    return( -1 );
395
0
  }
396
0
#endif
397
0
  read_count = libfdata_stream_read_buffer_at_offset(
398
0
                internal_data_stream->allocation_block_stream,
399
0
                (intptr_t *) internal_data_stream->file_io_handle,
400
0
                buffer,
401
0
                buffer_size,
402
0
                offset,
403
0
                0,
404
0
                error );
405
406
0
  if( read_count < 0 )
407
0
  {
408
0
    libcerror_error_set(
409
0
     error,
410
0
     LIBCERROR_ERROR_DOMAIN_IO,
411
0
     LIBCERROR_IO_ERROR_READ_FAILED,
412
0
     "%s: unable to read from allocation block stream.",
413
0
     function );
414
415
0
    read_count = -1;
416
0
  }
417
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
418
0
  if( libcthreads_read_write_lock_release_for_write(
419
0
       internal_data_stream->read_write_lock,
420
0
       error ) != 1 )
421
0
  {
422
0
    libcerror_error_set(
423
0
     error,
424
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
425
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
426
0
     "%s: unable to release read/write lock for writing.",
427
0
     function );
428
429
0
    return( -1 );
430
0
  }
431
0
#endif
432
0
  return( read_count );
433
0
}
434
435
/* Seeks a certain offset
436
 * Returns the offset if seek is successful or -1 on error
437
 */
438
off64_t libfshfs_data_stream_seek_offset(
439
         libfshfs_data_stream_t *data_stream,
440
         off64_t offset,
441
         int whence,
442
         libcerror_error_t **error )
443
0
{
444
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
445
0
  static char *function                                 = "libfshfs_data_stream_seek_offset";
446
447
0
  if( data_stream == NULL )
448
0
  {
449
0
    libcerror_error_set(
450
0
     error,
451
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
452
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
453
0
     "%s: invalid data stream.",
454
0
     function );
455
456
0
    return( -1 );
457
0
  }
458
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
459
460
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
461
0
  if( libcthreads_read_write_lock_grab_for_write(
462
0
       internal_data_stream->read_write_lock,
463
0
       error ) != 1 )
464
0
  {
465
0
    libcerror_error_set(
466
0
     error,
467
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
468
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
469
0
     "%s: unable to grab read/write lock for writing.",
470
0
     function );
471
472
0
    return( -1 );
473
0
  }
474
0
#endif
475
0
  offset = libfdata_stream_seek_offset(
476
0
            internal_data_stream->allocation_block_stream,
477
0
            offset,
478
0
            whence,
479
0
            error );
480
481
0
  if( offset == -1 )
482
0
  {
483
0
    libcerror_error_set(
484
0
     error,
485
0
     LIBCERROR_ERROR_DOMAIN_IO,
486
0
     LIBCERROR_IO_ERROR_SEEK_FAILED,
487
0
     "%s: unable to seek offset in allocation block stream.",
488
0
     function );
489
490
0
    offset = -1;
491
0
  }
492
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
493
0
  if( libcthreads_read_write_lock_release_for_write(
494
0
       internal_data_stream->read_write_lock,
495
0
       error ) != 1 )
496
0
  {
497
0
    libcerror_error_set(
498
0
     error,
499
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
500
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
501
0
     "%s: unable to release read/write lock for writing.",
502
0
     function );
503
504
0
    return( -1 );
505
0
  }
506
0
#endif
507
0
  return( offset );
508
0
}
509
510
/* Retrieves the current offset
511
 * Returns the offset if successful or -1 on error
512
 */
513
int libfshfs_data_stream_get_offset(
514
     libfshfs_data_stream_t *data_stream,
515
     off64_t *offset,
516
     libcerror_error_t **error )
517
0
{
518
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
519
0
  static char *function                                 = "libfshfs_data_stream_get_offset";
520
0
  int result                                            = 1;
521
522
0
  if( data_stream == NULL )
523
0
  {
524
0
    libcerror_error_set(
525
0
     error,
526
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
527
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
528
0
     "%s: invalid data stream.",
529
0
     function );
530
531
0
    return( -1 );
532
0
  }
533
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
534
535
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
536
0
  if( libcthreads_read_write_lock_grab_for_read(
537
0
       internal_data_stream->read_write_lock,
538
0
       error ) != 1 )
539
0
  {
540
0
    libcerror_error_set(
541
0
     error,
542
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
543
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
544
0
     "%s: unable to grab read/write lock for reading.",
545
0
     function );
546
547
0
    return( -1 );
548
0
  }
549
0
#endif
550
0
  if( libfdata_stream_get_offset(
551
0
       internal_data_stream->allocation_block_stream,
552
0
       offset,
553
0
       error ) != 1 )
554
0
  {
555
0
    libcerror_error_set(
556
0
     error,
557
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
558
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
559
0
     "%s: unable to retrieve offset from allocation block stream.",
560
0
     function );
561
562
0
    result = -1;
563
0
  }
564
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
565
0
  if( libcthreads_read_write_lock_release_for_read(
566
0
       internal_data_stream->read_write_lock,
567
0
       error ) != 1 )
568
0
  {
569
0
    libcerror_error_set(
570
0
     error,
571
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
572
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
573
0
     "%s: unable to release read/write lock for reading.",
574
0
     function );
575
576
0
    return( -1 );
577
0
  }
578
0
#endif
579
0
  return( result );
580
0
}
581
582
/* Retrieves the size
583
 * Returns 1 if successful or -1 on error
584
 */
585
int libfshfs_data_stream_get_size(
586
     libfshfs_data_stream_t *data_stream,
587
     size64_t *size,
588
     libcerror_error_t **error )
589
0
{
590
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
591
0
  static char *function                                 = "libfshfs_data_stream_get_size";
592
0
  int result                                            = 1;
593
594
0
  if( data_stream == NULL )
595
0
  {
596
0
    libcerror_error_set(
597
0
     error,
598
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
599
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
600
0
     "%s: invalid data stream.",
601
0
     function );
602
603
0
    return( -1 );
604
0
  }
605
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
606
607
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
608
0
  if( libcthreads_read_write_lock_grab_for_read(
609
0
       internal_data_stream->read_write_lock,
610
0
       error ) != 1 )
611
0
  {
612
0
    libcerror_error_set(
613
0
     error,
614
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
615
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
616
0
     "%s: unable to grab read/write lock for reading.",
617
0
     function );
618
619
0
    return( -1 );
620
0
  }
621
0
#endif
622
0
  if( libfdata_stream_get_size(
623
0
       internal_data_stream->allocation_block_stream,
624
0
       size,
625
0
       error ) != 1 )
626
0
  {
627
0
    libcerror_error_set(
628
0
     error,
629
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
630
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
631
0
     "%s: unable to retrieve size from allocation block stream.",
632
0
     function );
633
634
0
    result = -1;
635
0
  }
636
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
637
0
  if( libcthreads_read_write_lock_release_for_read(
638
0
       internal_data_stream->read_write_lock,
639
0
       error ) != 1 )
640
0
  {
641
0
    libcerror_error_set(
642
0
     error,
643
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
644
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
645
0
     "%s: unable to release read/write lock for reading.",
646
0
     function );
647
648
0
    return( -1 );
649
0
  }
650
0
#endif
651
0
  return( result );
652
0
}
653
654
/* Retrieves the number of extents (decoded data runs)
655
 * Returns 1 if successful or -1 on error
656
 */
657
int libfshfs_data_stream_get_number_of_extents(
658
     libfshfs_data_stream_t *data_stream,
659
     int *number_of_extents,
660
     libcerror_error_t **error )
661
0
{
662
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
663
0
  static char *function                                 = "libfshfs_data_stream_get_number_of_extents";
664
0
  int result                                            = 1;
665
666
0
  if( data_stream == NULL )
667
0
  {
668
0
    libcerror_error_set(
669
0
     error,
670
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
671
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
672
0
     "%s: invalid data stream.",
673
0
     function );
674
675
0
    return( -1 );
676
0
  }
677
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
678
679
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
680
0
  if( libcthreads_read_write_lock_grab_for_read(
681
0
       internal_data_stream->read_write_lock,
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_SET_FAILED,
688
0
     "%s: unable to grab read/write lock for reading.",
689
0
     function );
690
691
0
    return( -1 );
692
0
  }
693
0
#endif
694
0
  if( libcdata_array_get_number_of_entries(
695
0
       internal_data_stream->extents_array,
696
0
       number_of_extents,
697
0
       error ) != 1 )
698
0
  {
699
0
    libcerror_error_set(
700
0
     error,
701
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
702
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
703
0
     "%s: unable to retrieve number of extents.",
704
0
     function );
705
706
0
    result = -1;
707
0
  }
708
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
709
0
  if( libcthreads_read_write_lock_release_for_read(
710
0
       internal_data_stream->read_write_lock,
711
0
       error ) != 1 )
712
0
  {
713
0
    libcerror_error_set(
714
0
     error,
715
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
716
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
717
0
     "%s: unable to release read/write lock for reading.",
718
0
     function );
719
720
0
    return( -1 );
721
0
  }
722
0
#endif
723
0
  return( result );
724
0
}
725
726
/* Retrieves a specific extent (decoded data run)
727
 * Returns 1 if successful or -1 on error
728
 */
729
int libfshfs_data_stream_get_extent_by_index(
730
     libfshfs_data_stream_t *data_stream,
731
     int extent_index,
732
     off64_t *extent_offset,
733
     size64_t *extent_size,
734
     uint32_t *extent_flags,
735
     libcerror_error_t **error )
736
0
{
737
0
  libfshfs_extent_t *data_extent                        = NULL;
738
0
  libfshfs_internal_data_stream_t *internal_data_stream = NULL;
739
0
  static char *function                                 = "libfshfs_data_stream_get_extent_by_index";
740
0
  int result                                            = 1;
741
742
0
  if( data_stream == NULL )
743
0
  {
744
0
    libcerror_error_set(
745
0
     error,
746
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
747
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
748
0
     "%s: invalid data stream.",
749
0
     function );
750
751
0
    return( -1 );
752
0
  }
753
0
  internal_data_stream = (libfshfs_internal_data_stream_t *) data_stream;
754
755
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
756
0
  if( libcthreads_read_write_lock_grab_for_read(
757
0
       internal_data_stream->read_write_lock,
758
0
       error ) != 1 )
759
0
  {
760
0
    libcerror_error_set(
761
0
     error,
762
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
763
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
764
0
     "%s: unable to grab read/write lock for reading.",
765
0
     function );
766
767
0
    return( -1 );
768
0
  }
769
0
#endif
770
0
  if( libcdata_array_get_entry_by_index(
771
0
       internal_data_stream->extents_array,
772
0
       extent_index,
773
0
       (intptr_t **) &data_extent,
774
0
       error ) != 1 )
775
0
  {
776
0
    libcerror_error_set(
777
0
     error,
778
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
779
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
780
0
     "%s: unable to retrieve extent: %d.",
781
0
     function,
782
0
     extent_index );
783
784
0
    result = -1;
785
0
  }
786
0
  if( result == 1 )
787
0
  {
788
0
    if( libfshfs_extent_get_values(
789
0
         data_extent,
790
0
         internal_data_stream->io_handle,
791
0
         extent_offset,
792
0
         extent_size,
793
0
         extent_flags,
794
0
         error ) != 1 )
795
0
    {
796
0
      libcerror_error_set(
797
0
       error,
798
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
799
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
800
0
       "%s: unable to retrieve extent: %d values.",
801
0
       function,
802
0
       extent_index );
803
804
0
      result = -1;
805
0
    }
806
0
  }
807
0
#if defined( HAVE_LIBFSHFS_MULTI_THREAD_SUPPORT )
808
0
  if( libcthreads_read_write_lock_release_for_read(
809
0
       internal_data_stream->read_write_lock,
810
0
       error ) != 1 )
811
0
  {
812
0
    libcerror_error_set(
813
0
     error,
814
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
815
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
816
0
     "%s: unable to release read/write lock for reading.",
817
0
     function );
818
819
0
    return( -1 );
820
0
  }
821
0
#endif
822
0
  return( result );
823
0
}
824