GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_next_full_entry_find.c Lines: 103 103 100.0 %
Date: 2026-03-06 18:49:02 Branches: 70 70 100.0 %

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
56
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
56
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
56
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
56
    media_ptr -> fx_media_directory_next_full_entry_finds++;
107
#endif
108
109
    /* Setup pointer to media name buffer.  */
110
56
    entry.fx_dir_entry_name =  media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
111
112
    /* Clear the short name string.  */
113
56
    entry.fx_dir_entry_short_name[0] =  0;
114
115
116
    /* Check the media to make sure it is open.  */
117
56
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
118
    {
119
120
        /* Return the media not opened error.  */
121
1
        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
55
    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
55
    if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
134
    {
135
136
        /* Setup the default path pointer.  */
137
2
        path_ptr =  (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
138
139
        /* Determine if we are at the root directory.  */
140
2
        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
1
            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
1
            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
1
            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
53
    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
34
        path_ptr =  &media_ptr -> fx_media_default_path;
172
173
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
174
175
        /* Setup pointer to the path.  */
176
34
        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
34
        search_dir_ptr =  &path_ptr -> fx_path_directory;
181
    }
182
    else
183
    {
184
185
        /* Setup the path pointer to the global media path.  */
186
19
        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
19
        search_dir_ptr =  FX_NULL;
191
    }
192
193
    /* Calculate the directory size.  */
194
55
    if (search_dir_ptr)
195
    {
196
197
198
        /* Determine the directory size.  */
199
35
        if (path_ptr -> fx_path_current_entry !=  0)
200
        {
201
202
            /* Pickup the previously saved directory size.  */
203
27
            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
8
            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
8
            i =        0;
216
8
            cluster =  search_dir_ptr -> fx_dir_entry_cluster;
217
34
            while (cluster < media_ptr -> fx_media_fat_reserved)
218
            {
219
220
                /* Increment the cluster count.  */
221
30
                i++;
222
223
                /* Read the next FAT entry.  */
224
30
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
225
226
227
                /* Check the return status.  */
228
30
                if (status != FX_SUCCESS)
229
                {
230
231
                    /* Release media protection.  */
232
1
                    FX_UNPROTECT
233
234
                    /* Return the bad status.  */
235
1
                    return(status);
236
                }
237
238

29
                if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
239
                {
240
241
                    /* Release media protection.  */
242
3
                    FX_UNPROTECT
243
244
                    /* Return the bad status.  */
245
3
                    return(FX_FAT_READ_ERROR);
246
                }
247
248
26
                cluster = next_cluster;
249
            }
250
251
            /* Now we can calculate the directory size.  */
252
4
            directory_size =  (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
253
4
                               ((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
4
            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
20
        directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
265
    }
266
267
    /* Preset status with an error return.  */
268
51
    status =  FX_NO_MORE_ENTRIES;
269
270
    /* Determine if the current entry is inside of the directory's range.  */
271
52
    while (path_ptr -> fx_path_current_entry < directory_size)
272
    {
273
274
        /* Read an entry from the directory.  */
275
51
        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
51
        if (temp_status != FX_SUCCESS)
280
        {
281
282
            /* Release media protection.  */
283
1
            FX_UNPROTECT
284
285
            /* Return error status.  */
286
1
            return(temp_status);
287
        }
288
289
290
        /* Check to see if the entry has something in it.  */
291

50
        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
1
            path_ptr -> fx_path_current_entry++;
296
1
            continue;
297
        }
298
299
        /* Determine if a valid directory entry is present.  */
300
49
        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
789
            for (i = 0; entry.fx_dir_entry_name[i]; i++)
307
            {
308
309
744
                *directory_name =  entry.fx_dir_entry_name[i];
310
744
                directory_name++;
311
            }
312
313
            /* Place a NULL at the end of the directory name.  */
314
45
            *directory_name =  (CHAR)0;
315
316
            /* Determine if the entry's attributes are required.  */
317
45
            if (attributes)
318
            {
319
320
                /* Pickup the entry's attributes.  */
321
23
                *attributes =  entry.fx_dir_entry_attributes;
322
            }
323
324
            /* Determine if the entry's size is required.  */
325
45
            if (size)
326
            {
327
328
                /* Pickup the entry's size.  */
329
23
                *size =  (ULONG)entry.fx_dir_entry_file_size;
330
            }
331
332
            /* Determine if the entry's year is required.  */
333
45
            if (year)
334
            {
335
336
                /* Pickup the entry's year.  */
337
23
                *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
45
            if (month)
342
            {
343
344
                /* Pickup the entry's month.  */
345
23
                *month =  (entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
346
            }
347
348
            /* Determine if the entry's day is required.  */
349
45
            if (day)
350
            {
351
352
                /* Pickup the entry's day.  */
353
23
                *day =  entry.fx_dir_entry_date & FX_DAY_MASK;
354
            }
355
356
            /* Determine if the entry's hour is required.  */
357
45
            if (hour)
358
            {
359
360
                /* Pickup the entry's hour.  */
361
23
                *hour =  (entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
362
            }
363
364
            /* Determine if the entry's minute is required.  */
365
45
            if (minute)
366
            {
367
368
                /* Pickup the entry's minute.  */
369
24
                *minute =  (entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
370
            }
371
372
            /* Determine if the entry's second is required.  */
373
45
            if (second)
374
            {
375
376
                /* Pickup the entry's second.  */
377
44
                *second =  (entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
378
            }
379
380
            /* Increment the current entry for the media.  */
381
45
            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
45
                v =  0;
392
393
                /* First, build the full path and name.  */
394
45
                if (path_string_ptr)
395
                {
396
397
                    /* Copy the path into the destination.  */
398

1016
                    while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
399
                    {
400
401
                        /* Copy one character.   */
402
989
                        media_ptr -> fx_media_last_found_name[v] =  path_string_ptr[v];
403
404
                        /* Move to next character.  */
405
989
                        v++;
406
                    }
407
                }
408
409
                /* We know there is room at this point, place a directory separator character.  */
410
45
                media_ptr -> fx_media_last_found_name[v++] =  '/';
411
412
                /* Now append the name to the path.  */
413
45
                j =  0;
414

781
                while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
415
                {
416
417
                    /* Copy one character.   */
418
736
                    media_ptr -> fx_media_last_found_name[v] =  entry.fx_dir_entry_name[j];
419
420
                    /* Move to next character.  */
421
736
                    v++;
422
736
                    j++;
423
                }
424
425
                /* Null terminate the last name string.   */
426
45
                if (v < FX_MAX_LAST_NAME_LEN)
427
                {
428
429
                    /* Null terminate.  */
430
42
                    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
3
                    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
437
                }
438
439
                /* Determine if there is a search pointer.  */
440
45
                if (search_dir_ptr)
441
                {
442
443
                    /* Yes, there is a search directory pointer so save it!   */
444
27
                    media_ptr -> fx_media_last_found_directory =  *search_dir_ptr;
445
446
                    /* Indicate the search directory is valid.  */
447
27
                    media_ptr -> fx_media_last_found_directory_valid =  FX_TRUE;
448
                }
449
                else
450
                {
451
452
                    /* Indicate the search directory is not valid.  */
453
18
                    media_ptr -> fx_media_last_found_directory_valid =  FX_FALSE;
454
                }
455
456
                /* Copy the directory entry.  */
457
45
                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
45
                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
1299
                for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
464
                {
465
466
                    /* Copy character into the cached directory name.  */
467
1296
                    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
1296
                    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
73
                        if (v < (FX_MAX_LONG_NAME_LEN - 1))
475
                        {
476
477
                            /* Yes, not at the end of the string, break.  */
478
42
                            break;
479
                        }
480
                    }
481
                }
482
            }
483
#endif
484
485
            /* Set return status to success.  */
486
45
            status =  FX_SUCCESS;
487
488
            /* Get out of the loop.  */
489
45
            break;
490
        }
491
        else
492
        {
493
            /* Set the error code.  */
494
4
            status =  FX_NO_MORE_ENTRIES;
495
496
            /* Get out of the loop.  */
497
4
            break;
498
        }
499
    }
500
501
    /* Release media protection.  */
502
50
    FX_UNPROTECT
503
504
    /* Return status to the caller.  */
505
50
    return(status);
506
}
507