GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_FAT_flush.c Lines: 140 140 100.0 %
Date: 2024-03-11 05:15:45 Branches: 60 60 100.0 %

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
/**   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_system.h"
29
#include "fx_utility.h"
30
31
32
/**************************************************************************/
33
/*                                                                        */
34
/*  FUNCTION                                               RELEASE        */
35
/*                                                                        */
36
/*    _fx_utility_FAT_flush                               PORTABLE C      */
37
/*                                                           6.1.2        */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    William E. Lamie, Microsoft Corporation                             */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function flushes the contents of the FAT cache to the media.   */
45
/*    12-bit, 16-bit and 32-bit FAT writing is supported.                 */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    media_ptr                             Media control block pointer   */
50
/*                                                                        */
51
/*  OUTPUT                                                                */
52
/*                                                                        */
53
/*    return status                                                       */
54
/*                                                                        */
55
/*  CALLS                                                                 */
56
/*                                                                        */
57
/*    _fx_utility_16_unsigned_write         Write a UINT into buffer      */
58
/*    _fx_utility_32_unsigned_read          Read a ULONG from buffer      */
59
/*    _fx_utility_32_unsigned_write         Write a ULONG into buffer     */
60
/*    _fx_utility_logical_sector_read       Read FAT sector into memory   */
61
/*    _fx_utility_logical_sector_write      Write FAT sector back to disk */
62
/*                                                                        */
63
/*  CALLED BY                                                             */
64
/*                                                                        */
65
/*    FileX System Functions                                              */
66
/*                                                                        */
67
/*  RELEASE HISTORY                                                       */
68
/*                                                                        */
69
/*    DATE              NAME                      DESCRIPTION             */
70
/*                                                                        */
71
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
72
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
73
/*                                            resulting in version 6.1    */
74
/*  11-09-2020     William E. Lamie         Modified comment(s),          */
75
/*                                            updated logic for           */
76
/*                                            FAT secondary update map,   */
77
/*                                            resulting in version 6.1.2  */
78
/*                                                                        */
79
/**************************************************************************/
80
471818
UINT  _fx_utility_FAT_flush(FX_MEDIA *media_ptr)
81
{
82
83
ULONG  FAT_sector;
84
ULONG  byte_offset;
85
UCHAR *FAT_ptr;
86
UINT   temp, i;
87
UINT   status, index, ind;
88
ULONG  cluster, next_cluster;
89
UCHAR  sectors_per_bit;
90
INT    multi_sector_entry;
91
ULONG  sector;
92
93
#ifndef FX_MEDIA_STATISTICS_DISABLE
94
    /* Increment the number of cache flush requests.  */
95
471818
    media_ptr -> fx_media_fat_cache_flushes++;
96
#endif
97
98
    /* Loop through the media's FAT cache and flush out dirty entries.  */
99
26793961
    for (index = 0; index < FX_MAX_FAT_CACHE; index++)
100
    {
101
102
        /* Determine if the entry is dirty.  */
103
26389883
        if ((media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_dirty) == 0)
104
        {
105
106
            /* No, just advance to the next entry.  */
107
25945006
            continue;
108
        }
109
110
        /* Otherwise, the entry is indeed dirty and must be flushed out.  Process
111
           relative to the type of FAT that is being used.  */
112
113
        /* Pickup the contents of the FAT cache entry.  */
114
444877
        cluster =       media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_cluster;
115
116
        /* Determine which type of FAT is present.  */
117
444877
        if (media_ptr -> fx_media_12_bit_FAT)
118
        {
119
120
            /* Calculate the byte offset to the cluster entry.  */
121
42809
            byte_offset =  (((ULONG)cluster << 1) + cluster) >> 1;
122
123
            /* Calculate the FAT sector the requested FAT entry resides in.  */
124
42809
            FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
125
42809
                (ULONG)media_ptr -> fx_media_reserved_sectors;
126
127
            /* Initialize as not written.  */
128
42809
            multi_sector_entry = -1;
129
130
            for (;;)
131
            {
132
133
                /* Pickup the FAT sector.  */
134
7777
                status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
135
50586
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
136
137
                /* Determine if an error occurred.  */
138
50586
                if (status != FX_SUCCESS)
139
                {
140
141
                    /* Return the error status.  */
142
19464
                    return(status);
143
                }
144
145
                /* Determine if a mulit-sector FAT update is present.  */
146
31122
                if (multi_sector_entry != -1)
147
                {
148
149
                    /* Yes, store the remaining portion of the new FAT entry in the
150
                       next FAT sector.  */
151
152
                    /* Setup a pointer into the buffer.  */
153
4191
                    FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer;
154
155
                    /* Pickup the cluster and next cluster.  */
156
4191
                    cluster = (media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_cluster);
157
4191
                    next_cluster = media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_value;
158
159
                    /* Determine if the cluster entry is odd or even.  */
160
4191
                    if (cluster & 1)
161
                    {
162
163
                        /* Store the upper 8 bits of the FAT entry.  */
164
2215
                        *FAT_ptr =  (UCHAR)((next_cluster >> 4) & 0xFF);
165
                    }
166
                    else
167
                    {
168
169
                        /* Store the upper 4 bits of the FAT entry.  */
170
1976
                        temp =  ((UINT)*FAT_ptr) & 0xF0;
171
1976
                        *FAT_ptr =  (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
172
                    }
173
174
                    /* Clear the multi-sector flag.  */
175
4191
                    multi_sector_entry = -1;
176
                }
177
178
                /* Loop through the remainder of the cache to check for multiple entries
179
                   within the same FAT sector being written out.  */
180
1943515
                for (i = index; i < FX_MAX_FAT_CACHE; i++)
181
                {
182
183
                    /* Is the cache entry dirty?  */
184
1912393
                    if ((media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty) == 0)
185
                    {
186
187
                        /* Not dirty, does not need to be flushed.  */
188
566837
                        continue;
189
                    }
190
191
                    /* Isolate the cluster.  */
192
1345556
                    cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
193
194
                    /* Calculate the byte offset to the cluster entry.  */
195
1345556
                    byte_offset =  (((ULONG)cluster << 1) + cluster) >> 1;
196
197
                    /* Pickup the sector.  */
198
1345556
                    sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
199
1345556
                        (ULONG)media_ptr -> fx_media_reserved_sectors;
200
201
                    /* Is it the current FAT sector?  */
202
1345556
                    if (sector != FAT_sector)
203
                    {
204
205
                        /* Different FAT sector - not in this pass of the loop.  */
206
346287
                        continue;
207
                    }
208
209
                    /* Pickup new value for this FAT entry.  */
210
999269
                    next_cluster =  media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
211
212
                    /* Now calculate the byte offset into this FAT sector.  */
213
999269
                    byte_offset =  byte_offset -
214
999269
                        ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
215
999269
                         media_ptr -> fx_media_bytes_per_sector);
216
217
                    /* Determine if we are now past the end of the FAT buffer in memory.  */
218
999269
                    if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
219
                    {
220
221
                        /* Yes, we need to read the next sector */
222
7777
                        multi_sector_entry = (INT)i;
223
                    }
224
225
                    /* Setup a pointer into the buffer.  */
226
999269
                    FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
227
228
                    /* Clear the dirty flag.  */
229
999269
                    media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
230
231
                    /* Determine if the cluster entry is odd or even.  */
232
999269
                    if (cluster & 1)
233
                    {
234
235
                        /* Odd cluster number.  */
236
237
                        /* Pickup the upper nibble of the FAT entry.  */
238
239
                        /* First, set the lower nibble of the FAT entry.  */
240
500112
                        temp =      (((UINT)*FAT_ptr) & 0x0F);
241
500112
                        *FAT_ptr =  (UCHAR)(temp | ((next_cluster << 4) & 0xF0));
242
243
                        /* Determine if this is a mulit-sector entry.  */
244
500112
                        if ((multi_sector_entry) == (INT)i)
245
                        {
246
247
                            /* Yes, requires multiple sector - will write rest of the part later.  */
248
4143
                            continue;
249
                        }
250
251
                        /* Move to the next byte of the FAT entry.  */
252
495969
                        FAT_ptr++;
253
254
                        /* Store the upper 8 bits of the FAT entry.  */
255
495969
                        *FAT_ptr =  (UCHAR)((next_cluster >> 4) & 0xFF);
256
                    }
257
                    else
258
                    {
259
260
                        /* Even cluster number.  */
261
262
                        /* Store the lower byte of the FAT entry.  */
263
499157
                        *FAT_ptr =  (UCHAR)(next_cluster & 0xFF);
264
265
                        /* Determine if this is a mulit-sector entry.  */
266
499157
                        if ((multi_sector_entry) == (INT)i)
267
                        {
268
269
                            /* Yes, requires multiple sector - will write rest of the part later.  */
270
3634
                            continue;
271
                        }
272
273
                        /* Move to the next nibble of the FAT entry.  */
274
495523
                        FAT_ptr++;
275
276
                        /* Store the upper 4 bits of the FAT entry.  */
277
495523
                        temp =  ((UINT)*FAT_ptr) & 0xF0;
278
495523
                        *FAT_ptr =  (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
279
                    }
280
                }
281
282
                /* First, write out the current sector. */
283
31122
                status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
284
31122
                                                           media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
285
                /* Determine if an error occurred.  */
286
31122
                if (status != FX_SUCCESS)
287
                {
288
289
                    /* Return the error status.  */
290
1
                    return(status);
291
                }
292
293
                /* Mark the FAT sector update bit map to indicate this sector has been written.  */
294
31121
                if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
295
                {
296
30762
                    sectors_per_bit =  (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
297
                }
298
                else
299
                {
300
359
                    sectors_per_bit =  (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3) + 1);
301
                }
302
303
                /* Check for invalid value.  */
304
31121
                if (sectors_per_bit == 0)
305
                {
306
307
                    /* Invalid media, return error.  */
308
1
                    return(FX_MEDIA_INVALID);
309
                }
310
311
31120
                ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
312
31120
                media_ptr -> fx_media_fat_secondary_update_map[ind] =
313
31120
                    (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
314
31120
                    | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
315
316
                /* Determine if the multi-sector flag is set.  */
317
31120
                if (multi_sector_entry != -1)
318
                {
319
320
                    /* Yes, position to the next sector and read it in.  */
321
7777
                    FAT_sector++;
322
                }
323
                else
324
                {
325
326
                    /* No, we are finished with this loop.   */
327
23343
                    break;
328
                }
329
            }
330
        }
331
402068
        else if (!media_ptr -> fx_media_32_bit_FAT)
332
        {
333
334
            /* 16-bit FAT is present.  */
335
336
            /* Calculate the byte offset to the cluster entry.  */
337
322340
            byte_offset =  (((ULONG)cluster) << 1);
338
339
            /* Calculate the FAT sector the requested FAT entry resides in.  */
340
322340
            FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
341
322340
                (ULONG)media_ptr -> fx_media_reserved_sectors;
342
343
            /* Read the FAT sector.  */
344
322340
            status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
345
322340
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
346
347
            /* Determine if an error occurred.  */
348
322340
            if (status != FX_SUCCESS)
349
            {
350
351
                /* Return the error status.  */
352
19548
                return(status);
353
            }
354
355
            /* Loop through the remainder of the cache to check for multiple entries
356
               within the same FAT sector being written out.  */
357
11884775
            for (i = index; i < FX_MAX_FAT_CACHE; i++)
358
            {
359
360
                /* Determine if the entry is dirty.  */
361
11581983
                if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
362
                {
363
364
                    /* Not dirty, does not need to be flushed.  */
365
9622433
                    continue;
366
                }
367
368
                /* Isolate the cluster.  */
369
1959550
                cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
370
371
                /* Calculate the byte offset to the cluster entry.  */
372
1959550
                byte_offset =  (((ULONG)cluster) * 2);
373
374
                /* Pickup the sector.  */
375
1959550
                sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
376
1959550
                    (ULONG)media_ptr -> fx_media_reserved_sectors;
377
378
                /* Is it the current FAT sector?  */
379
1959550
                if (sector != FAT_sector)
380
                {
381
382
                    /* Different FAT sector - not in this pass of the loop.  */
383
561471
                    continue;
384
                }
385
386
                /* Now calculate the byte offset into this FAT sector.  */
387
1398079
                byte_offset =  byte_offset -
388
1398079
                    ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
389
1398079
                     media_ptr -> fx_media_bytes_per_sector);
390
391
                /* Setup a pointer into the buffer.  */
392
1398079
                FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
393
394
                /* Pickup new value for this FAT entry.  */
395
1398079
                next_cluster =  media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
396
397
                /* Store the FAT entry.  */
398
1398079
                _fx_utility_16_unsigned_write(FAT_ptr, (UINT)next_cluster);
399
400
                /* Clear the dirty flag.  */
401
1398079
                media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
402
            }
403
404
            /* Write the last written FAT sector out.  */
405
302792
            status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
406
302792
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
407
408
            /* Determine if an error occurred.  */
409
302792
            if (status != FX_SUCCESS)
410
            {
411
                /* Return the error status.  */
412
1
                return(status);
413
            }
414
415
            /* Mark the FAT sector update bit map to indicate this sector has been
416
               written.  */
417
302791
            if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
418
            {
419
3
                sectors_per_bit =  (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
420
            }
421
            else
422
            {
423
302788
                sectors_per_bit =  (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
424
            }
425
302791
            ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
426
302791
            media_ptr -> fx_media_fat_secondary_update_map[ind] =
427
302791
                (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
428
302791
                | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
429
        }
430
        else
431
        {
432
433
            /* 32-bit FAT is present.  */
434
435
            /* Calculate the byte offset to the cluster entry.  */
436
79728
            byte_offset =  (((ULONG)cluster) * 4);
437
438
            /* Calculate the FAT sector the requested FAT entry resides in.  */
439
79728
            FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
440
79728
                (ULONG)media_ptr -> fx_media_reserved_sectors;
441
442
            /* Read the FAT sector.  */
443
79728
            status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
444
79728
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
445
446
            /* Determine if an error occurred.  */
447
79728
            if (status != FX_SUCCESS)
448
            {
449
450
                /* Return the error status.  */
451
28724
                return(status);
452
            }
453
454
            /* Loop through the remainder of the cache to check for multiple entries
455
               within the same FAT sector being written out.  */
456
2997881
            for (i = index; i < FX_MAX_FAT_CACHE; i++)
457
            {
458
459
                /* Determine if the entry is dirty.  */
460
2946877
                if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
461
                {
462
463
                    /* Not dirty, does not need to be flushed.  */
464
867904
                    continue;
465
                }
466
467
                /* Isolate the cluster.  */
468
2078973
                cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
469
470
                /* Calculate the byte offset to the cluster entry.  */
471
2078973
                byte_offset =  (((ULONG)cluster) * 4);
472
473
                /* Pickup the sector.  */
474
2078973
                sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
475
2078973
                    (ULONG)media_ptr -> fx_media_reserved_sectors;
476
477
                /* Is it the current FAT sector?  */
478
2078973
                if (sector != FAT_sector)
479
                {
480
481
                    /* Different FAT sector - not in this pass of the loop.  */
482
1004363
                    continue;
483
                }
484
485
                /* Now calculate the byte offset into this FAT sector.  */
486
1074610
                byte_offset =  byte_offset -
487
1074610
                    ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
488
1074610
                     media_ptr -> fx_media_bytes_per_sector);
489
490
                /* Setup a pointer into the buffer.  */
491
1074610
                FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
492
493
                /* Pickup new value for this FAT entry.  */
494
1074610
                next_cluster =  media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
495
496
                /* Store the FAT entry.  */
497
1074610
                _fx_utility_32_unsigned_write(FAT_ptr, next_cluster);
498
499
                /* Clear the dirty flag.  */
500
1074610
                media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
501
            }
502
503
            /* Write the last written FAT sector out.  */
504
51004
            status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
505
51004
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
506
507
            /* Determine if an error occurred.  */
508
51004
            if (status != FX_SUCCESS)
509
            {
510
511
                /* Return the error status.  */
512
1
                return(status);
513
            }
514
515
516
            /* Mark the FAT sector update bit map to indicate this sector has been
517
               written.  */
518
51003
            if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
519
            {
520
46254
                sectors_per_bit =  (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
521
            }
522
            else
523
            {
524
4749
                sectors_per_bit =  (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
525
            }
526
51003
            ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
527
51003
            media_ptr -> fx_media_fat_secondary_update_map[ind] =
528
51003
                (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
529
51003
                | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
530
        }
531
    }
532
533
#ifdef FX_ENABLE_FAULT_TOLERANT
534
535
    /* While fault_tolerant is enabled, this function will be called before the return of all APIs. */
536
    if (media_ptr -> fx_media_fault_tolerant_enabled)
537
    {
538
539
        /* Delete the record of FAT sector since all FAT entries are flushed. */
540
        media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = 0;
541
    }
542
#endif /* FX_ENABLE_FAULT_TOLERANT */
543
544
    /* Return successful status.  */
545
404078
    return(FX_SUCCESS);
546
}
547