GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_unicode_directory_search.c Lines: 111 111 100.0 %
Date: 2026-03-06 18:49:02 Branches: 112 112 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Unicode                                                             */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "fx_api.h"
29
#include "fx_unicode.h"
30
#include "fx_utility.h"
31
32
#ifndef FX_NO_LOCAL_PATH
33
FX_LOCAL_PATH_SETUP
34
#endif
35
36
37
/* Define several Unicode working arrays...  This keeps the data structures
38
   off the local stack.  */
39
40
UCHAR _fx_unicode_temp_long_file_name[FX_MAX_LONG_NAME_LEN];
41
UCHAR _fx_unicode_search_name[FX_MAX_LONG_NAME_LEN * 2];
42
43
44
/**************************************************************************/
45
/*                                                                        */
46
/*  FUNCTION                                               RELEASE        */
47
/*                                                                        */
48
/*    _fx_unicode_directory_search                        PORTABLE C      */
49
/*                                                           6.1          */
50
/*  AUTHOR                                                                */
51
/*                                                                        */
52
/*    William E. Lamie, Microsoft Corporation                             */
53
/*                                                                        */
54
/*  DESCRIPTION                                                           */
55
/*                                                                        */
56
/*    This function searches for the specified unicode or short name.     */
57
/*                                                                        */
58
/*    Note: The buffer of short_name and unicode_name must be valid to    */
59
/*    fill search result. When short_name is a zero length string, search */
60
/*    is based on unicode string (terminated with NULL). If it's found    */
61
/*    the short name is written back to buffer of short_name. In this case*/
62
/*    unicode_name_buffer_length is ignored and short_name_buffer_length  */
63
/*    must not be zero to specify the buffer length. If buffer is too     */
64
/*    smallfor the result, overflow characters and NULL-terminator are cut*/
65
/*    off. When short_name is a valid string, search is based on          */
66
/*    short_name (terminated with NULL). If it's found the unicode name is*/
67
/*    written back to buffer of unicode_name. In this case                */
68
/*    short_name_buffer_length is ignored and unicode_name_buffer_length  */
69
/*    must not be zero to specify the unicode buffer length. If buffer is */
70
/*    too small for the result, overflow characters are cut off but       */
71
/*    NULL-terminator is kept.                                            */
72
/*                                                                        */
73
/*  INPUT                                                                 */
74
/*                                                                        */
75
/*    media_ptr                             Pointer to media              */
76
/*    short_name                            Pointer to short name         */
77
/*    short_name_buffer_length              Buffer length for short name  */
78
/*    unicode_name                          Pointer to Unicode name       */
79
/*    unicode_name_length                   Unicode name length           */
80
/*    unicode_name_buffer_length            Buffer length for Unicode name*/
81
/*                                                                        */
82
/*  OUTPUT                                                                */
83
/*                                                                        */
84
/*    Completion Status                                                   */
85
/*                                                                        */
86
/*  CALLS                                                                 */
87
/*                                                                        */
88
/*    _fx_unicode_directory_entry_read      Read a full unicode directory */
89
/*                                            entry                       */
90
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
91
/*                                                                        */
92
/*  CALLED BY                                                             */
93
/*                                                                        */
94
/*    Unicode Utilities                                                   */
95
/*                                                                        */
96
/**************************************************************************/
97
644
UINT  _fx_unicode_directory_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr,
98
                                   UCHAR *short_name, ULONG short_name_buffer_length,
99
                                   UCHAR *unicode_name, ULONG *unicode_name_length, ULONG unicode_name_buffer_length)
