GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_partition_offset_calculate.c Lines: 47 108 43.5 %
Date: 2024-03-11 05:15:45 Branches: 50 118 42.4 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** FileX Component                                                       */
16
/**                                                                       */
17
/**   Application Utility                                                 */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define FX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "fx_api.h"
28
#include "fx_utility.h"
29
30
31
/* Define internal data structures.  */
32
33
typedef struct FX_MEDIA_PARTITION_STRUCT
34
{
35
    ULONG fx_media_part_start;
36
    ULONG fx_media_part_size;
37
} FX_MEDIA_PARTITION;
38
39
/* Define internal partition constants. */
40
41
#ifndef FX_MAX_PARTITION_COUNT
42
#define FX_MAX_PARTITION_COUNT              16
43
#endif /* FX_MAX_PARTITION_COUNT */
44
45
#define FX_PARTITION_TABLE_OFFSET           446
46
#define FX_PARTITION_ENTRY_SIZE             16
47
#define FX_PARTITION_TYPE_OFFSET            4
48
#define FX_PARTITION_LBA_OFFSET             8
49
#define FX_PARTITION_SECTORS_OFFSET         12
50
51
#define FX_PARTITION_TYPE_FREE              0x00
52
#define FX_PARTITION_TYPE_EXTENDED          0x05
53
#define FX_PARTITION_TYPE_EXTENDED_LBA      0x0F
54
55
56
/* Define function prototypes for the partition table parsing application
57
   utility.  */
58
59
UINT    _fx_partition_offset_calculate(void  *partition_sector, UINT partition,
60
                                     ULONG *partition_start, ULONG *partition_size);
61
UINT    _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
62
                                UINT *count, ULONG sector, UCHAR *sector_buffer);
63
UINT    _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void  *partition_sector, UINT partition,
64
                                     ULONG *partition_start, ULONG *partition_size);
65
66
/**************************************************************************/
67
/*                                                                        */
68
/*  FUNCTION                                               RELEASE        */
69
/*                                                                        */
70
/*    _fx_partition_offset_calculate                      PORTABLE C      */
71
/*                                                           6.1.6        */
72
/*  AUTHOR                                                                */
73
/*                                                                        */
74
/*    William E. Lamie, Microsoft Corporation                             */
75
/*                                                                        */
76
/*  DESCRIPTION                                                           */
77
/*                                                                        */
78
/*    This function calculates the sector offset to the specified         */
79
/*    partition.  The buffer containing the partition table is also       */
80
/*    supplied to this function.  If the buffer supplied is a boot        */
81
/*    record (which could be the case in non-partition systems), this     */
82
/*    function returns an offset of zero, the total sectors, and a        */
83
/*    successful status indicating that the buffer supplied is the boot   */
84
/*    record.  Otherwise, if a partition is found, this function returns  */
85
/*    the sector offset to its boot record along with a successful        */
86
/*    status. If the specified partition is not found or the buffer is    */
87
/*    not a partition table or boot record, this function returns an      */
88
/*    error.                                                              */
89
/*                                                                        */
90
/*    Note: Empty partitions have a FX_SUCCESS return code, however their */
91
/*          starting sector is FX_NULL and the size returned is 0.        */
92
/*                                                                        */
93
/*  INPUT                                                                 */
94
/*                                                                        */
95
/*    partition_sector                      Pointer to buffer containing  */
96
/*                                            either the partition table  */
97
/*                                            or the boot sector          */
98
/*    partition                             Desired partition             */
99
/*    partition_start                       Return partition start        */
100
/*    partition_size                        Return partition size         */
101
/*                                                                        */
102
/*  OUTPUT                                                                */
103
/*                                                                        */
104
/*    return status                                                       */
105
/*                                                                        */
106
/*  CALLS                                                                 */
107
/*                                                                        */
108
/*     _fx_utility_partition_get            Actual partition parsing      */
109
/*                                            routine                     */
110
/*                                                                        */
111
/*  CALLED BY                                                             */
112
/*                                                                        */
113
/*    Application Driver                                                  */
114
/*                                                                        */
115
/*  RELEASE HISTORY                                                       */
116
/*                                                                        */
117
/*    DATE              NAME                      DESCRIPTION             */
118
/*                                                                        */
119
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
120
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
121
/*                                            resulting in version 6.1    */
122
/*  04-02-2021     William E. Lamie         Modified comment(s),          */
123
/*                                            ignored signature check for */
124
/*                                            no partition situation,     */
125
/*                                            resulting in version 6.1.6  */
126
/*                                                                        */
127
/**************************************************************************/
128
28
UINT  _fx_partition_offset_calculate(void  *partition_sector, UINT partition,
129
                                     ULONG *partition_start, ULONG *partition_size)
