GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_media_check.c Lines: 141 141 100.0 %
Date: 2024-01-10 21:53:23 Branches: 76 76 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
10
/**************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Media                                                               */
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_directory.h"
31
#include "fx_media.h"
32
#include "fx_utility.h"
33
#ifdef FX_ENABLE_EXFAT
34
#include "fx_directory_exFAT.h"
35
#endif /* FX_ENABLE_EXFAT */
36
37
38
/* Define parameters for FileX media check utility.  */
39
40
#ifndef FX_MAX_DIRECTORY_NESTING
41
#define FX_MAX_DIRECTORY_NESTING 20
42
#endif
43
44
45
/* Define data structures local to the FileX media check utility.  */
46
47
typedef struct CURRENT_DIRECTORY_ENTRY_STRUCT
48
{
49
    ULONG current_directory_entry;
50
    ULONG current_total_entries;
51
    ULONG current_start_cluster;
52
} CURRENT_DIRECTORY_ENTRY;
53
54
55
/**************************************************************************/
56
/*                                                                        */
57
/*  FUNCTION                                               RELEASE        */
58
/*                                                                        */
59
/*    _fx_media_check                                     PORTABLE C      */
60
/*                                                           6.1          */
61
/*  AUTHOR                                                                */
62
/*                                                                        */
63
/*    William E. Lamie, Microsoft Corporation                             */
64
/*                                                                        */
65
/*  DESCRIPTION                                                           */
66
/*                                                                        */
67
/*    This function checks the specified media for basic structural       */
68
/*    errors, including cross linking, invalid FAT chains, and lost       */
69
/*    clusters. The function also provides the capability to correct      */
70
/*    errors.                                                             */
71
/*                                                                        */
72
/*    The algorithm is to follow all sub-directories immediately and      */
73
/*    check their contents. The maximum depth of sub-directories is       */
74
/*    determined by the constant FX_MAX_DIRECTORY_NESTING.                */
75
/*    By default, this is set at 20. Basically, the FAT chain of every    */
76
/*    file and sub-directory is traversed. If valid, clusters are marked  */
77
/*    in a logical FAT bit map to signal they are already in-use. The     */
78
/*    algorithm should detect any broken or cross linked FAT condition.   */
79
/*                                                                        */
80
/*    As for memory usage, the scratch memory supplied to the media check */
81
/*    function is used to hold several directory entries, a data          */
82
/*    structure to "stack" the current directory entry position before    */
83
/*    diving into the sub-directory, and finally the logical FAT bit map. */
84
/*    The basic data structures take from 512-1024 bytes and the logical  */
85
/*    FAT bit map requires as many bits as there are clusters in your     */
86
/*    device. For example, a device with 8000 clusters would require      */
87
/*    1000 bytes to represent.                                            */
88
/*                                                                        */
89
/*    On the performance end of things, the traversal is reasonably fast  */
90
/*    and is basically linear with the number of files and their sizes.   */
91
/*    The lost cluster checking at the end of media check is a bit more   */
92
/*    performance comprehensive. It basically checks that each unused     */
93
/*    cluster is actually marked as free. You might decide to bypass this */
94
/*    step if no other errors are found... or there might be ways to      */
95
/*    optimize the search by reading whole FAT sectors. You probably just */
96
/*    need to see how it behaves in your system.                          */
97
/*                                                                        */
98
/*  INPUT                                                                 */
99
/*                                                                        */
100
/*    media_ptr                             Pointer to a previously       */
101
/*                                            opened media                */
102
/*    scratch_memory_ptr                    Pointer to memory area for    */
103
/*                                            media check to use (as      */
104
/*                                            mentioned above)            */
105
/*    scratch_memory_size                   Size of the scratch memory    */
106
/*    error_correction_option               Specifies which - if any -    */
107
/*                                            errors are corrected by     */
108
/*                                            the media check function.   */
109
/*                                            Setting the following bit   */
110
/*                                            causes that error to be     */
111
/*                                            corrected:                  */
112
/*                                                                        */
113
/*                                            0x01 -> Fix FAT Chain Errors*/
114
/*                                            0x02 -> Fix Directory Entry */
115
/*                                                      Errors            */
116
/*                                            0x04 -> Fix Lost Clusters   */
117
/*                                                                        */
118
/*    errors_detected                       Specifies the destination     */
119
/*                                            ULONG to place the error    */
120
/*                                            report from media check.    */
121
/*                                            This has a similar bit map  */
122
/*                                            as before:                  */
123
/*                                                                        */
124
/*                                            0x01 -> FAT Chain Error(s)  */
125
/*                                            0x02 -> Directory Entry     */
126
/*                                                      Error(s)          */
127
/*                                            0x04 -> Lost Cluster(s)     */
128
/*                                                                        */
129
/*  OUTPUT                                                                */
130
/*                                                                        */
131
/*    FX_SUCCESS                            Media check performed its     */
132
/*                                            operation successfully.     */
133
/*                                            This does not mean that     */
134
/*                                            there were no errors. The   */
135
/*                                            errors_detected variable    */
136
/*                                            needs to be examined.       */
137
/*    FX_MEDIA_NOT_OPEN                     The media was not open.       */
138
/*    FX_NOT_ENOUGH_MEMORY                  The scratch memory was not    */
139
/*                                            large enough or the nesting */
140
/*                                            depth was greater than the  */
141
/*                                            maximum specified.          */
142
/*    FX_IO_ERROR                           I/O Error reading/writing to  */
143
/*                                            the media.                  */
144
/*    FX_ERROR_NOT_FIXED                    Fundamental problem with      */
145
/*                                            media that couldn't be fixed*/
146
/*                                                                        */
147
/*  CALLS                                                                 */
148
/*                                                                        */
149
/*    _fx_media_cache_invalidate            Invalidate the cache          */
150
/*    _fx_media_check_FAT_chain_check       Walk the supplied FAT chain   */
151
/*    _fx_media_check_lost_cluster_check    Check for lost clusters       */
152
/*    _fx_directory_entry_read              Directory entry read          */
153
/*    _fx_directory_entry_write             Directory entry write         */
154
/*    _fx_media_flush                       Flush changes to the media    */
155
/*    _fx_utility_FAT_entry_write           Write value to FAT entry      */
156
/*                                                                        */
157
/*  CALLED BY                                                             */
158
/*                                                                        */
159
/*    Application Code                                                    */
160
/*                                                                        */
161
/*  RELEASE HISTORY                                                       */
162
/*                                                                        */
163
/*    DATE              NAME                      DESCRIPTION             */
164
/*                                                                        */
165
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
166
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
167
/*                                            resulting in version 6.1    */
168
/*                                                                        */
169
/**************************************************************************/
170
2036
UINT  _fx_media_check(FX_MEDIA *media_ptr, UCHAR *scratch_memory_ptr, ULONG scratch_memory_size, ULONG error_correction_option, ULONG *errors_detected)
171
{
172
173
CURRENT_DIRECTORY_ENTRY *current_directory;
174
ULONG                    total_entries, last_cluster, valid_clusters;
175
ULONG                    bytes_per_cluster, i, current_errors;
176
UINT                     status, long_name_size;
177
UINT                     current_directory_index;
178
UCHAR                   *logical_fat, *working_ptr;
179
ALIGN_TYPE               address_mask;
180
FX_DIR_ENTRY            *temp_dir_ptr, *source_dir_ptr, *dir_entry_ptr;
181
182
#ifdef TX_ENABLE_EVENT_TRACE
183
TX_TRACE_BUFFER_ENTRY   *trace_event;
184
ULONG                    trace_timestamp;
185
#endif
186
187
#ifdef FX_ENABLE_EXFAT
188
    current_errors = 0;
189
#endif
190
191
    /* Check the media to make sure it is open.  */
192
2036
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
193
    {
194
195
        /* Return the media not opened error.  */
196
1
        return(FX_MEDIA_NOT_OPEN);
197
    }
198
199
    /* If trace is enabled, insert this event into the trace buffer.  */
200
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CHECK, media_ptr, scratch_memory_ptr, scratch_memory_size, 0, FX_TRACE_MEDIA_EVENTS, &trace_event, &trace_timestamp)
201
202
    /* Protect against other threads accessing the media.  */
