Coverage Report

Created: 2025-06-13 07:22

/src/libfsext/libfsext/libfsext_inode_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Inode table functions
3
 *
4
 * Copyright (C) 2010-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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsext_definitions.h"
28
#include "libfsext_group_descriptor.h"
29
#include "libfsext_inode.h"
30
#include "libfsext_inode_table.h"
31
#include "libfsext_io_handle.h"
32
#include "libfsext_libcdata.h"
33
#include "libfsext_libcerror.h"
34
#include "libfsext_libcnotify.h"
35
#include "libfsext_libfcache.h"
36
#include "libfsext_libfdata.h"
37
#include "libfsext_superblock.h"
38
39
#include "fsext_inode.h"
40
41
/* Creates an inode table
42
 * Make sure the value inode_table is referencing, is set to NULL
43
 * Returns 1 if successful or -1 on error
44
 */
45
int libfsext_inode_table_initialize(
46
     libfsext_inode_table_t **inode_table,
47
     uint16_t inode_size,
48
     libfsext_io_handle_t *io_handle,
49
     libfsext_superblock_t *superblock,
50
     libcdata_array_t *group_descriptors_array,
51
     libcerror_error_t **error )
52
4.03k
{
53
4.03k
  libfsext_group_descriptor_t *group_descriptor = NULL;
54
4.03k
  static char *function                         = "libfsext_inode_table_initialize";
55
4.03k
  size64_t file_size                            = 0;
56
4.03k
  size_t inode_data_size                        = 0;
57
4.03k
  off64_t file_offset                           = 0;
58
4.03k
  int group_descriptor_index                    = 0;
59
4.03k
  int number_of_group_descriptors               = 0;
60
4.03k
  int segment_index                             = 0;
61
62
4.03k
  if( inode_table == NULL )
63
0
  {
64
0
    libcerror_error_set(
65
0
     error,
66
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
67
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
68
0
     "%s: invalid inode table.",
69
0
     function );
70
71
0
    return( -1 );
72
0
  }
73
4.03k
  if( *inode_table != NULL )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
78
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
79
0
     "%s: invalid inode table value already set.",
80
0
     function );
81
82
0
    return( -1 );
83
0
  }
84
4.03k
  if( ( inode_size != 128 )
85
4.03k
   && ( inode_size != 256 )
86
4.03k
   && ( inode_size != 512 )
87
4.03k
   && ( inode_size != 1024 ) )
88
199
  {
89
199
    libcerror_error_set(
90
199
     error,
91
199
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
92
199
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
93
199
     "%s: unsupported inode size.",
94
199
     function );
95
96
199
    return( -1 );
97
199
  }
98
3.83k
  if( superblock == NULL )
99
0
  {
100
0
    libcerror_error_set(
101
0
     error,
102
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
103
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
104
0
     "%s: invalid superblock.",
105
0
     function );
106
107
0
    return( -1 );
108
0
  }
109
3.83k
  if( superblock->block_size == 0 )
110
0
  {
111
0
    libcerror_error_set(
112
0
     error,
113
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
114
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
115
0
     "%s: invalid superblock - block size value out of bounds.",
116
0
     function );
117
118
0
    return( -1 );
119
0
  }
120
3.83k
  *inode_table = memory_allocate_structure(
121
3.83k
                  libfsext_inode_table_t );
122
123
3.83k
  if( *inode_table == NULL )
124
0
  {
125
0
    libcerror_error_set(
126
0
     error,
127
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
128
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
129
0
     "%s: unable to create inode table.",
130
0
     function );
131
132
0
    goto on_error;
133
0
  }
134
3.83k
  if( memory_set(
135
3.83k
       *inode_table,
136
3.83k
       0,
137
3.83k
       sizeof( libfsext_inode_table_t ) ) == NULL )
138
0
  {
139
0
    libcerror_error_set(
140
0
     error,
141
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
142
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
143
0
     "%s: unable to clear inode table.",
144
0
     function );
145
146
0
    goto on_error;
147
0
  }
148
3.83k
  if( inode_size != 0 )
149
3.83k
  {
150
3.83k
    inode_data_size = (size_t) inode_size;
151
3.83k
  }
152
0
  else if( io_handle->format_version == 4 )
153
0
  {
154
0
    inode_data_size = sizeof( fsext_inode_ext4_t );
155
0
  }
