Coverage Report

Created: 2023-06-07 06:53

/src/libfsfat/libfsfat/libfsfat_allocation_table.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Allocation table functions
3
 *
4
 * Copyright (C) 2021-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 <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfsfat_allocation_table.h"
28
#include "libfsfat_debug.h"
29
#include "libfsfat_definitions.h"
30
#include "libfsfat_io_handle.h"
31
#include "libfsfat_libbfio.h"
32
#include "libfsfat_libcerror.h"
33
#include "libfsfat_libcnotify.h"
34
35
/* Creates an allocation table
36
 * Make sure the value allocation_table is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libfsfat_allocation_table_initialize(
40
     libfsfat_allocation_table_t **allocation_table,
41
     uint32_t total_number_of_clusters,
42
     libcerror_error_t **error )
43
3.45k
{
44
3.45k
  static char *function            = "libfsfat_allocation_table_initialize";
45
3.45k
  size_t cluster_numbers_data_size = 0;
46
47
3.45k
  if( allocation_table == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid allocation table.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
3.45k
  if( *allocation_table != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid allocation table value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
3.45k
  if( ( total_number_of_clusters == 0 )
70
3.45k
   || ( total_number_of_clusters > (uint32_t) LIBFSFAT_MAXIMUM_NUMBER_OF_CLUSTERS_IN_FAT ) )
71
142
  {
72
142
    libcerror_error_set(
73
142
     error,
74
142
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75
142
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
76
142
     "%s: invalid total number of clusters value out of bounds.",
77
142
     function );
78
79
142
    return( -1 );
80
142
  }
81
3.30k
  *allocation_table = memory_allocate_structure(
82
3.30k
                       libfsfat_allocation_table_t );
83
84
3.30k
  if( *allocation_table == NULL )
85
0
  {
86
0
    libcerror_error_set(
87
0
     error,
88
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
89
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
90
0
     "%s: unable to create allocation table.",
91
0
     function );
92
93
0
    goto on_error;
94
0
  }
95
3.30k
  if( memory_set(
96
3.30k
       *allocation_table,
97
3.30k
       0,
98
3.30k
       sizeof( libfsfat_allocation_table_t ) ) == NULL )
99
0
  {
100
0
    libcerror_error_set(
101
0
     error,
102
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
103
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
104
0
     "%s: unable to clear allocation table.",
105
0
     function );
106
107
0
    memory_free(
108
0
     *allocation_table );
109
110
0
    *allocation_table = NULL;
111
112
0
    return( -1 );
113
0
  }
114
3.30k
  cluster_numbers_data_size = sizeof( uint32_t ) * total_number_of_clusters;
115
116
3.30k
  ( *allocation_table )->cluster_numbers = (uint32_t *) memory_allocate(
117
3.30k
                                                         cluster_numbers_data_size );
118
119
3.30k
  if( ( *allocation_table )->cluster_numbers == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
124
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
125
0
     "%s: unable to create cluster numbers.",
126
0
     function );
127
128
0
    goto on_error;
129
0
  }
130
3.30k
  ( *allocation_table )->number_of_cluster_numbers = total_number_of_clusters;
131
132
3.30k
  if( memory_set(
133
3.30k
       ( *allocation_table )->cluster_numbers,
134
3.30k
       0,
135
3.30k
       cluster_numbers_data_size ) == NULL )
136
0
  {
137
0
    libcerror_error_set(
138
0
     error,
139
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
140
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
141
0
     "%s: unable to clear cluster numbers.",
142
0
     function );
143
144
0
    goto on_error;
145
0
  }
146
3.30k
  return( 1 );
147
148
0
on_error:
149
0
  if( *allocation_table != NULL )
150
0
  {
151
0
    if( ( *allocation_table )->cluster_numbers != NULL )
152
0
    {
153
0
      memory_free(
154
0
       ( *allocation_table )->cluster_numbers );
155
0
    }
156
0
    memory_free(
157
0
     *allocation_table );
158
159
0
    *allocation_table = NULL;
160
0
  }
161
0
  return( -1 );
162
3.30k
}
163
164
/* Frees an allocation table
165
 * Returns 1 if successful or -1 on error
166
 */