130
{
131
132
FX_MEDIA_PARTITION partition_table[4];
133
UINT               count;
134
ULONG64            total_sectors;
135
UCHAR             *partition_sector_ptr;
136
137
138
    /* Setup working pointer and initialize count.  */
139
28
    partition_sector_ptr =  partition_sector;
140
28
    count =  0;
141
142
    /* Check for a real boot sector instead of a partition table.  */
143

28
    if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
144
    {
145
146
        /* Yes, a real boot sector could be present.  */
147
148
        /* See if there are good values for sectors per FAT.  */
149



21
        if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
150
        {
151
152
            /* There are values for sectors per FAT.  */
153
154
            /* Determine if there is a total sector count.  */
155
20
            total_sectors =  0;
156
157

20
            if (partition_sector_ptr[0x13] || partition_sector_ptr[0x14])
158
            {
159
160
                /* Calculate the total sectors, FAT12/16.  */
161
13
                total_sectors =  (((ULONG) partition_sector_ptr[0x14]) << 8) | ((ULONG) partition_sector_ptr[0x13]);
162
            }
163


7
            else if (partition_sector_ptr[0x20] || partition_sector_ptr[0x21] || partition_sector_ptr[0x22] || partition_sector_ptr[0x23])
164
            {
165
166
                /* Calculate the total sectors, FAT32.  */
167
6
                total_sectors =  (((ULONG) partition_sector_ptr[0x23]) << 24) |
168
6
                                 (((ULONG) partition_sector_ptr[0x22]) << 16) |
169
6
                                 (((ULONG) partition_sector_ptr[0x21]) << 8)  |
170
6
                                 ((ULONG) partition_sector_ptr[0x20]);
171
            }
172
173
            /* Determine if there is a total sector count.  */
174
20
            if (total_sectors)
175
            {
176
177
19
                if (partition_start != FX_NULL)
178
                {
179
                    /* Return an offset of 0, size of boot record, and a successful status.  */
180
18
                    *partition_start =  0;
181
                }
182
183
                /* Determine if the total sectors is required.  */
184
19
                if (partition_size != FX_NULL)
185
                {
186
187
                    /* Return the total sectors.  */
188
18
                    *partition_size =  (ULONG)(total_sectors & 0xFFFFFFFF);
189
                }
190
191
                /* Return success!  */
192
19
                return(FX_SUCCESS);
193
            }
194
        }
195
    }
196
197
    /* Check signature to make sure the buffer is valid.  */
198

9
    if ((partition_sector_ptr[510] != 0x55) || (partition_sector_ptr[511] != 0xAA))
199
    {
200
201
        /* Invalid, return an error.  */
202
2
        return(FX_NOT_FOUND);
203
    }
204
205
    /* Not bootable, look for specific partition.  */
206
7
    _fx_utility_partition_get(partition_table, &count, 0, partition_sector_ptr);
207
208
    /* Determine if return value is valid.  */
209
7
    if (partition >= count)
210
    {
211
212
        /* No, return an error.  */
213
5
        return(FX_NOT_FOUND);
214
    }
215
216
    /* Return the partition starting sector, if non-NULL.  */
217
2
    if (partition_start != FX_NULL)
218
    {
219
1
        *partition_start =  partition_table[partition].fx_media_part_start;
220
    }
221
222
    /* Return the partition size, if non-NULL.  */
223
2
    if (partition_size != FX_NULL)
224
    {
225
1
        *partition_size =  partition_table[partition].fx_media_part_size;
226
    }
227
228
    /* Return successful completion.  */
229
2
    return(FX_SUCCESS);
230
}
231
232
233
/**************************************************************************/
234
/*                                                                        */
235
/*  FUNCTION                                               RELEASE        */
236
/*                                                                        */
237
/*    _fx_utility_partition_get                           PORTABLE C      */
238
/*                                                           6.1.6        */
239
/*  AUTHOR                                                                */
240
/*                                                                        */
241
/*    William E. Lamie, Microsoft Corporation                             */
242
/*                                                                        */
243
/*  DESCRIPTION                                                           */
244
/*                                                                        */
245
/*    This function parses the partition sector and completes the         */
246
/*    supplied partition entry structure.                                 */
247
/*                                                                        */
248
/*  INPUT                                                                 */
249
/*                                                                        */
250
/*    partition_table                       Pointer to partition table    */
251
/*    count                                 Number of partitions found    */
252
/*    sector                                Base sector                   */
253
/*    sector_buffer                         Buffer containing partition   */
254
/*                                            table                       */
255
/*                                                                        */
256
/*  OUTPUT                                                                */
257
/*                                                                        */
258
/*    return status                                                       */
259
/*                                                                        */
260
/*  CALLS                                                                 */
261
/*                                                                        */
262
/*    None                                                                */
263
/*                                                                        */
264
/*  CALLED BY                                                             */
265
/*                                                                        */
266
/*    _fx_partition_offset_calculate        Calculate partition offset    */
267
/*                                                                        */
268
/*  RELEASE HISTORY                                                       */
269
/*                                                                        */
270
/*    DATE              NAME                      DESCRIPTION             */
271
/*                                                                        */
272
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
273
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
274
/*                                            resulting in version 6.1    */
275
/*  04-02-2021     William E. Lamie         Modified comment(s),          */
276
/*                                            resulting in version 6.1.6  */
277
/*                                                                        */
278
/**************************************************************************/
279
7
UINT  _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
280
                                UINT *count, ULONG sector, UCHAR *sector_buffer)
