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