GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_entry_write.c Lines: 292 292 100.0 %
Date: 2026-03-06 18:49:02 Branches: 222 222 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Directory                                                           */
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_system.h"
30
#include "fx_directory.h"
31
#include "fx_utility.h"
32
#ifdef FX_ENABLE_FAULT_TOLERANT
33
#include "fx_fault_tolerant.h"
34
#endif /* FX_ENABLE_FAULT_TOLERANT */
35
36
37
/**************************************************************************/
38
/*                                                                        */
39
/*  FUNCTION                                               RELEASE        */
40
/*                                                                        */
41
/*    _fx_directory_entry_write                           PORTABLE C      */
42
/*                                                           6.1.5        */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    William E. Lamie, Microsoft Corporation                             */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function writes the supplied directory entry to the specified  */
50
/*    logical sector and offset.                                          */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    media_ptr                             Media control block pointer   */
55
/*    entry_ptr                             Pointer to directory entry    */
56
/*                                                                        */
57
/*  OUTPUT                                                                */
58
/*                                                                        */
59
/*    return status                                                       */
60
/*                                                                        */
61
/*  CALLS                                                                 */
62
/*                                                                        */
63
/*    _fx_utility_FAT_entry_read            Read a new FAT entry          */
64
/*    _fx_utility_logical_sector_read       Read directory sector         */
65
/*    _fx_utility_logical_sector_write      Write directory sector        */
66
/*    _fx_utility_16_unsigned_write         Write a UINT from memory      */
67
/*    _fx_utility_32_unsigned_write         Write a ULONG from memory     */
68
/*    _fx_fault_tolerant_add_dir_log        Add directory redo log        */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    FileX System Functions                                              */
73
/*                                                                        */
74
/**************************************************************************/
75
145406
UINT  _fx_directory_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr)
76
{
77
78
UCHAR *work_ptr, *sector_base_ptr;
79
UINT   status, temp, entry, delete_flag;
80
UINT   i, j, k, l, card, len, dotfound, dotpos, match;
81
UCHAR  checksum, eof_marker;
82
CHAR   alpha;
83
CHAR   shortname[FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE + 1];
84
ULONG  logical_sector, relative_sector;
85
ULONG  byte_offset;
86
ULONG  cluster, next_cluster;
87
88
89
#ifdef FX_ENABLE_FAULT_TOLERANT
90
UCHAR *changed_ptr;
91
UINT   changed_size;
92
ULONG  changed_offset;
93
#endif /* FX_ENABLE_FAULT_TOLERANT */
94
95
96
#ifndef FX_MEDIA_STATISTICS_DISABLE
97
98
    /* Increment the number of directory entry write requests.  */
99
145406
    media_ptr -> fx_media_directory_entry_writes++;
100
#endif
101
102
    /* Extended port-specific processing macro, which is by default defined to white space.  */
103

145406
    FX_DIRECTORY_ENTRY_WRITE_EXTENSION
104
105
    /* If trace is enabled, insert this event into the trace buffer.  */
106
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_ENTRY_WRITE, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
107
108
    /* Determine if this is entry is being deleted.  */
109
145401
    if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) &&
110
3487
        ((UCHAR)entry_ptr -> fx_dir_entry_short_name[0] == (UCHAR)FX_DIR_ENTRY_FREE))
111
    {
112
113
        /* Yes, this is a request to delete the entry. Set the flag to remember this.  */
114
587
        delete_flag =  FX_TRUE;
115
116
        /* Null the short file name.  */
117
587
        entry_ptr -> fx_dir_entry_short_name[0] =  0;
118
    }
119
    else
120
    {
121
122
        /* Not a deleted entry. Set the flag to false.  */
123
144814
        delete_flag =  FX_FALSE;
124
    }
125
126
    /* Pickup the byte offset of the entry.  */
127
145401
    byte_offset = entry_ptr -> fx_dir_entry_byte_offset;
128
129
    /* Pickup the logical sector of the entry.  */
130
145401
    logical_sector = (ULONG)entry_ptr -> fx_dir_entry_log_sector;
131
132
    /* Figure out where what cluster we are in.  */
133
145401
    if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
134
    {
135
136
        /* Calculate the cluster that this logical sector is in.  */
137
88836
        cluster =  (logical_sector - media_ptr -> fx_media_data_sector_start) / (media_ptr -> fx_media_sectors_per_cluster) + FX_FAT_ENTRY_START;
138
139
        /* Calculate the relative cluster.  */
140
88836
        relative_sector =  logical_sector -  (((ULONG)media_ptr -> fx_media_data_sector_start) +
141
88836
                                              (((ULONG)cluster - FX_FAT_ENTRY_START) *
142
88836
                                               ((ULONG)media_ptr -> fx_media_sectors_per_cluster)));
143
    }
144
    else
