GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_unicode_directory_entry_read.c Lines: 200 200 100.0 %
Date: 2026-03-06 18:49:02 Branches: 136 136 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
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _fx_unicode_directory_entry_read                    PORTABLE C      */
38
/*                                                           6.1          */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    William E. Lamie, Microsoft Corporation                             */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function reads a unicode directory entry.                      */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    media_ptr                             Pointer to media              */
50
/*    source_dir                            Pointer to source directory   */
51
/*    entry_ptr                             Entry index in the directory  */
52
/*    destination_ptr                       Destination directory         */
53
/*    unicode_name                          Destination unicode name      */
54
/*    unicode_size                          Destination unicode name size */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    Completion Status                                                   */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
63
/*    _fx_utility_logical_sector_read       Read a logical sector         */
64
/*    _fx_utility_16_unsigned_read          Read a 2-byte value           */
65
/*    _fx_utility_32_unsigned_read          Read a 4-byte value           */
66
/*                                                                        */
67
/*  CALLED BY                                                             */
68
/*                                                                        */
69
/*    Unicode Utilities                                                   */
70
/*                                                                        */
71
/**************************************************************************/
72
8554
UINT  _fx_unicode_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
73
                                       ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr,
74
                                       UCHAR *unicode_name, ULONG *unicode_size)
