Coverage Report

Created: 2024-02-25 07:19

/src/libvsmbr/libvsmbr/libvsmbr_volume.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The volume functions
3
 *
4
 * Copyright (C) 2010-2023, 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 <memory.h>
24
#include <narrow_string.h>
25
#include <types.h>
26
#include <wide_string.h>
27
28
#include "libvsmbr_boot_record.h"
29
#include "libvsmbr_debug.h"
30
#include "libvsmbr_definitions.h"
31
#include "libvsmbr_volume.h"
32
#include "libvsmbr_io_handle.h"
33
#include "libvsmbr_libbfio.h"
34
#include "libvsmbr_libcerror.h"
35
#include "libvsmbr_libcnotify.h"
36
#include "libvsmbr_partition.h"
37
#include "libvsmbr_partition_entry.h"
38
#include "libvsmbr_partition_values.h"
39
#include "libvsmbr_section_values.h"
40
#include "libvsmbr_types.h"
41
42
/* Creates a volume
43
 * Make sure the value volume is referencing, is set to NULL
44
 * Returns 1 if successful or -1 on error
45
 */
46
int libvsmbr_volume_initialize(
47
     libvsmbr_volume_t **volume,
48
     libcerror_error_t **error )
49
271
{
50
271
  libvsmbr_internal_volume_t *internal_volume = NULL;
51
271
  static char *function                       = "libvsmbr_volume_initialize";
52
53
271
  if( volume == 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 volume.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
271
  if( *volume != 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 volume value already set.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
271
  internal_volume = memory_allocate_structure(
76
271
                     libvsmbr_internal_volume_t );
77
78
271
  if( internal_volume == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
83
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84
0
     "%s: unable to create volume.",
85
0
     function );
86
87
0
    goto on_error;
88
0
  }
89
271
  if( memory_set(
90
271
       internal_volume,
91
271
       0,
92
271
       sizeof( libvsmbr_internal_volume_t ) ) == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
97
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
98
0
     "%s: unable to clear volume.",
99
0
     function );
100
101
0
    memory_free(
102
0
     internal_volume );
103
104
0
    return( -1 );
105
0
  }
106
271
  if( libvsmbr_io_handle_initialize(
107
271
       &( internal_volume->io_handle ),
108
271
       error ) != 1 )
109
0
  {
110
0
    libcerror_error_set(
111
0
     error,
112
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
113
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
114
0
     "%s: unable to create IO handle.",
115
0
     function );
116
117
0
    goto on_error;
118
0
  }
119
271
  if( libcdata_array_initialize(
120
271
       &( internal_volume->partitions ),
121
271
       0,
122
271
       error ) != 1 )
123
0
  {
124
0
    libcerror_error_set(
125
0
     error,
126
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
127
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
128
0
     "%s: unable to create partitions array.",
129
0
     function );
130
131
0
    goto on_error;
132
0
  }
133
271
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
134
271
  if( libcthreads_read_write_lock_initialize(
135
271
       &( internal_volume->read_write_lock ),
136
271
       error ) != 1 )
137
0
  {
138
0
    libcerror_error_set(
139
0
     error,
140
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
141
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
142
0
     "%s: unable to initialize read/write lock.",
143
0
     function );
144
145
0
    goto on_error;
146
0
  }
147
271
#endif
148
271
  *volume = (libvsmbr_volume_t *) internal_volume;
149
150
271
  return( 1 );
151
152
0
on_error:
153
0
  if( internal_volume != NULL )
154
0
  {
155
0
    if( internal_volume->io_handle != NULL )
156
0
    {
157
0
      libvsmbr_io_handle_free(
158
0
       &( internal_volume->io_handle ),
159
0
       NULL );
160
0
    }
161
0
    memory_free(
162
0
     internal_volume );
163
0
  }
164
0
  return( -1 );
165
271
}
166
167
/* Frees a volume
168
 * Returns 1 if successful or -1 on error
169
 */
170
int libvsmbr_volume_free(
171
     libvsmbr_volume_t **volume,
172
     libcerror_error_t **error )
173
271
{
174
271
  libvsmbr_internal_volume_t *internal_volume = NULL;
175
271
  static char *function                       = "libvsmbr_volume_free";
176
271
  int result                                  = 1;
177
178
271
  if( volume == NULL )
179
0
  {
180
0
    libcerror_error_set(
181
0
     error,
182
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
183
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
184
0
     "%s: invalid volume.",
185
0
     function );
186
187
0
    return( -1 );
188
0
  }
189
271
  if( *volume != NULL )
190
271
  {
191
271
    internal_volume = (libvsmbr_internal_volume_t *) *volume;
192
193
271
    if( internal_volume->file_io_handle != NULL )
194
0
    {
195
0
      if( libvsmbr_volume_close(
196
0
           *volume,
197
0
           error ) != 0 )
198
0
      {
199
0
        libcerror_error_set(
200
0
         error,
201
0
         LIBCERROR_ERROR_DOMAIN_IO,
202
0
         LIBCERROR_IO_ERROR_CLOSE_FAILED,
203
0
         "%s: unable to close volume.",
204
0
         function );
205
206
0
        result = -1;
207
0
      }
208
0
    }
209
271
    *volume = NULL;
210
211
271
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
212
271
    if( libcthreads_read_write_lock_free(
213
271
         &( internal_volume->read_write_lock ),
214
271
         error ) != 1 )
215
0
    {
216
0
      libcerror_error_set(
217
0
       error,
218
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
219
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
220
0
       "%s: unable to free read/write lock.",
221
0
       function );
222
223
0
      result = -1;
224
0
    }
225
271
#endif
226
271
    if( libcdata_array_free(
227
271
         &( internal_volume->partitions ),
228
271
         (int (*)(intptr_t **, libcerror_error_t **)) &libvsmbr_partition_values_free,
229
271
         error ) != 1 )
230
0
    {
231
0
      libcerror_error_set(
232
0
       error,
233
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
234
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
235
0
       "%s: unable to free the partitions array.",
236
0
       function );
237
238
0
      result = -1;
239
0
    }
240
271
    if( libvsmbr_io_handle_free(
241
271
         &( internal_volume->io_handle ),
242
271
         error ) != 1 )
243
0
    {
244
0
      libcerror_error_set(
245
0
       error,
246
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
247
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
248
0
       "%s: unable to free IO handle.",
249
0
       function );
250
251
0
      result = -1;
252
0
    }
253
271
    memory_free(
254
271
     internal_volume );
255
271
  }
256
271
  return( result );
257
271
}
258
259
/* Signals the volume to abort its current activity
260
 * Returns 1 if successful or -1 on error
261
 */
262
int libvsmbr_volume_signal_abort(
263
     libvsmbr_volume_t *volume,
264
     libcerror_error_t **error )
