Coverage Report

Created: 2026-05-30 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsxfs/libfsxfs/libfsxfs_superblock.c
Line
Count
Source
1
/*
2
 * Superblock 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_debug.h"
28
#include "libfsxfs_libbfio.h"
29
#include "libfsxfs_libcerror.h"
30
#include "libfsxfs_libcnotify.h"
31
#include "libfsxfs_libfguid.h"
32
#include "libfsxfs_libuna.h"
33
#include "libfsxfs_superblock.h"
34
35
#include "fsxfs_superblock.h"
36
37
const char *fsxfs_superblock_signature = "XFSB";
38
39
/* Creates a superblock
40
 * Make sure the value superblock is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libfsxfs_superblock_initialize(
44
     libfsxfs_superblock_t **superblock,
45
     libcerror_error_t **error )
46
9.85k
{
47
9.85k
  static char *function = "libfsxfs_superblock_initialize";
48
49
9.85k
  if( superblock == NULL )
50
0
  {
51
0
    libcerror_error_set(
52
0
     error,
53
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
54
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
55
0
     "%s: invalid superblock.",
56
0
     function );
57
58
0
    return( -1 );
59
0
  }
60
9.85k
  if( *superblock != NULL )
61
0
  {
62
0
    libcerror_error_set(
63
0
     error,
64
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
65
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
66
0
     "%s: invalid superblock value already set.",
67
0
     function );
68
69
0
    return( -1 );
70
0
  }
71
9.85k
  *superblock = memory_allocate_structure(
72
9.85k
                 libfsxfs_superblock_t );
73
74
9.85k
  if( *superblock == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
79
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
80
0
     "%s: unable to create superblock.",
81
0
     function );
82
83
0
    goto on_error;
84
0
  }
85
9.85k
  if( memory_set(
86
9.85k
       *superblock,
87
9.85k
       0,
88
9.85k
       sizeof( libfsxfs_superblock_t ) ) == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
94
0
     "%s: unable to clear superblock.",
95
0
     function );
96
97
0
    goto on_error;
98
0
  }
99
9.85k
  return( 1 );
100
101
0
on_error:
102
0
  if( *superblock != NULL )
103
0
  {
104
0
    memory_free(
105
0
     *superblock );
106
107
0
    *superblock = NULL;
108
0
  }
109
0
  return( -1 );
110
9.85k
}
111
112
/* Frees a superblock
113
 * Returns 1 if successful or -1 on error
114
 */
115
int libfsxfs_superblock_free(
116
     libfsxfs_superblock_t **superblock,
117
     libcerror_error_t **error )
118
9.85k
{
119
9.85k
  static char *function = "libfsxfs_superblock_free";
120
121
9.85k
  if( superblock == NULL )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
126
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
127
0
     "%s: invalid superblock.",
128
0
     function );
129
130
0
    return( -1 );
131
0
  }
132
9.85k
  if( *superblock != NULL )
133
9.85k
  {
134
9.85k
    memory_free(
135
9.85k
     *superblock );
136
137
9.85k
    *superblock = NULL;
138
9.85k
  }
139
9.85k
  return( 1 );
140
9.85k
}
141
142
/* Reads the superblock data
143
 * Returns 1 if successful or -1 on error
144
 */
145
int libfsxfs_superblock_read_data(
146
     libfsxfs_superblock_t *superblock,
147
     const uint8_t *data,
148
     size_t data_size,
149
     libcerror_error_t **error )
