Coverage Report

Created: 2026-07-25 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsext/libfsext/libfsext_inode.c
Line
Count
Source
1
/*
2
 * Inode 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 <narrow_string.h>
26
#include <system_string.h>
27
#include <types.h>
28
#include <wide_string.h>
29
30
#include "libfsext_attribute_values.h"
31
#include "libfsext_attributes_block.h"
32
#include "libfsext_block_data.h"
33
#include "libfsext_checksum.h"
34
#include "libfsext_data_blocks.h"
35
#include "libfsext_debug.h"
36
#include "libfsext_definitions.h"
37
#include "libfsext_extents.h"
38
#include "libfsext_inode.h"
39
#include "libfsext_io_handle.h"
40
#include "libfsext_libbfio.h"
41
#include "libfsext_libcdata.h"
42
#include "libfsext_libcerror.h"
43
#include "libfsext_libcnotify.h"
44
#include "libfsext_libfdata.h"
45
#include "libfsext_libfdatetime.h"
46
#include "libfsext_unused.h"
47
#include "libfsext_types.h"
48
49
#include "fsext_inode.h"
50
51
/* Creates a inode
52
 * Make sure the value inode is referencing, is set to NULL
53
 * Returns 1 if successful or -1 on error
54
 */
55
int libfsext_inode_initialize(
56
     libfsext_inode_t **inode,
57
     libcerror_error_t **error )
58
4.69k
{
59
4.69k
  static char *function = "libfsext_inode_initialize";
60
61
4.69k
  if( inode == NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
66
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
67
0
     "%s: invalid inode.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
4.69k
  if( *inode != NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
77
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
78
0
     "%s: invalid inode value already set.",
79
0
     function );
80
81
0
    return( -1 );
82
0
  }
83
4.69k
  *inode = memory_allocate_structure(
84
4.69k
            libfsext_inode_t );
85
86
4.69k
  if( *inode == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
92
0
     "%s: unable to create inode.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
4.69k
  if( memory_set(
98
4.69k
       *inode,
99
4.69k
       0,
100
4.69k
       sizeof( libfsext_inode_t ) ) == NULL )
101
0
  {
102
0
    libcerror_error_set(
103
0
     error,
104
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
105
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
106
0
     "%s: unable to clear inode.",
107
0
     function );
108
109
0
    memory_free(
110
0
     *inode );
111
112
0
    *inode = NULL;
113
114
0
    return( -1 );
115
0
  }
116
4.69k
  if( libcdata_array_initialize(
117
4.69k
       &( ( *inode )->data_extents_array ),
118
4.69k
       0,
119
4.69k
       error ) != 1 )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
124
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
125
0
     "%s: unable to create data extents array.",
126
0
     function );
127
128
0
    goto on_error;
129
0
  }
130
4.69k
  return( 1 );
131
132
0
on_error:
133
0
  if( *inode != NULL )
134
0
  {
135
0
    memory_free(
136
0
     *inode );
137
138
0
    *inode = NULL;
139
0
  }
140
0
  return( -1 );
141
4.69k
}
142
143
/* Frees a inode
144
 * Returns 1 if successful or -1 on error
145
 */
146
int libfsext_inode_free(
147
     libfsext_inode_t **inode,
148
     libcerror_error_t **error )