265
0
{
266
0
  libvsmbr_internal_volume_t *internal_volume = NULL;
267
0
  static char *function                       = "libvsmbr_volume_signal_abort";
268
269
0
  if( volume == NULL )
270
0
  {
271
0
    libcerror_error_set(
272
0
     error,
273
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
274
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
275
0
     "%s: invalid volume.",
276
0
     function );
277
278
0
    return( -1 );
279
0
  }
280
0
  internal_volume = (libvsmbr_internal_volume_t *) volume;
281
282
0
  if( internal_volume->io_handle == NULL )
283
0
  {
284
0
    libcerror_error_set(
285
0
     error,
286
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
287
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
288
0
     "%s: invalid volume - missing IO handle.",
289
0
     function );
290
291
0
    return( -1 );
292
0
  }
293
0
  internal_volume->io_handle->abort = 1;
294
295
0
  return( 1 );
296
0
}
297
298
/* Opens a volume
299
 * Returns 1 if successful or -1 on error
300
 */
301
int libvsmbr_volume_open(
302
     libvsmbr_volume_t *volume,
303
     const char *filename,
304
     int access_flags,
305
     libcerror_error_t **error )
306
0
{
307
0
  libbfio_handle_t *file_io_handle            = NULL;
308
0
  libvsmbr_internal_volume_t *internal_volume = NULL;
309
0
  static char *function                       = "libvsmbr_volume_open";
310
0
  size_t filename_length                      = 0;
311
312
0
  if( volume == NULL )
313
0
  {
314
0
    libcerror_error_set(
315
0
     error,
316
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
317
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
318
0
     "%s: invalid volume.",
319
0
     function );
320
321
0
    return( -1 );
322
0
  }
323
0
  internal_volume = (libvsmbr_internal_volume_t *) volume;
324
325
0
  if( filename == NULL )
326
0
  {
327
0
    libcerror_error_set(
328
0
     error,
329
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
330
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
331
0
     "%s: invalid filename.",
332
0
     function );
333
334
0
    return( -1 );
335
0
  }
336
0
  if( ( ( access_flags & LIBVSMBR_ACCESS_FLAG_READ ) == 0 )
337
0
   && ( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) == 0 ) )
338
0
  {
339
0
    libcerror_error_set(
340
0
     error,
341
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
342
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
343
0
     "%s: unsupported access flags.",
344
0
     function );
345
346
0
    return( -1 );
347
0
  }
348
0
  if( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) != 0 )
349
0
  {
350
0
    libcerror_error_set(
351
0
     error,
352
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
353
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
354
0
     "%s: write access currently not supported.",
355
0
     function );
356
357
0
    return( -1 );
358
0
  }
359
0
  if( libbfio_file_initialize(
360
0
       &file_io_handle,
361
0
       error ) != 1 )
362
0
  {
363
0
    libcerror_error_set(
364
0
     error,
365
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
366
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
367
0
     "%s: unable to create file IO handle.",
368
0
     function );
369
370
0
    goto on_error;
371
0
  }
372
#if defined( HAVE_DEBUG_OUTPUT )
373
  if( libbfio_handle_set_track_offsets_read(
374
       file_io_handle,
375
       1,
376
       error ) != 1 )
377
  {
378
    libcerror_error_set(
379
     error,
380
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
381
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
382
     "%s: unable to set track offsets read in file IO handle.",
383
     function );
384
385
    goto on_error;
386
  }
387
#endif
388
0
  filename_length = narrow_string_length(
389
0
                     filename );
390
391
0
  if( libbfio_file_set_name(
392
0
       file_io_handle,
393
0
       filename,
394
0
       filename_length + 1,
395
0
       error ) != 1 )
396
0
  {
397
0
    libcerror_error_set(
398
0
     error,
399
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
400
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
401
0
     "%s: unable to set filename in file IO handle.",
402
0
     function );
403
404
0
    goto on_error;
405
0
  }
406
0
  if( libvsmbr_volume_open_file_io_handle(
407
0
       volume,
408
0
       file_io_handle,
409
0
       access_flags,
410
0
       error ) != 1 )
411
0
  {
412
0
    libcerror_error_set(
413
0
     error,
414
0
     LIBCERROR_ERROR_DOMAIN_IO,
415
0
     LIBCERROR_IO_ERROR_OPEN_FAILED,
416
0
     "%s: unable to open volume: %s.",
417
0
     function,
418
0
     filename );
419
420
0
    goto on_error;
421
0
  }
422
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
423
0
  if( libcthreads_read_write_lock_grab_for_write(
424
0
       internal_volume->read_write_lock,
425
0
       error ) != 1 )
426
0
  {
427
0
    libcerror_error_set(
428
0
     error,
429
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
430
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
431
0
     "%s: unable to grab read/write lock for writing.",
432
0
     function );
433
434
0
    return( -1 );
435
0
  }
436
0
#endif
437
0
  internal_volume->file_io_handle_created_in_library = 1;
438
439
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
440
0
  if( libcthreads_read_write_lock_release_for_write(
441
0
       internal_volume->read_write_lock,
442
0
       error ) != 1 )
443
0
  {
444
0
    libcerror_error_set(
445
0
     error,
446
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
447
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
448
0
     "%s: unable to release read/write lock for writing.",
449
0
     function );
450
451
0
    return( -1 );
452
0
  }
453
0
#endif
454
0
  return( 1 );
455
456
0
on_error:
457
0
  if( file_io_handle != NULL )
458
0
  {
459
0
    libbfio_handle_free(
460
0
     &file_io_handle,
461
0
     NULL );
462
0
  }
463
0
  return( -1 );
464
0
}
465
466
#if defined( HAVE_WIDE_CHARACTER_TYPE )
467
468
/* Opens a volume
469
 * Returns 1 if successful or -1 on error
470
 */
471
int libvsmbr_volume_open_wide(
472
     libvsmbr_volume_t *volume,
473
     const wchar_t *filename,
474
     int access_flags,
475
     libcerror_error_t **error )
476
{
477
  libbfio_handle_t *file_io_handle            = NULL;
478
  libvsmbr_internal_volume_t *internal_volume = NULL;
479
  static char *function                       = "libvsmbr_volume_open_wide";
480
  size_t filename_length                      = 0;
481
482
  if( volume == NULL )
483
  {
484
    libcerror_error_set(
485
     error,
486
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
487
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
488
     "%s: invalid volume.",
489
     function );
490
491
    return( -1 );
492
  }
493
  internal_volume = (libvsmbr_internal_volume_t *) volume;
494
495
  if( filename == NULL )
496
  {
497
    libcerror_error_set(
498
     error,
499
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
500
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
501
     "%s: invalid filename.",
502
     function );
503
504
    return( -1 );
505
  }
506
  if( ( ( access_flags & LIBVSMBR_ACCESS_FLAG_READ ) == 0 )
507
   && ( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) == 0 ) )
508
  {
509
    libcerror_error_set(
510
     error,
511
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
512
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
513
     "%s: unsupported access flags.",
514
     function );
515
516
    return( -1 );
517
  }
518
  if( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) != 0 )
