Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_extent.c
Line
Count
Source
1
/*
2
 * Extent functions
3
 *
4
 * Copyright (C) 2020-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 "libfsxfs_definitions.h"
28
#include "libfsxfs_extent.h"
29
#include "libfsxfs_io_handle.h"
30
#include "libfsxfs_libcerror.h"
31
#include "libfsxfs_libcnotify.h"
32
33
/* Creates an extent
34
 * Make sure the value extent is referencing, is set to NULL
35
 * Returns 1 if successful or -1 on error
36
 */
37
int libfsxfs_extent_initialize(
38
     libfsxfs_extent_t **extent,
39
     libcerror_error_t **error )
40
747k
{
41
747k
  static char *function = "libfsxfs_extent_initialize";
42
43
747k
  if( extent == NULL )
44
0
  {
45
0
    libcerror_error_set(
46
0
     error,
47
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
48
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
49
0
     "%s: invalid extent.",
50
0
     function );
51
52
0
    return( -1 );
53
0
  }
54
747k
  if( *extent != NULL )
55
0
  {
56
0
    libcerror_error_set(
57
0
     error,
58
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
59
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
60
0
     "%s: invalid extent value already set.",
61
0
     function );
62
63
0
    return( -1 );
64
0
  }
65
747k
  *extent = memory_allocate_structure(
66
747k
             libfsxfs_extent_t );
67
68
747k
  if( *extent == NULL )
69
0
  {
70
0
    libcerror_error_set(
71
0
     error,
72
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
73
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
74
0
     "%s: unable to create extent.",
75
0
     function );
76
77
0
    goto on_error;
78
0
  }
79
747k
  if( memory_set(
80
747k
       *extent,
81
747k
       0,
82
747k
       sizeof( libfsxfs_extent_t ) ) == NULL )
83
0
  {
84
0
    libcerror_error_set(
85
0
     error,
86
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
87
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
88
0
     "%s: unable to clear extent.",
89
0
     function );
90
91
0
    goto on_error;
92
0
  }
93
747k
  return( 1 );
94
95
0
on_error:
96
0
  if( *extent != NULL )
97
0
  {
98
0
    memory_free(
99
0
     *extent );
100
101
0
    *extent = NULL;
102
0
  }
103
0
  return( -1 );
104
747k
}
105
106
/* Frees an extent
107
 * Returns 1 if successful or -1 on error
108
 */
109
int libfsxfs_extent_free(
110
     libfsxfs_extent_t **extent,
111
     libcerror_error_t **error )
112
747k
{
113
747k
  static char *function = "libfsxfs_extent_free";
114
115
747k
  if( extent == NULL )
116
0
  {
117
0
    libcerror_error_set(
118
0
     error,
119
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
120
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
121
0
     "%s: invalid extent.",
122
0
     function );
123
124
0
    return( -1 );
125
0
  }
126
747k
  if( *extent != NULL )
127
747k
  {
128
747k
    memory_free(
129
747k
     *extent );
130
131
747k
    *extent = NULL;
132
747k
  }
133
747k
  return( 1 );
134
747k
}
135
136
/* Reads the extent data
137
 * Returns 1 if successful or -1 on error
138
 */
139
int libfsxfs_extent_read_data(
140
     libfsxfs_extent_t *extent,
141
     const uint8_t *data,
142
     size_t data_size,
143
     libcerror_error_t **error )
