GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_search.c Lines: 214 214 100.0 %
Date: 2024-03-11 05:15:45 Branches: 198 198 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_search                                PORTABLE C      */
42
/*                                                           6.1.10       */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    William E. Lamie, Microsoft Corporation                             */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function searches the media for the supplied name.  The search */
50
/*    routine will find files as well as directory names.                 */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    media_ptr                             Media control block pointer   */
55
/*    name_ptr                              Name pointer                  */
56
/*    entry_ptr                             Pointer to directory entry    */
57
/*                                            record                      */
58
/*    last_dir_ptr                          Pointer to destination for    */
59
/*                                            the last directory entry    */
60
/*    last_name_ptr                         Pointer to the last name      */
61
/*                                            token that was searched for */
62
/*                                                                        */
63
/*  OUTPUT                                                                */
64
/*                                                                        */
65
/*    return status                                                       */
66
/*                                                                        */
67
/*  CALLS                                                                 */
68
/*                                                                        */
69
/*    _fx_directory_name_extract            Extract directory name from   */
70
/*                                            input string                */
71
/*    _fx_directory_entry_read              Read entries from root dir    */
72
/*    _fx_utility_FAT_entry_read            Read FAT entries to calculate */
73
/*                                            the sub-directory size      */
74
/*                                                                        */
75
/*  CALLED BY                                                             */
76
/*                                                                        */
77
/*    FileX System Functions                                              */
78
/*                                                                        */
79
/*  RELEASE HISTORY                                                       */
80
/*                                                                        */
81
/*    DATE              NAME                      DESCRIPTION             */
82
/*                                                                        */
83
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
84
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
85
/*                                            added conditional to        */
86
/*                                            disable media search cache, */
87
/*                                            resulting in version 6.1    */
88
/*  06-02-2021     Bhupendra Naphade        Modified comment(s), and      */
89
/*                                            added check for             */
90
/*                                            volume label,               */
91
/*                                            resulting in version 6.1.7  */
92
/*  01-31-2022     William E. Lamie         Modified comment(s), and      */
93
/*                                            fixed path compare,         */
94
/*                                            resulting in version 6.1.10 */
95
/*                                                                        */
96
/**************************************************************************/
97
97598
UINT  _fx_directory_search(FX_MEDIA *media_ptr, CHAR *name_ptr, FX_DIR_ENTRY *entry_ptr,
98
                           FX_DIR_ENTRY *last_dir_ptr, CHAR **last_name_ptr)