203
2035
    FX_PROTECT
204
205
    /* Determine if there are any opened files.  */
206
2035
    if (media_ptr -> fx_media_opened_file_count)
207
    {
208
209
        /* There are opened files... this is an error!  */
210
211
        /* Release protection.  */
212
1
        FX_UNPROTECT
213
214
        /* Return an error.  */
215
1
        return(FX_ACCESS_ERROR);
216
    }
217
218
    /* Invalidate the cache.  */
219
2034
    _fx_media_cache_invalidate(media_ptr);
220
221
    /* Initialize the reported error flag.  */
222
2034
    *errors_detected =  0;
223
224
    /* Calculate the long name size, rounded up to something that is evenly divisible by 4.  */
225
2034
    long_name_size =  (((FX_MAX_LONG_NAME_LEN + 3) >> 2) << 2);
226
227
    /* Calculate the number of bytes per cluster.  */
228
2034
    bytes_per_cluster =  media_ptr -> fx_media_sectors_per_cluster * media_ptr -> fx_media_bytes_per_sector;
229
230
    /* Setup address mask.  */
231
2034
    address_mask =  sizeof(ULONG) - 1;
232
2034
    address_mask =  ~address_mask;
233
234
    /* Setup working pointer.  */
235
2034
    working_ptr =  scratch_memory_ptr + (sizeof(ULONG) - 1);
