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

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

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

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

20
    if ((*errors_detected) && (error_correction_option))
699
    {
700
701
        /* Flush any unwritten items to the media.  */
702
12
        _fx_media_flush(media_ptr);
703
    }
704
705
    /* Release media protection.  */
706
20
    FX_UNPROTECT
707
708
    /* At this point, we have completed the diagnostic of the media, return success!  */
709
20
    return(FX_SUCCESS);
710
}
711