Coverage Report

Created: 2026-01-13 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_data_stream.c
Line
Count
Source
1
/*
2
 * Data stream functions
3
 *
4
 * Copyright (C) 2020-2025, 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 "libfsxfs_block_data_handle.h"
26
#include "libfsxfs_buffer_data_handle.h"
27
#include "libfsxfs_definitions.h"
28
#include "libfsxfs_extent.h"
29
#include "libfsxfs_inode.h"
30
#include "libfsxfs_io_handle.h"
31
#include "libfsxfs_libcerror.h"
32
#include "libfsxfs_libcnotify.h"
33
#include "libfsxfs_libfdata.h"
34
35
/* Creates data data stream from a buffer of data
36
 * Make sure the value data_stream is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libfsxfs_data_stream_initialize_from_data(
40
     libfdata_stream_t **data_stream,
41
     const uint8_t *data,
42
     size64_t data_size,
43
     libcerror_error_t **error )
44
105
{
45
105
  libfdata_stream_t *safe_data_stream        = NULL;
46
105
  libfsxfs_buffer_data_handle_t *data_handle = NULL;
47
105
  static char *function                      = "libfsxfs_data_stream_initialize_from_data";
48
105
  int segment_index                          = 0;
49
50
105
  if( data_stream == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid data data stream.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
105
  if( libfsxfs_buffer_data_handle_initialize(
62
105
       &data_handle,
63
105
       data,
64
105
       data_size,
65
105
       error ) != 1 )
66
0
  {
67
0
    libcerror_error_set(
68
0
     error,
69
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
70
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
71
0
     "%s: unable to create buffer data handle.",
72
0
     function );
73
74
0
    goto on_error;
75
0
  }
76
105
  if( libfdata_stream_initialize(
77
105
       &safe_data_stream,
78
105
       (intptr_t *) data_handle,
79
105
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_buffer_data_handle_free,
80
105
       NULL,
81
105
       NULL,
82
105
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsxfs_buffer_data_handle_read_segment_data,
83
105
       NULL,
84
105
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsxfs_buffer_data_handle_seek_segment_offset,
85
105
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
86
105
       error ) != 1 )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
91
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
92
0
     "%s: unable to create data stream.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
105
  data_handle = NULL;
98
99
105
  if( libfdata_stream_append_segment(
100
105
       safe_data_stream,
101
105
       &segment_index,
102
105
       0,
103
105
       0,
104
105
       (size64_t) data_size,
105
105
       0,
106
105
       error ) != 1 )
107
0
  {
108
0
    libcerror_error_set(
109
0
     error,
110
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
111
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
112
0
     "%s: unable to append data stream segment.",
113
0
     function );
114
115
0
    goto on_error;
116
0
  }
117
105
  *data_stream = safe_data_stream;
118
119
105
  return( 1 );
120
121
0
on_error:
122
0
  if( safe_data_stream != NULL )
123
0
  {
124
0
    libfdata_stream_free(
125
0
     &safe_data_stream,
126
0
     NULL );
127
0
  }
128
0
  if( data_handle != NULL )
129
0
  {
130
0
    libfsxfs_buffer_data_handle_free(
131
0
     &data_handle,
132
0
     NULL );
133
0
  }
134
0
  return( -1 );
135
105
}
136
137
/* Creates data data stream from extents
138
 * Make sure the value data_stream is referencing, is set to NULL
139
 * Returns 1 if successful or -1 on error
140
 */
141
int libfsxfs_data_stream_initialize_from_extents(
142
     libfdata_stream_t **data_stream,
143
     libfsxfs_io_handle_t *io_handle,
144
     libfsxfs_inode_t *inode,
145
     size64_t data_size,
146
     libcerror_error_t **error )