100
{
101
102
ULONG         i, j;
103
UINT          status, found;
104
644
ULONG         cluster, next_cluster = 0;
105
ULONG         directory_size;
106
FX_DIR_ENTRY  search_dir;
107
FX_DIR_ENTRY *search_dir_ptr;
108
ULONG         unicode_search_length;
109
ULONG         local_unicode_name_length;
110
CHAR          unicode_to_short_name[13];
111
CHAR         *short_name_ptr;
112
113
114
    /* Setup temp unicode name length.  */
115
644
    local_unicode_name_length =  *unicode_name_length;
116
117
#ifndef FX_MEDIA_STATISTICS_DISABLE
118
119
    /* Increment the number of directory search requests.  */
120
644
    media_ptr -> fx_media_directory_searches++;
121
#endif
122
123
    /* Set the initial search directory to the current working
124
       directory - if there is one.  */
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
#ifndef FX_NO_LOCAL_PATH
129
644
    if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
130
    {
131
132
        /* Determine if the local directory is not the root directory.  */
133
116
        if (((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory.fx_dir_entry_name[0])
134
        {
135
136
            /* Start at the current working directory of the media.  */
137
96
            search_dir =   ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory;
138
139
            /* Set the internal pointer to the search directory as well.  */
140
96
            search_dir_ptr =  &search_dir;
141
        }
142
        else
143
        {
144
145
            /* We are searching in the root directory.  */
146
20
            search_dir_ptr =  FX_NULL;
147
        }
148
    }
149
    else
150
#endif
151
528
    if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
152
    {
153
154
        /* Start at the current working directory of the media.  */
155
12
        search_dir =  media_ptr -> fx_media_default_path.fx_path_directory;
156
157
        /* Set the internal pointer to the search directory as well.  */
158
12
        search_dir_ptr =  &search_dir;
159
    }
160
    else
161
    {
162
163
        /* The current default directory is the root so just set the
164
           search directory pointer to NULL.  */
165
516
        search_dir_ptr =  FX_NULL;
166
    }
167
168
    /* Calculate the directory size.  */
169
644
    if (search_dir_ptr)
170
    {
171
172
        /* Ensure that the search directory's last search cluster is cleared.  */
173
108
        search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
174
175
        /* Calculate the directory size by counting the allocated
176
           clusters for it.  */
177
108
        i =        0;
178
108
        cluster =  search_dir_ptr -> fx_dir_entry_cluster;
179

9327
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
180
        {
181
182
            /* Increment the cluster count.  */
183
9222
            i++;
184
185
            /* Read the next FAT entry.  */
186
9222
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
187
188
            /* Check the return status.  */
189
9222
            if (status != FX_SUCCESS)
190
            {
191
192
                /* Return the bad status.  */
193
1
                return(status);
194
            }
195
196
            /* Check for error situation.  */
197

9221
            if ((cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
198
            {
199
200
                /* Return the bad status.  */
201
2
                return(FX_FAT_READ_ERROR);
202
            }
203
204
9219
            cluster = next_cluster;
205
        }
206
207
        /* Now we can calculate the directory size.  */
208
105
        directory_size =  (((ULONG)media_ptr -> fx_media_bytes_per_sector) *
209
105
                           ((ULONG)media_ptr -> fx_media_sectors_per_cluster) * i) /
210
                           (ULONG)FX_DIR_ENTRY_SIZE;
211
212
        /* Also save this in the directory entry so we don't have to
213
           calculate it later.  */
214
105
        search_dir_ptr -> fx_dir_entry_file_size =  directory_size;
215
    }
216
    else
217
    {
218
219
        /* Directory size is the number of entries in the root directory.  */
220
536
        directory_size =  (ULONG)media_ptr -> fx_media_root_directory_entries;
221
    }
222
223
    /* Determine if we are searching for a short file name or a unicode file name.  */
224
641
    if (short_name[0] == 0)
225
    {
226
227
        /* If the unicode name fit into short name length, covert the Unicode to ASCII if possible.  */
228
629
        if (local_unicode_name_length <= 13)
229
        {
230
1621
            for (j = 0; j < local_unicode_name_length; j++)
231
            {
232

1312
                if ((unicode_name[j * 2] <= 0x7F) && (unicode_name[j * 2 + 1] == 0))
233
                {
234
235
1139
                    unicode_to_short_name[j] = (CHAR)unicode_name[j * 2];
236

1139
                    if ((unicode_to_short_name[j] >= 'a') && (unicode_to_short_name[j] <= 'z'))
237
                    {
238
239
                        /* Lower case, convert to upper case!  */
240
601
                        unicode_to_short_name[j] =  (CHAR)((INT)unicode_to_short_name[j] - 0x20);
241
                    }
242
                }
243
                else
244
                {
245
173
                    unicode_to_short_name[0] = 0;
246
173
                    break;
247
                }
248
            }
249
        }
250
        else
251
        {
252
147
            unicode_to_short_name[0] = 0;
253
        }
254
    }
255
    else
256
    {
257
12
        unicode_to_short_name[0] = 0;
258
    }
259
260
    /* Loop through entries in the directory.  Yes, this is a
261
       linear search!  */
262
641
    i =      0;
263
    do
264
    {
265
266
        /* Read an entry from the directory.  */
267
8551
        status =  _fx_unicode_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr, &_fx_unicode_search_name[0], &unicode_search_length);
268
8551
        i++;
269
270
        /* Check for error status.  */
271
8551
        if (status != FX_SUCCESS)
272
        {
273
14
            return(status);
274
        }
275
276
        /* Determine if this is an empty entry.  */
277

8537
        if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))
278
        {
279
277
            continue;
280
        }
281
282
        /* Determine if this is the last directory entry.  */
283
8260
        if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
284
        {
285
356
            break;
286
        }
287
288
        /* Determine if there is a short name to match.  */
289
7904
        if (unicode_to_short_name[0])
290
        {
291
292
            /* Get the short name pointer.  */
293
2483
            if (entry_ptr -> fx_dir_entry_short_name[0])
294
            {
295
2280
                short_name_ptr =  entry_ptr -> fx_dir_entry_short_name;
296
            }
297
            else
298
            {
299
203
                short_name_ptr =  entry_ptr -> fx_dir_entry_name;
300
            }
301
302
2596
            for (j = 0; j < local_unicode_name_length; j++)
303
            {
304
305
                /* Compare characters.  */
306
2593
                if (short_name_ptr[j] != unicode_to_short_name[j])
307
                {
308
2480
                    break;
309
                }
310
            }
311
2483
            if (j == local_unicode_name_length)
312
            {
313
314
                /* Only the 1st 13 bytes or the buffer length is copied, whichever is smaller.  */
315
3
                if (short_name_buffer_length > 13)
316
                {
317
1
                    short_name_buffer_length = 13;
318
                }
319
320
                /* The names match, copy the short name into the destination.  */
321
42
                for (j = 0; j < short_name_buffer_length; j++)
322
                {
323
39
                    short_name[j] = (UCHAR)short_name_ptr[j];
324
                }
325
326
                /* Return success to caller.  */
327
3
                return(FX_SUCCESS);
328
            }
329
        }
330
331
        /* Determine if this is not a unicode name.  */
332
7901
        if (unicode_search_length == 0)
333
        {
334
250
            continue;
335
        }
336
337
        /* Determine if we are searching for a short file name or a unicode file name.  */
338
7651
        if (short_name[0])
339
        {
340
341
            /* We have a short name and need a unicode name.  Compare the short name against the short name in
342
               the directory entry for a match.  */
343
36
            found =  FX_TRUE;
344
121
            for (j = 0; j < 12; j++)
345
            {
346
347
                /* Compare characters...  */
348
119
                if (entry_ptr -> fx_dir_entry_short_name[0])
349
                {
350
351
                    /* Yes, the return name is in the short name field... compare against it!  */
352
107
                    if (short_name[j] != (UCHAR)entry_ptr -> fx_dir_entry_short_name[j])
353
                    {
354
355
20
                        found = FX_FALSE;
356
20
                        break;
357
                    }
358
                }
359
                else
360
                {
361
362
                    /* No, the return name is in the name field... compare against it!  */
363
12
                    if (short_name[j] != (UCHAR)entry_ptr -> fx_dir_entry_name[j])
364
                    {
365
366
6
                        found = FX_FALSE;
367
6
                        break;
368
                    }
369
                }
370
371
                /* Are we done?  */
372
93
                if (short_name[j] == (UCHAR)FX_NULL)
373
                {
374
8
                    break;
375
                }
376
            }
377
378
            /* One final compare to see if we have a match.  */
379

36
            if ((found == FX_FALSE) || ((j == 12) && (short_name[12] != 0)))
380
            {
381
27
                continue;
382
            }
383
384
            /* A match was found so copy the unicode name and length and return.  */
385
            /* Copy the length.  */
386
9
            *unicode_name_length =  unicode_search_length;
387
388
            /* Check if the name fit in the buffer.  */
389
9
            if (unicode_name_buffer_length < (unicode_search_length + 1) * 2)
390
            {
391
1
                unicode_search_length = (unicode_name_buffer_length - 2) / 2;
392
            }
393
394
            /* Copy the unicode name.   */
395
107
            for (j = 0; j < unicode_search_length * 2; j++)
396
            {
397
398
                /* Copy one unicode character to the destination...  */
399
98
                unicode_name[j] =  _fx_unicode_search_name[j];
400
            }
401
402
            /* Make sure there is a NULL in the destination.  */
403
9
            unicode_name[j] =    (UCHAR)0;
404
9
            unicode_name[j + 1] =  (UCHAR)0;
405
406
407
408
            /* Return successful completion.  */
409
9
            return(FX_SUCCESS);
410
        }
411
        else
412
        {
413
414
            /* Determine if this is the correct unicode name.  */
415
7615
            if (unicode_search_length != local_unicode_name_length)
416
            {
417
1551
                continue;
418
            }
419
420
            /* Compare the unicode search name with the requested unicode name.  */
421
6837
            for (j = 0; j < (local_unicode_name_length * 2); j = j + 2)
422
            {
423
424
                /* Compare bytes of each unicode name.  */
425
6682
                if (unicode_name[j] != _fx_unicode_search_name[j])
426
                {
427
428
                    /* Not match, Check if the character is in ASCII range.  */
429

5873
                    if ((_fx_unicode_search_name[j + 1] == 0) && (unicode_name[j + 1] == 0))
430
                    {
431
432
                        /* Check if it is case mismatch.  */
433

5644
                        if ((unicode_name[j]) >= 'a' && (unicode_name[j] <= 'z'))
434
                        {
435
1152
                            if ((unicode_name[j] - 0x20) == _fx_unicode_search_name[j])
436
                            {
437
1
                                continue;
438
                            }
439
                        }
440

5643
                        if ((_fx_unicode_search_name[j]) >= 'a' && (_fx_unicode_search_name[j] <= 'z'))
441
                        {
442
1311
                            if ((_fx_unicode_search_name[j] - 0x20) == unicode_name[j])
443
                            {
444
1
                                continue;
445
                            }
446
                        }
447
                    }
448
449
5871
                    break;
450
                }
451
452
                /* Compare the next byte.  */
453
809
                if (unicode_name[j + 1] != _fx_unicode_search_name[j + 1])
454
                {
455
38
                    break;
456
                }
457
            }
458
459
            /* Determine if the names do not match.  */
460
6064
            if (j != (local_unicode_name_length * 2))
461
            {
462
5909
                continue;
463
            }
464
465
            /* Otherwise, the names match, copy the short name into the destination.  */
466
            /* Only the 1st 13 bytes or the buffer length is copied, whichever is smaller.  */
467
155
            if (short_name_buffer_length > 13)
468
            {
469
1
                short_name_buffer_length = 13;
470
            }
471
2170
            for (j = 0; j < short_name_buffer_length; j++)
472
            {
473
474
                /* Copy a character.  */
475
2015
                if (entry_ptr -> fx_dir_entry_short_name[0])
476
                {
477
1521
                    short_name[j] =  (UCHAR)entry_ptr -> fx_dir_entry_short_name[j];
478
                }
479
                else
480
                {
481
494
                    short_name[j] =  (UCHAR)entry_ptr -> fx_dir_entry_name[j];
482
                }
483
            }
484
485
            /* Return success to caller.  */
486
155
            return(FX_SUCCESS);
487
        }
488
8014
    } while (i < directory_size);
489
490
    /* Return not found.  */
491
460
    return(FX_NOT_FOUND);
492
}
493