149
6.68k
{
150
6.68k
  static char *function = "libfsext_inode_free";
151
6.68k
  int result            = 1;
152
153
6.68k
  if( inode == NULL )
154
0
  {
155
0
    libcerror_error_set(
156
0
     error,
157
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
158
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
159
0
     "%s: invalid inode.",
160
0
     function );
161
162
0
    return( -1 );
163
0
  }
164
6.68k
  if( *inode != NULL )
165
6.68k
  {
166
6.68k
    if( libcdata_array_free(
167
6.68k
         &( ( *inode )->data_extents_array ),
168
6.68k
         (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_extent_free,
169
6.68k
         error ) != 1 )
170
0
    {
171
0
      libcerror_error_set(
172
0
       error,
173
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
174
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
175
0
       "%s: unable to free data extents array.",
176
0
       function );
177
178
0
      result = -1;
179
0
    }
180
6.68k
    if( ( *inode )->extended_attributes_array != NULL )
181
116
    {
182
116
      if( libcdata_array_free(
183
116
           &( ( *inode )->extended_attributes_array ),
184
116
           (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_attribute_values_free,
185
116
           error ) != 1 )
186
0
      {
187
0
        libcerror_error_set(
188
0
         error,
189
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
190
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
191
0
         "%s: unable to free extended attributes array.",
192
0
         function );
193
194
0
        result = -1;
195
0
      }
196
116
    }
197
6.68k
    memory_free(
198
6.68k
     *inode );
199
200
6.68k
    *inode = NULL;
201
6.68k
  }
202
6.68k
  return( result );
203
6.68k
}
204
205
/* Clones an inode
206
 * Returns 1 if successful or -1 on error
207
 */
208
int libfsext_inode_clone(
209
     libfsext_inode_t **destination_inode,
210
     libfsext_inode_t *source_inode,
211
     libcerror_error_t **error )
212
1.98k
{
213
1.98k
  static char *function = "libfsext_inode_clone";
214
215
1.98k
  if( destination_inode == NULL )
216
0
  {
217
0
    libcerror_error_set(
218
0
     error,
219
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
220
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
221
0
     "%s: invalid inode.",
222
0
     function );
223
224
0
    return( -1 );
225
0
  }
226
1.98k
  if( *destination_inode != NULL )
227
0
  {
228
0
    libcerror_error_set(
229
0
     error,
230
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
231
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
232
0
     "%s: invalid destination inode value already set.",
233
0
     function );
234
235
0
    return( -1 );
236
0
  }
237
1.98k
  if( source_inode == NULL )
238
0
  {
239
0
    *destination_inode = source_inode;
240
241
0
    return( 1 );
242
0
  }
243
1.98k
  *destination_inode = memory_allocate_structure(
244
1.98k
                        libfsext_inode_t );
245
246
1.98k
  if( *destination_inode == NULL )
247
0
  {
248
0
    libcerror_error_set(
249
0
     error,
250
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
251
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
252
0
     "%s: unable to create destination inode.",
253
0
     function );
254
255
0
    goto on_error;
256
0
  }
257
1.98k
  if( memory_copy(
258
1.98k
       *destination_inode,
259
1.98k
       source_inode,
260
1.98k
       sizeof( libfsext_inode_t ) ) == NULL )
261
0
  {
262
0
    libcerror_error_set(
263
0
     error,
264
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
265
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
266
0
     "%s: unable to copy source to destination inode.",
267
0
     function );
268
269
0
    goto on_error;
270
0
  }
271
1.98k
  ( *destination_inode )->data_extents_array        = NULL;
272
1.98k
  ( *destination_inode )->extended_attributes_array = NULL;
273
274
1.98k
  if( libcdata_array_clone(
275
1.98k
       &( ( *destination_inode )->data_extents_array ),
276
1.98k
       source_inode->data_extents_array,
277
1.98k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_extent_free,
278
1.98k
       (int (*)(intptr_t **, intptr_t *, libcerror_error_t **)) &libfsext_extent_clone,
279
1.98k
       error ) != 1 )
280
0
  {
281
0
    libcerror_error_set(
282
0
     error,
283
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
284
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
285
0
     "%s: unable to create destination data extents array.",
286
0
     function );
287
288
0
    goto on_error;
289
0
  }
290
  /* Since the extended attribute array is only used in the file entry
291
   * do not do a full clone here.
292
   */
293
1.98k
  if( source_inode->extended_attributes_array != NULL )
294
28
  {
295
28
    ( *destination_inode )->extended_attributes_array = source_inode->extended_attributes_array;
296
28
    source_inode->extended_attributes_array           = NULL;
297
28
  }
298
1.98k
  return( 1 );
299
300
0
on_error:
301
0
  if( *destination_inode != NULL )
302
0
  {
303
0
    memory_free(
304
0
     *destination_inode );
305
306
0
    *destination_inode = NULL;
307
0
  }
308
0
  return( -1 );
309
1.98k
}
310
311
/* Reads the inode data
312
 * Returns 1 if successful or -1 on error
313
 */
314
int libfsext_inode_read_data(
315
     libfsext_inode_t *inode,
316
     libfsext_io_handle_t *io_handle,
317
     const uint8_t *data,
318
     size_t data_size,
319
     libcerror_error_t **error )
320
4.69k
{
321
4.69k
  uint8_t checksum_data[ 4 ];
322
4.69k
  uint8_t empty_checksum_data[ 2 ]     = { 0, 0 };
323
324
4.69k
  static char *function                = "libfsext_inode_read_data";
325
4.69k
  size_t data_offset                   = 0;
326
4.69k
  uint32_t access_time                 = 0;
327
4.69k
  uint32_t calculated_checksum         = 0;
328
4.69k
  uint32_t creation_time               = 0;
329
4.69k
  uint32_t data_size_upper             = 0;
330
4.69k
  uint32_t inode_change_time           = 0;
331
4.69k
  uint32_t modification_time           = 0;
332
4.69k
  uint32_t signature                   = 0;
333
4.69k
  uint32_t stored_checksum             = 0;
334
4.69k
  uint32_t supported_inode_flags       = 0;
335
4.69k
  uint32_t value_32bit                 = 0;
336
4.69k
  uint16_t extended_inode_size         = 0;
337
4.69k
  uint16_t file_acl_block_number_upper = 0;
338
4.69k
  uint16_t group_identifier_upper      = 0;
339
4.69k
  uint16_t number_of_blocks_upper      = 0;
340
4.69k
  uint16_t owner_identifier_upper      = 0;
341
4.69k
  uint16_t value_16bit                 = 0;
342
4.69k
  int result                           = 0;
343
344
#if defined( HAVE_DEBUG_OUTPUT )
345
  uint8_t value_data[ 8 ];
346
#endif
347
348
4.69k
  if( inode == NULL )
349
0
  {
350
0
    libcerror_error_set(
351
0
     error,
352
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
353
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
354
0
     "%s: invalid inode.",
355
0
     function );
356
357
0
    return( -1 );
358
0
  }
359
4.69k
  if( inode->extended_attributes_array != NULL )
360
0
  {
361
0
    libcerror_error_set(
362
0
     error,
363
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
365
0
     "%s: invalid inode - extended attributes array value already set.",
366
0
     function );
367
368
0
    return( -1 );
369
0
  }
370
4.69k
  if( io_handle == NULL )
371
0
  {
372
0
    libcerror_error_set(
373
0
     error,
374
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
375
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
376
0
     "%s: invalid IO handle.",
377
0
     function );
378
379
0
    return( -1 );
380
0
  }
381
4.69k
  if( data == NULL )
382
0
  {
383
0
    libcerror_error_set(
384
0
     error,
385
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
386
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
387
0
     "%s: invalid data.",
388
0
     function );
389
390
0
    return( -1 );
391
0
  }
392
4.69k
  if( ( data_size != 128 )
393
3.92k
   && ( data_size != 256 )
394
1.58k
   && ( data_size != 512 )
395
132
   && ( data_size != 1024 ) )
396
0
  {
397
0
    libcerror_error_set(
398
0
     error,
399
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
400
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
401
0
     "%s: unsupported data size.",
402
0
     function );
403
404
0
    return( -1 );
405
0
  }
406
#if defined( HAVE_DEBUG_OUTPUT )
407
  if( libcnotify_verbose != 0 )
408
  {
409
    libcnotify_printf(
410
     "%s: inode data:\n",
411
     function );
412
    libcnotify_print_data(
413
     data,
414
     data_size,
415
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
416
  }
417
#endif
418
4.69k
  result = libfsext_block_data_check_empty(
419
4.69k
            data,
420
4.69k
            data_size,
421
4.69k
            error );
422
423
4.69k
  if( result == -1 )
424
0
  {
425
0
    libcerror_error_set(
426
0
     error,
427
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
428
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
429
0
     "%s: unable to determine if inode is empty.",
430
0
     function );
431
432
0
    goto on_error;
433
0
  }
434
4.69k
  else if( result != 0 )
435
7
  {
436
7
    inode->is_empty = 1;
437
438
7
    return( 1 );
439
7
  }
440
4.68k
  inode->is_empty = 0;
441
442
  /* Check the inode flags and extended inode size first
443
   * since they can influence what values are stored in the inode
444
   */
445
4.68k
  byte_stream_copy_to_uint32_little_endian(
446
4.68k
   ( (fsext_inode_ext2_t *) data )->flags,
447
4.68k
   inode->flags );
448
449
4.68k
  if( data_size > 128 )
450
3.92k
  {
451
3.92k
    byte_stream_copy_to_uint16_little_endian(
452
3.92k
     ( (fsext_inode_ext3_t *) data )->extended_inode_size,
453
3.92k
     extended_inode_size );
454
455
3.92k
    if( extended_inode_size > ( data_size - sizeof( fsext_inode_ext2_t ) ) )
456
55
    {
457
55
      libcerror_error_set(
458
55
       error,
459
55
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
460
55
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
461
55
       "%s: invalid extended inode size value out of bounds.",
462
55
       function );
463
464
55
      goto on_error;
465
55
    }
466
3.92k
  }
467
4.63k
  byte_stream_copy_to_uint16_little_endian(
468
4.63k
   ( (fsext_inode_ext2_t *) data )->file_mode,
469
4.63k
   inode->file_mode );
470
471
4.63k
  byte_stream_copy_to_uint16_little_endian(
472
4.63k
   ( (fsext_inode_ext2_t *) data )->owner_identifier,
473
4.63k
   inode->owner_identifier );
474
475
4.63k
  byte_stream_copy_to_uint32_little_endian(
476
4.63k
   ( (fsext_inode_ext2_t *) data )->data_size,
477
4.63k
   inode->data_size );
478
479
4.63k
  if( ( inode->flags & LIBFSEXT_INODE_FLAG_IS_EXTENDED_ATTRIBUTE_INODE ) == 0 )
480
4.20k
  {
481
4.20k
    byte_stream_copy_to_uint32_little_endian(
482
4.20k
     ( (fsext_inode_ext2_t *) data )->access_time,
483
4.20k
     access_time );
484
485
4.20k
    inode->access_time  = (int32_t) access_time;
486
4.20k
    inode->access_time *= 1000000000;
487
488
4.20k
    byte_stream_copy_to_uint32_little_endian(
489
4.20k
     ( (fsext_inode_ext2_t *) data )->inode_change_time,
490
4.20k
     inode_change_time );
491
492
4.20k
    inode->inode_change_time  = (int32_t) inode_change_time;
493
4.20k
    inode->inode_change_time *= 1000000000;
494
495
4.20k
    byte_stream_copy_to_uint32_little_endian(
496
4.20k
     ( (fsext_inode_ext2_t *) data )->modification_time,
497
4.20k
     modification_time );
498
499
4.20k
    inode->modification_time  = (int32_t) modification_time;
500
4.20k
    inode->modification_time *= 1000000000;
501
4.20k
  }
502
4.63k
  byte_stream_copy_to_uint32_little_endian(
503
4.63k
   ( (fsext_inode_ext2_t *) data )->deletion_time,
504
4.63k
   inode->deletion_time );
505
506
4.63k
  byte_stream_copy_to_uint16_little_endian(
507
4.63k
   ( (fsext_inode_ext2_t *) data )->group_identifier,
508
4.63k
   inode->group_identifier );
509
510
4.63k
  byte_stream_copy_to_uint16_little_endian(
511
4.63k
   ( (fsext_inode_ext2_t *) data )->number_of_links,
512
4.63k
   inode->number_of_links );
513
514
4.63k
  byte_stream_copy_to_uint32_little_endian(
515
4.63k
   ( (fsext_inode_ext2_t *) data )->number_of_blocks,
516
4.63k
   inode->number_of_blocks );
517
518
#if defined( HAVE_DEBUG_OUTPUT )
519
  if( libcnotify_verbose != 0 )
520
  {
521
    libcnotify_printf(
522
     "%s: file mode\t\t\t\t\t: %" PRIo16 " (0x%04" PRIx16 ")\n",
523
     function,
524
     inode->file_mode,
525
     inode->file_mode );
526
    libfsext_debug_print_file_mode(
527
     inode->file_mode );
528
529
    libcnotify_printf(
530
     "%s: owner identifier (lower)\t\t\t: %" PRIu16 "\n",
531
     function,
532
     inode->owner_identifier );
533
534
    if( io_handle->format_version == 4 )
535
    {
536
      libcnotify_printf(
537
       "%s: data size (lower)\t\t\t\t: %" PRIu64 "\n",
538
       function,
539
       inode->data_size );
540
    }
541
    else
542
    {
543
      libcnotify_printf(
544
       "%s: data size\t\t\t\t\t: %" PRIu64 "\n",
545
       function,
546
       inode->data_size );
547
    }
548
    if( ( inode->flags & LIBFSEXT_INODE_FLAG_IS_EXTENDED_ATTRIBUTE_INODE ) == 0 )
549
    {
550
      if( libfsext_debug_print_posix_time_value(
551
           function,
552
           "access time (seconds)\t\t\t\t",
553
           ( (fsext_inode_ext2_t *) data )->access_time,
554
           4,
555
           LIBFDATETIME_ENDIAN_LITTLE,
556
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
557
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
558
           error ) != 1 )
559
      {
560
        libcerror_error_set(
561
         error,
562
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
563
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
564
         "%s: unable to print POSIX time value.",
565
         function );
566
567
        goto on_error;
568
      }
569
      if( libfsext_debug_print_posix_time_value(
570
           function,
571
           "inode change time (seconds)\t\t\t",
572
           ( (fsext_inode_ext2_t *) data )->inode_change_time,
573
           4,
574
           LIBFDATETIME_ENDIAN_LITTLE,
575
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
576
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
577
           error ) != 1 )
578
      {
579
        libcerror_error_set(
580
         error,
581
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
582
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
583
         "%s: unable to print POSIX time value.",
584
         function );
585
586
        goto on_error;
587
      }
588
      if( libfsext_debug_print_posix_time_value(
589
           function,
590
           "modification time (seconds)\t\t\t",
591
           ( (fsext_inode_ext2_t *) data )->modification_time,
592
           4,
593
           LIBFDATETIME_ENDIAN_LITTLE,
594
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
595
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
596
           error ) != 1 )
597
      {
598
        libcerror_error_set(
599
         error,
600
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
601
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
602
         "%s: unable to print POSIX time value.",
603
         function );
604
605
        goto on_error;
606
      }
607
    }
608
    else
609
    {
610
/* TODO implement, extended attribute value data checksum */
611
      byte_stream_copy_to_uint32_little_endian(
612
       ( (fsext_inode_ext2_t *) data )->access_time,
613
       value_32bit );
614
      libcnotify_printf(
615
       "%s: value data checksum\t\t\t\t: 0x%08" PRIx32 "\n",
616
       function,
617
       value_32bit );
618
619
/* TODO implement, lower 32-bit of extended attribute reference count */
620
      byte_stream_copy_to_uint32_little_endian(
621
       ( (fsext_inode_ext2_t *) data )->inode_change_time,
622
       value_32bit );
623
      libcnotify_printf(
624
       "%s: reference count (lower)\t\t\t: %" PRIu32 "\n",
625
       function,
626
       value_32bit );
627
628
/* TODO implement, lower 32-bit of extended attribute owner inode number */
629
      byte_stream_copy_to_uint32_little_endian(
630
       ( (fsext_inode_ext2_t *) data )->modification_time,
631
       value_32bit );
632
      libcnotify_printf(
633
       "%s: owner inode number\t\t\t\t: %" PRIu32 "\n",
634
       function,
635
       value_32bit );
636
    }
637
    if( libfsext_debug_print_posix_time_value(
638
         function,
639
         "deletion time\t\t\t\t\t",
640
         ( (fsext_inode_ext2_t *) data )->deletion_time,
641
         4,
642
         LIBFDATETIME_ENDIAN_LITTLE,
643
         LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
644
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
645
         error ) != 1 )
646
    {
647
      libcerror_error_set(
648
       error,
649
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
650
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
651
       "%s: unable to print POSIX time value.",
652
       function );
653
654
      goto on_error;
655
    }
656
    libcnotify_printf(
657
     "%s: group identifier (lower)\t\t\t: %" PRIu16 "\n",
658
     function,
659
     inode->group_identifier );
660
661
    libcnotify_printf(
662
     "%s: number of (hard) links\t\t\t: %" PRIu16 "\n",
663
     function,
664
     inode->number_of_links );
665
666
    if( io_handle->format_version == 4 )
667
    {
668
      libcnotify_printf(
669
       "%s: number of blocks (lower)\t\t\t: %" PRIu32 "\n",
670
       function,
671
       inode->number_of_blocks );
672
    }
673
    else
674
    {
675
      libcnotify_printf(
676
       "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
677
       function,
678
       inode->number_of_blocks );
679
    }
680
    libcnotify_printf(
681
     "%s: flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
682
     function,
683
     inode->flags );
684
    libfsext_debug_print_inode_flags(
685
     inode->flags );
686
    libcnotify_printf(
687
     "\n" );
688
689
    if( io_handle->format_version == 4 )
690
    {
691
      if( ( inode->flags & LIBFSEXT_INODE_FLAG_IS_EXTENDED_ATTRIBUTE_INODE ) == 0 )
692
      {
693
        byte_stream_copy_to_uint32_little_endian(
694
         ( (fsext_inode_ext4_t *) data )->version_lower,
695
         value_32bit );
696
        libcnotify_printf(
697
         "%s: version (lower)\t\t\t\t: %" PRIu32 "\n",
698
         function,
699
         value_32bit );
700
      }
701
      else
702
      {
703
/* TODO implement, upper 32-bit of extended attribute reference count */
704
        byte_stream_copy_to_uint32_little_endian(
705
         ( (fsext_inode_ext4_t *) data )->version_lower,
706
         value_32bit );
707
        libcnotify_printf(
708
         "%s: reference count (upper)\t\t\t: %" PRIu32 "\n",
709
         function,
710
         value_32bit );
711
      }
712
    }
713
    else
714
    {
715
      byte_stream_copy_to_uint32_little_endian(
716
       ( (fsext_inode_ext2_t *) data )->unknown1,
717
       value_32bit );
718
      libcnotify_printf(
719
       "%s: unknown (reserved)\t\t\t\t: %" PRIu32 "\n",
720
       function,
721
       value_32bit );
722
    }
723
  }
724
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
725
726
/* TODO check if corresponding flag in superblock is set? */
727
728
4.63k
  supported_inode_flags = 0x00000001UL
729
4.63k
                        | 0x00000002UL
730
4.63k
                        | 0x00000008UL
731
4.63k
                        | 0x00000010UL
732
4.63k
                        | 0x00000020UL
733
4.63k
                        | 0x00000040UL
734
4.63k
                        | 0x00000080UL
735
4.63k
                        | 0x00001000UL
736
4.63k
                        | 0x00004000UL
737
4.63k
                        | 0x00008000UL
738
4.63k
                        | 0x00010000UL
739
4.63k
                        | 0x00080000UL
740
4.63k
                        | 0x00200000UL
741
4.63k
                        | 0x10000000UL;
742
743
4.63k
  if( ( inode->flags & ~( supported_inode_flags ) ) != 0 )
744
61
  {
745
61
    libcerror_error_set(
746
61
     error,
747
61
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
748
61
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
749
61
     "%s: unsupported inode flags: 0x%08" PRIx32 ".",
750
61
     function,
751
61
     inode->flags );
752
753
61
    goto on_error;
754
61
  }
755
4.57k
  if( memory_copy(
756
4.57k
       inode->data_reference,
757
4.57k
       ( (fsext_inode_ext2_t *) data )->data_reference,
758
4.57k
       60 ) == NULL )
759
0
  {
760
0
    libcerror_error_set(
761
0
     error,
762
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
763
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
764
0
     "%s: unable to copy data reference.",
765
0
     function );
766
767
0
    goto on_error;
768
0
  }
769
4.57k
  byte_stream_copy_to_uint32_little_endian(
770
4.57k
   ( (fsext_inode_ext2_t *) data )->nfs_generation_number,
771
4.57k
   inode->nfs_generation_number );
772
773
4.57k
  byte_stream_copy_to_uint32_little_endian(
774
4.57k
   ( (fsext_inode_ext2_t *) data )->file_acl_block_number,
775
4.57k
   inode->file_acl_block_number );
776
777
4.57k
  if( io_handle->format_version == 4 )
778
3.52k
  {
779
3.52k
    byte_stream_copy_to_uint32_little_endian(
780
3.52k
     ( (fsext_inode_ext4_t *) data )->data_size_upper,
781
3.52k
     data_size_upper );
782
783
3.52k
    inode->data_size |= (uint64_t) data_size_upper << 32;
784
3.52k
  }
785
1.05k
  else
786
1.05k
  {
787
1.05k
    byte_stream_copy_to_uint32_little_endian(
788
1.05k
     ( (fsext_inode_ext2_t *) data )->directory_acl,
789
1.05k
     inode->directory_acl );
790
1.05k
  }
791
4.57k
  byte_stream_copy_to_uint32_little_endian(
792
4.57k
   ( (fsext_inode_ext2_t *) data )->fragment_block_address,
793
4.57k
   inode->fragment_block_address );
794
795
4.57k
  if( io_handle->format_version == 4 )
796
3.52k
  {
797
3.52k
    byte_stream_copy_to_uint16_little_endian(
798
3.52k
     ( (fsext_inode_ext4_t *) data )->number_of_blocks_upper,
799
3.52k
     number_of_blocks_upper );
800
801
3.52k
    inode->number_of_blocks |= (uint64_t) number_of_blocks_upper << 32;
802
803
3.52k
    byte_stream_copy_to_uint16_little_endian(
804
3.52k
     ( (fsext_inode_ext4_t *) data )->file_acl_block_number_upper,
805
3.52k
     file_acl_block_number_upper );
806
3.52k
  }
807
1.05k
  else
808
1.05k
  {
809
    /* TODO: fragment_block_index */
810
811
    /* TODO: fragment_size */
812
1.05k
  }
813
4.57k
  byte_stream_copy_to_uint16_little_endian(
814
4.57k
   ( (fsext_inode_ext2_t *) data )->owner_identifier_upper,
815
4.57k
   owner_identifier_upper );
816
817
4.57k
  inode->owner_identifier |= (uint32_t) owner_identifier_upper << 16;
818
819
4.57k
  byte_stream_copy_to_uint16_little_endian(
820
4.57k
   ( (fsext_inode_ext2_t *) data )->group_identifier_upper,
821
4.57k
   group_identifier_upper );
822
823
4.57k
  inode->group_identifier |= (uint32_t) group_identifier_upper << 16;
824
825
4.57k
  if( io_handle->format_version == 4 )
826
3.52k
  {
827
3.52k
    byte_stream_copy_to_uint16_little_endian(
828
3.52k
     ( (fsext_inode_ext4_t *) data )->checksum_lower,
829
3.52k
     value_16bit );
830
831
3.52k
    stored_checksum = value_16bit;
832
833
3.52k
    if( extended_inode_size >= 4 )
834
1.73k
    {
835
1.73k
      byte_stream_copy_to_uint16_little_endian(
836
1.73k
       ( (fsext_inode_ext4_t *) data )->checksum_upper,
837
1.73k
       value_16bit );
838
839
1.73k
      stored_checksum |= (uint32_t) value_16bit << 16;
840
1.73k
    }
841
3.52k
  }
842
#if defined( HAVE_DEBUG_OUTPUT )
843
  if( libcnotify_verbose != 0 )
844
  {
845
    if( ( io_handle->format_version == 4 )
846
     && ( ( inode->flags & 0x10080000UL ) != 0 ) )
847
    {
848
      libcnotify_printf(
849
       "%s: data reference:\n",
850
       function );
851
      libcnotify_print_data(
852
       inode->data_reference,
853
       60,
854
       0 );
855
    }
856
    else if( ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_CHARACTER_DEVICE )
857
          || ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_BLOCK_DEVICE ) )
858
    {
859
      libcnotify_printf(
860
       "%s: minor device number\t\t\t\t: %" PRIu8 "\n",
861
       function,
862
       inode->data_reference[ 0 ] );
863
864
      libcnotify_printf(
865
       "%s: major device number\t\t\t\t: %" PRIu8 "\n",
866
       function,
867
       inode->data_reference[ 1 ] );
868
    }
869
    else if( ( ( inode->file_mode & 0xf000 ) == 0xa000 )
870
          && ( inode->data_size < 60 ) )
871
    {
872
      libcnotify_printf(
873
       "%s: symbolic link data:\n",
874
       function );
875
      libcnotify_print_data(
876
       inode->data_reference,
877
       60,
878
       0 );
879
    }
880
    else
881
    {
882
      libcnotify_printf(
883
       "%s: direct block numbers\t\t\t\t:",
884
       function );
885
886
      for( data_offset = 0;
887
           data_offset < 48;
888
           data_offset += 4 )
889
      {
890
        byte_stream_copy_to_uint32_little_endian(
891
         &( ( inode->data_reference )[ data_offset ] ),
892
         value_32bit );
893
894
        if( data_offset == 0 )
895
        {
896
          libcnotify_printf(
897
           " %" PRIu32 "",
898
           value_32bit );
899
        }
900
        else
901
        {
902
          libcnotify_printf(
903
           ", %" PRIu32 "",
904
           value_32bit );
905
        }
906
      }
907
      libcnotify_printf(
908
       "\n" );
909
910
      byte_stream_copy_to_uint32_little_endian(
911
       &( ( inode->data_reference )[ data_offset ] ),
912
       value_32bit );
913
914
      data_offset += 4;
915
916
      libcnotify_printf(
917
       "%s: indirect block number\t\t\t\t: %" PRIu32 "\n",
918
       function,
919
       value_32bit );
920
921
      byte_stream_copy_to_uint32_little_endian(
922
       &( ( inode->data_reference )[ data_offset ] ),
923
       value_32bit );
924
925
      data_offset += 4;
926
927
      libcnotify_printf(
928
       "%s: double indirect block number\t\t\t: %" PRIu32 "\n",
929
       function,
930
       value_32bit );
931
932
      byte_stream_copy_to_uint32_little_endian(
933
       &( ( inode->data_reference )[ data_offset ] ),
934
       value_32bit );
935
936
      data_offset += 4;
937
938
      libcnotify_printf(
939
       "%s: triple indirect block number\t\t\t: %" PRIu32 "\n",
940
       function,
941
       value_32bit );
942
    }
943
    libcnotify_printf(
944
     "%s: NFS generation number\t\t\t\t: %" PRIu32 "\n",
945
     function,
946
     inode->nfs_generation_number );
947
948
    if( io_handle->format_version == 4 )
949
    {
950
      libcnotify_printf(
951
       "%s: file ACL block number (lower)\t\t\t: %" PRIu32 "\n",
952
       function,
953
       inode->file_acl_block_number );
954
955
      libcnotify_printf(
956
       "%s: data size (upper)\t\t\t\t: %" PRIu32 "\n",
957
       function,
958
       data_size_upper );
959
    }
960
    else
961
    {
962
      libcnotify_printf(
963
       "%s: file ACL block number\t\t\t\t: %" PRIu32 "\n",
964
       function,
965
       inode->file_acl_block_number );
966
967
      libcnotify_printf(
968
       "%s: directory ACL\t\t\t\t\t: %" PRIu32 "\n",
969
       function,
970
       inode->directory_acl );
971
    }
972
    libcnotify_printf(
973
     "%s: fragment block address\t\t\t: %" PRIu32 "\n",
974
     function,
975
     inode->fragment_block_address );
976
977
    if( io_handle->format_version == 4 )
978
    {
979
      libcnotify_printf(
980
       "%s: number of blocks (upper)\t\t\t: %" PRIu16 "\n",
981
       function,
982
       number_of_blocks_upper );
983
984
      libcnotify_printf(
985
       "%s: file ACL block number (upper)\t\t\t: %" PRIu16 "\n",
986
       function,
987
       file_acl_block_number_upper );
988
    }
989
    else
990
    {
991
      libcnotify_printf(
992
       "%s: fragment block index\t\t\t\t: %" PRIu8 "\n",
993
       function,
994
       ( (fsext_inode_ext2_t *) data )->fragment_block_index );
995
996
      libcnotify_printf(
997
       "%s: fragment size\t\t\t\t\t: %" PRIu8 "\n",
998
       function,
999
       ( (fsext_inode_ext2_t *) data )->fragment_size );
1000
1001
      byte_stream_copy_to_uint16_little_endian(
1002
       ( (fsext_inode_ext2_t *) data )->padding1,
1003
       value_16bit );
1004
      libcnotify_printf(
1005
       "%s: padding1\t\t\t\t\t: %" PRIu16 "\n",
1006
       function,
1007
       value_16bit );
1008
    }
1009
    libcnotify_printf(
1010
     "%s: owner identifier (upper)\t\t\t: %" PRIu16 "\n",
1011
     function,
1012
     owner_identifier_upper );
1013
1014
    libcnotify_printf(
1015
     "%s: group identifier (upper)\t\t\t: %" PRIu16 "\n",
1016
     function,
1017
     group_identifier_upper );
1018
1019
    if( io_handle->format_version == 4 )
1020
    {
1021
      byte_stream_copy_to_uint16_little_endian(
1022
       ( (fsext_inode_ext4_t *) data )->checksum_lower,
1023
       value_16bit );
1024
      libcnotify_printf(
1025
       "%s: checksum (lower)\t\t\t\t: 0x%04" PRIx16 "\n",
1026
       function,
1027
       value_16bit );
1028
1029
      byte_stream_copy_to_uint16_little_endian(
1030
       ( (fsext_inode_ext4_t *) data )->unknown2,
1031
       value_16bit );
1032
      libcnotify_printf(
1033
       "%s: unknown (reserved)\t\t\t\t: %" PRIu16 "\n",
1034
       function,
1035
       value_16bit );
1036
    }
1037
    else
1038
    {
1039
      byte_stream_copy_to_uint32_little_endian(
1040
       ( (fsext_inode_ext2_t *) data )->unknown2,
1041
       value_32bit );
1042
      libcnotify_printf(
1043
       "%s: unknown (reserved)\t\t\t\t: %" PRIu32 "\n",
1044
       function,
1045
       value_32bit );
1046
    }
1047
    if( data_size > 128 )
1048
    {
1049
      libcnotify_printf(
1050
       "%s: extended inode size\t\t\t\t: %" PRIu16 "\n",
1051
       function,
1052
       extended_inode_size );
1053
    }
1054
  }
1055
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1056
1057
4.57k
  if( extended_inode_size >= 28 )
1058
1.90k
  {
1059
1.90k
    if( ( inode->flags & LIBFSEXT_INODE_FLAG_IS_EXTENDED_ATTRIBUTE_INODE ) == 0 )
1060
1.72k
    {
1061
1.72k
      byte_stream_copy_to_uint32_little_endian(
1062
1.72k
       ( (fsext_inode_ext4_t *) data )->inode_change_time_extra,
1063
1.72k
       value_32bit );
1064
1065
1.72k
      if( ( value_32bit & 0x00000003UL ) != 0 )
1066
569
      {
1067
569
        inode->inode_change_time  = 0x100000000UL;
1068
569
        inode->inode_change_time *= ( value_32bit & 0x00000003UL );
1069
569
        inode->inode_change_time += (int32_t) inode_change_time;
1070
1071
569
        if( ( inode->inode_change_time < ( (int64_t) INT64_MIN / 1000000000 ) )
1072
569
         || ( inode->inode_change_time > ( (int64_t) INT64_MAX / 1000000000 ) ) )
1073
6
        {
1074
6
          libcerror_error_set(
1075
6
           error,
1076
6
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1077
6
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1078
6
           "%s: unsupported inode change time value out of bounds.",
1079
6
           function );
1080
1081
6
          goto on_error;
1082
6
        }
1083
563
        inode->inode_change_time *= 1000000000;
1084
563
      }
1085
1.72k
      value_32bit >>= 2;
1086
1087
1.72k
      if( ( inode->inode_change_time < ( (int64_t) INT64_MIN + value_32bit ) )
1088
1.72k
       || ( inode->inode_change_time > ( (int64_t) INT64_MAX - value_32bit ) ) )
1089
52
      {
1090
52
        libcerror_error_set(
1091
52
         error,
1092
52
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1093
52
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1094
52
         "%s: unsupported inode change time value out of bounds.",
1095
52
         function );
1096
1097
52
        goto on_error;
1098
52
      }
1099
1.66k
      inode->inode_change_time += value_32bit;
1100
1101
1.66k
      byte_stream_copy_to_uint32_little_endian(
1102
1.66k
       ( (fsext_inode_ext4_t *) data )->modification_time_extra,
1103
1.66k
       value_32bit );
1104
1105
1.66k
      if( ( value_32bit & 0x00000003UL ) != 0 )
1106
621
      {
1107
621
        inode->modification_time  = 0x100000000UL;
1108
621
        inode->modification_time *= ( value_32bit & 0x00000003UL );
1109
621
        inode->modification_time += (int32_t) modification_time;
1110
1111
621
        if( ( inode->modification_time < ( (int64_t) INT64_MIN / 1000000000 ) )
1112
621
         || ( inode->modification_time > ( (int64_t) INT64_MAX / 1000000000 ) ) )
1113
8
        {
1114
8
          libcerror_error_set(
1115
8
           error,
1116
8
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1117
8
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1118
8
           "%s: unsupported modification time value out of bounds.",
1119
8
           function );
1120
1121
8
          goto on_error;
1122
8
        }
1123
613
        inode->modification_time *= 1000000000;
1124
613
      }
1125
1.66k
      value_32bit >>= 2;
1126
1127
1.66k
      if( ( inode->modification_time < ( (int64_t) INT64_MIN + value_32bit ) )
1128
1.66k
       || ( inode->modification_time > ( (int64_t) INT64_MAX - value_32bit ) ) )
1129
46
      {
1130
46
        libcerror_error_set(
1131
46
         error,
1132
46
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1133
46
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1134
46
         "%s: unsupported modification time value out of bounds.",
1135
46
         function );
1136
1137
46
        goto on_error;
1138
46
      }
1139
1.61k
      inode->modification_time += value_32bit;
1140
1141
1.61k
      byte_stream_copy_to_uint32_little_endian(
1142
1.61k
       ( (fsext_inode_ext4_t *) data )->access_time_extra,
1143
1.61k
       value_32bit );
1144
1145
1.61k
      if( ( value_32bit & 0x00000003UL ) != 0 )
1146
791
      {
1147
791
        inode->access_time  = 0x100000000UL;
1148
791
        inode->access_time *= ( value_32bit & 0x00000003UL );
1149
791
        inode->access_time += (int32_t) access_time;
1150
1151
791
        if( ( inode->access_time < ( (int64_t) INT64_MIN / 1000000000 ) )
1152
791
         || ( inode->access_time > ( (int64_t) INT64_MAX / 1000000000 ) ) )
1153
10
        {
1154
10
          libcerror_error_set(
1155
10
           error,
1156
10
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1157
10
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1158
10
           "%s: unsupported access time value out of bounds.",
1159
10
           function );
1160
1161
10
          goto on_error;
1162
10
        }
1163
781
        inode->access_time *= 1000000000;
1164
781
      }
1165
1.60k
      value_32bit >>= 2;
1166
1167
1.60k
      if( ( inode->access_time < ( (int64_t) INT64_MIN + value_32bit ) )
1168
1.60k
       || ( inode->access_time > ( (int64_t) INT64_MAX - value_32bit ) ) )
1169
39
      {
1170
39
        libcerror_error_set(
1171
39
         error,
1172
39
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1173
39
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1174
39
         "%s: unsupported access time value out of bounds.",
1175
39
         function );
1176
1177
39
        goto on_error;
1178
39
      }
1179
1.56k
      inode->access_time += value_32bit;
1180
1.56k
    }
1181
1.74k
    byte_stream_copy_to_uint32_little_endian(
1182
1.74k
     ( (fsext_inode_ext4_t *) data )->creation_time,
1183
1.74k
     creation_time );
1184
1185
1.74k
    byte_stream_copy_to_uint32_little_endian(
1186
1.74k
     ( (fsext_inode_ext4_t *) data )->creation_time_extra,
1187
1.74k
     value_32bit );
1188
1189
1.74k
    if( ( value_32bit & 0x00000003UL ) == 0 )
1190
1.10k
    {
1191
1.10k
      inode->creation_time = (int32_t) creation_time;
1192
1.10k
    }
1193
639
    else
1194
639
    {
1195
639
      inode->creation_time  = 0x100000000UL;
1196
639
      inode->creation_time *= ( value_32bit & 0x00000003UL );
1197
639
      inode->creation_time += (int32_t) creation_time;
1198
639
    }
1199
1.74k
    value_32bit >>= 2;
1200
1201
1.74k
    if( ( inode->creation_time < ( ( (int64_t) INT64_MIN + value_32bit ) / 1000000000 ) )
1202
1.74k
     || ( inode->creation_time > ( ( (int64_t) INT64_MAX - value_32bit ) / 1000000000 ) ) )
1203
85
    {
1204
85
      libcerror_error_set(
1205
85
       error,
1206
85
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1207
85
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1208
85
       "%s: unsupported creation time value out of bounds.",
1209
85
       function );
1210
1211
85
      goto on_error;
1212
85
    }
1213
1.65k
    inode->creation_time *= 1000000000;
1214
1.65k
    inode->creation_time += value_32bit;
1215
1216
1.65k
    inode->has_creation_time = 1;
1217
1218
#if defined( HAVE_DEBUG_OUTPUT )
1219
    if( libcnotify_verbose != 0 )
1220
    {
1221
      byte_stream_copy_to_uint16_little_endian(
1222
       ( (fsext_inode_ext4_t *) data )->checksum_upper,
1223
       value_16bit );
1224
      libcnotify_printf(
1225
       "%s: checksum (upper)\t\t\t\t: 0x%04" PRIx16 "\n",
1226
       function,
1227
       value_16bit );
1228
1229
      byte_stream_copy_to_uint32_little_endian(
1230
       ( (fsext_inode_ext4_t *) data )->inode_change_time_extra,
1231
       value_32bit );
1232
      libcnotify_printf(
1233
       "%s: inode change time extra\t\t\t: 0x%04" PRIx32 "\n",
1234
       function,
1235
       value_32bit );
1236
1237
      byte_stream_copy_to_uint32_little_endian(
1238
       ( (fsext_inode_ext4_t *) data )->modification_time_extra,
1239
       value_32bit );
1240
      libcnotify_printf(
1241
       "%s: modification time extra\t\t\t: 0x%04" PRIx32 "\n",
1242
       function,
1243
       value_32bit );
1244
1245
      byte_stream_copy_to_uint32_little_endian(
1246
       ( (fsext_inode_ext4_t *) data )->access_time_extra,
1247
       value_32bit );
1248
      libcnotify_printf(
1249
       "%s: access time extra\t\t\t\t: 0x%04" PRIx32 "\n",
1250
       function,
1251
       value_32bit );
1252
1253
      if( libfsext_debug_print_posix_time_value(
1254
           function,
1255
           "creation time (seconds)\t\t\t",
1256
           ( (fsext_inode_ext4_t *) data )->creation_time,
1257
           4,
1258
           LIBFDATETIME_ENDIAN_LITTLE,
1259
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
1260
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
1261
           error ) != 1 )
1262
      {
1263
        libcerror_error_set(
1264
         error,
1265
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1266
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1267
         "%s: unable to print POSIX time value.",
1268
         function );
1269
1270
        goto on_error;
1271
      }
1272
      byte_stream_copy_to_uint32_little_endian(
1273
       ( (fsext_inode_ext4_t *) data )->creation_time_extra,
1274
       value_32bit );
1275
      libcnotify_printf(
1276
       "%s: creation time extra\t\t\t\t: 0x%04" PRIx32 "\n",
1277
       function,
1278
       value_32bit );
1279
1280
      byte_stream_copy_to_uint32_little_endian(
1281
       ( (fsext_inode_ext4_t *) data )->version_upper,
1282
       value_32bit );
1283
      libcnotify_printf(
1284
       "%s: version (upper)\t\t\t\t: %" PRIu32 "\n",
1285
       function,
1286
       value_32bit );
1287
1288
      byte_stream_copy_to_uint32_little_endian(
1289
       ( (fsext_inode_ext4_t *) data )->project_identifier,
1290
       value_32bit );
1291
      libcnotify_printf(
1292
       "%s: project identifier\t\t\t\t: %" PRIu32 "\n",
1293
       function,
1294
       value_32bit );
1295
    }
1296
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1297
1.65k
  }
1298
#if defined( HAVE_DEBUG_OUTPUT )
1299
  if( libcnotify_verbose != 0 )
1300
  {
1301
    if( io_handle->format_version == 4 )
1302
    {
1303
      libcnotify_printf(
1304
       "%s: data size\t\t\t\t\t: %" PRIu64 "\n",
1305
       function,
1306
       inode->data_size );
1307
1308
    }
1309
    if( extended_inode_size >= 28 )
1310
    {
1311
      byte_stream_copy_from_uint64_little_endian(
1312
       value_data,
1313
       inode->inode_change_time );
1314
1315
      if( libfsext_debug_print_posix_time_value(
1316
           function,
1317
           "inode change time\t\t\t\t",
1318
           value_data,
1319
           8,
1320
           LIBFDATETIME_ENDIAN_LITTLE,
1321
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
1322
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
1323
           error ) != 1 )
1324
      {
1325
        libcerror_error_set(
1326
         error,
1327
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1328
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1329
         "%s: unable to print POSIX time value.",
1330
         function );
1331
1332
        goto on_error;
1333
      }
1334
      byte_stream_copy_from_uint64_little_endian(
1335
       value_data,
1336
       inode->modification_time );
1337
1338
      if( libfsext_debug_print_posix_time_value(
1339
           function,
1340
           "modification time\t\t\t\t",
1341
           value_data,
1342
           8,
1343
           LIBFDATETIME_ENDIAN_LITTLE,
1344
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
1345
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
1346
           error ) != 1 )
1347
      {
1348
        libcerror_error_set(
1349
         error,
1350
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1351
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1352
         "%s: unable to print POSIX time value.",
1353
         function );
1354
1355
        goto on_error;
1356
      }
1357
      byte_stream_copy_from_uint64_little_endian(
1358
       value_data,
1359
       inode->access_time );
1360
1361
      if( libfsext_debug_print_posix_time_value(
1362
           function,
1363
           "access time\t\t\t\t\t",
1364
           value_data,
1365
           8,
1366
           LIBFDATETIME_ENDIAN_LITTLE,
1367
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
1368
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
1369
           error ) != 1 )
1370
      {
1371
        libcerror_error_set(
1372
         error,
1373
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1374
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1375
         "%s: unable to print POSIX time value.",
1376
         function );
1377
1378
        goto on_error;
1379
      }
1380
      byte_stream_copy_from_uint64_little_endian(
1381
       value_data,
1382
       inode->creation_time );
1383
1384
      if( libfsext_debug_print_posix_time_value(
1385
           function,
1386
           "creation time\t\t\t\t\t",
1387
           value_data,
1388
           8,
1389
           LIBFDATETIME_ENDIAN_LITTLE,
1390
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_NANO_SECONDS_64BIT_SIGNED,
1391
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
1392
           error ) != 1 )
1393
      {
1394
        libcerror_error_set(
1395
         error,
1396
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1397
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1398
         "%s: unable to print POSIX time value.",
1399
         function );
1400
1401
        goto on_error;
1402
      }
1403
      libcnotify_printf(
1404
       "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
1405
       function,
1406
       stored_checksum );
1407
1408
/* TODO print version */
1409
    }
1410
  }
1411
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1412
1413
4.32k
  if( ( io_handle->read_only_compatible_features_flags & LIBFSEXT_READ_ONLY_COMPATIBLE_FEATURES_FLAG_METADATA_CHECKSUM ) != 0 )
1414
131
  {
1415
131
    byte_stream_copy_from_uint32_little_endian(
1416
131
     checksum_data,
1417
131
     inode->inode_number );
1418
1419
131
    if( libfsext_checksum_calculate_crc32(
1420
131
         &calculated_checksum,
1421
131
         checksum_data,
1422
131
         4,
1423
131
         io_handle->metadata_checksum_seed,
1424
131
         error ) != 1 )
1425
0
    {
1426
0
      libcerror_error_set(
1427
0
       error,
1428
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1429
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1430
0
       "%s: unable to calculate CRC-32.",
1431
0
       function );
1432
1433
0
      return( -1 );
1434
0
    }
1435
131
    if( libfsext_checksum_calculate_crc32(
1436
131
         &calculated_checksum,
1437
131
         ( (fsext_inode_ext4_t *) data )->nfs_generation_number,
1438
131
         4,
1439
131
         calculated_checksum,
1440
131
         error ) != 1 )
1441
0
    {
1442
0
      libcerror_error_set(
1443
0
       error,
1444
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1445
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1446
0
       "%s: unable to calculate CRC-32.",
1447
0
       function );
1448
1449
0
      return( -1 );
1450
0
    }
1451
131
    if( libfsext_checksum_calculate_crc32(
1452
131
         &calculated_checksum,
1453
131
         data,
1454
131
         124,
1455
131
         calculated_checksum,
1456
131
         error ) != 1 )
1457
0
    {
1458
0
      libcerror_error_set(
1459
0
       error,
1460
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1461
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1462
0
       "%s: unable to calculate CRC-32.",
1463
0
       function );
1464
1465
0
      return( -1 );
1466
0
    }
1467
131
    if( libfsext_checksum_calculate_crc32(
1468
131
         &calculated_checksum,
1469
131
         empty_checksum_data,
1470
131
         2,
1471
131
         calculated_checksum,
1472
131
         error ) != 1 )
1473
0
    {
1474
0
      libcerror_error_set(
1475
0
       error,
1476
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1477
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1478
0
       "%s: unable to calculate CRC-32.",
1479
0
       function );
1480
1481
0
      return( -1 );
1482
0
    }
1483
131
    if( libfsext_checksum_calculate_crc32(
1484
131
         &calculated_checksum,
1485
131
         &( data[ 126 ] ),
1486
131
         2,
1487
131
         calculated_checksum,
1488
131
         error ) != 1 )
1489
0
    {
1490
0
      libcerror_error_set(
1491
0
       error,
1492
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1493
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1494
0
       "%s: unable to calculate CRC-32.",
1495
0
       function );
1496
1497
0
      return( -1 );
1498
0
    }
1499
131
    if( data_size > 128 )
1500
69
    {
1501
69
      if( libfsext_checksum_calculate_crc32(
1502
69
           &calculated_checksum,
1503
69
           &( data[ 128 ] ),
1504
69
           2,
1505
69
           calculated_checksum,
1506
69
           error ) != 1 )
1507
0
      {
1508
0
        libcerror_error_set(
1509
0
         error,
1510
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1511
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1512
0
         "%s: unable to calculate CRC-32.",
1513
0
         function );
1514
1515
0
        return( -1 );
1516
0
      }
1517
69
      if( libfsext_checksum_calculate_crc32(
1518
69
           &calculated_checksum,
1519
69
           empty_checksum_data,
1520
69
           2,
1521
69
           calculated_checksum,
1522
69
           error ) != 1 )
1523
0
      {
1524
0
        libcerror_error_set(
1525
0
         error,
1526
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1527
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1528
0
         "%s: unable to calculate CRC-32.",
1529
0
         function );
1530
1531
0
        return( -1 );
1532
0
      }
1533
69
      if( libfsext_checksum_calculate_crc32(
1534
69
           &calculated_checksum,
1535
69
           &( data[ 132 ] ),
1536
69
           data_size - 132,
1537
69
           calculated_checksum,
1538
69
           error ) != 1 )
1539
0
      {
1540
0
        libcerror_error_set(
1541
0
         error,
1542
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1543
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1544
0
         "%s: unable to calculate CRC-32.",
1545
0
         function );
1546
1547
0
        return( -1 );
1548
0
      }
1549
69
    }
1550
131
    calculated_checksum = 0xffffffffUL - calculated_checksum;
1551
1552
131
    if( ( stored_checksum != 0 )
1553
44
     && ( stored_checksum != calculated_checksum ) )
1554
44
    {
1555
#if defined( HAVE_DEBUG_OUTPUT )
1556
      if( libcnotify_verbose != 0 )
1557
      {
1558
        libcnotify_printf(
1559
         "%s: mismatch in checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
1560
         function,
1561
         stored_checksum,
1562
         calculated_checksum );
1563
      }
1564
#endif
1565
44
    }
1566
131
  }
1567
4.32k
  data_offset = 128 + extended_inode_size;
1568
1569
4.32k
  if( extended_inode_size >= 28 )
1570
1.65k
  {
1571
#if defined( HAVE_DEBUG_OUTPUT )
1572
    if( libcnotify_verbose != 0 )
1573
    {
1574
      libcnotify_printf(
1575
       "%s: unknown exended inode data:\n",
1576
       function );
1577
      libcnotify_print_data(
1578
       &( data[ sizeof( fsext_inode_ext4_t ) ] ),
1579
       data_offset - sizeof( fsext_inode_ext4_t ),
1580
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1581
    }
1582
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1583
1584
1.65k
    inode->file_acl_block_number |= (uint64_t) file_acl_block_number_upper << 32;
1585
1.65k
  }
1586
#if defined( HAVE_DEBUG_OUTPUT )
1587
  else if( libcnotify_verbose != 0 )
1588
  {
1589
    libcnotify_printf(
1590
     "\n" );
1591
  }
1592
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1593
1594
4.32k
  if( data_offset < ( data_size - 4 ) )
1595
3.42k
  {
1596
3.42k
    byte_stream_copy_to_uint32_little_endian(
1597
3.42k
     &( data[ data_offset ] ),
1598
3.42k
     signature );
1599
3.42k
  }
1600
4.32k
  if( signature == 0xea020000UL )
1601
271
  {
1602
#if defined( HAVE_DEBUG_OUTPUT )
1603
    if( libcnotify_verbose != 0 )
1604
    {
1605
      libcnotify_printf(
1606
       "%s: extended attributes data:\n",
1607
       function );
1608
      libcnotify_print_data(
1609
       &( data[ data_offset ] ),
1610
       data_size - data_offset,
1611
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1612
    }
1613
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1614
1615
271
    if( libcdata_array_initialize(
1616
271
         &( inode->extended_attributes_array ),
1617
271
         0,
1618
271
         error ) != 1 )
1619
0
    {
1620
0
      libcerror_error_set(
1621
0
       error,
1622
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1623
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1624
0
       "%s: unable to create extended attributes array.",
1625
0
       function );
1626
1627
0
      goto on_error;
1628
0
    }
1629
271
    if( libfsext_attributes_block_read_entries_data(
1630
271
         &( data[ data_offset + 4 ] ),
1631
271
         data_size - data_offset - 4,
1632
271
         0,
1633
271
         inode->extended_attributes_array,
1634
271
         error ) != 1 )
1635
149
    {
1636
149
      libcerror_error_set(
1637
149
       error,
1638
149
       LIBCERROR_ERROR_DOMAIN_IO,
1639
149
       LIBCERROR_IO_ERROR_READ_FAILED,
1640
149
       "%s: unable to read extended attributes entries.",
1641
149
       function );
1642
1643
149
      goto on_error;
1644
149
    }
1645
271
  }
1646
#if defined( HAVE_DEBUG_OUTPUT )
1647
  else if( libcnotify_verbose != 0 )
1648
  {
1649
    if( data_offset < data_size )
1650
    {
1651
      libcnotify_printf(
1652
       "%s: trailing data:\n",
1653
       function );
1654
      libcnotify_print_data(
1655
       &( data[ data_offset ] ),
1656
       data_size - data_offset,
1657
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1658
    }
1659
  }
1660
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1661
1662
4.17k
  return( 1 );
1663
1664
511
on_error:
1665
511
  if( inode->extended_attributes_array != NULL )
1666
149
  {
1667
149
    libcdata_array_free(
1668
149
     &( inode->extended_attributes_array ),
1669
149
     (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_attribute_values_free,
1670
149
     NULL );
1671
149
  }
1672
511
  return( -1 );
1673
4.32k
}
1674
1675
/* Reads the inode data reference
1676
 * Returns 1 if successful or -1 on error
1677
 */
1678
int libfsext_inode_read_data_reference(
1679
     libfsext_inode_t *inode,
1680
     libfsext_io_handle_t *io_handle,
1681
     libbfio_handle_t *file_io_handle,
1682
     libcerror_error_t **error )
1683
4.18k
{
1684
4.18k
  static char *function     = "libfsext_inode_read_data_reference";
1685
4.18k
  uint32_t number_of_blocks = 0;
1686
1687
4.18k
  if( inode == NULL )
1688
0
  {
1689
0
    libcerror_error_set(
1690
0
     error,
1691
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1692
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1693
0
     "%s: invalid inode.",
1694
0
     function );
1695
1696
0
    return( -1 );
1697
0
  }
1698
4.18k
  if( io_handle == NULL )
1699
0
  {
1700
0
    libcerror_error_set(
1701
0
     error,
1702
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1703
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1704
0
     "%s: invalid IO handle.",
1705
0
     function );
1706
1707
0
    return( -1 );
1708
0
  }
1709
4.18k
  if( io_handle->block_size == 0 )
1710
0
  {
1711
0
    libcerror_error_set(
1712
0
     error,
1713
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1714
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1715
0
     "%s: invalid IO handle - block size value out of bounds.",
1716
0
     function );
1717
1718
0
    return( -1 );
1719
0
  }
1720
4.18k
  if( ( io_handle->format_version == 4 )
1721
3.19k
   && ( ( inode->flags & LIBFSEXT_INODE_FLAG_COMPRESSED_DATA ) != 0 ) )
1722
0
  {
1723
0
    libcerror_error_set(
1724
0
     error,
1725
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1726
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1727
0
     "%s: compressed data currently not supported.",
1728
0
     function );
1729
1730
0
    return( -1 );
1731
0
  }
1732
4.18k
  if( inode->data_size > 0 )
1733
4.05k
  {
1734
4.05k
    if( ( inode->data_size / io_handle->block_size ) > (uint64_t) ( UINT32_MAX - 1 ) )
1735
192
    {
1736
192
      libcerror_error_set(
1737
192
       error,
1738
192
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1739
192
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1740
192
       "%s: invalid inode - data size value out of bounds.",
1741
192
       function );
1742
1743
192
      return( -1 );
1744
192
    }
1745
3.86k
    number_of_blocks = (uint32_t) ( inode->data_size / io_handle->block_size );
1746
1747
3.86k
    if( ( inode->data_size % io_handle->block_size ) != 0 )
1748
3.43k
    {
1749
3.43k
      number_of_blocks++;
1750
3.43k
    }
1751
3.86k
    if( ( io_handle->format_version == 4 )
1752
2.92k
     && ( ( inode->flags & LIBFSEXT_INODE_FLAG_INLINE_DATA ) != 0 ) )
1753
1.31k
    {
1754
      /* The data is stored inline in inode->data_reference
1755
       * Note that inode->data_size can be larger than 60
1756
       */
1757
1.31k
    }
1758
2.55k
    else if( ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_CHARACTER_DEVICE )
1759
2.54k
          || ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_BLOCK_DEVICE ) )
1760
16
    {
1761
      /* The major and minor device numbers are stored in inode->data_reference */
1762
16
    }
1763
2.53k
    else if( ( ( inode->file_mode & 0xf000 ) == 0xa000 )
1764
751
          && ( inode->data_size < 60 ) )
1765
48
    {
1766
      /* The symbolic link target path is stored in inode->data_reference */
1767
48
    }
1768
2.48k
    else if( ( io_handle->format_version == 4 )
1769
1.57k
          && ( ( inode->flags & LIBFSEXT_INODE_FLAG_HAS_EXTENTS ) != 0 ) )
1770
969
    {
1771
969
      if( libfsext_extents_read_inode_data_reference(
1772
969
           inode->data_extents_array,
1773
969
           io_handle,
1774
969
           file_io_handle,
1775
969
           number_of_blocks,
1776
969
           inode->data_reference,
1777
969
           60,
1778
969
           error ) == -1 )
1779
320
      {
1780
320
        libcerror_error_set(
1781
320
         error,
1782
320
         LIBCERROR_ERROR_DOMAIN_IO,
1783
320
         LIBCERROR_IO_ERROR_READ_FAILED,
1784
320
         "%s: unable to read extents from data reference.",
1785
320
         function );
1786
1787
320
        return( -1 );
1788
320
      }
1789
969
    }
1790
1.52k
    else
1791
1.52k
    {
1792
1.52k
      if( libfsext_data_blocks_read_inode_data_reference(
1793
1.52k
           inode->data_extents_array,
1794
1.52k
           io_handle,
1795
1.52k
           file_io_handle,
1796
1.52k
           number_of_blocks,
1797
1.52k
           inode->data_reference,
1798
1.52k
           60,
1799
1.52k
           error ) != 1 )
1800
394
      {
1801
394
        libcerror_error_set(
1802
394
         error,
1803
394
         LIBCERROR_ERROR_DOMAIN_IO,
1804
394
         LIBCERROR_IO_ERROR_READ_FAILED,
1805
394
         "%s: unable to read data blocks from data reference.",
1806
394
         function );
1807
1808
394
        return( -1 );
1809
394
      }
1810
1.52k
    }
1811
3.86k
  }
1812
3.27k
  return( 1 );
1813
4.18k
}
1814
1815
/* Determines if the inode is empty
1816
 * Returns 1 if empty, 0 if not or -1 on error
1817
 */
1818
int libfsext_inode_is_empty(
1819
     libfsext_inode_t *inode,
1820
     libcerror_error_t **error )
1821
0
{
1822
0
  static char *function = "libfsext_inode_is_empty";
1823
1824
0
  if( inode == NULL )
1825
0
  {
1826
0
    libcerror_error_set(
1827
0
     error,
1828
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1829
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1830
0
     "%s: invalid inode.",
1831
0
     function );
1832
1833
0
    return( -1 );
1834
0
  }
1835
0
  return( (int) inode->is_empty );
1836
0
}
1837
1838
/* Retrieves the access date and time
1839
 * The timestamp is a signed 64-bit POSIX date and time value in number of nano seconds
1840
 * Returns 1 if successful or -1 on error
1841
 */
1842
int libfsext_inode_get_access_time(
1843
     libfsext_inode_t *inode,
1844
     int64_t *posix_time,
1845
     libcerror_error_t **error )
1846
443
{
1847
443
  static char *function = "libfsext_inode_get_access_time";
1848
1849
443
  if( inode == NULL )
1850
0
  {
1851
0
    libcerror_error_set(
1852
0
     error,
1853
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1854
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1855
0
     "%s: invalid inode.",
1856
0
     function );
1857
1858
0
    return( -1 );
1859
0
  }
1860
443
  if( posix_time == NULL )
1861
0
  {
1862
0
    libcerror_error_set(
1863
0
     error,
1864
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1865
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1866
0
     "%s: invalid POSIX time.",
1867
0
     function );
1868
1869
0
    return( -1 );
1870
0
  }
1871
443
  *posix_time = inode->access_time;
1872
1873
443
  return( 1 );
1874
443
}
1875
1876
/* Retrieves the creation date and time
1877
 * The timestamp is a signed 64-bit POSIX date and time value in number of nano seconds
1878
 * Returns 1 if successful, 0 if not available or -1 on error
1879
 */
1880
int libfsext_inode_get_creation_time(
1881
     libfsext_inode_t *inode,
1882
     int64_t *posix_time,
1883
     libcerror_error_t **error )
1884
443
{
1885
443
  static char *function = "libfsext_inode_get_creation_time";
1886
1887
443
  if( inode == NULL )
1888
0
  {
1889
0
    libcerror_error_set(
1890
0
     error,
1891
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1892
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1893
0
     "%s: invalid inode.",
1894
0
     function );
1895
1896
0
    return( -1 );
1897
0
  }
1898
443
  if( posix_time == NULL )
1899
0
  {
1900
0
    libcerror_error_set(
1901
0
     error,
1902
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1903
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1904
0
     "%s: invalid POSIX time.",
1905
0
     function );
1906
1907
0
    return( -1 );
1908
0
  }
1909
443
  if( inode->has_creation_time != 0 )
1910
94
  {
1911
94
    *posix_time = inode->creation_time;
1912
1913
94
    return( 1 );
1914
94
  }
1915
349
  return( 0 );
1916
443
}
1917
1918
/* Retrieves the inode change time date and time
1919
 * The timestamp is a signed 64-bit POSIX date and time value in number of nano seconds
1920
 * Returns 1 if successful or -1 on error
1921
 */
1922
int libfsext_inode_get_inode_change_time(
1923
     libfsext_inode_t *inode,
1924
     int64_t *posix_time,
1925
     libcerror_error_t **error )
1926
443
{
1927
443
  static char *function = "libfsext_inode_get_inode_change_time";
1928
1929
443
  if( inode == NULL )
1930
0
  {
1931
0
    libcerror_error_set(
1932
0
     error,
1933
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1934
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1935
0
     "%s: invalid inode.",
1936
0
     function );
1937
1938
0
    return( -1 );
1939
0
  }
1940
443
  if( posix_time == NULL )
1941
0
  {
1942
0
    libcerror_error_set(
1943
0
     error,
1944
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1945
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1946
0
     "%s: invalid POSIX time.",
1947
0
     function );
1948
1949
0
    return( -1 );
1950
0
  }
1951
443
  *posix_time = inode->inode_change_time;
1952
1953
443
  return( 1 );
1954
443
}
1955
1956
/* Retrieves the modification date and time
1957
 * The timestamp is a signed 64-bit POSIX date and time value in number of nano seconds
1958
 * Returns 1 if successful or -1 on error
1959
 */
1960
int libfsext_inode_get_modification_time(
1961
     libfsext_inode_t *inode,
1962
     int64_t *posix_time,
1963
     libcerror_error_t **error )
1964
443
{
1965
443
  static char *function = "libfsext_inode_get_modification_time";
1966
1967
443
  if( inode == NULL )
1968
0
  {
1969
0
    libcerror_error_set(
1970
0
     error,
1971
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1972
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1973
0
     "%s: invalid inode.",
1974
0
     function );
1975
1976
0
    return( -1 );
1977
0
  }
1978
443
  if( posix_time == NULL )
1979
0
  {
1980
0
    libcerror_error_set(
1981
0
     error,
1982
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1983
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1984
0
     "%s: invalid POSIX time.",
1985
0
     function );
1986
1987
0
    return( -1 );
1988
0
  }
1989
443
  *posix_time = inode->modification_time;
1990
1991
443
  return( 1 );
1992
443
}
1993
1994
/* Retrieves the deletion date and time
1995
 * The timestamp is a signed 32-bit POSIX date and time value in number of seconds
1996
 * Returns 1 if successful or -1 on error
1997
 */
1998
int libfsext_inode_get_deletion_time(
1999
     libfsext_inode_t *inode,
2000
     int32_t *posix_time,
2001
     libcerror_error_t **error )
2002
443
{
2003
443
  static char *function = "libfsext_inode_get_deletion_time";
2004
2005
443
  if( inode == NULL )
2006
0
  {
2007
0
    libcerror_error_set(
2008
0
     error,
2009
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2010
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2011
0
     "%s: invalid inode.",
2012
0
     function );
2013
2014
0
    return( -1 );
2015
0
  }
2016
443
  if( posix_time == NULL )
2017
0
  {
2018
0
    libcerror_error_set(
2019
0
     error,
2020
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2021
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2022
0
     "%s: invalid POSIX time.",
2023
0
     function );
2024
2025
0
    return( -1 );
2026
0
  }
2027
443
  *posix_time = (int32_t) inode->deletion_time;
2028
2029
443
  return( 1 );
2030
443
}
2031
2032
/* Retrieves the file mode
2033
 * Returns 1 if successful or -1 on error
2034
 */
2035
int libfsext_inode_get_file_mode(
2036
     libfsext_inode_t *inode,
2037
     uint16_t *file_mode,
2038
     libcerror_error_t **error )
2039
1.16k
{
2040
1.16k
  static char *function = "libfsext_inode_get_file_mode";
2041
2042
1.16k
  if( inode == NULL )
2043
0
  {
2044
0
    libcerror_error_set(
2045
0
     error,
2046
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2047
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2048
0
     "%s: invalid inode.",
2049
0
     function );
2050
2051
0
    return( -1 );
2052
0
  }
2053
1.16k
  if( file_mode == NULL )
2054
0
  {
2055
0
    libcerror_error_set(
2056
0
     error,
2057
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2058
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2059
0
     "%s: invalid file mode.",
2060
0
     function );
2061
2062
0
    return( -1 );
2063
0
  }
2064
1.16k
  *file_mode = inode->file_mode;
2065
2066
1.16k
  return( 1 );
2067
1.16k
}
2068
2069
/* Retrieves the number of (hard) links
2070
 * Returns 1 if successful or -1 on error
2071
 */
2072
int libfsext_inode_get_number_of_links(
2073
     libfsext_inode_t *inode,
2074
     uint16_t *number_of_links,
2075
     libcerror_error_t **error )
2076
443
{
2077
443
  static char *function = "libfsext_inode_get_number_of_links";
2078
2079
443
  if( inode == NULL )
2080
0
  {
2081
0
    libcerror_error_set(
2082
0
     error,
2083
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2084
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2085
0
     "%s: invalid inode.",
2086
0
     function );
2087
2088
0
    return( -1 );
2089
0
  }
2090
443
  if( number_of_links == NULL )
2091
0
  {
2092
0
    libcerror_error_set(
2093
0
     error,
2094
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2095
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2096
0
     "%s: invalid number of links.",
2097
0
     function );
2098
2099
0
    return( -1 );
2100
0
  }
2101
443
  *number_of_links = inode->number_of_links;
2102
2103
443
  return( 1 );
2104
443
}
2105
2106
/* Retrieves the data size
2107
 * Returns 1 if successful or -1 on error
2108
 */
2109
int libfsext_inode_get_data_size(
2110
     libfsext_inode_t *inode,
2111
     uint64_t *data_size,
2112
     libcerror_error_t **error )
2113
1.20k
{
2114
1.20k
  static char *function = "libfsext_inode_get_data_size";
2115
2116
1.20k
  if( inode == NULL )
2117
0
  {
2118
0
    libcerror_error_set(
2119
0
     error,
2120
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2121
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2122
0
     "%s: invalid inode.",
2123
0
     function );
2124
2125
0
    return( -1 );
2126
0
  }
2127
1.20k
  if( data_size == NULL )
2128
0
  {
2129
0
    libcerror_error_set(
2130
0
     error,
2131
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2132
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2133
0
     "%s: invalid data size.",
2134
0
     function );
2135
2136
0
    return( -1 );
2137
0
  }
2138
1.20k
  *data_size = inode->data_size;
2139
2140
1.20k
  return( 1 );
2141
1.20k
}
2142
2143
/* Retrieves the owner identifier
2144
 * Returns 1 if successful or -1 on error
2145
 */
2146
int libfsext_inode_get_owner_identifier(
2147
     libfsext_inode_t *inode,
2148
     uint32_t *owner_identifier,
2149
     libcerror_error_t **error )
2150
443
{
2151
443
  static char *function = "libfsext_inode_get_owner_identifier";
2152
2153
443
  if( inode == NULL )
2154
0
  {
2155
0
    libcerror_error_set(
2156
0
     error,
2157
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2158
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2159
0
     "%s: invalid inode.",
2160
0
     function );
2161
2162
0
    return( -1 );
2163
0
  }
2164
443
  if( owner_identifier == NULL )
2165
0
  {
2166
0
    libcerror_error_set(
2167
0
     error,
2168
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2169
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2170
0
     "%s: invalid owner identifier.",
2171
0
     function );
2172
2173
0
    return( -1 );
2174
0
  }
2175
443
  *owner_identifier = inode->owner_identifier;
2176
2177
443
  return( 1 );
2178
443
}
2179
2180
/* Retrieves the group identifier
2181
 * Returns 1 if successful or -1 on error
2182
 */
2183
int libfsext_inode_get_group_identifier(
2184
     libfsext_inode_t *inode,
2185
     uint32_t *group_identifier,
2186
     libcerror_error_t **error )
2187
443
{
2188
443
  static char *function = "libfsext_inode_get_group_identifier";
2189
2190
443
  if( inode == NULL )
2191
0
  {
2192
0
    libcerror_error_set(
2193
0
     error,
2194
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2195
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2196
0
     "%s: invalid inode.",
2197
0
     function );
2198
2199
0
    return( -1 );
2200
0
  }
2201
443
  if( group_identifier == NULL )
2202
0
  {
2203
0
    libcerror_error_set(
2204
0
     error,
2205
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2206
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2207
0
     "%s: invalid group identifier.",
2208
0
     function );
2209
2210
0
    return( -1 );
2211
0
  }
2212
443
  *group_identifier = inode->group_identifier;
2213
2214
443
  return( 1 );
2215
443
}
2216
2217
/* Retrieves the file ACL (or extended attributes) block numer
2218
 * Returns 1 if successful or -1 on error
2219
 */
2220
int libfsext_inode_get_file_acl_block_number(
2221
     libfsext_inode_t *inode,
2222
     uint32_t *file_acl_block_number,
2223
     libcerror_error_t **error )
2224
260
{
2225
260
  static char *function = "libfsext_inode_get_file_acl_block_number";
2226
2227
260
  if( inode == NULL )
2228
0
  {
2229
0
    libcerror_error_set(
2230
0
     error,
2231
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2232
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2233
0
     "%s: invalid inode.",
2234
0
     function );
2235
2236
0
    return( -1 );
2237
0
  }
2238
260
  if( file_acl_block_number == NULL )
2239
0
  {
2240
0
    libcerror_error_set(
2241
0
     error,
2242
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2243
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2244
0
     "%s: invalid file ACL block number.",
2245
0
     function );
2246
2247
0
    return( -1 );
2248
0
  }
2249
260
  *file_acl_block_number = inode->file_acl_block_number;
2250
2251
260
  return( 1 );
2252
260
}
2253
2254
/* Retrieves the device identifier
2255
 * Returns 1 if successful, 0 if not available or -1 on error
2256
 */
2257
int libfsext_inode_get_device_identifier(
2258
     libfsext_inode_t *inode,
2259
     uint32_t *device_identifier,
2260
     libcerror_error_t **error )
2261
443
{
2262
443
  static char *function = "libfsext_inode_get_device_identifier";
2263
2264
443
  if( inode == NULL )
2265
0
  {
2266
0
    libcerror_error_set(
2267
0
     error,
2268
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2269
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2270
0
     "%s: invalid inode.",
2271
0
     function );
2272
2273
0
    return( -1 );
2274
0
  }
2275
443
  if( device_identifier == NULL )
2276
0
  {
2277
0
    libcerror_error_set(
2278
0
     error,
2279
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2280
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2281
0
     "%s: invalid device identifier.",
2282
0
     function );
2283
2284
0
    return( -1 );
2285
0
  }
2286
443
  if( ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_CHARACTER_DEVICE )
2287
438
   || ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_BLOCK_DEVICE ) )
2288
8
  {
2289
8
    byte_stream_copy_to_uint16_little_endian(
2290
8
     inode->data_reference,
2291
8
     *device_identifier );
2292
2293
8
    return( 1 );
2294
8
  }
2295
435
  return( 0 );
2296
443
}
2297
2298
/* Retrieves the device number
2299
 * Returns 1 if successful, 0 if not available or -1 on error
2300
 */
2301
int libfsext_inode_get_device_number(
2302
     libfsext_inode_t *inode,
2303
     uint8_t *major_device_number,
2304
     uint8_t *minor_device_number,
2305
     libcerror_error_t **error )
2306
443
{
2307
443
  static char *function = "libfsext_inode_get_device_number";
2308
2309
443
  if( inode == NULL )
2310
0
  {
2311
0
    libcerror_error_set(
2312
0
     error,
2313
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2314
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2315
0
     "%s: invalid inode.",
2316
0
     function );
2317
2318
0
    return( -1 );
2319
0
  }
2320
443
  if( major_device_number == NULL )
2321
0
  {
2322
0
    libcerror_error_set(
2323
0
     error,
2324
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2325
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2326
0
     "%s: invalid major device number.",
2327
0
     function );
2328
2329
0
    return( -1 );
2330
0
  }
2331
443
  if( minor_device_number == NULL )
2332
0
  {
2333
0
    libcerror_error_set(
2334
0
     error,
2335
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2336
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2337
0
     "%s: invalid minor device number.",
2338
0
     function );
2339
2340
0
    return( -1 );
2341
0
  }
2342
443
  if( ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_CHARACTER_DEVICE )
2343
438
   || ( ( inode->file_mode & 0xf000 ) == LIBFSEXT_FILE_TYPE_BLOCK_DEVICE ) )
2344
8
  {
2345
8
    *major_device_number = inode->data_reference[ 1 ];
2346
8
    *minor_device_number = inode->data_reference[ 0 ];
2347
2348
8
    return( 1 );
2349
8
  }
2350
435
  return( 0 );
2351
443
}
2352
2353
/* Retrieves the number of extents
2354
 * Returns 1 if successful or -1 on error
2355
 */