75
{
76
77
UINT   i, j, k, card, dotflag, get_short_name;
78
UINT   number_of_lfns;
79
UINT   status;
80
8554
ULONG  cluster, next_cluster = 0;
81
UINT   relative_cluster;
82
UINT   relative_sector;
83
ULONG  logical_sector;
84
ULONG  byte_offset;
85
ULONG  bytes_per_cluster;
86
UCHAR *read_ptr;
87
CHAR  *short_name_ptr;
88
8554
ULONG  entry = *entry_ptr;
89
UINT   u;
90
91
92
#ifndef FX_MEDIA_STATISTICS_DISABLE
93
94
    /* Increment the number of directory entry read requests.  */
95
8554
    media_ptr -> fx_media_directory_entry_reads++;
96
#endif
97
98
    /* Calculate the byte offset of this directory entry.  */
99
8554
    byte_offset =  entry * FX_DIR_ENTRY_SIZE;
100
101
    /* Determine if a sub-directory or FAT32 root directory is specified.  */
102

8554
    if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
103
    {
104
105
        /* Yes, a sub-directory is present.  */
106
107
        /* Calculate the number of bytes per cluster.  */
108
5941
        bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
109
5941
            ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
110
111
        /* Check for invalid value.  */
112
5941
        if (bytes_per_cluster == 0)
113
        {
114
115
            /* Invalid media, return error.  */
116
1
            return(FX_MEDIA_INVALID);
117
        }
118
119
        /* Now determine the relative cluster in the sub-directory file.  */
120
5940
        relative_cluster =   (UINT)(byte_offset / bytes_per_cluster);
121
122
        /* Calculate the byte offset within the cluster.  */
123
5940
        byte_offset =  byte_offset % bytes_per_cluster;
124
125
        /* Now figure out the relative sector within the cluster.  */
126
5940
        relative_sector =    (UINT)(byte_offset / ((ULONG)media_ptr -> fx_media_bytes_per_sector));
127
128
        /* Read the directory sector into the internal memory buffer.  */
129
130
        /* Determine if there is a sub-directory.  */
131
5940
        if (source_dir)
132
        {
133
134
            /* Determine if this source directory has valid information from the previous call.  */
135
3207
            if ((source_dir -> fx_dir_entry_last_search_cluster) &&
136
3102
                (source_dir -> fx_dir_entry_last_search_relative_cluster <= relative_cluster) &&
137
3101
                (source_dir -> fx_dir_entry_last_search_log_sector == source_dir -> fx_dir_entry_log_sector) &&
138
3100
                (source_dir -> fx_dir_entry_last_search_byte_offset == source_dir -> fx_dir_entry_byte_offset))
139
            {
140
141
                /* Use the previous information to start the search.  */
142
3099
                cluster =  source_dir -> fx_dir_entry_last_search_cluster;
143
144
                /* Setup the relative cluster index to the saved relative cluster.  */
145
3099
                i =  source_dir -> fx_dir_entry_last_search_relative_cluster;
146
147
                /* Clear the search cluster.  It will be updated prior to successful return.  */
148
3099
                source_dir -> fx_dir_entry_last_search_cluster =  0;
149
            }
150
            else
151
            {
152
153
                /* Nothing from the previous directory read, just setup the starting cluster to the
154
                   beginning of the sub-directory.  */
155
108
                cluster =  source_dir -> fx_dir_entry_cluster;
156
157
                /* Setup the relative cluster index to zero.  */
158
108
                i =  0;
159
            }
160
        }
161
        else
162
        {
163
164
            /* No, setup the starting cluster to the FAT32 root cluster.  */
165
2733
            cluster =  media_ptr -> fx_media_root_cluster_32;
166
167
            /* Setup the relative cluster index to zero.  */
168
2733
            i =  0;
169
        }
170
171
        /* Loop to position to the appropriate cluster.  */
172
6668
        while (i < relative_cluster)
173
        {
174
175
            /* Check the value of the new cluster - it must be a valid cluster number
176
               or something is really wrong!  */
177

731
            if ((cluster < FX_FAT_ENTRY_START) || (cluster > media_ptr -> fx_media_fat_reserved))
178
            {
179
180
                /* Send error message back to caller.  */
181
2
                return(FX_FILE_CORRUPT);
182
            }
183
184
            /* Read the next cluster.  */
185
729
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
186
187
            /* There is a potential for loop, but hardly anything can be done */
188
189
            /* Check for I/O error.  */
190
729
            if (status != FX_SUCCESS)
191
            {
192
193
                /* Return error code.  */
194
1
                return(status);
195
            }
196
197
            /* Setup the actual cluster.  */
198
728
            cluster = next_cluster;
199
200
            /* Increment the relative cluster number.  */
201
728
            i++;
202
        }
203
204
        /* At this point, the directory data sector needs to be read.  */
205
5937
        logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
206
5937
            (((ULONG)cluster - FX_FAT_ENTRY_START) *
207
5937
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
208
            relative_sector;
209
210
        /* Read the logical directory sector.  */
211
5937
        status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
212
5937
                                                  media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
213
214
        /* Determine if an error occurred.  */
215
5937
        if (status != FX_SUCCESS)
216
        {
217
218
            /* Return error code.  */
219
1
            return(status);
220
        }
221
222
        /* Calculate the byte offset within this sector.  */
223
5936
        byte_offset =  byte_offset % media_ptr -> fx_media_bytes_per_sector;
224
    }
225
    else
226
    {
227
228
        /* Read the entry from the root directory.  */
229
230
        /* Determine which sector the requested root directory entry is in.  */
231
2613
        logical_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
232
2613
            (ULONG)media_ptr -> fx_media_root_sector_start;
233
234
        /* Read the logical directory sector.  */
235
2613
        status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
236
2613
                                                  media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
237
238
        /* Determine if an error occurred.  */
239
2613
        if (status != FX_SUCCESS)
240
        {
241
242
            /* Return error code.  */
243
1
            return(status);
244
        }
245
246
        /* Set the cluster and relative variables (not used in this case) to avoid any compiler
247
           warnings.  */
248
2612
        relative_cluster =  relative_sector =  cluster =  0;
249
250
        /* Now calculate the byte offset into this sector.  */
251
2612
        byte_offset =  byte_offset -
252
2612
            ((logical_sector - (ULONG)media_ptr -> fx_media_root_sector_start) *
253
2612
             media_ptr -> fx_media_bytes_per_sector);
254
    }
255
256
    /* Setup a pointer into the buffer.  */
257
8548
    read_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
258
259
    /* Save the logical sector and byte offset in the returned directory entry.  */
260
8548
    destination_ptr -> fx_dir_entry_log_sector =       logical_sector;
261
8548
    destination_ptr -> fx_dir_entry_byte_offset =      byte_offset;
262
263
    /* Clear the short file name information.  */
264
8548
    destination_ptr -> fx_dir_entry_long_name_shorted =  0;
265
8548
    destination_ptr -> fx_dir_entry_short_name[0]     =  0;
266
267
    /* Setup short name pointer.  */
268
8548
    short_name_ptr =  destination_ptr -> fx_dir_entry_name;
269
270
    /* Initialize the unicode index.  */
271
8548
    u =  0;
272
273
    /* Check if long file name exists.  */
274
8548
    get_short_name =  0;
275

8548
    if ((*(read_ptr + 11) == (UCHAR)FX_LONG_NAME) && (*read_ptr != (UCHAR)FX_DIR_ENTRY_FREE))
276
    {
277
278
        /* Collate the long name. */
279
280
281
        /* Save the number of LFN entries.  */
282
7679
        number_of_lfns =  (UINT)(*read_ptr & (UCHAR)0x1f);
283
284
7679
        if(number_of_lfns == 0)
285
        {
286
            /* Number of LFN cannot is 1-based.  Therefore it cannot be zero. */
287
1
            return(FX_FILE_CORRUPT);
288
        }
289
        else
290
        {
291
            /* Pickup the file name length.  */
292
7678
            i = (number_of_lfns - 1) * FX_LONG_NAME_ENTRY_LEN;
293
        }
294
295
        /* Check the file name size.  */
296
7678
        if (i >= (FX_MAX_LONG_NAME_LEN - 1))
297
        {
298
299
            /* Name is too big, shorten it.  */
300
15
            get_short_name = 1;
301
15
            destination_ptr -> fx_dir_entry_long_name_shorted =  (UINT)(*read_ptr & (UCHAR)0x1f);
302
        }
303
        else
304
        {
305
306
            /* Size of name is fine, save pointer to short file name.  */
307
7663
            short_name_ptr = destination_ptr -> fx_dir_entry_short_name;
308
309
            /* Loop to make sure the long file name is NULL terminated.  */
310
7663
            j = i + FX_LONG_NAME_ENTRY_LEN + 1;
311
            do
312
            {
313
                /* Place a NULL in the long name.  */
314
107212
                destination_ptr -> fx_dir_entry_name[i] =  0;
315
316
                /* Position to the next entry.  */
317
107212
                i++;
318

107212
            } while ((i < j) && (i < FX_MAX_LONG_NAME_LEN));
319
        }
320
321
        /* Loop to pickup the rest of the name.  */
322
        do
323
        {
324
325
            /* Get the lower 5 bit containing the cardinality.  */
326
11515
            card = (*read_ptr) & 0x1f;
327
328
11515
            if(card == 0)
329
            {
330
331
                /* Number of LFN starts from one.  Therefore it cannot be zero. */
332
2
                return(FX_FILE_CORRUPT);
333
            }
334
            else
335
            {
336
11513
                card = card - 1;
337
            }
338
            /* For simplicity no checksum or cardinality checking is done */
339

11513
            if ((get_short_name == 0) || (u))
340
            {
341
342
                /* Loop to pickup name.  */
343
190811
                for (i = 1, j = 0, k = 0; i < FX_DIR_ENTRY_SIZE; i += 2)
344
                {
345
346

179596
                    if ((i == 11) || (i == 26))
347
                    {
348
22444
                        continue;
349
                    }
350
351
                    /* i = 12, 27 is not generated due to +=2 */
352
157152
                    if (i == 13)
353
                    {
354
11229
                        i = 12;
355
11229
                        continue; /* this time next unicode is byte offset 14*/
356
                    }
357
358
                    /* Determine if there is an actual unicode character present.  */
359
145923
                    if (read_ptr[i + 1])
360
                    {
361
362
                        /* Extended byte is non-zero, make sure both bytes of the unicode entry are not
363
                           all ones, since this is a normal case.  */
364

74639
                        if ((read_ptr[i + 1] != (UCHAR)0xFF) || (read_ptr[i] != (UCHAR)0xFF))
365
                        {
366
367
                            /* Name is an actual unicode name, shorten it.  */
368
842
                            get_short_name = 1;
369
370
                            /* Save the number of directory entries the LFN has.  This will be
371
                               used later when updating the 8.3 portion of the LFN.  */
372
842
                            destination_ptr -> fx_dir_entry_long_name_shorted =  number_of_lfns;
373
374
                            /* Setup short name pointer.  */
375
842
                            short_name_ptr =  destination_ptr -> fx_dir_entry_name;
376
                        }
377
                    }
378
379
                    /* Determine if the character is NULL.  */
380

145923
                    if (((read_ptr[i] == FX_NULL) && (read_ptr[i + 1] == FX_NULL)) ||
381

138279
                        ((read_ptr[i] == (UCHAR)0xFF) && (read_ptr[i + 1] == (UCHAR)0xFF)))
382
                    {
383
81441
                        continue;
384
                    }
385
386
                    /* Determine if the name is too big.  */
387
64482
                    if ((card * 13 + j) >= (FX_MAX_LONG_NAME_LEN - 1))
388
                    {
389
390
                        /* Name is actually too big, shorten it.  */
391
16
                        get_short_name =  1;
392
393
                        /* Save the number of directory entries the LFN has.  This will be
394
                           used later when updating the 8.3 portion of the LFN.  */
395
16
                        destination_ptr -> fx_dir_entry_long_name_shorted =  number_of_lfns;
396
397
                        /* Also reposition the short name pointer.  */
398
16
                        short_name_ptr =  destination_ptr -> fx_dir_entry_name;
399
400
16
                        break;
401
                    }
402
403
                    /* Each entry contains 13 unicode and first byte ASCII, second byte is extended. */
404
64466
                    if (get_short_name == 0)
405
                    {
406
59031
                        destination_ptr -> fx_dir_entry_name[13 * card + j] = (CHAR)read_ptr[i];
407
                    }
408
409
                    /* Save the potential unicode characters.  */
410
64466
                    unicode_name[k + 26 * card + j] =    read_ptr[i];
411
64466
                    unicode_name[k + 26 * card + j + 1] =  read_ptr[i + 1];
412
64466
                    k++;
413
64466
                    u++;
414
415
64466
                    j++;
416
                }
417
            }
418
419
            /* Determine if a new sector needs to be read.  */
420
11513
            if (byte_offset + FX_DIR_ENTRY_SIZE >= media_ptr -> fx_media_bytes_per_sector)
421
            {
422
423
                /* Determine if a sub-directory or FAT32 root directory is specified.  */
424

2350
                if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
425
                {
426
427
                    /* Determine the next sector of the directory entry.  */
428
1777
                    if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
429
                    {
430
431
                        /* More sectors in this cluster.  */
432
433
                        /* Simply increment the logical sector.  */
434
313
                        logical_sector++;
435
436
                        /* Increment the relative sector.  */
437
313
                        relative_sector++;
438
                    }
439
                    else
440
                    {
441
442
                        /* We need to move to the next cluster.  */
443
444
                        /* Pickup the next cluster.  */
445
1464
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
446
447
                        /* Check for I/O error.  */
448
1464
                        if (status != FX_SUCCESS)
449
                        {
450
451
                            /* Return error code.  */
452
1
                            return(status);
453
                        }
454
455
                        /* Copy next cluster to the current cluster.  */
456
1463
                        cluster =  next_cluster;
457
458
                        /* Check the value of the new cluster - it must be a valid cluster number
459
                           or something is really wrong!  */
460

1463
                        if ((cluster < FX_FAT_ENTRY_START) || (cluster > media_ptr -> fx_media_fat_reserved))
461
                        {
462
463
                            /* Send error message back to caller.  */
464
2
                            return(FX_FILE_CORRUPT);
465
                        }
466
467
                        /* Now increment the relative cluster.  */
468
1461
                        relative_cluster++;
469
470
                        /* Setup the relative sector (this is zero for subsequent cluster.  */
471
1461
                        relative_sector =  0;
472
473
                        /* Calculate the next logical sector.  */
474
1461
                        logical_sector =   ((ULONG)media_ptr -> fx_media_data_sector_start) +
475
1461
                            (((ULONG)cluster - FX_FAT_ENTRY_START) *
476
1461
                             ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
477
                    }
478
                }
479
                else
480
                {
481
482
                    /* Non-FAT 32 root directory.  */
483
484
                    /* Advance to the next sector.  */
485
573
                    logical_sector++;
486
487
                    /* Determine if the logical sector is valid.  */
488
573
                    if (logical_sector >= (ULONG)(media_ptr -> fx_media_root_sector_start + media_ptr -> fx_media_root_sectors))
489
                    {
490
491
                        /* Trying to read past root directory - send error message back to caller.  */
492
1
                        return(FX_FILE_CORRUPT);
493
                    }
494
                }
495
496
                /* Read the new sector.  */
497
2346
                status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
498
2346
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
499
500
                /* Check I/O status.  */
501
2346
                if (status != FX_SUCCESS)
502
                {
503
1
                    return(status);
504
                }
505
506
                /* Set the byte offset to 0 for new sector.  */
507
2345
                byte_offset = 0;
508
            }
509
            else
510
            {
511
512
                /* Calculate the new byte offset.  */
513
9163
                byte_offset += FX_DIR_ENTRY_SIZE;
514
            }
515
516
            /* Calculate the next read pointer.  */
517
11508
            read_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
518
519
            /* Move to the next entry.  */
520
11508
            entry++;
521
11508
        } while (card > 0);
522
523
        /* Set flag indicating long file name is present.  */
524
7671
        destination_ptr -> fx_dir_entry_long_name_present = 1;
525
    }
526
    else
527
    {
528
        /* No long file name is present.  */
529
869
        get_short_name = 1;
530
    }
531
532
    /* Determine if we need to clear the long name flag.  */
533
8540
    if (get_short_name == 1)
534
    {
535
536
        /* Clear the long name flag.  */
537
1322
        destination_ptr -> fx_dir_entry_long_name_present =  0;
538
    }
539
540
    /* Store the unicode name size.  */
541
8540
    *unicode_size =  u;
542
543
    /* Pickup the short file name.  */
544
8540
    short_name_ptr[0] =  0;
545
8540
    dotflag =  0;
546
97582
    for (i = 0, j = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
547
    {
548
549
        /* Check for a NULL.  */
550
89506
        if ((CHAR)read_ptr[i] == 0)
551
        {
552
464
            break;
553
        }
554
555
        /* Check for a dot.  This happens for the first two directory entries, no
556
           extra dot is needed.  */
557
89042
        if ((CHAR)read_ptr[i] == '.')
558
        {
559
316
            dotflag =  2;
560
        }
561
562
        /* Check for a space.  */
563
89042
        if ((CHAR)read_ptr[i] == ' ')
564
        {
565
            /* Put a dot if a character comes after space.  */
566
46877
            if (dotflag == 0)
567
            {
568
7847
                dotflag =  1;
569
            }
570
46877
            continue;
571
        }
572
573
        /* Check for the main short file name size.  */
574
42165
        if (i == FX_DIR_NAME_SIZE)
575
        {
576
            /* Check to see if we need to insert a dot.  */
577
20
            if (dotflag == 0)
578
            {
579
19
                dotflag =  1;
580
            }
581
        }
582
583
        /* Check to see if we need to add a dot.  */
584
42165
        if (dotflag == 1)
585
        {
586
            /* Add dot to short file name.  */
587
19
            short_name_ptr[j++] =  '.';
588
19
            dotflag =  2;    /* no more dot for spaces */
589
        }
590
591
        /* Copy a character.  */
592
42165
        short_name_ptr[j] =  (CHAR)read_ptr[i];
593
594
        /* Increment size.  */
595
42165
        j++;
596
    }
597
598
    /* Determine if a long file name is present and its associated short file
599
       name is actually free.  */
600

8540
    if ((destination_ptr -> fx_dir_entry_long_name_present) && (((UCHAR)short_name_ptr[0]) == (UCHAR)FX_DIR_ENTRY_FREE))
601
    {
602
603
        /* Yes, the short file name is really free even though long file name entries directly precede it.
604
           In this case, simply place the free directory marker at the front of the long file name.  */
605
1
        destination_ptr -> fx_dir_entry_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
606
1
        short_name_ptr[0] =  (CHAR)0;
607
    }
608
609
    /* Determine if the short name pointer is NULL while the read pointer is
610
       non-NULL.  */
611

8540
    if ((short_name_ptr[0] == 0) && (read_ptr[0] == ' '))
612
    {
613
614
        /* This condition can occur with an all blank volume name.  Simply
615
           copy the volume name to the short name in this case.  */
616
48
        for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
617
        {
618
619
            /* Copy a byte of the volume name.  */
620
44
            short_name_ptr[j] =  (CHAR)read_ptr[j];
621
        }
622
    }
623
624
    /* Set end of string to null.  */
625
8540
    short_name_ptr[j] = 0;
626
627
    /* Load up the destination directory entry.  */
628
8540
    read_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
629
630
    /* Copy the attribute into the destination.  */
631
8540
    destination_ptr -> fx_dir_entry_attributes =  *read_ptr++;
632
633
    /* Pickup the reserved byte.  */
634
8540
    destination_ptr -> fx_dir_entry_reserved =  *read_ptr++;
635
636
    /* Check for an undocumented NT file name feature for optimizing the storage
637
       of all lower case file names that otherwise are valid 8.3 file names. The
638
       following reserved bit definitions are present:
639
640
         BIT3 - set if 8.3 is all in lower case and no extended filename.
641
         BIT4 - set for file, clear for directory entry if no extended filename.
642
643
       This is true for all NT systems. Prior to NT follows MSDOS FAT documentation and
644
       is set to 0x00, all bits cleared. Therefore if BIT3 is set force lowercase.  */
645

8540
    if ((get_short_name) && (destination_ptr -> fx_dir_entry_reserved & 0x08))
646
    {
647
648
        /* Microsoft undocumented NT file name feature... convert short name to lower
649
           case.  */
650

174
        for (j = 0; j <= (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE) && (short_name_ptr[j] != 0x00); j++)
651
        {
652
653
            /* Determine if an upper case character is present.  */
654

156
            if ((short_name_ptr[j] >= 'A') && (short_name_ptr[j] <= 'Z'))
655
            {
656
657
                /* Yes, an upper case character is present. Force it to lower case.  */
658
72
                short_name_ptr[j] =  (CHAR)((INT)short_name_ptr[j] + 32);
659
            }
660
        }
661
    }
662
663
    /* Pickup the created time in milliseconds.  */
664
8540
    destination_ptr -> fx_dir_entry_created_time_ms =  *read_ptr++;
665
666
    /* Pickup the created time.  */
667
8540
    destination_ptr -> fx_dir_entry_created_time =  _fx_utility_16_unsigned_read(read_ptr);
668
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
669
670
    /* Pickup the created date.  */
671
8540
    destination_ptr -> fx_dir_entry_created_date =  _fx_utility_16_unsigned_read(read_ptr);
672
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
673
674
    /* Pickup the last accessed date.  */
675
8540
    destination_ptr -> fx_dir_entry_last_accessed_date =  _fx_utility_16_unsigned_read(read_ptr);
676
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
677
678
    /* read the upper 2 bytes of starting cluster - required only for 32 bit FAT */
679
8540
    if (media_ptr -> fx_media_32_bit_FAT)
680
    {
681
682
        /* FAT32 only.  */
683
5812
        destination_ptr -> fx_dir_entry_cluster =  _fx_utility_16_unsigned_read(read_ptr);
684
5812
        destination_ptr -> fx_dir_entry_cluster <<= 16;
685
    }
686
    else
687
    {
688
        /* Not required for non FAT32.  */
689
2728
        destination_ptr -> fx_dir_entry_cluster =  0;
690
    }
691
692
    /* Advance the read pointer.  */
693
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
694
695
    /* Copy the time into the destination.  */
696
8540
    destination_ptr -> fx_dir_entry_time =  _fx_utility_16_unsigned_read(read_ptr);
697
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
698
699
    /* Copy the date into the destination.  */
700
8540
    destination_ptr -> fx_dir_entry_date =  _fx_utility_16_unsigned_read(read_ptr);
701
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
702
703
    /* Copy the starting cluster into the destination.  */
704
8540
    destination_ptr -> fx_dir_entry_cluster +=  _fx_utility_16_unsigned_read(read_ptr);
705
8540
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
706
707
    /* Copy the file size into the destination.  */
708
8540
    destination_ptr -> fx_dir_entry_file_size =  _fx_utility_32_unsigned_read(read_ptr);
709
710
    /* Clear the destination search specific fields.  */
711
8540
    destination_ptr -> fx_dir_entry_last_search_cluster =           0;
712
8540
    destination_ptr -> fx_dir_entry_last_search_relative_cluster =  0;
713
8540
    destination_ptr -> fx_dir_entry_last_search_log_sector =        0;
714
8540
    destination_ptr -> fx_dir_entry_last_search_byte_offset =       0;
715
716
    /* Remember the entry number.  */
717
8540
    destination_ptr -> fx_dir_entry_number =  entry;
718
719
    /* Return entry number.  */
720
8540
    *entry_ptr =  entry;
721
722
    /* Determine if we should remember the last cluster and relative cluster.  */
723
8540
    if (source_dir)
724
    {
725
726
        /* Yes, remember the last cluster and relative cluster for a subsequent call
727
           to read a directory entry.  */
728
3203
        source_dir -> fx_dir_entry_last_search_cluster =           cluster;
729
3203
        source_dir -> fx_dir_entry_last_search_relative_cluster =  relative_cluster;
730
731
        /* Also remember several other items that are unique to the directory... just to verify that the
732
           search information can be used.  */
733
3203
        source_dir -> fx_dir_entry_last_search_log_sector =        source_dir -> fx_dir_entry_log_sector;
734
3203
        source_dir -> fx_dir_entry_last_search_byte_offset =       source_dir -> fx_dir_entry_byte_offset;
735
    }
736
737
    /* Return success to the caller.  */
738
8540
    return(FX_SUCCESS);
739
}
740