236
2034
    working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
237
238
    /* Memory is set aside for two FX_DIR_ENTRY structures */
239
2034
    dir_entry_ptr =  (FX_DIR_ENTRY *)working_ptr;
240
241
    /* Adjust the scratch memory pointer forward.  */
242
2034
    working_ptr =  &working_ptr[sizeof(FX_DIR_ENTRY)];
243
244
    /* Setup the name buffer for the first directory entry.  */
245
2034
    dir_entry_ptr -> fx_dir_entry_name =  (CHAR *)working_ptr;
246
247
    /* Adjust the scratch memory pointer forward.  */
248
2034
    working_ptr =  working_ptr + long_name_size + (sizeof(ULONG) - 1);
249
2034
    working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
250
251
    /* Setup the source directory entry.  */
252
2034
    source_dir_ptr =  (FX_DIR_ENTRY *)working_ptr;
253
254
    /* Adjust the scratch memory pointer forward.  */
255
2034
    working_ptr =  &working_ptr[sizeof(FX_DIR_ENTRY)];
256
257
    /* Setup the name buffer for the source directory entry.  */
258
2034
    source_dir_ptr -> fx_dir_entry_name =  (CHAR *)working_ptr;
259
260
    /* Adjust the scratch memory pointer forward.  */
261
2034
    working_ptr =  working_ptr + long_name_size + (sizeof(ULONG) - 1);
262
2034
    working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
263
264
    /* Setup the current directory stack memory.  */
265
2034
    current_directory =  (CURRENT_DIRECTORY_ENTRY *)working_ptr;
266
267
    /* Allocate space for the size of the directory entry stack.  This basically
268
       defines the maximum level of sub-directories supported.  */
269
2034
    working_ptr =  &working_ptr[(FX_MAX_DIRECTORY_NESTING * sizeof(CURRENT_DIRECTORY_ENTRY))];
270
271
    /* Setup the initial current directory entry.  */
272
2034
    current_directory_index =  0;
273
274
    /* Adjust the size to account for the header information.  */
275
2034
    if (scratch_memory_size < (ULONG)((working_ptr - scratch_memory_ptr)))