99
{
100
101
ULONG         i, n;
102
UINT          found;
103
UINT          status;
104
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
105
UINT          v, j;
106
#endif /* FX_MEDIA_DISABLE_SEARCH_CACHE */
107
97598
ULONG         cluster, next_cluster = 0;
108
ULONG64       directory_size;
109
CHAR         *dir_name_ptr;
110
CHAR         *work_ptr;
111
CHAR         *source_name_ptr;
112
CHAR         *destination_name_ptr;
113
FX_DIR_ENTRY  search_dir;
114
FX_DIR_ENTRY *search_dir_ptr;
115
CHAR         *name, alpha, name_alpha;
116
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
117
UINT          index;
118
97598
CHAR         *path_ptr =  FX_NULL;
119
97598
CHAR         *original_name =  name_ptr;
120
#endif
121
122
#ifndef FX_MEDIA_STATISTICS_DISABLE
123
124
    /* Increment the number of directory search requests.  */
125
97598
    media_ptr -> fx_media_directory_searches++;
126
#endif
127
128
    /* Setup pointer to media name buffer.  */
129
97598
    name =  media_ptr -> fx_media_name_buffer;
130
131
    /* Setup the last directory, if required.  */
132
97598
    if (last_dir_ptr)
133
    {
134
135
        /* Set the first character of the directory entry to NULL to
136
           indicate root or no directory.  */
137
77838
        last_dir_ptr -> fx_dir_entry_name[0] =  0;
138
    }
139
140
    /* Determine if the file name has a full directory path.  */
141

97598
    if ((*name_ptr == '\\') || (*name_ptr == '/'))
142
    {
143
144
        /* Directory name has full path, set the search pointer to NULL.  */
145
14653
        search_dir_ptr =  FX_NULL;
146
    }
147
    else
148
    {
149
150
        /* Set the initial search directory to the current working
151
           directory - if there is one.  */
152
153
        /* First check for a local path pointer stored in the thread control block.  This
154
           is only available in ThreadX Version 4 and above.  */
155
#ifndef FX_NO_LOCAL_PATH
156
82945
        if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
157
        {
158
159
            /* Determine if the local directory is not the root directory.  */
160
746
            if (((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory.fx_dir_entry_name[0])
161
            {
162
163
                /* Start at the current working directory of the media.  */
164
686
                search_dir =   ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory;
165
166
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
167
168
                /* Setup pointer to the path.  */
169
686
                path_ptr =  ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
170
#endif
171
172
                /* Set the internal pointer to the search directory as well.  */
173
686
                search_dir_ptr =  &search_dir;
174
            }
175
            else
176
            {
177
178
                /* We are searching in the root directory.  */
179
60
                search_dir_ptr =  FX_NULL;
180
            }
181
        }
182
        else
183
#endif
184
82199
        if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
185
        {
186
187
            /* Start at the current working directory of the media.  */
188
466
            search_dir =  media_ptr -> fx_media_default_path.fx_path_directory;
189
190
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
191
192
            /* Setup pointer to the path.  */
193
466
            path_ptr =  media_ptr -> fx_media_default_path.fx_path_string;
194
#endif
195
196
            /* Set the internal pointer to the search directory as well.  */
197
466
            search_dir_ptr =  &search_dir;
198
        }
199
        else
200
        {
201
202
            /* The current default directory is the root so just set the
203
               search directory pointer to NULL.  */
204
81733
            search_dir_ptr =  FX_NULL;
205
        }
206
    }
207
208
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
209
210
    /* Determine if there is a previously found directory entry.  */
211
97598
    if (media_ptr -> fx_media_last_found_name[0])
212
    {
213
214
    UINT  match;
215
    CHAR *temp_ptr, beta;
216
217
        /* Yes, there is a previously found directory in our cache.  */
218
219
        /* Initialize the index.  */
220
21137
        v =  0;
221
222
        /* Determine if there is a full path.  */
223

21137
        if ((*name_ptr == '\\') || (*name_ptr == '/'))
224
        {
225
226
            /* Yes, the full path is in the name buffer. Simply compare with what is in
227
               the last search buffer.  */
228

3847
            while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[v]))
229
            {
230
231
                /* Pickup the respective name characters.  */
232
3827
                alpha =  name_ptr[v];
233
3827
                beta =   media_ptr -> fx_media_last_found_name[v];
234
235
                /* Ensure directory markers are the same.  */
236
3827
                if (alpha == '\\')
237
                {
238
17
                    alpha =  '/';
239
                }
240
3827
                if (beta == '\\')
241
                {
242
14
                    beta =  '/';
243
                }
244
245
                /* Is the name the same?  */
246
3827
                if (alpha != beta)
247
                {
248
249
                    /* Break out of loop!  */
250
23
                    break;
251
                }
252
253
                /* Move to next character.  */
254
3804
                v++;
255
            }
256
257
            /* Determine if we have a match.  */
258
43
            if (name_ptr[v] != media_ptr -> fx_media_last_found_name[v])
259
            {
260
25
                match =  FX_FALSE;
261
            }
262
            else
263
            {
264
18
                match =  FX_TRUE;
265
            }
266
        }
267
        else
268
        {
269
270
            /* Default to found.  */
271
21094
            match =  FX_TRUE;
272
273
            /* Determine if there is a default path to compare with.  */
274
21094
            if (path_ptr)
275
            {
276
277
                /* Yes, compare the current path with what is contained in the last
278
                   found buffer. Note that the last found name must have at least one
279
                   path separator as well as room for at least one character for a name. */
280

28971
                while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
281
                {
282
283
                    /* Pickup the respective name characters.  */
284
28285
                    alpha =  media_ptr -> fx_media_last_found_name[v];
285
28285
                    beta =   path_ptr[v];
286
287
                    /* Ensure directory markers are the same.  */
288
28285
                    if (alpha == '\\')
289
                    {
290
1504
                        alpha =  '/';
291
                    }
292
28285
                    if (beta == '\\')
293
                    {
294
1653
                        beta =  '/';
295
                    }
296
297
                    /* Is the name the same?  */
298
28285
                    if (alpha != beta)
299
                    {
300
301
                        /* Break out of loop!  */
302
10
                        break;
303
                    }
304
305
                    /* Move to next character.  */
306
28275
                    v++;
307
                }
308
309
                /* Determine if we don't have a match...  The relative path must be exhausted. */
310
696
                if (path_ptr[v])
311
                {
312
10
                    match =  FX_FALSE;
313
                }
314
            }
315
316
            /* Determine if we still have a match.  */
317
21094
            if (match)
318
            {
319
320
                /* Now examine the rest of the last name and the newly supplied
321
                   input name.  */
322
323
                /* Determine if a valid directory separator is present.  */
324
21084
                if ((media_ptr -> fx_media_last_found_name[v] != '\\') &&
325
21077
                    (media_ptr -> fx_media_last_found_name[v] != '/'))
326
                {
327
328
                    /* Set match to false - invalid directory path separator.  */
329
166
                    match =  FX_FALSE;
330
                }
331
                else
332
                {
333
                    /* Position past the next directory separator in the
334
                       last name string.  */
335
20918
                    v++;
336
                }
337
338
                /* Yes, the full path is in the name buffer. Simply compare with what is in
339
                   the last search buffer.  */
340
21084
                j =  0;
341

104709
                while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[j]) && (match))
342
                {
343
344
                    /* Pickup the respective name characters.  */
345
104000
                    alpha =  name_ptr[j];
346
104000
                    beta =   media_ptr -> fx_media_last_found_name[v];
347
348
                    /* Ensure directory markers are the same.  */
349
104000
                    if (alpha == '\\')
350
                    {
351
6
                        alpha =  '/';
352
                    }
353
104000
                    if (beta == '\\')
354
                    {
355
6
                        beta =  '/';
356
                    }
357
358
                    /* Is the name the same?  */
359
104000
                    if (alpha != beta)
360
                    {
361
362
                        /* Break out of loop!  */
363
20375
                        break;
364
                    }
365
366
                    /* Move to next character.  */
367
83625
                    v++;
368
83625
                    j++;
369
                }
370
371
                /* Avoid accessing fx_media_last_found_name out of bounds. */
372
21084
                if (v >= 256)
373
                {
374
1
                    match = FX_FALSE;
375
                }
376

21083
                else if ((match) && (name_ptr[j] != media_ptr -> fx_media_last_found_name[v]))
377
                {
378
379
                    /* We don't have a match.  */
380
20402
                    match =  FX_FALSE;
381
                }
382
            }
383
        }
