Coverage Report

Created: 2026-03-05 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsext/libfsext/libfsext_extent.c
Line
Count
Source
1
/*
2
 * Extent functions
3
 *
4
 * Copyright (C) 2010-2026, 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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsext_definitions.h"
28
#include "libfsext_extent.h"
29
#include "libfsext_io_handle.h"
30
#include "libfsext_libcerror.h"
31
#include "libfsext_libcnotify.h"
32
33
#include "fsext_extents.h"
34
35
/* Creates an extent
36
 * Make sure the value extent is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libfsext_extent_initialize(
40
     libfsext_extent_t **extent,
41
     libcerror_error_t **error )
42
4.16M
{
43
4.16M
  static char *function = "libfsext_extent_initialize";
44
45
4.16M
  if( extent == NULL )
46
0
  {
47
0
    libcerror_error_set(
48
0
     error,
49
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
50
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
51
0
     "%s: invalid extent.",
52
0
     function );
53
54
0
    return( -1 );
55
0
  }
56
4.16M
  if( *extent != NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
61
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
62
0
     "%s: invalid extent value already set.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
4.16M
  *extent = memory_allocate_structure(
68
4.16M
             libfsext_extent_t );
69
70
4.16M
  if( *extent == NULL )
71
0
  {
72
0
    libcerror_error_set(
73
0
     error,
74
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
75
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
76
0
     "%s: unable to create extent.",
77
0
     function );
78
79
0
    goto on_error;
80
0
  }
81
4.16M
  if( memory_set(
82
4.16M
       *extent,
83
4.16M
       0,
84
4.16M
       sizeof( libfsext_extent_t ) ) == NULL )
85
0
  {
86
0
    libcerror_error_set(
87
0
     error,
88
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
89
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
90
0
     "%s: unable to clear extent.",
91
0
     function );
92
93
0
    goto on_error;
94
0
  }
95
4.16M
  return( 1 );
96
97
0
on_error:
98
0
  if( *extent != NULL )
99
0
  {
100
0
    memory_free(
101
0
     *extent );
102
103
0
    *extent = NULL;
104
0
  }
105
0
  return( -1 );
106
4.16M
}
107
108
/* Frees an extent
109
 * Returns 1 if successful or -1 on error
110
 */
111
int libfsext_extent_free(
112
     libfsext_extent_t **extent,
113
     libcerror_error_t **error )
114
5.14M
{
115
5.14M
  static char *function = "libfsext_extent_free";
116
117
5.14M
  if( extent == NULL )
118
0
  {
119
0
    libcerror_error_set(
120
0
     error,
121
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
122
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
123
0
     "%s: invalid extent.",
124
0
     function );
125
126
0
    return( -1 );
127
0
  }
128
5.14M
  if( *extent != NULL )
129
5.14M
  {
130
5.14M
    memory_free(
131
5.14M
     *extent );
132
133
5.14M
    *extent = NULL;
134
5.14M
  }
135
5.14M
  return( 1 );
136
5.14M
}
137
138
/* Clones an extent
139
 * Returns 1 if successful or -1 on error
140
 */
141
int libfsext_extent_clone(
142
     libfsext_extent_t **destination_extent,
143
     libfsext_extent_t *source_extent,
144
     libcerror_error_t **error )