276
    {
277
278
        /* Release media protection.  */
279
2
        FX_UNPROTECT
280
281
        /* Return the not enough memory error.  */
282
2
        return(FX_NOT_ENOUGH_MEMORY);
283
    }
284
285
    /* Adjust the scratch memory size.  */
286
2032
    scratch_memory_size =  scratch_memory_size - (ULONG)(working_ptr - scratch_memory_ptr);
287
288
    /* Memory is set aside for logical FAT - one bit per cluster */
289
2032
    logical_fat =  (UCHAR *)working_ptr;
290
291
    /* Determine if there is enough memory.  */
292
2032
    if (scratch_memory_size < ((media_ptr -> fx_media_total_clusters >> 3) + 1))
293
    {
294
295
        /* Release media protection.  */
296
1001
        FX_UNPROTECT
297
298
        /* Return the not enough memory error.  */
299
1001
        return(FX_NOT_ENOUGH_MEMORY);
300
    }
301
302
    /* Initialize the logical FAT table. */
303
832433
    for (i = 0; i < ((media_ptr -> fx_media_total_clusters >> 3) + 1); i++)
304
    {
305
        /* Clear the logical FAT entry, which actually represents eight clusters.  */
306
831402
        logical_fat[i] =  0;
307
    }
308
309
#ifdef FX_ENABLE_EXFAT
310
311
    /* Mark the clusters occupied by Allocation Bitmap table, Up-cast table and the first cluster of root directory. */
312
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
313
    {
314
    ULONG offset = 0;
315
316
        for (i = ((media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) >> 3); i; i--)
317
        {
318
            logical_fat[offset++] = 0xff;
319
        }
320
321
        for (i = ((media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) & 7); i; i--)
322
        {
323
            logical_fat[offset] = (UCHAR)((logical_fat[offset] << 1) | 0x1);
324
        }
325
    }
326
#endif /* FX_ENABLE_EXFAT */
327
328
#ifdef FX_ENABLE_FAULT_TOLERANT
329
    if (media_ptr -> fx_media_fault_tolerant_enabled)
330
    {
331
    ULONG cluster, cluster_number;
332
333
        /* Mark the cluster used by fault tolerant as valid. */
334
        for (cluster = media_ptr -> fx_media_fault_tolerant_start_cluster;
335
             cluster < media_ptr -> fx_media_fault_tolerant_start_cluster + media_ptr -> fx_media_fault_tolerant_clusters;
336
             cluster++)
337
        {
338
339
            cluster_number = cluster;
340
341
#ifdef FX_ENABLE_EXFAT
342
343
            /* For the index of the first cluster in exFAT is 2, adjust the number of clusters to fit Allocation Bitmap Table. */
344
            /* We will compare logical_fat with Aollcation Bitmap table later to find out lost clusters. */
345
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
346
            {
347
                cluster_number = cluster - FX_FAT_ENTRY_START;
348
            }
349
#endif /* FX_ENABLE_EXFAT */
350
351
            logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
352
        }
353
    }
354
#endif /* FX_ENABLE_FAULT_TOLERANT */
355
356
    /* If FAT32 is present, determine if the root directory is coherent.  */
357
#ifdef FX_ENABLE_EXFAT
358
    if ((media_ptr -> fx_media_FAT_type == FX_FAT32) ||
359
        (media_ptr -> fx_media_FAT_type == FX_exFAT))
360
#else
361
1031
    if (media_ptr -> fx_media_32_bit_FAT)
