GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_unicode_directory_search.c Lines: 111 111 100.0 %
Date: 2024-03-11 05:15:45 Branches: 112 112 100.0 %

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

9327
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
187
        {
188
189
            /* Increment the cluster count.  */
190
9222
            i++;
191
192
            /* Read the next FAT entry.  */
193
9222
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
194
195
            /* Check the return status.  */
196
9222
            if (status != FX_SUCCESS)
197
            {
198
199
                /* Return the bad status.  */
200
1
                return(status);
201
            }
202
203
            /* Check for error situation.  */
204

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

1312
                if ((unicode_name[j * 2] <= 0x7F) && (unicode_name[j * 2 + 1] == 0))
240
                {
241
242
1139
                    unicode_to_short_name[j] = (CHAR)unicode_name[j * 2];
243

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

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

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

5873
                    if ((_fx_unicode_search_name[j + 1] == 0) && (unicode_name[j + 1] == 0))
437
                    {
438
439
                        /* Check if it is case mismatch.  */
440

5644
                        if ((unicode_name[j]) >= 'a' && (unicode_name[j] <= 'z'))
441
                        {
442
1152
                            if ((unicode_name[j] - 0x20) == _fx_unicode_search_name[j])
443
                            {
444
1
                                continue;
445
                            }
446
                        }
447

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