281
{
282
283
UINT  i;
284
ULONG base_sector, value;
285
286
    /* This parameter has not been supported yet. */
287
    FX_PARAMETER_NOT_USED(sector);
288
289
    /* Initialize base sector.  */
290
7
    base_sector =  0;
291
292
35
    for(i = 446; i <= 494; i+=16)
293
    {
294
28
        if (sector_buffer[i + 4] == 0) /* no partition entry here */
295
        {
296
297
21
            partition_table[*count].fx_media_part_start = 0;
298
21
            partition_table[*count].fx_media_part_size  = 0;
299
        }
300
        else
301
        {
302
303
7
            value =  (ULONG) sector_buffer[i + 8]; /* little endian start value */
304
7
            value =  (((ULONG) sector_buffer[i + 9]) << 8) | value;
305
7
            value =  (((ULONG) sector_buffer[i + 10]) << 16) | value;
306
7
            value =  (((ULONG) sector_buffer[i + 11]) << 24) | value;
307
7
            partition_table[*count].fx_media_part_start = value + base_sector;
308
309
7
            value =  (ULONG) sector_buffer[i + 12]; /* little endian size value */
310
7
            value =  (((ULONG) sector_buffer[i + 13]) << 8) | value;
311
7
            value =  (((ULONG) sector_buffer[i + 14]) << 16) | value;
312
7
            value =  (((ULONG) sector_buffer[i + 15]) << 24) | value;
313
7
            partition_table[*count].fx_media_part_size = value;
314
        }
315
316
28
        (*count)++;
317
    }
318
319
    /* Return success.  */
320
7
    return(FX_SUCCESS);
321
}
322
323
/**************************************************************************/
324
/*                                                                        */
325
/*  FUNCTION                                               RELEASE        */
326
/*                                                                        */
327
/*    _fx_partition_offset_calculate_extended             PORTABLE C      */
328
/*                                                           6.2.0        */
329
/*  AUTHOR                                                                */
330
/*                                                                        */
331
/*    Xiuwen Cai, Microsoft Corporation                                   */
332
/*                                                                        */
333
/*  DESCRIPTION                                                           */
334
/*                                                                        */
335
/*    This function calculates the sector offset to the specified         */
336
/*    partition.  The buffer containing the partition table is also       */
337
/*    supplied to this function.  If the buffer supplied is a boot        */
338
/*    record (which could be the case in non-partition systems), this     */
339
/*    function returns an offset of zero, the total sectors, and a        */
340
/*    successful status indicating that the buffer supplied is the boot   */
341
/*    record.  Otherwise, if a partition is found, this function returns  */
342
/*    the sector offset to its boot record along with a successful        */
343
/*    status. If the specified partition is not found or the buffer is    */
344
/*    not a partition table or boot record, this function returns an      */
345
/*    error.                                                              */
346
/*                                                                        */
347
/*    Note: Empty partitions have a FX_NOT_FOUND return code.             */
348
/*      Use partition index 0 to 3 for primary partition and index 4 to   */
349
/*      FX_MAX_PARTITION_COUNT for extended partition.                    */
350
/*                                                                        */
351
/*  INPUT                                                                 */
352
/*                                                                        */
353
/*    media_ptr                             Media control block pointer   */
354
/*    partition_sector                      Pointer to buffer containing  */
355
/*                                            either the partition table  */
356
/*                                            or the boot sector          */
357
/*    partition                             Desired partition             */
358
/*    partition_start                       Return partition start        */
359
/*    partition_size                        Return partition size         */
360
/*                                                                        */
361
/*  OUTPUT                                                                */
362
/*                                                                        */
363
/*    return status                                                       */
364
/*                                                                        */
365
/*  CALLS                                                                 */
366
/*                                                                        */
367
/*    _fx_utility_16_unsigned_read          Read a USHORT from memory     */
368
/*    _fx_utility_32_unsigned_read          Read a ULONG from memory      */
369
/*    _fx_utility_64_unsigned_read          Read a ULONG64 from memory    */
370
/*    Media driver                                                        */
371
/*                                                                        */
372
/*  CALLED BY                                                             */
373
/*                                                                        */
374
/*    Application Driver                                                  */
375
/*                                                                        */
376
/*  RELEASE HISTORY                                                       */
377
/*                                                                        */
378
/*    DATE              NAME                      DESCRIPTION             */
379
/*                                                                        */
380
/*  10-31-2022     Xiuwen Cai               Initial Version 6.2.0        */
381
/*                                                                        */
382
/**************************************************************************/
383
UINT  _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void  *partition_sector, UINT partition,
384
                                     ULONG *partition_start, ULONG *partition_size)
