Coverage Report

Created: 2024-06-12 07:07

/src/libfsxfs/libfsxfs/libfsxfs_inode_information.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Inode information 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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsxfs_debug.h"
28
#include "libfsxfs_inode_information.h"
29
#include "libfsxfs_io_handle.h"
30
#include "libfsxfs_libbfio.h"
31
#include "libfsxfs_libcerror.h"
32
#include "libfsxfs_libcnotify.h"
33
#include "libfsxfs_libfguid.h"
34
35
#include "fsxfs_inode_information.h"
36
37
/* Creates inode information
38
 * Make sure the value inode_information is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsxfs_inode_information_initialize(
42
     libfsxfs_inode_information_t **inode_information,
43
     libcerror_error_t **error )
44
15.3k
{
45
15.3k
  static char *function = "libfsxfs_inode_information_initialize";
46
47
15.3k
  if( inode_information == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid inode information.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
15.3k
  if( *inode_information != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid inode information value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
15.3k
  *inode_information = memory_allocate_structure(
70
15.3k
                        libfsxfs_inode_information_t );
71
72
15.3k
  if( *inode_information == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
77
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78
0
     "%s: unable to create inode information.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
15.3k
  if( memory_set(
84
15.3k
       *inode_information,
85
15.3k
       0,
86
15.3k
       sizeof( libfsxfs_inode_information_t ) ) == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
92
0
     "%s: unable to clear inode information.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
15.3k
  return( 1 );
98
99
0
on_error:
100
0
  if( *inode_information != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *inode_information );
104
105
0
    *inode_information = NULL;
106
0
  }
107
0
  return( -1 );
108
15.3k
}
109
110
/* Frees inode information
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libfsxfs_inode_information_free(
114
     libfsxfs_inode_information_t **inode_information,
115
     libcerror_error_t **error )
116
15.3k
{
117
15.3k
  static char *function = "libfsxfs_inode_information_free";
118
119
15.3k
  if( inode_information == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
124
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
125
0
     "%s: invalid inode information.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
15.3k
  if( *inode_information != NULL )
131
15.3k
  {
132
15.3k
    memory_free(
133
15.3k
     *inode_information );
134
135
15.3k
    *inode_information = NULL;
136
15.3k
  }
137
15.3k
  return( 1 );
138
15.3k
}
139
140
/* Reads the inode information data
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libfsxfs_inode_information_read_data(
144
     libfsxfs_inode_information_t *inode_information,
145
     libfsxfs_io_handle_t *io_handle,
146
     const uint8_t *data,
147
     size_t data_size,
148
     libcerror_error_t **error )
149
14.1k
{
150
14.1k
  static char *function              = "libfsxfs_inode_information_read_data";
151
14.1k
  size_t inode_information_data_size = 0;
152
14.1k
  uint32_t format_version            = 0;
153
154
#if defined( HAVE_DEBUG_OUTPUT )
155
  uint64_t value_64bit               = 0;
156
  uint32_t value_32bit               = 0;
157
#endif
158
159
14.1k
  if( inode_information == 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 inode information.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
14.1k
  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
14.1k
  if( io_handle->format_version >= 5 )
182
5.76k
  {
183
5.76k
    inode_information_data_size = sizeof( fsxfs_inode_information_v5_t );
184
5.76k
  }
185
8.37k
  else
186
8.37k
  {
187
8.37k
    inode_information_data_size = sizeof( fsxfs_inode_information_t );
188
8.37k
  }
189
14.1k
  if( data == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid data.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
14.1k
  if( ( data_size < inode_information_data_size )
201
14.1k
   || ( data_size > (size_t) SSIZE_MAX ) )
202
0
  {
203
0
    libcerror_error_set(
204
0
     error,
205
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
206
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
207
0
     "%s: invalid data size value out of bounds.",
208
0
     function );
209
210
0
    return( -1 );
211
0
  }
212
#if defined( HAVE_DEBUG_OUTPUT )
213
  if( libcnotify_verbose != 0 )
214
  {
215
    libcnotify_printf(
216
     "%s: inode information data:\n",
217
     function );
218
    libcnotify_print_data(
219
     data,
220
     inode_information_data_size,
221
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
222
  }
223
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
224
225
14.1k
  if( memory_compare(
226
14.1k
       ( (fsxfs_inode_information_t *) data )->signature,
227
14.1k
       "XAGI",
228
14.1k
       4 ) != 0 )
229
6.15k
  {
230
6.15k
    libcerror_error_set(
231
6.15k
     error,
232
6.15k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
233
6.15k
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
234
6.15k
     "%s: unsupported signature.",
235
6.15k
     function );
236
237
6.15k
    return( -1 );
238
6.15k
  }
239
7.98k
  byte_stream_copy_to_uint32_big_endian(
240
7.98k
   ( (fsxfs_inode_information_t *) data )->format_version,
241
7.98k
   format_version );
242
243
7.98k
  byte_stream_copy_to_uint32_big_endian(
244
7.98k
   ( (fsxfs_inode_information_t *) data )->inode_btree_root_block_number,
245
7.98k
   inode_information->inode_btree_root_block_number );
246
247
7.98k
  byte_stream_copy_to_uint32_big_endian(
248
7.98k
   ( (fsxfs_inode_information_t *) data )->inode_btree_depth,
249
7.98k
   inode_information->inode_btree_depth );
250
251
7.98k
  byte_stream_copy_to_uint32_big_endian(
252
7.98k
   ( (fsxfs_inode_information_t *) data )->last_allocated_chunk,
253
7.98k
   inode_information->last_allocated_chunk );
254
255
#if defined( HAVE_DEBUG_OUTPUT )
256
  if( libcnotify_verbose != 0 )
257
  {
258
    libcnotify_printf(
259
     "%s: signature\t\t\t\t\t: %c%c%c%c\n",
260
     function,
261
     ( (fsxfs_inode_information_t *) data )->signature[ 0 ],
262
     ( (fsxfs_inode_information_t *) data )->signature[ 1 ],
263
     ( (fsxfs_inode_information_t *) data )->signature[ 2 ],
264
     ( (fsxfs_inode_information_t *) data )->signature[ 3 ] );
265
266
    libcnotify_printf(
267
     "%s: format version\t\t\t\t: %" PRIu32 "\n",
268
     function,
269
     format_version );
270
271
    byte_stream_copy_to_uint32_big_endian(
272
     ( (fsxfs_inode_information_t *) data )->sequence_number,
273
     value_32bit );
274
    libcnotify_printf(
275
     "%s: sequence number\t\t\t\t: %" PRIu32 "\n",
276
     function,
277
     value_32bit );
278
279
    byte_stream_copy_to_uint32_big_endian(
280
     ( (fsxfs_inode_information_t *) data )->unknown1,
281
     value_32bit );
282
    libcnotify_printf(
283
     "%s: unknown1\t\t\t\t\t: %" PRIu32 "\n",
284
     function,
285
     value_32bit );
286
287
    byte_stream_copy_to_uint32_big_endian(
288
     ( (fsxfs_inode_information_t *) data )->number_of_inodes,
289
     value_32bit );
290
    libcnotify_printf(
291
     "%s: number of inodes\t\t\t\t: %" PRIu32 "\n",
292
     function,
293
     value_32bit );
294
295
    libcnotify_printf(
296
     "%s: inode B+ tree root block number\t\t: %" PRIu32 "\n",
297
     function,
298
     inode_information->inode_btree_root_block_number );
299
300
    libcnotify_printf(
301
     "%s: inode B+ tree depth\t\t\t: %" PRIu32 "\n",
302
     function,
303
     inode_information->inode_btree_depth );
304
305
    byte_stream_copy_to_uint32_big_endian(
306
     ( (fsxfs_inode_information_t *) data )->number_of_unused_inodes,
307
     value_32bit );
308
    libcnotify_printf(
309
     "%s: number of unused inodes\t\t\t: %" PRIu32 "\n",
310
     function,
311
     value_32bit );
312
313
    libcnotify_printf(
314
     "%s: last allocated chunk\t\t\t: %" PRIu32 "\n",
315
     function,
316
     inode_information->last_allocated_chunk );
317
318
    byte_stream_copy_to_uint32_big_endian(
319
     ( (fsxfs_inode_information_t *) data )->unknown2,
320
     value_32bit );
321
    libcnotify_printf(
322
     "%s: unknown2\t\t\t\t\t: 0x%08" PRIx32 "\n",
323
     function,
324
     value_32bit );
325
326
    libcnotify_printf(
327
     "%s: unlinked hash table:\n",
328
     function );
329
    libcnotify_print_data(
330
     ( (fsxfs_inode_information_t *) data )->unlinked_hash_table,
331
     64 * 4,
332
     0 );
333
  }
334
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
335
336
7.98k
  if( format_version != 1 )
337
1.61k
  {
338
1.61k
    libcerror_error_set(
339
1.61k
     error,
340
1.61k
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
341
1.61k
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
342
1.61k
     "%s: unsupported format version: %" PRIu32 ".",
343
1.61k
     function,
344
1.61k
     format_version );
345
346
1.61k
    return( -1 );
347
1.61k
  }
348
6.37k
  if( io_handle->format_version >= 5 )
349
1.29k
  {
350
#if defined( HAVE_DEBUG_OUTPUT )
351
    if( libcnotify_verbose != 0 )
352
    {
353
      if( libfsxfs_debug_print_guid_value(
354
           function,
355
           "block type identifier\t\t\t",
356
           ( (fsxfs_inode_information_v5_t *) data )->block_type_identifier,
357
           16,
358
           LIBFGUID_ENDIAN_BIG,
359
           LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
360
           error ) != 1 )
361
      {
362
        libcerror_error_set(
363
         error,
364
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
365
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
366
         "%s: unable to print GUID value.",
367
         function );
368
369
        return( -1 );
370
      }
371
      byte_stream_copy_to_uint32_big_endian(
372
       ( (fsxfs_inode_information_v5_t *) data )->checksum,
373
       value_32bit );
374
      libcnotify_printf(
375
       "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
376
       function,
377
       value_32bit );
378
379
      byte_stream_copy_to_uint32_big_endian(
380
       ( (fsxfs_inode_information_v5_t *) data )->unknown3,
381
       value_32bit );
382
      libcnotify_printf(
383
       "%s: unknown3\t\t\t\t\t: 0x%08" PRIx32 "\n",
384
       function,
385
       value_32bit );
386
387
      byte_stream_copy_to_uint64_big_endian(
388
       ( (fsxfs_inode_information_v5_t *) data )->log_sequence_number,
389
       value_64bit );
390
      libcnotify_printf(
391
       "%s: log sequence number\t\t\t: %" PRIu64 "\n",
392
       function,
393
       value_64bit );
394
395
      byte_stream_copy_to_uint32_big_endian(
396
       ( (fsxfs_inode_information_v5_t *) data )->free_inode_btree_root_block_number,
397
       value_32bit );
398
      libcnotify_printf(
399
       "%s: free inode B+ tree root block number\t: %" PRIu32 "\n",
400
       function,
401
       value_32bit );
402
403
      byte_stream_copy_to_uint32_big_endian(
404
       ( (fsxfs_inode_information_v5_t *) data )->free_inode_btree_depth,
405
       value_32bit );
406
      libcnotify_printf(
407
       "%s: free inode B+ tree depth\t\t\t: %" PRIu32 "\n",
408
       function,
409
       value_32bit );
410
411
      libcnotify_printf(
412
       "\n" );
413
    }
414
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
415
1.29k
  }
416
6.37k
  return( 1 );
417
7.98k
}
418
419
/* Reads the inode information from a Basic File IO (bfio) handle
420
 * Returns 1 if successful or -1 on error
421
 */
