Coverage Report

Created: 2025-12-05 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsext/libfsext/libfsext_block_vector.c
Line
Count
Source
1
/*
2
 * Block vector functions
3
 *
4
 * Copyright (C) 2010-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 "libfsext_block.h"
26
#include "libfsext_block_vector.h"
27
#include "libfsext_extent.h"
28
#include "libfsext_inode.h"
29
#include "libfsext_definitions.h"
30
#include "libfsext_io_handle.h"
31
#include "libfsext_libcerror.h"
32
#include "libfsext_libbfio.h"
33
#include "libfsext_libfdata.h"
34
#include "libfsext_unused.h"
35
36
/* Creates a block vector
37
 * Make sure the value block_vector is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfsext_block_vector_initialize(
41
     libfdata_vector_t **block_vector,
42
     libfsext_io_handle_t *io_handle,
43
     libfsext_inode_t *inode,
44
     libcerror_error_t **error )
45
1.46k
{
46
1.46k
  libfsext_extent_t *extent = NULL;
47
1.46k
  static char *function     = "libfsext_block_vector_initialize";
48
1.46k
  size64_t data_size        = 0;
49
1.46k
  off64_t file_offset       = 0;
50
1.46k
  int extent_index          = 0;
51
1.46k
  int number_of_extents     = 0;
52
1.46k
  int segment_index         = 0;
53
54
1.46k
  if( block_vector == NULL )
55
0
  {
56
0
    libcerror_error_set(
57
0
     error,
58
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60
0
     "%s: invalid block vector.",
61
0
     function );
62
63
0
    return( -1 );
64
0
  }
65
1.46k
  if( io_handle == NULL )
66
0
  {
67
0
    libcerror_error_set(
68
0
     error,
69
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
70
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
71
0
     "%s: invalid IO handle.",
72
0
     function );
73
74
0
    return( -1 );
75
0
  }
76
1.46k
  if( io_handle->block_size == 0 )
77
0
  {
78
0
    libcerror_error_set(
79
0
     error,
80
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
81
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
82
0
     "%s: invalid IO handle - missing block size.",
83
0
     function );
84
85
0
    return( -1 );
86
0
  }
87
1.46k
  if( inode == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
92
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
93
0
     "%s: invalid inode.",
94
0
     function );
95
96
0
    return( -1 );
97
0
  }
98
1.46k
  if( libfdata_vector_initialize(
99
1.46k
       block_vector,
100
1.46k
       (size64_t) io_handle->block_size,
101
1.46k
       (intptr_t *) io_handle,
102
1.46k
       NULL,
103
1.46k
       NULL,
104
1.46k
       (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libfsext_block_vector_read_element_data,
105
1.46k
       NULL,
106
1.46k
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
107
1.46k
       error ) != 1 )
108
0
  {
109
0
    libcerror_error_set(
110
0
     error,
111
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
112
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
113
0
     "%s: unable to create block vector.",
114
0
     function );
115
116
0
    goto on_error;
117
0
  }
118
1.46k
  if( libfsext_inode_get_number_of_extents(
119
1.46k
       inode,
120
1.46k
       &number_of_extents,
121
1.46k
       error ) != 1 )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
126
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
127
0
     "%s: unable to retrieve number of extents from inode.",
128
0
     function );
129
130
0
    goto on_error;
131
0
  }
132
1.46k
  for( extent_index = 0;
133
17.3k
       extent_index < number_of_extents;
134
15.8k
       extent_index++ )
135
17.0k
  {
136
17.0k
    if( libfsext_inode_get_extent_by_index(
137
17.0k
         inode,
138
17.0k
         extent_index,
139
17.0k
         &extent,
140
17.0k
         error ) != 1 )
141
0
    {
142
0
      libcerror_error_set(
143
0
       error,
144
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
145
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
146
0
       "%s: unable to retrieve extent: %d.",
147
0
       function,
148
0
       extent_index );
149
150
0
      goto on_error;
151
0
    }
152
17.0k
    if( extent == NULL )
153
0
    {
154
0
      libcerror_error_set(
155
0
       error,
156
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
157
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
158
0
       "%s: missing extent: %d.",
159
0
       function,
160
0
       extent_index );
161
162
0
      goto on_error;
163
0
    }
164
17.0k
    if( extent->physical_block_number == 0 )
165
1.11k
    {
166
1.11k
      break;
167
1.11k
    }
168
15.8k
    if( extent->physical_block_number > ( (uint64_t) INT64_MAX / io_handle->block_size ) )
169
47
    {
170
47
      libcerror_error_set(
171
47
       error,
172
47
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
173
47
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
174
47
       "%s: invalid extent: %d - invalid physical block number value out of bounds.",
175
47
       function,
176
47
       extent_index );
177
178
47
      goto on_error;
179
47
    }
180
15.8k
    if( extent->number_of_blocks > ( (uint64_t) UINT64_MAX / io_handle->block_size ) )
181
0
    {
182
0
      libcerror_error_set(
183
0
       error,
184
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
185
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
186
0
       "%s: invalid extent: %d - invalid number of blocks value out of bounds.",
187
0
       function,
188
0
       extent_index );
189
190
0
      goto on_error;
191
0
    }
192
15.8k
    file_offset = (off64_t) extent->physical_block_number * (off64_t) io_handle->block_size;
193
15.8k
    data_size   = (size64_t) extent->number_of_blocks * io_handle->block_size;
194
195
15.8k
    if( libfdata_vector_append_segment(
196
15.8k
         *block_vector,
197
15.8k
         &segment_index,
198
15.8k
         0,
199
15.8k
         file_offset,
200
15.8k
         data_size,
201
15.8k
         0,
202
15.8k
         error ) != 1 )
203
0
    {
204
0
      libcerror_error_set(
205
0
       error,
206
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
207
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
208
0
       "%s: unable to append block: %" PRIu64 " as vector segment.",
209
0
       function,
210
0
       extent->physical_block_number );
211
212
0
      goto on_error;
213
0
    }
214
15.8k
  }
215
1.41k
  return( 1 );
216
217
47
on_error:
218
47
  if( *block_vector != NULL )
219
47
  {
220
47
    libfdata_vector_free(
221
47
     block_vector,
222
47
     NULL );
223
47
  }
224
47
  return( -1 );
225
1.46k
}
226
227
/* Reads a block
228
 * Callback function for the block vector
229
 * Returns 1 if successful or -1 on error
230
 */