147
429
{
148
429
  libfdata_stream_t *safe_data_stream = NULL;
149
429
  libfsxfs_extent_t *extent           = NULL;
150
429
  static char *function               = "libfsxfs_data_stream_initialize_from_extents";
151
429
  size64_t data_segment_size          = 0;
152
429
  off64_t data_segment_offset         = 0;
153
429
  uint64_t relative_block_number      = 0;
154
429
  int allocation_group_index          = 0;
155
429
  int extent_index                    = 0;
156
429
  int number_of_extents               = 0;
157
429
  int segment_index                   = 0;
158
159
429
  if( data_stream == NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
164
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
165
0
     "%s: invalid data stream.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
429
  if( io_handle == NULL )
171
0
  {
172
0
    libcerror_error_set(
173
0
     error,
174
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
175
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
176
0
     "%s: invalid IO handle.",
177
0
     function );
178
179
0
    return( -1 );
180
0
  }
181
429
  if( io_handle->allocation_group_size == 0 )
182
0
  {
183
0
    libcerror_error_set(
184
0
     error,
185
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
186
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
187
0
     "%s: invalid IO handle - allocation group size value out of bounds.",
188
0
     function );
189
190
0
    return( -1 );
191
0
  }
192
429
  if( io_handle->block_size == 0 )
193
0
  {
194
0
    libcerror_error_set(
195
0
     error,
196
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
197
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
198
0
     "%s: invalid IO handle - block size value out of bounds.",
199
0
     function );
200
201
0
    return( -1 );
202
0
  }
203
429
  if( libfdata_stream_initialize(
204
429
       &safe_data_stream,
205
429
       NULL,
206
429
       NULL,
207
429
       NULL,
208
429
       NULL,
209
429
       (ssize_t (*)(intptr_t *, intptr_t *, int, int, uint8_t *, size_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsxfs_block_data_handle_read_segment_data,
210
429
       NULL,
211
429
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsxfs_block_data_handle_seek_segment_offset,
212
429
       0,
213
429
       error ) != 1 )
214
0
  {
215
0
    libcerror_error_set(
216
0
     error,
217
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
218
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
219
0
     "%s: unable to create data stream.",
220
0
     function );
221
222
0
    goto on_error;
223
0
  }
224
429
  if( libfsxfs_inode_get_number_of_data_extents(
225
429
       inode,
226
429
       &number_of_extents,
227
429
       error ) != 1 )
228
0
  {
229
0
    libcerror_error_set(
230
0
     error,
231
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
232
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
233
0
     "%s: unable to retrieve number of data extents.",
234
0
     function );
235
236
0
    goto on_error;
237
0
  }
238
429
  for( extent_index = 0;
239
15.8k
       extent_index < number_of_extents;
240
15.4k
       extent_index++ )
241
15.4k
  {
242
15.4k
    if( libfsxfs_inode_get_data_extent_by_index(
243
15.4k
         inode,
244
15.4k
         extent_index,
245
15.4k
         &extent,
246
15.4k
         error ) != 1 )
247
0
    {
248
0
      libcerror_error_set(
249
0
       error,
250
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
251
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
252
0
       "%s: unable to retrieve data extent: %d.",
253
0
       function,
254
0
       extent_index );
255
256
0
      goto on_error;
257
0
    }
258
15.4k
    if( extent == NULL )
259
0
    {
260
0
      libcerror_error_set(
261
0
       error,
262
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
263
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
264
0
       "%s: missing extent: %d.",
265
0
       function,
266
0
       extent_index );
267
268
0
      goto on_error;
269
0
    }
270
15.4k
    allocation_group_index = (int) ( extent->physical_block_number >> io_handle->number_of_relative_block_number_bits );
271
15.4k
    relative_block_number  = extent->physical_block_number & ( ( 1 << io_handle->number_of_relative_block_number_bits ) - 1 );
272
273
#if defined( HAVE_DEBUG_OUTPUT )
274
    if( libcnotify_verbose != 0 )
275
    {
276
      libcnotify_printf(
277
       "%s: extent: %d allocation group index\t: %d\n",
278
       function,
279
       extent_index,
280
       allocation_group_index );
281
282
      libcnotify_printf(
283
       "%s: extent: %d relative block number\t: %" PRIu64 "\n",
284
       function,
285
       extent_index,
286
       relative_block_number );
287
288
      libcnotify_printf(
289
       "\n" );
290
    }
291
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
292
293
15.4k
    data_segment_offset = ( ( (off64_t) allocation_group_index * io_handle->allocation_group_size ) + relative_block_number ) * io_handle->block_size;
294
15.4k
    data_segment_size   = (size64_t) extent->number_of_blocks * io_handle->block_size;
295
296
15.4k
    if( libfdata_stream_append_segment(
297
15.4k
         safe_data_stream,
298
15.4k
         &segment_index,
299
15.4k
         0,
300
15.4k
         data_segment_offset,
301
15.4k
         data_segment_size,
302
15.4k
         extent->range_flags,
303
15.4k
         error ) != 1 )
304
81
    {
305
81
      libcerror_error_set(
306
81
       error,
307
81
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
308
81
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
309
81
       "%s: unable to append extent: %d data stream segment.",
310
81
       function,
311
81
       extent_index );
312
313
81
      goto on_error;
314
81
    }
315
15.4k
  }
316
348
  if( libfdata_stream_set_mapped_size(
317
348
       safe_data_stream,
318
348
       data_size,
319
348
       error ) != 1 )
320
123
  {
321
123
    libcerror_error_set(
322
123
     error,
323
123
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
324
123
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
325
123
     "%s: unable to set mapped size of data stream.",
326
123
     function );
327
328
123
    goto on_error;
329
123
  }
330
225
  *data_stream = safe_data_stream;
331
332
225
  return( 1 );
333
334
204
on_error:
335
204
  if( safe_data_stream != NULL )
336
204
  {
337
204
    libfdata_stream_free(
338
204
     &safe_data_stream,
339
204
     NULL );
340
204
  }
341
204
  return( -1 );
342
348
}
343
344
/* Creates a data stream
345
 * Make sure the value data_stream is referencing, is set to NULL
346
 * Returns 1 if successful or -1 on error
347
 */
348
int libfsxfs_data_stream_initialize(
349
     libfdata_stream_t **data_stream,
350
     libfsxfs_io_handle_t *io_handle,
351
     libfsxfs_inode_t *inode,
352
     size64_t data_size,
353
     libcerror_error_t **error )
354
545
{
355
545
  libfdata_stream_t *safe_data_stream = NULL;
356
545
  static char *function               = "libfsxfs_data_stream_initialize";
357
545
  int result                          = 0;
358
359
545
  if( data_stream == NULL )
360
0
  {
361
0
    libcerror_error_set(
362
0
     error,
363
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
364
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
365
0
     "%s: invalid data stream.",
366
0
     function );
367
368
0
    return( -1 );
369
0
  }
370
545
  if( inode == NULL )
371
0
  {
372
0
    libcerror_error_set(
373
0
     error,
374
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
375
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
376
0
     "%s: invalid inode.",
377
0
     function );
378
379
0
    return( -1 );
380
0
  }
381
545
  if( ( inode->fork_type != LIBFSXFS_FORK_TYPE_INLINE_DATA )
382
444
   && ( inode->fork_type != LIBFSXFS_FORK_TYPE_EXTENTS )
383
68
   && ( inode->fork_type != LIBFSXFS_FORK_TYPE_BTREE ) )
384
11
  {
385
11
    libcerror_error_set(
386
11
     error,
387
11
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
388
11
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
389
11
     "%s: unsupported directory data fork type.",
390
11
     function );
391
392
11
    return( -1 );
393
11
  }
394
534
  if( ( data_size == 0 )
395
530
   || ( inode->fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA ) )
396
105
  {
397
105
    result = libfsxfs_data_stream_initialize_from_data(
398
105
              &safe_data_stream,
399
105
              inode->inline_data,
400
105
              (size_t) data_size,
401
105
              error );
402
105
  }
403
429
  else
404
429
  {
405
429
    result = libfsxfs_data_stream_initialize_from_extents(
406
429
              &safe_data_stream,
407
429
              io_handle,
408
429
              inode,
409
429
              data_size,
410
429
              error );
411
429
  }
412
534
  if( result != 1 )
413
204
  {
414
204
    libcerror_error_set(
415
204
     error,
416
204
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
417
204
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
418
204
     "%s: unable to create data stream.",
419
204
     function );
420
421
204
    goto on_error;
422
204
  }
423
330
  *data_stream = safe_data_stream;
424
425
330
  return( 1 );
426
427
204
on_error:
428
204
  if( safe_data_stream != NULL )
429
0
  {
430
0
    libfdata_stream_free(
431
0
     &safe_data_stream,
432
     NULL );
433
0
  }
434
204
  return( -1 );
435
534
}
436