GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_next_entry_find.c Lines: 87 87 100.0 %
Date: 2024-03-11 05:15:45 Branches: 54 54 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** FileX Component                                                       */
16
/**                                                                       */
17
/**   Directory                                                           */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define FX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "fx_api.h"
28
#include "fx_system.h"
29
#include "fx_directory.h"
30
#include "fx_utility.h"
31
32
#ifndef FX_NO_LOCAL_PATH
33
FX_LOCAL_PATH_SETUP
34
#endif
35
36
37
/**************************************************************************/
38
/*                                                                        */
39
/*  FUNCTION                                               RELEASE        */
40
/*                                                                        */
41
/*    _fx_directory_next_entry_find                       PORTABLE C      */
42
/*                                                           6.1          */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    William E. Lamie, Microsoft Corporation                             */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function returns the name of the next entry in the current     */
50
/*    working directory.  The function that returns the first name in the */
51
/*    current directory must be called prior to this function.            */
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    media_ptr                             Media control block pointer   */
56
/*    directory_name                        Destination for directory     */
57
/*                                            name                        */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    return status                                                       */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    _fx_directory_entry_read              Read entries from root dir    */
66
/*    _fx_utility_FAT_entry_read            Read FAT entries to calculate */
67
/*                                            the sub-directory size      */
68
/*                                                                        */
69
/*  CALLED BY                                                             */
70
/*                                                                        */
71
/*    Application Code and                                                */
72
/*    FileX System Functions                                              */
73
/*                                                                        */
74
/*  RELEASE HISTORY                                                       */
75
/*                                                                        */
76
/*    DATE              NAME                      DESCRIPTION             */
77
/*                                                                        */
78
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
79
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
80
/*                                            resulting in version 6.1    */
81
/*                                                                        */
82
/**************************************************************************/
83
519
UINT  _fx_directory_next_entry_find(FX_MEDIA *media_ptr, CHAR *directory_name)
84
{
85
86
ULONG         i;
87
UINT          status;
88
UINT          temp_status;
89
519
ULONG         cluster, next_cluster = 0;
90
ULONG64       directory_size;
91
FX_DIR_ENTRY  entry;
92
FX_DIR_ENTRY *search_dir_ptr;
93
FX_PATH      *path_ptr;
94
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
95
UINT          index;
96
519
CHAR         *path_string_ptr =  FX_NULL;
97
#endif
98
99
100
#ifndef FX_MEDIA_STATISTICS_DISABLE
101
102
    /* Increment the number of times this service has been called.  */
103
519
    media_ptr -> fx_media_directory_next_entry_finds++;
104
#endif
105
106
    /* Setup pointer to media name buffer.  */
107
519
    entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
108
109
    /* Clear the short name string.  */
110
519
    entry.fx_dir_entry_short_name[0] =  0;
111
112
    /* Check the media to make sure it is open.  */
113
519
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
114
    {
115
116
        /* Return the media not opened error.  */
117
1
        return(FX_MEDIA_NOT_OPEN);
118
    }
119
120
    /* If trace is enabled, insert this event into the trace buffer.  */
121
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
122
123
    /* Protect against other threads accessing the media.  */
124
518
    FX_PROTECT
125
126
    /* First check for a local path pointer stored in the thread control block.  This
127
       is only available in ThreadX Version 4 and above.  */
128
129
#ifndef FX_NO_LOCAL_PATH
130
131
518
    if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
132
    {
133
134
        /* Setup the default path pointer.  */
135
322
        path_ptr =  (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
136
137
        /* Determine if we are at the root directory.  */
138
322
        if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
139
        {
140
141
            /* No, we are not at the root directory.  */
142
143
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
144
145
            /* Setup pointer to the path.  */
146
301
            path_string_ptr =  ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
147
#endif
148
149
            /* Set the internal pointer to the search directory as well.  */
150
301
            search_dir_ptr =  &(path_ptr -> fx_path_directory);
151
        }
152
        else
153
        {
154
155
            /* The current default directory is the root so just set the
156
               search directory pointer to NULL.  */
157
21
            search_dir_ptr =  FX_NULL;
158
        }
159
    }
160
    else
161
#endif
162
163
    /* Set the initial search directory to the current working
164
       directory - if there is one.  */
165
196
    if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
166
    {
167
168
        /* Setup the path pointer to the global media path.  */
169
117
        path_ptr =  &media_ptr -> fx_media_default_path;
170
171
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
172
173
        /* Setup pointer to the path.  */
174
117
        path_string_ptr =  media_ptr -> fx_media_default_path.fx_path_string;
175
#endif
176
177
        /* Set the internal pointer to the search directory as well.  */
178
117
        search_dir_ptr =  &(path_ptr -> fx_path_directory);
179
    }
180
    else
181
    {
182
183
        /* Setup the path pointer to the global media path.  */
184
79
        path_ptr =  &media_ptr -> fx_media_default_path;
185
186
        /* The current default directory is the root so just set the
187
           search directory pointer to NULL.  */
188
79
        search_dir_ptr =  FX_NULL;
189
    }
190
191
    /* Calculate the directory size.  */
192
518
    if (search_dir_ptr)
193
    {
194
        /* Determine the directory size.  */
195
418
        if (path_ptr -> fx_path_current_entry != 0)
196
        {
197
198
            /* Pickup the previously saved directory size.  */
199
334
            directory_size =  search_dir_ptr -> fx_dir_entry_file_size;
200
        }
201
        else
202
        {
203
204
            /* This should only be done on the first time into next directory find.  */
205
206
            /* Ensure that the search directory's last search cluster is cleared.  */
207
84
            search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
208
209
            /* Calculate the directory size by counting the allocated
210
               clusters for it. */
211
84
            i =        0;
212
84
            cluster =  search_dir_ptr -> fx_dir_entry_cluster;
213
309
            while (cluster < media_ptr -> fx_media_fat_reserved)
214
            {
215
216
                /* Increment the cluster count.  */
217
229
                i++;
218
219
                /* Read the next FAT entry.  */
220
229
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
221
222
                /* Check the return status.  */
223
229
                if (status != FX_SUCCESS)
224
                {
225
226
                    /* Release media protection.  */
227
1
                    FX_UNPROTECT
228
229
                    /* Return the bad status.  */
230
1
                    return(status);
231
                }
232
233

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

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

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

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