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 /**************************************************************************/
_fx_media_check(FX_MEDIA * media_ptr,UCHAR * scratch_memory_ptr,ULONG scratch_memory_size,ULONG error_correction_option,ULONG * errors_detected)166 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     if (media_ptr -> fx_media_id != FX_MEDIA_ID)
186     {
187 
188         /* Return the media not opened error.  */
189         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     FX_PROTECT
197 
198     /* Determine if there are any opened files.  */
199     if (media_ptr -> fx_media_opened_file_count)
200     {
201 
202         /* There are opened files... this is an error!  */
203 
204         /* Release protection.  */
205         FX_UNPROTECT
206 
207         /* Return an error.  */
208         return(FX_ACCESS_ERROR);
209     }
210 
211     /* Invalidate the cache.  */
212     _fx_media_cache_invalidate(media_ptr);
213 
214     /* Initialize the reported error flag.  */
215     *errors_detected =  0;
216 
217     /* Calculate the long name size, rounded up to something that is evenly divisible by 4.  */
218     long_name_size =  (((FX_MAX_LONG_NAME_LEN + 3) >> 2) << 2);
219 
220     /* Calculate the number of bytes per cluster.  */
221     bytes_per_cluster =  media_ptr -> fx_media_sectors_per_cluster * media_ptr -> fx_media_bytes_per_sector;
222 
223     /* Setup address mask.  */
224     address_mask =  sizeof(ULONG) - 1;
225     address_mask =  ~address_mask;
226 
227     /* Setup working pointer.  */
228     working_ptr =  scratch_memory_ptr + (sizeof(ULONG) - 1);
229     working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
230 
231     /* Memory is set aside for two FX_DIR_ENTRY structures */
232     dir_entry_ptr =  (FX_DIR_ENTRY *)working_ptr;
233 
234     /* Adjust the scratch memory pointer forward.  */
235     working_ptr =  &working_ptr[sizeof(FX_DIR_ENTRY)];
236 
237     /* Setup the name buffer for the first directory entry.  */
238     dir_entry_ptr -> fx_dir_entry_name =  (CHAR *)working_ptr;
239 
240     /* Adjust the scratch memory pointer forward.  */
241     working_ptr =  working_ptr + long_name_size + (sizeof(ULONG) - 1);
242     working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
243 
244     /* Setup the source directory entry.  */
245     source_dir_ptr =  (FX_DIR_ENTRY *)working_ptr;
246 
247     /* Adjust the scratch memory pointer forward.  */
248     working_ptr =  &working_ptr[sizeof(FX_DIR_ENTRY)];
249 
250     /* Setup the name buffer for the source directory entry.  */
251     source_dir_ptr -> fx_dir_entry_name =  (CHAR *)working_ptr;
252 
253     /* Adjust the scratch memory pointer forward.  */
254     working_ptr =  working_ptr + long_name_size + (sizeof(ULONG) - 1);
255     working_ptr =  (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
256 
257     /* Setup the current directory stack memory.  */
258     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     working_ptr =  &working_ptr[(FX_MAX_DIRECTORY_NESTING * sizeof(CURRENT_DIRECTORY_ENTRY))];
263 
264     /* Setup the initial current directory entry.  */
265     current_directory_index =  0;
266 
267     /* Adjust the size to account for the header information.  */
268     if (scratch_memory_size < (ULONG)((working_ptr - scratch_memory_ptr)))
269     {
270 
271         /* Release media protection.  */
272         FX_UNPROTECT
273 
274         /* Return the not enough memory error.  */
275         return(FX_NOT_ENOUGH_MEMORY);
276     }
277 
278     /* Adjust the scratch memory size.  */
279     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     logical_fat =  (UCHAR *)working_ptr;
283 
284     /* Determine if there is enough memory.  */
285     if (scratch_memory_size < ((media_ptr -> fx_media_total_clusters >> 3) + 1))
286     {
287 
288         /* Release media protection.  */
289         FX_UNPROTECT
290 
291         /* Return the not enough memory error.  */
292         return(FX_NOT_ENOUGH_MEMORY);
293     }
294 
295     /* Initialize the logical FAT table. */
296     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         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     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         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         *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         if (current_errors & FX_IO_ERROR)
339         {
340 
341             /* Release media protection.  */
342             FX_UNPROTECT
343 
344             /* File I/O Error.  */
345             return(FX_IO_ERROR);
346         }
347 
348         /* Check the status.  */
349         if (*errors_detected)
350         {
351 
352             /* Determine if we can fix the FAT32 root directory error.  */
353             if ((valid_clusters) && (error_correction_option & FX_FAT_CHAIN_ERROR))
354             {
355 
356                 /* Make the chain end at the last cluster. */
357                 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                 if (status)
361                 {
362 
363                     /* Release media protection.  */
364                     FX_UNPROTECT
365 
366                     /* Return the error code.  */
367                     return(status);
368                 }
369 
370                 /* Adjust the total entries in the root directory.  */
371                 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                 FX_UNPROTECT
378 
379                 /* Return an error.  */
380                 return(FX_ERROR_NOT_FIXED);
381             }
382         }
383     }
384 
385     /* Pickup total entries in the root directory.  */
386     total_entries =  media_ptr -> fx_media_root_directory_entries;
387 
388     /* Set temp directory pointer to NULL.  */
389     temp_dir_ptr =  FX_NULL;
390 
391     /* Put the root directory information in the entry stack */
392     current_directory[current_directory_index].current_total_entries =    total_entries;
393     current_directory[current_directory_index].current_start_cluster =    media_ptr -> fx_media_fat_last;
394     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         i =  current_directory[current_directory_index].current_directory_entry;
402 
403         /* Loop to process remaining directory entries.  */
404         while (i < current_directory[current_directory_index].current_total_entries)
405         {
406 
407             /* Read a directory entry.  */
408             status =  _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
409 
410             /* Determine if the read was successful.  */
411             if (status)
412             {
413 
414                 /* Release media protection.  */
415                 FX_UNPROTECT
416 
417                 /* Return the error code.  */
418                 return(status);
419             }
420 
421             /* Check for the last entry.  */
422             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                 break;
427             }
428 
429             /* Is the entry free?  */
430             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                 i++;
435                 continue;
436             }
437 
438 
439             /* Look for any cross links or errors in the FAT chain of current directory entry. */
440             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             *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             if (current_errors & FX_IO_ERROR)
451             {
452 
453                 /* Release media protection.  */
454                 FX_UNPROTECT
455 
456                 /* File I/O Error.  */
457                 return(FX_IO_ERROR);
458             }
459 
460             /* Check for errors.  */
461             if (*errors_detected)
462             {
463 
464                 /* Determine if we can fix the FAT chain.  */
465                 if (error_correction_option & FX_FAT_CHAIN_ERROR)
466                 {
467 
468                     /* Determine if there is a valid cluster to write the EOF to.  */
469                     if (valid_clusters)
470                     {
471 
472                         /* Write EOF in the last FAT entry.  */
473                         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                         if (status)
477                         {
478 
479                             /* Release media protection.  */
480                             FX_UNPROTECT
481 
482                             /* Return the error code.  */
483                             return(status);
484                         }
485                     }
486                 }
487             }
488 
489             /* Determine if we need to update the size of the directory entry.  */
490             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                 dir_entry_ptr -> fx_dir_entry_file_size =  valid_clusters * bytes_per_cluster;
495 
496                 /* Determine if the new file size is zero. */
497                 if (dir_entry_ptr -> fx_dir_entry_file_size == 0)
498                 {
499 
500                     /* Consider this a directory error.  */
501                     *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                     dir_entry_ptr -> fx_dir_entry_cluster =  0;
508 
509                     /* If directory fixing is required, delete this directory entry as well.  */
510                     if (error_correction_option & FX_DIRECTORY_ERROR)
511                     {
512 
513                         /* Mark the entry as deleted.  */
514                         dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
515                         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                 if (error_correction_option & FX_FAT_CHAIN_ERROR)
521                 {
522 
523                     /* Update the directory entry.  */
524                     status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
525 
526                     /* Determine if the write was successful.  */
527                     if (status)
528                     {
529 
530                         /* Release media protection.  */
531                         FX_UNPROTECT
532 
533                         /* Return the error code.  */
534                         return(status);
535                     }
536                 }
537             }
538 
539             /* Determine if the entry is a sub-directory.  */
540             if ((dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
541                  && (valid_clusters == 0))
542             {
543 
544                 /* Consider this a directory error.  */
545                 *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                 if (error_correction_option & FX_DIRECTORY_ERROR)
552                 {
553 
554                     /* Yes, make the directory entry free.  */
555                     dir_entry_ptr -> fx_dir_entry_name[0] =        (CHAR)FX_DIR_ENTRY_FREE;
556                     dir_entry_ptr -> fx_dir_entry_short_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
557 
558                     /* Delete the sub-directory entry.  */
559                     status =  _fx_directory_entry_write(media_ptr, dir_entry_ptr);
560 
561                     /* Determine if the write was successful.  */
562                     if (status)
563                     {
564 
565                         /* Release media protection.  */
566                         FX_UNPROTECT
567 
568                         /* Return the error code.  */
569                         return(status);
570                     }
571 
572                     /* Move to next entry.  */
573                     i++;
574                     continue;
575                 }
576             }
577 
578             /* Determine if the entry is a directory.  */
579             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                 current_directory[current_directory_index].current_directory_entry =  i + 1;
587 
588                 /* Push the current directory entry on the stack.  */
589                 current_directory_index++;
590 
591                 /* Check for current directory stack overflow.  */
592                 if (current_directory_index >= FX_MAX_DIRECTORY_NESTING)
593                 {
594 
595                     /* Release media protection.  */
596                     FX_UNPROTECT
597 
598                     /* Current directory stack overflow.  Return error.  */
599                     return(FX_NOT_ENOUGH_MEMORY);
600                 }
601 
602                 /* Otherwise, setup the new directory entry.  */
603                 current_directory[current_directory_index].current_total_entries =      (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
604                 current_directory[current_directory_index].current_start_cluster =      dir_entry_ptr -> fx_dir_entry_cluster;
605                 current_directory[current_directory_index].current_directory_entry =    2;
606 
607                 /* Setup new source directory.  */
608                 source_dir_ptr -> fx_dir_entry_cluster =              dir_entry_ptr -> fx_dir_entry_cluster;
609                 source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
610                 source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
611                 temp_dir_ptr =                                        source_dir_ptr;
612 
613                 /* Skip the first two entries of sub-directories.  */
614                 i =  2;
615 
616             }
617             else
618             {
619 
620                 /* Regular file entry.  */
621 
622                 /* Check for an invalid file size.  */
623                 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                     *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                 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         if (current_directory_index == 0)
646         {
647 
648             /* Yes, we have now exhausted searching the root directory so we are done!  */
649             break;
650         }
651 
652         /* Backup to the place we left off in the previous directory.  */
653         current_directory_index--;
654 
655         /* Determine if we are now back at the root directory.  */
656         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             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             source_dir_ptr -> fx_dir_entry_cluster =              current_directory[current_directory_index].current_start_cluster;
668             source_dir_ptr -> fx_dir_entry_file_size =            current_directory[current_directory_index].current_total_entries;
669             source_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
670             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     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     *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     if (current_errors & FX_IO_ERROR)
688     {
689 
690         /* Release media protection.  */
691         FX_UNPROTECT
692 
693         /* File I/O Error.  */
694         return(FX_IO_ERROR);
695     }
696 
697     /* Determine if there was any error and update was selected.  */
698     if ((*errors_detected) && (error_correction_option))
699     {
700 
701         /* Flush any unwritten items to the media.  */
702         _fx_media_flush(media_ptr);
703     }
704 
705     /* Release media protection.  */
706     FX_UNPROTECT
707 
708     /* At this point, we have completed the diagnostic of the media, return success!  */
709     return(FX_SUCCESS);
710 }
711 
712