2356
int libfsext_inode_get_number_of_extents(
2357
     libfsext_inode_t *inode,
2358
     int *number_of_extents,
2359
     libcerror_error_t **error )
2360
2.29k
{
2361
2.29k
  static char *function = "libfsext_inode_get_number_of_extents";
2362
2363
2.29k
  if( inode == NULL )
2364
0
  {
2365
0
    libcerror_error_set(
2366
0
     error,
2367
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2368
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2369
0
     "%s: invalid inode.",
2370
0
     function );
2371
2372
0
    return( -1 );
2373
0
  }
2374
2.29k
  if( libcdata_array_get_number_of_entries(
2375
2.29k
       inode->data_extents_array,
2376
2.29k
       number_of_extents,
2377
2.29k
       error ) != 1 )
2378
0
  {
2379
0
    libcerror_error_set(
2380
0
     error,
2381
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2382
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2383
0
     "%s: unable to retrieve number of entries.",
2384
0
     function );
2385
2386
0
    return( -1 );
2387
0
  }
2388
2.29k
  return( 1 );
2389
2.29k
}
2390
2391
/* Retrieves a specific extent
2392
 * Returns 1 if successful or -1 on error
2393
 */
2394
int libfsext_inode_get_extent_by_index(
2395
     libfsext_inode_t *inode,
2396
     int extent_index,
2397
     libfsext_extent_t **extent,
2398
     libcerror_error_t **error )