167
int libfsfat_allocation_table_free(
168
     libfsfat_allocation_table_t **allocation_table,
169
     libcerror_error_t **error )
170
3.30k
{
171
3.30k
  static char *function = "libfsfat_allocation_table_free";
172
173
3.30k
  if( allocation_table == 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 allocation table.",
180
0
     function );
181
182
0
    return( -1 );
183
0
  }
184
3.30k
  if( *allocation_table != NULL )
185
3.30k
  {
186
3.30k
    if( ( *allocation_table )->cluster_numbers != NULL )
187
3.30k
    {
188
3.30k
      memory_free(
189
3.30k
       ( *allocation_table )->cluster_numbers );
190
3.30k
    }
191
3.30k
    memory_free(
192
3.30k
     *allocation_table );
193
194
3.30k
    *allocation_table = NULL;
195
3.30k
  }
196
3.30k
  return( 1 );
197
3.30k
}
198
199
/* Reads an allocation table
200
 * Returns 1 if successful or -1 on error
201
 */
202
int libfsfat_allocation_table_read_file_io_handle(
203
     libfsfat_allocation_table_t *allocation_table,
204
     libfsfat_allocation_table_t *reversed_allocation_table,
205
     libfsfat_io_handle_t *io_handle,
206
     libbfio_handle_t *file_io_handle,
207
     off64_t file_offset,
208
     size64_t size,
209
     libcerror_error_t **error )