519
  {
520
    libcerror_error_set(
521
     error,
522
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
523
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
524
     "%s: write access currently not supported.",
525
     function );
526
527
    return( -1 );
528
  }
529
  if( libbfio_file_initialize(
530
       &file_io_handle,
531
       error ) != 1 )
532
  {
533
    libcerror_error_set(
534
     error,
535
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
536
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
537
     "%s: unable to create file IO handle.",
538
     function );
539
540
    goto on_error;
541
  }
542
#if defined( HAVE_DEBUG_OUTPUT )
543
  if( libbfio_handle_set_track_offsets_read(
544
       file_io_handle,
545
       1,
546
       error ) != 1 )
547
  {
548
    libcerror_error_set(
549
     error,
550
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
551
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
552
     "%s: unable to set track offsets read in file IO handle.",
553
     function );
554
555
    goto on_error;
556
  }
557
#endif
558
  filename_length = wide_string_length(
559
                     filename );
560
561
  if( libbfio_file_set_name_wide(
562
       file_io_handle,
563
       filename,
564
       filename_length + 1,
565
       error ) != 1 )
566
  {
567
    libcerror_error_set(
568
     error,
569
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
570
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
571
     "%s: unable to set filename in file IO handle.",
572
     function );
573
574
    goto on_error;
575
  }
576
  if( libvsmbr_volume_open_file_io_handle(
577
       volume,
578
       file_io_handle,
579
       access_flags,
580
       error ) != 1 )
581
  {
582
    libcerror_error_set(
583
     error,
584
     LIBCERROR_ERROR_DOMAIN_IO,
585
     LIBCERROR_IO_ERROR_OPEN_FAILED,
586
     "%s: unable to open volume: %ls.",
587
     function,
588
     filename );
589
590
    goto on_error;
591
  }
592
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
593
  if( libcthreads_read_write_lock_grab_for_write(
594
       internal_volume->read_write_lock,
595
       error ) != 1 )
596
  {
597
    libcerror_error_set(
598
     error,
599
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
600
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
601
     "%s: unable to grab read/write lock for writing.",
602
     function );
603
604
    return( -1 );
605
  }
606
#endif
607
  internal_volume->file_io_handle_created_in_library = 1;
608
609
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
610
  if( libcthreads_read_write_lock_release_for_write(
611
       internal_volume->read_write_lock,
612
       error ) != 1 )
613
  {
614
    libcerror_error_set(
615
     error,
616
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
617
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
618
     "%s: unable to release read/write lock for writing.",
619
     function );
620
621
    return( -1 );
622
  }
623
#endif
624
  return( 1 );
625
626
on_error:
627
  if( file_io_handle != NULL )
628
  {
629
    libbfio_handle_free(
630
     &file_io_handle,
631
     NULL );
632
  }
633
  return( -1 );
634
}
635
636
#endif /* defined( HAVE_WIDE_CHARACTER_TYPE ) */
637
638
/* Opens a volume using a Basic File IO (bfio) volume
639
 * Returns 1 if successful or -1 on error
640
 */
641
int libvsmbr_volume_open_file_io_handle(
642
     libvsmbr_volume_t *volume,
643
     libbfio_handle_t *file_io_handle,
644
     int access_flags,
645
     libcerror_error_t **error )
646
271
{
647
271
  libvsmbr_internal_volume_t *internal_volume = NULL;
648
271
  static char *function                       = "libvsmbr_volume_open_file_io_handle";
649
271
  uint8_t file_io_handle_opened_in_library    = 0;
650
271
  int bfio_access_flags                       = 0;
651
271
  int file_io_handle_is_open                  = 0;
652
653
271
  if( volume == NULL )
654
0
  {
655
0
    libcerror_error_set(
656
0
     error,
657
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
658
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
659
0
     "%s: invalid volume.",
660
0
     function );
661
662
0
    return( -1 );
663
0
  }
664
271
  internal_volume = (libvsmbr_internal_volume_t *) volume;
665
666
271
  if( internal_volume->file_io_handle != NULL )
667
0
  {
668
0
    libcerror_error_set(
669
0
     error,
670
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
671
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
672
0
     "%s: invalid volume - file IO handle value already set.",
673
0
     function );
674
675
0
    return( -1 );
676
0
  }
677
271
  if( file_io_handle == NULL )
678
0
  {
679
0
    libcerror_error_set(
680
0
     error,
681
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
682
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
683
0
     "%s: invalid file IO handle.",
684
0
     function );
685
686
0
    return( -1 );
687
0
  }
688
271
  if( ( ( access_flags & LIBVSMBR_ACCESS_FLAG_READ ) == 0 )
689
271
   && ( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) == 0 ) )
690
0
  {
691
0
    libcerror_error_set(
692
0
     error,
693
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
694
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
695
0
     "%s: unsupported access flags.",
696
0
     function );
697
698
0
    return( -1 );
699
0
  }
700
271
  if( ( access_flags & LIBVSMBR_ACCESS_FLAG_WRITE ) != 0 )
701
0
  {
702
0
    libcerror_error_set(
703
0
     error,
704
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
705
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
706
0
     "%s: write access currently not supported.",
707
0
     function );
708
709
0
    return( -1 );
710
0
  }
711
271
  if( ( access_flags & LIBVSMBR_ACCESS_FLAG_READ ) != 0 )
712
271
  {
713
271
    bfio_access_flags = LIBBFIO_ACCESS_FLAG_READ;
714
271
  }
715
271
  file_io_handle_is_open = libbfio_handle_is_open(
716
271
                            file_io_handle,
717
271
                            error );
718
719
271
  if( file_io_handle_is_open == -1 )
720
0
  {
721
0
    libcerror_error_set(
722
0
     error,
723
0
     LIBCERROR_ERROR_DOMAIN_IO,
724
0
     LIBCERROR_IO_ERROR_OPEN_FAILED,
725
0
     "%s: unable to open volume.",
726
0
     function );
727
728
0
    goto on_error;
729
0
  }
730
271
  else if( file_io_handle_is_open == 0 )
731
271
  {
732
271
    if( libbfio_handle_open(
733
271
         file_io_handle,
734
271
         bfio_access_flags,
735
271
         error ) != 1 )
736
0
    {
737
0
      libcerror_error_set(
738
0
       error,
739
0
       LIBCERROR_ERROR_DOMAIN_IO,
740
0
       LIBCERROR_IO_ERROR_OPEN_FAILED,
741
0
       "%s: unable to open file IO handle.",
742
0
       function );
743
744
0
      goto on_error;
745
0
    }
746
271
    file_io_handle_opened_in_library = 1;
747
271
  }
748
271
  if( libvsmbr_internal_volume_open_read(
749
271
       internal_volume,
750
271
       file_io_handle,
751
271
       error ) != 1 )
