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