Coverage Report

Created: 2026-08-31 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_inode.c
Line
Count
Source
1
/*
2
 * Inode functions
3
 *
4
 * Copyright (C) 2020-2026, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsxfs_attribute_values.h"
28
#include "libfsxfs_debug.h"
29
#include "libfsxfs_definitions.h"
30
#include "libfsxfs_extent.h"
31
#include "libfsxfs_extent_btree.h"
32
#include "libfsxfs_extent_list.h"
33
#include "libfsxfs_inode.h"
34
#include "libfsxfs_io_handle.h"
35
#include "libfsxfs_libcerror.h"
36
#include "libfsxfs_libcnotify.h"
37
#include "libfsxfs_libfdatetime.h"
38
#include "libfsxfs_libfguid.h"
39
40
#include "fsxfs_inode.h"
41
42
/* Creates a inode
43
 * Make sure the value inode is referencing, is set to NULL
44
 * Returns 1 if successful or -1 on error
45
 */
46
int libfsxfs_inode_initialize(
47
     libfsxfs_inode_t **inode,
48
     size_t inode_size,
49
     libcerror_error_t **error )
50
5.13k
{
51
5.13k
  static char *function = "libfsxfs_inode_initialize";
52
53
5.13k
  if( inode == NULL )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59
0
     "%s: invalid inode.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
5.13k
  if( *inode != NULL )
65
0
  {
66
0
    libcerror_error_set(
67
0
     error,
68
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
69
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70
0
     "%s: invalid inode value already set.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
5.13k
  if( ( inode_size != 256 )
76
4.07k
   && ( inode_size != 512 )
77
151
   && ( inode_size != 1024 )
78
94
   && ( inode_size != 2048 ) )
79
44
  {
80
44
    libcerror_error_set(
81
44
     error,
82
44
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
83
44
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
84
44
     "%s: invalid inode size value out of bounds.",
85
44
     function );
86
87
44
    return( -1 );
88
44
  }
89
5.09k
  *inode = memory_allocate_structure(
90
5.09k
            libfsxfs_inode_t );
91
92
5.09k
  if( *inode == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
97
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
98
0
     "%s: unable to create inode.",
99
0
     function );
100
101
0
    goto on_error;
102
0
  }
103
5.09k
  if( memory_set(
104
5.09k
       *inode,
105
5.09k
       0,
106
5.09k
       sizeof( libfsxfs_inode_t ) ) == NULL )
107
0
  {
108
0
    libcerror_error_set(
109
0
     error,
110
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
111
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
112
0
     "%s: unable to clear inode.",
113
0
     function );
114
115
0
    memory_free(
116
0
     *inode );
117
118
0
    *inode = NULL;
119
120
0
    return( -1 );
121
0
  }
122
5.09k
  ( *inode )->data = (uint8_t *) memory_allocate(
123
5.09k
                                  sizeof( uint8_t ) * inode_size );
124
125
5.09k
  if( ( *inode )->data == NULL )
126
0
  {
127
0
    libcerror_error_set(
128
0
     error,
129
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
130
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
131
0
     "%s: unable to create inode data.",
132
0
     function );
133
134
0
    goto on_error;
135
0
  }
136
5.09k
  ( *inode )->data_size = inode_size;
137
138
5.09k
  return( 1 );
139
140
0
on_error:
141
0
  if( *inode != NULL )
142
0
  {
143
0
    memory_free(
144
0
     *inode );
145
146
0
    *inode = NULL;
147
0
  }
148
0
  return( -1 );
149
5.09k
}
150
151
/* Frees a inode
152
 * Returns 1 if successful or -1 on error
153
 */
154
int libfsxfs_inode_free(
155
     libfsxfs_inode_t **inode,
156
     libcerror_error_t **error )
157
5.09k
{
158
5.09k
  static char *function = "libfsxfs_inode_free";
159
5.09k
  int result            = 1;
160
161
5.09k
  if( inode == NULL )
162
0
  {
163
0
    libcerror_error_set(
164
0
     error,
165
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
166
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
167
0
     "%s: invalid inode.",
168
0
     function );
169
170
0
    return( -1 );
171
0
  }
172
5.09k
  if( *inode != NULL )
173
5.09k
  {
174
5.09k
    if( ( *inode )->data != NULL )
175
5.09k
    {
176
5.09k
      memory_free(
177
5.09k
       ( *inode )->data );
178
5.09k
    }
179
5.09k
    if( ( *inode )->data_extents_array != NULL )
180
2.71k
    {
181
2.71k
      if( libcdata_array_free(
182
2.71k
           &( ( *inode )->data_extents_array ),
183
2.71k
           (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
184
2.71k
           error ) != 1 )
185
0
      {
186
0
        libcerror_error_set(
187
0
         error,
188
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
189
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
190
0
         "%s: unable to free data extents array.",
191
0
         function );
192
193
0
        result = -1;
194
0
      }
195
2.71k
    }
196
5.09k
    if( ( *inode )->attributes_extents_array != NULL )
197
469
    {
198
469
      if( libcdata_array_free(
199
469
           &( ( *inode )->attributes_extents_array ),
200
469
           (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
201
469
           error ) != 1 )
202
0
      {
203
0
        libcerror_error_set(
204
0
         error,
205
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
206
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
207
0
         "%s: unable to free attributes extents array.",
208
0
         function );
209
210
0
        result = -1;
211
0
      }
212
469
    }
213
5.09k
    memory_free(
214
5.09k
     *inode );
215
216
5.09k
    *inode = NULL;
217
5.09k
  }
218
5.09k
  return( result );
219
5.09k
}
220
221
/* Reads the inode data
222
 * Returns 1 if successful or -1 on error
223
 */
224
int libfsxfs_inode_read_data(
225
     libfsxfs_inode_t *inode,
226
     libfsxfs_io_handle_t *io_handle,
227
     const uint8_t *data,
228
     size_t data_size,
229
     libcerror_error_t **error )
230
5.06k
{
231
5.06k
  static char *function      = "libfsxfs_inode_read_data";
232
5.06k
  uint8_t *timestamp_data    = NULL;
233
5.06k
  size_t data_fork_size      = 0;
234
5.06k
  size_t inode_data_size     = 0;
235
5.06k
  uint64_t bigtime_timestamp = 0;
236
5.06k
  uint64_t posix_nanoseconds = 0;
237
5.06k
  uint64_t posix_seconds     = 0;
238
5.06k
  uint32_t value_32bit       = 0;
239
5.06k
  uint8_t format_version     = 0;
240
241
#if defined( HAVE_DEBUG_OUTPUT )
242
  uint64_t value_64bit       = 0;
243
  uint16_t value_16bit       = 0;
244
#endif
245
246
5.06k
  if( inode == NULL )
247
0
  {
248
0
    libcerror_error_set(
249
0
     error,
250
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
251
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
252
0
     "%s: invalid inode.",
253
0
     function );
254
255
0
    return( -1 );
256
0
  }
257
5.06k
  if( io_handle == NULL )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
262
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
263
0
     "%s: invalid IO handle.",
264
0
     function );
265
266
0
    return( -1 );
267
0
  }
268
5.06k
  if( data == NULL )
269
0
  {
270
0
    libcerror_error_set(
271
0
     error,
272
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
273
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
274
0
     "%s: invalid data.",
275
0
     function );
276
277
0
    return( -1 );
278
0
  }
279
5.06k
  if( ( data_size < sizeof( fsxfs_inode_v1_t ) )
280
5.06k
   || ( data_size > (size_t) SSIZE_MAX ) )
281
0
  {
282
0
    libcerror_error_set(
283
0
     error,
284
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
285
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
286
0
     "%s: invalid data size value out of bounds.",
287
0
     function );
288
289
0
    return( -1 );
290
0
  }
291
5.06k
  format_version = ( (fsxfs_inode_v1_t *) data )->format_version;
292
293
5.06k
  if( format_version == 3 )
294
4.45k
  {
295
4.45k
    if( data_size < sizeof( fsxfs_inode_v3_t ) )
296
0
    {
297
0
      libcerror_error_set(
298
0
       error,
299
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
300
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
301
0
       "%s: invalid data size value out of bounds.",
302
0
       function );
303
304
0
      return( -1 );
305
0
    }
306
4.45k
    inode_data_size = sizeof( fsxfs_inode_v3_t );
307
4.45k
  }
308
606
  else
309
606
  {
310
606
    inode_data_size = sizeof( fsxfs_inode_v1_t );
311
606
  }
312
#if defined( HAVE_DEBUG_OUTPUT )
313
  if( libcnotify_verbose != 0 )
314
  {
315
    libcnotify_printf(
316
     "%s: inode data:\n",
317
     function );
318
    libcnotify_print_data(
319
     data,
320
     inode_data_size,
321
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
322
  }
323
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
324
325
5.06k
  if( memory_compare(
326
5.06k
      ( (fsxfs_inode_v1_t *) data )->signature,
327
5.06k
      "IN",
328
5.06k
      2 ) != 0 )
329
9
  {
330
9
    libcerror_error_set(
331
9
     error,
332
9
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
9
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
334
9
     "%s: unsupported signature.",
335
9
     function );
336
337
9
    return( -1 );
338
9
  }
339
5.05k
  byte_stream_copy_to_uint16_big_endian(
340
5.05k
   ( (fsxfs_inode_v1_t *) data )->file_mode,
341
5.05k
   inode->file_mode );
342
343
5.05k
  inode->fork_type = ( (fsxfs_inode_v1_t *) data )->fork_type;
344
345
5.05k
  inode->format_version = format_version;
346
347
5.05k
  if( format_version == 1 )
348
280
  {
349
280
    byte_stream_copy_to_uint16_big_endian(
350
280
     ( (fsxfs_inode_v1_t *) data )->number_of_links,
351
280
     inode->number_of_links );
352
280
  }
353
5.05k
  byte_stream_copy_to_uint32_big_endian(
354
5.05k
   ( (fsxfs_inode_v1_t *) data )->owner_identifier,
355
5.05k
   inode->owner_identifier );
356
357
5.05k
  byte_stream_copy_to_uint32_big_endian(
358
5.05k
   ( (fsxfs_inode_v1_t *) data )->group_identifier,
359
5.05k
   inode->group_identifier );
360
361
5.05k
  if( format_version != 1 )
362
4.77k
  {
363
4.77k
    byte_stream_copy_to_uint32_big_endian(
364
4.77k
     ( (fsxfs_inode_v2_t *) data )->number_of_links,
365
4.77k
     inode->number_of_links );
366
4.77k
  }
367
5.05k
  if( ( format_version == 3 )
368
4.45k
   && ( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_BIGTIME ) != 0 ) )
369
1.08k
  {
370
1.08k
    byte_stream_copy_to_uint64_big_endian(
371
1.08k
     ( (fsxfs_inode_v1_t *) data )->access_time,
372
1.08k
     bigtime_timestamp );
373
374
1.08k
    posix_seconds     = ( bigtime_timestamp / 1000000000 ) - 2147483648;
375
1.08k
    posix_nanoseconds = bigtime_timestamp % 1000000000;
376
377
1.08k
    if( ( (int64_t) posix_seconds < ( (int64_t) INT64_MIN / 1000000000 ) )
378
1.08k
     || ( (int64_t) posix_seconds > ( (int64_t) INT64_MAX / 1000000000 ) ) )
379
3
    {
380
3
      libcerror_error_set(
381
3
       error,
382
3
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
383
3
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
384
3
       "%s: unsupported access time value out of bounds.",
385
3
       function );
386
387
3
      return( -1 );
388
3
    }
389
1.07k
    inode->access_time = (int64_t) posix_seconds * 1000000000;
390
391
1.07k
    if( ( ( inode->access_time < 0 )
392
374
      &&  ( (int64_t) posix_nanoseconds < ( (int64_t) INT64_MIN - inode->access_time ) ) )
393
1.07k
     || ( ( inode->access_time > 0 )
394
705
      &&  ( (int64_t) posix_nanoseconds > ( (int64_t) INT64_MAX - inode->access_time ) ) ) )
395
89
    {
396
89
      libcerror_error_set(
397
89
       error,
398
89
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
399
89
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
400
89
       "%s: unsupported access time value out of bounds.",
401
89
       function );
402
403
89
      return( -1 );
404
89
    }
405
990
    inode->access_time += (int64_t) posix_nanoseconds;
406
407
990
    byte_stream_copy_to_uint64_big_endian(
408
990
     ( (fsxfs_inode_v1_t *) data )->modification_time,
409
990
     bigtime_timestamp );
410
411
990
    posix_seconds     = ( bigtime_timestamp / 1000000000 ) - 2147483648;
412
990
    posix_nanoseconds = bigtime_timestamp % 1000000000;
413
414
990
    if( ( (int64_t) posix_seconds < ( (int64_t) INT64_MIN / 1000000000 ) )
415
990
     || ( (int64_t) posix_seconds > ( (int64_t) INT64_MAX / 1000000000 ) ) )
416
18
    {
417
18
      libcerror_error_set(
418
18
       error,
419
18
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
420
18
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
421
18
       "%s: unsupported modification time value out of bounds.",
422
18
       function );
423
424
18
      return( -1 );
425
18
    }
426
972
    inode->modification_time = (int64_t) posix_seconds * 1000000000;
427
428
972
    if( ( ( inode->modification_time < 0 )
429
316
      &&  ( (int64_t) posix_nanoseconds < ( (int64_t) INT64_MIN - inode->modification_time ) ) )
430
972
     || ( ( inode->modification_time > 0 )
431
653
      &&  ( (int64_t) posix_nanoseconds > ( (int64_t) INT64_MAX - inode->modification_time ) ) ) )
432
84
    {
433
84
      libcerror_error_set(
434
84
       error,
435
84
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
436
84
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
437
84
       "%s: unsupported modification time value out of bounds.",
438
84
       function );
439
440
84
      return( -1 );
441
84
    }
442
888
    inode->modification_time += (int64_t) posix_nanoseconds;
443
444
888
    byte_stream_copy_to_uint64_big_endian(
445
888
     ( (fsxfs_inode_v1_t *) data )->inode_change_time,
446
888
     bigtime_timestamp );
447
448
888
    posix_seconds     = ( bigtime_timestamp / 1000000000 ) - 2147483648;
449
888
    posix_nanoseconds = bigtime_timestamp % 1000000000;
450
451
888
    if( ( (int64_t) posix_seconds < ( (int64_t) INT64_MIN / 1000000000 ) )
452
888
     || ( (int64_t) posix_seconds > ( (int64_t) INT64_MAX / 1000000000 ) ) )
453
37
    {
454
37
      libcerror_error_set(
455
37
       error,
456
37
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
457
37
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
458
37
       "%s: unsupported inode change time value out of bounds.",
459
37
       function );
460
461
37
      return( -1 );
462
37
    }
463
851
    inode->inode_change_time = (int64_t) posix_seconds * 1000000000;
464
465
851
    if( ( ( inode->inode_change_time < 0 )
466
343
      &&  ( (int64_t) posix_nanoseconds < ( (int64_t) INT64_MIN - inode->inode_change_time ) ) )
467
851
     || ( ( inode->inode_change_time > 0 )
468
507
      &&  ( (int64_t) posix_nanoseconds > ( (int64_t) INT64_MAX - inode->inode_change_time ) ) ) )
469
83
    {
470
83
      libcerror_error_set(
471
83
       error,
472
83
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
473
83
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
474
83
       "%s: unsupported change time value out of bounds.",
475
83
       function );
476
477
83
      return( -1 );
478
83
    }
479
768
    inode->inode_change_time += (int64_t) posix_nanoseconds;
480
768
  }
481
3.97k
  else
482
3.97k
  {
483
3.97k
    timestamp_data = ( (fsxfs_inode_v1_t *) data )->access_time;
484
485
3.97k
    byte_stream_copy_to_uint32_big_endian(
486
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
487
3.97k
     value_32bit );
488
489
3.97k
    inode->access_time = (int32_t) value_32bit * (int64_t) 1000000000;
490
491
3.97k
    byte_stream_copy_to_uint32_big_endian(
492
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
493
3.97k
     value_32bit );
494
495
3.97k
    if( inode->access_time > 0 )
496
1.74k
    {
497
1.74k
      inode->access_time += value_32bit;
498
1.74k
    }
499
2.22k
    else
500
2.22k
    {
501
2.22k
      inode->access_time -= value_32bit;
502
2.22k
    }
503
3.97k
    timestamp_data = ( (fsxfs_inode_v1_t *) data )->modification_time;
504
505
3.97k
    byte_stream_copy_to_uint32_big_endian(
506
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
507
3.97k
     value_32bit );
508
509
3.97k
    inode->modification_time = (int32_t) value_32bit * (int64_t) 1000000000;
510
511
3.97k
    byte_stream_copy_to_uint32_big_endian(
512
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
513
3.97k
     value_32bit );
514
515
3.97k
    if( inode->modification_time > 0 )
516
1.95k
    {
517
1.95k
      inode->modification_time += value_32bit;
518
1.95k
    }
519
2.01k
    else
520
2.01k
    {
521
2.01k
      inode->modification_time -= value_32bit;
522
2.01k
    }
523
3.97k
    timestamp_data = ( (fsxfs_inode_v1_t *) data )->inode_change_time;
524
525
3.97k
    byte_stream_copy_to_uint32_big_endian(
526
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
527
3.97k
     value_32bit );
528
529
3.97k
    inode->inode_change_time = (int32_t) value_32bit * (int64_t) 1000000000;
530
531
3.97k
    byte_stream_copy_to_uint32_big_endian(
532
3.97k
     ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
533
3.97k
     value_32bit );
534
535
3.97k
    if( inode->inode_change_time > 0 )
536
1.85k
    {
537
1.85k
      inode->inode_change_time += value_32bit;
538
1.85k
    }
539
2.12k
    else
540
2.12k
    {
541
2.12k
      inode->inode_change_time -= value_32bit;
542
2.12k
    }
543
3.97k
  }
544
4.73k
  byte_stream_copy_to_uint64_big_endian(
545
4.73k
   ( (fsxfs_inode_v1_t *) data )->data_size,
546
4.73k
   inode->size );
547
548
4.73k
  if( ( format_version == 3 )
549
4.14k
   && ( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_64BIT_EXTENT_COUNTERS ) != 0 ) )
550
224
  {
551
224
    byte_stream_copy_to_uint64_big_endian(
552
224
     ( (fsxfs_inode_v3_t *) data )->number_of_data_extents_64bit,
553
224
     inode->number_of_data_extents );
554
555
224
    byte_stream_copy_to_uint32_big_endian(
556
224
     ( (fsxfs_inode_v3_t *) data )->number_of_attributes_extents_32bit,
557
224
     inode->number_of_attributes_extents );
558
224
  }
559
4.51k
  else
560
4.51k
  {
561
4.51k
    byte_stream_copy_to_uint32_big_endian(
562
4.51k
     ( (fsxfs_inode_v1_t *) data )->number_of_data_extents,
563
4.51k
     inode->number_of_data_extents );
564
565
4.51k
    byte_stream_copy_to_uint16_big_endian(
566
4.51k
     ( (fsxfs_inode_v1_t *) data )->number_of_attributes_extents,
567
4.51k
     inode->number_of_attributes_extents );
568
4.51k
  }
569
4.73k
  inode->attributes_fork_offset = (uint16_t) ( (fsxfs_inode_v1_t *) data )->attributes_fork_offset * 8;
570
571
4.73k
  inode->attributes_fork_type = ( (fsxfs_inode_v1_t *) data )->attributes_fork_type;
572
573
#if defined( HAVE_DEBUG_OUTPUT )
574
  if( libcnotify_verbose != 0 )
575
  {
576
    libcnotify_printf(
577
     "%s: signature\t\t\t\t\t: %c%c\n",
578
     function,
579
     ( (fsxfs_inode_v1_t *) data )->signature[ 0 ],
580
     ( (fsxfs_inode_v1_t *) data )->signature[ 1 ] );
581
582
    libcnotify_printf(
583
     "%s: file mode\t\t\t\t\t: 0o07%" PRIo16 " (0x%04" PRIx16 ")\n",
584
     function,
585
     inode->file_mode,
586
     inode->file_mode );
587
    libfsxfs_debug_print_file_mode(
588
     inode->file_mode );
589
590
    libcnotify_printf(
591
     "%s: format version\t\t\t\t: %" PRIu8 "\n",
592
     function,
593
     format_version );
594
595
    libcnotify_printf(
596
     "%s: fork type\t\t\t\t\t: %" PRIu8 " (%s)\n",
597
     function,
598
     ( (fsxfs_inode_v1_t *) data )->fork_type,
599
     libfsxfs_debug_print_fork_type(
600
      ( (fsxfs_inode_v1_t *) data )->fork_type ) );
601
602
    if( format_version == 1 )
603
    {
604
      libcnotify_printf(
605
       "%s: number of links\t\t\t\t: %" PRIu32 "\n",
606
       function,
607
       inode->number_of_links );
608
    }
609
    else
610
    {
611
      byte_stream_copy_to_uint16_big_endian(
612
       ( (fsxfs_inode_v1_t *) data )->number_of_links,
613
       value_16bit );
614
      libcnotify_printf(
615
       "%s: unknown1\t\t\t\t\t: 0x%04" PRIx16 "\n",
616
       function,
617
       value_16bit );
618
    }
619
    libcnotify_printf(
620
     "%s: owner identifier\t\t\t\t: %" PRIu32 "\n",
621
     function,
622
     inode->owner_identifier );
623
624
    libcnotify_printf(
625
     "%s: group identifier\t\t\t\t: %" PRIu32 "\n",
626
     function,
627
     inode->group_identifier );
628
629
    if( format_version == 1 )
630
    {
631
      libcnotify_printf(
632
       "%s: unknown2:\n",
633
       function );
634
      libcnotify_print_data(
635
       ( (fsxfs_inode_v1_t *) data )->unknown2,
636
       14,
637
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
638
639
      byte_stream_copy_to_uint16_big_endian(
640
       ( (fsxfs_inode_v1_t *) data )->flush_counter,
641
       value_16bit );
642
      libcnotify_printf(
643
       "%s: flush counter\t\t\t\t\t: %" PRIu16 "\n",
644
       function,
645
       value_16bit );
646
    }
647
    else
648
    {
649
      libcnotify_printf(
650
       "%s: number of links\t\t\t\t: %" PRIu32 "\n",
651
       function,
652
       inode->number_of_links );
653
654
      byte_stream_copy_to_uint16_big_endian(
655
       ( (fsxfs_inode_v2_t *) data )->project_identifier,
656
       value_16bit );
657
    }
658
    if( format_version == 2 )
659
    {
660
      libcnotify_printf(
661
       "%s: project identifier\t\t\t\t: %" PRIu16 "\n",
662
       function,
663
       value_16bit );
664
665
      libcnotify_printf(
666
       "%s: unknown2:\n",
667
       function );
668
      libcnotify_print_data(
669
       ( (fsxfs_inode_v2_t *) data )->unknown2,
670
       8,
671
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
672
673
      byte_stream_copy_to_uint16_big_endian(
674
       ( (fsxfs_inode_v1_t *) data )->flush_counter,
675
       value_16bit );
676
      libcnotify_printf(
677
       "%s: flush counter\t\t\t\t\t: %" PRIu16 "\n",
678
       function,
679
       value_16bit );
680
    }
681
    else if( format_version == 3 )
682
    {
683
      libcnotify_printf(
684
       "%s: project identifier (lower 16-bit)\t\t: %" PRIu16 "\n",
685
       function,
686
       value_16bit );
687
688
      byte_stream_copy_to_uint16_big_endian(
689
       ( (fsxfs_inode_v3_t *) data )->project_identifier_upper,
690
       value_16bit );
691
      libcnotify_printf(
692
       "%s: project identifier (upper 16-bit)\t\t: %" PRIu16 "\n",
693
       function,
694
       value_16bit );
695
696
      if( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_64BIT_EXTENT_COUNTERS ) != 0 )
697
      {
698
        libcnotify_printf(
699
         "%s: number of data extents (64-bit)\t\t: %" PRIu64 "\n",
700
         function,
701
         inode->number_of_data_extents );
702
      }
703
      else
704
      {
705
        libcnotify_printf(
706
         "%s: unknown2:\n",
707
         function );
708
        libcnotify_print_data(
709
         ( (fsxfs_inode_v3_t *) data )->unknown2,
710
         8,
711
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
712
      }
713
    }
714
    if( ( format_version == 3 )
715
     && ( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_BIGTIME ) != 0 ) )
716
    {
717
      byte_stream_copy_to_uint64_big_endian(
718
       ( (fsxfs_inode_v1_t *) data )->access_time,
719
       value_64bit );
720
      libcnotify_printf(
721
       "%s: access time (bigtime)\t\t\t\t: %" PRIu64 "\n",
722
       function,
723
       value_64bit );
724
725
      byte_stream_copy_to_uint64_big_endian(
726
       ( (fsxfs_inode_v1_t *) data )->modification_time,
727
       value_64bit );
728
      libcnotify_printf(
729
       "%s: modification time (bigtime)\t\t\t: %" PRIu64 "\n",
730
       function,
731
       value_64bit );
732
733
      byte_stream_copy_to_uint64_big_endian(
734
       ( (fsxfs_inode_v1_t *) data )->inode_change_time,
735
       value_64bit );
736
      libcnotify_printf(
737
       "%s: inode change time (bigtime)\t\t\t: %" PRIu64 "\n",
738
       function,
739
       value_64bit );
740
    }
741
    else
742
    {
743
      timestamp_data = ( (fsxfs_inode_v1_t *) data )->access_time;
744
745
      if( libfsxfs_debug_print_posix_time_value(
746
           function,
747
           "access time (seconds)\t\t\t\t",
748
           ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
749
           4,
750
           LIBFDATETIME_ENDIAN_BIG,
751
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
752
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
753
           error ) != 1 )
754
      {
755
        libcerror_error_set(
756
         error,
757
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
758
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
759
         "%s: unable to print POSIX time value.",
760
         function );
761
762
        return( -1 );
763
      }
764
      byte_stream_copy_to_uint32_big_endian(
765
       ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
766
       value_32bit );
767
      libcnotify_printf(
768
       "%s: access time nanoseconds\t\t\t: %" PRIu32 "\n",
769
       function,
770
       value_32bit );
771
772
      timestamp_data = ( (fsxfs_inode_v1_t *) data )->modification_time;
773
774
      if( libfsxfs_debug_print_posix_time_value(
775
           function,
776
           "modification time (seconds)\t\t\t",
777
           ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
778
           4,
779
           LIBFDATETIME_ENDIAN_BIG,
780
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
781
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
782
           error ) != 1 )
783
      {
784
        libcerror_error_set(
785
         error,
786
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
787
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
788
         "%s: unable to print POSIX time value.",
789
         function );
790
791
        return( -1 );
792
      }
793
      byte_stream_copy_to_uint32_big_endian(
794
       ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
795
       value_32bit );
796
      libcnotify_printf(
797
       "%s: modification time nanoseconds\t\t\t: %" PRIu32 "\n",
798
       function,
799
       value_32bit );
800
801
      timestamp_data = ( (fsxfs_inode_v1_t *) data )->inode_change_time;
802
803
      if( libfsxfs_debug_print_posix_time_value(
804
           function,
805
           "inode change time (seconds)\t\t\t",
806
           ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
807
           4,
808
           LIBFDATETIME_ENDIAN_BIG,
809
           LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
810
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
811
           error ) != 1 )
812
      {
813
        libcerror_error_set(
814
         error,
815
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
816
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
817
         "%s: unable to print POSIX time value.",
818
         function );
819
820
        return( -1 );
821
      }
822
      byte_stream_copy_to_uint32_big_endian(
823
       ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
824
       value_32bit );
825
      libcnotify_printf(
826
       "%s: inode change time nanoseconds\t\t\t: %" PRIu32 "\n",
827
       function,
828
       value_32bit );
829
    }
830
    libcnotify_printf(
831
     "%s: data size\t\t\t\t\t: %" PRIu64 "\n",
832
     function,
833
     inode->size );
834
835
    byte_stream_copy_to_uint32_big_endian(
836
     ( (fsxfs_inode_v1_t *) data )->extent_size,
837
     value_32bit );
838
    libcnotify_printf(
839
     "%s: extent size\t\t\t\t\t: %" PRIu32 "\n",
840
     function,
841
     value_32bit );
842
843
    if( ( format_version == 3 )
844
     && ( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_64BIT_EXTENT_COUNTERS ) != 0 ) )
845
    {
846
      libcnotify_printf(
847
       "%s: number of attributes extents (32-bit)\t\t: %" PRIu32 "\n",
848
       function,
849
       inode->number_of_attributes_extents );
850
851
      byte_stream_copy_to_uint16_big_endian(
852
       ( (fsxfs_inode_v3_t *) data )->unknown4b,
853
       value_16bit );
854
      libcnotify_printf(
855
       "%s: unknown4b\t\t\t\t\t: 0x%04" PRIx16 "\n",
856
       function,
857
       value_16bit );
858
    }
859
    else
860
    {
861
      libcnotify_printf(
862
       "%s: number of data extents\t\t\t: %" PRIu64 "\n",
863
       function,
864
       inode->number_of_data_extents );
865
866
      libcnotify_printf(
867
       "%s: number of attributes extents\t\t\t: %" PRIu32 "\n",
868
       function,
869
       inode->number_of_attributes_extents );
870
    }
871
    libcnotify_printf(
872
     "%s: attributes fork offset\t\t\t: %" PRIu8 " (%" PRIu16 ")\n",
873
     function,
874
     ( (fsxfs_inode_v1_t *) data )->attributes_fork_offset,
875
     inode->attributes_fork_offset );
876
877
    libcnotify_printf(
878
     "%s: attributes fork type\t\t\t\t: %" PRIu8 " (%s)\n",
879
     function,
880
     inode->attributes_fork_type,
881
     libfsxfs_debug_print_fork_type(
882
      inode->attributes_fork_type ) );
883
884
    byte_stream_copy_to_uint32_big_endian(
885
     ( (fsxfs_inode_v1_t *) data )->unknown5,
886
     value_32bit );
887
    libcnotify_printf(
888
     "%s: unknown5\t\t\t\t\t: 0x%08" PRIx32 "\n",
889
     function,
890
     value_32bit );
891
892
    byte_stream_copy_to_uint16_big_endian(
893
     ( (fsxfs_inode_v1_t *) data )->unknown6,
894
     value_16bit );
895
    libcnotify_printf(
896
     "%s: unknown6\t\t\t\t\t: 0x%04" PRIx16 "\n",
897
     function,
898
     value_16bit );
899
900
    byte_stream_copy_to_uint16_big_endian(
901
     ( (fsxfs_inode_v1_t *) data )->inode_flags,
902
     value_16bit );
903
    libcnotify_printf(
904
     "%s: inode flags\t\t\t\t\t: 0x%04" PRIx16 "\n",
905
     function,
906
     value_16bit );
907
908
    byte_stream_copy_to_uint32_big_endian(
909
     ( (fsxfs_inode_v1_t *) data )->generation_number,
910
     value_32bit );
911
    libcnotify_printf(
912
     "%s: generation number\t\t\t\t: %" PRIu32 "\n",
913
     function,
914
     value_32bit );
915
916
    byte_stream_copy_to_uint32_big_endian(
917
     ( (fsxfs_inode_v3_t *) data )->unknown7,
918
     value_32bit );
919
    libcnotify_printf(
920
     "%s: unknown7\t\t\t\t\t: 0x%08" PRIx32 "\n",
921
     function,
922
     value_32bit );
923
  }
924
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
925
926
4.73k
  if( ( format_version != 1 )
927
4.45k
   && ( format_version != 2 )
928
4.15k
   && ( format_version != 3 ) )
929
16
  {
930
16
    libcerror_error_set(
931
16
     error,
932
16
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
933
16
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
934
16
     "%s: unsupported format version: %" PRIu32 ".",
935
16
     function,
936
16
     format_version );
937
938
16
    return( -1 );
939
16
  }
940
4.72k
  if( format_version == 3 )
941
4.14k
  {
942
4.14k
    if( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_BIGTIME ) != 0 )
943
768
    {
944
768
      byte_stream_copy_to_uint64_big_endian(
945
768
       ( (fsxfs_inode_v3_t *) data )->creation_time,
946
768
       bigtime_timestamp );
947
948
768
      posix_seconds     = ( bigtime_timestamp / 1000000000 ) - 2147483648;
949
768
      posix_nanoseconds = bigtime_timestamp % 1000000000;
950
951
768
      if( ( (int64_t) posix_seconds < ( (int64_t) INT64_MIN / 1000000000 ) )
952
768
       || ( (int64_t) posix_seconds > ( (int64_t) INT64_MAX / 1000000000 ) ) )
953
34
      {
954
34
        libcerror_error_set(
955
34
         error,
956
34
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
957
34
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
958
34
         "%s: unsupported creation time value out of bounds.",
959
34
         function );
960
961
34
        return( -1 );
962
34
      }
963
734
      inode->creation_time = (int64_t) posix_seconds * 1000000000;
964
965
734
      if( ( ( inode->creation_time < 0 )
966
285
        &&  ( (int64_t) posix_nanoseconds < ( (int64_t) INT64_MIN - inode->creation_time ) ) )
967
734
       || ( ( inode->creation_time > 0 )
968
449
        &&  ( (int64_t) posix_nanoseconds > ( (int64_t) INT64_MAX - inode->creation_time ) ) ) )
969
86
      {
970
86
        libcerror_error_set(
971
86
         error,
972
86
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
973
86
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
974
86
         "%s: unsupported creation time value out of bounds.",
975
86
         function );
976
977
86
        return( -1 );
978
86
      }
979
648
      inode->creation_time += (int64_t) posix_nanoseconds;
980
648
    }
981
3.37k
    else
982
3.37k
    {
983
3.37k
      timestamp_data = ( (fsxfs_inode_v3_t *) data )->creation_time;
984
985
3.37k
      byte_stream_copy_to_uint32_big_endian(
986
3.37k
       ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
987
3.37k
       value_32bit );
988
989
3.37k
      inode->creation_time = (int32_t) value_32bit * (int64_t) 1000000000;
990
991
3.37k
      byte_stream_copy_to_uint32_big_endian(
992
3.37k
       ( (fsxfs_timestamp_t *) timestamp_data )->nanoseconds,
993
3.37k
       value_32bit );
994
995
3.37k
      if( inode->creation_time > 0 )
996
2.34k
      {
997
2.34k
        inode->creation_time += value_32bit;
998
2.34k
      }
999
1.02k
      else
1000
1.02k
      {
1001
1.02k
        inode->creation_time -= value_32bit;
1002
1.02k
      }
1003
3.37k
    }
1004
#if defined( HAVE_DEBUG_OUTPUT )
1005
    if( libcnotify_verbose != 0 )
1006
    {
1007
      byte_stream_copy_to_uint32_big_endian(
1008
       ( (fsxfs_inode_v3_t *) data )->checksum,
1009
       value_32bit );
1010
      libcnotify_printf(
1011
       "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
1012
       function,
1013
       value_32bit );
1014
1015
      byte_stream_copy_to_uint64_big_endian(
1016
       ( (fsxfs_inode_v3_t *) data )->change_count,
1017
       value_64bit );
1018
      libcnotify_printf(
1019
       "%s: change count\t\t\t\t\t: %" PRIu64 "\n",
1020
       function,
1021
       value_64bit );
1022
1023
      byte_stream_copy_to_uint64_big_endian(
1024
       ( (fsxfs_inode_v3_t *) data )->log_sequence_number,
1025
       value_64bit );
1026
      libcnotify_printf(
1027
       "%s: log sequence number\t\t\t\t: 0x%08" PRIx64 "\n",
1028
       function,
1029
       value_64bit );
1030
1031
      byte_stream_copy_to_uint64_big_endian(
1032
       ( (fsxfs_inode_v3_t *) data )->extended_inode_flags,
1033
       value_64bit );
1034
      libcnotify_printf(
1035
       "%s: extended inode flags\t\t\t\t: 0x%08" PRIx64 "\n",
1036
       function,
1037
       value_64bit );
1038
1039
      byte_stream_copy_to_uint32_big_endian(
1040
       ( (fsxfs_inode_v3_t *) data )->cow_extent_size,
1041
       value_32bit );
1042
      libcnotify_printf(
1043
       "%s: copy-on-write extent size\t\t\t: %" PRIu32 "\n",
1044
       function,
1045
       value_32bit );
1046
1047
      libcnotify_printf(
1048
       "%s: unknown8:\n",
1049
       function );
1050
      libcnotify_print_data(
1051
       ( (fsxfs_inode_v3_t *) data )->unknown8,
1052
       12,
1053
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1054
1055
      if( ( io_handle->incompatible_features_flags & LIBFSXFS_INCOMPATIBLE_FEATURES_FLAG_HAS_BIGTIME ) != 0 )
1056
      {
1057
        byte_stream_copy_to_uint64_big_endian(
1058
         ( (fsxfs_inode_v3_t *) data )->creation_time,
1059
         value_64bit );
1060
        libcnotify_printf(
1061
         "%s: creation time (bigtime)\t\t\t: %" PRIu64 "\n",
1062
         function,
1063
         value_64bit );
1064
      }
1065
      else
1066
      {
1067
        timestamp_data = ( (fsxfs_inode_v3_t *) data )->creation_time;
1068
1069
        if( libfsxfs_debug_print_posix_time_value(
1070
             function,
1071
             "creation time (seconds)\t\t\t",
1072
             ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
1073
             4,
1074
             LIBFDATETIME_ENDIAN_BIG,
1075
             LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
1076
             LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
1077
             error ) != 1 )
1078
        {
1079
          libcerror_error_set(
1080
           error,
1081
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1082
           LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1083
           "%s: unable to print POSIX time value.",
1084
           function );
1085
1086
          return( -1 );
1087
        }
1088
        byte_stream_copy_to_uint32_big_endian(
1089
         ( (fsxfs_timestamp_t *) timestamp_data )->seconds,
1090
         value_32bit );
1091
        libcnotify_printf(
1092
         "%s: creation time nanoseconds\t\t\t: %" PRIu32 "\n",
1093
         function,
1094
         value_32bit );
1095
      }
1096
      byte_stream_copy_to_uint64_big_endian(
1097
       ( (fsxfs_inode_v3_t *) data )->inode_number,
1098
       value_64bit );
1099
      libcnotify_printf(
1100
       "%s: inode number\t\t\t\t\t: %" PRIu64 "\n",
1101
       function,
1102
       value_64bit );
1103
1104
      if( libfsxfs_debug_print_guid_value(
1105
           function,
1106
           "inode type identifier\t\t\t\t",
1107
           ( (fsxfs_inode_v3_t *) data )->inode_type_identifier,
1108
           16,
1109
           LIBFGUID_ENDIAN_BIG,
1110
           LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
1111
           error ) != 1 )
1112
      {
1113
        libcerror_error_set(
1114
         error,
1115
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1116
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1117
         "%s: unable to print GUID value.",
1118
         function );
1119
1120
        return( -1 );
1121
      }
1122
    }
1123
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1124
4.14k
  }
1125
#if defined( HAVE_DEBUG_OUTPUT )
1126
  if( libcnotify_verbose != 0 )
1127
  {
1128
    libcnotify_printf(
1129
     "\n" );
1130
  }
1131
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1132
1133
4.60k
  data_fork_size = data_size - inode_data_size;
1134
1135
4.60k
  if( inode->attributes_fork_offset > 0 )
1136
2.42k
  {
1137
2.42k
    if( inode->attributes_fork_offset >= data_fork_size )
1138
124
    {
1139
124
      libcerror_error_set(
1140
124
       error,
1141
124
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1142
124
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1143
124
       "%s: invalid attributes fork offset value out of bounds.",
1144
124
       function );
1145
1146
124
      return( -1 );
1147
124
    }
1148
2.29k
    data_fork_size = (size_t) inode->attributes_fork_offset;
1149
1150
2.29k
    inode->attributes_fork_offset += inode_data_size;
1151
2.29k
    inode->attributes_fork_size    = data_size - inode->attributes_fork_offset;
1152
2.29k
  }
1153
4.47k
  inode->data_fork_offset = (uint16_t) inode_data_size;
1154
4.47k
  inode->data_fork_size   = (uint16_t) data_fork_size;
1155
1156
4.47k
  if( ( inode->fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA )
1157
1.01k
   && ( inode->size > inode->data_fork_size ) )
1158
192
  {
1159
192
    libcerror_error_set(
1160
192
     error,
1161
192
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1162
192
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1163
192
     "%s: invalid inline data size value out of bounds.",
1164
192
     function );
1165
1166
192
    return( -1 );
1167
192
  }
1168
4.28k
  return( 1 );
1169
4.47k
}
1170
1171
/* Reads the inode from a Basic File IO (bfio) handle
1172
 * Returns 1 if successful or -1 on error
1173
 */