752
195
  {
753
195
    libcerror_error_set(
754
195
     error,
755
195
     LIBCERROR_ERROR_DOMAIN_IO,
756
195
     LIBCERROR_IO_ERROR_READ_FAILED,
757
195
     "%s: unable to read from file IO handle.",
758
195
     function );
759
760
195
    goto on_error;
761
195
  }
762
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
763
76
  if( libcthreads_read_write_lock_grab_for_write(
764
76
       internal_volume->read_write_lock,
765
76
       error ) != 1 )
766
0
  {
767
0
    libcerror_error_set(
768
0
     error,
769
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
770
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
771
0
     "%s: unable to grab read/write lock for writing.",
772
0
     function );
773
774
0
    return( -1 );
775
0
  }
776
76
#endif
777
76
  internal_volume->file_io_handle                   = file_io_handle;
778
76
  internal_volume->file_io_handle_opened_in_library = file_io_handle_opened_in_library;
779
780
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
781
76
  if( libcthreads_read_write_lock_release_for_write(
782
76
       internal_volume->read_write_lock,
783
76
       error ) != 1 )
784
0
  {
785
0
    libcerror_error_set(
786
0
     error,
787
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
788
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
789
0
     "%s: unable to release read/write lock for writing.",
790
0
     function );
791
792
0
    return( -1 );
793
0
  }
794
76
#endif
795
76
  return( 1 );
796
797
195
on_error:
798
195
  if( file_io_handle_opened_in_library != 0 )
799
195
  {
800
195
    libbfio_handle_close(
801
195
     file_io_handle,
802
195
     error );
803
195
  }
804
195
  return( -1 );
805
76
}
806
807
/* Closes a volume
808
 * Returns 0 if successful or -1 on error
809
 */
810
int libvsmbr_volume_close(
811
     libvsmbr_volume_t *volume,
812
     libcerror_error_t **error )
813
76
{
814
76
  libvsmbr_internal_volume_t *internal_volume = NULL;
815
76
  static char *function                       = "libvsmbr_volume_close";
816
76
  int result                                  = 0;
817
818
76
  if( volume == NULL )
819
0
  {
820
0
    libcerror_error_set(
821
0
     error,
822
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
823
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
824
0
     "%s: invalid volume.",
825
0
     function );
826
827
0
    return( -1 );
828
0
  }
829
76
  internal_volume = (libvsmbr_internal_volume_t *) volume;
830
831
76
  if( internal_volume->file_io_handle == NULL )
832
0
  {
833
0
    libcerror_error_set(
834
0
     error,
835
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
836
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
837
0
     "%s: invalid volume - missing file IO handle.",
838
0
     function );
839
840
0
    return( -1 );
841
0
  }
842
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
843
76
  if( libcthreads_read_write_lock_grab_for_write(
844
76
       internal_volume->read_write_lock,
845
76
       error ) != 1 )
846
0
  {
847
0
    libcerror_error_set(
848
0
     error,
849
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
850
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
851
0
     "%s: unable to grab read/write lock for writing.",
852
0
     function );
853
854
0
    return( -1 );
855
0
  }
856
76
#endif
857
#if defined( HAVE_DEBUG_OUTPUT )
858
  if( libcnotify_verbose != 0 )
859
  {
860
    if( internal_volume->file_io_handle_created_in_library != 0 )
861
    {
862
      if( libvsmbr_debug_print_read_offsets(
863
           internal_volume->file_io_handle,
864
           error ) != 1 )
865
      {
866
        libcerror_error_set(
867
         error,
868
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
869
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
870
         "%s: unable to print the read offsets.",
871
         function );
872
873
        result = -1;
874
      }
875
    }
876
  }
877
#endif
878
76
  if( internal_volume->file_io_handle_opened_in_library != 0 )
879
76
  {
880
76
    if( libbfio_handle_close(
881
76
         internal_volume->file_io_handle,
882
76
         error ) != 0 )
883
0
    {
884
0
      libcerror_error_set(
885
0
       error,
886
0
       LIBCERROR_ERROR_DOMAIN_IO,
887
0
       LIBCERROR_IO_ERROR_CLOSE_FAILED,
888
0
       "%s: unable to close file IO handle.",
889
0
       function );
890
891
0
      result = -1;
892
0
    }
893
76
    internal_volume->file_io_handle_opened_in_library = 0;
894
76
  }
895
76
  if( internal_volume->file_io_handle_created_in_library != 0 )
896
0
  {
897
0
    if( libbfio_handle_free(
898
0
         &( internal_volume->file_io_handle ),
899
0
         error ) != 1 )
900
0
    {
901
0
      libcerror_error_set(
902
0
       error,
903
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
904
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
905
0
       "%s: unable to free file IO handle.",
906
0
       function );
907
908
0
      result = -1;
909
0
    }
910
0
    internal_volume->file_io_handle_created_in_library = 0;
911
0
  }
912
76
  internal_volume->file_io_handle = NULL;
913
914
76
  if( libvsmbr_io_handle_clear(
915
76
       internal_volume->io_handle,
916
76
       error ) != 1 )
917
0
  {
918
0
    libcerror_error_set(
919
0
     error,
920
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
921
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
922
0
     "%s: unable to clear the IO handle.",
923
0
     function );
924
925
0
    result = -1;
926
0
  }
927
76
  if( libcdata_array_empty(
928
76
       internal_volume->partitions,
929
76
       (int (*)(intptr_t **, libcerror_error_t **)) &libvsmbr_partition_values_free,
930
76
       error ) != 1 )
931
0
  {
932
0
    libcerror_error_set(
933
0
     error,
934
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
935
0
     LIBCERROR_RUNTIME_ERROR_RESIZE_FAILED,
936
0
     "%s: unable to empty the partitions array.",
937
0
     function );
938
939
0
    result = -1;
940
0
  }
941
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
942
76
  if( libcthreads_read_write_lock_release_for_write(
943
76
       internal_volume->read_write_lock,
944
76
       error ) != 1 )
945
0
  {
946
0
    libcerror_error_set(
947
0
     error,
948
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
949
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
950
0
     "%s: unable to release read/write lock for writing.",
951
0
     function );
952
953
0
    return( -1 );
954
0
  }
955
76
#endif
956
76
  return( result );
957
76
}
958
959
/* Opens a volume for reading
960
 * Returns 1 if successful or -1 on error
961
 */
962
int libvsmbr_internal_volume_open_read(
963
     libvsmbr_internal_volume_t *internal_volume,
964
     libbfio_handle_t *file_io_handle,
965
     libcerror_error_t **error )