422
int libfsxfs_inode_information_read_file_io_handle(
423
     libfsxfs_inode_information_t *inode_information,
424
     libfsxfs_io_handle_t *io_handle,
425
     libbfio_handle_t *file_io_handle,
426
     off64_t file_offset,
427
     libcerror_error_t **error )
428
15.3k
{
429
15.3k
  uint8_t data[ 512 ];
430
431
15.3k
  static char *function = "libfsxfs_inode_information_read_file_io_handle";
432
15.3k
  ssize_t read_count    = 0;
433
434
#if defined( HAVE_DEBUG_OUTPUT )
435
  if( libcnotify_verbose != 0 )
436
  {
437
    libcnotify_printf(
438
     "%s: reading inode information at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
439
     function,
440
     file_offset,
441
     file_offset );
442
  }
443
#endif
444
15.3k
  read_count = libbfio_handle_read_buffer_at_offset(
445
15.3k
                file_io_handle,
446
15.3k
                data,
447
15.3k
                512,
448
15.3k
                file_offset,
449
15.3k
                error );
450
451
15.3k
  if( read_count != (ssize_t) 512 )
452
1.23k
  {
453
1.23k
    libcerror_error_set(
454
1.23k
     error,
455
1.23k
     LIBCERROR_ERROR_DOMAIN_IO,
456
1.23k
     LIBCERROR_IO_ERROR_READ_FAILED,
457
1.23k
     "%s: unable to read inode information at offset: %" PRIi64 " (0x%08" PRIx64 ").",
458
1.23k
     function,
459
1.23k
     file_offset,
460
1.23k
     file_offset );
461
462
1.23k
    return( -1 );
463
1.23k
  }
464
14.1k
  if( libfsxfs_inode_information_read_data(
465
14.1k
       inode_information,
466
14.1k
       io_handle,
467
14.1k
       data,
468
14.1k
       512,
469
14.1k
       error ) != 1 )
470
7.76k
  {
471
7.76k
    libcerror_error_set(
472
7.76k
     error,
473
7.76k
     LIBCERROR_ERROR_DOMAIN_IO,
474
7.76k
     LIBCERROR_IO_ERROR_READ_FAILED,
475
7.76k
     "%s: unable to read inode information at offset: %" PRIi64 " (0x%08" PRIx64 ").",
476
7.76k
     function,
477
7.76k
     file_offset,
478
7.76k
     file_offset );
479
480
7.76k
    return( -1 );
481
7.76k
  }
482
6.37k
  return( 1 );
483
14.1k
}
484