210
1.95k
{
211
1.95k
  uint8_t *table_data      = NULL;
212
1.95k
  static char *function    = "libfsfat_allocation_table_read_file_io_handle";
213
1.95k
  size_t read_size         = 0;
214
1.95k
  size_t table_data_offset = 0;
215
1.95k
  size_t table_offset      = 0;
216
1.95k
  ssize_t read_count       = 0;
217
1.95k
  uint32_t cluster_number  = 0;
218
1.95k
  int table_index          = 0;
219
220
1.95k
  if( allocation_table == NULL )
221
0
  {
222
0
    libcerror_error_set(
223
0
     error,
224
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
225
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
226
0
     "%s: invalid allocation table.",
227
0
     function );
228
229
0
    return( -1 );
230
0
  }
231
1.95k
  if( io_handle == NULL )
232
0
  {
233
0
    libcerror_error_set(
234
0
     error,
235
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
236
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
237
0
     "%s: invalid IO handle.",
238
0
     function );
239
240
0
    return( -1 );
241
0
  }
242
1.95k
  if( io_handle->bytes_per_sector == 0 )
243
0
  {
244
0
    libcerror_error_set(
245
0
     error,
246
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
247
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
248
0
     "%s: invalid IO handle - missing bytes per sector.",
249
0
     function );
250
251
0
    return( -1 );
252
0
  }
253
  /* Add 2 bytes to ensure we can read 3 bytes from the table data buffer
254
   */
255
1.95k
  table_data = (uint8_t *) memory_allocate(
256
1.95k
                            (size_t) io_handle->bytes_per_sector + 2 );
257
258
1.95k
  if( table_data == NULL )
259
0
  {
260
0
    libcerror_error_set(
261
0
     error,
262
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
263
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
264
0
     "%s: unable to create table data.",
265
0
     function );
266
267
0
    goto on_error;
268
0
  }
269
1.95k
  table_data[ io_handle->bytes_per_sector     ] = 0;
270
1.95k
  table_data[ io_handle->bytes_per_sector + 1 ] = 0;
271
272
1.95k
  read_size = io_handle->bytes_per_sector;
273
274
5.91k
  while( table_offset < size )
275
4.22k
  {
276
4.22k
    if( read_size > ( size - table_offset ) )
277
0
    {
278
0
      read_size = (size_t) size - table_offset;
279
0
    }
280
4.22k
    read_count = libbfio_handle_read_buffer_at_offset(
281
4.22k
                  file_io_handle,
282
4.22k
                  table_data,
283
4.22k
                  read_size,
284
4.22k
                  file_offset,
285
4.22k
                  error );
286
287
4.22k
    if( read_count != (ssize_t) read_size )
288
268
    {
289
268
      libcerror_error_set(
290
268
       error,
291
268
       LIBCERROR_ERROR_DOMAIN_IO,
292
268
       LIBCERROR_IO_ERROR_READ_FAILED,
293
268
       "%s: unable to read allocation table data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
294
268
       function,
295
268
       file_offset,
296
268
       file_offset );
297
298
268
      goto on_error;
299
268
    }
300
3.95k
    file_offset  += read_size;
301
3.95k
    table_offset += read_size;
302
303
3.95k
    table_data_offset = 0;
304
305
625k
    while( table_data_offset < read_size )
306
622k
    {
307
622k
      if( table_index >= allocation_table->number_of_cluster_numbers )
308
1.52k
      {
309
1.52k
        break;
310
1.52k
      }
311
621k
      if( io_handle->file_system_format == LIBFSFAT_FILE_SYSTEM_FORMAT_FAT12 )
312
28.7k
      {
313
28.7k
        byte_stream_copy_to_uint24_little_endian(
314
28.7k
         &( table_data[ table_data_offset ] ),
315
28.7k
         cluster_number );
316
317
28.7k
        table_data_offset += 3;
318
319
#if defined( HAVE_DEBUG_OUTPUT )
320
        if( libcnotify_verbose != 0 )
321
        {
322
          if( ( cluster_number & 0x00000fffUL ) >= 0x00000800UL )
323
          {
324
            libcnotify_printf(
325
             "%s: cluster: %04d number\t: 0x%03" PRIx32 " (%s)\n",
326
             function,
327
             table_index,
328
             cluster_number & 0x00000fffUL,
329
             libfsfat_debug_print_fat12_cluster_type(
330
              cluster_number & 0x00000fffUL ) );
331
          }
332
          else if( ( cluster_number & 0x00000fffUL ) != 0 )
333
          {
334
            libcnotify_printf(
335
             "%s: cluster: %04d number\t: %" PRIu32 "\n",
336
             function,
337
             table_index,
338
             cluster_number & 0x00000fffUL );
339
          }
340
        }
341
#endif
342
28.7k
        allocation_table->cluster_numbers[ table_index ] = cluster_number & 0x00000fffUL;
343
344
28.7k
        if( ( reversed_allocation_table != NULL )
345
28.7k
         && ( cluster_number < (uint32_t) allocation_table->number_of_cluster_numbers ) )
346
8.29k
        {
347
8.29k
          reversed_allocation_table->cluster_numbers[ cluster_number & 0x00000fffUL ] = table_index;
348
8.29k
        }
349
28.7k
        table_index++;
350
351
28.7k
        if( table_index >= allocation_table->number_of_cluster_numbers )
352
65
        {
353
65
          break;
354
65
        }
355
28.7k
        cluster_number >>= 12;
356
357
#if defined( HAVE_DEBUG_OUTPUT )
358
        if( libcnotify_verbose != 0 )
359
        {
360
          if( cluster_number >= 0x00000800UL )
361
          {
362
            libcnotify_printf(
363
             "%s: cluster: %04d number\t: 0x%03" PRIx32 " (%s)\n",
364
             function,
365
             table_index,
366
             cluster_number,
367
             libfsfat_debug_print_fat12_cluster_type(
368
              cluster_number ) );
369
          }
370
          else if( cluster_number != 0 )
371
          {
372
            libcnotify_printf(
373
             "%s: cluster: %04d number\t: %" PRIu32 "\n",
374
             function,
375
             table_index,
376
             cluster_number );
377
          }
378
        }
379
#endif
380
28.7k
      }
381
592k
      else if( io_handle->file_system_format == LIBFSFAT_FILE_SYSTEM_FORMAT_FAT16 )
382
183k
      {
383
183k
        byte_stream_copy_to_uint16_little_endian(
384
183k
         &( table_data[ table_data_offset ] ),
385
183k
         cluster_number );
386
387
183k
        table_data_offset += 2;
388
389
#if defined( HAVE_DEBUG_OUTPUT )
390
        if( libcnotify_verbose != 0 )
391
        {
392
          if( cluster_number >= 0x00008000UL )
393
          {
394
            libcnotify_printf(
395
             "%s: cluster: %04d number\t: 0x%04" PRIx32 " (%s)\n",
396
             function,
397
             table_index,
398
             cluster_number,
399
             libfsfat_debug_print_fat16_cluster_type(
400
              cluster_number ) );
401
          }
402
          else if( cluster_number != 0 )
403
          {
404
            libcnotify_printf(
405
             "%s: cluster: %04d number\t: %" PRIu32 "\n",
406
             function,
407
             table_index,
408
             cluster_number );
409
          }
410
        }
411
#endif
412
183k
      }
413
409k
      else
414
409k
      {
415
409k
        byte_stream_copy_to_uint32_little_endian(
416
409k
         &( table_data[ table_data_offset ] ),
417
409k
         cluster_number );
418
419
409k
        table_data_offset += 4;
420
421
#if defined( HAVE_DEBUG_OUTPUT )
422
        if( libcnotify_verbose != 0 )
423
        {
424
          if( cluster_number >= 0x08000000UL )
425
          {
426
            if( io_handle->file_system_format == LIBFSFAT_FILE_SYSTEM_FORMAT_FAT32 )
427
            {
428
              libcnotify_printf(
429
               "%s: cluster: %04d number\t: 0x%08" PRIx32 " (%s)\n",
430
               function,
431
               table_index,
432
               cluster_number,
433
               libfsfat_debug_print_fat32_cluster_type(
434
                cluster_number ) );
435
            }
436
            else
437
            {
438
              libcnotify_printf(
439
               "%s: cluster: %04d number\t: 0x%08" PRIx32 " (%s)\n",
440
               function,
441
               table_index,
442
               cluster_number,
443
               libfsfat_debug_print_exfat_cluster_type(
444
                cluster_number ) );
445
            }
446
          }
447
          else if( cluster_number != 0 )
448
          {
449
            libcnotify_printf(
450
             "%s: cluster: %04d number\t: %" PRIu32 "\n",
451
             function,
452
             table_index,
453
             cluster_number );
454
          }
455
        }
456
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
457
409k
      }
458
621k
      allocation_table->cluster_numbers[ table_index ] = cluster_number;
459
460
621k
      if( ( reversed_allocation_table != NULL )
461
621k
       && ( cluster_number < (uint32_t) allocation_table->number_of_cluster_numbers ) )
462
127k
      {
463
127k
        reversed_allocation_table->cluster_numbers[ cluster_number ] = table_index;
464
127k
      }
465
621k
      table_index++;
466
621k
    }
467
3.95k
  }
468
1.68k
  memory_free(
469
1.68k
   table_data );
470
471
#if defined( HAVE_DEBUG_OUTPUT )
472
  if( libcnotify_verbose != 0 )
473
  {
474
    libcnotify_printf(
475
     "\n" );
476
  }
477
#endif
478
1.68k
  return( 1 );
479
480
268
on_error:
481
268
  if( table_data != NULL )
482
268
  {
483
268
    memory_free(
484
268
     table_data );
485
268
  }
486
268
  return( -1 );
487
1.95k
}
488
489
/* Retrieves a specific cluster number from the allocation table
490
 * Returns 1 if successful or -1 on error
491
 */