2399
340k
{
2400
340k
  static char *function = "libfsext_inode_get_extent_by_index";
2401
2402
340k
  if( inode == NULL )
2403
0
  {
2404
0
    libcerror_error_set(
2405
0
     error,
2406
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2407
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2408
0
     "%s: invalid inode.",
2409
0
     function );
2410
2411
0
    return( -1 );
2412
0
  }
2413
340k
  if( libcdata_array_get_entry_by_index(
2414
340k
       inode->data_extents_array,
2415
340k
       extent_index,
2416
340k
       (intptr_t **) extent,
2417
340k
       error ) != 1 )
2418
0
  {
2419
0
    libcerror_error_set(
2420
0
     error,
2421
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2422
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2423
0
     "%s: unable to retrieve extent: %d.",
2424
0
     function,
2425
0
     extent_index );
2426
2427
0
    return( -1 );
2428
0
  }
2429
340k
  return( 1 );
2430
340k
}
2431
2432
/* Reads an inode
2433
 * Callback function for the inodes vector
2434
 * Returns 1 if successful or -1 on error
2435
 */
2436
int libfsext_inode_read_element_data(
2437
     libfsext_io_handle_t *io_handle,
2438
     libbfio_handle_t *file_io_handle,
2439
     libfdata_vector_t *vector,
2440
     libfdata_cache_t *cache,
2441
     int element_index,
2442
     int element_data_file_index LIBFSEXT_ATTRIBUTE_UNUSED,
2443
     off64_t element_data_offset,
2444
     size64_t element_data_size,
2445
     uint32_t element_flags LIBFSEXT_ATTRIBUTE_UNUSED,
2446
     uint8_t read_flags LIBFSEXT_ATTRIBUTE_UNUSED,
2447
     libcerror_error_t **error )