145
    {
146
147
        /* Clear the cluster and the relative sector.  */
148
56565
        cluster =  0;
149
56565
        relative_sector =  0;
150
    }
151
152
    /* Read the logical directory sector.  */
153
145401
    status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) entry_ptr -> fx_dir_entry_log_sector,
154
145401
                                              media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
155
156
    /* Determine if an error occurred.  */
157
145401
    if (status != FX_SUCCESS)
158
    {
159
160
        /* Return the error status.  */
161
30
        return(status);
162
    }
163
164
    /* Setup a pointer into the buffer.  */
165
145371
    sector_base_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
166
145371
    work_ptr =  sector_base_ptr + (UINT)entry_ptr -> fx_dir_entry_byte_offset;
167
168
#ifdef FX_ENABLE_FAULT_TOLERANT
169
    /* Initialize data for fault tolerant. */
170
    changed_ptr = work_ptr;
171
    changed_size = 0;
172
    changed_offset = entry_ptr -> fx_dir_entry_byte_offset;
173
#endif /* FX_ENABLE_FAULT_TOLERANT */
174
175
    /* Determine if a long file name is present.  */
176
145371
    if (entry_ptr -> fx_dir_entry_long_name_present)
177
    {
178
179
        /* Yes, long name is present - prepare short name and write out this name.  */
180
24106
        for (len = 0, i = 0, dotpos = 0, dotfound = 0; entry_ptr -> fx_dir_entry_name[len]; len++)
181
        {
182
183
            /* Check for a dot.  */
184
22901
            if (entry_ptr -> fx_dir_entry_name[len] == '.')
185
            {
186
187
                /* Check for leading dot. */
188
109
                if (len == 0)
189
                {
190
                    /* Yes, this is a leading dot. */
191
6
                    continue;
192
                }
193
194
                /* Yes, a dot is present.  From this position the extension will
195
                   be written.  */
196
103
                dotfound = i;
197
103
                dotpos   = len + 1;
198
103
                continue;
199
            }
200
201
            /* Check for non-space and within the short file name length.  */
202

22792
            if ((entry_ptr -> fx_dir_entry_name[len] != ' ') && (i < 8))
203
            {
204
205
                /* Copy characters into the short file name area.  */
206
7484
                shortname[i] = entry_ptr -> fx_dir_entry_name[len];
207
7484
                i++;
208
            }
209
        }
210
211
        /* Fill remaining short file name with spaces.  */
212
6976
        for (j = i; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; j++)
213
        {
214
5771
            shortname[j] =  ' ';
215
        }
216
217
        /* Determine if a dot was encountered.  */
218
1205
        if (dotpos)
219
        {
220
221
            /* Process relative to the dot position.  */
222
83
            if (entry_ptr -> fx_dir_entry_name[dotpos])
223
            {
224
70
                shortname[8] = entry_ptr -> fx_dir_entry_name[dotpos++];
225
            }
226
83
            if (entry_ptr -> fx_dir_entry_name[dotpos])
227
            {
228
67
                shortname[9] = entry_ptr -> fx_dir_entry_name[dotpos++];
229
            }
230
83
            if (entry_ptr -> fx_dir_entry_name[dotpos])
231
            {
232
64
                shortname[10] = entry_ptr -> fx_dir_entry_name[dotpos++];
233
            }
234
235
            /* Determine if additional spaces are needed.  */
236
83
            i = dotfound;
237
238
348
            for (; dotfound <= 7; dotfound++)
239
            {
240
                /* Add space...  */
241
265
                shortname[dotfound] = ' ';
242
            }
243
        }
244
245
        /* Each entry contains 13 unicode entries.  Calculate the remainder.  */
246
1205
        if (len % 13 == 0)
247
        {
248
30
            card =  len / 13;
249
        }
250
        else
251
        {
252
1175
            card =  len / 13 + 1;
253
        }
254
255
        /* Default the name match to true.  */
256
1205
        match =  FX_TRUE;
257
258
        /* Loop through the newly derived short name and the original name and look
259
           for a non-matching character.  */
260
1205
        l =  0;
261
1205
        k =  0;
262
8692
        while (k < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE)
263
        {
264
265
            /* Determine if a space is detected in the short name. If so,
266
               advance to the extension index.  */
267
8647
            if (shortname[k] == ' ')
268
            {
269
270
                /* The first pad space was detected. First, check for a name
271
                   without an extension.  */
272
1194
                if (entry_ptr -> fx_dir_entry_name[l] == FX_NULL)
273
                {
274
275
                    /* All is okay, get out of the loop!  */
276
467
                    break;
277
                }
278
279
                /* Now check for a period in the long name... if not, there is a non-match!  */
280
727
                if (entry_ptr -> fx_dir_entry_name[l] != '.')
281
                {
282
283
                    /* Set the match flag to false and exit the loop.  */
284
670
                    match =  FX_FALSE;
285
670
                    break;
286
                }
287
288
                /* Otherwise move short file name index to the extension area and
289
                   increment the long file name index.  */
290
57
                k =  8;
291
57
                l++;
292
293
                /* Restart the loop at the top.  */
294
57
                continue;
295
            }
296
297
            /* Check for the dot for the 8.3 match... it is no longer in the
298
               shortname but possibly still present in the long name.  */
299

7453
            if ((k == 8) && (entry_ptr -> fx_dir_entry_name[l] == '.'))
300
            {
301
302
                /* Yes, handle the implicit dot in the shortname by
303
                   positioning past it in the long name.  */
304
10
                l++;
305
            }
306
307
            /* Do the names match?  */
308
7453
            if (shortname[k] != entry_ptr -> fx_dir_entry_name[l])
309
            {
310
311
                /* No, the names do not match, set the match flag to false and
312
                   exit the loop.  */
313
23
                match =  FX_FALSE;
314
23
                break;
315
            }
316
317
            /* Move the indices forward.  */
318
7430
            k++;
319
7430
            l++;
320
        }
321
322
        /* Check if there is a dot in the name, but no extension in the short name.  In this case,
323
           we should create a mangled short name.  */
324

1205
        if ((dotpos) && (shortname[8] == ' '))
325
        {
326
327
            /* Something left.. the names do not match!  */
328
17
            match =  FX_FALSE;
329
        }
330
331
        /* One final check to make sure there is nothing left on the long file name.  */
332
1205
        if (entry_ptr -> fx_dir_entry_name[l])
333
        {
334
335
            /* Something left.. the names do not match!  */
336
694
            match =  FX_FALSE;
337
        }
338
339
        /* Determine if the derived short name matches exactly the long file name. If so
340
           we don't need to mangle the name with a numeric value based on its entry.  */
341
1205
        if (match == FX_FALSE)
342
        {
343
344
            /* Name does not match, create a mangled name.  */
345
346
            /* Generate short file name from LFN.  */
347
705
            entry = entry_ptr -> fx_dir_entry_number;
348
349
            /* Name suffice is between 000 and FFFF in hex, calculate this short file
350
               name's numeric component.  */
351
705
            entry = entry % 0x10000;
352
353
            /* Build short name of the format xxx~NNNN.ext.  */
354
705
            if (i > 3)
355
            {
356
698
                i = 3;
357
            }
358
705
            shortname[i++] = '~';
359
360
            /* Loop to build the numeric part of the name.  */
361
3525
            for (l = 0; l < 4; l++)
362
            {
363
364
                /* Shift down the entry number based on the numeric position.  */
365
2820
                if (l == 0)
366
                {
367
705
                    temp =  ((entry >> 12) & 0xf);
368
                }
369
2115
                else if (l == 1)
370
                {
371
705
                    temp = ((entry >> 8) & 0xf);
372
                }
373
1410
                else if (l == 2)
374
                {
375
705
                    temp = ((entry >> 4) & 0xf);
376
                }
377
                else
378
                {
379
705
                    temp = ((entry) & 0xf);
380
                }
381
382
                /* Now build hex value.  */
383
2820
                if (temp > 9)
384
191
                    shortname[i++] =  (CHAR)('A' + (temp - 10));
385
                else
386
2629
                    shortname[i++] =  (CHAR)('0' + temp);
387
            }
388
        }
389
390
        /* Set end of short string to NULL.   */
391
1205
        shortname[11] = 0;
392
393
        /* Determine if the first character of the short file name is the directory free
394
           value. If so, it must be changed.  */
395

1205
        if (((UCHAR)shortname[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (delete_flag == FX_FALSE))
396
        {
397
398
            /* Change to 0x8F to be compatible with what DOS does.  */
399
11
            shortname[0] =  (CHAR)0x8F;
400
        }
401
402
        /* Loop to convert the new short file name to upper case.  */
403
14460
        for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
404
        {
405
406
            /* Pickup shortname character.  */
407
13255
            alpha = shortname[i];
408
409
            /* Determine if character is lower case.  */
410

13255
            if ((alpha >= 'a') && (alpha <= 'z'))
411
            {
412
413
                /* Store the character - converted to upper case.  */
414
2260
                alpha =  (CHAR)(alpha - ((CHAR)0x20));
415
            }
416
417
            /* Now store the short name character.  */
418
13255
            shortname[i] =  alpha;
419
        }
420
421
        /* Determine if there already is a short name and we are not deleting the entry.  */
422
1205
        if (entry_ptr -> fx_dir_entry_short_name[0] != 0)
423
        {
424
425
            /* Yes, override the calculated shortname with the original 8.3 name.  */
426
427
            /* Clear the short file name area.  */
428
636
            for (i = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
429
            {
430
583
                shortname[i] = ' ';
431
            }
432
433
            /* Loop to copy the original short file name.  */
434
433
            for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
435
            {
436
437
                /* Check for end of copy conditions.  */
438
390
                if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == '.')
439
                {
440
2
                    break;
441
                }
442
388
                if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
443
                {
444
8
                    break;
445
                }
446
447
                /* Pickup the character.  */
448
380
                alpha =  entry_ptr -> fx_dir_entry_short_name[i];
449
450
                /* Copy file name character.  */
451
380
                shortname[j] =  alpha;
452
            }
453
454
            /* Determine if there is anything left in the short file name.  */
455
53
            if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] != 0)
456
            {
457
458
                /* Pickup remaining characters.  */
459
15
                for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
460
                {
461
462
                    /* If NULL is encountered, stop the copying.  */
463
12
                    if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
464
                    {
465
1
                        break;
466
                    }
467
468
                    /* Pickup the character.  */
469
11
                    alpha =  entry_ptr -> fx_dir_entry_short_name[i];
470
471
                    /* Copy file name character.  */
472
11
                    shortname[j] =  alpha;
473
                }
474
            }
475
476
            /* Loop to make sure the short name is upper case.  */
477
636
            for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
478
            {
479
480
                /* Pickup the character.  */
481
583
                alpha =  shortname[j];
482
483
                /* Determine if character is lower case.  */
484

583
                if ((alpha >= 'a') && (alpha <= 'z'))
485
                {
486
487
                    /* Store the character - converted to upper case.  */
488
1
                    alpha =  (CHAR)(alpha - ((CHAR)0x20));
489
                }
490
491
                /* Copy file name character.  */
492
583
                shortname[j] =  alpha;
493
            }
494
495
            /* Determine if the first character of the short file name is the directory free
496
               value. If so, it must be changed.  */
497
53
            if (((UCHAR)shortname[0]) == ((UCHAR)FX_DIR_ENTRY_FREE))
498
            {
499
500
                /* Change to 0x8F to be compatible with what DOS does.  */
501
1
                shortname[0] =  (CHAR)0x8F;
502
            }
503
        }
504
505
        /* Loop to calculate the checksum.  */
506
14460
        for (i = checksum = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
507
        {
508
509
            /* Calculate the checksum.  */
510
13255
            checksum = (UCHAR)((UCHAR)(((checksum & 1) << 7) | ((checksum & (UCHAR)0xfe) >> 1)) + shortname[i]);
511
        }
512
513
        /* Set the last entry mark.  */
514
1205
        work_ptr[0] =  (UCHAR)(0x40 | card);
515
516
        /* Loop to process remainder of long file name entry.  */
517
3636
        while (card > 0)
518
        {
519
520
            /* Clear eof marker.  */
521
2437
            eof_marker = 0;
522
523
            /* Determine if the entry is free.  */
524
2437
            if ((UCHAR)shortname[0] == (UCHAR)FX_DIR_ENTRY_FREE)
525
            {
526
                /* Yes, place delete marker.  */
527
290
                work_ptr[0] =  (UCHAR)FX_DIR_ENTRY_FREE;
528
            }
529
530
            /* Setup various long file name fields.  */
531
2437
            work_ptr[11] = FX_LONG_NAME;
532
2437
            work_ptr[12] = 0;
533
2437
            work_ptr[13] = checksum;
534
2437
            work_ptr[26] = 0;
535
2437
            work_ptr[27] = 0;
536
537
            /* Loop through file name fields.  */
538
41429
            for (i = 1, j = 13 * (card - 1); i < FX_DIR_ENTRY_SIZE; i += 2)
539
            {
540
541
                /* Process relative to specific fields.  */
542

38992
                if ((i == 11) || (i == 26))
543
                {
544
4874
                    continue;
545
                }
546
547
34118
                if (i == 13)
548
                {
549
2437
                    i = 12;
550
2437
                    continue;
551
                }
552
553
                /* Determine if the EOF marker is present.  */
554
31681
                if (eof_marker)
555
                {
556
557
8931
                    work_ptr[i] = eof_marker;
558
8931
                    work_ptr[i + 1] = eof_marker;
559
                }
560
                else
561
                {
562
22750
                    work_ptr[i] = (UCHAR)entry_ptr -> fx_dir_entry_name[j];
563
22750
                    work_ptr[i + 1] = 0;
564
                }
565
566
31681
                if (entry_ptr -> fx_dir_entry_name[j] == 0)
567
                {
568
569
                    /* end of name, pad with 0xff.  */
570
9429
                    eof_marker =  (UCHAR)0xff;
571
                }
572
573
31681
                j++;
574
            }
575
576
            /* Move to the next directory entry.  */
577
2437
            work_ptr += FX_DIR_ENTRY_SIZE;
578
2437
            byte_offset += FX_DIR_ENTRY_SIZE;
579
580
#ifdef FX_ENABLE_FAULT_TOLERANT
581
            /* Update changed_size. */
582
            changed_size += FX_DIR_ENTRY_SIZE;
583
#endif /* FX_ENABLE_FAULT_TOLERANT */
584
585
            /* Determine if the entry overlaps into the next sector.  */
586
2437
            if (byte_offset >= media_ptr -> fx_media_bytes_per_sector)
587
            {
588
#ifdef FX_ENABLE_FAULT_TOLERANT
589
                if (media_ptr -> fx_media_fault_tolerant_enabled)
590
                {
591
592
                    /* Redirect this request to log file. */
593
                    status = _fx_fault_tolerant_add_dir_log(media_ptr, logical_sector, changed_offset, changed_ptr, changed_size);
594
                }
595
                else
596
                {
597
#endif /* FX_ENABLE_FAULT_TOLERANT */
598
599
                    /* Write current logical sector out.  */
600
550
                    status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
601
                                                               sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
602
#ifdef FX_ENABLE_FAULT_TOLERANT
603
                }
604
#endif /* FX_ENABLE_FAULT_TOLERANT */
605
606
                /* Determine if an error occurred.  */
607
550
                if (status != FX_SUCCESS)
608
                {
609
610
                    /* Return the error status.  */
611
1
                    return(status);
612
                }
613
614
                /* Determine if we are in the root directory.  */
615
549
                if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
616
                {
617
618
                    /* Determine the next sector of the directory entry.  */
619
400
                    if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
620
                    {
621
622
                        /* More sectors in this cluster.  */
623
624
                        /* Simply increment the logical sector.  */
625
45
                        logical_sector++;
626
627
                        /* Increment the relative sector.  */
628
45
                        relative_sector++;
629
                    }
630
                    else
631
                    {
632
633
                        /* We need to move to the next cluster.  */
634
635
                        /* Pickup the next cluster.  */
636
355
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
637
638
                        /* Check for I/O error.  */
639
355
                        if (status != FX_SUCCESS)
640
                        {
641
642
                            /* Return error code.  */
643
1
                            return(status);
644
                        }
645
646
                        /* Copy next cluster to the current cluster.  */
647
354
                        cluster =  next_cluster;
648
649
                        /* Check the value of the new cluster - it must be a valid cluster number
650
                           or something is really wrong!  */
651

354
                        if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
652
                        {
653
654
                            /* Send error message back to caller.  */
655
2
                            return(FX_FILE_CORRUPT);
656
                        }
657
658
                        /* Setup the relative sector (this is zero for subsequent cluster.  */
659
352
                        relative_sector =  0;
660
661
                        /* Calculate the next logical sector.  */
662
352
                        logical_sector =   ((ULONG)media_ptr -> fx_media_data_sector_start) +
663
352
                            (((ULONG)cluster - FX_FAT_ENTRY_START) *
664
352
                             ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
665
                    }
666
                }
667
                else
668
                {
669
670
                    /* Increment the logical sector.  */
671
149
                    logical_sector++;
672
673
                    /* Determine if the logical sector is valid.  */
674
149
                    if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
675
                    {
676
677
                        /* We have exceeded the root directory.  */
678
679
                        /* Send error message back to caller.  */
680
1
                        return(FX_FILE_CORRUPT);
681
                    }
682
                }
683
684
                /* Read the sector.  */
685
545
                status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
686
545
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
687
688
                /* Determine if an error occurred.  */
689
545
                if (status != FX_SUCCESS)
690
                {
691
692
                    /* Return the error status.  */
693
1
                    return(status);
694
                }
695
696
                /* Setup logical sector.  */
697
544
                sector_base_ptr = media_ptr -> fx_media_memory_buffer;
698
699
                /* Setup a fresh byte offset.  */
700
544
                byte_offset = 0;
701
702
                /* Setup a new pointer into the buffer.  */
703
544
                work_ptr = sector_base_ptr;
704
705
#ifdef FX_ENABLE_FAULT_TOLERANT
706
                /* Initialize data for fault tolerant. */
707
                changed_ptr = work_ptr;
708
                changed_size = 0;
709
                changed_offset = 0;
710
#endif /* FX_ENABLE_FAULT_TOLERANT */
711
            }
712
713
            /* Decrement loop control.  */
714
2431
            card--;
715
2431
            work_ptr[0] = (UCHAR)card;
716
        }
717
718
        /* Determine if there is a short name.  */
719
1199
        if (entry_ptr -> fx_dir_entry_short_name[0] == 0)
720
        {
721
722
            /* Loop to copy the new short file name.  */
723
13752
            for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
724
            {
725
726
                /* Pickup shortname character.  */
727
12606
                alpha = shortname[i];
728
729
                /* Now store the short name character.  */
730
12606
                *work_ptr++ =  (UCHAR)alpha;
731
            }
732
        }
733
        else
734
        {
735
736
            /* Clear the short file name area.  */
737
636
            for (i = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
738
            {
739
583
                work_ptr[i] = ' ';
740
            }
741
742
            /* Loop to copy the old short file name.  */
743
433
            for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
744
            {
745
746
                /* Check for end of copy conditions.  */
747
390
                if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == '.')
748
                {
749
2
                    break;
750
                }
751
388
                if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
752
                {
753
8
                    break;
754
                }
755
756
                /* Copy file name character.  */
757
380
                work_ptr[j] =  (UCHAR)entry_ptr -> fx_dir_entry_short_name[i];
758
            }
759
760
            /* Determine if there is anything left in the short file name.  */
761
53
            if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] != 0)
762
            {
763
764
                /* Pickup remaining characters.  */
765
15
                for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
766
                {
767
768
                    /* If NULL is encountered, stop the copying.  */
769
12
                    if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
770
                    {
771
1
                        break;
772
                    }
773
774
                    /* Copy file name character.  */
775
11
                    work_ptr[j] =  (UCHAR)entry_ptr -> fx_dir_entry_short_name[i];
776
                }
777
            }
778
779
            /* Adjust the work pointer accordingly.  */
780
53
            work_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
781
        }
782
    }
