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

5
            if ((valid_clusters) && (error_correction_option & FX_FAT_CHAIN_ERROR))
347
            {
348
349
                /* Make the chain end at the last cluster. */
350
2
                status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
351
352
                /* Determine if the write was successful.  */
353
2
                if (status)
354
                {
355
356
                    /* Release media protection.  */
357
1
                    FX_UNPROTECT
358
359
                    /* Return the error code.  */
360
1
                    return(status);
361
                }
362
363
                /* Adjust the total entries in the root directory.  */
364
1
                media_ptr -> fx_media_root_directory_entries =  (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
365
            }
366
            else
367
            {
368
369
                /* Release media protection.  */
370
3
                FX_UNPROTECT
371
372
                /* Return an error.  */
373
3
                return(FX_ERROR_NOT_FIXED);
374
            }
375
        }
376
    }
377
378
    /* Pickup total entries in the root directory.  */
379
1026
    total_entries =  media_ptr -> fx_media_root_directory_entries;
380
381
    /* Set temp directory pointer to NULL.  */
382
1026
    temp_dir_ptr =  FX_NULL;
383
384
    /* Put the root directory information in the entry stack */
385
1026
    current_directory[current_directory_index].current_total_entries =    total_entries;
386
1026
    current_directory[current_directory_index].current_start_cluster =    media_ptr -> fx_media_fat_last;
387
1026
    current_directory[current_directory_index].current_directory_entry =  0;
388
389
    /* Now we shall do the checking in depth first manner. */
390
    do
391
    {
392
393
        /* Pickup the directory index.  */
394
1286
        i =  current_directory[current_directory_index].current_directory_entry;
395
396
        /* Loop to process remaining directory entries.  */
397
15163
        while (i < current_directory[current_directory_index].current_total_entries)
398
        {
399
400
            /* Read a directory entry.  */
401
15158
            status =  _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
402
403
            /* Determine if the read was successful.  */
404
15158
            if (status)
405
            {
406
407
                /* Release media protection.  */
408
727
                FX_UNPROTECT
409
410
                /* Return the error code.  */
411
727
                return(status);
412
            }
413
414
            /* Check for the last entry.  */
415
14431
            if (dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_DONE)
416
            {
417
418
                /* Last entry in this directory - no need to check further.  */
419
278
                break;
420
            }
421
422
            /* Is the entry free?  */
423

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))
424
            {
425
426
                /* A deleted entry */
427
1
                i++;
428
1
                continue;
429
            }
430
431
432
            /* Look for any cross links or errors in the FAT chain of current directory entry. */
433
14152
            current_errors =  _fx_media_check_FAT_chain_check(media_ptr, dir_entry_ptr -> fx_dir_entry_cluster,
434
                                                              &last_cluster, &valid_clusters, logical_fat);
435
436
            /* Make them part of the errors reported to the caller.  */
437
14152
            *errors_detected =  *errors_detected | current_errors;
438
439
            /* Update the trace event with the errors detected.  */
440
            FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
441
442
            /* Determine if the I/O error is set.  */
443
14152
            if (current_errors & FX_IO_ERROR)
444
            {
445
446
                /* Release media protection.  */
447
249
                FX_UNPROTECT
448
449
                /* File I/O Error.  */
450
249
                return(FX_IO_ERROR);
451
            }
452
453
            /* Check for errors.  */
454
13903
            if (*errors_detected)
455
            {
456
457
                /* Determine if we can fix the FAT chain.  */
458
13008
                if (error_correction_option & FX_FAT_CHAIN_ERROR)
459
                {
460
461
                    /* Determine if there is a valid cluster to write the EOF to.  */
462
5760
                    if (valid_clusters)
463
                    {
464
465
                        /* Write EOF in the last FAT entry.  */
466
539
                        status =  _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
467
468
                        /* Determine if the write was successful.  */
469
539
                        if (status)
470
                        {
471
472
                            /* Release media protection.  */
473
1
                            FX_UNPROTECT
474
475
                            /* Return the error code.  */
476
1
                            return(status);
477
                        }
478
                    }
479
                }
480
            }
