GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_next_entry_find.c Lines: 87 87 100.0 %
Date: 2026-03-06 18:49:02 Branches: 54 54 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_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.  The function that returns the first name in the */
52
/*    current directory must be called prior to this function.            */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    media_ptr                             Media control block pointer   */
57
/*    directory_name                        Destination for directory     */
58
/*                                            name                        */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _fx_directory_entry_read              Read entries from root dir    */
67
/*    _fx_utility_FAT_entry_read            Read FAT entries to calculate */
68
/*                                            the sub-directory size      */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    Application Code and                                                */
73
/*    FileX System Functions                                              */
74
/*                                                                        */
75
/**************************************************************************/
76
519
UINT  _fx_directory_next_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name)
77
{
78
79
ULONG         i;
80
UINT          status;
81
UINT          temp_status;
82
519
ULONG         cluster, next_cluster = 0;
83
ULONG64       directory_size;
84
FX_DIR_ENTRY  entry;
85
FX_DIR_ENTRY *search_dir_ptr;
86
FX_PATH      *path_ptr;
87
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
88
UINT          index;
89
519
CHAR         *path_string_ptr =  FX_NULL;
90
#endif
91
92
93
#ifndef FX_MEDIA_STATISTICS_DISABLE
94
95
    /* Increment the number of times this service has been called.  */
96
519
    media_ptr -> fx_media_directory_next_entry_finds++;
97
#endif
98
99
    /* Setup pointer to media name buffer.  */
100
519
    entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
101
102
    /* Clear the short name string.  */
103
519
    entry.fx_dir_entry_short_name[0] =  0;
104
105
    /* Check the media to make sure it is open.  */
106
519
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
107
    {
108
109
        /* Return the media not opened error.  */
110
1
        return(FX_MEDIA_NOT_OPEN);
111
    }
112
113
    /* If trace is enabled, insert this event into the trace buffer.  */
114
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
115
116
    /* Protect against other threads accessing the media.  */
117
518
    FX_PROTECT
118
119
    /* First check for a local path pointer stored in the thread control block.  This
120
       is only available in ThreadX Version 4 and above.  */
121
122
#ifndef FX_NO_LOCAL_PATH
123
124
518
    if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
125
    {
126
127
        /* Setup the default path pointer.  */
128
322
        path_ptr =  (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
129
130
        /* Determine if we are at the root directory.  */
131
322
        if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
132
        {
133
134
            /* No, we are not at the root directory.  */
135
136
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
137
138
            /* Setup pointer to the path.  */
139
301
            path_string_ptr =  ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
140
#endif
141
142
            /* Set the internal pointer to the search directory as well.  */
143
301
            search_dir_ptr =  &(path_ptr -> fx_path_directory);
144
        }
145
        else
146
        {
147
148
            /* The current default directory is the root so just set the
149
               search directory pointer to NULL.  */
150
21
            search_dir_ptr =  FX_NULL;
151
        }
152
    }
153
    else
154
#endif
155
156
    /* Set the initial search directory to the current working
157
       directory - if there is one.  */
158
196
    if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
159
    {
160
161
        /* Setup the path pointer to the global media path.  */
162
117
        path_ptr =  &media_ptr -> fx_media_default_path;
163
164
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
165
166
        /* Setup pointer to the path.  */
167
117
        path_string_ptr =  media_ptr -> fx_media_default_path.fx_path_string;
168
#endif
169
170
        /* Set the internal pointer to the search directory as well.  */
171
117
        search_dir_ptr =  &(path_ptr -> fx_path_directory);
172
    }
173
    else
174
    {
175
176
        /* Setup the path pointer to the global media path.  */
177
79
        path_ptr =  &media_ptr -> fx_media_default_path;
178
179
        /* The current default directory is the root so just set the
180
           search directory pointer to NULL.  */
181
79
        search_dir_ptr =  FX_NULL;
182
    }
183
184
    /* Calculate the directory size.  */
185
518
    if (search_dir_ptr)
186
    {
187
        /* Determine the directory size.  */
188
418
        if (path_ptr -> fx_path_current_entry != 0)
189
        {
190
191
            /* Pickup the previously saved directory size.  */
192
334
            directory_size =  search_dir_ptr -> fx_dir_entry_file_size;
193
        }
194
        else
195
        {
196
197
            /* This should only be done on the first time into next directory find.  */
198
199
            /* Ensure that the search directory's last search cluster is cleared.  */
200
84
            search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
201
202
            /* Calculate the directory size by counting the allocated
203
               clusters for it. */
204
84
            i =        0;
205
84
            cluster =  search_dir_ptr -> fx_dir_entry_cluster;
206
309
            while (cluster < media_ptr -> fx_media_fat_reserved)
207
            {
208
209
                /* Increment the cluster count.  */
210
229
                i++;
211
212
                /* Read the next FAT entry.  */
213
229
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
214
215
                /* Check the return status.  */
216
229
                if (status != FX_SUCCESS)
217
                {
218
219
                    /* Release media protection.  */
220
1
                    FX_UNPROTECT
221
222
                    /* Return the bad status.  */
223
1
                    return(status);
224
                }
225
226

228
                if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
227
                {
228
229
                    /* Release media protection.  */
230
3
                    FX_UNPROTECT
231
232
                    /* Return the bad status.  */
233
3
                    return(FX_FAT_READ_ERROR);
234
                }
235
236
225
                cluster = next_cluster;
237
            }
238
239
            /* Now we can calculate the directory size.  */
240
80
            directory_size =  (((ULONG64)media_ptr -> fx_media_bytes_per_sector) *
241
80
                               ((ULONG64)media_ptr -> fx_media_sectors_per_cluster) * i) /
242
                (ULONG64)FX_DIR_ENTRY_SIZE;
243
244
            /* Save how many entries there are in the directory.  */
245
80
            search_dir_ptr -> fx_dir_entry_file_size =  directory_size;
246
        }
247
    }
248
    else
249
    {
250
251
        /* Directory size is the number of entries in the root directory.  */
252
100
        directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
253
    }
254
255
    /* Preset status with an error return.  */
256
514
    status =  FX_NO_MORE_ENTRIES;
257
258
    /* Determine if the current entry is inside of the directory's range.  */
259
525
    while (path_ptr -> fx_path_current_entry < directory_size)
260
    {
261
262
        /* Read an entry from the directory.  */
263
524
        temp_status =  _fx_directory_entry_read(media_ptr, search_dir_ptr,
264
                                                &(path_ptr -> fx_path_current_entry), &entry);
265
266
        /* Check for error status.  */
267
524
        if (temp_status != FX_SUCCESS)
268
        {
269
270
            /* Release media protection.  */
271
10
            FX_UNPROTECT
272
273
            /* Return error status.  */
274
10
            return(temp_status);
275
        }
276
277
        /* Check to see if the entry has something in it.  */
278

514
        if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
279
        {
280
281
            /* Current entry is free, skip to next entry and continue the loop.  */
282
11
            path_ptr -> fx_path_current_entry++;
283
11
            continue;
284
        }
285
503
        else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
286
        {
287
288
            /* A valid directory entry is present.  */
289
290
            /* Copy the name into the destination.  */
291
5078
            for (i = 0; entry.fx_dir_entry_name[i]; i++)
292
            {
293
294
4648
                *directory_name = entry.fx_dir_entry_name[i];
295
4648
                directory_name++;
296
            }
297
298
            /* Place a NULL at the end of the directory name.  */
299
430
            *directory_name =  (CHAR)0;
300
301
            /* Increment the current entry for the media.  */
302
430
            path_ptr -> fx_path_current_entry++;
303
304
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
305
            {
306
            UINT v, j;
307
308
309
                /* If a subsequent search for the same name is done, it will find it immediately.  */
310
311
                /* Set the index of the saved name string.  */
312
430
                v =  0;
313
314
                /* First, build the full path and name.  */
315
430
                if (path_string_ptr)
316
                {
317
318
                    /* Copy the path into the destination.  */
319

10276
                    while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
320
                    {
321
322
                        /* Copy one character.   */
323
9940
                        media_ptr -> fx_media_last_found_name[v] =  path_string_ptr[v];
324
325
                        /* Move to next character.  */
326
9940
                        v++;
327
                    }
328
                }
329
330
                /* We know there is room at this point, place a directory separator character.  */
331
430
                media_ptr -> fx_media_last_found_name[v++] =  '/';
332
333
                /* Now append the name to the path.  */
334
430
                j =  0;
335

5049
                while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
336
                {
337
338
                    /* Copy one character.   */
339
4619
                    media_ptr -> fx_media_last_found_name[v] =  entry.fx_dir_entry_name[j];
340
341
                    /* Move to next character.  */
342
4619
                    v++;
343
4619
                    j++;
344
                }
345
346
                /* Null terminate the last name string.   */
347
430
                if (v < FX_MAX_LAST_NAME_LEN)
348
                {
349
350
                    /* Null terminate.  */
351
423
                    media_ptr -> fx_media_last_found_name[v] =  FX_NULL;
352
                }
353
                else
354
                {
355
356
                    /* The string is too big, NULL the string so it won't be used in searching.  */
357
7
                    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
358
                }
359
360
                /* Determine if there is a search pointer.  */
361
430
                if (search_dir_ptr)
362
                {
363
364
                    /* Yes, there is a search directory pointer so save it!   */
365
336
                    media_ptr -> fx_media_last_found_directory =  *search_dir_ptr;
366
367
                    /* Indicate the search directory is valid.  */
368
336
                    media_ptr -> fx_media_last_found_directory_valid =  FX_TRUE;
369
                }
370
                else
371
                {
372
373
                    /* Indicate the search directory is not valid.  */
374
94
                    media_ptr -> fx_media_last_found_directory_valid =  FX_FALSE;
375
                }
376
377
                /* Copy the directory entry.  */
378
430
                media_ptr -> fx_media_last_found_entry =  entry;
379
380
                /* Setup the last found directory entry to point at the last found internal file name.  */
381
430
                media_ptr -> fx_media_last_found_entry.fx_dir_entry_name =  media_ptr -> fx_media_last_found_file_name;
382
383
                /* Copy the actual directory name into the cached directory name.  */
384
6591
                for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
385
                {
386
387
                    /* Copy character into the cached directory name.  */
388
6584
                    media_ptr -> fx_media_last_found_file_name[index] =  entry.fx_dir_entry_name[index];
389
390
                    /* See if we have copied the NULL termination character.  */
391
6584
                    if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
392
                    {
393
394
                        /* Check to see if we use the break to get out of the loop.  */
395
478
                        if (v < (FX_MAX_LONG_NAME_LEN - 1))
396
                        {
397
398
                            /* Yes, not at the end of the string, break.  */
399
423
                            break;
400
                        }
401
                    }
402
                }
403
            }
404
#endif
405
406
            /* Set return status to success.  */
407
430
            status =  FX_SUCCESS;
408
409
            /* Get out of the loop.  */
410
430
            break;
411
        }
412
        else
413
        {
414
415
            /* Set the error code.  */
416
73
            status =  FX_NO_MORE_ENTRIES;
417
418
            /* Get out of the loop.  */
419
73
            break;
420
        }
421
    }
422
423
    /* Release media protection.  */
424
504
    FX_UNPROTECT
425
426
    /* Return status to the caller.  */
427
504
    return(status);
428
}
429