783
    else
784
    {
785
786
        /* Determine if long name was shorted.  */
787
144166
        if (entry_ptr -> fx_dir_entry_long_name_shorted > 0)
788
        {
789
790
            /* Check for a valid short name.  */
791
15
            if ((UCHAR)(0x40 | entry_ptr -> fx_dir_entry_long_name_shorted) == (UCHAR)(*work_ptr))
792
            {
793
794
                /* Loop through the file name.  */
795
89
                for (j = 0; j < entry_ptr -> fx_dir_entry_long_name_shorted; j++)
796
                {
797
798
                    /* Check for a free entry to be written.  */
799
81
                    if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE)
800
                    {
801
                        /* Delete long parts.  */
802
26
                        work_ptr[0] =  (UCHAR)FX_DIR_ENTRY_FREE;
803
                    }
804
805
                    /* Setup pointers for the name write.  */
806
81
                    work_ptr += FX_DIR_ENTRY_SIZE;
807
81
                    byte_offset += FX_DIR_ENTRY_SIZE;
808
809
#ifdef FX_ENABLE_FAULT_TOLERANT
810
                    /* Update changed_size. */
811
                    changed_size += FX_DIR_ENTRY_SIZE;
812
#endif /* FX_ENABLE_FAULT_TOLERANT */
813
814
                    /* Determine if the write is within the current sector.   */
815
81
                    if (byte_offset >= media_ptr -> fx_media_bytes_per_sector)
816
                    {
817
#ifdef FX_ENABLE_FAULT_TOLERANT
818
                        if (media_ptr -> fx_media_fault_tolerant_enabled)
819
                        {
820
821
                            /* Redirect this request to log file. */
822
                            status = _fx_fault_tolerant_add_dir_log(media_ptr, (ULONG64) logical_sector, changed_offset, changed_ptr, changed_size);
823
                        }
824
                        else
825
                        {
826
#endif /* FX_ENABLE_FAULT_TOLERANT */
827
828
                            /* Write the current sector out.  */
829
22
                            status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
830
                                                                       sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
831
#ifdef FX_ENABLE_FAULT_TOLERANT
832
                        }
833
#endif /* FX_ENABLE_FAULT_TOLERANT */
834
835
                        /* Determine if an error occurred.  */
836
22
                        if (status != FX_SUCCESS)
837
                        {
838
839
                            /* Return the error status.  */
840
1
                            return(status);
841
                        }
842
843
                        /* Determine if we are in the root directory.  */
844
21
                        if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
845
                        {
846
847
                            /* Determine the next sector of the directory entry.  */
848
11
                            if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
849
                            {
850
851
                                /* More sectors in this cluster.  */
852
853
                                /* Simply increment the logical sector.  */
854
6
                                logical_sector++;
855
856
                                /* Increment the relative sector.  */
857
6
                                relative_sector++;
858
                            }
859
                            else
860
                            {
861
862
                                /* We need to move to the next cluster.  */
863
864
                                /* Pickup the next cluster.  */
865
5
                                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
866
867
                                /* Check for I/O error.  */
868
5
                                if (status != FX_SUCCESS)
869
                                {
870
871
                                    /* Return error code.  */
872
1
                                    return(status);
873
                                }
874
875
                                /* Copy next cluster to the current cluster.  */
876
4
                                cluster =  next_cluster;
877
878
                                /* Check the value of the new cluster - it must be a valid cluster number
879
                                   or something is really wrong!  */
880

4
                                if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
881
                                {
882
883
                                    /* Send error message back to caller.  */
884
2
                                    return(FX_FILE_CORRUPT);
885
                                }
886
887
                                /* Setup the relative sector (this is zero for subsequent cluster.  */
888
2
                                relative_sector =  0;
889
890
                                /* Calculate the next logical sector.  */
891
2
                                logical_sector =   ((ULONG)media_ptr -> fx_media_data_sector_start) +
892
2
                                    (((ULONG)cluster - FX_FAT_ENTRY_START) *
893
2
                                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
894
                            }
895
                        }
896
                        else
897
                        {
898
899
                            /* Increment the logical sector.  */
900
10
                            logical_sector++;
901
902
                            /* Determine if the logical sector is valid.  */
903
10
                            if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
904
                            {
905
906
                                /* We have exceeded the root directory.  */
907
908
                                /* Send error message back to caller.  */
909
1
                                return(FX_FILE_CORRUPT);
910
                            }
911
                        }
912
913
                        /* Read the next logical sector.  */
914
17
                        status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
915
17
                                                                  media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
916
917
                        /* Determine if an error occurred.  */
918
17
                        if (status != FX_SUCCESS)
919
                        {
920
921
                            /* Return the error status.  */
922
1
                            return(status);
923
                        }
924
925
                        /* Move to the next sector buffer.  */
926
16
                        sector_base_ptr = media_ptr -> fx_media_memory_buffer;
927
928
                        /* Setup new buffer pointers.  */
929
16
                        byte_offset =  0;
930
16
                        work_ptr = sector_base_ptr;
931
932
#ifdef FX_ENABLE_FAULT_TOLERANT
933
                        /* Initialize data for fault tolerant. */
934
                        changed_ptr = work_ptr;
935
                        changed_size = 0;
936
                        changed_offset = 0;
937
#endif /* FX_ENABLE_FAULT_TOLERANT */
938
                    }
939
                }
940
            }
941
        }
942
943
        /* This is an 8.3 name.  First clear the directory name.  */
944
1729920
        for (j = 0; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; j++)
945
        {
946
1585760
            work_ptr[j] = ' ';
947
        }
948
949
        /* Copy leading dots in case of first two entries of a directory.  */
950
203432
        for (i = 0; (UCHAR)entry_ptr -> fx_dir_entry_name[i] == '.'; i++)
951
        {
952
59272
            work_ptr[i] = '.';
953
        }
954
955
        /* Determine if there are more characters to copy.  */
956
144160
        if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] != 0)
