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

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

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

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

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

11513
            if ((get_short_name == 0) || (u))
347
            {
348
349
                /* Loop to pickup name.  */
350
190811
                for (i = 1, j = 0, k = 0; i < FX_DIR_ENTRY_SIZE; i += 2)
351
                {
352
353

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

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

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

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

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

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

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

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

8540
    if ((get_short_name) && (destination_ptr -> fx_dir_entry_reserved & 0x08))
653
    {
654
655
        /* Microsoft undocumented NT file name feature... convert short name to lower
656
           case.  */
657

174
        for (j = 0; j <= (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE) && (short_name_ptr[j] != 0x00); j++)
658
        {
659
660
            /* Determine if an upper case character is present.  */
661

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