966
271
{
967
271
  libvsmbr_boot_record_t *master_boot_record = NULL;
968
271
  static char *function                      = "libvsmbr_internal_volume_open_read";
969
970
271
  if( internal_volume == NULL )
971
0
  {
972
0
    libcerror_error_set(
973
0
     error,
974
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
975
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
976
0
     "%s: invalid internal volume.",
977
0
     function );
978
979
0
    return( -1 );
980
0
  }
981
271
  if( libbfio_handle_get_size(
982
271
       file_io_handle,
983
271
       &( internal_volume->size ),
984
271
       error ) != 1 )
985
0
  {
986
0
    libcerror_error_set(
987
0
     error,
988
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
989
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
990
0
     "%s: unable to retrieve size from file IO handle.",
991
0
     function );
992
993
0
    goto on_error;
994
0
  }
995
#if defined( HAVE_DEBUG_OUTPUT )
996
  if( libcnotify_verbose != 0 )
997
  {
998
    libcnotify_printf(
999
     "%s: reading Master Boot Record (MBR).\n",
1000
     function );
1001
  }
1002
#endif
1003
271
  if( libvsmbr_boot_record_initialize(
1004
271
       &master_boot_record,
1005
271
       error ) != 1 )
1006
0
  {
1007
0
    libcerror_error_set(
1008
0
     error,
1009
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1010
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1011
0
     "%s: unable to create master boot record.",
1012
0
     function );
1013
1014
0
    goto on_error;
1015
0
  }
1016
271
  if( libvsmbr_boot_record_read_file_io_handle(
1017
271
       master_boot_record,
1018
271
       file_io_handle,
1019
271
       0,
1020
271
       error ) != 1 )
1021
62
  {
1022
62
    libcerror_error_set(
1023
62
     error,
1024
62
     LIBCERROR_ERROR_DOMAIN_IO,
1025
62
     LIBCERROR_IO_ERROR_READ_FAILED,
1026
62
     "%s: unable to read master boot record.",
1027
62
     function );
1028
1029
62
    goto on_error;
1030
62
  }
1031
209
  internal_volume->disk_identity = master_boot_record->disk_identity;
1032
1033
209
  if( libvsmbr_internal_volume_read_partition_entries(
1034
209
       internal_volume,
1035
209
       file_io_handle,
1036
209
       0,
1037
209
       master_boot_record,
1038
209
       1,
1039
209
       0,
1040
209
       0,
1041
209
       error ) != 1 )
1042
133
  {
1043
133
    libcerror_error_set(
1044
133
     error,
1045
133
     LIBCERROR_ERROR_DOMAIN_IO,
1046
133
     LIBCERROR_IO_ERROR_READ_FAILED,
1047
133
     "%s: unable to read partition entries.",
1048
133
     function );
1049
1050
133
    goto on_error;
1051
133
  }
1052
76
  if( libvsmbr_boot_record_free(
1053
76
       &master_boot_record,
1054
76
       error ) != 1 )
1055
0
  {
1056
0
    libcerror_error_set(
1057
0
     error,
1058
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1059
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1060
0
     "%s: unable to free master boot record.",
1061
0
     function );
1062
1063
0
    goto on_error;
1064
0
  }
1065
76
  return( 1 );
1066
1067
195
on_error:
1068
195
  if( master_boot_record != NULL )
1069
195
  {
1070
195
    libvsmbr_boot_record_free(
1071
195
     &master_boot_record,
1072
195
     NULL );
1073
195
  }
1074
195
  return( -1 );
1075
76
}
1076
1077
/* Reads partition entries in a master boot record or extended partition record
1078
 * Returns 1 if successful or -1 on error
1079
 */
1080
int libvsmbr_internal_volume_read_partition_entries(
1081
     libvsmbr_internal_volume_t *internal_volume,
1082
     libbfio_handle_t *file_io_handle,
1083
     off64_t file_offset,
1084
     libvsmbr_boot_record_t *boot_record,
1085
     uint8_t is_master_boot_record,
1086
     off64_t first_extended_boot_record_offset,
1087
     int recursion_depth,
1088
     libcerror_error_t **error )
