Coverage Report

Created: 2024-02-25 07:20

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