481
482
            /* Determine if we need to update the size of the directory entry.  */
483
13902
            if (dir_entry_ptr -> fx_dir_entry_file_size > (valid_clusters * bytes_per_cluster))
484
            {
485
486
                /* Yes, update the directory entry's size.  */
487
1546
                dir_entry_ptr -> fx_dir_entry_file_size =  valid_clusters * bytes_per_cluster;
488
489
                /* Determine if the new file size is zero. */
490
1546
                if (dir_entry_ptr -> fx_dir_entry_file_size == 0)
491
                {
492
493
                    /* Consider this a directory error.  */
494
811
                    *errors_detected =  *errors_detected | FX_DIRECTORY_ERROR;
495
496
                    /* Update the trace event with the errors detected.  */
497
                    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
498
499
                    /* Clear the starting cluster number of this directory entry.  */
500
811
                    dir_entry_ptr -> fx_dir_entry_cluster =  0;
501
502
                    /* If directory fixing is required, delete this directory entry as well.  */
503
811
                    if (error_correction_option & FX_DIRECTORY_ERROR)
504
                    {
505
506
                        /* Mark the entry as deleted.  */
507
410
                        dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
508
410
                        dir_entry_ptr -> fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
509
                    }
510
                }
511
512
                /* Only update the directory if the FAT chain was actually updated.  */
513
1546
                if (error_correction_option & FX_FAT_CHAIN_ERROR)
514
                {
515
516
                    /* Update the directory entry.  */
517
765
                    status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
518
519
                    /* Determine if the write was successful.  */
520
765
                    if (status)
521
                    {
522
523
                        /* Release media protection.  */
524
24
                        FX_UNPROTECT
525
526
                        /* Return the error code.  */
527
24
                        return(status);
528
                    }
529
                }
530
            }
531
532
            /* Determine if the entry is a sub-directory.  */