362
#endif /* FX_ENABLE_EXFAT */
363
    {
364
365
        /* A 32-bit FAT is present. We need to walk the clusters of the root directory to determine if
366
           it is intact. */
367
10
        current_errors =  _fx_media_check_FAT_chain_check(media_ptr, media_ptr -> fx_media_root_cluster_32,
368
                                                          &last_cluster, &valid_clusters, logical_fat);
369
370
        /* Make them part of the errors reported to the caller.  */
371
10
        *errors_detected =  *errors_detected | current_errors;
372
373
        /* Update the trace event with the errors detected.  */
374
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
375
376
        /* Determine if the I/O error is set.  */
377
10
        if (current_errors & FX_IO_ERROR)
378
        {
379
380
            /* Release media protection.  */
381
1
            FX_UNPROTECT
382
383
            /* File I/O Error.  */
384
1
            return(FX_IO_ERROR);
385
        }
386
387
        /* Check the status.  */
388
9
        if (*errors_detected)
389
        {
390
391
            /* Determine if we can fix the FAT32 root directory error.  */
392

5
            if ((valid_clusters) && (error_correction_option & FX_FAT_CHAIN_ERROR))
393
            {
394
395
                /* Make the chain end at the last cluster. */
396
2
                status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
397
398
                /* Determine if the write was successful.  */
399
2
                if (status)
400
                {
401
402
                    /* Release media protection.  */
403
1
                    FX_UNPROTECT
404
405
                    /* Return the error code.  */
406
1
                    return(status);
407
                }
408
409
                /* Adjust the total entries in the root directory.  */
410
1
                media_ptr -> fx_media_root_directory_entries =  (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
411
            }
412
            else
413
            {
414
415
                /* Release media protection.  */
416
3
                FX_UNPROTECT
417
418
                /* Return an error.  */
419
3
                return(FX_ERROR_NOT_FIXED);
420
            }
421
        }
422
    }
423
424
    /* Pickup total entries in the root directory.  */
425
1026
    total_entries =  media_ptr -> fx_media_root_directory_entries;
426
427
    /* Set temp directory pointer to NULL.  */
428
1026
    temp_dir_ptr =  FX_NULL;
429
430
    /* Put the root directory information in the entry stack */
431
1026
    current_directory[current_directory_index].current_total_entries =    total_entries;
432
1026
    current_directory[current_directory_index].current_start_cluster =    media_ptr -> fx_media_fat_last;
433
1026
    current_directory[current_directory_index].current_directory_entry =  0;
434
435
    /* Now we shall do the checking in depth first manner. */
436
    do
437
    {
438
439
        /* Pickup the directory index.  */
440
1286
        i =  current_directory[current_directory_index].current_directory_entry;
441
442
        /* Loop to process remaining directory entries.  */
443
15163
        while (i < current_directory[current_directory_index].current_total_entries)
444
        {
445
446
            /* Read a directory entry.  */
447
#ifdef FX_ENABLE_EXFAT
448
            /* Hash value of the file name is not cared. */
449
            status =  _fx_directory_entry_read_ex(media_ptr, temp_dir_ptr, &i, dir_entry_ptr, 0);
450
#else
451
15158
            status =  _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
452
#endif /* FX_ENABLE_EXFAT */
453
454
            /* Determine if the read was successful.  */
455
15158
            if (status)
456
            {
457
458
                /* Release media protection.  */
459
727
                FX_UNPROTECT
460
461
                /* Return the error code.  */
462
727
                return(status);
463
            }
464
465
            /* Check for the last entry.  */
466
#ifdef FX_ENABLE_EXFAT
467
            if (dir_entry_ptr -> fx_dir_entry_type == FX_EXFAT_DIR_ENTRY_TYPE_END_MARKER)
468
#else
469
14431
            if (dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_DONE)
470
#endif /* FX_ENABLE_EXFAT */
471
            {
472
473
                /* Last entry in this directory - no need to check further.  */
474
278
                break;
475
            }
476
477
            /* Is the entry free?  */
478
#ifdef FX_ENABLE_EXFAT
479
            if (dir_entry_ptr -> fx_dir_entry_type != FX_EXFAT_DIR_ENTRY_TYPE_FILE_DIRECTORY)
480
#else
481

14153
            if ((dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry_ptr -> fx_dir_entry_short_name[0] == 0))
482
#endif /* FX_ENABLE_EXFAT */
483
            {
484
485
                /* A deleted entry */
486
1
                i++;
487
1
                continue;
488
            }
489
490
#ifdef FX_ENABLE_EXFAT
491
492
            /* Determine whether FAT chain is used. */
493
            if (dir_entry_ptr -> fx_dir_entry_dont_use_fat & 1)
494
            {
495
            ULONG64 remaining_size = dir_entry_ptr -> fx_dir_entry_file_size;
496
            ULONG   cluster = dir_entry_ptr -> fx_dir_entry_cluster, cluster_number;
497
498
                valid_clusters = 0;
499
500
                while (remaining_size)
501
                {
502
                    if (remaining_size >= bytes_per_cluster)
503
                    {
504
                        remaining_size -= bytes_per_cluster;
505
                    }
506
                    else
507
                    {
508
                        remaining_size = 0;
509
                        last_cluster = cluster;
510
                    }
511
512
                    cluster_number = cluster - FX_FAT_ENTRY_START;
513
514
                    /* Is the current cluster already marked? */
515
                    if ((logical_fat[cluster_number / 8] >> (cluster_number % 8)) & 0x01)
516
                    {
517
                        current_errors = FX_FILE_SIZE_ERROR;
518
                        last_cluster = dir_entry_ptr -> fx_dir_entry_cluster + valid_clusters;
519
                        break;
520
                    }
521
522
                    /* Mark the current cluster. */
523
                    logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
524
525
                    valid_clusters++;
526
                    cluster++;
527
                }
528
            }
529
            else
530
            {
531
#endif /* FX_ENABLE_EXFAT */
532
533
                /* Look for any cross links or errors in the FAT chain of current directory entry. */
534
14152
                current_errors =  _fx_media_check_FAT_chain_check(media_ptr, dir_entry_ptr -> fx_dir_entry_cluster,
535
                                                                  &last_cluster, &valid_clusters, logical_fat);
536
#ifdef FX_ENABLE_EXFAT
537
            }
538
#endif /* FX_ENABLE_EXFAT */
539
540
            /* Make them part of the errors reported to the caller.  */
541
14152
            *errors_detected =  *errors_detected | current_errors;
542
543
            /* Update the trace event with the errors detected.  */
544
            FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
545
546
            /* Determine if the I/O error is set.  */
547
14152
            if (current_errors & FX_IO_ERROR)
548
            {
549
550
                /* Release media protection.  */
551
249
                FX_UNPROTECT
552
553
                /* File I/O Error.  */
554
249
                return(FX_IO_ERROR);
555
            }
556
557
            /* Check for errors.  */
558
13903
            if (*errors_detected)
559
            {
560
561
                /* Determine if we can fix the FAT chain.  */
562
13008
                if (error_correction_option & FX_FAT_CHAIN_ERROR)
563
                {
564
565
                    /* Determine if there is a valid cluster to write the EOF to.  */
566
5760
                    if (valid_clusters)
567
                    {
568
569
                        /* Write EOF in the last FAT entry.  */
570
539
                        status =  _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
571
572
                        /* Determine if the write was successful.  */
573
539
                        if (status)
574
                        {
575
576
                            /* Release media protection.  */
577
1
                            FX_UNPROTECT
578
579
                            /* Return the error code.  */
580
1
                            return(status);
581
                        }
582
                    }
583
                }
584
            }
585
586
            /* Determine if we need to update the size of the directory entry.  */
587
13902
            if (dir_entry_ptr -> fx_dir_entry_file_size > (valid_clusters * bytes_per_cluster))
588
            {
589
590
                /* Yes, update the directory entry's size.  */
591
1546
                dir_entry_ptr -> fx_dir_entry_file_size =  valid_clusters * bytes_per_cluster;
592
593
                /* Determine if the new file size is zero. */
594
1546
                if (dir_entry_ptr -> fx_dir_entry_file_size == 0)
595
                {
596
597
                    /* Consider this a directory error.  */
598
811
                    *errors_detected =  *errors_detected | FX_DIRECTORY_ERROR;
599
600
                    /* Update the trace event with the errors detected.  */
601
                    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
602
603
                    /* Clear the starting cluster number of this directory entry.  */
604
811
                    dir_entry_ptr -> fx_dir_entry_cluster =  0;
605
606
                    /* If directory fixing is required, delete this directory entry as well.  */
607
811
                    if (error_correction_option & FX_DIRECTORY_ERROR)
608
                    {
609
610
                        /* Mark the entry as deleted.  */
611
410
                        dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
612
410
                        dir_entry_ptr -> fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
613
                    }
614
                }
615
616
                /* Only update the directory if the FAT chain was actually updated.  */
617
1546
                if (error_correction_option & FX_FAT_CHAIN_ERROR)
618
                {
619
620
                    /* Update the directory entry.  */
621
765
                    status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
622
623
                    /* Determine if the write was successful.  */
624
765
                    if (status)
625
                    {
626
627
                        /* Release media protection.  */
628
24
                        FX_UNPROTECT
629
630
                        /* Return the error code.  */
631
24
                        return(status);
632
                    }
633
                }
634
            }
635
636
            /* Determine if the entry is a sub-directory.  */
637
13878
            if ((dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
638
499
                 && (valid_clusters == 0))
639
            {
640
641
                /* Consider this a directory error.  */
642
3
                *errors_detected =  *errors_detected | FX_DIRECTORY_ERROR;
643
644
                /* Update the trace event with the errors detected.  */
645
                FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
646
647
                /* Determine if we can fix the error.  */
648
3
                if (error_correction_option & FX_DIRECTORY_ERROR)
649
                {
650
651
                    /* Yes, make the directory entry free.  */
652
2
                    dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
653
2
                    dir_entry_ptr -> fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
654
655
                    /* Delete the sub-directory entry.  */
656
2
                    status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
657
658
                    /* Determine if the write was successful.  */
659
2
                    if (status)
660
                    {
661
662
                        /* Release media protection.  */
663
1
                        FX_UNPROTECT
664
665
                        /* Return the error code.  */
666
1
                        return(status);
667
                    }
668
669
                    /* Move to next entry.  */
670
1
                    i++;
671
1
                    continue;
672
                }
673
            }
674
675
            /* Determine if the entry is a directory.  */
676
13876
            if (dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
677
            {
678
679
                /* Current entry is a directory. The algorithm is designed to follow all
680
                   sub-directories immediately, i.e., a depth first search.  */
681
682
                /* First, save the next entry position. */
683
497
                current_directory[current_directory_index].current_directory_entry =  i + 1;
684
685
                /* Push the current directory entry on the stack.  */
686
497
                current_directory_index++;
687
688
                /* Check for current directory stack overflow.  */
689
497
                if (current_directory_index >= FX_MAX_DIRECTORY_NESTING)
690
                {
691
692
                    /* Release media protection.  */
693
1
                    FX_UNPROTECT
694
695
                    /* Current directory stack overflow.  Return error.  */
696
1
                    return(FX_NOT_ENOUGH_MEMORY);
697
                }
698
699
                /* Otherwise, setup the new directory entry.  */
700
496
                current_directory[current_directory_index].current_total_entries =      (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
701
496
                current_directory[current_directory_index].current_start_cluster =      dir_entry_ptr -> fx_dir_entry_cluster;
702
496
                current_directory[current_directory_index].current_directory_entry =    2;
703
704
                /* Setup new source directory.  */
705
496
                source_dir_ptr -> fx_dir_entry_cluster =              dir_entry_ptr -> fx_dir_entry_cluster;
706
496
                source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
707
496
                source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
708
496
                temp_dir_ptr =                                        source_dir_ptr;
709
710
                /* Skip the first two entries of sub-directories.  */
711
496
                i =  2;
712
713
#ifdef FX_ENABLE_EXFAT
714
715
                /* For exFAT, there is no dir-entries for ".." and ".". */
716
                if (media_ptr -> fx_media_FAT_type == FX_exFAT)
717
                {
718
                    current_directory[current_directory_index].current_directory_entry = 0;
719
                    i =  0;
720
                }
721
#endif /* FX_ENABLE_EXFAT */
722
            }
723
            else
724
            {
725
726
                /* Regular file entry.  */
727
728
                /* Check for an invalid file size.  */
729
13379
                if (((valid_clusters * bytes_per_cluster) - dir_entry_ptr -> fx_dir_entry_file_size) > bytes_per_cluster)
730
                {
731
732
                    /* There are more clusters allocated than needed for the file's size.  Indicate that this error
733
                       is present.  */
734
1
                    *errors_detected =  *errors_detected | FX_FILE_SIZE_ERROR;
735
736
                    /* Update the trace event with the errors detected.  */
737
                    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
738
739
                    /* For now, don't shorten the cluster chain.  */
740
                }
741
742
                /* Look into the next entry in the current directory.  */
743
13379
                i++;
744
            }
745
        }
746
747
        /* Once we get here, we have exhausted the current directory and need to return to the previous
748
           directory.  */
749
750
        /* Check for being at the root directory.  */
751
283
        if (current_directory_index == 0)
752
        {
753
754
            /* Yes, we have now exhausted searching the root directory so we are done!  */
755
23
            break;
756
        }
757
758
        /* Backup to the place we left off in the previous directory.  */
759
260
        current_directory_index--;
760
761
        /* Determine if we are now back at the root directory.  */
762
260
        if (current_directory[current_directory_index].current_start_cluster == media_ptr -> fx_media_fat_last)
763
        {
764
765
            /* The search directory should be NULL since it is the root directory.  */
766
258
            temp_dir_ptr =  FX_NULL;
767
        }
768
        else
769
        {
770
771
            /* Otherwise, we are returning to a sub-directory.  Setup the search directory
772
               appropriately.  */
773
2
            source_dir_ptr -> fx_dir_entry_cluster =              current_directory[current_directory_index].current_start_cluster;
774
2
            source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
775
2
            source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
776
2
            temp_dir_ptr =                                        source_dir_ptr;
777
        }
778
    } while (1);
779
780
#ifdef FX_ENABLE_EXFAT
781
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
782
    {
783
784
        /* If exFAT is in use, compare the logical_fat with Allocation Bitmap Table directly. */
785
        current_errors =  _fx_media_check_exFAT_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
786
    }
787
    else
788
    {
789
#endif /* FX_ENABLE_EXFAT */
790
791
        /* At this point, all the files and sub-directories have been examined.  We now need to check for
792
           lost clusters in the logical FAT.  A lost cluster is basically anything that is not reported in
793
           the logical FAT that has a non-zero value in the real FAT.  */
794
23
        current_errors =  _fx_media_check_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
795
#ifdef FX_ENABLE_EXFAT
796
    }
797
#endif /* FX_ENABLE_EXFAT */
798
799
    /* Incorporate the error returned by the lost FAT check.  */
800
23
    *errors_detected =  *errors_detected | current_errors;
801
802
    /* Update the trace event with the errors detected.  */
803
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
804
805
    /* Determine if the I/O error is set.  */
806
23
    if (current_errors & FX_IO_ERROR)
807
    {
808
809
        /* Release media protection.  */
810
3
        FX_UNPROTECT
811
812
        /* File I/O Error.  */
813
3
        return(FX_IO_ERROR);
814
    }
815
816
    /* Determine if there was any error and update was selected.  */
817

20
    if ((*errors_detected) && (error_correction_option))
818
    {
819
820
        /* Flush any unwritten items to the media.  */
821
12
        _fx_media_flush(media_ptr);
822
    }
823
824
    /* Release media protection.  */
825
20
    FX_UNPROTECT
826
827
    /* At this point, we have completed the diagnostic of the media, return success!  */
828
20
    return(FX_SUCCESS);
829
}
830