1089
6.16k
{
1090
6.16k
  libvsmbr_boot_record_t *extended_partition_record = NULL;
1091
6.16k
  libvsmbr_partition_entry_t *partition_entry       = NULL;
1092
6.16k
  libvsmbr_partition_values_t *partition_values     = NULL;
1093
6.16k
  static char *function                             = "libvsmbr_internal_volume_read_partition_entries";
1094
6.16k
  off64_t extended_partition_record_offset          = 0;
1095
6.16k
  int entry_index                                   = 0;
1096
6.16k
  int partition_entry_index                         = 0;
1097
6.16k
  int result                                        = 0;
1098
1099
6.16k
  if( internal_volume == NULL )
1100
0
  {
1101
0
    libcerror_error_set(
1102
0
     error,
1103
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1104
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1105
0
     "%s: invalid internal volume.",
1106
0
     function );
1107
1108
0
    return( -1 );
1109
0
  }
1110
6.16k
  if( ( recursion_depth < 0 )
1111
6.16k
   || ( recursion_depth > LIBVSMBR_MAXIMUM_RECURSION_DEPTH ) )
1112
22
  {
1113
22
    libcerror_error_set(
1114
22
     error,
1115
22
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1116
22
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1117
22
     "%s: invalid recursion depth value out of bounds.",
1118
22
     function );
1119
1120
22
    return( -1 );
1121
22
  }
1122
6.14k
  for( partition_entry_index = 0;
1123
30.4k
       partition_entry_index < 4;
1124
24.2k
       partition_entry_index++ )
1125
24.3k
  {
1126
24.3k
    if( libvsmbr_boot_record_get_partition_entry_by_index(
1127
24.3k
         boot_record,
1128
24.3k
         partition_entry_index,
1129
24.3k
         &partition_entry,
1130
24.3k
         error ) != 1 )
1131
0
    {
1132
0
      libcerror_error_set(
1133
0
       error,
1134
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1135
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1136
0
       "%s: unable to retrieve partition entry: %d.",
1137
0
       function,
1138
0
       partition_entry_index );
1139
1140
0
      goto on_error;
1141
0
    }
1142
24.3k
    if( partition_entry == NULL )
1143
0
    {
1144
0
      libcerror_error_set(
1145
0
       error,
1146
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1147
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1148
0
       "%s: missing partition entry: %" PRIu8 ".",
1149
0
       function,
1150
0
       partition_entry_index );
1151
1152
0
      goto on_error;
1153
0
    }
1154
    /* Ignore empty partition entries
1155
     */
1156
24.3k
    if( partition_entry->type == 0 )
1157
7.99k
    {
1158
7.99k
      continue;
1159
7.99k
    }
1160
16.3k
    if( ( partition_entry->type == 0x05 )
1161
16.3k
     || ( ( is_master_boot_record != 0 )
1162
10.2k
      &&  ( partition_entry->type == 0x0f ) ) )
1163
6.08k
    {
1164
6.08k
      if( extended_partition_record != NULL )
1165
10
      {
1166
10
        libcerror_error_set(
1167
10
         error,
1168
10
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1169
10
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1170
10
         "%s: more than 1 extended partition entry per table is not supported.",
1171
10
         function );
1172
1173
10
        goto on_error;
1174
10
      }
1175
6.07k
      extended_partition_record_offset = first_extended_boot_record_offset + ( (off64_t) partition_entry->start_address_lba * internal_volume->io_handle->bytes_per_sector );
1176
1177
#if defined( HAVE_DEBUG_OUTPUT )
1178
      if( libcnotify_verbose != 0 )
1179
      {
1180
        libcnotify_printf(
1181
         "%s: reading Extended Partition Record (EPR) at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
1182
         function,
1183
         extended_partition_record_offset,
1184
         extended_partition_record_offset );
1185
      }
1186
#endif
1187
6.07k
      if( libvsmbr_boot_record_initialize(
1188
6.07k
           &extended_partition_record,
1189
6.07k
           error ) != 1 )
1190
0
      {
1191
0
        libcerror_error_set(
1192
0
         error,
1193
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1194
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1195
0
         "%s: unable to create extended partition record.",
1196
0
         function );
1197
1198
0
        goto on_error;
1199
0
      }
1200
6.07k
      result = libvsmbr_boot_record_read_file_io_handle(
1201
6.07k
          extended_partition_record,
1202
6.07k
          file_io_handle,
1203
6.07k
          extended_partition_record_offset,
1204
6.07k
          error );
1205
1206
      /* Linux fdisk supports sector sizes of: 512, 1024, 2048, 4096
1207
       */
1208
6.29k
      while( ( result != 1 )
1209
6.29k
          && ( is_master_boot_record != 0 )
1210
6.29k
          && ( internal_volume->io_handle->bytes_per_sector < 4096 ) )
1211
219
      {
1212
219
        libcerror_error_free(
1213
219
         error );
1214
1215
219
        internal_volume->io_handle->bytes_per_sector *= 2;
1216
1217
219
        extended_partition_record_offset = first_extended_boot_record_offset + ( (off64_t) partition_entry->start_address_lba * internal_volume->io_handle->bytes_per_sector );
1218
1219
#if defined( HAVE_DEBUG_OUTPUT )
1220
        if( libcnotify_verbose != 0 )
1221
        {
1222
          libcnotify_printf(
1223
           "%s: reading Extended Partition Record (EPR) at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
1224
           function,
1225
           extended_partition_record_offset,
1226
           extended_partition_record_offset );
1227
        }
1228
#endif
1229
219
        result = libvsmbr_boot_record_read_file_io_handle(
1230
219
            extended_partition_record,
1231
219
            file_io_handle,
1232
219
            extended_partition_record_offset,
1233
219
            error );
1234
219
      }
1235
6.07k
      if( result != 1 )
1236
87
      {
1237
87
        libcerror_error_set(
1238
87
         error,
1239
87
         LIBCERROR_ERROR_DOMAIN_IO,
1240
87
         LIBCERROR_IO_ERROR_READ_FAILED,
1241
87
         "%s: unable to read extended partition record.",
1242
87
         function );
1243
1244
87
        goto on_error;
1245
87
      }
1246
5.98k
      internal_volume->bytes_per_sector_set_by_library = 1;
1247
5.98k
    }
1248
10.2k
    else
1249
10.2k
    {
1250
/* TODO do bytes per sector check for known volume types and GPT */
1251
1252
10.2k
      if( libvsmbr_partition_values_initialize(
1253
10.2k
           &partition_values,
1254
10.2k
           error ) != 1 )
1255
0
      {
1256
0
        libcerror_error_set(
1257
0
         error,
1258
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1259
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1260
0
         "%s: unable to create partition values.",
1261
0
         function );
1262
1263
0
        goto on_error;
1264
0
      }
1265
10.2k
      partition_values->type                    = partition_entry->type;
1266
10.2k
      partition_values->partition_record_offset = file_offset;
1267
10.2k
      partition_values->sector_number           = partition_entry->start_address_lba;
1268
10.2k
      partition_values->number_of_sectors       = partition_entry->number_of_sectors;
1269
1270
10.2k
      if( libcdata_array_append_entry(
1271
10.2k
           internal_volume->partitions,
1272
10.2k
           &entry_index,
1273
10.2k
           (intptr_t *) partition_values,
1274
10.2k
           error ) != 1 )
1275
0
      {
1276
0
        libcerror_error_set(
1277
0
         error,
1278
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1279
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1280
0
         "%s: unable to append partition to array.",
1281
0
         function );
1282
1283
0
        goto on_error;
1284
0
      }
1285
10.2k
      partition_values = NULL;
1286
10.2k
    }
1287
16.3k
  }
1288
6.05k
  if( extended_partition_record != NULL )
1289
5.97k
  {
1290
5.97k
    if( ( extended_partition_record_offset == 0 )
1291
5.97k
     || ( extended_partition_record_offset == file_offset ) )
1292
14
    {
1293
14
      libcerror_error_set(
1294
14
       error,
1295
14
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1296
14
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1297
14
       "%s: unsupported extended partition record offset.",
1298
14
       function );
1299
1300
14
      goto on_error;
1301
14
    }
1302
5.96k
    if( is_master_boot_record != 0 )
1303
89
    {
1304
89
      first_extended_boot_record_offset = extended_partition_record_offset;
1305
89
    }
1306
5.96k
    if( libvsmbr_internal_volume_read_partition_entries(
1307
5.96k
         internal_volume,
1308
5.96k
         file_io_handle,
1309
5.96k
         extended_partition_record_offset,
1310
5.96k
         extended_partition_record,
1311
5.96k
         0,
1312
5.96k
         first_extended_boot_record_offset,
1313
5.96k
         recursion_depth + 1,
1314
5.96k
         error ) != 1 )
1315
5.82k
    {
1316
5.82k
      libcerror_error_set(
1317
5.82k
       error,
1318
5.82k
       LIBCERROR_ERROR_DOMAIN_IO,
1319
5.82k
       LIBCERROR_IO_ERROR_READ_FAILED,
1320
5.82k
       "%s: unable to read partition entries.",
1321
5.82k
       function );
1322
1323
5.82k
      goto on_error;
1324
5.82k
    }
1325
133
    if( libvsmbr_boot_record_free(
1326
133
         &extended_partition_record,
1327
133
         error ) != 1 )
1328
0
    {
1329
0
      libcerror_error_set(
1330
0
       error,
1331
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1332
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
1333
0
       "%s: unable to free extended partition record.",
1334
0
       function );
1335
1336
0
      goto on_error;
1337
0
    }
1338
133
  }
1339
209
  return( 1 );
1340
1341
5.93k
on_error:
1342
5.93k
  if( partition_values != NULL )
1343
0
  {
1344
0
    libvsmbr_partition_values_free(
1345
0
     &partition_values,
1346
0
     NULL );
1347
0
  }
1348
5.93k
  if( extended_partition_record != NULL )
1349
5.93k
  {
1350
5.93k
    libvsmbr_boot_record_free(
1351
5.93k
     &extended_partition_record,
1352
5.93k
     NULL );
1353
5.93k
  }
1354
5.93k
  return( -1 );
1355
6.05k
}
1356
1357
/* Retrieves the number of bytes per sector
1358
 * Returns 1 if successful or -1 on error
1359
 */
