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

29
                if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
246
                {
247
248
                    /* Release media protection.  */
249
3
                    FX_UNPROTECT
250
251
                    /* Return the bad status.  */
252
3
                    return(FX_FAT_READ_ERROR);
253
                }
254
255
26
                cluster = next_cluster;
256
            }
257
258
            /* Now we can calculate the directory size.  */
259
4
            directory_size =  (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
260
4
                               ((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
261
                                / (ULONG64) FX_DIR_ENTRY_SIZE;
262
263
            /* Save how many entries there are in the directory.  */
264
4
            search_dir_ptr -> fx_dir_entry_file_size =  directory_size;
265
        }
266
    }
267
    else
268
    {
269
270
        /* Directory size is the number of entries in the root directory.  */
271
20
        directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
272
    }
273
274
    /* Preset status with an error return.  */
275
51
    status =  FX_NO_MORE_ENTRIES;
276
277
    /* Determine if the current entry is inside of the directory's range.  */
278
52
    while (path_ptr -> fx_path_current_entry < directory_size)
279
    {
280
281
        /* Read an entry from the directory.  */
282
51
        temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
283
                                               &(path_ptr -> fx_path_current_entry), &entry);
284
285
        /* Check for error status.  */
286
51
        if (temp_status != FX_SUCCESS)
287
        {
288
289
            /* Release media protection.  */
290
1
            FX_UNPROTECT
291
292
            /* Return error status.  */
293
1
            return(temp_status);
294
        }
295
296
297
        /* Check to see if the entry has something in it.  */
298

50
        if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
299
        {
300
301
            /* Current entry is free, skip to next entry and continue the loop.  */
302
1
            path_ptr -> fx_path_current_entry++;
303
1
            continue;
304
        }
305
306
        /* Determine if a valid directory entry is present.  */
307
49
        else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
308
        {
309
310
            /* A valid directory entry is present.  */
311
312
            /* Copy the name into the destination.  */
313
789
            for (i = 0; entry.fx_dir_entry_name[i]; i++)
314
            {
315
316
744
                *directory_name =  entry.fx_dir_entry_name[i];
317
744
                directory_name++;
318
            }
319
320
            /* Place a NULL at the end of the directory name.  */
321
45
            *directory_name =  (CHAR)0;
322
323
            /* Determine if the entry's attributes are required.  */
324
45
            if (attributes)
325
            {
326
327
                /* Pickup the entry's attributes.  */
328
23
                *attributes =  entry.fx_dir_entry_attributes;
329
            }
330
331
            /* Determine if the entry's size is required.  */
332
45
            if (size)
333
            {
334
335
                /* Pickup the entry's size.  */
336
23
                *size =  (ULONG)entry.fx_dir_entry_file_size;
337
            }
338
339
            /* Determine if the entry's year is required.  */
340
45
            if (year)
341
            {
342
343
                /* Pickup the entry's year.  */
344
23
                *year =  ((entry.fx_dir_entry_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
345
            }
346
347
            /* Determine if the entry's month is required.  */
348
45
            if (month)
349
            {
350
351
                /* Pickup the entry's month.  */
352
23
                *month =  (entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
353
            }
354
355
            /* Determine if the entry's day is required.  */
356
45
            if (day)
357
            {
358
359
                /* Pickup the entry's day.  */
360
23
                *day =  entry.fx_dir_entry_date & FX_DAY_MASK;
361
            }
362
363
            /* Determine if the entry's hour is required.  */
364
45
            if (hour)
365
            {
366
367
                /* Pickup the entry's hour.  */
368
23
                *hour =  (entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
369
            }
370
371
            /* Determine if the entry's minute is required.  */
372
45
            if (minute)
373
            {
374
375
                /* Pickup the entry's minute.  */
376
24
                *minute =  (entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
377
            }
378
379
            /* Determine if the entry's second is required.  */
380
45
            if (second)
381
            {
382
383
                /* Pickup the entry's second.  */
384
44
                *second =  (entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
385
            }
386
387
            /* Increment the current entry for the media.  */
388
45
            path_ptr -> fx_path_current_entry++;
389
390
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
391
            {
392
            UINT v, j;
393
394
395
                /* If a subsequent search for the same name is done, it will find it immediately.  */
396
397
                /* Set the index of the saved name string.  */
398
45
                v =  0;
399
400
                /* First, build the full path and name.  */
401
45
                if (path_string_ptr)
402
                {
403
404
                    /* Copy the path into the destination.  */
405

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

781
                while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
422
                {
423
424
                    /* Copy one character.   */
425
736
                    media_ptr -> fx_media_last_found_name[v] =  entry.fx_dir_entry_name[j];
426
427
                    /* Move to next character.  */
428
736
                    v++;
429
736
                    j++;
430
                }
431
432
                /* Null terminate the last name string.   */
433
45
                if (v < FX_MAX_LAST_NAME_LEN)
434
                {
435
436
                    /* Null terminate.  */
437
42
                    media_ptr -> fx_media_last_found_name[v] =  FX_NULL;
438
                }
439
                else
440
                {
441
442
                    /* The string is too big, NULL the string so it won't be used in searching.  */
443
3
                    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
444
                }
445
446
                /* Determine if there is a search pointer.  */
447
45
                if (search_dir_ptr)
448
                {
449
450
                    /* Yes, there is a search directory pointer so save it!   */
451
27
                    media_ptr -> fx_media_last_found_directory =  *search_dir_ptr;
452
453
                    /* Indicate the search directory is valid.  */
454
27
                    media_ptr -> fx_media_last_found_directory_valid =  FX_TRUE;
455
                }
456
                else
457
                {
458
459
                    /* Indicate the search directory is not valid.  */
460
18
                    media_ptr -> fx_media_last_found_directory_valid =  FX_FALSE;
461
                }
462
463
                /* Copy the directory entry.  */
464
45
                media_ptr -> fx_media_last_found_entry =  entry;
465
466
                /* Setup the last found directory entry to point at the last found internal file name.  */
467
45
                media_ptr -> fx_media_last_found_entry.fx_dir_entry_name =  media_ptr -> fx_media_last_found_file_name;
468
469
                /* Copy the actual directory name into the cached directory name.  */
470
1299
                for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
471
                {
472
473
                    /* Copy character into the cached directory name.  */
474
1296
                    media_ptr -> fx_media_last_found_file_name[index] =  entry.fx_dir_entry_name[index];
475
476
                    /* See if we have copied the NULL termination character.  */
477
1296
                    if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
478
                    {
479
480
                        /* Check to see if we use the break to get out of the loop.  */
481
73
                        if (v < (FX_MAX_LONG_NAME_LEN - 1))
482
                        {
483
484
                            /* Yes, not at the end of the string, break.  */
485
42
                            break;
486
                        }
487
                    }
488
                }
489
            }
490
#endif
491
492
            /* Set return status to success.  */
493
45
            status =  FX_SUCCESS;
494
495
            /* Get out of the loop.  */
496
45
            break;
497
        }
498
        else
499
        {
500
            /* Set the error code.  */
501
4
            status =  FX_NO_MORE_ENTRIES;
502
503
            /* Get out of the loop.  */
504
4
            break;
505
        }
506
    }
507
508
    /* Release media protection.  */
509
50
    FX_UNPROTECT
510
511
    /* Return status to the caller.  */
512
50
    return(status);
513
}
514