150
9.36k
{
151
9.36k
  static char *function               = "libfsxfs_superblock_read_data";
152
9.36k
  uint32_t supported_feature_flags    = 0;
153
9.36k
  uint16_t number_of_inodes_per_block = 0;
154
9.36k
  uint16_t version_and_feature_flags  = 0;
155
156
#if defined( HAVE_DEBUG_OUTPUT )
157
  uint64_t value_64bit                = 0;
158
  uint32_t value_32bit                = 0;
159
  uint16_t value_16bit                = 0;
160
#endif
161
162
9.36k
  if( superblock == NULL )
163
0
  {
164
0
    libcerror_error_set(
165
0
     error,
166
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
167
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
168
0
     "%s: invalid superblock.",
169
0
     function );
170
171
0
    return( -1 );
172
0
  }
173
9.36k
  if( data == NULL )
174
0
  {
175
0
    libcerror_error_set(
176
0
     error,
177
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
178
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
179
0
     "%s: invalid data.",
180
0
     function );
181
182
0
    return( -1 );
183
0
  }
184
9.36k
  if( ( data_size < sizeof( fsxfs_superblock_t ) )
185
9.36k
   || ( data_size > (size_t) SSIZE_MAX ) )
186
0
  {
187
0
    libcerror_error_set(
188
0
     error,
189
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
190
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
191
0
     "%s: invalid data size value out of bounds.",
192
0
     function );
193
194
0
    return( -1 );
195
0
  }
196
#if defined( HAVE_DEBUG_OUTPUT )
197
  if( libcnotify_verbose != 0 )
198
  {
199
    libcnotify_printf(
200
     "%s: superblock data:\n",
201
     function );
202
    libcnotify_print_data(
203
     data,
204
     sizeof( fsxfs_superblock_t ),
205
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
206
  }
207
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
208
209
9.36k
  if( memory_compare(
210
9.36k
       ( (fsxfs_superblock_t *) data )->signature,
211
9.36k
       fsxfs_superblock_signature,
212
9.36k
       4 ) != 0 )
213
129
  {
214
129
    libcerror_error_set(
215
129
     error,
216
129
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
217
129
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
218
129
     "%s: unsupported signature.",
219
129
     function );
220
221
129
    return( -1 );
222
129
  }
223
9.23k
  byte_stream_copy_to_uint32_big_endian(
224
9.23k
   ( (fsxfs_superblock_t *) data )->block_size,
225
9.23k
   superblock->block_size );
226
227
9.23k
  byte_stream_copy_to_uint64_big_endian(
228
9.23k
   ( (fsxfs_superblock_t *) data )->number_of_blocks,
229
9.23k
   superblock->number_of_blocks );
230
231
9.23k
  byte_stream_copy_to_uint64_big_endian(
232
9.23k
   ( (fsxfs_superblock_t *) data )->journal_block_number,
233
9.23k
   superblock->journal_block_number );
234
235
9.23k
  byte_stream_copy_to_uint64_big_endian(
236
9.23k
   ( (fsxfs_superblock_t *) data )->root_directory_inode_number,
237
9.23k
   superblock->root_directory_inode_number );
238
239
9.23k
  byte_stream_copy_to_uint32_big_endian(
240
9.23k
   ( (fsxfs_superblock_t *) data )->allocation_group_size,
241
9.23k
   superblock->allocation_group_size );
242
243
9.23k
  byte_stream_copy_to_uint32_big_endian(
244
9.23k
   ( (fsxfs_superblock_t *) data )->number_of_allocation_groups,
245
9.23k
   superblock->number_of_allocation_groups );
246
247
9.23k
  byte_stream_copy_to_uint16_big_endian(
248
9.23k
   ( (fsxfs_superblock_t *) data )->version_and_feature_flags,
249
9.23k
   version_and_feature_flags );
250
251
9.23k
  superblock->format_version = (uint8_t) ( version_and_feature_flags & 0x000f );
252
9.23k
  superblock->feature_flags  = version_and_feature_flags & 0xfff0;
253
254
9.23k
  byte_stream_copy_to_uint16_big_endian(
255
9.23k
   ( (fsxfs_superblock_t *) data )->sector_size,
256
9.23k
   superblock->sector_size );
257
258
9.23k
  byte_stream_copy_to_uint16_big_endian(
259
9.23k
   ( (fsxfs_superblock_t *) data )->inode_size,
260
9.23k
   superblock->inode_size );
261
262
9.23k
  byte_stream_copy_to_uint16_big_endian(
263
9.23k
   ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block,
264
9.23k
   number_of_inodes_per_block );
265
266
9.23k
  if( memory_copy(
267
9.23k
       superblock->volume_label,
268
9.23k
       ( (fsxfs_superblock_t *) data )->volume_label,
269
9.23k
       12 ) == NULL )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
274
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
275
0
     "%s: unable to copy volume label.",
276
0
     function );
277
278
0
    return( -1 );
279
0
  }
280
9.23k
  byte_stream_copy_to_uint32_big_endian(
281
9.23k
   ( (fsxfs_superblock_t *) data )->secondary_feature_flags,
282
9.23k
   superblock->secondary_feature_flags );
283
284
#if defined( HAVE_DEBUG_OUTPUT )
285
  if( libcnotify_verbose != 0 )
