Coverage Report

Created: 2026-01-20 07:11

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
103
{
45
103
  libfdata_stream_t *safe_data_stream        = NULL;
46
103
  libfsxfs_buffer_data_handle_t *data_handle = NULL;
47
103
  static char *function                      = "libfsxfs_data_stream_initialize_from_data";
48
103
  int segment_index                          = 0;
49
50
103
  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
103
  if( libfsxfs_buffer_data_handle_initialize(
62
103
       &data_handle,
63
103
       data,
64
103
       data_size,
65
103
       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
103
  if( libfdata_stream_initialize(
77
103
       &safe_data_stream,
78
103
       (intptr_t *) data_handle,
79
103
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_buffer_data_handle_free,
80
103
       NULL,
81
103
       NULL,
82
103
       (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
103
       NULL,
84
103
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsxfs_buffer_data_handle_seek_segment_offset,
85
103
       LIBFDATA_DATA_HANDLE_FLAG_MANAGED,
86
103
       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
103
  data_handle = NULL;
98
99
103
  if( libfdata_stream_append_segment(
100
103
       safe_data_stream,
101
103
       &segment_index,
102
103
       0,
103
103
       0,
104
103
       (size64_t) data_size,
105
103
       0,
106
103
       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
103
  *data_stream = safe_data_stream;
118
119
103
  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
103
}
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
438
{
148
438
  libfdata_stream_t *safe_data_stream = NULL;
149
438
  libfsxfs_extent_t *extent           = NULL;
150
438
  static char *function               = "libfsxfs_data_stream_initialize_from_extents";
151
438
  size64_t data_segment_size          = 0;
152
438
  off64_t data_segment_offset         = 0;
153
438
  uint64_t relative_block_number      = 0;
154
438
  int allocation_group_index          = 0;
155
438
  int extent_index                    = 0;
156
438
  int number_of_extents               = 0;
157
438
  int segment_index                   = 0;
158
159
438
  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
438
  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
438
  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
438
  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
438
  if( libfdata_stream_initialize(
204
438
       &safe_data_stream,
205
438
       NULL,
206
438
       NULL,
207
438
       NULL,
208
438
       NULL,
209
438
       (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
438
       NULL,
211
438
       (off64_t (*)(intptr_t *, intptr_t *, int, int, off64_t, libcerror_error_t **)) &libfsxfs_block_data_handle_seek_segment_offset,
212
438
       0,
213
438
       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
438
  if( libfsxfs_inode_get_number_of_data_extents(
225
438
       inode,
226
438
       &number_of_extents,
227
438
       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
438
  for( extent_index = 0;
239
15.9k
       extent_index < number_of_extents;
240
15.4k
       extent_index++ )
241
15.5k
  {
242
15.5k
    if( libfsxfs_inode_get_data_extent_by_index(
243
15.5k
         inode,
244
15.5k
         extent_index,
245
15.5k
         &extent,
246
15.5k
         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.5k
    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.5k
    allocation_group_index = (int) ( extent->physical_block_number >> io_handle->number_of_relative_block_number_bits );
271
15.5k
    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.5k
    data_segment_offset = ( ( (off64_t) allocation_group_index * io_handle->allocation_group_size ) + relative_block_number ) * io_handle->block_size;
294
15.5k
    data_segment_size   = (size64_t) extent->number_of_blocks * io_handle->block_size;
295
296
15.5k
    if( libfdata_stream_append_segment(
297
15.5k
         safe_data_stream,
298
15.5k
         &segment_index,
299
15.5k
         0,
300
15.5k
         data_segment_offset,
301
15.5k
         data_segment_size,
302
15.5k
         extent->range_flags,
303
15.5k
         error ) != 1 )
304
84
    {
305
84
      libcerror_error_set(
306
84
       error,
307
84
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
308
84
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
309
84
       "%s: unable to append extent: %d data stream segment.",
310
84
       function,
311
84
       extent_index );
312
313
84
      goto on_error;
314
84
    }
315
15.5k
  }
316
354
  if( libfdata_stream_set_mapped_size(
317
354
       safe_data_stream,
318
354
       data_size,
319
354
       error ) != 1 )
320
127
  {
321
127
    libcerror_error_set(
322
127
     error,
323
127
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
324
127
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
325
127
     "%s: unable to set mapped size of data stream.",
326
127
     function );
327
328
127
    goto on_error;
329
127
  }
330
227
  *data_stream = safe_data_stream;
331
332
227
  return( 1 );
333
334
211
on_error:
335
211
  if( safe_data_stream != NULL )
336
211
  {
337
211
    libfdata_stream_free(
338
211
     &safe_data_stream,
339
211
     NULL );
340
211
  }
341
211
  return( -1 );
342
354
}
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
553
{
355
553
  libfdata_stream_t *safe_data_stream = NULL;
356
553
  static char *function               = "libfsxfs_data_stream_initialize";
357
553
  int result                          = 0;
358
359
553
  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
553
  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
553
  if( ( inode->fork_type != LIBFSXFS_FORK_TYPE_INLINE_DATA )
382
454
   && ( inode->fork_type != LIBFSXFS_FORK_TYPE_EXTENTS )
383
72
   && ( inode->fork_type != LIBFSXFS_FORK_TYPE_BTREE ) )
384
12
  {
385
12
    libcerror_error_set(
386
12
     error,
387
12
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
388
12
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
389
12
     "%s: unsupported directory data fork type.",
390
12
     function );
391
392
12
    return( -1 );
393
12
  }
394
541
  if( ( data_size == 0 )
395
537
   || ( inode->fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA ) )
396
103
  {
397
103
    result = libfsxfs_data_stream_initialize_from_data(
398
103
              &safe_data_stream,
399
103
              inode->inline_data,
400
103
              (size_t) data_size,
401
103
              error );
402
103
  }
403
438
  else
404
438
  {
405
438
    result = libfsxfs_data_stream_initialize_from_extents(
406
438
              &safe_data_stream,
407
438
              io_handle,
408
438
              inode,
409
438
              data_size,
410
438
              error );
411
438
  }
412
541
  if( result != 1 )
413
211
  {
414
211
    libcerror_error_set(
415
211
     error,
416
211
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
417
211
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
418
211
     "%s: unable to create data stream.",
419
211
     function );
420
421
211
    goto on_error;
422
211
  }
423
330
  *data_stream = safe_data_stream;
424
425
330
  return( 1 );
426
427
211
on_error:
428
211
  if( safe_data_stream != NULL )
429
0
  {
430
0
    libfdata_stream_free(
431
0
     &safe_data_stream,
432
     NULL );
433
0
  }
434
211
  return( -1 );
435
541
}
436