1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** FileX Component */
16 /** */
17 /** Directory */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define FX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "fx_api.h"
28 #include "fx_system.h"
29 #include "fx_directory.h"
30 #include "fx_utility.h"
31
32 #ifndef FX_NO_LOCAL_PATH
33 FX_LOCAL_PATH_SETUP
34 #endif
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _fx_directory_next_full_entry_find PORTABLE C */
42 /* 6.1 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function returns the name of the next entry in the current */
50 /* working directory and various information about the name. The */
51 /* function that returns the first name in the current directory must */
52 /* be called prior to this function. */
53 /* */
54 /* INPUT */
55 /* */
56 /* media_ptr Media control block pointer */
57 /* directory_name Destination for directory */
58 /* name */
59 /* attributes Destination for attributes */
60 /* size Destination for size */
61 /* year Destination for year */
62 /* month Destination for month */
63 /* day Destination for day */
64 /* hour Destination for hour */
65 /* minute Destination for minute */
66 /* second Destination for second */
67 /* */
68 /* OUTPUT */
69 /* */
70 /* return status */
71 /* */
72 /* CALLS */
73 /* */
74 /* _fx_directory_entry_read Read entries from root dir */
75 /* _fx_utility_FAT_entry_read Read FAT entries */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code and */
80 /* FileX System Functions */
81 /* */
82 /* RELEASE HISTORY */
83 /* */
84 /* DATE NAME DESCRIPTION */
85 /* */
86 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
87 /* 09-30-2020 William E. Lamie Modified comment(s), */
88 /* resulting in version 6.1 */
89 /* */
90 /**************************************************************************/
_fx_directory_next_full_entry_find(FX_MEDIA * media_ptr,CHAR * directory_name,UINT * attributes,ULONG * size,UINT * year,UINT * month,UINT * day,UINT * hour,UINT * minute,UINT * second)91 UINT _fx_directory_next_full_entry_find(FX_MEDIA *media_ptr,
92 CHAR *directory_name, UINT *attributes, ULONG *size,
93 UINT *year, UINT *month, UINT *day, UINT *hour, UINT *minute, UINT *second)
94 {
95
96 ULONG i;
97 UINT status;
98 UINT temp_status;
99 ULONG cluster, next_cluster = 0;
100 ULONG64 directory_size;
101 FX_DIR_ENTRY entry;
102 FX_DIR_ENTRY *search_dir_ptr;
103 FX_PATH *path_ptr;
104 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
105 UINT index;
106 CHAR *path_string_ptr = FX_NULL;
107 #endif
108
109
110 #ifndef FX_MEDIA_STATISTICS_DISABLE
111
112 /* Increment the number of times this service has been called. */
113 media_ptr -> fx_media_directory_next_full_entry_finds++;
114 #endif
115
116 /* Setup pointer to media name buffer. */
117 entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
118
119 /* Clear the short name string. */
120 entry.fx_dir_entry_short_name[0] = 0;
121
122
123 /* Check the media to make sure it is open. */
124 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
125 {
126
127 /* Return the media not opened error. */
128 return(FX_MEDIA_NOT_OPEN);
129 }
130
131 /* If trace is enabled, insert this event into the trace buffer. */
132 FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_NEXT_FULL_ENTRY_FIND, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
133
134 /* Protect against other threads accessing the media. */
135 FX_PROTECT
136
137 /* First check for a local path pointer stored in the thread control block. This
138 is only available in ThreadX Version 4 and above. */
139 #ifndef FX_NO_LOCAL_PATH
140 if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
141 {
142
143 /* Setup the default path pointer. */
144 path_ptr = (FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr;
145
146 /* Determine if we are at the root directory. */
147 if (path_ptr -> fx_path_directory.fx_dir_entry_name[0])
148 {
149
150 /* No, we are not at the root directory. */
151
152 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
153
154 /* Setup pointer to the path. */
155 path_string_ptr = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_string;
156 #endif
157
158 /* Set the internal pointer to the search directory as well. */
159 search_dir_ptr = &path_ptr -> fx_path_directory;
160 }
161 else
162 {
163
164 /* The current default directory is the root so just set the
165 search directory pointer to NULL. */
166 search_dir_ptr = FX_NULL;
167 }
168 }
169 else
170 #endif
171
172 /* Set the initial search directory to the current working
173 directory - if there is one. */
174 if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
175 {
176
177 /* Setup the path pointer to the global media path. */
178 path_ptr = &media_ptr -> fx_media_default_path;
179
180 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
181
182 /* Setup pointer to the path. */
183 path_string_ptr = media_ptr -> fx_media_default_path.fx_path_string;
184 #endif
185
186 /* Set the internal pointer to the search directory as well. */
187 search_dir_ptr = &path_ptr -> fx_path_directory;
188 }
189 else
190 {
191
192 /* Setup the path pointer to the global media path. */
193 path_ptr = &media_ptr -> fx_media_default_path;
194
195 /* The current default directory is the root so just set the
196 search directory pointer to NULL. */
197 search_dir_ptr = FX_NULL;
198 }
199
200 /* Calculate the directory size. */
201 if (search_dir_ptr)
202 {
203
204
205 /* Determine the directory size. */
206 if (path_ptr -> fx_path_current_entry != 0)
207 {
208
209 /* Pickup the previously saved directory size. */
210 directory_size = search_dir_ptr -> fx_dir_entry_file_size;
211 }
212 else
213 {
214
215 /* This should only be done on the first time into next directory find. */
216
217 /* Ensure that the search directory's last search cluster is cleared. */
218 search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
219
220 /* Calculate the directory size by counting the allocated
221 clusters for it. */
222 i = 0;
223 cluster = search_dir_ptr -> fx_dir_entry_cluster;
224 while (cluster < media_ptr -> fx_media_fat_reserved)
225 {
226
227 /* Increment the cluster count. */
228 i++;
229
230 /* Read the next FAT entry. */
231 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
232
233
234 /* Check the return status. */
235 if (status != FX_SUCCESS)
236 {
237
238 /* Release media protection. */
239 FX_UNPROTECT
240
241 /* Return the bad status. */
242 return(status);
243 }
244
245 if ((cluster < FX_FAT_ENTRY_START) || (cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
246 {
247
248 /* Release media protection. */
249 FX_UNPROTECT
250
251 /* Return the bad status. */
252 return(FX_FAT_READ_ERROR);
253 }
254
255 cluster = next_cluster;
256 }
257
258 /* Now we can calculate the directory size. */
259 directory_size = (((ULONG64) media_ptr -> fx_media_bytes_per_sector) *
260 ((ULONG64) media_ptr -> fx_media_sectors_per_cluster) * i)
261 / (ULONG64) FX_DIR_ENTRY_SIZE;
262
263 /* Save how many entries there are in the directory. */
264 search_dir_ptr -> fx_dir_entry_file_size = directory_size;
265 }
266 }
267 else
268 {
269
270 /* Directory size is the number of entries in the root directory. */
271 directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
272 }
273
274 /* Preset status with an error return. */
275 status = FX_NO_MORE_ENTRIES;
276
277 /* Determine if the current entry is inside of the directory's range. */
278 while (path_ptr -> fx_path_current_entry < directory_size)
279 {
280
281 /* Read an entry from the directory. */
282 temp_status = _fx_directory_entry_read(media_ptr, search_dir_ptr,
283 &(path_ptr -> fx_path_current_entry), &entry);
284
285 /* Check for error status. */
286 if (temp_status != FX_SUCCESS)
287 {
288
289 /* Release media protection. */
290 FX_UNPROTECT
291
292 /* Return error status. */
293 return(temp_status);
294 }
295
296
297 /* Check to see if the entry has something in it. */
298 if (((UCHAR)entry.fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry.fx_dir_entry_short_name[0] == 0))
299 {
300
301 /* Current entry is free, skip to next entry and continue the loop. */
302 path_ptr -> fx_path_current_entry++;
303 continue;
304 }
305
306 /* Determine if a valid directory entry is present. */
307 else if ((UCHAR)entry.fx_dir_entry_name[0] != (UCHAR)FX_DIR_ENTRY_DONE)
308 {
309
310 /* A valid directory entry is present. */
311
312 /* Copy the name into the destination. */
313 for (i = 0; entry.fx_dir_entry_name[i]; i++)
314 {
315
316 *directory_name = entry.fx_dir_entry_name[i];
317 directory_name++;
318 }
319
320 /* Place a NULL at the end of the directory name. */
321 *directory_name = (CHAR)0;
322
323 /* Determine if the entry's attributes are required. */
324 if (attributes)
325 {
326
327 /* Pickup the entry's attributes. */
328 *attributes = entry.fx_dir_entry_attributes;
329 }
330
331 /* Determine if the entry's size is required. */
332 if (size)
333 {
334
335 /* Pickup the entry's size. */
336 *size = (ULONG)entry.fx_dir_entry_file_size;
337 }
338
339 /* Determine if the entry's year is required. */
340 if (year)
341 {
342
343 /* Pickup the entry's year. */
344 *year = ((entry.fx_dir_entry_date >> FX_YEAR_SHIFT) & FX_YEAR_MASK) + FX_BASE_YEAR;
345 }
346
347 /* Determine if the entry's month is required. */
348 if (month)
349 {
350
351 /* Pickup the entry's month. */
352 *month = (entry.fx_dir_entry_date >> FX_MONTH_SHIFT) & FX_MONTH_MASK;
353 }
354
355 /* Determine if the entry's day is required. */
356 if (day)
357 {
358
359 /* Pickup the entry's day. */
360 *day = entry.fx_dir_entry_date & FX_DAY_MASK;
361 }
362
363 /* Determine if the entry's hour is required. */
364 if (hour)
365 {
366
367 /* Pickup the entry's hour. */
368 *hour = (entry.fx_dir_entry_time >> FX_HOUR_SHIFT) & FX_HOUR_MASK;
369 }
370
371 /* Determine if the entry's minute is required. */
372 if (minute)
373 {
374
375 /* Pickup the entry's minute. */
376 *minute = (entry.fx_dir_entry_time >> FX_MINUTE_SHIFT) & FX_MINUTE_MASK;
377 }
378
379 /* Determine if the entry's second is required. */
380 if (second)
381 {
382
383 /* Pickup the entry's second. */
384 *second = (entry.fx_dir_entry_time & FX_SECOND_MASK) * 2;
385 }
386
387 /* Increment the current entry for the media. */
388 path_ptr -> fx_path_current_entry++;
389
390 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
391 {
392 UINT v, j;
393
394
395 /* If a subsequent search for the same name is done, it will find it immediately. */
396
397 /* Set the index of the saved name string. */
398 v = 0;
399
400 /* First, build the full path and name. */
401 if (path_string_ptr)
402 {
403
404 /* Copy the path into the destination. */
405 while ((v < (FX_MAX_LAST_NAME_LEN - 1)) && (path_string_ptr[v]))
406 {
407
408 /* Copy one character. */
409 media_ptr -> fx_media_last_found_name[v] = path_string_ptr[v];
410
411 /* Move to next character. */
412 v++;
413 }
414 }
415
416 /* We know there is room at this point, place a directory separator character. */
417 media_ptr -> fx_media_last_found_name[v++] = '/';
418
419 /* Now append the name to the path. */
420 j = 0;
421 while ((v < FX_MAX_LAST_NAME_LEN) && (entry.fx_dir_entry_name[j]))
422 {
423
424 /* Copy one character. */
425 media_ptr -> fx_media_last_found_name[v] = entry.fx_dir_entry_name[j];
426
427 /* Move to next character. */
428 v++;
429 j++;
430 }
431
432 /* Null terminate the last name string. */
433 if (v < FX_MAX_LAST_NAME_LEN)
434 {
435
436 /* Null terminate. */
437 media_ptr -> fx_media_last_found_name[v] = FX_NULL;
438 }
439 else
440 {
441
442 /* The string is too big, NULL the string so it won't be used in searching. */
443 media_ptr -> fx_media_last_found_name[0] = FX_NULL;
444 }
445
446 /* Determine if there is a search pointer. */
447 if (search_dir_ptr)
448 {
449
450 /* Yes, there is a search directory pointer so save it! */
451 media_ptr -> fx_media_last_found_directory = *search_dir_ptr;
452
453 /* Indicate the search directory is valid. */
454 media_ptr -> fx_media_last_found_directory_valid = FX_TRUE;
455 }
456 else
457 {
458
459 /* Indicate the search directory is not valid. */
460 media_ptr -> fx_media_last_found_directory_valid = FX_FALSE;
461 }
462
463 /* Copy the directory entry. */
464 media_ptr -> fx_media_last_found_entry = entry;
465
466 /* Setup the last found directory entry to point at the last found internal file name. */
467 media_ptr -> fx_media_last_found_entry.fx_dir_entry_name = media_ptr -> fx_media_last_found_file_name;
468
469 /* Copy the actual directory name into the cached directory name. */
470 for (index = 0; index < FX_MAX_LONG_NAME_LEN; index++)
471 {
472
473 /* Copy character into the cached directory name. */
474 media_ptr -> fx_media_last_found_file_name[index] = entry.fx_dir_entry_name[index];
475
476 /* See if we have copied the NULL termination character. */
477 if (entry.fx_dir_entry_name[index] == (CHAR)FX_NULL)
478 {
479
480 /* Check to see if we use the break to get out of the loop. */
481 if (v < (FX_MAX_LONG_NAME_LEN - 1))
482 {
483
484 /* Yes, not at the end of the string, break. */
485 break;
486 }
487 }
488 }
489 }
490 #endif
491
492 /* Set return status to success. */
493 status = FX_SUCCESS;
494
495 /* Get out of the loop. */
496 break;
497 }
498 else
499 {
500 /* Set the error code. */
501 status = FX_NO_MORE_ENTRIES;
502
503 /* Get out of the loop. */
504 break;
505 }
506 }
507
508 /* Release media protection. */
509 FX_UNPROTECT
510
511 /* Return status to the caller. */
512 return(status);
513 }
514
515