286
  {
287
    libcnotify_printf(
288
     "%s: signature\t\t\t\t: %c%c%c%c\n",
289
     function,
290
     ( (fsxfs_superblock_t *) data )->signature[ 0 ],
291
     ( (fsxfs_superblock_t *) data )->signature[ 1 ],
292
     ( (fsxfs_superblock_t *) data )->signature[ 2 ],
293
     ( (fsxfs_superblock_t *) data )->signature[ 3 ] );
294
295
    libcnotify_printf(
296
     "%s: block size\t\t\t\t: %" PRIu32 "\n",
297
     function,
298
     superblock->block_size );
299
300
    libcnotify_printf(
301
     "%s: number of blocks\t\t\t\t: %" PRIu64 "\n",
302
     function,
303
     superblock->number_of_blocks );
304
305
    byte_stream_copy_to_uint64_big_endian(
306
     ( (fsxfs_superblock_t *) data )->number_of_realtime_blocks,
307
     value_64bit );
308
    libcnotify_printf(
309
     "%s: number of real-time blocks\t\t: %" PRIu64 "\n",
310
     function,
311
     value_64bit );
312
313
    byte_stream_copy_to_uint64_big_endian(
314
     ( (fsxfs_superblock_t *) data )->number_of_realtime_extents,
315
     value_64bit );
316
    libcnotify_printf(
317
     "%s: number of real-time extents\t\t: %" PRIu64 "\n",
318
     function,
319
     value_64bit );
320
321
    if( libfsxfs_debug_print_guid_value(
322
         function,
323
         "file system identifier\t\t\t",
324
         ( (fsxfs_superblock_t *) data )->file_system_identifier,
325
         16,
326
         LIBFGUID_ENDIAN_BIG,
327
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
328
         error ) != 1 )
329
    {
330
      libcerror_error_set(
331
       error,
332
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
333
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
334
       "%s: unable to print GUID value.",
335
       function );
336
337
      return( -1 );
338
    }
339
    libcnotify_printf(
340
     "%s: journal block number\t\t\t: %" PRIu64 "\n",
341
     function,
342
     superblock->journal_block_number );
343
344
    if( superblock->root_directory_inode_number == 0xffffffffffffffffUL )
345
    {
346
      libcnotify_printf(
347
       "%s: root directory inode number\t\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
348
       function,
349
       (int64_t) superblock->root_directory_inode_number,
350
       superblock->root_directory_inode_number );
351
    }
352
    else
353
    {
354
      libcnotify_printf(
355
       "%s: root directory inode number\t\t: %" PRIu64 "\n",
356
       function,
357
       superblock->root_directory_inode_number );
358
    }
359
    byte_stream_copy_to_uint64_big_endian(
360
     ( (fsxfs_superblock_t *) data )->realtime_bitmap_extents_inode_number,
361
     value_64bit );
362
363
    if( value_64bit == 0xffffffffffffffffUL )
364
    {
365
      libcnotify_printf(
366
       "%s: real-time bitmap extents inode number\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
367
       function,
368
       (int64_t) value_64bit,
369
       value_64bit );
370
    }
371
    else
372
    {
373
      libcnotify_printf(
374
       "%s: real-time bitmap extents inode number\t: %" PRIu64 "\n",
375
       function,
376
       value_64bit );
377
    }
378
    byte_stream_copy_to_uint64_big_endian(
379
     ( (fsxfs_superblock_t *) data )->realtime_bitmap_summary_inode_number,
380
     value_64bit );
381
382
    if( value_64bit == 0xffffffffffffffffUL )
383
    {
384
      libcnotify_printf(
385
       "%s: real-time bitmap summary inode number\t: %" PRIi64 " (0x%08" PRIx64 ")\n",
386
       function,
387
       (int64_t) value_64bit,
388
       value_64bit );
389
    }
390
    else
391
    {
392
      libcnotify_printf(
393
       "%s: real-time bitmap summary inode number\t: %" PRIu64 "\n",
394
       function,
395
       value_64bit );
396
    }
397
    byte_stream_copy_to_uint32_big_endian(
398
     ( (fsxfs_superblock_t *) data )->realtime_extents_size,
399
     value_32bit );
400
    libcnotify_printf(
401
     "%s: real-time extents size\t\t\t: %" PRIu32 " blocks\n",
402
     function,
403
     value_32bit );
404
405
    libcnotify_printf(
406
     "%s: allocation group size\t\t\t: %" PRIu32 " blocks\n",
407
     function,
408
     superblock->allocation_group_size );
409
410
    libcnotify_printf(
411
     "%s: number of allocation groups\t\t: %" PRIu32 "\n",
412
     function,
413
     superblock->number_of_allocation_groups );
414
415
    byte_stream_copy_to_uint32_big_endian(
416
     ( (fsxfs_superblock_t *) data )->realtime_bitmap_size,
417
     value_32bit );
418
    libcnotify_printf(
419
     "%s: real-time bitmap size\t\t\t: %" PRIu32 " blocks\n",
420
     function,
421
     value_32bit );
422
423
    byte_stream_copy_to_uint32_big_endian(
424
     ( (fsxfs_superblock_t *) data )->journal_size,
425
     value_32bit );
426
    libcnotify_printf(
427
     "%s: journal size\t\t\t\t: %" PRIu32 " blocks\n",
428
     function,
429
     value_32bit );
430
431
    libcnotify_printf(
432
     "%s: version and feature flags\t\t: 0x%04" PRIx16 " (version: %" PRIu8 ", feature flags: 0x%04" PRIx16 ")\n",
433
     function,
434
     version_and_feature_flags,
435
     superblock->format_version,
436
     superblock->feature_flags );
437
    libfsxfs_debug_print_feature_flags(
438
     superblock->feature_flags );
439
    libcnotify_printf(
440
     "\n" );
441
442
    libcnotify_printf(
443
     "%s: sector size\t\t\t\t: %" PRIu16 "\n",
444
     function,
445
     superblock->sector_size );
446
447
    libcnotify_printf(
448
     "%s: inode size\t\t\t\t: %" PRIu16 "\n",
449
     function,
450
     superblock->inode_size );
451
452
    libcnotify_printf(
453
     "%s: number of inodes per block\t\t: %" PRIu16 "\n",
454
     function,
455
     number_of_inodes_per_block );
456
457
/* TODO print as string */
458
    libcnotify_printf(
459
     "%s: volume label:\n",
460
     function );
461
    libcnotify_print_data(
462
     superblock->volume_label,
463
     12,
464
     0 );
465
466
    libcnotify_printf(
467
     "%s: block size (log2)\t\t\t: %" PRIu8 " (%" PRIu64 ")\n",
468
     function,
469
     ( (fsxfs_superblock_t *) data )->block_size_log2,
470
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->block_size_log2 );
471
472
    libcnotify_printf(
473
     "%s: sector size (log2)\t\t\t: %" PRIu8 " (%" PRIu64 ")\n",
474
     function,
475
     ( (fsxfs_superblock_t *) data )->sector_size_log2,
476
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->sector_size_log2 );
477
478
    libcnotify_printf(
479
     "%s: inode size (log2)\t\t\t: %" PRIu8 " (%" PRIu64 ")\n",
480
     function,
481
     ( (fsxfs_superblock_t *) data )->inode_size_log2,
482
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->inode_size_log2 );
483
484
    libcnotify_printf(
485
     "%s: number of inodes per block (log2)\t: %" PRIu8 " (%" PRIu64 ")\n",
486
     function,
487
     ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2,
488
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2 );
489
490
    libcnotify_printf(
491
     "%s: allocation group size (log2)\t\t: %" PRIu8 " (%" PRIu64 ")\n",
492
     function,
493
     ( (fsxfs_superblock_t *) data )->allocation_group_size_log2,
494
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->allocation_group_size_log2 );
495
496
    libcnotify_printf(
497
     "%s: number of real-time extents (log2)\t: %" PRIu8 " (%" PRIu64 ")\n",
498
     function,
499
     ( (fsxfs_superblock_t *) data )->number_of_realtime_extents_log2,
500
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->number_of_realtime_extents_log2 );
501
502
    libcnotify_printf(
503
     "%s: creation flag\t\t\t\t: %" PRIu8 "\n",
504
     function,
505
     ( (fsxfs_superblock_t *) data )->creation_flag );
506
507
    libcnotify_printf(
508
     "%s: inodes percentage\t\t\t: %" PRIu8 " %%\n",
509
     function,
510
     ( (fsxfs_superblock_t *) data )->inodes_percentage );
511
512
    byte_stream_copy_to_uint64_big_endian(
513
     ( (fsxfs_superblock_t *) data )->number_of_inodes,
514
     value_64bit );
515
    libcnotify_printf(
516
     "%s: number of inodes\t\t\t\t: %" PRIu64 "\n",
517
     function,
518
     value_64bit );
519
520
    byte_stream_copy_to_uint64_big_endian(
521
     ( (fsxfs_superblock_t *) data )->number_of_free_inodes,
522
     value_64bit );
523
    libcnotify_printf(
524
     "%s: number of free inodes\t\t\t: %" PRIu64 "\n",
525
     function,
526
     value_64bit );
527
528
    byte_stream_copy_to_uint64_big_endian(
529
     ( (fsxfs_superblock_t *) data )->number_of_free_data_blocks,
530
     value_64bit );
531
    libcnotify_printf(
532
     "%s: number of free data blocks\t\t: %" PRIu64 "\n",
533
     function,
534
     value_64bit );
535
536
    byte_stream_copy_to_uint64_big_endian(
537
     ( (fsxfs_superblock_t *) data )->number_of_free_realtime_extents,
538
     value_64bit );
539
    libcnotify_printf(
540
     "%s: number of free real-time extents\t\t: %" PRIu64 "\n",
541
     function,
542
     value_64bit );
543
544
    byte_stream_copy_to_uint64_big_endian(
545
     ( (fsxfs_superblock_t *) data )->user_quota_inode_number,
546
     value_64bit );
547
    libcnotify_printf(
548
     "%s: user quota extents inode number\t\t: %" PRIu64 "\n",
549
     function,
550
     value_64bit );
551
552
    byte_stream_copy_to_uint64_big_endian(
553
     ( (fsxfs_superblock_t *) data )->group_quota_inode_number,
554
     value_64bit );
555
    libcnotify_printf(
556
     "%s: group quota extents inode number\t\t: %" PRIu64 "\n",
557
     function,
558
     value_64bit );
559
560
    byte_stream_copy_to_uint16_big_endian(
561
     ( (fsxfs_superblock_t *) data )->quota_flags,
562
     value_16bit );
563
    libcnotify_printf(
564
     "%s: quota flags\t\t\t\t: 0x%04" PRIx16 "\n",
565
     function,
566
     value_16bit );
567
568
    libcnotify_printf(
569
     "%s: miscellaneous flags\t\t\t: 0x%02" PRIx8 "\n",
570
     function,
571
     ( (fsxfs_superblock_t *) data )->miscellaneous_flags );
572
573
    libcnotify_printf(
574
     "%s: unknown1\t\t\t\t\t: 0x%02" PRIx8 "\n",
575
     function,
576
     ( (fsxfs_superblock_t *) data )->unknown1 );
577
578
    byte_stream_copy_to_uint32_big_endian(
579
     ( (fsxfs_superblock_t *) data )->inode_chunk_alignment_size,
580
     value_32bit );
581
    libcnotify_printf(
582
     "%s: inode chunk alignment size\t\t: %" PRIu32 " blocks\n",
583
     function,
584
     value_32bit );
585
586
    byte_stream_copy_to_uint32_big_endian(
587
     ( (fsxfs_superblock_t *) data )->raid_unit_size,
588
     value_32bit );
589
    libcnotify_printf(
590
     "%s: RAID unit size\t\t\t\t: %" PRIu32 " blocks\n",
591
     function,
592
     value_32bit );
593
594
    byte_stream_copy_to_uint32_big_endian(
595
     ( (fsxfs_superblock_t *) data )->raid_width,
596
     value_32bit );
597
    libcnotify_printf(
598
     "%s: RAID width\t\t\t\t: %" PRIu32 " blocks\n",
599
     function,
600
     value_32bit );
601
602
    libcnotify_printf(
603
     "%s: directory block size (log2)\t\t: %" PRIu8 " (%" PRIu64 ")\n",
604
     function,
605
     ( (fsxfs_superblock_t *) data )->directory_block_size_log2,
606
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->directory_block_size_log2 );
607
608
    libcnotify_printf(
609
     "%s: journal device sector size (log2)\t: %" PRIu8 " (%" PRIu64 ")\n",
610
     function,
611
     ( (fsxfs_superblock_t *) data )->journal_device_sector_size_log2,
612
     (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->journal_device_sector_size_log2 );
613
614
    byte_stream_copy_to_uint16_big_endian(
615
     ( (fsxfs_superblock_t *) data )->journal_device_sector_size,
616
     value_16bit );
617
    libcnotify_printf(
618
     "%s: journal device sector size\t\t: %" PRIu16 "\n",
619
     function,
620
     value_16bit );
621
622
    byte_stream_copy_to_uint32_big_endian(
623
     ( (fsxfs_superblock_t *) data )->journal_device_raid_unit_size,
624
     value_32bit );
625
    libcnotify_printf(
626
     "%s: journal device RAID unit size\t\t: %" PRIu32 "\n",
627
     function,
628
     value_32bit );
629
630
    libcnotify_printf(
631
     "%s: secondary feature flags\t\t\t: 0x%08" PRIx32 "\n",
632
     function,
633
     superblock->secondary_feature_flags );
634
    libfsxfs_debug_print_secondary_feature_flags(
635
     superblock->secondary_feature_flags );
636
    libcnotify_printf(
637
     "\n" );
638
639
    byte_stream_copy_to_uint32_big_endian(
640
     ( (fsxfs_superblock_t *) data )->secondary_feature_flags_copy,
641
     value_32bit );
642
    libcnotify_printf(
643
     "%s: secondary feature flags (copy)\t\t: 0x%08" PRIx32 "\n",
644
     function,
645
     value_32bit );
646
    libfsxfs_debug_print_secondary_feature_flags(
647
     value_32bit );
648
    libcnotify_printf(
649
     "\n" );
650
  }
651
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
652
653
9.23k
  switch( superblock->format_version )
654
9.23k
  {
655
21
    case 1:
656
21
      supported_feature_flags = 0;
657
21
      break;
658
659
24
    case 2:
660
24
      supported_feature_flags = 0x0010;
661
24
      break;
662
663
17
    case 3:
664
17
      supported_feature_flags = 0x0010
665
17
                              | 0x0020;
666
17
      break;
667
668
7.94k
    case 4:
669
9.16k
    case 5:
670
9.16k
      supported_feature_flags = 0x0010
671
9.16k
                              | 0x0020
672
9.16k
                              | 0x0080
673
9.16k
                              | 0x0100
674
9.16k
                              | 0x0400
675
9.16k
                              | 0x0800
676
9.16k
                              | 0x1000
677
9.16k
                              | 0x2000
678
9.16k
                              | 0x4000
679
9.16k
                              | 0x8000;
680
9.16k
      break;
681
682
13
    default:
683
13
      libcerror_error_set(
684
13
       error,
685
13
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
686
13
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
687
13
       "%s: unsupported format version: %" PRIu8 ".",
688
13
       function,
689
13
       superblock->format_version );
690
691
13
      return( -1 );
692
9.23k
  }
693
9.22k
  if( ( (uint32_t) superblock->feature_flags & ~( supported_feature_flags ) ) != 0 )
694
38
  {
695
38
    libcerror_error_set(
696
38
     error,
697
38
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
698
38
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
699
38
     "%s: unsupported features flags: 0x%04" PRIx16 ".",
700
38
     function,
701
38
     superblock->feature_flags );
702
703
38
    return( -1 );
704
38
  }
705
/* TODO check if block size a multitude of 2 */
706
9.18k
  if( ( superblock->block_size < 512 )
707
9.17k
   || ( superblock->block_size > 65536 ) )
708
91
  {
709
91
    libcerror_error_set(
710
91
     error,
711
91
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
712
91
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
713
91
     "%s: unsupported block size: %" PRIu32 ".",
714
91
     function,
715
91
     superblock->block_size );
716
717
91
    return( -1 );
718
91
  }
719
9.09k
  if( ( superblock->sector_size != 512 )
720
3.48k
   && ( superblock->sector_size != 1024 )
721
3.14k
   && ( superblock->sector_size != 2048 )
722
2.82k
   && ( superblock->sector_size != 4096 )
723
2.05k
   && ( superblock->sector_size != 8192 )
724
278
   && ( superblock->sector_size != 16384 ) )
725
226
  {
726
226
    libcerror_error_set(
727
226
     error,
728
226
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
729
226
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
730
226
     "%s: unsupported sector size: %" PRIu16 ".",
731
226
     function,
732
226
     superblock->sector_size );
733
734
226
    return( -1 );
735
226
  }
736
/* TODO check if inode size a multitude of 2 */
737
8.86k
  if( ( superblock->inode_size < 256 )
738
8.86k
   || ( superblock->inode_size > 2048 ) )
739
26
  {
740
26
    libcerror_error_set(
741
26
     error,
742
26
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
743
26
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
744
26
     "%s: unsupported inode size: %" PRIu16 ".",
745
26
     function,
746
26
     superblock->inode_size );
747
748
26
    return( -1 );
749
26
  }
750
8.84k
  if( ( (fsxfs_superblock_t *) data )->directory_block_size_log2 == 0 )
751
5.86k
  {
752
5.86k
    superblock->directory_block_size = superblock->block_size;
753
5.86k
  }
754
2.97k
  else
755
2.97k
  {
756
2.97k
    if( ( (fsxfs_superblock_t *) data )->directory_block_size_log2 >= 32 )
757
30
    {
758
30
      libcerror_error_set(
759
30
       error,
760
30
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
761
30
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
762
30
       "%s: invalid directory block size log2 value out of bounds.",
763
30
       function );
764
765
30
      return( -1 );
766
30
    }
767
2.94k
    superblock->directory_block_size = (uint32_t) 1 << ( (fsxfs_superblock_t *) data )->directory_block_size_log2;
768
769
2.94k
    if( (size_t) superblock->directory_block_size > (size_t) ( UINT32_MAX / superblock->block_size ) )
770
14
    {
771
14
      libcerror_error_set(
772
14
       error,
773
14
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
774
14
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
775
14
       "%s: invalid directory block size log2 value out of bounds.",
776
14
       function );
777
778
14
      return( -1 );
779
14
    }
780
2.93k
    superblock->directory_block_size *= superblock->block_size;
781
2.93k
  }
782
8.79k
  if( ( superblock->allocation_group_size < 5 )
783
8.78k
   || ( superblock->allocation_group_size > (uint32_t) INT32_MAX ) )
784
102
  {
785
102
    libcerror_error_set(
786
102
     error,
787
102
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
788
102
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
789
102
     "%s: invalid allocation group size value out of bounds.",
790
102
     function );
791
792
102
    return( -1 );
793
102
  }
794
8.69k
  if( ( ( (fsxfs_superblock_t *) data )->allocation_group_size_log2 == 0 )
795
8.69k
   || ( ( (fsxfs_superblock_t *) data )->allocation_group_size_log2 > 31 ) )
796
25
  {
797
25
    libcerror_error_set(
798
25
     error,
799
25
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
800
25
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
801
25
     "%s: invalid allocation group size log2 value out of bounds.",
802
25
     function );
803
804
25
    return( -1 );
805
25
  }
806
8.67k
  superblock->number_of_relative_block_number_bits = (uint8_t) ( (fsxfs_superblock_t *) data )->allocation_group_size_log2;
807
808
8.67k
  if( ( ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2 == 0 )
809
8.66k
   || ( ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2 > ( 32 - superblock->number_of_relative_block_number_bits ) ) )
810
26
  {
811
26
    libcerror_error_set(
812
26
     error,
813
26
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
814
26
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
815
26
     "%s: invalid number of inodes per block log2 value out of bounds.",
816
26
     function );
817
818
26
    return( -1 );
819
26
  }
820
8.64k
  superblock->number_of_relative_inode_number_bits = superblock->number_of_relative_block_number_bits + (uint8_t) ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2;
821
822
8.64k
  if( ( superblock->number_of_relative_inode_number_bits == 0 )
823
8.64k
   || ( superblock->number_of_relative_inode_number_bits >= 32 ) )
824
5
  {
825
5
    libcerror_error_set(
826
5
     error,
827
5
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
828
5
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
829
5
     "%s: invalid number of relative inode number bits value out of bounds.",
830
5
     function );
831
832
5
    return( -1 );
833
5
  }
834
8.64k
  if( ( ( (uint64_t) 1UL << ( (fsxfs_superblock_t *) data )->number_of_inodes_per_block_log2 ) != (uint64_t) number_of_inodes_per_block ) )
835
99
  {
836
99
    libcerror_error_set(
837
99
     error,
838
99
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
839
99
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
840
99
     "%s: mismatch between number of inodes per block and log2 values.",
841
99
     function );
842
843
99
    return( -1 );
844
99
  }
845
8.54k
  if( superblock->format_version == 5 )
846
942
  {
847
942
    if( data_size < sizeof( fsxfs_superblock_v5_t ) )
848
0
    {
849
0
      libcerror_error_set(
850
0
       error,
851
0
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
852
0
       LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
853
0
       "%s: invalid data size value out of bounds.",
854
0
       function );
855
856
0
      return( -1 );
857
0
    }
858
942
    byte_stream_copy_to_uint32_big_endian(
859
942
     ( (fsxfs_superblock_v5_t *) data )->compatible_features_flags,
860
942
     superblock->compatible_features_flags );
861
862
942
    byte_stream_copy_to_uint32_big_endian(
863
942
     ( (fsxfs_superblock_v5_t *) data )->read_only_compatible_features_flags,
864
942
     superblock->read_only_compatible_features_flags );
865
866
942
    byte_stream_copy_to_uint32_big_endian(
867
942
     ( (fsxfs_superblock_v5_t *) data )->incompatible_features_flags,
868
942
     superblock->incompatible_features_flags );
869
870
942
    byte_stream_copy_to_uint32_big_endian(
871
942
     ( (fsxfs_superblock_v5_t *) data )->journal_incompatible_features_flags,
872
942
     superblock->journal_incompatible_features_flags );
873
874
/* TODO read version 5 additional values */
875
876
#if defined( HAVE_DEBUG_OUTPUT )
877
    if( libcnotify_verbose != 0 )
878
    {
879
      libcnotify_printf(
880
       "%s: compatible features flags\t\t: 0x%08" PRIx32 "\n",
881
       function,
882
       superblock->compatible_features_flags );
883
884
      libcnotify_printf(
885
       "%s: read-only compatible features flags\t: 0x%08" PRIx32 "\n",
886
       function,
887
       superblock->read_only_compatible_features_flags );
888
      libfsxfs_debug_print_read_only_compatible_features_flags(
889
       superblock->read_only_compatible_features_flags );
890
      libcnotify_printf(
891
       "\n" );
892
893
      libcnotify_printf(
894
       "%s: incompatible features flags\t\t: 0x%08" PRIx32 "\n",
895
       function,
896
       superblock->incompatible_features_flags );
897
      libfsxfs_debug_print_incompatible_features_flags(
898
       superblock->incompatible_features_flags );
899
      libcnotify_printf(
900
       "\n" );
901
902
      libcnotify_printf(
903
       "%s: journal incompatible features flags\t: 0x%08" PRIx32 "\n",
904
       function,
905
       superblock->journal_incompatible_features_flags );
906
907
      libcnotify_printf(
908
       "\n" );
909
    }
910
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
911
912
942
    supported_feature_flags = 0x00000001UL
913
942
                            | 0x00000002UL
914
942
                            | 0x00000008UL
915
942
                            | 0x00000020UL;
916
917
942
    if( ( superblock->incompatible_features_flags & ~( supported_feature_flags ) ) != 0 )
918
170
    {
919
170
      libcerror_error_set(
920
170
       error,
921
170
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
922
170
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
923
170
       "%s: unsupported incompatible features flags: 0x%08" PRIx32 ".",
924
170
       function,
925
170
       superblock->incompatible_features_flags );
926
927
170
      return( -1 );
928
170
    }
929
772
    supported_feature_flags = 0x00000000UL;
930
931
772
    if( ( superblock->journal_incompatible_features_flags & ~( supported_feature_flags ) ) != 0 )
932
148
    {
933
148
      libcerror_error_set(
934
148
       error,
935
148
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
936
148
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
937
148
       "%s: unsupported journal incompatible features flags: 0x%08" PRIx32 ".",
938
148
       function,
939
148
       superblock->journal_incompatible_features_flags );
940
941
148
      return( -1 );
942
148
    }
943
772
  }
944
#if defined( HAVE_DEBUG_OUTPUT )
945
  if( libcnotify_verbose != 0 )
946
  {
947
    libcnotify_printf(
948
     "%s: directory block size\t\t\t: %" PRIu32 "\n",
949
     function,
950
     superblock->directory_block_size );
951
952
    libcnotify_printf(
953
     "%s: number of relative block number bits\t: %" PRIu8 "\n",
954
     function,
955
     superblock->number_of_relative_block_number_bits );
956
957
    libcnotify_printf(
958
     "%s: number of relative inode number bits\t: %" PRIu8 "\n",
959
     function,
960
     superblock->number_of_relative_inode_number_bits );
961
962
    libcnotify_printf(
963
     "\n" );
964
  }
965
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
966
967
8.22k
  return( 1 );
968
8.54k
}
969
970
/* Reads the superblock from a Basic File IO (bfio) handle
971
 * Returns 1 if successful or -1 on error
972
 */