957
        {
958
959
            /* Copy directory name.  */
960
692275
            for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
961
            {
962
963
                /* Check for end of copy conditions.  */
964
692268
                if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == '.')
965
                {
966
82229
                    break;
967
                }
968
610039
                if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == 0)
969
                {
970
22409
                    break;
971
                }
972
973
                /* Pickup shortname character.  */
974
587630
                alpha = entry_ptr -> fx_dir_entry_name[i];
975
976
                /* Determine if character is lower case.  */
977

587630
                if ((alpha >= 'a') && (alpha <= 'z'))
978
                {
979
980
                    /* Store the character - converted to upper case.  */
981
10
                    alpha =  (CHAR)(alpha - ((CHAR)0x20));
982
                }
983
984
                /* Copy a name character.  */
985
587630
                work_ptr[j] =  (UCHAR)alpha;
986
            }
987
        }
988
989
        /* Determine if there are more characters in the name.  */
990
144160
        if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] != 0)
991
        {
992
993
            /* Loop to copy the remainder of the name.  */
994
328922
            for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
995
            {
996
997
                /* Check for end of copy conditions.  */
998
246693
                if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == 0)
999
                {
1000
2
                    break;
1001
                }
1002
1003
                /* Pickup shortname character.  */
1004
246691
                alpha = entry_ptr -> fx_dir_entry_name[i];
1005
1006
                /* Determine if character is lower case.  */
1007

246691
                if ((alpha >= 'a') && (alpha <= 'z'))
1008
                {
1009
1010
                    /* Store the character - converted to upper case.  */
1011
3
                    alpha =  (CHAR)(alpha - ((CHAR)0x20));
1012
                }
1013
1014
                /* Copy a name character.  */
1015
246691
                work_ptr[j] =  (UCHAR)alpha;
1016
            }