1360
int libvsmbr_volume_get_bytes_per_sector(
1361
     libvsmbr_volume_t *volume,
1362
     uint32_t *bytes_per_sector,
1363
     libcerror_error_t **error )
1364
0
{
1365
0
  libvsmbr_internal_volume_t *internal_volume = NULL;
1366
0
  static char *function                       = "libvsmbr_volume_get_bytes_per_sector";
1367
1368
0
  if( volume == NULL )
1369
0
  {
1370
0
    libcerror_error_set(
1371
0
     error,
1372
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1373
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1374
0
     "%s: invalid volume.",
1375
0
     function );
1376
1377
0
    return( -1 );
1378
0
  }
1379
0
  internal_volume = (libvsmbr_internal_volume_t *) volume;
1380
1381
0
  if( internal_volume->io_handle == NULL )
1382
0
  {
1383
0
    libcerror_error_set(
1384
0
     error,
1385
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1386
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1387
0
     "%s: invalid volume - missing IO handle.",
1388
0
     function );
1389
1390
0
    return( -1 );
1391
0
  }
1392
0
  if( bytes_per_sector == NULL )
1393
0
  {
1394
0
    libcerror_error_set(
1395
0
     error,
1396
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1397
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1398
0
     "%s: invalid bytes per sector.",
1399
0
     function );
1400
1401
0
    return( -1 );
1402
0
  }
1403
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1404
0
  if( libcthreads_read_write_lock_grab_for_read(
1405
0
       internal_volume->read_write_lock,
1406
0
       error ) != 1 )
1407
0
  {
1408
0
    libcerror_error_set(
1409
0
     error,
1410
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1411
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1412
0
     "%s: unable to grab read/write lock for reading.",
1413
0
     function );
1414
1415
0
    return( -1 );
1416
0
  }
1417
0
#endif
1418
0
  *bytes_per_sector = internal_volume->io_handle->bytes_per_sector;
1419
1420
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1421
0
  if( libcthreads_read_write_lock_release_for_read(
1422
0
       internal_volume->read_write_lock,
1423
0
       error ) != 1 )
1424
0
  {
1425
0
    libcerror_error_set(
1426
0
     error,
1427
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1428
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1429
0
     "%s: unable to release read/write lock for reading.",
1430
0
     function );
1431
1432
0
    return( -1 );
1433
0
  }
1434
0
#endif
1435
0
  return( 1 );
1436
0
}
1437
1438
/* Sets the number of bytes per sector
1439
 * Returns 1 if successful or -1 on error
1440
 */
1441
int libvsmbr_volume_set_bytes_per_sector(
1442
     libvsmbr_volume_t *volume,
1443
     uint32_t bytes_per_sector,
1444
     libcerror_error_t **error )
1445
0
{
1446
0
  libvsmbr_internal_volume_t *internal_volume = NULL;
1447
0
  static char *function                       = "libvsmbr_volume_set_bytes_per_sector";
1448
1449
0
  if( volume == NULL )
1450
0
  {
1451
0
    libcerror_error_set(
1452
0
     error,
1453
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1454
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1455
0
     "%s: invalid volume.",
1456
0
     function );
1457
1458
0
    return( -1 );
1459
0
  }
1460
0
  internal_volume = (libvsmbr_internal_volume_t *) volume;
1461
1462
0
  if( internal_volume->io_handle == NULL )
1463
0
  {
1464
0
    libcerror_error_set(
1465
0
     error,
1466
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1467
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
1468
0
     "%s: invalid volume - missing IO handle.",
1469
0
     function );
1470
1471
0
    return( -1 );
1472
0
  }
1473
0
  if( internal_volume->bytes_per_sector_set_by_library != 0 )
1474
0
  {
1475
0
    libcerror_error_set(
1476
0
     error,
1477
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1478
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1479
0
     "%s: bytes per sector value already set.",
1480
0
     function );
1481
1482
0
    return( -1 );
1483
0
  }
1484
0
  if( ( bytes_per_sector != 512 )
1485
0
   && ( bytes_per_sector != 1024 )
1486
0
   && ( bytes_per_sector != 2048 )
1487
0
   && ( bytes_per_sector != 4096 ) )
1488
0
  {
1489
0
    libcerror_error_set(
1490
0
     error,
1491
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1492
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1493
0
     "%s: unsupported bytes per sector.",
1494
0
     function );
1495
1496
0
    return( -1 );
1497
0
  }
1498
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1499
0
  if( libcthreads_read_write_lock_grab_for_write(
1500
0
       internal_volume->read_write_lock,
1501
0
       error ) != 1 )
1502
0
  {
1503
0
    libcerror_error_set(
1504
0
     error,
1505
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1506
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1507
0
     "%s: unable to grab read/write lock for writing.",
1508
0
     function );
1509
1510
0
    return( -1 );
1511
0
  }
1512
0
#endif
1513
0
  internal_volume->io_handle->bytes_per_sector = bytes_per_sector;
1514
1515
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1516
0
  if( libcthreads_read_write_lock_release_for_write(
1517
0
       internal_volume->read_write_lock,
1518
0
       error ) != 1 )
1519
0
  {
1520
0
    libcerror_error_set(
1521
0
     error,
1522
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1523
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1524
0
     "%s: unable to release read/write lock for writing.",
1525
0
     function );
1526
1527
0
    return( -1 );
1528
0
  }
1529
0
#endif
1530
0
  return( 1 );
1531
0
}
1532
1533
/* Retrieves the disk identity (or disk identifier)
1534
 * Returns 1 if successful, 0 if not available or -1 on error
1535
 */
1536
int libvsmbr_volume_get_disk_identity(
1537
     libvsmbr_volume_t *volume,
1538
     uint32_t *disk_identity,
1539
     libcerror_error_t **error )
1540
0
{
1541
0
  libvsmbr_internal_volume_t *internal_volume = NULL;
1542
0
  static char *function                       = "libvsmbr_volume_get_disk_identity";
1543
0
  int result                                  = 1;
1544
1545
0
  if( volume == NULL )
1546
0
  {
1547
0
    libcerror_error_set(
1548
0
     error,
1549
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1550
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1551
0
     "%s: invalid volume.",
1552
0
     function );
1553
1554
0
    return( -1 );
1555
0
  }
1556
0
  internal_volume = (libvsmbr_internal_volume_t *) volume;
1557
1558
0
  if( disk_identity == NULL )
1559
0
  {
1560
0
    libcerror_error_set(
1561
0
     error,
1562
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1563
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1564
0
     "%s: invalid disk identity.",
1565
0
     function );
1566
1567
0
    return( -1 );
1568
0
  }
1569
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1570
0
  if( libcthreads_read_write_lock_grab_for_read(
1571
0
       internal_volume->read_write_lock,
1572
0
       error ) != 1 )
1573
0
  {
1574
0
    libcerror_error_set(
1575
0
     error,
1576
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1577
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1578
0
     "%s: unable to grab read/write lock for reading.",
1579
0
     function );
1580
1581
0
    return( -1 );
1582
0
  }
1583
0
#endif
1584
1585
/* TODO add support to return 0 if not available */
1586
1587
0
  *disk_identity = internal_volume->disk_identity;
1588
1589
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1590
0
  if( libcthreads_read_write_lock_release_for_read(
1591
0
       internal_volume->read_write_lock,
1592
0
       error ) != 1 )
1593
0
  {
1594
0
    libcerror_error_set(
1595
0
     error,
1596
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1597
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1598
0
     "%s: unable to release read/write lock for reading.",
1599
0
     function );
1600
1601
0
    return( -1 );
1602
0
  }
1603
0
#endif
1604
0
  return( result );
1605
0
}
1606
1607
/* Retrieves the number of partitions
1608
 * Returns 1 if successful or -1 on error
1609
 */
