GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 147 / 0 / 147
Functions: 100.0% 1 / 0 / 1
Branches: 100.0% 287 / 0 / 287

fx_media_check.c
Line Branch Exec Source
1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 * Copyright (c) 2026-present Eclipse ThreadX contributors
4 *
5 * This program and the accompanying materials are made available under the
6 * terms of the MIT License which is available at
7 * https://opensource.org/licenses/MIT.
8 *
9 * SPDX-License-Identifier: MIT
10 **************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** FileX Component */
17 /** */
18 /** Media */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define FX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "fx_api.h"
29 #include "fx_system.h"
30 #include "fx_directory.h"
31 #include "fx_media.h"
32 #include "fx_utility.h"
33
34
35 /* Define parameters for FileX media check utility. */
36
37 #ifndef FX_MAX_DIRECTORY_NESTING
38 #define FX_MAX_DIRECTORY_NESTING 20
39 #endif
40
41
42 /* Define data structures local to the FileX media check utility. */
43
44 typedef struct CURRENT_DIRECTORY_ENTRY_STRUCT
45 {
46 ULONG current_directory_entry;
47 ULONG current_total_entries;
48 ULONG current_start_cluster;
49 } CURRENT_DIRECTORY_ENTRY;
50
51
52 /**************************************************************************/
53 /* */
54 /* FUNCTION RELEASE */
55 /* */
56 /* _fx_media_check PORTABLE C */
57 /* 6.1 */
58 /* AUTHOR */
59 /* */
60 /* William E. Lamie, Microsoft Corporation */
61 /* */
62 /* DESCRIPTION */
63 /* */
64 /* This function checks the specified media for basic structural */
65 /* errors, including cross linking, invalid FAT chains, and lost */
66 /* clusters. The function also provides the capability to correct */
67 /* errors. */
68 /* */
69 /* The algorithm is to follow all sub-directories immediately and */
70 /* check their contents. The maximum depth of sub-directories is */
71 /* determined by the constant FX_MAX_DIRECTORY_NESTING. */
72 /* By default, this is set at 20. Basically, the FAT chain of every */
73 /* file and sub-directory is traversed. If valid, clusters are marked */
74 /* in a logical FAT bit map to signal they are already in-use. The */
75 /* algorithm should detect any broken or cross linked FAT condition. */
76 /* */
77 /* As for memory usage, the scratch memory supplied to the media check */
78 /* function is used to hold several directory entries, a data */
79 /* structure to "stack" the current directory entry position before */
80 /* diving into the sub-directory, and finally the logical FAT bit map. */
81 /* The basic data structures take from 512-1024 bytes and the logical */
82 /* FAT bit map requires as many bits as there are clusters in your */
83 /* device. For example, a device with 8000 clusters would require */
84 /* 1000 bytes to represent. */
85 /* */
86 /* On the performance end of things, the traversal is reasonably fast */
87 /* and is basically linear with the number of files and their sizes. */
88 /* The lost cluster checking at the end of media check is a bit more */
89 /* performance comprehensive. It basically checks that each unused */
90 /* cluster is actually marked as free. You might decide to bypass this */
91 /* step if no other errors are found... or there might be ways to */
92 /* optimize the search by reading whole FAT sectors. You probably just */
93 /* need to see how it behaves in your system. */
94 /* */
95 /* INPUT */
96 /* */
97 /* media_ptr Pointer to a previously */
98 /* opened media */
99 /* scratch_memory_ptr Pointer to memory area for */
100 /* media check to use (as */
101 /* mentioned above) */
102 /* scratch_memory_size Size of the scratch memory */
103 /* error_correction_option Specifies which - if any - */
104 /* errors are corrected by */
105 /* the media check function. */
106 /* Setting the following bit */
107 /* causes that error to be */
108 /* corrected: */
109 /* */
110 /* 0x01 -> Fix FAT Chain Errors*/
111 /* 0x02 -> Fix Directory Entry */
112 /* Errors */
113 /* 0x04 -> Fix Lost Clusters */
114 /* */
115 /* errors_detected Specifies the destination */
116 /* ULONG to place the error */
117 /* report from media check. */
118 /* This has a similar bit map */
119 /* as before: */
120 /* */
121 /* 0x01 -> FAT Chain Error(s) */
122 /* 0x02 -> Directory Entry */
123 /* Error(s) */
124 /* 0x04 -> Lost Cluster(s) */
125 /* */
126 /* OUTPUT */
127 /* */
128 /* FX_SUCCESS Media check performed its */
129 /* operation successfully. */
130 /* This does not mean that */
131 /* there were no errors. The */
132 /* errors_detected variable */
133 /* needs to be examined. */
134 /* FX_MEDIA_NOT_OPEN The media was not open. */
135 /* FX_NOT_ENOUGH_MEMORY The scratch memory was not */
136 /* large enough or the nesting */
137 /* depth was greater than the */
138 /* maximum specified. */
139 /* FX_IO_ERROR I/O Error reading/writing to */
140 /* the media. */
141 /* FX_ERROR_NOT_FIXED Fundamental problem with */
142 /* media that couldn't be fixed*/
143 /* */
144 /* CALLS */
145 /* */
146 /* _fx_media_cache_invalidate Invalidate the cache */
147 /* _fx_media_check_FAT_chain_check Walk the supplied FAT chain */
148 /* _fx_media_check_lost_cluster_check Check for lost clusters */
149 /* _fx_directory_entry_read Directory entry read */
150 /* _fx_directory_entry_write Directory entry write */
151 /* _fx_media_flush Flush changes to the media */
152 /* _fx_utility_FAT_entry_write Write value to FAT entry */
153 /* */
154 /* CALLED BY */
155 /* */
156 /* Application Code */
157 /* */
158 /**************************************************************************/
159 18360 UINT _fx_media_check(FX_MEDIA *media_ptr, UCHAR *scratch_memory_ptr, ULONG scratch_memory_size, ULONG error_correction_option, ULONG *errors_detected)
160 {
161
162 CURRENT_DIRECTORY_ENTRY *current_directory;
163 ULONG total_entries, last_cluster, valid_clusters;
164 ULONG bytes_per_cluster, i, current_errors;
165 UINT status, long_name_size;
166 UINT current_directory_index;
167 UCHAR *logical_fat, *working_ptr;
168 ALIGN_TYPE address_mask;
169 FX_DIR_ENTRY *temp_dir_ptr, *source_dir_ptr, *dir_entry_ptr;
170
171 #ifdef TX_ENABLE_EVENT_TRACE
172 TX_TRACE_BUFFER_ENTRY *trace_event;
173 ULONG trace_timestamp;
174 #endif
175
176
177 /* Check the media to make sure it is open. */
178
2/2
✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 4 taken 18351 times.
18360 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
179 {
180
181 /* Return the media not opened error. */
182 9 return(FX_MEDIA_NOT_OPEN);
183 }
184
185 /* If trace is enabled, insert this event into the trace buffer. */
186 FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CHECK, media_ptr, scratch_memory_ptr, scratch_memory_size, 0, FX_TRACE_MEDIA_EVENTS, &trace_event, &trace_timestamp)
187
188 /* Protect against other threads accessing the media. */
189 10193 FX_PROTECT
190
191 /* Determine if there are any opened files. */
192
4/4
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 8154 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 8 taken 10188 times.
18351 if (media_ptr -> fx_media_opened_file_count)
193 {
194
195 /* There are opened files... this is an error! */
196
197 /* Release protection. */
198 5 FX_UNPROTECT
199
200 /* Return an error. */
201 9 return(FX_ACCESS_ERROR);
202 }
203
204 /* Invalidate the cache. */
205 18342 _fx_media_cache_invalidate(media_ptr);
206
207 /* Initialize the reported error flag. */
208 18342 *errors_detected = 0;
209
210 /* Calculate the long name size, rounded up to something that is evenly divisible by 4. */
211 18342 long_name_size = (((FX_MAX_LONG_NAME_LEN + 3) >> 2) << 2);
212
213 /* Calculate the number of bytes per cluster. */
214 18342 bytes_per_cluster = media_ptr -> fx_media_sectors_per_cluster * media_ptr -> fx_media_bytes_per_sector;
215
216 /* Setup address mask. */
217 18342 address_mask = sizeof(ULONG) - 1;
218 18342 address_mask = ~address_mask;
219
220 /* Setup working pointer. */
221 18342 working_ptr = scratch_memory_ptr + (sizeof(ULONG) - 1);
222 18342 working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
223
224 /* Memory is set aside for two FX_DIR_ENTRY structures */
225 18342 dir_entry_ptr = (FX_DIR_ENTRY *)working_ptr;
226
227 /* Adjust the scratch memory pointer forward. */
228 18342 working_ptr = &working_ptr[sizeof(FX_DIR_ENTRY)];
229
230 /* Setup the name buffer for the first directory entry. */
231 18342 dir_entry_ptr -> fx_dir_entry_name = (CHAR *)working_ptr;
232
233 /* Adjust the scratch memory pointer forward. */
234 18342 working_ptr = working_ptr + long_name_size + (sizeof(ULONG) - 1);
235 18342 working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
236
237 /* Setup the source directory entry. */
238 18342 source_dir_ptr = (FX_DIR_ENTRY *)working_ptr;
239
240 /* Adjust the scratch memory pointer forward. */
241 18342 working_ptr = &working_ptr[sizeof(FX_DIR_ENTRY)];
242
243 /* Setup the name buffer for the source directory entry. */
244 18342 source_dir_ptr -> fx_dir_entry_name = (CHAR *)working_ptr;
245
246 /* Adjust the scratch memory pointer forward. */
247 18342 working_ptr = working_ptr + long_name_size + (sizeof(ULONG) - 1);
248 18342 working_ptr = (UCHAR *)(((ALIGN_TYPE)working_ptr) & address_mask);
249
250 /* Setup the current directory stack memory. */
251 18342 current_directory = (CURRENT_DIRECTORY_ENTRY *)working_ptr;
252
253 /* Allocate space for the size of the directory entry stack. This basically
254 defines the maximum level of sub-directories supported. */
255 18342 working_ptr = &working_ptr[(FX_MAX_DIRECTORY_NESTING * sizeof(CURRENT_DIRECTORY_ENTRY))];
256
257 /* Setup the initial current directory entry. */
258 18342 current_directory_index = 0;
259
260 /* Adjust the size to account for the header information. */
261
4/4
✓ Branch 7 → 8 taken 8 times.
✓ Branch 7 → 9 taken 8146 times.
✓ Branch 9 → 10 taken 10 times.
✓ Branch 9 → 12 taken 10178 times.
18342 if (scratch_memory_size < (ULONG)((working_ptr - scratch_memory_ptr)))
262 {
263
264 /* Release media protection. */
265 10 FX_UNPROTECT
266
267 /* Return the not enough memory error. */
268 18 return(FX_NOT_ENOUGH_MEMORY);
269 }
270
271 /* Adjust the scratch memory size. */
272 18324 scratch_memory_size = scratch_memory_size - (ULONG)(working_ptr - scratch_memory_ptr);
273
274 /* Memory is set aside for logical FAT - one bit per cluster */
275 18324 logical_fat = (UCHAR *)working_ptr;
276
277 /* Determine if there is enough memory. */
278
4/4
✓ Branch 9 → 10 taken 4004 times.
✓ Branch 9 → 11 taken 4142 times.
✓ Branch 12 → 13 taken 5005 times.
✓ Branch 12 → 15 taken 5173 times.
18324 if (scratch_memory_size < ((media_ptr -> fx_media_total_clusters >> 3) + 1))
279 {
280
281 /* Release media protection. */
282 5005 FX_UNPROTECT
283
284 /* Return the not enough memory error. */
285 9009 return(FX_NOT_ENOUGH_MEMORY);
286 }
287
288 /* Initialize the logical FAT table. */
289
4/4
✓ Branch 13 → 12 taken 3464584 times.
✓ Branch 13 → 14 taken 4142 times.
✓ Branch 17 → 16 taken 4295986 times.
✓ Branch 17 → 18 taken 5173 times.
7769885 for (i = 0; i < ((media_ptr -> fx_media_total_clusters >> 3) + 1); i++)
290 {
291 /* Clear the logical FAT entry, which actually represents eight clusters. */
292 7760570 logical_fat[i] = 0;
293 }
294
295
296 #ifdef FX_ENABLE_FAULT_TOLERANT
297
4/4
✓ Branch 14 → 15 taken 18 times.
✓ Branch 14 → 18 taken 2062 times.
✓ Branch 18 → 19 taken 18 times.
✓ Branch 18 → 22 taken 2062 times.
4160 if (media_ptr -> fx_media_fault_tolerant_enabled)
298 {
299 ULONG cluster, cluster_number;
300
301 /* Mark the cluster used by fault tolerant as valid. */
302 36 for (cluster = media_ptr -> fx_media_fault_tolerant_start_cluster;
303
4/4
✓ Branch 17 → 16 taken 100 times.
✓ Branch 17 → 18 taken 18 times.
✓ Branch 21 → 20 taken 100 times.
✓ Branch 21 → 22 taken 18 times.
236 cluster < media_ptr -> fx_media_fault_tolerant_start_cluster + media_ptr -> fx_media_fault_tolerant_clusters;
304 200 cluster++)
305 {
306
307 200 cluster_number = cluster;
308
309
310 200 logical_fat[cluster_number >> 3] = (UCHAR)(logical_fat[cluster_number >> 3] | (1 << (cluster_number & 7)));
311 }
312 }
313 #endif /* FX_ENABLE_FAULT_TOLERANT */
314
315 /* If FAT32 is present, determine if the root directory is coherent. */
316
7/7
✓ Branch 14 → 15 taken 20 times.
✓ Branch 14 → 26 taken 2042 times.
✓ Branch 18 → 19 taken 66 times.
✓ Branch 18 → 30 taken 2044 times.
✓ Branch 18 → 33 taken 3063 times.
✓ Branch 22 → 23 taken 36 times.
✓ Branch 22 → 37 taken 2044 times.
9315 if (media_ptr -> fx_media_32_bit_FAT)
317 {
318
319 /* A 32-bit FAT is present. We need to walk the clusters of the root directory to determine if
320 it is intact. */
321 122 current_errors = _fx_media_check_FAT_chain_check(media_ptr, media_ptr -> fx_media_root_cluster_32,
322 &last_cluster, &valid_clusters, logical_fat);
323
324 /* Make them part of the errors reported to the caller. */
325 122 *errors_detected = *errors_detected | current_errors;
326
327 /* Update the trace event with the errors detected. */
328 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
329
330 /* Determine if the I/O error is set. */
331
7/7
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 18 taken 18 times.
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 22 taken 34 times.
✓ Branch 20 → 23 taken 27 times.
✓ Branch 24 → 25 taken 2 times.
✓ Branch 24 → 27 taken 34 times.
122 if (current_errors & FX_IO_ERROR)
332 {
333
334 /* Release media protection. */
335 5 FX_UNPROTECT
336
337 /* File I/O Error. */
338 9 return(FX_IO_ERROR);
339 }
340
341 /* Check the status. */
342
8/8
✓ Branch 18 → 19 taken 10 times.
✓ Branch 18 → 26 taken 8 times.
✓ Branch 22 → 23 taken 10 times.
✓ Branch 22 → 30 taken 24 times.
✓ Branch 23 → 24 taken 15 times.
✓ Branch 23 → 33 taken 12 times.
✓ Branch 27 → 28 taken 10 times.
✓ Branch 27 → 37 taken 24 times.
113 if (*errors_detected)
343 {
344
345 /* Determine if we can fix the FAT32 root directory error. */
346
15/15
✓ Branch 19 → 20 taken 8 times.
✓ Branch 19 → 25 taken 2 times.
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 25 taken 4 times.
✓ Branch 23 → 24 taken 8 times.
✓ Branch 23 → 29 taken 2 times.
✓ Branch 24 → 25 taken 16 times.
✓ Branch 24 → 29 taken 4 times.
✓ Branch 24 → 31 taken 3 times.
✓ Branch 25 → 26 taken 6 times.
✓ Branch 25 → 31 taken 6 times.
✓ Branch 28 → 29 taken 8 times.
✓ Branch 28 → 35 taken 2 times.
✓ Branch 29 → 30 taken 4 times.
✓ Branch 29 → 35 taken 4 times.
45 if ((valid_clusters) && (error_correction_option & FX_FAT_CHAIN_ERROR))
347 {
348
349 /* Make the chain end at the last cluster. */
350 18 status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
351
352 /* Determine if the write was successful. */
353
8/8
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 2 times.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 26 → 28 taken 2 times.
✓ Branch 27 → 28 taken 3 times.
✓ Branch 27 → 30 taken 3 times.
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 34 taken 2 times.
18 if (status)
354 {
355
356 /* Release media protection. */
357 5 FX_UNPROTECT
358
359 /* Return the error code. */
360 9 return(status);
361 }
362
363 /* Adjust the total entries in the root directory. */
364 9 media_ptr -> fx_media_root_directory_entries = (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
365 }
366 else
367 {
368
369 /* Release media protection. */
370 15 FX_UNPROTECT
371
372 /* Return an error. */
373 27 return(FX_ERROR_NOT_FIXED);
374 }
375 }
376 }
377
378 /* Pickup total entries in the root directory. */
379 9270 total_entries = media_ptr -> fx_media_root_directory_entries;
380
381 /* Set temp directory pointer to NULL. */
382 9270 temp_dir_ptr = FX_NULL;
383
384 /* Put the root directory information in the entry stack */
385 9270 current_directory[current_directory_index].current_total_entries = total_entries;
386 9270 current_directory[current_directory_index].current_start_cluster = media_ptr -> fx_media_fat_last;
387 9270 current_directory[current_directory_index].current_directory_entry = 0;
388
389 /* Now we shall do the checking in depth first manner. */
390 do
391 {
392
393 /* Pickup the directory index. */
394 11402 i = current_directory[current_directory_index].current_directory_entry;
395
396 /* Loop to process remaining directory entries. */
397
8/8
✓ Branch 68 → 28 taken 28874 times.
✓ Branch 68 → 69 taken 10 times.
✓ Branch 72 → 32 taken 28834 times.
✓ Branch 72 → 73 taken 10 times.
✓ Branch 81 → 35 taken 44032 times.
✓ Branch 81 → 82 taken 15 times.
✓ Branch 85 → 39 taken 28834 times.
✓ Branch 85 → 86 taken 10 times.
130619 while (i < current_directory[current_directory_index].current_total_entries)
398 {
399
400 /* Read a directory entry. */
401 130574 status = _fx_directory_entry_read(media_ptr, temp_dir_ptr, &i, dir_entry_ptr);
402
403 /* Determine if the read was successful. */
404
8/8
✓ Branch 29 → 30 taken 1438 times.
✓ Branch 29 → 31 taken 27436 times.
✓ Branch 33 → 34 taken 1415 times.
✓ Branch 33 → 35 taken 27419 times.
✓ Branch 36 → 37 taken 2165 times.
✓ Branch 36 → 39 taken 41867 times.
✓ Branch 40 → 41 taken 1415 times.
✓ Branch 40 → 43 taken 27419 times.
130574 if (status)
405 {
406
407 /* Release media protection. */
408 3580 FX_UNPROTECT
409
410 /* Return the error code. */
411 6433 return(status);
412 }
413
414 /* Check for the last entry. */
415
8/8
✓ Branch 31 → 32 taken 504 times.
✓ Branch 31 → 33 taken 26932 times.
✓ Branch 35 → 36 taken 522 times.
✓ Branch 35 → 37 taken 26897 times.
✓ Branch 39 → 40 taken 782 times.
✓ Branch 39 → 41 taken 41085 times.
✓ Branch 43 → 44 taken 522 times.
✓ Branch 43 → 45 taken 26897 times.
124141 if (dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_DONE)
416 {
417
418 /* Last entry in this directory - no need to check further. */
419 2330 break;
420 }
421
422 /* Is the entry free? */
423
16/16
✓ Branch 33 → 34 taken 10 times.
✓ Branch 33 → 36 taken 26922 times.
✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 36 taken 8 times.
✓ Branch 37 → 38 taken 10 times.
✓ Branch 37 → 40 taken 26887 times.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 38 → 40 taken 8 times.
✓ Branch 41 → 42 taken 15 times.
✓ Branch 41 → 44 taken 41070 times.
✓ Branch 42 → 43 taken 3 times.
✓ Branch 42 → 44 taken 12 times.
✓ Branch 45 → 46 taken 10 times.
✓ Branch 45 → 48 taken 26887 times.
✓ Branch 46 → 47 taken 2 times.
✓ Branch 46 → 48 taken 8 times.
121811 if ((dir_entry_ptr -> fx_dir_entry_name[0] == (CHAR)FX_DIR_ENTRY_FREE) && (dir_entry_ptr -> fx_dir_entry_short_name[0] == 0))
424 {
425
426 /* A deleted entry */
427 9 i++;
428 9 continue;
429 }
430
431
432 /* Look for any cross links or errors in the FAT chain of current directory entry. */
433 121802 current_errors = _fx_media_check_FAT_chain_check(media_ptr, dir_entry_ptr -> fx_dir_entry_cluster,
434 &last_cluster, &valid_clusters, logical_fat);
435
436 /* Make them part of the errors reported to the caller. */
437 121802 *errors_detected = *errors_detected | current_errors;
438
439 /* Update the trace event with the errors detected. */
440 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
441
442 /* Determine if the I/O error is set. */
443
8/8
✓ Branch 37 → 38 taken 454 times.
✓ Branch 37 → 39 taken 26476 times.
✓ Branch 41 → 42 taken 426 times.
✓ Branch 41 → 43 taken 26469 times.
✓ Branch 45 → 46 taken 703 times.
✓ Branch 45 → 48 taken 40379 times.
✓ Branch 49 → 50 taken 426 times.
✓ Branch 49 → 52 taken 26469 times.
121802 if (current_errors & FX_IO_ERROR)
444 {
445
446 /* Release media protection. */
447 1129 FX_UNPROTECT
448
449 /* File I/O Error. */
450 2009 return(FX_IO_ERROR);
451 }
452
453 /* Check for errors. */
454
8/8
✓ Branch 39 → 40 taken 24686 times.
✓ Branch 39 → 45 taken 1790 times.
✓ Branch 43 → 44 taken 24663 times.
✓ Branch 43 → 49 taken 1806 times.
✓ Branch 48 → 49 taken 37694 times.
✓ Branch 48 → 55 taken 2685 times.
✓ Branch 52 → 53 taken 24663 times.
✓ Branch 52 → 59 taken 1806 times.
119793 if (*errors_detected)
455 {
456
457 /* Determine if we can fix the FAT chain. */
458
8/8
✓ Branch 40 → 41 taken 10190 times.
✓ Branch 40 → 45 taken 14496 times.
✓ Branch 44 → 45 taken 10167 times.
✓ Branch 44 → 49 taken 14496 times.
✓ Branch 49 → 50 taken 15950 times.
✓ Branch 49 → 55 taken 21744 times.
✓ Branch 53 → 54 taken 10167 times.
✓ Branch 53 → 59 taken 14496 times.
111706 if (error_correction_option & FX_FAT_CHAIN_ERROR)
459 {
460
461 /* Determine if there is a valid cluster to write the EOF to. */
462
8/8
✓ Branch 41 → 42 taken 978 times.
✓ Branch 41 → 45 taken 9212 times.
✓ Branch 45 → 46 taken 978 times.
✓ Branch 45 → 49 taken 9189 times.
✓ Branch 50 → 51 taken 1517 times.
✓ Branch 50 → 55 taken 14433 times.
✓ Branch 54 → 55 taken 978 times.
✓ Branch 54 → 59 taken 9189 times.
46474 if (valid_clusters)
463 {
464
465 /* Write EOF in the last FAT entry. */
466 4451 status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
467
468 /* Determine if the write was successful. */
469
8/8
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 45 taken 976 times.
✓ Branch 47 → 48 taken 2 times.
✓ Branch 47 → 49 taken 976 times.
✓ Branch 52 → 53 taken 3 times.
✓ Branch 52 → 55 taken 1514 times.
✓ Branch 56 → 57 taken 2 times.
✓ Branch 56 → 59 taken 976 times.
4451 if (status)
470 {
471
472 /* Release media protection. */
473 5 FX_UNPROTECT
474
475 /* Return the error code. */
476 9 return(status);
477 }
478 }
479 }
480 }
481
482 /* Determine if we need to update the size of the directory entry. */
483
8/8
✓ Branch 45 → 46 taken 3068 times.
✓ Branch 45 → 53 taken 23406 times.
✓ Branch 49 → 50 taken 3068 times.
✓ Branch 49 → 57 taken 23399 times.
✓ Branch 55 → 56 taken 4614 times.
✓ Branch 55 → 64 taken 35762 times.
✓ Branch 59 → 60 taken 3068 times.
✓ Branch 59 → 68 taken 23399 times.
119784 if (dir_entry_ptr -> fx_dir_entry_file_size > (valid_clusters * bytes_per_cluster))
484 {
485
486 /* Yes, update the directory entry's size. */
487 13818 dir_entry_ptr -> fx_dir_entry_file_size = valid_clusters * bytes_per_cluster;
488
489 /* Determine if the new file size is zero. */
490
8/8
✓ Branch 46 → 47 taken 1622 times.
✓ Branch 46 → 49 taken 1446 times.
✓ Branch 50 → 51 taken 1622 times.
✓ Branch 50 → 53 taken 1446 times.
✓ Branch 56 → 57 taken 2433 times.
✓ Branch 56 → 59 taken 2181 times.
✓ Branch 60 → 61 taken 1622 times.
✓ Branch 60 → 63 taken 1446 times.
13818 if (dir_entry_ptr -> fx_dir_entry_file_size == 0)
491 {
492
493 /* Consider this a directory error. */
494 7299 *errors_detected = *errors_detected | FX_DIRECTORY_ERROR;
495
496 /* Update the trace event with the errors detected. */
497 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
498
499 /* Clear the starting cluster number of this directory entry. */
500 7299 dir_entry_ptr -> fx_dir_entry_cluster = 0;
501
502 /* If directory fixing is required, delete this directory entry as well. */
503
8/8
✓ Branch 47 → 48 taken 820 times.
✓ Branch 47 → 49 taken 802 times.
✓ Branch 51 → 52 taken 820 times.
✓ Branch 51 → 53 taken 802 times.
✓ Branch 57 → 58 taken 1230 times.
✓ Branch 57 → 59 taken 1203 times.
✓ Branch 61 → 62 taken 820 times.
✓ Branch 61 → 63 taken 802 times.
7299 if (error_correction_option & FX_DIRECTORY_ERROR)
504 {
505
506 /* Mark the entry as deleted. */
507 3690 dir_entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
508 3690 dir_entry_ptr -> fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
509 }
510 }
511
512 /* Only update the directory if the FAT chain was actually updated. */
513
8/8
✓ Branch 49 → 50 taken 1506 times.
✓ Branch 49 → 53 taken 1562 times.
✓ Branch 53 → 54 taken 1506 times.
✓ Branch 53 → 57 taken 1562 times.
✓ Branch 59 → 60 taken 2271 times.
✓ Branch 59 → 64 taken 2343 times.
✓ Branch 63 → 64 taken 1506 times.
✓ Branch 63 → 68 taken 1562 times.
13818 if (error_correction_option & FX_FAT_CHAIN_ERROR)
514 {
515
516 /* Update the directory entry. */
517 6789 status = _fx_directory_entry_write(media_ptr, dir_entry_ptr);
518
519 /* Determine if the write was successful. */
520
8/8
✓ Branch 51 → 52 taken 108 times.
✓ Branch 51 → 53 taken 1398 times.
✓ Branch 55 → 56 taken 159 times.
✓ Branch 55 → 57 taken 1347 times.
✓ Branch 61 → 62 taken 132 times.
✓ Branch 61 → 64 taken 2139 times.
✓ Branch 65 → 66 taken 159 times.
✓ Branch 65 → 68 taken 1347 times.
6789 if (status)
521 {
522
523 /* Release media protection. */
524 291 FX_UNPROTECT
525
526 /* Return the error code. */
527 558 return(status);
528 }
529 }
530 }
531
532 /* Determine if the entry is a sub-directory. */
533
8/8
✓ Branch 53 → 54 taken 922 times.
✓ Branch 53 → 60 taken 25444 times.
✓ Branch 57 → 58 taken 922 times.
✓ Branch 57 → 64 taken 25386 times.
✓ Branch 64 → 65 taken 1421 times.
✓ Branch 64 → 72 taken 38823 times.
✓ Branch 68 → 69 taken 922 times.
✓ Branch 68 → 76 taken 25386 times.
119226 if ((dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
534
8/8
✓ Branch 54 → 55 taken 6 times.
✓ Branch 54 → 60 taken 916 times.
✓ Branch 58 → 59 taken 6 times.
✓ Branch 58 → 64 taken 916 times.
✓ Branch 65 → 66 taken 9 times.
✓ Branch 65 → 72 taken 1412 times.
✓ Branch 69 → 70 taken 6 times.
✓ Branch 69 → 76 taken 916 times.
4187 && (valid_clusters == 0))
535 {
536
537 /* Consider this a directory error. */
538 27 *errors_detected = *errors_detected | FX_DIRECTORY_ERROR;
539
540 /* Update the trace event with the errors detected. */
541 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
542
543 /* Determine if we can fix the error. */
544
8/8
✓ Branch 55 → 56 taken 4 times.
✓ Branch 55 → 60 taken 2 times.
✓ Branch 59 → 60 taken 4 times.
✓ Branch 59 → 64 taken 2 times.
✓ Branch 66 → 67 taken 6 times.
✓ Branch 66 → 72 taken 3 times.
✓ Branch 70 → 71 taken 4 times.
✓ Branch 70 → 76 taken 2 times.
27 if (error_correction_option & FX_DIRECTORY_ERROR)
545 {
546
547 /* Yes, make the directory entry free. */
548 18 dir_entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
549 18 dir_entry_ptr -> fx_dir_entry_short_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
550
551 /* Delete the sub-directory entry. */
552 18 status = _fx_directory_entry_write(media_ptr, dir_entry_ptr);
553
554 /* Determine if the write was successful. */
555
8/8
✓ Branch 57 → 58 taken 2 times.
✓ Branch 57 → 59 taken 2 times.
✓ Branch 61 → 62 taken 2 times.
✓ Branch 61 → 63 taken 2 times.
✓ Branch 68 → 69 taken 3 times.
✓ Branch 68 → 71 taken 3 times.
✓ Branch 72 → 73 taken 2 times.
✓ Branch 72 → 75 taken 2 times.
18 if (status)
556 {
557
558 /* Release media protection. */
559 5 FX_UNPROTECT
560
561 /* Return the error code. */
562 9 return(status);
563 }
564
565 /* Move to next entry. */
566 9 i++;
567 9 continue;
568 }
569 }
570
571 /* Determine if the entry is a directory. */
572
8/8
✓ Branch 60 → 61 taken 918 times.
✓ Branch 60 → 64 taken 25444 times.
✓ Branch 64 → 65 taken 918 times.
✓ Branch 64 → 68 taken 25386 times.
✓ Branch 72 → 73 taken 1415 times.
✓ Branch 72 → 77 taken 38823 times.
✓ Branch 76 → 77 taken 918 times.
✓ Branch 76 → 81 taken 25386 times.
119208 if (dir_entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
573 {
574
575 /* Current entry is a directory. The algorithm is designed to follow all
576 sub-directories immediately, i.e., a depth first search. */
577
578 /* First, save the next entry position. */
579 4169 current_directory[current_directory_index].current_directory_entry = i + 1;
580
581 /* Push the current directory entry on the stack. */
582 4169 current_directory_index++;
583
584 /* Check for current directory stack overflow. */
585
8/8
✓ Branch 61 → 62 taken 2 times.
✓ Branch 61 → 63 taken 916 times.
✓ Branch 65 → 66 taken 2 times.
✓ Branch 65 → 67 taken 916 times.
✓ Branch 73 → 74 taken 3 times.
✓ Branch 73 → 76 taken 1412 times.
✓ Branch 77 → 78 taken 2 times.
✓ Branch 77 → 80 taken 916 times.
4169 if (current_directory_index >= FX_MAX_DIRECTORY_NESTING)
586 {
587
588 /* Release media protection. */
589 5 FX_UNPROTECT
590
591 /* Current directory stack overflow. Return error. */
592 9 return(FX_NOT_ENOUGH_MEMORY);
593 }
594
595 /* Otherwise, setup the new directory entry. */
596 4160 current_directory[current_directory_index].current_total_entries = (valid_clusters * bytes_per_cluster) / FX_DIR_ENTRY_SIZE;
597 4160 current_directory[current_directory_index].current_start_cluster = dir_entry_ptr -> fx_dir_entry_cluster;
598 4160 current_directory[current_directory_index].current_directory_entry = 2;
599
600 /* Setup new source directory. */
601 4160 source_dir_ptr -> fx_dir_entry_cluster = dir_entry_ptr -> fx_dir_entry_cluster;
602 4160 source_dir_ptr -> fx_dir_entry_file_size = current_directory[current_directory_index].current_total_entries;
603 4160 source_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
604 4160 temp_dir_ptr = source_dir_ptr;
605
606 /* Skip the first two entries of sub-directories. */
607 4160 i = 2;
608
609 }
610 else
611 {
612
613 /* Regular file entry. */
614
615 /* Check for an invalid file size. */
616
8/8
✓ Branch 64 → 65 taken 2 times.
✓ Branch 64 → 66 taken 25442 times.
✓ Branch 68 → 69 taken 2 times.
✓ Branch 68 → 70 taken 25384 times.
✓ Branch 77 → 78 taken 3 times.
✓ Branch 77 → 79 taken 38820 times.
✓ Branch 81 → 82 taken 2 times.
✓ Branch 81 → 83 taken 25384 times.
115039 if (((valid_clusters * bytes_per_cluster) - dir_entry_ptr -> fx_dir_entry_file_size) > bytes_per_cluster)
617 {
618
619 /* There are more clusters allocated than needed for the file's size. Indicate that this error
620 is present. */
621 9 *errors_detected = *errors_detected | FX_FILE_SIZE_ERROR;
622
623 /* Update the trace event with the errors detected. */
624 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
625
626 /* For now, don't shorten the cluster chain. */
627 }
628
629 /* Look into the next entry in the current directory. */
630 115039 i++;
631 }
632 }
633
634 /* Once we get here, we have exhausted the current directory and need to return to the previous
635 directory. */
636
637 /* Check for being at the root directory. */
638
8/8
✓ Branch 69 → 70 taken 46 times.
✓ Branch 69 → 71 taken 468 times.
✓ Branch 73 → 74 taken 64 times.
✓ Branch 73 → 75 taken 468 times.
✓ Branch 82 → 83 taken 69 times.
✓ Branch 82 → 84 taken 728 times.
✓ Branch 86 → 87 taken 64 times.
✓ Branch 86 → 88 taken 468 times.
2375 if (current_directory_index == 0)
639 {
640
641 /* Yes, we have now exhausted searching the root directory so we are done! */
642 243 break;
643 }
644
645 /* Backup to the place we left off in the previous directory. */
646 2132 current_directory_index--;
647
648 /* Determine if we are now back at the root directory. */
649
8/8
✓ Branch 71 → 72 taken 464 times.
✓ Branch 71 → 73 taken 4 times.
✓ Branch 75 → 76 taken 464 times.
✓ Branch 75 → 77 taken 4 times.
✓ Branch 84 → 85 taken 722 times.
✓ Branch 84 → 86 taken 6 times.
✓ Branch 88 → 89 taken 464 times.
✓ Branch 88 → 90 taken 4 times.
2132 if (current_directory[current_directory_index].current_start_cluster == media_ptr -> fx_media_fat_last)
650 {
651
652 /* The search directory should be NULL since it is the root directory. */
653 2114 temp_dir_ptr = FX_NULL;
654 }
655 else
656 {
657
658 /* Otherwise, we are returning to a sub-directory. Setup the search directory
659 appropriately. */
660 18 source_dir_ptr -> fx_dir_entry_cluster = current_directory[current_directory_index].current_start_cluster;
661 18 source_dir_ptr -> fx_dir_entry_file_size = current_directory[current_directory_index].current_total_entries;
662 18 source_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
663 18 temp_dir_ptr = source_dir_ptr;
664 }
665 } while (1);
666
667
668 /* At this point, all the files and sub-directories have been examined. We now need to check for
669 lost clusters in the logical FAT. A lost cluster is basically anything that is not reported in
670 the logical FAT that has a non-zero value in the real FAT. */
671 243 current_errors = _fx_media_check_lost_cluster_check(media_ptr, logical_fat, media_ptr -> fx_media_total_clusters, error_correction_option);
672
673 /* Incorporate the error returned by the lost FAT check. */
674 243 *errors_detected = *errors_detected | current_errors;
675
676 /* Update the trace event with the errors detected. */
677 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_MEDIA_CHECK, 0, 0, 0, *errors_detected)
678
679 /* Determine if the I/O error is set. */
680
8/8
✓ Branch 76 → 77 taken 6 times.
✓ Branch 76 → 78 taken 40 times.
✓ Branch 80 → 81 taken 6 times.
✓ Branch 80 → 82 taken 58 times.
✓ Branch 89 → 90 taken 9 times.
✓ Branch 89 → 92 taken 60 times.
✓ Branch 93 → 94 taken 6 times.
✓ Branch 93 → 96 taken 58 times.
243 if (current_errors & FX_IO_ERROR)
681 {
682
683 /* Release media protection. */
684 15 FX_UNPROTECT
685
686 /* File I/O Error. */
687 27 return(FX_IO_ERROR);
688 }
689
690 /* Determine if there was any error and update was selected. */
691
16/16
✓ Branch 78 → 79 taken 30 times.
✓ Branch 78 → 81 taken 10 times.
✓ Branch 79 → 80 taken 24 times.
✓ Branch 79 → 81 taken 6 times.
✓ Branch 82 → 83 taken 30 times.
✓ Branch 82 → 85 taken 28 times.
✓ Branch 83 → 84 taken 24 times.
✓ Branch 83 → 85 taken 6 times.
✓ Branch 92 → 93 taken 48 times.
✓ Branch 92 → 95 taken 12 times.
✓ Branch 93 → 94 taken 36 times.
✓ Branch 93 → 95 taken 12 times.
✓ Branch 96 → 97 taken 32 times.
✓ Branch 96 → 99 taken 26 times.
✓ Branch 97 → 98 taken 24 times.
✓ Branch 97 → 99 taken 8 times.
216 if ((*errors_detected) && (error_correction_option))
692 {
693
694 /* Flush any unwritten items to the media. */
695 108 _fx_media_flush(media_ptr);
696 }
697
698 /* Release media protection. */
699 118 FX_UNPROTECT
700
701 /* At this point, we have completed the diagnostic of the media, return success! */
702 216 return(FX_SUCCESS);
703 }
704
705