1017
        }
1018
1019
        /* Move to the next entry.  */
1020
144160
        work_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
1021
    }
1022
1023
    /* Write out the 8.3 part of the name. */
1024
1025
    /* Copy the attribute into the destination.  */
1026
145359
    *work_ptr++ =  entry_ptr -> fx_dir_entry_attributes;
1027
1028
    /* Copy the reserved byte.  */
1029
145359
    *work_ptr++ =  entry_ptr -> fx_dir_entry_reserved;
1030
1031
    /* Copy the created time in milliseconds.  */
1032
145359
    *work_ptr++ =  entry_ptr -> fx_dir_entry_created_time_ms;
1033
1034
    /* Copy the created time.  */
1035
145359
    _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_created_time);
1036
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1037
1038
    /* Copy the created date.  */
1039
145359
    _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_created_date);
1040
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1041
1042
    /* Copy the last accessed date.  */
1043
145359
    _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_last_accessed_date);
1044
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1045
1046
    /* Determine if a FAT32 entry is present.  */
1047
145359
    if (media_ptr -> fx_media_32_bit_FAT)
1048
    {
1049
1050
        /* Yes, FAT32 is present, store upper half of cluster.  */
1051
58334
        temp = (entry_ptr -> fx_dir_entry_cluster >> 16);
1052
58334
        _fx_utility_16_unsigned_write(work_ptr, temp);
1053
    }
