GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_FAT_flush.c Lines: 140 140 100.0 %
Date: 2026-03-06 18:49:02 Branches: 60 60 100.0 %

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