GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_unicode_directory_search.c Lines: 111 111 100.0 %
Date: 2024-01-10 21:53:23 Branches: 112 112 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
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
/*  RELEASE HISTORY                                                       */
97
/*                                                                        */
98
/*    DATE              NAME                      DESCRIPTION             */
99
/*                                                                        */
100
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
101
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
102
/*                                            resulting in version 6.1    */
103
/*                                                                        */
104
/**************************************************************************/
105
644
UINT  _fx_unicode_directory_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr,
106
                                   UCHAR *short_name, ULONG short_name_buffer_length,
107
                                   UCHAR *unicode_name, ULONG *unicode_name_length, ULONG unicode_name_buffer_length)
108
{
109
110
ULONG         i, j;
111
UINT          status, found;
112
644
ULONG         cluster, next_cluster = 0;
113
ULONG         directory_size;
114
FX_DIR_ENTRY  search_dir;
115
FX_DIR_ENTRY *search_dir_ptr;
116
ULONG         unicode_search_length;
117
ULONG         local_unicode_name_length;
118
CHAR          unicode_to_short_name[13];
119
CHAR         *short_name_ptr;
120
121
122
    /* Setup temp unicode name length.  */
123
644
    local_unicode_name_length =  *unicode_name_length;
124
125
#ifndef FX_MEDIA_STATISTICS_DISABLE
126
127
    /* Increment the number of directory search requests.  */
128
644
    media_ptr -> fx_media_directory_searches++;
129
#endif
130
131
    /* Set the initial search directory to the current working
132
       directory - if there is one.  */
133
134
    /* First check for a local path pointer stored in the thread control block.  This
135
       is only available in ThreadX Version 4 and above.  */
136
#ifndef FX_NO_LOCAL_PATH
137
644
    if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
138
    {
139
140
        /* Determine if the local directory is not the root directory.  */
141
116
        if (((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory.fx_dir_entry_name[0])
142
        {
143
144
            /* Start at the current working directory of the media.  */
145
96
            search_dir =   ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory;
146
147
            /* Set the internal pointer to the search directory as well.  */
148
96
            search_dir_ptr =  &search_dir;
149
        }
150
        else
151
        {
152
153
            /* We are searching in the root directory.  */
154
20
            search_dir_ptr =  FX_NULL;
155
        }
156
    }
157
    else
158
#endif
159
528
    if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
160
    {
161
162
        /* Start at the current working directory of the media.  */
163
12
        search_dir =  media_ptr -> fx_media_default_path.fx_path_directory;
164
165
        /* Set the internal pointer to the search directory as well.  */
166
12
        search_dir_ptr =  &search_dir;
167
    }
168
    else
169
    {
170
171
        /* The current default directory is the root so just set the
172
           search directory pointer to NULL.  */
173
516
        search_dir_ptr =  FX_NULL;
174
    }
175
176
    /* Calculate the directory size.  */
177
644
    if (search_dir_ptr)
178
    {
179
180
        /* Ensure that the search directory's last search cluster is cleared.  */
181
108
        search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
182
183
        /* Calculate the directory size by counting the allocated
184
           clusters for it.  */
185
108
        i =        0;
186
108
        cluster =  search_dir_ptr -> fx_dir_entry_cluster;
187

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

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

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

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

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

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

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

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

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