1054
    else
1055
    {
1056
1057
        /* No, FAT16 or FAT12 is present, just write a 0 for
1058
           the upper half of the cluster.  */
1059
87025
        _fx_utility_16_unsigned_write(work_ptr, 0);
1060
    }
1061
1062
    /* Advance the entry pointer.  */
1063
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1064
1065
    /* Copy the time into the destination.  */
1066
145359
    _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_time);
1067
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1068
1069
    /* Copy the date into the destination.  */
1070
145359
    _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_date);
1071
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1072
1073
    /* Copy the starting cluster into the destination.  */
1074
145359
    _fx_utility_16_unsigned_write(work_ptr, (UINT)entry_ptr -> fx_dir_entry_cluster);
1075
145359
    work_ptr =  work_ptr + 2;  /* Always 2 bytes  */
1076
1077
    /* Copy the file size into the destination.  */
1078
145359
    _fx_utility_32_unsigned_write(work_ptr, (ULONG)entry_ptr -> fx_dir_entry_file_size);
1079
1080
#ifdef FX_ENABLE_FAULT_TOLERANT
1081
    /* Update changed_size. */
1082
    changed_size += FX_DIR_ENTRY_SIZE;
1083
1084
    if (media_ptr -> fx_media_fault_tolerant_enabled &&
1085
        (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
1086
    {
1087
1088
        /* Redirect this request to log file. */
1089
        status = _fx_fault_tolerant_add_dir_log(media_ptr, (ULONG64) logical_sector, changed_offset, changed_ptr, changed_size);
1090
    }
1091
    else
1092
    {
1093
#endif /* FX_ENABLE_FAULT_TOLERANT */
1094
1095
        /* Write the directory sector to the media.  */
1096
145359
        status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
1097
                                                   sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
1098
#ifdef FX_ENABLE_FAULT_TOLERANT
1099
    }
1100
#endif /* FX_ENABLE_FAULT_TOLERANT */
1101
1102
    /* Determine if an error occurred.  */
1103
145359
    if (status != FX_SUCCESS)
1104
    {
1105
1106
        /* Return the error status.  */
1107
4
        return(status);
1108
    }
1109
1110
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
1111
1112
    /* Determine if there is a previously found directory entry in the directory
1113
       search cache.  */
1114
145355
    if (media_ptr -> fx_media_last_found_name[0])
1115
    {
1116
1117
        /* Determine if the cached search directory entry matches the directory entry being
1118
           written.  */
1119
27092
        if ((entry_ptr -> fx_dir_entry_log_sector == media_ptr -> fx_media_last_found_entry.fx_dir_entry_log_sector) &&
1120
27075
            (entry_ptr -> fx_dir_entry_byte_offset == media_ptr -> fx_media_last_found_entry.fx_dir_entry_byte_offset))
1121
        {
1122
1123
            /* Yes, this entry is the same as the one currently in the directory search cache.
1124
               Update various fields in the directory search cache with the information being
1125
               written now.  */
1126
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_cluster =         entry_ptr -> fx_dir_entry_cluster;
1127
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_file_size =       entry_ptr -> fx_dir_entry_file_size;
1128
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_attributes =      entry_ptr -> fx_dir_entry_attributes;
1129
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_time =            entry_ptr -> fx_dir_entry_time;
1130
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_date =            entry_ptr -> fx_dir_entry_date;
1131
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_reserved =        entry_ptr -> fx_dir_entry_reserved;
1132
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time_ms = entry_ptr -> fx_dir_entry_created_time_ms;
1133
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time =    entry_ptr -> fx_dir_entry_created_time;
1134
7150
            media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_date =    entry_ptr -> fx_dir_entry_created_date;
1135
        }
1136
    }
1137
#endif
1138
1139
    /* Return success to the caller.  */
1140
145355
    return(FX_SUCCESS);
1141
}
1142