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

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
10
/**************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   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
/*  RELEASE HISTORY                                                       */
75
/*                                                                        */
76
/*    DATE              NAME                      DESCRIPTION             */
77
/*                                                                        */
78
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
79
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
80
/*                                            resulting in version 6.1    */
81
/*  03-02-2021     William E. Lamie         Modified comment(s),          */
82
/*                                            resulting in version 6.1.5  */
83
/*                                                                        */
84
/**************************************************************************/
85
145406
UINT  _fx_directory_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr)
86
{
87
88
UCHAR *work_ptr, *sector_base_ptr;
89
UINT   status, temp, entry, delete_flag;
90
UINT   i, j, k, l, card, len, dotfound, dotpos, match;
91
UCHAR  checksum, eof_marker;
92
CHAR   alpha;
93
CHAR   shortname[FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE + 1];
94
ULONG  logical_sector, relative_sector;
95
ULONG  byte_offset;
96
ULONG  cluster, next_cluster;
97
98
99
#ifdef FX_ENABLE_FAULT_TOLERANT
100
UCHAR *changed_ptr;
101
UINT   changed_size;
102
ULONG  changed_offset;
103
#endif /* FX_ENABLE_FAULT_TOLERANT */
104
105
106
#ifndef FX_MEDIA_STATISTICS_DISABLE
107
108
    /* Increment the number of directory entry write requests.  */
109
145406
    media_ptr -> fx_media_directory_entry_writes++;
110
#endif
111
112
    /* Extended port-specific processing macro, which is by default defined to white space.  */
113

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

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

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

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

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

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

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

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

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

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

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

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