385
{
386
387
ULONG64 total_sectors;
388
UCHAR  *partition_sector_ptr;
389
UCHAR   partition_type;
390
UINT    i;
391
ULONG   base_sector;
392
ULONG   base_sector_extended;
393
394
395
    /* Setup working pointer.  */
396
    partition_sector_ptr =  partition_sector;
397
398
    /* Check for a real boot sector instead of a partition table.  */
399
    if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
400
    {
401
402
        /* Yes, a real boot sector could be present.  */
403
404
        /* See if there are good values for sectors per FAT.  */
405
        if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
406
        {
407
408
            /* There are values for sectors per FAT.  */
409
410
            /* Get the total sectors, FAT12/16.  */
411
            total_sectors =  _fx_utility_16_unsigned_read(&partition_sector_ptr[FX_SECTORS]);
412
413
            if (total_sectors == 0)
414
            {
415
416
                /* Get the total sectors, FAT32.  */
417
                total_sectors = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_HUGE_SECTORS]);
418
            }
419
420
            /* Determine if there is a total sector count.  */
421
            if (total_sectors)
422
            {
423
424
                if (partition_start != FX_NULL)
425
                {
426
                    /* Return an offset of 0, size of boot record, and a successful status.  */
427
                    *partition_start =  0;
428
                }
429
430
                /* Determine if the total sectors is required.  */
431
                if (partition_size != FX_NULL)
432
                {
433
434
                    /* Return the total sectors.  */
435
                    *partition_size =  (ULONG)(total_sectors & 0xFFFFFFFF);
436
                }
437
438
                /* Return success!  */
439
                return(FX_SUCCESS);
440
            }
441
        }
442
    }
443
444
    /* Check signature to make sure the buffer is valid.  */
445
    if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
446
    {
447
448
        /* Invalid, return an error.  */
449
        return(FX_NOT_FOUND);
450
    }
451
452
    /* Not bootable, look for specific partition.  */
453
454
    /* Check if primary partitions are addressed.  */
455
    if (partition < 4)