145
978k
{
146
978k
  static char *function = "libfsext_extent_clone";
147
148
978k
  if( destination_extent == NULL )
149
0
  {
150
0
    libcerror_error_set(
151
0
     error,
152
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
153
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
154
0
     "%s: invalid extent.",
155
0
     function );
156
157
0
    return( -1 );
158
0
  }
159
978k
  if( *destination_extent != NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
164
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
165
0
     "%s: invalid destination extent value already set.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
978k
  if( source_extent == NULL )
171
0
  {
172
0
    *destination_extent = source_extent;
173
174
0
    return( 1 );
175
0
  }
176
978k
  *destination_extent = memory_allocate_structure(
177
978k
                         libfsext_extent_t );
178
179
978k
  if( *destination_extent == NULL )
180
0
  {
181
0
    libcerror_error_set(
182
0
     error,
183
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
184
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
185
0
     "%s: unable to create destination extent.",
186
0
     function );
187
188
0
    goto on_error;
189
0
  }
190
978k
  if( memory_copy(
191
978k
       *destination_extent,
192
978k
       source_extent,
193
978k
       sizeof( libfsext_extent_t ) ) == NULL )
194
0
  {
195
0
    libcerror_error_set(
196
0
     error,
197
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
198
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
199
0
     "%s: unable to copy source to destination extent.",
200
0
     function );
201
202
0
    goto on_error;
203
0
  }
204
978k
  return( 1 );
205
206
0
on_error:
207
0
  if( *destination_extent != NULL )
208
0
  {
209
0
    memory_free(
210
0
     *destination_extent );
211
212
0
    *destination_extent = NULL;
213
0
  }
214
0
  return( -1 );
215
978k
}
216
217
/* Reads the extent data
218
 * Returns 1 if successful or -1 on error
219
 */
220
int libfsext_extent_read_data(
221
     libfsext_extent_t *extent,
222
     const uint8_t *data,
223
     size_t data_size,
224
     libcerror_error_t **error )
225
2.47M
{
226
2.47M
  static char *function                = "libfsext_extent_read_data";
227
2.47M
  uint32_t physical_block_number_lower = 0;
228
2.47M
  uint16_t physical_block_number_upper = 0;
229
230
2.47M
  if( extent == NULL )
231
0
  {
232
0
    libcerror_error_set(
233
0
     error,
234
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
235
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
236
0
     "%s: invalid extent.",
237
0
     function );
238
239
0
    return( -1 );
240
0
  }
241
2.47M
  if( data == NULL )
242
0
  {
243
0
    libcerror_error_set(
244
0
     error,
245
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
246
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
247
0
     "%s: invalid data.",
248
0
     function );
249
250
0
    return( -1 );
251
0
  }
252
2.47M
  if( ( data_size < sizeof( fsext_extent_ext4_t ) )
253
2.47M
   || ( data_size > (size_t) SSIZE_MAX ) )
254
0
  {
255
0
    libcerror_error_set(
256
0
     error,
257
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
258
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
259
0
     "%s: invalid data size value out of bounds.",
260
0
     function );
261
262
0
    return( -1 );
263
0
  }
264
#if defined( HAVE_DEBUG_OUTPUT )
265
  if( libcnotify_verbose != 0 )
266
  {
267
    libcnotify_printf(
268
     "%s: extent data:\n",
269
     function );
270
    libcnotify_print_data(
271
     data,
272
     data_size,
273
     0 );
274
  }
275
#endif
276
2.47M
  byte_stream_copy_to_uint32_little_endian(
277
2.47M
   ( (fsext_extent_ext4_t *) data )->logical_block_number,
278
2.47M
   extent->logical_block_number );
279
280
2.47M
  byte_stream_copy_to_uint16_little_endian(
281
2.47M
   ( (fsext_extent_ext4_t *) data )->number_of_blocks,
282
2.47M
   extent->number_of_blocks );
283
284
2.47M
  byte_stream_copy_to_uint16_little_endian(
285
2.47M
   ( (fsext_extent_ext4_t *) data )->physical_block_number_upper,
286
2.47M
   physical_block_number_upper );
287
288
2.47M
  byte_stream_copy_to_uint32_little_endian(
289
2.47M
   ( (fsext_extent_ext4_t *) data )->physical_block_number_lower,
290
2.47M
   physical_block_number_lower );
291
292
#if defined( HAVE_DEBUG_OUTPUT )
293
  if( libcnotify_verbose != 0 )
294
  {
295
    libcnotify_printf(
296
     "%s: logical block number\t\t\t\t: %" PRIu32 "\n",
297
     function,
298
     extent->logical_block_number );
299
300
    if( extent->number_of_blocks > 32768 )
301
    {
302
      libcnotify_printf(
303
       "%s: number of blocks\t\t\t\t: %" PRIu64 " (uninitialized)\n",
304
       function,
305
       extent->number_of_blocks - 32768 );
306
    }
307
    else
308
    {
309
      libcnotify_printf(
310
       "%s: number of blocks\t\t\t\t: %" PRIu64 "\n",
311
       function,
312
       extent->number_of_blocks );
313
    }
314
    libcnotify_printf(
315
     "%s: physical block number (upper)\t\t: %" PRIu16 "\n",
316
     function,
317
     physical_block_number_upper );
318
319
    libcnotify_printf(
320
     "%s: physical block number (lower)\t\t: %" PRIu32 "\n",
321
     function,
322
     physical_block_number_lower );
323
  }
324
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
325
326
2.47M
  extent->physical_block_number = ( (uint64_t) physical_block_number_upper << 32 ) | physical_block_number_lower;
327
328
2.47M
  if( extent->number_of_blocks > 32768 )
329
676k
  {
330
676k
    extent->number_of_blocks -= 32768;
331
676k
    extent->range_flags       = LIBFSEXT_EXTENT_FLAG_IS_SPARSE;
332
676k
  }
333
#if defined( HAVE_DEBUG_OUTPUT )
334
  if( libcnotify_verbose != 0 )
335
  {
336
    libcnotify_printf(
337
     "%s: physical block number\t\t\t: %" PRIu32 "\n",
338
     function,
339
     extent->physical_block_number );
340
341
    libcnotify_printf(
342
     "\n" );
343
  }
344
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
345
346
2.47M
  return( 1 );
347
2.47M
}
348
349
/* Retrieves the extents values
350
 * Returns 1 if successful or -1 on error
351
 */
352
int libfsext_extent_get_values(
353
     libfsext_extent_t *extent,
354
     libfsext_io_handle_t *io_handle,
355
     off64_t *extent_offset,
356
     size64_t *extent_size,
357
     uint32_t *extent_flags,
358
     libcerror_error_t **error )
359
0
{
360
0
  static char *function = "libfsext_extent_get_values";
361
362
0
  if( extent == NULL )
363
0
  {
364
0
    libcerror_error_set(
365
0
     error,
366
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
367
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
368
0
     "%s: invalid extent.",
369
0
     function );
370
371
0
    return( -1 );
372
0
  }
373
0
  if( io_handle == NULL )
374
0
  {
375
0
    libcerror_error_set(
376
0
     error,
377
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
378
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
379
0
     "%s: invalid IO handle.",
380
0
     function );
381
382
0
    return( -1 );
383
0
  }
384
0
  if( io_handle->block_size == 0 )
385
0
  {
386
0
    libcerror_error_set(
387
0
     error,
388
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
389
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
390
0
     "%s: invalid IO handle - block size value out of bounds.",
391
0
     function );
392
393
0
    return( -1 );
394
0
  }
395
0
  if( extent_offset == NULL )
396
0
  {
397
0
    libcerror_error_set(
398
0
     error,
399
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
400
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
401
0
     "%s: invalid extent offset.",
402
0
     function );
403
404
0
    return( -1 );
405
0
  }
406
0
  if( extent_size == NULL )
407
0
  {
408
0
    libcerror_error_set(
409
0
     error,
410
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
411
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
412
0
     "%s: invalid extent size.",
413
0
     function );
414
415
0
    return( -1 );
416
0
  }
417
0
  if( extent_flags == NULL )
418
0
  {
419
0
    libcerror_error_set(
420
0
     error,
421
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
422
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
423
0
     "%s: invalid extent flags.",
424
0
     function );
425
426
0
    return( -1 );
427
0
  }
428
0
  if( extent->physical_block_number > ( (uint64_t) INT64_MAX / io_handle->block_size ) )
429
0
  {
430
0
    libcerror_error_set(
431
0
     error,
432
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
433
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
434
0
     "%s: invalid extent - invalid physical block number value out of bounds.",
435
0
     function );
436
437
0
    return( -1 );
438
0
  }
439
0
  if( extent->number_of_blocks > ( (uint64_t) UINT64_MAX / io_handle->block_size ) )
440
0
  {
441
0
    libcerror_error_set(
442
0
     error,
443
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
444
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
445
0
     "%s: invalid extent - invalid number of blocks value out of bounds.",
446
0
     function );
447
448
0
    return( -1 );
449
0
  }
450
0
  *extent_offset = (off64_t) extent->physical_block_number * (off64_t) io_handle->block_size;
451
0
  *extent_size   = (size64_t) extent->number_of_blocks * (size64_t) io_handle->block_size;
452
0
  *extent_flags  = extent->range_flags;
453
454
0
  return( 1 );
455
0
}
456