384
385
        /* Now determine if we actually found a match.  */
386
21137
        if (match)
387
        {
388
389
            /* Save the directory entry name pointer.  */
390
533
            temp_ptr =  entry_ptr -> fx_dir_entry_name;
391
392
            /* Copy the saved directory entry.  */
393
533
            *entry_ptr =  media_ptr -> fx_media_last_found_entry;
394
395
            /* Restore the directory entry name pointer.  */
396
533
            entry_ptr -> fx_dir_entry_name =  temp_ptr;
397
398
            /* Copy the directory name into the destination directory name.  */
399
7576
            for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
400
            {
401
402
                /* Copy character into the destination.  */
403
7574
                temp_ptr[index] =  media_ptr -> fx_media_last_found_file_name[index];
404
405
                /* See if we have copied the NULL termination character.  */
406
7574
                if (temp_ptr[index] == (CHAR)FX_NULL)
407
                {
408
409
                    /* Determine if we should break here or at the top of the loop.  */
410
533
                    if (index < (FX_MAX_LONG_NAME_LEN - 1))
411
                    {
412
413
                        /* Yes, break out of the loop early.  */
414
531
                        break;
415
                    }
416
                }
417
            }
418
419
            /* Determine if there is a search directory to copy.  */
420

533
            if ((last_dir_ptr) && (media_ptr -> fx_media_last_found_directory_valid))
421
            {
422
423
                /* Yes, there was a search directory... and one is requested in this request as well.
424
                   Simply copy it into the destination.  */
425
426
                /* First, save the name pointer from the list directory pointer.  */
427
49
                destination_name_ptr =  last_dir_ptr -> fx_dir_entry_name;
428
429
                /* Copy the entire directory entry structure.  */
430
49
                *last_dir_ptr =  media_ptr -> fx_media_last_found_directory;
431
432
                /* Restore the original name buffer pointer.  */
433
49
                last_dir_ptr -> fx_dir_entry_name =  destination_name_ptr;
434
435
                /* Pickup pointer to name to copy.  */
436
49
                source_name_ptr =  media_ptr -> fx_media_last_found_directory.fx_dir_entry_name;
437
438
                /* Loop to copy the name into the last directory name buffer.  */
439
947
                for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
440
                {
441
442
                    /* Copy a character.  */
443
946
                    destination_name_ptr[n] =  source_name_ptr[n];
444
445
                    /* See if we have copied the NULL termination character.  */
446
946
                    if (source_name_ptr[n] == (CHAR)FX_NULL)
447
                    {
448
449
                        /* Determine if we should break here or at the top of the loop.  */
450
49
                        if (n < (FX_MAX_LONG_NAME_LEN - 1))
451
                        {
452
453
                            /* Yes, break out of the loop early.  */
454
48
                            break;
455
                        }
456
                    }
457
                }
458
            }
459
460
            /* Return the last name pointer, if required.  */
461
533
            if (last_name_ptr)
462
            {
463
464
                /* Just set the last name to initial name string.  */
465
51
                *last_name_ptr =  temp_ptr;
466
            }
467
468
#ifndef FX_MEDIA_STATISTICS_DISABLE
469
470
            /* Increment the number of directory search cache hits.  */
471
533
            media_ptr -> fx_media_directory_search_cache_hits++;
472
#endif
473
474
            /* Return success.  */
475
533
            return(FX_SUCCESS);
476
        }