1610
int libvsmbr_volume_get_number_of_partitions(
1611
     libvsmbr_volume_t *volume,
1612
     int *number_of_partitions,
1613
     libcerror_error_t **error )
1614
76
{
1615
76
  libvsmbr_internal_volume_t *internal_volume = NULL;
1616
76
  static char *function                       = "libvsmbr_volume_get_number_of_partitions";
1617
76
  int result                                  = 1;
1618
1619
76
  if( volume == NULL )
1620
0
  {
1621
0
    libcerror_error_set(
1622
0
     error,
1623
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1624
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1625
0
     "%s: invalid volume.",
1626
0
     function );
1627
1628
0
    return( -1 );
1629
0
  }
1630
76
  internal_volume = (libvsmbr_internal_volume_t *) volume;
1631
1632
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1633
76
  if( libcthreads_read_write_lock_grab_for_read(
1634
76
       internal_volume->read_write_lock,
1635
76
       error ) != 1 )
1636
0
  {
1637
0
    libcerror_error_set(
1638
0
     error,
1639
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1640
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1641
0
     "%s: unable to grab read/write lock for reading.",
1642
0
     function );
1643
1644
0
    return( -1 );
1645
0
  }
1646
76
#endif
1647
76
  if( libcdata_array_get_number_of_entries(
1648
76
       internal_volume->partitions,
1649
76
       number_of_partitions,
1650
76
       error ) != 1 )
1651
0
  {
1652
0
    libcerror_error_set(
1653
0
     error,
1654
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1655
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1656
0
     "%s: unable to retrieve number of partitions from array.",
1657
0
     function );
1658
1659
0
    result = -1;
1660
0
  }
1661
76
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1662
76
  if( libcthreads_read_write_lock_release_for_read(
1663
76
       internal_volume->read_write_lock,
1664
76
       error ) != 1 )
1665
0
  {
1666
0
    libcerror_error_set(
1667
0
     error,
1668
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1669
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1670
0
     "%s: unable to release read/write lock for reading.",
1671
0
     function );
1672
1673
0
    return( -1 );
1674
0
  }
1675
76
#endif
1676
76
  return( result );
1677
76
}
1678
1679
/* Retrieves a specific partition
1680
 * Returns 1 if successful or -1 on error
1681
 */
1682
int libvsmbr_volume_get_partition_by_index(
1683
     libvsmbr_volume_t *volume,
1684
     int partition_index,
1685
     libvsmbr_partition_t **partition,
1686
     libcerror_error_t **error )
1687
74
{
1688
74
  libvsmbr_internal_volume_t *internal_volume   = NULL;
1689
74
  libvsmbr_partition_values_t *partition_values = NULL;
1690
74
  static char *function                         = "libvsmbr_volume_get_partition_by_index";
1691
1692
74
  if( volume == NULL )
1693
0
  {
1694
0
    libcerror_error_set(
1695
0
     error,
1696
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1697
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1698
0
     "%s: invalid volume.",
1699
0
     function );
1700
1701
0
    return( -1 );
1702
0
  }
1703
74
  internal_volume = (libvsmbr_internal_volume_t *) volume;
1704
1705
74
  if( partition == NULL )
1706
0
  {
1707
0
    libcerror_error_set(
1708
0
     error,
1709
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1710
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1711
0
     "%s: invalid partition.",
1712
0
     function );
1713
1714
0
    return( -1 );
1715
0
  }
1716
74
  if( *partition != NULL )
1717
0
  {
1718
0
    libcerror_error_set(
1719
0
     error,
1720
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1721
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
1722
0
     "%s: invalid partition value already set.",
1723
0
     function );
1724
1725
0
    return( -1 );
1726
0
  }
1727
74
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1728
74
  if( libcthreads_read_write_lock_grab_for_read(
1729
74
       internal_volume->read_write_lock,
1730
74
       error ) != 1 )
1731
0
  {
1732
0
    libcerror_error_set(
1733
0
     error,
1734
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1735
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1736
0
     "%s: unable to grab read/write lock for reading.",
1737
0
     function );
1738
1739
0
    return( -1 );
1740
0
  }
1741
74
#endif
1742
74
  if( libcdata_array_get_entry_by_index(
1743
74
       internal_volume->partitions,
1744
74
       partition_index,
1745
74
       (intptr_t **) &partition_values,
1746
74
       error ) != 1 )
1747
0
  {
1748
0
    libcerror_error_set(
1749
0
     error,
1750
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1751
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1752
0
     "%s: unable to retrieve partition values: %d from array.",
1753
0
     function,
1754
0
     partition_index );
1755
1756
0
    goto on_error;
1757
0
  }
1758
74
  if( libvsmbr_partition_initialize(
1759
74
       partition,
1760
74
       internal_volume->io_handle,
1761
74
       internal_volume->file_io_handle,
1762
74
       partition_values,
1763
74
       error ) != 1 )
1764
0
  {
1765
0
    libcerror_error_set(
1766
0
     error,
1767
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1768
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1769
0
     "%s: unable to create partition: %d.",
1770
0
     function,
1771
0
     partition_index );
1772
1773
0
    goto on_error;
1774
0
  }
1775
74
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1776
74
  if( libcthreads_read_write_lock_release_for_read(
1777
74
       internal_volume->read_write_lock,
1778
74
       error ) != 1 )
1779
0
  {
1780
0
    libcerror_error_set(
1781
0
     error,
1782
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1783
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1784
0
     "%s: unable to release read/write lock for reading.",
1785
0
     function );
1786
1787
0
    return( -1 );
1788
0
  }
1789
74
#endif
1790
74
  return( 1 );
1791
1792
0
on_error:
1793
0
#if defined( HAVE_LIBVSMBR_MULTI_THREAD_SUPPORT )
1794
0
  libcthreads_read_write_lock_release_for_read(
1795
0
   internal_volume->read_write_lock,
1796
0
   NULL );
1797
0
#endif
1798
0
  return( -1 );
1799
74
}
1800