492
int libfsfat_allocation_table_get_cluster_number_by_index(
493
     libfsfat_allocation_table_t *allocation_table,
494
     int entry_index,
495
     uint32_t *cluster_number,
496
     libcerror_error_t **error )
497
471
{
498
471
  static char *function = "libfsfat_allocation_table_resize";
499
500
471
  if( allocation_table == NULL )
501
0
  {
502
0
    libcerror_error_set(
503
0
     error,
504
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
505
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
506
0
     "%s: invalid allocation table.",
507
0
     function );
508
509
0
    return( -1 );
510
0
  }
511
471
  if( ( entry_index < 0 )
512
471
   || ( entry_index >= allocation_table->number_of_cluster_numbers ) )
513
14
  {
514
14
    libcerror_error_set(
515
14
     error,
516
14
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
517
14
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
518
14
     "%s: invalid entry index value out of bounds.",
519
14
     function );
520
521
14
    return( -1 );
522
14
  }
523
457
  if( cluster_number == NULL )
524
0
  {
525
0
    libcerror_error_set(
526
0
     error,
527
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
528
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
529
0
     "%s: invalid cluster number.",
530
0
     function );
531
532
0
    return( -1 );
533
0
  }
534
457
  *cluster_number = allocation_table->cluster_numbers[ entry_index ];
535
536
457
  return( 1 );
537
457
}
538