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

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
10
/**************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Unicode                                                             */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "fx_api.h"
29
#include "fx_unicode.h"
30
#include "fx_utility.h"
31
32
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
/*  RELEASE HISTORY                                                       */
72
/*                                                                        */
73
/*    DATE              NAME                      DESCRIPTION             */
74
/*                                                                        */
75
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
76
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
77
/*                                            resulting in version 6.1    */
78
/*                                                                        */
79
/**************************************************************************/
80
8554
UINT  _fx_unicode_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
81
                                       ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr,
82
                                       UCHAR *unicode_name, ULONG *unicode_size)
83
{
84
85
UINT   i, j, k, card, dotflag, get_short_name;
86
UINT   number_of_lfns;
87
UINT   status;
88
8554
ULONG  cluster, next_cluster = 0;
89
UINT   relative_cluster;
90
UINT   relative_sector;
91
ULONG  logical_sector;
92
ULONG  byte_offset;
93
ULONG  bytes_per_cluster;
94
UCHAR *read_ptr;
95
CHAR  *short_name_ptr;
96
8554
ULONG  entry = *entry_ptr;
97
UINT   u;
98
99
100
#ifndef FX_MEDIA_STATISTICS_DISABLE
101
102
    /* Increment the number of directory entry read requests.  */
103
8554
    media_ptr -> fx_media_directory_entry_reads++;
104
#endif
105
106
    /* Calculate the byte offset of this directory entry.  */
107
8554
    byte_offset =  entry * FX_DIR_ENTRY_SIZE;
108
109
    /* Determine if a sub-directory or FAT32 root directory is specified.  */
110

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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