456
    {
457
458
        /* Get partition type.  */
459
        partition_type =  partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
460
461
        /* Check if there is a vaild partition.  */
462
        if (partition_type != FX_PARTITION_TYPE_FREE)
463
        {
464
465
            /* Return the partition starting sector, if non-NULL.  */
466
            if (partition_start != FX_NULL)
467
            {
468
                *partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]);
469
            }
470
471
            /* Return the partition size, if non-NULL.  */
472
            if (partition_size != FX_NULL)
473
            {
474
                *partition_size =  _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_SECTORS_OFFSET]);
475
            }
476
477
            /* Return success!  */
478
            return(FX_SUCCESS);
479
        }
480
        else
481
        {
482
483
            /* Not partition here.  */
484
            return(FX_NOT_FOUND);
485
        }
486
    }
487
488
    /* Check for invalid parameter.  */
489
    if (partition > FX_MAX_PARTITION_COUNT)
490
    {
491
492
        /* Return error.  */
493
        return(FX_NOT_FOUND);
494
    }
495
496
    base_sector = 0;
497
498
    /* Loop to find the extended partition table.  */
499
    for(i = FX_PARTITION_TABLE_OFFSET; i <= FX_PARTITION_TABLE_OFFSET + 3 * FX_PARTITION_ENTRY_SIZE; i += FX_PARTITION_ENTRY_SIZE)
500
    {
501
502
        /* Get partition type.  */
503
        partition_type =  partition_sector_ptr[i + FX_PARTITION_TYPE_OFFSET];
504
        if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
505
        {
506
            base_sector =  _fx_utility_32_unsigned_read(&partition_sector_ptr[i + FX_PARTITION_LBA_OFFSET]);
507
            break;
508
        }
509
    }
510
511
    if (base_sector == 0)
512
    {
513
514
        /* No extended partition.  */
515
        return(FX_NOT_FOUND);
516
    }
517
518
    base_sector_extended = base_sector;
519
520
    for (i = 4; i <= partition; i++)
521
    {
522
523
        /* Read the partition sector from the device.  Build the read sector
524
            command.  */
525
        media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
526
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
527
        media_ptr -> fx_media_driver_buffer =           partition_sector_ptr;
528
        media_ptr -> fx_media_driver_logical_sector =   base_sector;
529
        media_ptr -> fx_media_driver_sectors =          1;
530
        media_ptr -> fx_media_driver_sector_type =      FX_UNKNOWN_SECTOR;
531
        media_ptr -> fx_media_hidden_sectors =          0;
532
533
        /* Invoke the driver to read the sector.  */
534
        (media_ptr -> fx_media_driver_entry) (media_ptr);
535
536
        /* Determine if the sector was read correctly. */
537
        if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
538
        {
539
540
            /* Return error.  */
541
            return(FX_IO_ERROR);
542
        }
543
544
        /* Check signature to make sure the sector is valid.  */
545
        if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
546
        {
547
548
            /* Invalid, return an error.  */
549
            return(FX_NOT_FOUND);
550
        }
551
552
        /* Determine if this is the desired partition.  */
553
        if (i == partition)
554
        {
555
556
            /* Get partition type.  */
557
            partition_type =  partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_TYPE_OFFSET];
558
            if (partition_type != FX_PARTITION_TYPE_FREE)
559
            {
560
561
                /* Return the partition starting sector, if non-NULL.  */
562
                if (partition_start != FX_NULL)
563
                {
564
                    *partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_LBA_OFFSET]) + base_sector;
565
                }
566
567
                /* Return the partition size, if non-NULL.  */
568
                if (partition_size != FX_NULL)
569
                {
570
                    *partition_size =  _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_SECTORS_OFFSET]);
571
                }
572
573
                /* Return success!  */
574
                return(FX_SUCCESS);
575
            }
576
            else
577
            {
578
                /* Not partition here.  */
579
                return(FX_NOT_FOUND);
580
            }
581
        }
582
        else
583
        {
584
585
            /* Get partition type.  */
586
            partition_type =  partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
587
            if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
588
            {
589
590
                /* Update sector number for next partition table.  */
591
                base_sector =  _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]) + base_sector_extended;
592
            }
593
            else
594
            {
595
                /* No valid partition, get out of the loop.  */
596
                break;
597
            }
598
        }
599
600
    }
601
602
    /* Return error.  */
603
    return(FX_NOT_FOUND);
604
}