973
int libfsxfs_superblock_read_file_io_handle(
974
     libfsxfs_superblock_t *superblock,
975
     libbfio_handle_t *file_io_handle,
976
     off64_t file_offset,
977
     libcerror_error_t **error )
978
9.85k
{
979
9.85k
  uint8_t data[ 512 ];
980
981
9.85k
  static char *function = "libfsxfs_superblock_read_file_io_handle";
982
9.85k
  ssize_t read_count    = 0;
983
984
#if defined( HAVE_DEBUG_OUTPUT )
985
  if( libcnotify_verbose != 0 )
986
  {
987
    libcnotify_printf(
988
     "%s: reading superblock at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
989
     function,
990
     file_offset,
991
     file_offset );
992
  }
993
#endif
994
9.85k
  read_count = libbfio_handle_read_buffer_at_offset(
995
9.85k
                file_io_handle,
996
9.85k
                data,
997
9.85k
                512,
998
9.85k
                file_offset,
999
9.85k
                error );
1000
1001
9.85k
  if( read_count != (ssize_t) 512 )
1002
490
  {
1003
490
    libcerror_error_set(
1004
490
     error,
1005
490
     LIBCERROR_ERROR_DOMAIN_IO,
1006
490
     LIBCERROR_IO_ERROR_READ_FAILED,
1007
490
     "%s: unable to read superblock at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1008
490
     function,
1009
490
     file_offset,
1010
490
     file_offset );
1011
1012
490
    return( -1 );
1013
490
  }
1014
9.36k
  if( libfsxfs_superblock_read_data(
1015
9.36k
       superblock,
1016
9.36k
       data,
1017
9.36k
       512,
1018
9.36k
       error ) != 1 )
1019
1.14k
  {
1020
1.14k
    libcerror_error_set(
1021
1.14k
     error,
1022
1.14k
     LIBCERROR_ERROR_DOMAIN_IO,
1023
1.14k
     LIBCERROR_IO_ERROR_READ_FAILED,
1024
1.14k
     "%s: unable to read superblock at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1025
1.14k
     function,
1026
1.14k
     file_offset,
1027
1.14k
     file_offset );
1028
1029
1.14k
    return( -1 );
1030
1.14k
  }
1031
8.22k
  return( 1 );
1032
9.36k
}
1033
1034
/* Retrieves the size of the UTF-8 encoded volume label
1035
 * The returned size includes the end of string character
1036
 * Returns 1 if successful, 0 if not available or -1 on error
1037
 */
