GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_entry_read.c Lines: 188 188 100.0 %
Date: 2024-03-11 05:15:45 Branches: 128 128 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
/**   Directory                                                           */
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_system.h"
29
#include "fx_directory.h"
30
#include "fx_utility.h"
31
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _fx_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 the supplied directory entry from the supplied  */
46
/*    source directory.  If the supplied directory entry is NULL, then    */
47
/*    the root directory is assumed.                                      */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    media_ptr                             Media control block pointer   */
52
/*    source_dir                            Source directory entry        */
53
/*    entry_ptr                             Directory entry number        */
54
/*    destination_ptr                       Pointer to destination for    */
55
/*                                            the directory entry         */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    return status                                                       */
60
/*    *entry_ptr should point to the 8:3 entry if it is a long name       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
65
/*    _fx_utility_logical_sector_read       Read directory sector         */
66
/*    _fx_utility_16_unsigned_read          Read a UINT from memory       */
67
/*    _fx_utility_32_unsigned_read          Read a ULONG from memory      */
68
/*                                                                        */
69
/*  CALLED BY                                                             */
70
/*                                                                        */
71
/*    FileX System Functions                                              */
72
/*                                                                        */
73
/*  RELEASE HISTORY                                                       */
74
/*                                                                        */
75
/*    DATE              NAME                      DESCRIPTION             */
76
/*                                                                        */
77
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
78
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
79
/*                                            resulting in version 6.1    */
80
/*                                                                        */
81
/**************************************************************************/
82
2418163
UINT  _fx_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
83
                               ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr)