231
int libfsext_block_vector_read_element_data(
232
     libfsext_io_handle_t *io_handle,
233
     libbfio_handle_t *file_io_handle,
234
     libfdata_vector_t *vector,
235
     libfdata_cache_t *cache,
236
     int element_index LIBFSEXT_ATTRIBUTE_UNUSED,
237
     int element_data_file_index LIBFSEXT_ATTRIBUTE_UNUSED,
238
     off64_t block_offset,
239
     size64_t block_size,
240
     uint32_t range_flags LIBFSEXT_ATTRIBUTE_UNUSED,
241
     uint8_t read_flags LIBFSEXT_ATTRIBUTE_UNUSED,
242
     libcerror_error_t **error )
243
2.81k
{
244
2.81k
  libfsext_block_t *block = NULL;
245
2.81k
  static char *function   = "libfsext_block_vector_read_element_data";
246
247
2.81k
  LIBFSEXT_UNREFERENCED_PARAMETER( element_index )
248
2.81k
  LIBFSEXT_UNREFERENCED_PARAMETER( element_data_file_index )
249
2.81k
  LIBFSEXT_UNREFERENCED_PARAMETER( range_flags )
250
2.81k
  LIBFSEXT_UNREFERENCED_PARAMETER( read_flags )
251
252
2.81k
  if( io_handle == NULL )
253
0
  {
254
0
    libcerror_error_set(
255
0
     error,
256
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
257
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
258
0
     "%s: invalid IO handle.",
259
0
     function );
260
261
0
    return( -1 );
262
0
  }
263
2.81k
  if( ( block_size == 0 )
264
2.81k
   || ( block_size > (size64_t) SSIZE_MAX ) )
265
0
  {
266
0
    libcerror_error_set(
267
0
     error,
268
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
269
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
270
0
     "%s: invalid block size value out of bounds.",
271
0
     function );
272
273
0
    return( -1 );
274
0
  }
275
2.81k
  if( libfsext_block_initialize(
276
2.81k
       &block,
277
2.81k
       (size_t) block_size,
278
2.81k
       error ) != 1 )
279
0
  {
280
0
    libcerror_error_set(
281
0
     error,
282
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
283
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
284
0
     "%s: unable to create block.",
285
0
     function );
286
287
0
    goto on_error;
288
0
  }
289
2.81k
  if( block == NULL )
290
0
  {
291
0
    libcerror_error_set(
292
0
     error,
293
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
294
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
295
0
     "%s: missing block.",
296
0
     function );
297
298
0
    goto on_error;
299
0
  }
300
2.81k
  if( libfsext_block_read_file_io_handle(
301
2.81k
       block,
302
2.81k
       file_io_handle,
303
2.81k
       block_offset,
304
2.81k
       error ) != 1 )
305
287
  {
306
287
    libcerror_error_set(
307
287
     error,
308
287
     LIBCERROR_ERROR_DOMAIN_IO,
309
287
     LIBCERROR_IO_ERROR_READ_FAILED,
310
287
     "%s: unable to read block.",
311
287
     function );
312
313
287
    goto on_error;
314
287
  }
315
2.53k
  if( libfdata_vector_set_element_value_by_index(
316
2.53k
       vector,
317
2.53k
       (intptr_t *) file_io_handle,
318
2.53k
       cache,
319
2.53k
       element_index,
320
2.53k
       (intptr_t *) block,
321
2.53k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_block_free,
322
2.53k
       LIBFDATA_VECTOR_ELEMENT_VALUE_FLAG_MANAGED,
323
2.53k
       error ) != 1 )
324
0
  {
325
0
    libcerror_error_set(
326
0
     error,
327
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
329
0
     "%s: unable to set block as element value.",
330
0
     function );
331
332
0
    goto on_error;
333
0
  }
334
2.53k
  return( 1 );
335
336
287
on_error:
337
287
  if( block != NULL )
338
287
  {
339
287
    libfsext_block_free(
340
287
     &block,
341
     NULL );
342
287
  }
343
287
  return( -1 );
344
2.53k
}
345