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 /**************************************************************************/
_fx_directory_search(FX_MEDIA * media_ptr,CHAR * name_ptr,FX_DIR_ENTRY * entry_ptr,FX_DIR_ENTRY * last_dir_ptr,CHAR ** last_name_ptr)97 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 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 CHAR *path_ptr = FX_NULL;
119 CHAR *original_name = name_ptr;
120 #endif
121
122 #ifndef FX_MEDIA_STATISTICS_DISABLE
123
124 /* Increment the number of directory search requests. */
125 media_ptr -> fx_media_directory_searches++;
126 #endif
127
128 /* Setup pointer to media name buffer. */
129 name = media_ptr -> fx_media_name_buffer;
130
131 /* Setup the last directory, if required. */
132 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 last_dir_ptr -> fx_dir_entry_name[0] = 0;
138 }
139
140 /* Determine if the file name has a full directory path. */
141 if ((*name_ptr == '\\') || (*name_ptr == '/'))
142 {
143
144 /* Directory name has full path, set the search pointer to NULL. */
145 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 if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
157 {
158
159 /* Determine if the local directory is not the root directory. */
160 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 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 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 search_dir_ptr = &search_dir;
174 }
175 else
176 {
177
178 /* We are searching in the root directory. */
179 search_dir_ptr = FX_NULL;
180 }
181 }
182 else
183 #endif
184 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 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 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 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 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 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 v = 0;
221
222 /* Determine if there is a full path. */
223 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 while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[v]))
229 {
230
231 /* Pickup the respective name characters. */
232 alpha = name_ptr[v];
233 beta = media_ptr -> fx_media_last_found_name[v];
234
235 /* Ensure directory markers are the same. */
236 if (alpha == '\\')
237 {
238 alpha = '/';
239 }
240 if (beta == '\\')
241 {
242 beta = '/';
243 }
244
245 /* Is the name the same? */
246 if (alpha != beta)
247 {
248
249 /* Break out of loop! */
250 break;
251 }
252
253 /* Move to next character. */
254 v++;
255 }
256
257 /* Determine if we have a match. */
258 if (name_ptr[v] != media_ptr -> fx_media_last_found_name[v])
259 {
260 match = FX_FALSE;
261 }
262 else
263 {
264 match = FX_TRUE;
265 }
266 }
267 else
268 {
269
270 /* Default to found. */
271 match = FX_TRUE;
272
273 /* Determine if there is a default path to compare with. */
274 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 while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
281 {
282
283 /* Pickup the respective name characters. */
284 alpha = media_ptr -> fx_media_last_found_name[v];
285 beta = path_ptr[v];
286
287 /* Ensure directory markers are the same. */
288 if (alpha == '\\')
289 {
290 alpha = '/';
291 }
292 if (beta == '\\')
293 {
294 beta = '/';
295 }
296
297 /* Is the name the same? */
298 if (alpha != beta)
299 {
300
301 /* Break out of loop! */
302 break;
303 }
304
305 /* Move to next character. */
306 v++;
307 }
308
309 /* Determine if we don't have a match... The relative path must be exhausted. */
310 if (path_ptr[v])
311 {
312 match = FX_FALSE;
313 }
314 }
315
316 /* Determine if we still have a match. */
317 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 if ((media_ptr -> fx_media_last_found_name[v] != '\\') &&
325 (media_ptr -> fx_media_last_found_name[v] != '/'))
326 {
327
328 /* Set match to false - invalid directory path separator. */
329 match = FX_FALSE;
330 }
331 else
332 {
333 /* Position past the next directory separator in the
334 last name string. */
335 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 j = 0;
341 while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (name_ptr[j]) && (match))
342 {
343
344 /* Pickup the respective name characters. */
345 alpha = name_ptr[j];
346 beta = media_ptr -> fx_media_last_found_name[v];
347
348 /* Ensure directory markers are the same. */
349 if (alpha == '\\')
350 {
351 alpha = '/';
352 }
353 if (beta == '\\')
354 {
355 beta = '/';
356 }
357
358 /* Is the name the same? */
359 if (alpha != beta)
360 {
361
362 /* Break out of loop! */
363 break;
364 }
365
366 /* Move to next character. */
367 v++;
368 j++;
369 }
370
371 /* Avoid accessing fx_media_last_found_name out of bounds. */
372 if (v >= 256)
373 {
374 match = FX_FALSE;
375 }
376 else if ((match) && (name_ptr[j] != media_ptr -> fx_media_last_found_name[v]))
377 {
378
379 /* We don't have a match. */
380 match = FX_FALSE;
381 }
382 }
383 }
384
385 /* Now determine if we actually found a match. */
386 if (match)
387 {
388
389 /* Save the directory entry name pointer. */
390 temp_ptr = entry_ptr -> fx_dir_entry_name;
391
392 /* Copy the saved directory entry. */
393 *entry_ptr = media_ptr -> fx_media_last_found_entry;
394
395 /* Restore the directory entry name pointer. */
396 entry_ptr -> fx_dir_entry_name = temp_ptr;
397
398 /* Copy the directory name into the destination directory name. */
399 for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
400 {
401
402 /* Copy character into the destination. */
403 temp_ptr[index] = media_ptr -> fx_media_last_found_file_name[index];
404
405 /* See if we have copied the NULL termination character. */
406 if (temp_ptr[index] == (CHAR)FX_NULL)
407 {
408
409 /* Determine if we should break here or at the top of the loop. */
410 if (index < (FX_MAX_LONG_NAME_LEN - 1))
411 {
412
413 /* Yes, break out of the loop early. */
414 break;
415 }
416 }
417 }
418
419 /* Determine if there is a search directory to copy. */
420 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 destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
428
429 /* Copy the entire directory entry structure. */
430 *last_dir_ptr = media_ptr -> fx_media_last_found_directory;
431
432 /* Restore the original name buffer pointer. */
433 last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
434
435 /* Pickup pointer to name to copy. */
436 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 for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
440 {
441
442 /* Copy a character. */
443 destination_name_ptr[n] = source_name_ptr[n];
444
445 /* See if we have copied the NULL termination character. */
446 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 if (n < (FX_MAX_LONG_NAME_LEN - 1))
451 {
452
453 /* Yes, break out of the loop early. */
454 break;
455 }
456 }
457 }
458 }
459
460 /* Return the last name pointer, if required. */
461 if (last_name_ptr)
462 {
463
464 /* Just set the last name to initial name string. */
465 *last_name_ptr = temp_ptr;
466 }
467
468 #ifndef FX_MEDIA_STATISTICS_DISABLE
469
470 /* Increment the number of directory search cache hits. */
471 media_ptr -> fx_media_directory_search_cache_hits++;
472 #endif
473
474 /* Return success. */
475 return(FX_SUCCESS);
476 }
477 }
478
479 /* Not a sequential search, invalidate the saved information. */
480 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 if (last_name_ptr)
499 {
500
501 /* Just set the last name to initial name string. */
502 *last_name_ptr = name_ptr;
503 }
504
505 /* Extract file name. */
506 name_ptr = _fx_directory_name_extract(name_ptr, name);
507
508 /* Calculate the directory size. */
509 if (search_dir_ptr)
510 {
511
512 /* Ensure that the search directory's last search cluster is cleared. */
513 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 i = 0;
518 cluster = search_dir_ptr -> fx_dir_entry_cluster;
519 while (cluster < media_ptr -> fx_media_fat_reserved)
520 {
521
522 /* Increment the cluster count. */
523 i++;
524
525 /* Read the next FAT entry. */
526 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
527
528 /* Check the return status. */
529 if (status != FX_SUCCESS)
530 {
531
532 /* Return the bad status. */
533 return(status);
534 }
535
536 /* Check for error situation. */
537 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
538 {
539
540 /* Return the bad status. */
541 return(FX_FAT_READ_ERROR);
542 }
543
544 cluster = next_cluster;
545 }
546
547 /* Now we can calculate the directory size. */
548 directory_size = (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
549 ((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 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 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 destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
565
566 /* Copy the entire directory entry structure. */
567 *last_dir_ptr = *search_dir_ptr;
568
569 /* Restore the original name buffer pointer. */
570 last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
571
572 /* Pickup pointer to name to copy. */
573 source_name_ptr = search_dir_ptr -> fx_dir_entry_name;
574
575 /* Loop to copy the name into the last directory name buffer. */
576 for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
577 {
578
579 /* Copy a character. */
580 destination_name_ptr[n] = source_name_ptr[n];
581
582 /* See if we have copied the NULL termination character. */
583 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 if (n < (FX_MAX_LONG_NAME_LEN - 1))
588 {
589
590 /* Yes, break out of the loop early. */
591 break;
592 }
593 }
594 }
595 }
596 }
597 else
598 {
599
600 /* Directory size is the number of entries in the root directory. */
601 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 i = 0;
607 found = FX_FALSE;
608
609
610 do
611 {
612
613 /* Read an entry from the directory. */
614 status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr);
615
616 i++;
617
618 /* Check for error status. */
619 if (status != FX_SUCCESS)
620 {
621 return(status);
622 }
623
624 /* Determine if this is the last directory entry. */
625 if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
626 {
627 break;
628 }
629
630 /* Determine if the entry is a volume label entry */
631 if ((entry_ptr -> fx_dir_entry_attributes & FX_VOLUME))
632 {
633 continue;
634 }
635
636 /* Determine if this is an empty entry. */
637 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 continue;
640 }
641
642 /* Compare the input name and extension with the directory
643 entry. */
644 work_ptr = &name[0];
645 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 alpha = *dir_name_ptr;
653
654 /* Pickup character of name. */
655 name_alpha = *work_ptr;
656
657 /* Determine if its case needs to be changed. */
658 if ((alpha >= 'a') && (alpha <= 'z'))
659 {
660
661 /* Yes, make upper case. */
662 alpha = (CHAR)((INT)alpha - 0x20);
663 }
664
665 /* Determine if its case needs to be changed. */
666 if ((name_alpha >= 'a') && (name_alpha <= 'z'))
667 {
668
669 /* Yes, make upper case. */
670 name_alpha = (CHAR)((INT)name_alpha - 0x20);
671 }
672
673 /* Compare name with directory name. */
674 if (alpha != name_alpha)
675 {
676
677 /* The names don't match, get out of the loop. */
678 break;
679 }
680
681 /* Otherwise, increment the name pointers. */
682 work_ptr++;
683 dir_name_ptr++;
684 } while (*dir_name_ptr);
685
686 /* Determine if the requested name has been found. If so,
687 return success to the caller. */
688 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 found = FX_TRUE;
694 }
695 /* Determine if there is a short name to check. */
696 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 work_ptr = &name[0];
703 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 alpha = *dir_name_ptr;
711
712 /* Pickup character of name. */
713 name_alpha = *work_ptr;
714
715 /* Determine if its case needs to be changed. */
716 if ((name_alpha >= 'a') && (name_alpha <= 'z'))
717 {
718
719 /* Yes, make upper case. */
720 name_alpha = (CHAR)((INT)name_alpha - 0x20);
721 }
722
723 /* Compare name with directory name. */
724 if (alpha != name_alpha)
725 {
726
727 /* The names don't match, get out of the loop. */
728 break;
729 }
730
731 /* Otherwise, move the name pointers and increment the
732 count. */
733 work_ptr++;
734 dir_name_ptr++;
735 } while (*dir_name_ptr);
736
737 /* Determine if the names match. */
738 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 found = FX_TRUE;
744 }
745 }
746 } while ((i < directory_size) && (!found));
747
748 /* Now determine if we have a match. */
749 if (!found)
750 {
751
752 /* Return a "not found" status to the caller. */
753 return(FX_NOT_FOUND);
754 }
755
756 /* Determine if the found entry is indeed a sub-directory. */
757 if (entry_ptr -> fx_dir_entry_attributes & FX_DIRECTORY)
758 {
759
760 /* Move the directory search pointer to this entry. */
761 search_dir = *entry_ptr;
762 search_dir_ptr = &search_dir;
763
764 /* Ensure that the search directory's last search cluster is cleared. */
765 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 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 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 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 destination_name_ptr = last_dir_ptr -> fx_dir_entry_name;
786
787 /* Copy the entire directory entry structure. */
788 *last_dir_ptr = *search_dir_ptr;
789
790 /* Restore the original name buffer pointer. */
791 last_dir_ptr -> fx_dir_entry_name = destination_name_ptr;
792
793 /* Pickup pointer to name to copy. */
794 source_name_ptr = search_dir_ptr -> fx_dir_entry_name;
795
796 /* Loop to copy the name into the last directory name buffer. */
797 for (n = 0; n < FX_MAX_LONG_NAME_LEN; n++)
798 {
799
800 /* Copy a character. */
801 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 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 if (name_ptr)
816 {
817
818 /* Return not-found status to caller. */
819 return(FX_NOT_FOUND);
820 }
821 }
822 } 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 v= 0;
833
834 /* First, build the full path and name. */
835 if ((*original_name != '\\') && (*original_name != '/') && (path_ptr))
836 {
837
838 /* Copy the path into the destination. */
839 while ((v< (FX_MAX_LAST_NAME_LEN - 1)) && (path_ptr[v]))
840 {
841
842 /* Copy one character. */
843 media_ptr -> fx_media_last_found_name[v] = path_ptr[v];
844
845 /* Move to next character. */
846 v++;
847 }
848 }
849
850 /* Now see if there is no directory path symbol in the name itself. */
851 if ((*original_name != '\\') && (*original_name != '/'))
852 {
853
854 /* If there is room, place a directory separator character. */
855 if (v < (FX_MAX_LAST_NAME_LEN - 1))
856 {
857 media_ptr -> fx_media_last_found_name[v++] = '/';
858 }
859 }
860
861 /* Now append the name to the path. */
862 j = 0;
863 while ((v < FX_MAX_LAST_NAME_LEN) && (original_name[j]))
864 {
865
866 /* Copy one character. */
867 media_ptr -> fx_media_last_found_name[v] = original_name[j];
868
869 /* Move to next character. */
870 v++;
871 j++;
872 }
873
874 /* Null terminate the last name string. */
875 if (v< FX_MAX_LAST_NAME_LEN)
876 {
877
878 /* Null terminate. */
879 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 media_ptr -> fx_media_last_found_name[0] = FX_NULL;
886 }
887
888 /* Determine if there is a search pointer. */
889 if (search_dir_ptr)
890 {
891
892 /* Yes, there is a search directory pointer so save it! */
893 media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
894
895 /* Indicate the search directory is valid. */
896 media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
897 }
898 else
899 {
900
901 /* Indicate the search directory is not valid. */
902 media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
903 }
904
905 /* Copy the directory entry. */
906 media_ptr -> fx_media_last_found_entry = *entry_ptr;
907
908 /* Setup the directory entry for the last found internal file name. */
909 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 for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
913 {
914
915 /* Copy character into the cached directory name. */
916 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 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 if (index < (FX_MAX_LONG_NAME_LEN - 1))
924 {
925
926 /* Yes, not at the end of the string, break. */
927 break;
928 }
929 }
930 }
931 #endif
932
933 return(FX_SUCCESS);
934 }
935
936