1174
int libfsxfs_inode_read_file_io_handle(
1175
     libfsxfs_inode_t *inode,
1176
     libfsxfs_io_handle_t *io_handle,
1177
     libbfio_handle_t *file_io_handle,
1178
     off64_t file_offset,
1179
     libcerror_error_t **error )
1180
5.09k
{
1181
5.09k
  libfsxfs_extent_btree_t *extent_btree = NULL;
1182
5.09k
  static char *function                 = "libfsxfs_inode_read_file_io_handle";
1183
5.09k
  ssize_t read_count                    = 0;
1184
5.09k
  uint64_t number_of_blocks             = 0;
1185
5.09k
  uint8_t add_sparse_extents            = 0;
1186
1187
5.09k
  if( inode == NULL )
1188
0
  {
1189
0
    libcerror_error_set(
1190
0
     error,
1191
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1192
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1193
0
     "%s: invalid inode.",
1194
0
     function );
1195
1196
0
    return( -1 );
1197
0
  }
1198
5.09k
  if( io_handle == NULL )
1199
0
  {
1200
0
    libcerror_error_set(
1201
0
     error,
1202
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1203
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1204
0
     "%s: invalid IO handle.",
1205
0
     function );
1206
1207
0
    return( -1 );
1208
0
  }
1209
5.09k
  if( io_handle->block_size == 0 )
1210
0
  {
1211
0
    libcerror_error_set(
1212
0
     error,
1213
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1214
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1215
0
     "%s: invalid IO handle - block size value out of bounds.",
1216
0
     function );
1217
1218
0
    return( -1 );
1219
0
  }
1220
#if defined( HAVE_DEBUG_OUTPUT )
1221
  if( libcnotify_verbose != 0 )
1222
  {
1223
    libcnotify_printf(
1224
     "%s: reading inode at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1225
     function,
1226
     file_offset,
1227
     file_offset );
1228
  }
1229
#endif
1230
5.09k
  read_count = libbfio_handle_read_buffer_at_offset(
1231
5.09k
                file_io_handle,
1232
5.09k
                inode->data,
1233
5.09k
                inode->data_size,
1234
5.09k
                file_offset,
1235
5.09k
                error );
1236
1237
5.09k
  if( read_count != (ssize_t) inode->data_size )
1238
30
  {
1239
30
    libcerror_error_set(
1240
30
     error,
1241
30
     LIBCERROR_ERROR_DOMAIN_IO,
1242
30
     LIBCERROR_IO_ERROR_READ_FAILED,
1243
30
     "%s: unable to read inode data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1244
30
     function,
1245
30
     file_offset,
1246
30
     file_offset );
1247
1248
30
    return( -1 );
1249
30
  }
1250
5.06k
  if( libfsxfs_inode_read_data(
1251
5.06k
       inode,
1252
5.06k
       io_handle,
1253
5.06k
       inode->data,
1254
5.06k
       inode->data_size,
1255
5.06k
       error ) != 1 )
1256
775
  {
1257
775
    libcerror_error_set(
1258
775
     error,
1259
775
     LIBCERROR_ERROR_DOMAIN_IO,
1260
775
     LIBCERROR_IO_ERROR_READ_FAILED,
1261
775
     "%s: unable to read inode at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1262
775
     function,
1263
775
     file_offset,
1264
775
     file_offset );
1265
1266
775
    return( -1 );
1267
775
  }
1268
4.28k
  number_of_blocks = inode->size / io_handle->block_size;
1269
1270
4.28k
  if( ( inode->size % io_handle->block_size ) != 0 )
1271
4.01k
  {
1272
4.01k
    number_of_blocks++;
1273
4.01k
  }
1274
4.28k
  if( ( inode->file_mode & 0xf000 ) != LIBFSXFS_FILE_TYPE_DIRECTORY )
1275
1.13k
  {
1276
1.13k
    add_sparse_extents = 1;
1277
1.13k
  }
1278
4.28k
  if( inode->fork_type == LIBFSXFS_FORK_TYPE_DEVICE )
1279
10
  {
1280
#if defined( HAVE_DEBUG_OUTPUT )
1281
    if( libcnotify_verbose != 0 )
1282
    {
1283
      libcnotify_printf(
1284
       "%s: device identifier data:\n",
1285
       function );
1286
      libcnotify_print_data(
1287
       &( inode->data[ inode->data_fork_offset ] ),
1288
       4,
1289
       0 );
1290
    }
1291
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1292
1293
10
    byte_stream_copy_to_uint32_big_endian(
1294
10
     &( inode->data[ inode->data_fork_offset ] ),
1295
10
     inode->device_identifier );
1296
10
  }
1297
4.27k
  else if( inode->fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA )
1298
824
  {
1299
#if defined( HAVE_DEBUG_OUTPUT )
1300
    if( libcnotify_verbose != 0 )
1301
    {
1302
      libcnotify_printf(
1303
       "%s: inline data:\n",
1304
       function );
1305
      libcnotify_print_data(
1306
       &( inode->data[ inode->data_fork_offset ] ),
1307
       (size_t) inode->size,
1308
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1309
    }
1310
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1311
1312
824
    inode->inline_data = &( inode->data[ inode->data_fork_offset ] );
1313
824
  }
1314
3.45k
  else if( inode->fork_type == LIBFSXFS_FORK_TYPE_EXTENTS )
1315
2.68k
  {
1316
#if defined( HAVE_DEBUG_OUTPUT )
1317
    if( libcnotify_verbose != 0 )
1318
    {
1319
      libcnotify_printf(
1320
       "%s: data extent list:\n",
1321
       function );
1322
      libcnotify_print_data(
1323
       &( inode->data[ inode->data_fork_offset ] ),
1324
       (size_t) inode->data_fork_size,
1325
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1326
    }
1327
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1328
1329
2.68k
    if( libcdata_array_initialize(
1330
2.68k
         &( inode->data_extents_array ),
1331
2.68k
         0,
1332
2.68k
         error ) != 1 )
1333
0
    {
1334
0
      libcerror_error_set(
1335
0
       error,
1336
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1337
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1338
0
       "%s: unable to create data extents array.",
1339
0
       function );
1340
1341
0
      goto on_error;
1342
0
    }
1343
2.68k
    if( libfsxfs_extent_list_read_data(
1344
2.68k
         inode->data_extents_array,
1345
2.68k
         number_of_blocks,
1346
2.68k
         inode->number_of_data_extents,
1347
2.68k
         &( inode->data[ inode->data_fork_offset ] ),
1348
2.68k
         inode->data_fork_size,
1349
2.68k
         add_sparse_extents,
1350
2.68k
         error ) != 1 )
1351
317
    {
1352
317
      libcerror_error_set(
1353
317
       error,
1354
317
       LIBCERROR_ERROR_DOMAIN_IO,
1355
317
       LIBCERROR_IO_ERROR_READ_FAILED,
1356
317
       "%s: unable to read data extent list.",
1357
317
       function );
1358
1359
317
      goto on_error;
1360
317
    }
1361
2.68k
  }
1362
771
  else if( inode->fork_type == LIBFSXFS_FORK_TYPE_BTREE )
1363
699
  {
1364
#if defined( HAVE_DEBUG_OUTPUT )
1365
    if( libcnotify_verbose != 0 )
1366
    {
1367
      libcnotify_printf(
1368
       "%s: data extent B+ tree:\n",
1369
       function );
1370
      libcnotify_print_data(
1371
       &( inode->data[ inode->data_fork_offset ] ),
1372
       (size_t) inode->data_fork_size,
1373
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1374
    }
1375
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1376
1377
699
    if( libcdata_array_initialize(
1378
699
         &( inode->data_extents_array ),
1379
699
         0,
1380
699
         error ) != 1 )
1381
0
    {
1382
0
      libcerror_error_set(
1383
0
       error,
1384
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1385
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1386
0
       "%s: unable to create data extents array.",
1387
0
       function );
1388
1389
0
      goto on_error;
1390
0
    }
1391
699
    if( libfsxfs_extent_btree_initialize(
1392
699
         &extent_btree,
1393
699
         error ) != 1 )
1394
0
    {
1395
0
      libcerror_error_set(
1396
0
       error,
1397
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1398
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1399
0
       "%s: unable to create data extents B+ tree.",
1400
0
       function );
1401
1402
0
      goto on_error;
1403
0
    }
1404
699
    if( libfsxfs_extent_btree_get_extents_from_root_node(
1405
699
         extent_btree,
1406
699
         io_handle,
1407
699
         file_io_handle,
1408
699
         number_of_blocks,
1409
699
         &( inode->data[ inode->data_fork_offset ] ),
1410
699
         inode->data_fork_size,
1411
699
         inode->data_extents_array,
1412
699
         add_sparse_extents,
1413
699
         error ) != 1 )
1414
244
    {
1415
244
      libcerror_error_set(
1416
244
       error,
1417
244
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1418
244
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1419
244
       "%s: unable to retrieve data extents from extent B+ tree.",
1420
244
       function );
1421
1422
244
      goto on_error;
1423
244
    }
1424
455
    if( libfsxfs_extent_btree_free(
1425
455
         &extent_btree,
1426
455
         error ) != 1 )
1427
0
    {
1428
0
      libcerror_error_set(
1429
0
       error,
1430
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1431
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1432
0
       "%s: unable to free data extents B+ tree.",
1433
0
       function );
1434
1435
0
      goto on_error;
1436
0
    }
1437
455
  }
1438
3.72k
  if( inode->attributes_fork_size > 0 )
1439
1.93k
  {
1440
#if defined( HAVE_DEBUG_OUTPUT )
1441
    if( libcnotify_verbose != 0 )
1442
    {
1443
      libcnotify_printf(
1444
       "%s: attributes fork data:\n",
1445
       function );
1446
      libcnotify_print_data(
1447
       &( inode->data[ inode->attributes_fork_offset ] ),
1448
       (size_t) inode->attributes_fork_size,
1449
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1450
    }
1451
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1452
1453
1.93k
    number_of_blocks = inode->attributes_fork_size / io_handle->block_size;
1454
1455
1.93k
    if( ( inode->attributes_fork_size % io_handle->block_size ) != 0 )
1456
1.93k
    {
1457
1.93k
      number_of_blocks++;
1458
1.93k
    }
1459
1.93k
    if( inode->attributes_fork_type == LIBFSXFS_FORK_TYPE_INLINE_DATA )
1460
233
    {
1461
#if defined( HAVE_DEBUG_OUTPUT )
1462
      if( libcnotify_verbose != 0 )
1463
      {
1464
        libcnotify_printf(
1465
         "%s: inline attributes data:\n",
1466
         function );
1467
        libcnotify_print_data(
1468
         &( inode->data[ inode->attributes_fork_offset ] ),
1469
         (size_t) inode->attributes_fork_size,
1470
         LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
1471
      }
1472
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1473
1474
233
      inode->inline_attributes_data = &( inode->data[ inode->attributes_fork_offset ] );
1475
233
    }
1476
1.70k
    else if( ( inode->attributes_fork_type == LIBFSXFS_FORK_TYPE_EXTENTS )
1477
692
          && ( inode->number_of_attributes_extents > 0 ) )
1478
331
    {
1479
331
      if( libcdata_array_initialize(
1480
331
           &( inode->attributes_extents_array ),
1481
331
           0,
1482
331
           error ) != 1 )
1483
0
      {
1484
0
        libcerror_error_set(
1485
0
         error,
1486
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1487
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1488
0
         "%s: unable to create attributes extents array.",
1489
0
         function );
1490
1491
0
        goto on_error;
1492
0
      }
1493
331
      if( libfsxfs_extent_list_read_data(
1494
331
           inode->attributes_extents_array,
1495
331
           number_of_blocks,
1496
331
           inode->number_of_attributes_extents,
1497
331
           &( inode->data[ inode->attributes_fork_offset ] ),
1498
331
           inode->attributes_fork_size,
1499
331
           0,
1500
331
           error ) != 1 )
1501
67
      {
1502
67
        libcerror_error_set(
1503
67
         error,
1504
67
         LIBCERROR_ERROR_DOMAIN_IO,
1505
67
         LIBCERROR_IO_ERROR_READ_FAILED,
1506
67
         "%s: unable to read attributes extent list.",
1507
67
         function );
1508
1509
67
        goto on_error;
1510
67
      }
1511
331
    }
1512
1.37k
    else if( inode->attributes_fork_type == LIBFSXFS_FORK_TYPE_BTREE )
1513
273
    {
1514
273
      if( libcdata_array_initialize(
1515
273
           &( inode->attributes_extents_array ),
1516
273
           0,
1517
273
           error ) != 1 )
1518
0
      {
1519
0
        libcerror_error_set(
1520
0
         error,
1521
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1522
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1523
0
         "%s: unable to create attributes extents array.",
1524
0
         function );
1525
1526
0
        goto on_error;
1527
0
      }
1528
273
      if( libfsxfs_extent_btree_initialize(
1529
273
           &extent_btree,
1530
273
           error ) != 1 )
1531
0
      {
1532
0
        libcerror_error_set(
1533
0
         error,
1534
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1535
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1536
0
         "%s: unable to create attributes extents B+ tree.",
1537
0
         function );
1538
1539
0
        goto on_error;
1540
0
      }
1541
273
      if( libfsxfs_extent_btree_get_extents_from_root_node(
1542
273
           extent_btree,
1543
273
           io_handle,
1544
273
           file_io_handle,
1545
273
           number_of_blocks,
1546
273
           &( inode->data[ inode->attributes_fork_offset ] ),
1547
273
           inode->attributes_fork_size,
1548
273
           inode->attributes_extents_array,
1549
273
           0,
1550
273
           error ) != 1 )
1551
68
      {
1552
68
        libcerror_error_set(
1553
68
         error,
1554
68
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1555
68
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1556
68
         "%s: unable to retrieve attributes extents from extent B+ tree.",
1557
68
         function );
1558
1559
68
        goto on_error;
1560
68
      }
1561
205
      if( libfsxfs_extent_btree_free(
1562
205
           &extent_btree,
1563
205
           error ) != 1 )
1564
0
      {
1565
0
        libcerror_error_set(
1566
0
         error,
1567
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1568
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1569
0
         "%s: unable to free attributes extents B+ tree.",
1570
0
         function );
1571
1572
0
        goto on_error;
1573
0
      }
1574
205
    }
1575
1.93k
  }
1576
3.59k
  return( 1 );
1577
1578
696
on_error:
1579
696
  if( extent_btree != NULL )
1580
312
  {
1581
312
    libfsxfs_extent_btree_free(
1582
312
     &extent_btree,
1583
312
     NULL );
1584
312
  }
1585
696
  if( inode->attributes_extents_array != NULL )
1586
135
  {
1587
135
    libcdata_array_free(
1588
135
     &( inode->attributes_extents_array ),
1589
135
     (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
1590
135
     NULL );
1591
135
  }
1592
696
  if( inode->data_extents_array != NULL )
1593
664
  {
1594
664
    libcdata_array_free(
1595
664
     &( inode->data_extents_array ),
1596
664
     (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
1597
664
     NULL );
1598
664
  }
1599
696
  return( -1 );
1600
3.72k
}
1601
1602
/* Retrieves the creation time
1603
 * The timestamp is a signed 64-bit POSIX date and time value in number of nanoseconds
1604
 * Returns 1 if successful, 0 if not available or -1 on error
1605
 */
1606
int libfsxfs_inode_get_creation_time(
1607
     libfsxfs_inode_t *inode,
1608
     int64_t *posix_time,
1609
     libcerror_error_t **error )
1610
359
{
1611
359
  static char *function = "libfsxfs_inode_get_creation_time";
1612
1613
359
  if( inode == NULL )
1614
0
  {
1615
0
    libcerror_error_set(
1616
0
     error,
1617
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1618
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1619
0
     "%s: invalid inode.",
1620
0
     function );
1621
1622
0
    return( -1 );
1623
0
  }
1624
359
  if( posix_time == NULL )
1625
0
  {
1626
0
    libcerror_error_set(
1627
0
     error,
1628
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1629
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1630
0
     "%s: invalid POSIX time.",
1631
0
     function );
1632
1633
0
    return( -1 );
1634
0
  }
1635
359
  if( inode->format_version == 3 )
1636
218
  {
1637
218
    *posix_time = inode->creation_time;
1638
1639
218
    return( 1 );
1640
218
  }
1641
141
  return( 0 );
1642
359
}
1643
1644
/* Retrieves the modification time
1645
 * The timestamp is a signed 64-bit POSIX date and time value in number of nanoseconds
1646
 * Returns 1 if successful or -1 on error
1647
 */
1648
int libfsxfs_inode_get_modification_time(
1649
     libfsxfs_inode_t *inode,
1650
     int64_t *posix_time,
1651
     libcerror_error_t **error )
1652
359
{
1653
359
  static char *function = "libfsxfs_inode_get_modification_time";
1654
1655
359
  if( inode == NULL )
1656
0
  {
1657
0
    libcerror_error_set(
1658
0
     error,
1659
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1660
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1661
0
     "%s: invalid inode.",
1662
0
     function );
1663
1664
0
    return( -1 );
1665
0
  }
1666
359
  if( posix_time == NULL )
1667
0
  {
1668
0
    libcerror_error_set(
1669
0
     error,
1670
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1671
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1672
0
     "%s: invalid POSIX time.",
1673
0
     function );
1674
1675
0
    return( -1 );
1676
0
  }
1677
359
  *posix_time = inode->modification_time;
1678
1679
359
  return( 1 );
1680
359
}
1681
1682
/* Retrieves the access time
1683
 * The timestamp is a signed 64-bit POSIX date and time value in number of nanoseconds
1684
 * Returns 1 if successful or -1 on error
1685
 */
1686
int libfsxfs_inode_get_access_time(
1687
     libfsxfs_inode_t *inode,
1688
     int64_t *posix_time,
1689
     libcerror_error_t **error )
1690
359
{
1691
359
  static char *function = "libfsxfs_inode_get_access_time";
1692
1693
359
  if( inode == NULL )
1694
0
  {
1695
0
    libcerror_error_set(
1696
0
     error,
1697
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1698
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1699
0
     "%s: invalid inode.",
1700
0
     function );
1701
1702
0
    return( -1 );
1703
0
  }
1704
359
  if( posix_time == NULL )
1705
0
  {
1706
0
    libcerror_error_set(
1707
0
     error,
1708
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1709
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1710
0
     "%s: invalid POSIX time.",
1711
0
     function );
1712
1713
0
    return( -1 );
1714
0
  }
1715
359
  *posix_time = inode->access_time;
1716
1717
359
  return( 1 );
1718
359
}
1719
1720
/* Retrieves the inode change time
1721
 * The timestamp is a signed 64-bit POSIX date and time value in number of nanoseconds
1722
 * Returns 1 if successful or -1 on error
1723
 */
1724
int libfsxfs_inode_get_inode_change_time(
1725
     libfsxfs_inode_t *inode,
1726
     int64_t *posix_time,
1727
     libcerror_error_t **error )
1728
359
{
1729
359
  static char *function = "libfsxfs_inode_get_inode_change_time";
1730
1731
359
  if( inode == NULL )
1732
0
  {
1733
0
    libcerror_error_set(
1734
0
     error,
1735
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1736
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1737
0
     "%s: invalid inode.",
1738
0
     function );
1739
1740
0
    return( -1 );
1741
0
  }
1742
359
  if( posix_time == NULL )
1743
0
  {
1744
0
    libcerror_error_set(
1745
0
     error,
1746
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1747
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1748
0
     "%s: invalid POSIX time.",
1749
0
     function );
1750
1751
0
    return( -1 );
1752
0
  }
1753
359
  *posix_time = inode->inode_change_time;
1754
1755
359
  return( 1 );
1756
359
}
1757
1758
/* Retrieves the owner identifier
1759
 * Returns 1 if successful or -1 on error
1760
 */
1761
int libfsxfs_inode_get_owner_identifier(
1762
     libfsxfs_inode_t *inode,
1763
     uint32_t *owner_identifier,
1764
     libcerror_error_t **error )
1765
359
{
1766
359
  static char *function = "libfsxfs_inode_get_owner_identifier";
1767
1768
359
  if( inode == NULL )
1769
0
  {
1770
0
    libcerror_error_set(
1771
0
     error,
1772
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1773
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1774
0
     "%s: invalid inode.",
1775
0
     function );
1776
1777
0
    return( -1 );
1778
0
  }
1779
359
  if( owner_identifier == NULL )
1780
0
  {
1781
0
    libcerror_error_set(
1782
0
     error,
1783
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1784
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1785
0
     "%s: invalid owner identifier.",
1786
0
     function );
1787
1788
0
    return( -1 );
1789
0
  }
1790
359
  *owner_identifier = inode->owner_identifier;
1791
1792
359
  return( 1 );
1793
359
}
1794
1795
/* Retrieves the group identifier
1796
 * Returns 1 if successful or -1 on error
1797
 */
1798
int libfsxfs_inode_get_group_identifier(
1799
     libfsxfs_inode_t *inode,
1800
     uint32_t *group_identifier,
1801
     libcerror_error_t **error )
1802
359
{
1803
359
  static char *function = "libfsxfs_inode_get_group_identifier";
1804
1805
359
  if( inode == NULL )
1806
0
  {
1807
0
    libcerror_error_set(
1808
0
     error,
1809
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1810
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1811
0
     "%s: invalid inode.",
1812
0
     function );
1813
1814
0
    return( -1 );
1815
0
  }
1816
359
  if( group_identifier == NULL )
1817
0
  {
1818
0
    libcerror_error_set(
1819
0
     error,
1820
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1821
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1822
0
     "%s: invalid group identifier.",
1823
0
     function );
1824
1825
0
    return( -1 );
1826
0
  }
1827
359
  *group_identifier = inode->group_identifier;
1828
1829
359
  return( 1 );
1830
359
}
1831
1832
/* Retrieves the file mode
1833
 * Returns 1 if successful or -1 on error
1834
 */
1835
int libfsxfs_inode_get_file_mode(
1836
     libfsxfs_inode_t *inode,
1837
     uint16_t *file_mode,
1838
     libcerror_error_t **error )
1839
359
{
1840
359
  static char *function = "libfsxfs_inode_get_file_mode";
1841
1842
359
  if( inode == NULL )
1843
0
  {
1844
0
    libcerror_error_set(
1845
0
     error,
1846
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1847
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1848
0
     "%s: invalid inode.",
1849
0
     function );
1850
1851
0
    return( -1 );
1852
0
  }
1853
359
  if( file_mode == NULL )
1854
0
  {
1855
0
    libcerror_error_set(
1856
0
     error,
1857
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1858
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1859
0
     "%s: invalid file mode.",
1860
0
     function );
1861
1862
0
    return( -1 );
1863
0
  }
1864
359
  *file_mode = inode->file_mode;
1865
1866
359
  return( 1 );
1867
359
}
1868
1869
/* Retrieves the number of (hard) links
1870
 * Returns 1 if successful or -1 on error
1871
 */
1872
int libfsxfs_inode_get_number_of_links(
1873
     libfsxfs_inode_t *inode,
1874
     uint32_t *number_of_links,
1875
     libcerror_error_t **error )
1876
359
{
1877
359
  static char *function = "libfsxfs_inode_get_number_of_links";
1878
1879
359
  if( inode == NULL )
1880
0
  {
1881
0
    libcerror_error_set(
1882
0
     error,
1883
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1884
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1885
0
     "%s: invalid inode.",
1886
0
     function );
1887
1888
0
    return( -1 );
1889
0
  }
1890
359
  if( number_of_links == NULL )
1891
0
  {
1892
0
    libcerror_error_set(
1893
0
     error,
1894
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1895
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1896
0
     "%s: invalid number of (hard) links.",
1897
0
     function );
1898
1899
0
    return( -1 );
1900
0
  }
1901
359
  *number_of_links = inode->number_of_links;
1902
1903
359
  return( 1 );
1904
359
}
1905
1906
/* Retrieves the data size
1907
 * Returns 1 if successful or -1 on error
1908
 */
1909
int libfsxfs_inode_get_data_size(
1910
     libfsxfs_inode_t *inode,
1911
     uint64_t *data_size,
1912
     libcerror_error_t **error )
1913
592
{
1914
592
  static char *function = "libfsxfs_inode_get_data_size";
1915
1916
592
  if( inode == NULL )
1917
0
  {
1918
0
    libcerror_error_set(
1919
0
     error,
1920
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1921
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1922
0
     "%s: invalid inode.",
1923
0
     function );
1924
1925
0
    return( -1 );
1926
0
  }
1927
592
  if( data_size == NULL )
1928
0
  {
1929
0
    libcerror_error_set(
1930
0
     error,
1931
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1932
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1933
0
     "%s: invalid data size.",
1934
0
     function );
1935
1936
0
    return( -1 );
1937
0
  }
1938
592
  *data_size = inode->size;
1939
1940
592
  return( 1 );
1941
592
}
1942
1943
/* Retrieves the device identifier
1944
 * Returns 1 if successful, 0 if not available or -1 on error
1945
 */
1946
int libfsxfs_inode_get_device_identifier(
1947
     libfsxfs_inode_t *inode,
1948
     uint32_t *device_identifier,
1949
     libcerror_error_t **error )
1950
359
{
1951
359
  static char *function = "libfsxfs_inode_get_device_identifier";
1952
1953
359
  if( inode == NULL )
1954
0
  {
1955
0
    libcerror_error_set(
1956
0
     error,
1957
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1958
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1959
0
     "%s: invalid inode.",
1960
0
     function );
1961
1962
0
    return( -1 );
1963
0
  }
1964
359
  if( device_identifier == NULL )
1965
0
  {
1966
0
    libcerror_error_set(
1967
0
     error,
1968
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1969
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1970
0
     "%s: invalid device identifier.",
1971
0
     function );
1972
1973
0
    return( -1 );
1974
0
  }
1975
359
  if( inode->fork_type == LIBFSXFS_FORK_TYPE_DEVICE )
1976
3
  {
1977
3
    *device_identifier = inode->device_identifier;
1978
1979
3
    return( 1 );
1980
3
  }
1981
356
  return( 0 );
1982
359
}
1983
1984
/* Retrieves the device number
1985
 * Returns 1 if successful, 0 if not available or -1 on error
1986
 */
1987
int libfsxfs_inode_get_device_number(
1988
     libfsxfs_inode_t *inode,
1989
     uint32_t *major_device_number,
1990
     uint32_t *minor_device_number,
1991
     libcerror_error_t **error )
1992
359
{
1993
359
  static char *function = "libfsxfs_inode_get_device_number";
1994
1995
359
  if( inode == NULL )
1996
0
  {
1997
0
    libcerror_error_set(
1998
0
     error,
1999
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2000
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2001
0
     "%s: invalid inode.",
2002
0
     function );
2003
2004
0
    return( -1 );
2005
0
  }
2006
359
  if( major_device_number == NULL )
2007
0
  {
2008
0
    libcerror_error_set(
2009
0
     error,
2010
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2011
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2012
0
     "%s: invalid major device number.",
2013
0
     function );
2014
2015
0
    return( -1 );
2016
0
  }
2017
359
  if( minor_device_number == NULL )
2018
0
  {
2019
0
    libcerror_error_set(
2020
0
     error,
2021
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2022
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2023
0
     "%s: invalid minor device number.",
2024
0
     function );
2025
2026
0
    return( -1 );
2027
0
  }
2028
359
  if( inode->fork_type == LIBFSXFS_FORK_TYPE_DEVICE )
2029
3
  {
2030
3
    *major_device_number = inode->device_identifier >> 18;
2031
3
    *minor_device_number = inode->device_identifier & 0x0003ffffUL;
2032
2033
3
    return( 1 );
2034
3
  }
2035
356
  return( 0 );
2036
359
}
2037
2038
/* Retrieves the number of data extents
2039
 * Returns 1 if successful or -1 on error
2040
 */
2041
int libfsxfs_inode_get_number_of_data_extents(
2042
     libfsxfs_inode_t *inode,
2043
     int *number_of_extents,
2044
     libcerror_error_t **error )
2045
2.93k
{
2046
2.93k
  static char *function = "libfsxfs_inode_get_number_of_data_extents";
2047
2048
2.93k
  if( inode == NULL )
2049
0
  {
2050
0
    libcerror_error_set(
2051
0
     error,
2052
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2053
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2054
0
     "%s: invalid inode.",
2055
0
     function );
2056
2057
0
    return( -1 );
2058
0
  }
2059
2.93k
  if( libcdata_array_get_number_of_entries(
2060
2.93k
       inode->data_extents_array,
2061
2.93k
       number_of_extents,
2062
2.93k
       error ) != 1 )
2063
116
  {
2064
116
    libcerror_error_set(
2065
116
     error,
2066
116
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2067
116
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2068
116
     "%s: unable to retrieve number of data entries.",
2069
116
     function );
2070
2071
116
    return( -1 );
2072
116
  }
2073
2.81k
  return( 1 );
2074
2.93k
}
2075
2076
/* Retrieves a specific data extent
2077
 * Returns 1 if successful or -1 on error
2078
 */
2079
int libfsxfs_inode_get_data_extent_by_index(
2080
     libfsxfs_inode_t *inode,
2081
     int extent_index,
2082
     libfsxfs_extent_t **extent,
2083
     libcerror_error_t **error )
2084
29.2k
{
2085
29.2k
  static char *function = "libfsxfs_inode_get_data_extent_by_index";
2086
2087
29.2k
  if( inode == NULL )
2088
0
  {
2089
0
    libcerror_error_set(
2090
0
     error,
2091
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2092
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2093
0
     "%s: invalid inode.",
2094
0
     function );
2095
2096
0
    return( -1 );
2097
0
  }
2098
29.2k
  if( libcdata_array_get_entry_by_index(
2099
29.2k
       inode->data_extents_array,
2100
29.2k
       extent_index,
2101
29.2k
       (intptr_t **) extent,
2102
29.2k
       error ) != 1 )
2103
0
  {
2104
0
    libcerror_error_set(
2105
0
     error,
2106
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2107
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2108
0
     "%s: unable to retrieve data extent: %d.",
2109
0
     function,
2110
0
     extent_index );
2111
2112
0
    return( -1 );
2113
0
  }
2114
29.2k
  return( 1 );
2115
29.2k
}
2116
2117
/* Retrieves the number of attributes extents
2118
 * Returns 1 if successful or -1 on error
2119
 */
2120
int libfsxfs_inode_get_number_of_attributes_extents(
2121
     libfsxfs_inode_t *inode,
2122
     int *number_of_extents,
2123
     libcerror_error_t **error )
2124
0
{
2125
0
  static char *function = "libfsxfs_inode_get_number_of_attributes_extents";
2126
2127
0
  if( inode == 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 inode.",
2134
0
     function );
2135
2136
0
    return( -1 );
2137
0
  }
2138
0
  if( libcdata_array_get_number_of_entries(
2139
0
       inode->attributes_extents_array,
2140
0
       number_of_extents,
2141
0
       error ) != 1 )
2142
0
  {
2143
0
    libcerror_error_set(
2144
0
     error,
2145
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2146
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2147
0
     "%s: unable to retrieve number of attributes entries.",
2148
0
     function );
2149
2150
0
    return( -1 );
2151
0
  }
2152
0
  return( 1 );
2153
0
}
2154
2155
/* Retrieves a specific attributes extent
2156
 * Returns 1 if successful or -1 on error
2157
 */
2158
int libfsxfs_inode_get_attributes_extent_by_index(
2159
     libfsxfs_inode_t *inode,
2160
     int extent_index,
2161
     libfsxfs_extent_t **extent,
2162
     libcerror_error_t **error )
2163
0
{
2164
0
  static char *function = "libfsxfs_inode_get_attributes_extent_by_index";
2165
2166
0
  if( inode == NULL )
2167
0
  {
2168
0
    libcerror_error_set(
2169
0
     error,
2170
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2171
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2172
0
     "%s: invalid inode.",
2173
0
     function );
2174
2175
0
    return( -1 );
2176
0
  }
2177
0
  if( libcdata_array_get_entry_by_index(
2178
0
       inode->attributes_extents_array,
2179
0
       extent_index,
2180
0
       (intptr_t **) extent,
2181
0
       error ) != 1 )
2182
0
  {
2183
0
    libcerror_error_set(
2184
0
     error,
2185
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
2186
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
2187
0
     "%s: unable to retrieve attributes extent: %d.",
2188
0
     function,
2189
0
     extent_index );
2190
2191
0
    return( -1 );
2192
0
  }
2193
0
  return( 1 );
2194
0
}
2195