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 /**************************************************************************/
_fx_directory_next_entry_find(FX_MEDIA * media_ptr,CHAR * directory_name)83 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 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 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     media_ptr -> fx_media_directory_next_entry_finds++;
104 #endif
105 
106     /* Setup pointer to media name buffer.  */
107     entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
108 
109     /* Clear the short name string.  */
110     entry.fx_dir_entry_short_name[0] =  0;
111 
112     /* Check the media to make sure it is open.  */
113     if (media_ptr -> fx_media_id != FX_MEDIA_ID)
114     {
115 
116         /* Return the media not opened error.  */
117         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     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     if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
132     {
133 
134         /* Setup the default path pointer.  */
135         path_ptr =  (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
136 
137         /* Determine if we are at the root directory.  */
138         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             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             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             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     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         path_ptr =  &media_ptr -> fx_media_default_path;
170 
171 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
172 
173         /* Setup pointer to the path.  */
174         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         search_dir_ptr =  &(path_ptr -> fx_path_directory);
179     }
180     else
181     {
182 
183         /* Setup the path pointer to the global media path.  */
184         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         search_dir_ptr =  FX_NULL;
189     }
190 
191     /* Calculate the directory size.  */
192     if (search_dir_ptr)
193     {
194         /* Determine the directory size.  */
195         if (path_ptr -> fx_path_current_entry != 0)
196         {
197 
198             /* Pickup the previously saved directory size.  */
199             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             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             i =        0;
212             cluster =  search_dir_ptr -> fx_dir_entry_cluster;
213             while (cluster < media_ptr -> fx_media_fat_reserved)
214             {
215 
216                 /* Increment the cluster count.  */
217                 i++;
218 
219                 /* Read the next FAT entry.  */
220                 status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
221 
222                 /* Check the return status.  */
223                 if (status != FX_SUCCESS)
224                 {
225 
226                     /* Release media protection.  */
227                     FX_UNPROTECT
228 
229                     /* Return the bad status.  */
230                     return(status);
231                 }
232 
233                 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
234                 {
235 
236                     /* Release media protection.  */
237                     FX_UNPROTECT
238 
239                     /* Return the bad status.  */
240                     return(FX_FAT_READ_ERROR);
241                 }
242 
243                 cluster = next_cluster;
244             }
245 
246             /* Now we can calculate the directory size.  */
247             directory_size =  (((ULONG64)media_ptr -> fx_media_bytes_per_sector) *
248                                ((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             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         directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
260     }
261 
262     /* Preset status with an error return.  */
263     status =  FX_NO_MORE_ENTRIES;
264 
265     /* Determine if the current entry is inside of the directory's range.  */
266     while (path_ptr -> fx_path_current_entry < directory_size)
267     {
268 
269         /* Read an entry from the directory.  */
270         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         if (temp_status != FX_SUCCESS)
275         {
276 
277             /* Release media protection.  */
278             FX_UNPROTECT
279 
280             /* Return error status.  */
281             return(temp_status);
282         }
283 
284         /* Check to see if the entry has something in it.  */
285         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             path_ptr -> fx_path_current_entry++;
290             continue;
291         }
292         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             for (i = 0; entry.fx_dir_entry_name[i]; i++)
299             {
300 
301                 *directory_name = entry.fx_dir_entry_name[i];
302                 directory_name++;
303             }
304 
305             /* Place a NULL at the end of the directory name.  */
306             *directory_name =  (CHAR)0;
307 
308             /* Increment the current entry for the media.  */
309             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                 v =  0;
320 
321                 /* First, build the full path and name.  */
322                 if (path_string_ptr)
323                 {
324 
325                     /* Copy the path into the destination.  */
326                     while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
327                     {
328 
329                         /* Copy one character.   */
330                         media_ptr -> fx_media_last_found_name[v] =  path_string_ptr[v];
331 
332                         /* Move to next character.  */
333                         v++;
334                     }
335                 }
336 
337                 /* We know there is room at this point, place a directory separator character.  */
338                 media_ptr -> fx_media_last_found_name[v++] =  '/';
339 
340                 /* Now append the name to the path.  */
341                 j =  0;
342                 while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
343                 {
344 
345                     /* Copy one character.   */
346                     media_ptr -> fx_media_last_found_name[v] =  entry.fx_dir_entry_name[j];
347 
348                     /* Move to next character.  */
349                     v++;
350                     j++;
351                 }
352 
353                 /* Null terminate the last name string.   */
354                 if (v < FX_MAX_LAST_NAME_LEN)
355                 {
356 
357                     /* Null terminate.  */
358                     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                     media_ptr -> fx_media_last_found_name[0] =  FX_NULL;
365                 }
366 
367                 /* Determine if there is a search pointer.  */
368                 if (search_dir_ptr)
369                 {
370 
371                     /* Yes, there is a search directory pointer so save it!   */
372                     media_ptr -> fx_media_last_found_directory =  *search_dir_ptr;
373 
374                     /* Indicate the search directory is valid.  */
375                     media_ptr -> fx_media_last_found_directory_valid =  FX_TRUE;
376                 }
377                 else
378                 {
379 
380                     /* Indicate the search directory is not valid.  */
381                     media_ptr -> fx_media_last_found_directory_valid =  FX_FALSE;
382                 }
383 
384                 /* Copy the directory entry.  */
385                 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                 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                 for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
392                 {
393 
394                     /* Copy character into the cached directory name.  */
395                     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                     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                         if (v < (FX_MAX_LONG_NAME_LEN - 1))
403                         {
404 
405                             /* Yes, not at the end of the string, break.  */
406                             break;
407                         }
408                     }
409                 }
410             }
411 #endif
412 
413             /* Set return status to success.  */
414             status =  FX_SUCCESS;
415 
416             /* Get out of the loop.  */
417             break;
418         }
419         else
420         {
421 
422             /* Set the error code.  */
423             status =  FX_NO_MORE_ENTRIES;
424 
425             /* Get out of the loop.  */
426             break;
427         }
428     }
429 
430     /* Release media protection.  */
431     FX_UNPROTECT
432 
433     /* Return status to the caller.  */
434     return(status);
435 }
436 
437