GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_entry_write.c Lines: 292 292 100.0 %
Date: 2024-03-11 05:15:45 Branches: 222 222 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
#ifdef FX_ENABLE_FAULT_TOLERANT
32
#include "fx_fault_tolerant.h"
33
#endif /* FX_ENABLE_FAULT_TOLERANT */
34
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _fx_directory_entry_write                           PORTABLE C      */
41
/*                                                           6.1.5        */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    William E. Lamie, Microsoft Corporation                             */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function writes the supplied directory entry to the specified  */
49
/*    logical sector and offset.                                          */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    media_ptr                             Media control block pointer   */
54
/*    entry_ptr                             Pointer to directory entry    */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    return status                                                       */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _fx_utility_FAT_entry_read            Read a new FAT entry          */
63
/*    _fx_utility_logical_sector_read       Read directory sector         */
64
/*    _fx_utility_logical_sector_write      Write directory sector        */
65
/*    _fx_utility_16_unsigned_write         Write a UINT from memory      */
66
/*    _fx_utility_32_unsigned_write         Write a ULONG from memory     */
67
/*    _fx_fault_tolerant_add_dir_log        Add directory redo log        */
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
/*  03-02-2021     William E. Lamie         Modified comment(s),          */
81
/*                                            resulting in version 6.1.5  */
82
/*                                                                        */
83
/**************************************************************************/
84
145406
UINT  _fx_directory_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr)
85
{
86
87
UCHAR *work_ptr, *sector_base_ptr;
88
UINT   status, temp, entry, delete_flag;
89
UINT   i, j, k, l, card, len, dotfound, dotpos, match;
90
UCHAR  checksum, eof_marker;
91
CHAR   alpha;
92
CHAR   shortname[FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE + 1];
93
ULONG  logical_sector, relative_sector;
94
ULONG  byte_offset;
95
ULONG  cluster, next_cluster;
96
97
98
#ifdef FX_ENABLE_FAULT_TOLERANT
99
UCHAR *changed_ptr;
100
UINT   changed_size;
101
ULONG  changed_offset;
102
#endif /* FX_ENABLE_FAULT_TOLERANT */
103
104
105
#ifndef FX_MEDIA_STATISTICS_DISABLE
106
107
    /* Increment the number of directory entry write requests.  */
108
145406
    media_ptr -> fx_media_directory_entry_writes++;
109
#endif
110
111
    /* Extended port-specific processing macro, which is by default defined to white space.  */
112

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

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

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

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

1205
        if (((UCHAR)shortname[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (delete_flag == FX_FALSE))
405
        {
406
407
            /* Change to 0x8F to be compatible with what DOS does.  */
408
11
            shortname[0] =  (CHAR)0x8F;
409
        }
410
411
        /* Loop to convert the new short file name to upper case.  */
412
14460
        for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
413
        {
414
415
            /* Pickup shortname character.  */
416
13255
            alpha = shortname[i];
417
418
            /* Determine if character is lower case.  */
419

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

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

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

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

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

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

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