1038
int libfsxfs_superblock_get_utf8_volume_label_size(
1039
     libfsxfs_superblock_t *superblock,
1040
     size_t *utf8_string_size,
1041
     libcerror_error_t **error )
1042
161
{
1043
161
  static char *function = "libfsxfs_superblock_get_utf8_volume_label_size";
1044
1045
161
  if( superblock == NULL )
1046
0
  {
1047
0
    libcerror_error_set(
1048
0
     error,
1049
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1050
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1051
0
     "%s: invalid superblock.",
1052
0
     function );
1053
1054
0
    return( -1 );
1055
0
  }
1056
161
  if( libuna_utf8_string_size_from_utf8_stream(
1057
161
       superblock->volume_label,
1058
161
       12,
1059
161
       utf8_string_size,
1060
161
       error ) != 1 )
1061
101
  {
1062
101
    libcerror_error_set(
1063
101
     error,
1064
101
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1065
101
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1066
101
     "%s: unable to retrieve UTF-8 string size.",
1067
101
     function );
1068
1069
101
    return( -1 );
1070
101
  }
1071
60
  return( 1 );
1072
161
}
1073
1074
/* Retrieves the UTF-8 encoded volume label
1075
 * The size should include the end of string character
1076
 * Returns 1 if successful, 0 if not available or -1 on error
1077
 */
