GCC Code Coverage Report


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

fx_directory_next_full_entry_find.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 /** Directory */
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_utility.h"
32
33 #ifndef FX_NO_LOCAL_PATH
34 FX_LOCAL_PATH_SETUP
35 #endif
36
37
38 /**************************************************************************/
39 /* */
40 /* FUNCTION RELEASE */
41 /* */
42 /* _fx_directory_next_full_entry_find PORTABLE C */
43 /* 6.1 */
44 /* AUTHOR */
45 /* */
46 /* William E. Lamie, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function returns the name of the next entry in the current */
51 /* working directory and various information about the name. The */
52 /* function that returns the first name in the current directory must */
53 /* be called prior to this function. */
54 /* */
55 /* INPUT */
56 /* */
57 /* media_ptr Media control block pointer */
58 /* directory_name Destination for directory */
59 /* name */
60 /* attributes Destination for attributes */
61 /* size Destination for size */
62 /* year Destination for year */
63 /* month Destination for month */
64 /* day Destination for day */
65 /* hour Destination for hour */
66 /* minute Destination for minute */
67 /* second Destination for second */
68 /* */
69 /* OUTPUT */
70 /* */
71 /* return status */
72 /* */
73 /* CALLS */
74 /* */
75 /* _fx_directory_entry_read Read entries from root dir */
76 /* _fx_utility_FAT_entry_read Read FAT entries */
77 /* */
78 /* CALLED BY */
79 /* */
80 /* Application Code and */
81 /* FileX System Functions */
82 /* */
83 /**************************************************************************/
84 496 UINT _fx_directory_next_full_entry_find(FX_MEDIA *media_ptr,
85 CHAR *directory_name, UINT *attributes, ULONG *size,
86 UINT *year, UINT *month, UINT *day, UINT *hour, UINT *minute, UINT *second)
87 {
88
89 ULONG i;
90 UINT status;
91 UINT temp_status;
92 496 ULONG cluster, next_cluster = 0;
93 ULONG64 directory_size;
94 FX_DIR_ENTRY entry;
95 FX_DIR_ENTRY *search_dir_ptr;
96 FX_PATH *path_ptr;
97 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
98 UINT index;
99 496 CHAR *path_string_ptr = FX_NULL;
100 #endif
101
102
103 #ifndef FX_MEDIA_STATISTICS_DISABLE
104
105 /* Increment the number of times this service has been called. */
106 496 media_ptr -> fx_media_directory_next_full_entry_finds++;
107 #endif
108
109 /* Setup pointer to media name buffer. */
110 496 entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
111
112 /* Clear the short name string. */
113 496 entry.fx_dir_entry_short_name[0] = 0;
114
115
116 /* Check the media to make sure it is open. */
117
2/2
✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 4 taken 487 times.
496 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
118 {
119
120 /* Return the media not opened error. */
121 9 return(FX_MEDIA_NOT_OPEN);
122 }
123
124 /* If trace is enabled, insert this event into the trace buffer. */
125 FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_FULL_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
126
127 /* Protect against other threads accessing the media. */
128 275 FX_PROTECT
129
130 /* First check for a local path pointer stored in the thread control block. This
131 is only available in ThreadX Version 4 and above. */
132 #ifndef FX_NO_LOCAL_PATH
133
2/2
✓ Branch 5 → 6 taken 10 times.
✓ Branch 5 → 9 taken 265 times.
275 if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
134 {
135
136 /* Setup the default path pointer. */
137 10 path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
138
139 /* Determine if we are at the root directory. */
140
2/2
✓ Branch 6 → 7 taken 5 times.
✓ Branch 6 → 8 taken 5 times.
10 if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
141 {
142
143 /* No, we are not at the root directory. */
144
145 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
146
147 /* Setup pointer to the path. */
148 5 path_string_ptr = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
149 #endif
150
151 /* Set the internal pointer to the search directory as well. */
152 5 search_dir_ptr = &path_ptr -> fx_path_directory;
153 }
154 else
155 {
156
157 /* The current default directory is the root so just set the
158 search directory pointer to NULL. */
159 5 search_dir_ptr = FX_NULL;
160 }
161 }
162 else
163 #endif
164
165 /* Set the initial search directory to the current working
166 directory - if there is one. */
167
4/4
✓ Branch 4 → 5 taken 136 times.
✓ Branch 4 → 6 taken 76 times.
✓ Branch 9 → 10 taken 170 times.
✓ Branch 9 → 11 taken 95 times.
477 if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
168 {
169
170 /* Setup the path pointer to the global media path. */
171 306 path_ptr = &media_ptr -> fx_media_default_path;
172
173 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
174
175 /* Setup pointer to the path. */
176 306 path_string_ptr = media_ptr -> fx_media_default_path.fx_path_string;
177 #endif
178
179 /* Set the internal pointer to the search directory as well. */
180 306 search_dir_ptr = &path_ptr -> fx_path_directory;
181 }
182 else
183 {
184
185 /* Setup the path pointer to the global media path. */
186 171 path_ptr = &media_ptr -> fx_media_default_path;
187
188 /* The current default directory is the root so just set the
189 search directory pointer to NULL. */
190 171 search_dir_ptr = FX_NULL;
191 }
192
193 /* Calculate the directory size. */
194
4/4
✓ Branch 7 → 8 taken 136 times.
✓ Branch 7 → 21 taken 76 times.
✓ Branch 12 → 13 taken 175 times.
✓ Branch 12 → 28 taken 100 times.
487 if (search_dir_ptr)
195 {
196
197
198 /* Determine the directory size. */
199
4/4
✓ Branch 8 → 9 taken 108 times.
✓ Branch 8 → 10 taken 28 times.
✓ Branch 13 → 14 taken 135 times.
✓ Branch 13 → 15 taken 40 times.
311 if (path_ptr -> fx_path_current_entry != 0)
200 {
201
202 /* Pickup the previously saved directory size. */
203 243 directory_size = search_dir_ptr -> fx_dir_entry_file_size;
204 }
205 else
206 {
207
208 /* This should only be done on the first time into next directory find. */
209
210 /* Ensure that the search directory's last search cluster is cleared. */
211 68 search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
212
213 /* Calculate the directory size by counting the allocated
214 clusters for it. */
215 68 i = 0;
216 68 cluster = search_dir_ptr -> fx_dir_entry_cluster;
217
4/4
✓ Branch 19 → 11 taken 100 times.
✓ Branch 19 → 20 taken 12 times.
✓ Branch 26 → 16 taken 150 times.
✓ Branch 26 → 27 taken 20 times.
282 while (cluster < media_ptr -> fx_media_fat_reserved)
218 {
219
220 /* Increment the cluster count. */
221 250 i++;
222
223 /* Read the next FAT entry. */
224 250 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
225
226
227 /* Check the return status. */
228
4/4
✓ Branch 12 → 13 taken 4 times.
✓ Branch 12 → 14 taken 96 times.
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 20 taken 145 times.
250 if (status != FX_SUCCESS)
229 {
230
231 /* Release media protection. */
232 5 FX_UNPROTECT
233
234 /* Return the bad status. */
235 9 return(status);
236 }
237
238
12/12
✓ Branch 14 → 15 taken 92 times.
✓ Branch 14 → 17 taken 4 times.
✓ Branch 15 → 16 taken 88 times.
✓ Branch 15 → 17 taken 4 times.
✓ Branch 16 → 17 taken 4 times.
✓ Branch 16 → 18 taken 84 times.
✓ Branch 20 → 21 taken 140 times.
✓ Branch 20 → 23 taken 5 times.
✓ Branch 21 → 22 taken 135 times.
✓ Branch 21 → 23 taken 5 times.
✓ Branch 22 → 23 taken 5 times.
✓ Branch 22 → 25 taken 130 times.
241 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
239 {
240
241 /* Release media protection. */
242 15 FX_UNPROTECT
243
244 /* Return the bad status. */
245 27 return(FX_FAT_READ_ERROR);
246 }
247
248 214 cluster = next_cluster;
249 }
250
251 /* Now we can calculate the directory size. */
252 32 directory_size = (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
253 32 ((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
254 / (ULONG64) FX_DIR_ENTRY_SIZE;
255
256 /* Save how many entries there are in the directory. */
257 32 search_dir_ptr -> fx_dir_entry_file_size = directory_size;
258 }
259 }
260 else
261 {
262
263 /* Directory size is the number of entries in the root directory. */
264 176 directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
265 }
266
267 /* Preset status with an error return. */
268 451 status = FX_NO_MORE_ENTRIES;
269
270 /* Determine if the current entry is inside of the directory's range. */
271
4/4
✓ Branch 72 → 23 taken 196 times.
✓ Branch 72 → 73 taken 4 times.
✓ Branch 80 → 30 taken 255 times.
✓ Branch 80 → 81 taken 5 times.
460 while (path_ptr -> fx_path_current_entry < directory_size)
272 {
273
274 /* Read an entry from the directory. */
275 451 temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
276 &(path_ptr -> fx_path_current_entry), &entry);
277
278 /* Check for error status. */
279
4/4
✓ Branch 24 → 25 taken 4 times.
✓ Branch 24 → 26 taken 192 times.
✓ Branch 31 → 32 taken 5 times.
✓ Branch 31 → 34 taken 250 times.
451 if (temp_status != FX_SUCCESS)
280 {
281
282 /* Release media protection. */
283 5 FX_UNPROTECT
284
285 /* Return error status. */
286 9 return(temp_status);
287 }
288
289
290 /* Check to see if the entry has something in it. */
291
8/8
✓ Branch 26 → 27 taken 12 times.
✓ Branch 26 → 29 taken 180 times.
✓ Branch 27 → 28 taken 4 times.
✓ Branch 27 → 29 taken 8 times.
✓ Branch 34 → 35 taken 15 times.
✓ Branch 34 → 37 taken 235 times.
✓ Branch 35 → 36 taken 5 times.
✓ Branch 35 → 37 taken 10 times.
442 if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
292 {
293
294 /* Current entry is free, skip to next entry and continue the loop. */
295 9 path_ptr -> fx_path_current_entry++;
296 9 continue;
297 }
298
299 /* Determine if a valid directory entry is present. */
300
4/4
✓ Branch 29 → 30 taken 172 times.
✓ Branch 29 → 71 taken 16 times.
✓ Branch 37 → 38 taken 225 times.
✓ Branch 37 → 79 taken 20 times.
433 else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
301 {
302
303 /* A valid directory entry is present. */
304
305 /* Copy the name into the destination. */
306
4/4
✓ Branch 32 → 31 taken 2932 times.
✓ Branch 32 → 33 taken 172 times.
✓ Branch 40 → 39 taken 3720 times.
✓ Branch 40 → 41 taken 225 times.
7049 for (i = 0; entry.fx_dir_entry_name[i]; i++)
307 {
308
309 6652 *directory_name = entry.fx_dir_entry_name[i];
310 6652 directory_name++;
311 }
312
313 /* Place a NULL at the end of the directory name. */
314 397 *directory_name = (CHAR)0;
315
316 /* Determine if the entry's attributes are required. */
317
4/4
✓ Branch 33 → 34 taken 84 times.
✓ Branch 33 → 35 taken 88 times.
✓ Branch 41 → 42 taken 115 times.
✓ Branch 41 → 43 taken 110 times.
397 if (attributes)
318 {
319
320 /* Pickup the entry's attributes. */
321 199 *attributes = entry.fx_dir_entry_attributes;
322 }
323
324 /* Determine if the entry's size is required. */
325
4/4
✓ Branch 35 → 36 taken 84 times.
✓ Branch 35 → 37 taken 88 times.
✓ Branch 43 → 44 taken 115 times.
✓ Branch 43 → 45 taken 110 times.
397 if (size)
326 {
327
328 /* Pickup the entry's size. */
329 199 *size = (ULONG)entry.fx_dir_entry_file_size;
330 }
331
332 /* Determine if the entry's year is required. */
333
4/4
✓ Branch 37 → 38 taken 84 times.
✓ Branch 37 → 39 taken 88 times.
✓ Branch 45 → 46 taken 115 times.
✓ Branch 45 → 47 taken 110 times.
397 if (year)
334 {
335
336 /* Pickup the entry's year. */
337 199 *year = ((entry.fx_dir_entry_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
338 }
339
340 /* Determine if the entry's month is required. */
341
4/4
✓ Branch 39 → 40 taken 84 times.
✓ Branch 39 → 41 taken 88 times.
✓ Branch 47 → 48 taken 115 times.
✓ Branch 47 → 49 taken 110 times.
397 if (month)
342 {
343
344 /* Pickup the entry's month. */
345 199 *month = (entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
346 }
347
348 /* Determine if the entry's day is required. */
349
4/4
✓ Branch 41 → 42 taken 84 times.
✓ Branch 41 → 43 taken 88 times.
✓ Branch 49 → 50 taken 115 times.
✓ Branch 49 → 51 taken 110 times.
397 if (day)
350 {
351
352 /* Pickup the entry's day. */
353 199 *day = entry.fx_dir_entry_date & FX_DAY_MASK;
354 }
355
356 /* Determine if the entry's hour is required. */
357
4/4
✓ Branch 43 → 44 taken 84 times.
✓ Branch 43 → 45 taken 88 times.
✓ Branch 51 → 52 taken 115 times.
✓ Branch 51 → 53 taken 110 times.
397 if (hour)
358 {
359
360 /* Pickup the entry's hour. */
361 199 *hour = (entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
362 }
363
364 /* Determine if the entry's minute is required. */
365
4/4
✓ Branch 45 → 46 taken 88 times.
✓ Branch 45 → 47 taken 84 times.
✓ Branch 53 → 54 taken 120 times.
✓ Branch 53 → 55 taken 105 times.
397 if (minute)
366 {
367
368 /* Pickup the entry's minute. */
369 208 *minute = (entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
370 }
371
372 /* Determine if the entry's second is required. */
373
4/4
✓ Branch 47 → 48 taken 168 times.
✓ Branch 47 → 49 taken 4 times.
✓ Branch 55 → 56 taken 220 times.
✓ Branch 55 → 57 taken 5 times.
397 if (second)
374 {
375
376 /* Pickup the entry's second. */
377 388 *second = (entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
378 }
379
380 /* Increment the current entry for the media. */
381 397 path_ptr -> fx_path_current_entry++;
382
383 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
384 {
385 UINT v, j;
386
387
388 /* If a subsequent search for the same name is done, it will find it immediately. */
389
390 /* Set the index of the saved name string. */
391 397 v = 0;
392
393 /* First, build the full path and name. */
394
4/4
✓ Branch 49 → 50 taken 104 times.
✓ Branch 49 → 54 taken 68 times.
✓ Branch 57 → 58 taken 135 times.
✓ Branch 57 → 62 taken 90 times.
397 if (path_string_ptr)
395 {
396
397 /* Copy the path into the destination. */
398
8/8
✓ Branch 52 → 53 taken 3936 times.
✓ Branch 52 → 54 taken 8 times.
✓ Branch 53 → 51 taken 3840 times.
✓ Branch 53 → 54 taken 96 times.
✓ Branch 60 → 61 taken 5070 times.
✓ Branch 60 → 62 taken 10 times.
✓ Branch 61 → 59 taken 4945 times.
✓ Branch 61 → 62 taken 125 times.
9024 while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
399 {
400
401 /* Copy one character. */
402 8785 media_ptr -> fx_media_last_found_name[v] = path_string_ptr[v];
403
404 /* Move to next character. */
405 8785 v++;
406 }
407 }
408
409 /* We know there is room at this point, place a directory separator character. */
410 397 media_ptr -> fx_media_last_found_name[v++] = '/';
411
412 /* Now append the name to the path. */
413 397 j = 0;
414
8/8
✓ Branch 56 → 57 taken 3060 times.
✓ Branch 56 → 58 taken 12 times.
✓ Branch 57 → 55 taken 2900 times.
✓ Branch 57 → 58 taken 160 times.
✓ Branch 64 → 65 taken 3890 times.
✓ Branch 64 → 66 taken 15 times.
✓ Branch 65 → 63 taken 3680 times.
✓ Branch 65 → 66 taken 210 times.
6977 while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
415 {
416
417 /* Copy one character. */
418 6580 media_ptr -> fx_media_last_found_name[v] = entry.fx_dir_entry_name[j];
419
420 /* Move to next character. */
421 6580 v++;
422 6580 j++;
423 }
424
425 /* Null terminate the last name string. */
426
4/4
✓ Branch 58 → 59 taken 160 times.
✓ Branch 58 → 60 taken 12 times.
✓ Branch 66 → 67 taken 210 times.
✓ Branch 66 → 68 taken 15 times.
397 if (v < FX_MAX_LAST_NAME_LEN)
427 {
428
429 /* Null terminate. */
430 370 media_ptr -> fx_media_last_found_name[v] = FX_NULL;
431 }
432 else
433 {
434
435 /* The string is too big, NULL the string so it won't be used in searching. */
436 27 media_ptr -> fx_media_last_found_name[0] = FX_NULL;
437 }
438
439 /* Determine if there is a search pointer. */
440
4/4
✓ Branch 61 → 62 taken 104 times.
✓ Branch 61 → 63 taken 68 times.
✓ Branch 69 → 70 taken 135 times.
✓ Branch 69 → 71 taken 90 times.
397 if (search_dir_ptr)
441 {
442
443 /* Yes, there is a search directory pointer so save it! */
444 239 media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
445
446 /* Indicate the search directory is valid. */
447 239 media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
448 }
449 else
450 {
451
452 /* Indicate the search directory is not valid. */
453 158 media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
454 }
455
456 /* Copy the directory entry. */
457 397 media_ptr -> fx_media_last_found_entry = entry;
458
459 /* Setup the last found directory entry to point at the last found internal file name. */
460 397 media_ptr -> fx_media_last_found_entry.fx_dir_entry_name = media_ptr -> fx_media_last_found_file_name;
461
462 /* Copy the actual directory name into the cached directory name. */
463
4/4
✓ Branch 69 → 65 taken 5132 times.
✓ Branch 69 → 70 taken 12 times.
✓ Branch 77 → 73 taken 6480 times.
✓ Branch 77 → 78 taken 15 times.
11639 for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
464 {
465
466 /* Copy character into the cached directory name. */
467 11612 media_ptr -> fx_media_last_found_file_name[index] = entry.fx_dir_entry_name[index];
468
469 /* See if we have copied the NULL termination character. */
470
4/4
✓ Branch 65 → 66 taken 284 times.
✓ Branch 65 → 68 taken 4848 times.
✓ Branch 73 → 74 taken 365 times.
✓ Branch 73 → 76 taken 6115 times.
11612 if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
471 {
472
473 /* Check to see if we use the break to get out of the loop. */
474
4/4
✓ Branch 66 → 67 taken 160 times.
✓ Branch 66 → 68 taken 124 times.
✓ Branch 74 → 75 taken 210 times.
✓ Branch 74 → 76 taken 155 times.
649 if (v < (FX_MAX_LONG_NAME_LEN - 1))
475 {
476
477 /* Yes, not at the end of the string, break. */
478 370 break;
479 }
480 }
481 }
482 }
483 #endif
484
485 /* Set return status to success. */
486 397 status = FX_SUCCESS;
487
488 /* Get out of the loop. */
489 397 break;
490 }
491 else
492 {
493 /* Set the error code. */
494 36 status = FX_NO_MORE_ENTRIES;
495
496 /* Get out of the loop. */
497 36 break;
498 }
499 }
500
501 /* Release media protection. */
502 250 FX_UNPROTECT
503
504 /* Return status to the caller. */
505 442 return(status);
506 }
507
508