533
13878
            if ((dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
534
499
                 && (valid_clusters == 0))
535
            {
536
537
                /* Consider this a directory error.  */
538
3
                *errors_detected =  *errors_detected | FX_DIRECTORY_ERROR;
539
540
                /* Update the trace event with the errors detected.  */
541
                FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
542
543
                /* Determine if we can fix the error.  */
544
3
                if (error_correction_option & FX_DIRECTORY_ERROR)
545
                {
546
547
                    /* Yes, make the directory entry free.  */
548
2
                    dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
549
2
                    dir_entry_ptr -> fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
550
551
                    /* Delete the sub-directory entry.  */
552
2
                    status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
553
554
                    /* Determine if the write was successful.  */
555
2
                    if (status)
556
                    {
557
558
                        /* Release media protection.  */
559
1
                        FX_UNPROTECT
560
561
                        /* Return the error code.  */
562
1
                        return(status);
563
                    }
564
565
                    /* Move to next entry.  */
566
1
                    i++;
567
1
                    continue;
568
                }
569
            }
570
571
            /* Determine if the entry is a directory.  */
572
13876
            if (dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
573
            {
574
575
                /* Current entry is a directory. The algorithm is designed to follow all
576
                   sub-directories immediately, i.e., a depth first search.  */
577
578
                /* First, save the next entry position. */
579
497
                current_directory[current_directory_index].current_directory_entry =  i + 1;
580
581
                /* Push the current directory entry on the stack.  */
582
497
                current_directory_index++;
583
584
                /* Check for current directory stack overflow.  */
585
497
                if (current_directory_index >= FX_MAX_DIRECTORY_NESTING)
586
                {
587
588
                    /* Release media protection.  */
589
1
                    FX_UNPROTECT
590
591
                    /* Current directory stack overflow.  Return error.  */
592
1
                    return(FX_NOT_ENOUGH_MEMORY);
593
                }
594
595
                /* Otherwise, setup the new directory entry.  */
596
496
                current_directory[current_directory_index].current_total_entries =      (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
597
496
                current_directory[current_directory_index].current_start_cluster =      dir_entry_ptr -> fx_dir_entry_cluster;
598
496
                current_directory[current_directory_index].current_directory_entry =    2;
599
600
                /* Setup new source directory.  */
601
496
                source_dir_ptr -> fx_dir_entry_cluster =              dir_entry_ptr -> fx_dir_entry_cluster;
602
496
                source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
603
496
                source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
604
496
                temp_dir_ptr =                                        source_dir_ptr;
605
606
                /* Skip the first two entries of sub-directories.  */
607
496
                i =  2;
608
609
            }
610
            else
611
            {
612
613
                /* Regular file entry.  */
614
615
                /* Check for an invalid file size.  */
616
13379
                if (((valid_clusters * bytes_per_cluster) - dir_entry_ptr -> fx_dir_entry_file_size) > bytes_per_cluster)
617
                {
618
619
                    /* There are more clusters allocated than needed for the file's size.  Indicate that this error
620
                       is present.  */
621
1
                    *errors_detected =  *errors_detected | FX_FILE_SIZE_ERROR;
622
623
                    /* Update the trace event with the errors detected.  */
624
                    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
625
626
                    /* For now, don't shorten the cluster chain.  */
627
                }
628
629
                /* Look into the next entry in the current directory.  */
630
13379
                i++;
631
            }
632
        }
633
634
        /* Once we get here, we have exhausted the current directory and need to return to the previous
635
           directory.  */
636
637
        /* Check for being at the root directory.  */
638
283
        if (current_directory_index == 0)
639
        {
640
641
            /* Yes, we have now exhausted searching the root directory so we are done!  */
642
23
            break;
643
        }
644
645
        /* Backup to the place we left off in the previous directory.  */
646
260
        current_directory_index--;
647
648
        /* Determine if we are now back at the root directory.  */
649
260
        if (current_directory[current_directory_index].current_start_cluster == media_ptr -> fx_media_fat_last)
650
        {
651
652
            /* The search directory should be NULL since it is the root directory.  */
653
258
            temp_dir_ptr =  FX_NULL;
654
        }
655
        else
656
        {
657
658
            /* Otherwise, we are returning to a sub-directory.  Setup the search directory
659
               appropriately.  */
660
2
            source_dir_ptr -> fx_dir_entry_cluster =              current_directory[current_directory_index].current_start_cluster;
661
2
            source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
662
2
            source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
663
2
            temp_dir_ptr =                                        source_dir_ptr;
664
        }
665
    } while (1);
666
667
668
    /* At this point, all the files and sub-directories have been examined.  We now need to check for
669
       lost clusters in the logical FAT.  A lost cluster is basically anything that is not reported in
670
       the logical FAT that has a non-zero value in the real FAT.  */
671
23
    current_errors =  _fx_media_check_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
672
673
    /* Incorporate the error returned by the lost FAT check.  */
674
23
    *errors_detected =  *errors_detected | current_errors;
675
676
    /* Update the trace event with the errors detected.  */
677
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
678
679
    /* Determine if the I/O error is set.  */
680
23
    if (current_errors & FX_IO_ERROR)
681
    {
682
683
        /* Release media protection.  */
684
3
        FX_UNPROTECT
685
686
        /* File I/O Error.  */
687
3
        return(FX_IO_ERROR);
688
    }
689
690
    /* Determine if there was any error and update was selected.  */
691

20
    if ((*errors_detected) && (error_correction_option))
692
    {
693
694
        /* Flush any unwritten items to the media.  */
695
12
        _fx_media_flush(media_ptr);
696
    }
697
698
    /* Release media protection.  */
699
20
    FX_UNPROTECT
700
701
    /* At this point, we have completed the diagnostic of the media, return success!  */
702
20
    return(FX_SUCCESS);
703
}
704