1078
int libfsxfs_superblock_get_utf8_volume_label(
1079
     libfsxfs_superblock_t *superblock,
1080
     uint8_t *utf8_string,
1081
     size_t utf8_string_size,
1082
     libcerror_error_t **error )
1083
161
{
1084
161
  static char *function = "libfsxfs_superblock_get_utf8_volume_label";
1085
1086
161
  if( superblock == NULL )
1087
0
  {
1088
0
    libcerror_error_set(
1089
0
     error,
1090
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1091
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1092
0
     "%s: invalid superblock.",
1093
0
     function );
1094
1095
0
    return( -1 );
1096
0
  }
1097
161
  if( libuna_utf8_string_copy_from_utf8_stream(
1098
161
       utf8_string,
1099
161
       utf8_string_size,
1100
161
       superblock->volume_label,
1101
161
       12,
1102
161
       error ) != 1 )
1103
101
  {
1104
101
    libcerror_error_set(
1105
101
     error,
1106
101
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1107
101
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1108
101
     "%s: unable to retrieve UTF-8 string.",
1109
101
     function );
1110
1111
101
    return( -1 );
1112
101
  }
1113
60
  return( 1 );
1114
161
}
1115
1116
/* Retrieves the size of the UTF-16 encoded volume label
1117
 * The returned size includes the end of string character
1118
 * Returns 1 if successful, 0 if not available or -1 on error
1119
 */