84
{
85
86
UINT   i, j, card, dotflag, get_short_name;
87
UINT   number_of_lfns;
88
UINT   status;
89
2418163
ULONG  cluster, next_cluster = 0;
90
UINT   relative_cluster;
91
UINT   relative_sector;
92
ULONG  logical_sector;
93
ULONG  byte_offset;
94
ULONG  bytes_per_cluster;
95
UCHAR *read_ptr;
96
CHAR  *short_name_ptr;
97
2418163
ULONG  entry = *entry_ptr;
98
99
100
#ifndef FX_MEDIA_STATISTICS_DISABLE
101
102
    /* Increment the number of directory entry read requests.  */
103
2418163
    media_ptr -> fx_media_directory_entry_reads++;
104
#endif
105
106
    /* Extended port-specific processing macro, which is by default defined to white space.  */
107

2418163
    FX_DIRECTORY_ENTRY_READ_EXTENSION
108
109
    /* If trace is enabled, insert this event into the trace buffer.  */
110
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_ENTRY_READ, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
111
112
    /* Calculate the byte offset of this directory entry.  */
113
2418162
    byte_offset =  entry * FX_DIR_ENTRY_SIZE;
114
115
    /* Determine if a sub-directory or FAT32 root directory is specified.  */
116

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

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

2417416
    if ((*(read_ptr + 11) == (UCHAR)FX_LONG_NAME) && (*read_ptr != (UCHAR)FX_DIR_ENTRY_FREE))
287
    {
288
289
        /* Collate the long name. */
290
291
        /* Pickup the file name length.  */
292
62626
        i = (((UINT)(*read_ptr & (UCHAR)0x1f) - 1) * FX_LONG_NAME_ENTRY_LEN) & 0xFFFFFFFF;
293
294
        /* Save the number of LFN entries.  */
295
62626
        number_of_lfns =  (UINT)(*read_ptr & (UCHAR)0x1f);
296
297
        /* Check the file name size.  */
298
62626
        if (i >= (FX_MAX_LONG_NAME_LEN - 1))
299
        {
300
301
            /* Name is too big, shorten it.  */
302
36
            get_short_name = 1;
303
36
            destination_ptr -> fx_dir_entry_long_name_shorted =  (UINT)(*read_ptr & (UCHAR)0x1f);
304
        }
305
        else
306
        {
307
308
            /* Size of name is fine, save pointer to short file name.  */
309
62590
            short_name_ptr = destination_ptr -> fx_dir_entry_short_name;
310
311
            /* Loop to make sure the long file name is NULL terminated.  */
312
62590
            j = i + FX_LONG_NAME_ENTRY_LEN + 1;
313
            do
314
            {
315
                /* Place a NULL in the long name.  */
316
875020
                destination_ptr -> fx_dir_entry_name[i] =  0;
317
318
                /* Position to the next entry.  */
319
875020
                i++;
320

875020
            } while ((i < j) && (i < FX_MAX_LONG_NAME_LEN));
321
        }
322
323
        /* Loop to pickup the rest of the name.  */
324
        do
325
        {
326
327
            /* Get the lower 5 bit containing the cardinality.  */
328
86148
            card = (UINT)(*read_ptr & (UCHAR)0x1f) - 1;
329
330
            /* For simplicity no checksum or cardinality checking is done */
331
86148
            if (get_short_name == 0)
332
            {
333
334
                /* Loop to pickup name.  */
335
1442028
                for (i = 1, j = 0; i < FX_DIR_ENTRY_SIZE; i += 2)
336
                {
337
338

1357223
                    if ((i == 11) || (i == 26))
339
                    {
340
169641
                        continue;
341
                    }
342
343
                    /* i = 12, 27 is not generated due to +=2 */
344
1187582
                    if (i == 13)
345
                    {
346
84836
                        i = 12;
347
84836
                        continue; /* this time next unicode is byte offset 14*/
348
                    }
349
350
                    /* Determine if there is an actual unicode character present.  */
351
1102746
                    if (read_ptr[i + 1])
352
                    {
353
354
                        /* Extended byte is non-zero, make sure both bytes of the unicode entry are not
355
                           all ones, since this is a normal case.  */
356

542868
                        if ((read_ptr[i + 1] != (UCHAR)0xFF) || (read_ptr[i] != (UCHAR)0xFF))
357
                        {
358
359
                            /* Name is an actual unicode name, shorten it.  */
360
4091
                            get_short_name = 1;
361
362
                            /* Save the number of directory entries the LFN has.  This will be
363
                               used later when updating the 8.3 portion of the LFN.  */
364
4091
                            destination_ptr -> fx_dir_entry_long_name_shorted =  number_of_lfns;
365
366
                            /* Setup short name pointer.  */
367
4091
                            short_name_ptr =  destination_ptr -> fx_dir_entry_name;
368
                        }
369
                    }
370
371
                    /* Determine if the character is NULL.  */
372

1102746
                    if ((read_ptr[i] == FX_NULL) || (read_ptr[i] == (UCHAR)0xFF))
373
                    {
374
600999
                        continue;
375
                    }
376
377
                    /* Determine if the name is too big.  */
378
501747
                    if ((card * 13 + j) >= (FX_MAX_LONG_NAME_LEN - 1))
379
                    {
380
381
                        /* Name is actually too big, shorten it.  */
382
33
                        get_short_name =  1;
383
384
                        /* Save the number of directory entries the LFN has.  This will be
385
                           used later when updating the 8.3 portion of the LFN.  */
386
33
                        destination_ptr -> fx_dir_entry_long_name_shorted =  number_of_lfns;
387
388
                        /* Also reposition the short name pointer.  */
389
33
                        short_name_ptr =  destination_ptr -> fx_dir_entry_name;
390
391
33
                        break;
392
                    }
393
394
                    /* Each entry contains 13 unicode and first byte ASCII, second byte is extended. */
395
501714
                    destination_ptr -> fx_dir_entry_name[13 * card + j] = (CHAR)read_ptr[i];
396
397
501714
                    j++;
398
                }
399
            }
400
401
            /* Determine if a new sector needs to be read.  */
402
86148
            if (byte_offset + FX_DIR_ENTRY_SIZE >= media_ptr -> fx_media_bytes_per_sector)
403
            {
404
405
                /* Determine if a sub-directory or FAT32 root directory is specified.  */
406

15692
                if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
407
                {
408
409
                    /* Determine the next sector of the directory entry.  */
410
11005
                    if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
411
                    {
412
413
                        /* More sectors in this cluster.  */
414
415
                        /* Simply increment the logical sector.  */
416
4260
                        logical_sector++;
417
418
                        /* Increment the relative sector.  */
419
4260
                        relative_sector++;
420
                    }
421
                    else
422
                    {
423
424
                        /* We need to move to the next cluster.  */
425
426
                        /* Pickup the next cluster.  */
427
6745
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
428
429
                        /* Check for I/O error.  */
430
6745
                        if (status != FX_SUCCESS)
431
                        {
432
433
                            /* Return error code.  */
434
1
                            return(status);
435
                        }
436
437
                        /* Copy next cluster to the current cluster.  */
438
6744
                        cluster =  next_cluster;
439
440
                        /* Check the value of the new cluster - it must be a valid cluster number
441
                           or something is really wrong!  */
442

6744
                        if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
443
                        {
444
445
                            /* Send error message back to caller.  */
446
5
                            return(FX_FILE_CORRUPT);
447
                        }
448
449
                        /* Now increment the relative cluster.  */
450
6739
                        relative_cluster++;
451
452
                        /* Setup the relative sector (this is zero for subsequent cluster.  */
453
6739
                        relative_sector =  0;
454
455
                        /* Calculate the next logical sector.  */
456
6739
                        logical_sector =   ((ULONG)media_ptr -> fx_media_data_sector_start) +
457
6739
                            (((ULONG)cluster - FX_FAT_ENTRY_START) *
458
6739
                             ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
459
                    }
460
                }
461
                else
462
                {
463
464
                    /* Non-FAT 32 root directory.  */
465
466
                    /* Advance to the next sector.  */
467
4687
                    logical_sector++;
468
469
                    /* Determine if the logical sector is valid.  */
470
4687
                    if (logical_sector >= (ULONG)(media_ptr -> fx_media_root_sector_start + media_ptr -> fx_media_root_sectors))
471
                    {
472
473
                        /* Trying to read past root directory - send error message back to caller.  */
474
5
                        return(FX_FILE_CORRUPT);
475
                    }
476
                }
477
478
                /* Read the new sector.  */
479
15681
                status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
480
15681
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
481
482
                /* Check I/O status.  */
483
15681
                if (status != FX_SUCCESS)
484
                {
485
2
                    return(status);
486
                }
487
488
                /* Set the byte offset to 0 for new sector.  */
489
15679
                byte_offset = 0;
490
            }
491
            else
492
            {
493
494
                /* Calculate the new byte offset.  */
495
70456
                byte_offset += FX_DIR_ENTRY_SIZE;
496
            }
497
498
            /* Calculate the next read pointer.  */
499
86135
            read_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT) byte_offset;
500
501
            /* Move to the next entry.  */
502
86135
            entry++;
503
86135
        } while (card > 0);
504
505
        /* Set flag indicating long file name is present.  */
506
62613
        destination_ptr -> fx_dir_entry_long_name_present = 1;
507
    }
508
    else
509
    {
510
        /* No long file name is present.  */
511
2354790
        get_short_name = 1;
512
    }
513
514
    /* Determine if we need to clear the long name flag.  */
515
2417403
    if (get_short_name == 1)
516
    {
517
518
        /* Clear the long name flag.  */
519
2358721
        destination_ptr -> fx_dir_entry_long_name_present =  0;
520
    }
521
522
    /* Pickup the short file name.  */
523
2417403
    short_name_ptr[0] =  0;
524
2417403
    dotflag =  0;
525
27449467
    for (i = 0, j = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
526
    {
527
528
        /* Check for a NULL.  */
529
25174047
        if ((CHAR)read_ptr[i] == 0)
530
        {
531
141983
            break;
532
        }
533
534
        /* Check for a dot.  This happens for the first two directory entries, no
535
           extra dot is needed.  */
536
25032064
        if ((CHAR)read_ptr[i] == '.')
537
        {
538
47976
            dotflag =  2;
539
        }
540
541
        /* Check for a space.  */
542
25032064
        if ((CHAR)read_ptr[i] == ' ')
543
        {
544
            /* Put a dot if a character comes after space.  */
545
5172728
            if (dotflag == 0)
546
            {
547
2243065
                dotflag =  1;
548
            }
549
5172728
            continue;
550
        }
551
552
        /* Check for the main short file name size.  */
553
19859336
        if (i == FX_DIR_NAME_SIZE)
554
        {
555
            /* Check to see if we need to insert a dot.  */
556
1995933
            if (dotflag == 0)
557
            {
558
370
                dotflag =  1;
559
            }
560
        }
561
562
        /* Check to see if we need to add a dot.  */
563
19859336
        if (dotflag == 1)
564
        {
565
            /* Add dot to short file name.  */
566
1995964
            short_name_ptr[j++] =  '.';
567
1995964
            dotflag =  2;    /* no more dot for spaces */
568
        }
569
570
        /* Copy a character.  */
571
19859336
        short_name_ptr[j] =  (CHAR)read_ptr[i];
572
573
        /* Increment size.  */
574
19859336
        j++;
575
    }
576
577
    /* Determine if a long file name is present and its associated short file
578
       name is actually free.  */
579

2417403
    if ((destination_ptr -> fx_dir_entry_long_name_present) && (((UCHAR)short_name_ptr[0]) == (UCHAR)FX_DIR_ENTRY_FREE))
580
    {
581
582
        /* Yes, the short file name is really free even though long file name entries directly precede it.
583
           In this case, simply place the free directory marker at the front of the long file name.  */
584
17
        destination_ptr -> fx_dir_entry_name[0] =  (CHAR)FX_DIR_ENTRY_FREE;
585
17
        short_name_ptr[0] =  (CHAR)0;
586
    }
587
588
    /* Determine if the short name pointer is NULL while the read pointer is
589
       non-NULL.  */
590

2417403
    if ((short_name_ptr[0] == 0) && (read_ptr[0] == ' '))
591
    {
592
593
        /* This condition can occur with an all blank volume name.  Simply
594
           copy the volume name to the short name in this case.  */
595
72
        for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
596
        {
597
598
            /* Copy a byte of the volume name.  */
599
66
            short_name_ptr[j] =  (CHAR)read_ptr[j];
600
        }
601
    }
602
603
    /* Set end of string to null.  */
604
2417403
    short_name_ptr[j] = 0;
605
606
    /* Load up the destination directory entry.  */
607
2417403
    read_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
608
609
    /* Copy the attribute into the destination.  */
610
2417403
    destination_ptr -> fx_dir_entry_attributes =  *read_ptr++;
611
612
    /* Pickup the reserved byte.  */
613
2417403
    destination_ptr -> fx_dir_entry_reserved =  *read_ptr++;
614
615
    /* Check for an undocumented NT file name feature for optimizing the storage
616
       of all lower case file names that otherwise are valid 8.3 file names. The
617
       following reserved bit definitions are present:
618
619
         BIT3 - set if 8.3 is all in lower case and no extended filename.
620
         BIT4 - set for file, clear for directory entry if no extended filename.
621
622
       This is true for all NT systems. Prior to NT follows MSDOS FAT documentation and
623
       is set to 0x00, all bits cleared. Therefore if BIT3 is set force lowercase.  */
624

2417403
    if ((get_short_name) && (destination_ptr -> fx_dir_entry_reserved & 0x08))
625
    {
626
627
        /* Microsoft undocumented NT file name feature... convert short name to lower
628
           case.  */
629

540
        for (j = 0; j <= (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE) && (short_name_ptr[j] != 0x00); j++)
630
        {
631
632
            /* Determine if an upper case character is present.  */
633

484
            if ((short_name_ptr[j] >= 'A') && (short_name_ptr[j] <= 'Z'))
634
            {
635
636
                /* Yes, an upper case character is present. Force it to lower case.  */
637
248
                short_name_ptr[j] =  (CHAR)(short_name_ptr[j] + 32);
638
            }
639
        }
640
    }
641
642
    /* Pickup the created time in milliseconds.  */
643
2417403
    destination_ptr -> fx_dir_entry_created_time_ms =  *read_ptr++;
644
645
    /* Pickup the created time.  */
646
2417403
    destination_ptr -> fx_dir_entry_created_time =  _fx_utility_16_unsigned_read(read_ptr);
647
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
648
649
    /* Pickup the created date.  */
650
2417403
    destination_ptr -> fx_dir_entry_created_date =  _fx_utility_16_unsigned_read(read_ptr);
651
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
652
653
    /* Pickup the last accessed date.  */
654
2417403
    destination_ptr -> fx_dir_entry_last_accessed_date =  _fx_utility_16_unsigned_read(read_ptr);
655
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
656
657
    /* read the upper 2 bytes of starting cluster - required only for 32 bit FAT */
658
2417403
    if (media_ptr -> fx_media_32_bit_FAT)
659
    {
660
661
        /* FAT32 only.  */
662
1124328
        destination_ptr -> fx_dir_entry_cluster =  _fx_utility_16_unsigned_read(read_ptr);
663
1124328
        destination_ptr -> fx_dir_entry_cluster <<= 16;
664
    }
665
    else
666
    {
667
        /* Not required for non FAT32.  */
668
1293075
        destination_ptr -> fx_dir_entry_cluster =  0;
669
    }
670
671
    /* Advance the read pointer.  */
672
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
673
674
    /* Copy the time into the destination.  */
675
2417403
    destination_ptr -> fx_dir_entry_time =  _fx_utility_16_unsigned_read(read_ptr);
676
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
677
678
    /* Copy the date into the destination.  */
679
2417403
    destination_ptr -> fx_dir_entry_date =  _fx_utility_16_unsigned_read(read_ptr);
680
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
681
682
    /* Copy the starting cluster into the destination.  */
683
2417403
    destination_ptr -> fx_dir_entry_cluster +=  _fx_utility_16_unsigned_read(read_ptr);
684
2417403
    read_ptr =  read_ptr + 2;  /* Always 2 bytes */
685
686
    /* Copy the file size into the destination.  */
687
2417403
    destination_ptr -> fx_dir_entry_file_size =  _fx_utility_32_unsigned_read(read_ptr);
688
689
    /* Clear the destination search specific fields.  */
690
2417403
    destination_ptr -> fx_dir_entry_last_search_cluster =           0;
691
2417403
    destination_ptr -> fx_dir_entry_last_search_relative_cluster =  0;
692
2417403
    destination_ptr -> fx_dir_entry_last_search_log_sector =        0;
693
2417403
    destination_ptr -> fx_dir_entry_last_search_byte_offset =       0;
694
695
    /* Remember the entry number.  */
696
2417403
    destination_ptr -> fx_dir_entry_number =  entry;
697
698
    /* Return entry number.  */
699
2417403
    *entry_ptr =  entry;
700
701
    /* Determine if we should remember the last cluster and relative cluster.  */
702
2417403
    if (source_dir)
703
    {
704
705
        /* Yes, remember the last cluster and relative cluster for a subsequent call
706
           to read a directory entry.  */
707
163937
        source_dir -> fx_dir_entry_last_search_cluster =           cluster;
708
163937
        source_dir -> fx_dir_entry_last_search_relative_cluster =  relative_cluster;
709
710
        /* Also remember several other items that are unique to the directory... just to verify that the
711
           search information can be used.  */
712
163937
        source_dir -> fx_dir_entry_last_search_log_sector =        source_dir -> fx_dir_entry_log_sector;
713
163937
        source_dir -> fx_dir_entry_last_search_byte_offset =       source_dir -> fx_dir_entry_byte_offset;
714
    }
715
716
    /* Return success to the caller.  */
717
2417403
    return(FX_SUCCESS);
718
}
719
720
721