2448
4.98k
{
2449
4.98k
  libfsext_inode_t *inode = NULL;
2450
4.98k
  uint8_t *data           = NULL;
2451
4.98k
  static char *function   = "libfsext_inode_read_element_data";
2452
4.98k
  ssize_t read_count      = 0;
2453
2454
4.98k
  LIBFSEXT_UNREFERENCED_PARAMETER( element_data_file_index )
2455
4.98k
  LIBFSEXT_UNREFERENCED_PARAMETER( element_flags )
2456
4.98k
  LIBFSEXT_UNREFERENCED_PARAMETER( read_flags )
2457
2458
4.98k
  if( (uint64_t) element_index > (uint64_t) ( UINT32_MAX - 1 ) )
2459
0
  {
2460
0
    libcerror_error_set(
2461
0
     error,
2462
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2463
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2464
0
     "%s: element index value out of bounds.",
2465
0
     function );
2466
2467
0
    return( -1 );
2468
0
  }
2469
4.98k
  if( ( element_data_size == 0 )
2470
4.98k
   || ( element_data_size > (size64_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
2471
0
  {
2472
0
    libcerror_error_set(
2473
0
     error,
2474
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2475
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
2476
0
     "%s: element data size value out of bounds.",
2477
0
     function );
2478
2479
0
    return( -1 );
2480
0
  }
2481
4.98k
  data = (uint8_t *) memory_allocate(
2482
4.98k
                      sizeof( uint8_t ) * (size_t) element_data_size );
2483
2484
4.98k
  if( data == NULL )
2485
0
  {
2486
0
    libcerror_error_set(
2487
0
     error,
2488
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
2489
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
2490
0
     "%s: unable to create data.",
2491
0
     function );
2492
2493
0
    goto on_error;
2494
0
  }
2495
#if defined( HAVE_DEBUG_OUTPUT )
2496
  if( libcnotify_verbose != 0 )
2497
  {
2498
    libcnotify_printf(
2499
     "%s: reading inode at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
2500
     function,
2501
     element_data_offset,
2502
     element_data_offset );
2503
  }
2504
#endif
2505
4.98k
  read_count = libbfio_handle_read_buffer_at_offset(
2506
4.98k
                file_io_handle,
2507
4.98k
                data,
2508
4.98k
                (size_t) element_data_size,
2509
4.98k
                element_data_offset,
2510
4.98k
                error );
2511
2512
4.98k
  if( read_count != (ssize_t) element_data_size )
2513
287
  {
2514
287
    libcerror_error_set(
2515
287
     error,
2516
287
     LIBCERROR_ERROR_DOMAIN_IO,
2517
287
     LIBCERROR_IO_ERROR_READ_FAILED,
2518
287
     "%s: unable to read inode at offset: %" PRIi64 " (0x%08" PRIx64 ").",
2519
287
     function,
2520
287
     element_data_offset,
2521
287
     element_data_offset );
2522
2523
287
    goto on_error;
2524
287
  }
2525
4.69k
  if( libfsext_inode_initialize(
2526
4.69k
       &inode,
2527
4.69k
       error ) != 1 )
2528
0
  {
2529
0
    libcerror_error_set(
2530
0
     error,
2531
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2532
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
2533
0
     "%s: unable to create inode.",
2534
0
     function );
2535
2536
0
    goto on_error;
2537
0
  }
2538
4.69k
  inode->inode_number = (uint32_t) element_index + 1;
2539
2540
4.69k
  if( libfsext_inode_read_data(
2541
4.69k
       inode,
2542
4.69k
       io_handle,
2543
4.69k
       data,
2544
4.69k
       (size_t) element_data_size,
2545
4.69k
       error ) != 1 )
2546
511
  {
2547
511
    libcerror_error_set(
2548
511
     error,
2549
511
     LIBCERROR_ERROR_DOMAIN_IO,
2550
511
     LIBCERROR_IO_ERROR_READ_FAILED,
2551
511
     "%s: unable to read inode at offset: %" PRIi64 " (0x%08" PRIx64 ").",
2552
511
     function,
2553
511
     element_data_offset,
2554
511
     element_data_offset );
2555
2556
511
    goto on_error;
2557
511
  }
2558
4.18k
  if( libfsext_inode_read_data_reference(
2559
4.18k
       inode,
2560
4.18k
       io_handle,
2561
4.18k
       file_io_handle,
2562
4.18k
       error ) != 1 )
2563
906
  {
2564
906
    libcerror_error_set(
2565
906
     error,
2566
906
     LIBCERROR_ERROR_DOMAIN_IO,
2567
906
     LIBCERROR_IO_ERROR_READ_FAILED,
2568
906
     "%s: unable to read inode data reference.",
2569
906
     function );
2570
2571
906
    goto on_error;
2572
906
  }
2573
3.27k
  if( libfdata_vector_set_element_value_by_index(
2574
3.27k
       vector,
2575
3.27k
       (intptr_t *) file_io_handle,
2576
3.27k
       cache,
2577
3.27k
       element_index,
2578
3.27k
       (intptr_t *) inode,
2579
3.27k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsext_inode_free,
2580
3.27k
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
2581
3.27k
       error ) != 1 )
2582
0
  {
2583
0
    libcerror_error_set(
2584
0
     error,
2585
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2586
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
2587
0
     "%s: unable to set inode as element value.",
2588
0
     function );
2589
2590
0
    goto on_error;
2591
0
  }
2592
3.27k
  memory_free(
2593
3.27k
   data );
2594
2595
3.27k
  return( 1 );
2596
2597
1.70k
on_error:
2598
1.70k
  if( inode != NULL )
2599
1.41k
  {
2600
1.41k
    libfsext_inode_free(
2601
1.41k
     &inode,
2602
1.41k
     NULL );
2603
1.41k
  }
2604
1.70k
  if( data != NULL )
2605
1.70k
  {
2606
1.70k
    memory_free(
2607
1.70k
     data );
2608
1.70k
  }
2609
1.70k
  return( -1 );
2610
3.27k
}
2611