156
0
  else if( io_handle->format_version == 3 )
157
0
  {
158
0
    inode_data_size = sizeof( fsext_inode_ext3_t );
159
0
  }
160
0
  else
161
0
  {
162
0
    inode_data_size = sizeof( fsext_inode_ext2_t );
163
0
  }
164
3.83k
  if( libfdata_vector_initialize(
165
3.83k
       &( ( *inode_table )->inodes_vector ),
166
3.83k
       inode_data_size,
167
3.83k
       (intptr_t *) io_handle,
168
3.83k
       NULL,
169
3.83k
       NULL,
170
3.83k
       (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_inode_read_element_data,
171
3.83k
       NULL,
172
3.83k
       LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
173
3.83k
       error ) != 1 )
174
0
  {
175
0
    libcerror_error_set(
176
0
     error,
177
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
178
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
179
0
     "%s: unable to create inodes vector.",
180
0
     function );
181
182
0
    goto on_error;
183
0
  }
184
3.83k
  if( libcdata_array_get_number_of_entries(
185
3.83k
       group_descriptors_array,
186
3.83k
       &number_of_group_descriptors,
187
3.83k
       error ) != 1 )
188
0
  {
189
0
    libcerror_error_set(
190
0
     error,
191
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
192
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
193
0
     "%s: unable to retrieve number of group descriptors.",
194
0
     function );
195
196
0
    goto on_error;
197
0
  }
198
3.83k
  for( group_descriptor_index = 0;
199
1.17M
       group_descriptor_index < number_of_group_descriptors;
200
1.17M
       group_descriptor_index++ )
201
1.17M
  {
202
1.17M
    if( libcdata_array_get_entry_by_index(
203
1.17M
         group_descriptors_array,
204
1.17M
         group_descriptor_index,
205
1.17M
         (intptr_t **) &group_descriptor,
206
1.17M
         error ) != 1 )
207
0
    {
208
0
      libcerror_error_set(
209
0
       error,
210
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
211
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
212
0
       "%s: unable to retrieve group descriptor: %d.",
213
0
       function,
214
0
       group_descriptor_index );
215
216
0
      goto on_error;
217
0
    }
218
1.17M
    if( group_descriptor == NULL )
219
0
    {
220
0
      libcerror_error_set(
221
0
       error,
222
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
223
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
224
0
       "%s: missing group descriptor: %d.",
225
0
       function,
226
0
       group_descriptor_index );
227
228
0
      goto on_error;
229
0
    }
230
1.17M
    if( (uint64_t) group_descriptor->inode_table_block_number > ( (uint64_t) INT64_MAX / superblock->block_size ) )
231
235
    {
232
235
      libcerror_error_set(
233
235
       error,
234
235
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
235
235
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
236
235
       "%s: invalid group descriptor - inode table block number value out of bounds.",
237
235
       function );
238
239
235
      goto on_error;
240
235
    }
241
1.17M
    file_offset = (off64_t) group_descriptor->inode_table_block_number * superblock->block_size;
242
1.17M
    file_size   = (size64_t) superblock->number_of_inodes_per_block_group * inode_data_size;
243
244
1.17M
    if( libfdata_vector_append_segment(
245
1.17M
         ( *inode_table )->inodes_vector,
246
1.17M
         &segment_index,
247
1.17M
         0,
248
1.17M
         file_offset,
249
1.17M
         file_size,
250
1.17M
         0,
251
1.17M
         error ) != 1 )
252
0
    {
253
0
      libcerror_error_set(
254
0
       error,
255
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
256
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
257
0
       "%s: unable to append segment to inodes vector.",
258
0
       function );
259
260
0
      goto on_error;
261
0
    }
262
1.17M
  }
263
3.60k
  if( libfcache_cache_initialize(
264
3.60k
       &( ( *inode_table )->inodes_cache ),
265
3.60k
       LIBFSEXT_MAXIMUM_CACHE_ENTRIES_INODES,
266
3.60k
       error ) != 1 )
267
0
  {
268
0
    libcerror_error_set(
269
0
     error,
270
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
271
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
272
0
     "%s: unable to create inodes cache.",
273
0
     function );
274
275
0
    goto on_error;
276
0
  }
277
3.60k
  return( 1 );
278
279
235
on_error:
280
235
  if( *inode_table != NULL )
281
235
  {
282
235
    if( ( *inode_table )->inodes_vector != NULL )
283
235
    {
284
235
      libfdata_vector_free(
285
235
       &( ( *inode_table )->inodes_vector ),
286
235
       NULL );
287
235
    }
288
235
    memory_free(
289
235
     *inode_table );
290
291
235
    *inode_table = NULL;
292
235
  }
293
235
  return( -1 );
294
3.60k
}
295
296
/* Frees an inode_table
297
 * Returns 1 if successful or -1 on error
298
 */