1120
int libfsxfs_superblock_get_utf16_volume_label_size(
1121
     libfsxfs_superblock_t *superblock,
1122
     size_t *utf16_string_size,
1123
     libcerror_error_t **error )
1124
0
{
1125
0
  static char *function = "libfsxfs_superblock_get_utf16_volume_label_size";
1126
1127
0
  if( superblock == NULL )
1128
0
  {
1129
0
    libcerror_error_set(
1130
0
     error,
1131
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1132
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1133
0
     "%s: invalid superblock.",
1134
0
     function );
1135
1136
0
    return( -1 );
1137
0
  }
1138
0
  if( libuna_utf16_string_size_from_utf8_stream(
1139
0
       superblock->volume_label,
1140
0
       12,
1141
0
       utf16_string_size,
1142
0
       error ) != 1 )
1143
0
  {
1144
0
    libcerror_error_set(
1145
0
     error,
1146
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1147
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1148
0
     "%s: unable to retrieve UTF-16 string size.",
1149
0
     function );
1150
1151
0
    return( -1 );
1152
0
  }
1153
0
  return( 1 );
1154
0
}
1155
1156
/* Retrieves the UTF-16 encoded volume label
1157
 * The size should include the end of string character
1158
 * Returns 1 if successful, 0 if not available or -1 on error
1159
 */
1160
int libfsxfs_superblock_get_utf16_volume_label(
1161
     libfsxfs_superblock_t *superblock,
1162
     uint16_t *utf16_string,
1163
     size_t utf16_string_size,
1164
     libcerror_error_t **error )
1165
0
{
1166
0
  static char *function = "libfsxfs_superblock_get_utf16_volume_label";
1167
1168
0
  if( superblock == NULL )
1169
0
  {
1170
0
    libcerror_error_set(
1171
0
     error,
1172
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1173
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1174
0
     "%s: invalid superblock.",
1175
0
     function );
1176
1177
0
    return( -1 );
1178
0
  }
1179
0
  if( libuna_utf16_string_copy_from_utf8_stream(
1180
0
       utf16_string,
1181
0
       utf16_string_size,
1182
0
       superblock->volume_label,
1183
0
       12,
1184
0
       error ) != 1 )
1185
0
  {
1186
0
    libcerror_error_set(
1187
0
     error,
1188
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1189
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1190
0
     "%s: unable to retrieve UTF-16 string.",
1191
0
     function );
1192
1193
0
    return( -1 );
1194
0
  }
1195
0
  return( 1 );
1196
0
}
1197