144
530k
{
145
530k
  static char *function       = "libfsxfs_extent_read_data";
146
530k
  uint64_t value_128bit_lower = 0;
147
530k
  uint64_t value_128bit_upper = 0;
148
149
530k
  if( extent == NULL )
150
0
  {
151
0
    libcerror_error_set(
152
0
     error,
153
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
154
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
155
0
     "%s: invalid extent.",
156
0
     function );
157
158
0
    return( -1 );
159
0
  }
160
530k
  if( data == NULL )
161
0
  {
162
0
    libcerror_error_set(
163
0
     error,
164
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
165
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
166
0
     "%s: invalid data.",
167
0
     function );
168
169
0
    return( -1 );
170
0
  }
171
530k
  if( ( data_size < 16 )
172
530k
   || ( data_size > (size_t) SSIZE_MAX ) )
173
0
  {
174
0
    libcerror_error_set(
175
0
     error,
176
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
177
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
178
0
     "%s: invalid data size value out of bounds.",
179
0
     function );
180
181
0
    return( -1 );
182
0
  }
183
#if defined( HAVE_DEBUG_OUTPUT )
184
  if( libcnotify_verbose != 0 )
185
  {
186
    libcnotify_printf(
187
     "%s: extent data:\n",
188
     function );
189
    libcnotify_print_data(
190
     data,
191
     16,
192
     0 );
193
  }
194
#endif
195
530k
  byte_stream_copy_to_uint64_big_endian(
196
530k
   &( data[ 0 ] ),
197
530k
   value_128bit_upper );
198
199
530k
  byte_stream_copy_to_uint64_big_endian(
200
530k
   &( data[ 8 ] ),
201
530k
   value_128bit_lower );
202
203
530k
  extent->number_of_blocks = (uint32_t) ( value_128bit_lower & 0x1fffffUL );
204
205
530k
  value_128bit_lower >>= 21;
206
207
530k
  extent->physical_block_number = value_128bit_lower | ( value_128bit_upper & 0x1ffUL );
208
209
530k
  value_128bit_upper >>= 9;
210
211
530k
  extent->logical_block_number = value_128bit_upper & 0x3fffffffffffffUL;
212
213
530k
  value_128bit_upper >>= 54;
214
215
530k
  if( value_128bit_upper == 0 )
216
427k
  {
217
427k
    extent->range_flags = 0;
218
427k
  }
219
103k
  else
220
103k
  {
221
103k
    extent->range_flags = LIBFSXFS_EXTENT_FLAG_IS_SPARSE;
222
103k
  }
223
#if defined( HAVE_DEBUG_OUTPUT )
224
  if( libcnotify_verbose != 0 )
225
  {
226
    libcnotify_printf(
227
     "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
228
     function,
229
     extent->number_of_blocks );
230
231
    libcnotify_printf(
232
     "%s: physical block number\t\t\t: %" PRIu64 "\n",
233
     function,
234
     extent->physical_block_number );
235
236
    libcnotify_printf(
237
     "%s: logical block number\t\t\t\t: %" PRIu64 "\n",
238
     function,
239
     extent->logical_block_number );
240
241
    libcnotify_printf(
242
     "%s: flag\t\t\t\t\t\t: %" PRIu64 "\n",
243
     function,
244
     value_128bit_upper );
245
246
    libcnotify_printf(
247
     "\n" );
248
  }
249
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
250
251
530k
  return( 1 );
252
530k
}
253
254
/* Retrieves the extents values
255
 * Returns 1 if successful or -1 on error
256
 */
257
int libfsxfs_extent_get_values(
258
     libfsxfs_extent_t *extent,
259
     libfsxfs_io_handle_t *io_handle,
260
     off64_t *extent_offset,
261
     size64_t *extent_size,
262
     uint32_t *extent_flags,
263
     libcerror_error_t **error )
264
0
{
265
0
  static char *function = "libfsxfs_extent_get_values";
266
267
0
  if( extent == NULL )
268
0
  {
269
0
    libcerror_error_set(
270
0
     error,
271
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
272
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
273
0
     "%s: invalid extent.",
274
0
     function );
275
276
0
    return( -1 );
277
0
  }
278
0
  if( io_handle == NULL )
279
0
  {
280
0
    libcerror_error_set(
281
0
     error,
282
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
283
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
284
0
     "%s: invalid IO handle.",
285
0
     function );
286
287
0
    return( -1 );
288
0
  }
289
0
  if( io_handle->block_size == 0 )
290
0
  {
291
0
    libcerror_error_set(
292
0
     error,
293
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
294
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
295
0
     "%s: invalid IO handle - block size value out of bounds.",
296
0
     function );
297
298
0
    return( -1 );
299
0
  }
300
0
  if( extent_offset == NULL )
301
0
  {
302
0
    libcerror_error_set(
303
0
     error,
304
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
305
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
306
0
     "%s: invalid extent offset.",
307
0
     function );
308
309
0
    return( -1 );
310
0
  }
311
0
  if( extent_size == NULL )
312
0
  {
313
0
    libcerror_error_set(
314
0
     error,
315
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
316
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
317
0
     "%s: invalid extent size.",
318
0
     function );
319
320
0
    return( -1 );
321
0
  }
322
0
  if( extent_flags == NULL )
323
0
  {
324
0
    libcerror_error_set(
325
0
     error,
326
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
327
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
328
0
     "%s: invalid extent flags.",
329
0
     function );
330
331
0
    return( -1 );
332
0
  }
333
0
  if( extent->physical_block_number > ( (uint64_t) INT64_MAX / io_handle->block_size ) )
334
0
  {
335
0
    libcerror_error_set(
336
0
     error,
337
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
338
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
339
0
     "%s: invalid extent - invalid physical block number value out of bounds.",
340
0
     function );
341
342
0
    return( -1 );
343
0
  }
344
0
  if( extent->number_of_blocks > ( (uint64_t) UINT64_MAX / io_handle->block_size ) )
345
0
  {
346
0
    libcerror_error_set(
347
0
     error,
348
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
349
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
350
0
     "%s: invalid extent - invalid number of blocks value out of bounds.",
351
0
     function );
352
353
0
    return( -1 );
354
0
  }
355
0
  *extent_offset = (off64_t) extent->physical_block_number * (off64_t) io_handle->block_size;
356
0
  *extent_size   = (size64_t) extent->number_of_blocks * (size64_t) io_handle->block_size;
357
0
  *extent_flags  = extent->range_flags;
358
359
0
  return( 1 );
360
0
}
361