477
    }
478
479
    /* Not a sequential search, invalidate the saved information.  */
480
97065
    media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
481
482
#ifndef FX_MEDIA_STATISTICS_DISABLE
483
484
    /* If trace is enabled, insert this event into the trace buffer.  */
485
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_CACHE_MISS, media_ptr, media_ptr -> fx_media_directory_searches - media_ptr -> fx_media_directory_search_cache_hits, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
486
#else
487
488
    /* If trace is enabled, insert this event into the trace buffer.  */
489
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_CACHE_MISS, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
490
#endif
491
#endif
492
493
    /* Loop to traverse the directory paths to find the specified file.  */
494
    do
495
    {
496
497
        /* Remember the last name pointer, if required.  */
498
112229
        if (last_name_ptr)
499
        {
500
501
            /* Just set the last name to initial name string.  */
502
92433
            *last_name_ptr =  name_ptr;
503
        }
504
505
        /* Extract file name.  */
506
112229
        name_ptr =  _fx_directory_name_extract(name_ptr, name);
507
508
        /* Calculate the directory size.  */
509
112229
        if (search_dir_ptr)
510
        {
511
512
            /* Ensure that the search directory's last search cluster is cleared.  */
513
15926
            search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
514
515
            /* Calculate the directory size by counting the allocated
516
            clusters for it.  */
517
15926
            i =        0;
518
15926
            cluster =  search_dir_ptr -> fx_dir_entry_cluster;
519
61286
            while (cluster < media_ptr -> fx_media_fat_reserved)
520
            {
521
522
                /* Increment the cluster count.  */
523
45376
                i++;
524
525
                /* Read the next FAT entry.  */
526
45376
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
527
528
                /* Check the return status.  */
529
45376
                if (status != FX_SUCCESS)
530
                {
531
532
                    /* Return the bad status.  */
533
1
                    return(status);
534
                }
535
536
                /* Check for error situation.  */
537

45375
                if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
538
                {
539
540
                    /* Return the bad status.  */
541
15
                    return(FX_FAT_READ_ERROR);
542
                }
543
544
45360
                cluster = next_cluster;
545
            }
546
547
            /* Now we can calculate the directory size.  */
548
15910
            directory_size =  (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
549
15910
                               ((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
550
                                / (ULONG64) FX_DIR_ENTRY_SIZE;
551
552
            /* Also save this in the directory entry so we don't have to
553
               calculate it later.  */
554
15910
            search_dir_ptr -> fx_dir_entry_file_size =  directory_size;
555
556
            /* If required, copy the last search directory entry into the
557
               destination.  */
558
15910
            if (last_dir_ptr)
559
            {
560
561
                /* Copy the last search directory into the destination.  */
562
563
                /* First, save the name pointer from the list directory pointer.  */
564
15185
                destination_name_ptr =  last_dir_ptr -> fx_dir_entry_name;
565
566
                /* Copy the entire directory entry structure.  */
567
15185
                *last_dir_ptr =  *search_dir_ptr;
568
569
                /* Restore the original name buffer pointer.  */
570
15185
                last_dir_ptr -> fx_dir_entry_name =  destination_name_ptr;
571
572
                /* Pickup pointer to name to copy.  */
573
15185
                source_name_ptr =  search_dir_ptr -> fx_dir_entry_name;
574
575
                /* Loop to copy the name into the last directory name buffer.  */
576
84857
                for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
577
                {
578
579
                    /* Copy a character.  */
580
84854
                    destination_name_ptr[n] =  source_name_ptr[n];
581
582
                    /* See if we have copied the NULL termination character.  */
583
84854
                    if (source_name_ptr[n] == (CHAR) FX_NULL)
584
                    {
585
586
                        /* Determine if we should break here or at the top of the loop.  */
587
15185
                        if (n < (FX_MAX_LONG_NAME_LEN - 1))
588
                        {
589
590
                            /* Yes, break out of the loop early.  */
591
15182
                            break;
592
                        }
593
                    }
594
                }
595
            }
596
        }
597
        else
598
        {
599
600
            /* Directory size is the number of entries in the root directory.  */
601
96303
            directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
602
        }
603
604
        /* Loop through entries in the directory.  Yes, this is a
605
           linear search!  */
606
112213
        i =      0;
607
112213
        found =  FX_FALSE;
608
609
610
        do
611
        {
612
613
            /* Read an entry from the directory.  */
614
1425685
            status =  _fx_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr);
615
616
1425685
            i++;
617
618
            /* Check for error status.  */
619
1425685
            if (status != FX_SUCCESS)
620
            {
621
12
                return(status);
622
            }
623
624
            /* Determine if this is the last directory entry.  */
625
1425673
            if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
626
            {
627
63561
                break;
628
            }
629
630
            /* Determine if the entry is a volume label entry */
631
1362112
            if ((entry_ptr -> fx_dir_entry_attributes & FX_VOLUME))
632
            {
633
995
                continue;
634
            }
635
636
            /* Determine if this is an empty entry.  */
637

1361117
            if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))
638
            {
639
2712
                continue;
640
            }
641
642
            /* Compare the input name and extension with the directory
643
               entry.  */
644
1358405
            work_ptr =      &name[0];
645
1358405
            dir_name_ptr =  &(entry_ptr -> fx_dir_entry_name[0]);
646
647
            /* Loop to compare names.  */
648
            do
649
            {
650
651
                /* Pickup character of directory name.  */
652
4462143
                alpha =  *dir_name_ptr;
653
654
                /* Pickup character of name.  */
655
4462143
                name_alpha =  *work_ptr;
656
657
                /* Determine if its case needs to be changed.  */
658

4462143
                if ((alpha >= 'a') && (alpha <= 'z'))
659
                {
660
661
                    /* Yes, make upper case.  */
662
69404
                    alpha =  (CHAR)((INT)alpha - 0x20);
663
                }
664
665
                /* Determine if its case needs to be changed.  */
666

4462143
                if ((name_alpha >= 'a') && (name_alpha <= 'z'))
667
                {
668
669
                    /* Yes, make upper case.  */
670
99226
                    name_alpha =  (CHAR)((INT)name_alpha - 0x20);
671
                }
672
673
                /* Compare name with directory name.  */
674
4462143
                if (alpha != name_alpha)
675
                {
676
677
                    /* The names don't match, get out of the loop. */
678
1321985
                    break;
679
                }
680
681
                /* Otherwise, increment the name pointers.  */
682
3140158
                work_ptr++;
683
3140158
                dir_name_ptr++;
684
3140158
            } while (*dir_name_ptr);
685
686
            /* Determine if the requested name has been found.  If so,
687
               return success to the caller.  */
688

1358405
            if ((*dir_name_ptr == 0) && (*work_ptr == *dir_name_ptr))
689
            {
690
691
                /* Yes, the name was located.  All pertinent directory
692
                   information is in the directory entry field.  */
693
34631
                found =  FX_TRUE;
694
            }
695
            /* Determine if there is a short name to check.  */
696
1323774
            else if (entry_ptr -> fx_dir_entry_short_name[0] != 0)
697
            {
698
699
                /* Yes, check for the short part of the name.  */
700
701
                /* Compare the input name and extension with the directory entry.  */
702
46915
                work_ptr =      &name[0];
703
46915
                dir_name_ptr =  &(entry_ptr -> fx_dir_entry_short_name[0]);
704
705
                /* Loop to compare names.  */
706
                do
707
                {
708
709
                    /* Pickup character of directory name.  */
710
77450
                    alpha =  *dir_name_ptr;
711
712
                    /* Pickup character of name.  */
713
77450
                    name_alpha =  *work_ptr;
714
715
                    /* Determine if its case needs to be changed.  */
716

77450
                    if ((name_alpha >= 'a') && (name_alpha <= 'z'))
717
                    {
718
719
                        /* Yes, make upper case.  */
720
52801
                        name_alpha =  (CHAR)((INT)name_alpha - 0x20);
721
                    }
722
723
                    /* Compare name with directory name.  */
724
77450
                    if (alpha != name_alpha)
725
                    {
726
727
                        /* The names don't match, get out of the loop. */
728
43266
                        break;
729
                    }
730
731
                    /* Otherwise, move the name pointers and increment the
732
                       count.  */
733
34184
                    work_ptr++;
734
34184
                    dir_name_ptr++;
735
34184
                } while (*dir_name_ptr);
736
737
                /* Determine if the names match.  */
738

46915
                if ((*dir_name_ptr == 0) && (*work_ptr == *dir_name_ptr))
739
                {
740
741
                    /* Yes, the name was located.  All pertinent directory
742
                        information is in the directory entry field.  */
743
2742
                    found =  FX_TRUE;
744
                }
745
            }
746

1362112
        } while ((i < directory_size) && (!found));
747
748
        /* Now determine if we have a match.  */
749
112201
        if (!found)
750
        {
751
752
            /* Return a "not found" status to the caller.  */
753
74828
            return(FX_NOT_FOUND);
754
        }
755
756
        /* Determine if the found entry is indeed a sub-directory.  */
757
37373
        if (entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
758
        {
759
760
            /* Move the directory search pointer to this entry.  */
761
18090
            search_dir =      *entry_ptr;
762
18090
            search_dir_ptr =  &search_dir;
763
764
            /* Ensure that the search directory's last search cluster is cleared.  */
765
18090
            search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
766
767
            /* Now determine if the new search directory is the root
768
               directory.  */
769
18090
            if (!search_dir_ptr -> fx_dir_entry_cluster)
770
            {
771
772
                /* This is a backward link to the root directory.  Make
773
                   sure this is indicated in the search directory
774
                   information.  */
775
19
                search_dir_ptr -> fx_dir_entry_name[0] =  0;
776
777
                /* Determine if we need to remember this in the last
778
                   directory searched return area.  */
779
19
                if (last_dir_ptr)
780
                {
781
782
                    /* Yes, return this value to the caller.  */
783
784
                    /* First, save the name pointer from the list directory pointer.  */
785
1
                    destination_name_ptr =  last_dir_ptr -> fx_dir_entry_name;
786
787
                    /* Copy the entire directory entry structure.  */
788
1
                    *last_dir_ptr =  *search_dir_ptr;
789
790
                    /* Restore the original name buffer pointer.  */
791
1
                    last_dir_ptr -> fx_dir_entry_name =  destination_name_ptr;
792
793
                    /* Pickup pointer to name to copy.  */
794
1
                    source_name_ptr =  search_dir_ptr -> fx_dir_entry_name;
795
796
                    /* Loop to copy the name into the last directory name buffer.  */
797
257
                    for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
798
                    {
799
800
                        /* Copy a character.  */
801
256
                        destination_name_ptr[n] =  source_name_ptr[n];
802
                    }
803
                }
804
805
                /* Set the search directory pointer to NULL to indicate
806
                   we are at the root directory.  */
807
19
                search_dir_ptr =  FX_NULL;
808
            }
809
        }
810
        else
811
        {
812
813
            /* This is not a directory, we better return not found
814
               since we can't continue the search.  */
815
19283
            if (name_ptr)
816
            {
817
818
                /* Return not-found status to caller.  */
819
1
                return(FX_NOT_FOUND);
820
            }
821
        }
822
37372
    } while (name_ptr);
823
824
    /* If you reach this point, the directory is found absolutely, since !found will return directly in the loop above.   */
825
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
826
827
828
    /* At this point, cache the found information.  If a subsequent search for the same name is done,
829
       it will return immediately.  */
830
831
    /* Set the index of the saved name string.  */
832
22208
    v=  0;
833
834
    /* First, build the full path and name.  */
835

22208
    if ((*original_name != '\\') && (*original_name != '/') && (path_ptr))
836
    {
837
838
        /* Copy the path into the destination.  */
839

45042
        while ((v< (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
840
        {
841
842
            /* Copy one character.   */
843
44649
            media_ptr -> fx_media_last_found_name[v] =  path_ptr[v];
844
845
            /* Move to next character.  */
846
44649
            v++;
847
        }
848
    }
849
850
    /* Now see if there is no directory path symbol in the name itself.  */
851

22208
    if ((*original_name != '\\') && (*original_name != '/'))
852
    {
853
854
        /* If there is room, place a directory separator character.  */
855
21982
        if (v < (FX_MAX_LAST_NAME_LEN - 1))
856
        {
857
21875
            media_ptr -> fx_media_last_found_name[v++] =  '/';
858
        }
859
    }
860
861
    /* Now append the name to the path.  */
862
22208
    j =  0;
863

221448
    while ((v < FX_MAX_LAST_NAME_LEN) && (original_name[j]))
864
    {
865
866
        /* Copy one character.   */
867
199240
        media_ptr -> fx_media_last_found_name[v] =  original_name[j];
868
869
        /* Move to next character.  */
870
199240
        v++;
871
199240
        j++;
872
    }
873
874
    /* Null terminate the last name string.   */
875
22208
    if (v< FX_MAX_LAST_NAME_LEN)
876
    {
877
878
        /* Null terminate.  */
879
22058
        media_ptr -> fx_media_last_found_name[v] =  FX_NULL;
880
    }
881
    else
882
    {
883
884
        /* The string is too big, NULL the string so it won't be used in searching.  */
885
150
        media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
886
    }
887
888
    /* Determine if there is a search pointer.  */
889
22208
    if (search_dir_ptr)
890
    {
891
892
        /* Yes, there is a search directory pointer so save it!   */
893
3021
        media_ptr -> fx_media_last_found_directory =  *search_dir_ptr;
894
895
        /* Indicate the search directory is valid.  */
896
3021
        media_ptr -> fx_media_last_found_directory_valid =  FX_TRUE;
897
    }
898
    else
899
    {
900
901
        /* Indicate the search directory is not valid.  */
902
19187
        media_ptr -> fx_media_last_found_directory_valid =  FX_FALSE;
903
    }
904
905
    /* Copy the directory entry.  */
906
22208
    media_ptr -> fx_media_last_found_entry =  *entry_ptr;
907
908
    /* Setup the directory entry for the last found internal file name.  */
909
22208
    media_ptr -> fx_media_last_found_entry.fx_dir_entry_name =  media_ptr -> fx_media_last_found_file_name;
910
911
    /* Copy the actual directory name into the cached directory name.  */
912
217372
    for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
913
    {
914
915
        /* Copy character into the cached directory name.  */
916
217353
        media_ptr -> fx_media_last_found_file_name[index] =  entry_ptr ->  fx_dir_entry_name[index];
917
918
        /* See if we have copied the NULL termination character.  */
919
217353
        if (entry_ptr -> fx_dir_entry_name[index] == (CHAR)FX_NULL)
920
        {
921
922
            /* Check to see if we use the break to get out of the loop.  */
923
22208
            if (index < (FX_MAX_LONG_NAME_LEN - 1))
924
            {
925
926
                /* Yes, not at the end of the string, break.  */
927
22189
                break;
928
            }
929
        }
930
    }
931
#endif
932
933
22208
    return(FX_SUCCESS);
934
}
935