299
int libfsext_inode_table_free(
300
     libfsext_inode_table_t **inode_table,
301
     libcerror_error_t **error )
302
3.60k
{
303
3.60k
  static char *function = "libfsext_inode_table_free";
304
3.60k
  int result            = 1;
305
306
3.60k
  if( inode_table == NULL )
307
0
  {
308
0
    libcerror_error_set(
309
0
     error,
310
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
311
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
312
0
     "%s: invalid inode table.",
313
0
     function );
314
315
0
    return( -1 );
316
0
  }
317
3.60k
  if( *inode_table != NULL )
318
3.60k
  {
319
3.60k
    if( libfdata_vector_free(
320
3.60k
         &( ( *inode_table )->inodes_vector ),
321
3.60k
         error ) != 1 )
322
0
    {
323
0
      libcerror_error_set(
324
0
       error,
325
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
326
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
327
0
       "%s: unable to free inodes vector.",
328
0
       function );
329
330
0
      result = -1;
331
0
    }
332
3.60k
    if( libfcache_cache_free(
333
3.60k
         &( ( *inode_table )->inodes_cache ),
334
3.60k
         error ) != 1 )
335
0
    {
336
0
      libcerror_error_set(
337
0
       error,
338
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
339
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
340
0
       "%s: unable to free inodes cache.",
341
0
       function );
342
343
0
      result = -1;
344
0
    }
345
3.60k
    memory_free(
346
3.60k
     *inode_table );
347
348
3.60k
    *inode_table = NULL;
349
3.60k
  }
350
3.60k
  return( result );
351
3.60k
}
352
353
/* Retrieves a specific inode
354
 * Returns 1 if successful or -1 on error
355
 */
356
int libfsext_inode_table_get_inode_by_number(
357
     libfsext_inode_table_t *inode_table,
358
     libbfio_handle_t *file_io_handle,
359
     uint32_t inode_number,
360
     libfsext_inode_t **inode,
361
     libcerror_error_t **error )
362
4.94k
{
363
4.94k
  static char *function = "libfsext_inode_table_get_inode_by_number";
364
365
4.94k
  if( inode_table == NULL )
366
0
  {
367
0
    libcerror_error_set(
368
0
     error,
369
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
370
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
371
0
     "%s: invalid inode table.",
372
0
     function );
373
374
0
    return( -1 );
375
0
  }
376
4.94k
  if( inode_number == 0 )
377
0
  {
378
0
    libcerror_error_set(
379
0
     error,
380
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
381
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
382
0
     "%s: invalid inode number value zero or less.",
383
0
     function );
384
385
0
    return( -1 );
386
0
  }
387
#if defined( HAVE_DEBUG_OUTPUT )
388
  if( libcnotify_verbose != 0 )
389
  {
390
    libcnotify_printf(
391
     "Retrieving inode: %" PRIu32 ".\n",
392
     inode_number );
393
  }
394
#endif
395
4.94k
  if( libfdata_vector_get_element_value_by_index(
396
4.94k
       inode_table->inodes_vector,
397
4.94k
       (intptr_t *) file_io_handle,
398
4.94k
       (libfdata_cache_t *) inode_table->inodes_cache,
399
4.94k
       inode_number - 1,
400
4.94k
       (intptr_t **) inode,
401
4.94k
       0,
402
4.94k
       error ) != 1 )
403
1.84k
  {
404
1.84k
    libcerror_error_set(
405
1.84k
     error,
406
1.84k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
407
1.84k
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
408
1.84k
     "%s: unable to retrieve inode: %" PRIu32 ".",
409
1.84k
     function,
410
1.84k
     inode_number );
411
412
1.84k
    return( -1 );
413
1.84k
  }
414
3.09k
  return( 1 );
415
4.94k
}
416