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

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Directory                                                           */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "fx_api.h"
29
#include "fx_system.h"
30
#include "fx_directory.h"
31
#include "fx_utility.h"
32
33
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _fx_directory_free_search                           PORTABLE C      */
39
/*                                                           6.1.12       */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    William E. Lamie, Microsoft Corporation                             */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function searches the media for a free directory entry.        */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    media_ptr                             Media control block pointer   */
51
/*    directory_ptr                         Pointer to directory to       */
52
/*                                            search in                   */
53
/*    entry_ptr                             Pointer to directory entry    */
54
/*                                            record                      */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    return status                                                       */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _fx_directory_entry_read              Read entries from directory   */
63
/*    _fx_directory_entry_write             Write entries to directory    */
64
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
65
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
66
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
67
/*    _fx_utility_logical_sector_flush      Flush logical sector cache    */
68
/*    _fx_utility_logical_sector_read       Read logical sector           */
69
/*    _fx_utility_logical_sector_write      Write logical sector          */
70
/*                                                                        */
71
/*  CALLED BY                                                             */
72
/*                                                                        */
73
/*    FileX System Functions                                              */
74
/*                                                                        */
75
/**************************************************************************/
76
74847
UINT  _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr)
77
{
78
79
ULONG         i, j;
80
UCHAR        *work_ptr;
81
UINT          status, total_entries;
82
ULONG         entry_sector, entry_offset;
83
ULONG         FAT_index, FAT_value;
84
ULONG         cluster, total_clusters, clusters_needed;
85
ULONG         first_new_cluster, last_cluster, clusters;
86
ULONG         directory_index;
87
ULONG         directory_entries;
88
ULONG         logical_sector;
89
FX_DIR_ENTRY *search_dir_ptr;
90
ULONG         free_entry_start;
91
UINT          sectors;
92
93
FX_INT_SAVE_AREA
94
95
96
97
#ifndef FX_MEDIA_STATISTICS_DISABLE
98
99
    /* Increment the number of directory free entry search requests.  */
100
74847
    media_ptr -> fx_media_directory_free_searches++;
101
#endif
102
103
    /* Initialize the entry sector values.  */
104
74847
    entry_sector = entry_offset = 0;
105
106
    /* Set the long file name flag to false.  */
107
74847
    entry_ptr -> fx_dir_entry_long_name_present =  0;
108
109
    /* Are there leading dots?  */
110
74847
    if (entry_ptr -> fx_dir_entry_name[0] == '.')
111
    {
112
113
        /* Is there more than 1 dot?  */
114
7
        if (entry_ptr -> fx_dir_entry_name[1] == '.')
115
        {
116
            /* Yes, consider the name invalid.  */
117
1
            return(FX_INVALID_NAME);
118
        }
119
    }
120
121
    /* Determine if a long file name is present.  */
122
761992
    for (i = 0, j = 0; entry_ptr -> fx_dir_entry_name[i]; i++)
123
    {
124
125
        /* Check for upper-case characters.  */
126

687147
        if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z'))
127
        {
128
494738
            continue;
129
        }
130
        /* Check for numeric characters.  */
131

192409
        else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9'))
132
        {
133
121505
            continue;
134
        }
135
        /* Check for any lower-case characters.  */
136

70904
        else if ((entry_ptr -> fx_dir_entry_name[i] >= 'a') && (entry_ptr -> fx_dir_entry_name[i] <= 'z'))
137
        {
138
15878
            entry_ptr -> fx_dir_entry_long_name_present =  1;
139
        }
140
        /* Check for a space in the middle of the name.  */
141
55026
        else if (entry_ptr -> fx_dir_entry_name[i] == ' ')
142
        {
143
15
            entry_ptr -> fx_dir_entry_long_name_present = 1;
144
        }
145
        /* Check for a dot in the name.  */
146
55011
        else if (entry_ptr -> fx_dir_entry_name[i] == '.')
147
        {
148
            /* Determine if this is the first dot detected.  */
149
54497
            if (j == 0)
150
            {
151
                /* First dot, remember where it was.  */
152
54487
                j = i;
153
154
                /* Determine if this is a leading dot.  */
155
54487
                if (i == 0)
156
                {
157
158
                    /* Leading dot detected, treat as a long filename.  */
159
6
                    entry_ptr -> fx_dir_entry_long_name_present =  1;
160
                }
161
            }
162
            else
163
            {
164
                /* Second dot detected, must have a long file name.  */
165
10
                entry_ptr -> fx_dir_entry_long_name_present = 1;
166
            }
167
        }
168
        /* Check for a special 0xE5 character.  */
169
514
        else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == (UCHAR)0xE5)
170
        {
171
10
            entry_ptr -> fx_dir_entry_long_name_present = 1;
172
        }
173
        /* Check for code point value greater than 127.  */
174
504
        else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] > (UCHAR)127)
175
        {
176
1
            continue;
177
        }
178
        /* Check for any special characters.  */
179
503
        else if ((entry_ptr -> fx_dir_entry_name[i] == '~') ||
180
495
                 (entry_ptr -> fx_dir_entry_name[i] == '-') ||
181
423
                 (entry_ptr -> fx_dir_entry_name[i] == '_') ||
182
23
                 (entry_ptr -> fx_dir_entry_name[i] == '}') ||
183
22
                 (entry_ptr -> fx_dir_entry_name[i] == '{') ||
184
21
                 (entry_ptr -> fx_dir_entry_name[i] == '(') ||
185
19
                 (entry_ptr -> fx_dir_entry_name[i] == ')') ||
186
17
                 (entry_ptr -> fx_dir_entry_name[i] == '`') ||
187
16
                 (entry_ptr -> fx_dir_entry_name[i] == '\'') ||
188
14
                 (entry_ptr -> fx_dir_entry_name[i] == '!') ||
189
13
                 (entry_ptr -> fx_dir_entry_name[i] == '#') ||
190
12
                 (entry_ptr -> fx_dir_entry_name[i] == '$') ||
191
11
                 (entry_ptr -> fx_dir_entry_name[i] == '&') ||
192
10
                 (entry_ptr -> fx_dir_entry_name[i] == '@') ||
193
9
                 (entry_ptr -> fx_dir_entry_name[i] == '^') ||
194
8
                 (entry_ptr -> fx_dir_entry_name[i] == '%'))
195
        {
196
496
            continue;
197
        }
198
        /* Check for long filename special characters.  */
199
7
        else if ((entry_ptr -> fx_dir_entry_name[i] == '+') ||
200
6
                 (entry_ptr -> fx_dir_entry_name[i] == ',') ||
201
5
                 (entry_ptr -> fx_dir_entry_name[i] == ';') ||
202
4
                 (entry_ptr -> fx_dir_entry_name[i] == '=') ||
203
3
                 (entry_ptr -> fx_dir_entry_name[i] == '[') ||
204
2
                 (entry_ptr -> fx_dir_entry_name[i] == ']'))
205
        {
206
6
            entry_ptr -> fx_dir_entry_long_name_present = 1;
207
        }
208
        /* Something is wrong with the supplied name.  */
209
        else
210
        {
211
1
            return(FX_INVALID_NAME);
212
        }
213
    }
214
215
    /* Determine if a dot was found.  */
216
74845
    if (j != 0)
217
    {
218
219
        /* Yes, Determine if the extension exceeds a 3 character extension.  */
220
54481
        if ((i - j) > 4)
221
        {
222
223
            /* Yes, long file name is present.  */
224
5
            entry_ptr -> fx_dir_entry_long_name_present = 1;
225
        }
226
    }
227
228
    /* Calculate the total entries needed.  */
229

74845
    if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0))
230
    {
231
232
        /* Initialize the total entries to 1.  */
233
73731
        total_entries = 1;
234
235
        /* Check for special instance of long file name.  */
236

73731
        if ((j >= 9) || ((i - j) >= 9))
237
        {
238
239
            /* The dot is after 8 character or there is no dot and the name
240
               is greater than 8 character. */
241
7
            entry_ptr -> fx_dir_entry_long_name_present = 1;
242
7
            total_entries = 2;
243
        }
244
    }
245
    else
246
    {
247
248
        /* Long file name is present, calculate how many entries are needed
249
           to represent it.  */
250
1114
        if (i % 13 == 0)
251
        {
252
            /* Exact fit, just add one for the 8.3 short name.  */
253
27
            total_entries = i / 13 + 1;
254
        }
255
        else
256
        {
257
            /* Non-exact fit, add two for 8.3 short name and overlap.  */
258
1087
            total_entries = i / 13 + 2;
259
        }
260
    }
261
262
    /* Determine if the search is in the root directory or in a
263
       sub-directory.  Note: the directory search function clears the
264
       first character of the name for the root directory.  */
265
74845
    if (directory_ptr -> fx_dir_entry_name[0])
266
    {
267
268
        /* Search for a free entry in a sub-directory.  */
269
270
        /* Pickup the number of entries in this directory.  This was placed
271
           into the unused file size field.  */
272
14739
        directory_entries =  (ULONG)directory_ptr -> fx_dir_entry_file_size;
273
274
        /* Point the search directory pointer to this entry.  */
275
14739
        search_dir_ptr =  directory_ptr;
276
277
        /* Ensure that the search directory's last search cluster is cleared.  */
278
14739
        search_dir_ptr -> fx_dir_entry_last_search_cluster =  0;
279
280
        /* Set the initial index to 2, since the first two directory entries are
281
           always allocated.  */
282
14739
        directory_index =  2;
283
    }
284
    else
285
    {
286
287
        /* Find a free entry in the root directory.  */
288
289
        /* Setup the number of directory entries.  */
290
60106
        directory_entries =  (ULONG)media_ptr -> fx_media_root_directory_entries;
291
292
        /* Set the search pointer to NULL since we are working off of the
293
           root directory.  */
294
60106
        search_dir_ptr =  FX_NULL;
295
296
        /* Set the initial index to 0, since the first entry of the root directory is valid.  */
297
60106
        directory_index =  0;
298
    }
299
300
    /* Loop through entries in the search directory.  Yes, this is a
301
       linear search!  */
302
74845
    free_entry_start = directory_entries;
303
    do
304
    {
305
306
        /* Read an entry from the directory.  */
307
976091
        status =  _fx_directory_entry_read(media_ptr, search_dir_ptr, &directory_index, entry_ptr);
308
309
        /* Check for error status.  */
310
976091
        if (status != FX_SUCCESS)
311
        {
312
7
            return(status);
313
        }
314
315
        /* Determine if this is an empty entry.  */
316

976084
        if ((((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)) ||
317
975528
            ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE))
318
        {
319
320
            /* Determine how many entries are needed.  */
321
77142
            if (total_entries > 1)
322
            {
323
324
                /* Multiple entries are needed for long file names.  Mark this
325
                   entry as free. */
326
3420
                if (entry_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
327
                {
328
329
2890
                    entry_ptr -> fx_dir_entry_long_name_present =  0;
330
2890
                    entry_ptr -> fx_dir_entry_name[0] =      (CHAR)FX_DIR_ENTRY_FREE;
331
2890
                    entry_ptr -> fx_dir_entry_name[1] =      (CHAR)0;
332
333
                    /* Write out the directory entry.  */
334
2890
                    status = _fx_directory_entry_write(media_ptr, entry_ptr);
335
2890
                    if(status != FX_SUCCESS)
336
                    {
337
1
                        return(status);
338
                    }
339
340
                    /* Note that for long names we need to avoid holes in the middle,
341
                       i.e. entries must be logically contiguous.  */
342
                }
343
            }
344
345
            /* Determine if we are at the first free entry.  */
346
77141
            if (free_entry_start == directory_entries)
347
            {
348
349
                /* Remember the start of the free entry.  */
350
74861
                free_entry_start =  directory_index;
351
74861
                entry_sector =      (ULONG)entry_ptr -> fx_dir_entry_log_sector;
352
74861
                entry_offset  =     entry_ptr -> fx_dir_entry_byte_offset;
353
            }
354
355
            /* Determine if there are enough free entries to satisfy the request.  */
356
77141
            if ((directory_index - free_entry_start + 1) >= total_entries)
357
            {
358
359
                /* Found an empty slot.  Most pertinent information is already
360
                   in the entry structure.  */
361
362
                /* Setup the the sector and the offset.  */
363
74737
                entry_ptr -> fx_dir_entry_log_sector =      entry_sector;
364
74737
                entry_ptr -> fx_dir_entry_byte_offset =     entry_offset;
365
366
                /* Initialize the additional directory entries.  */
367
74737
                entry_ptr -> fx_dir_entry_reserved =            0;
368
74737
                entry_ptr -> fx_dir_entry_created_time_ms =     0;
369
370
                /* Lockout interrupts for time/date access.  */
371
74737
                FX_DISABLE_INTS
372
373
74737
                entry_ptr -> fx_dir_entry_created_time =        _fx_system_time;
374
74737
                entry_ptr -> fx_dir_entry_created_date =        _fx_system_date;
375
74737
                entry_ptr -> fx_dir_entry_last_accessed_date =  _fx_system_date;
376
377
                /* Restore interrupts.  */
378
74737
                FX_RESTORE_INTS
379
380
                /* Determine if a long file name is present.  */
381
74737
                if (total_entries == 1)
382
                {
383
73722
                    entry_ptr -> fx_dir_entry_long_name_present =  0;
384
                }
385
                else
386
                {
387
1015
                    entry_ptr -> fx_dir_entry_long_name_present =  1;
388
                }
389
390
                /* Return a successful completion.  */
391
74737
                return(FX_SUCCESS);
392
            }
393
        }
394
        else
395
        {
396
397
            /* Reset the free entry start.  */
398
898942
            free_entry_start =  directory_entries;
399
        }
400
401
        /* Move to the next entry.  */
402
901346
        directory_index++;
403
404
        /* Determine if we have exceeded the number of entries in the current directory.  */
405
901346
        if (directory_index >= directory_entries)
406
        {
407
408
            /* Calculate how many sectors we need for the new directory entry.  */
409
11511
            sectors =  ((total_entries * FX_DIR_ENTRY_SIZE) + (media_ptr -> fx_media_bytes_per_sector - 1))/
410
11511
                                                                            media_ptr -> fx_media_bytes_per_sector;
411
412
            /* Now calculate how many clusters we need for the new directory entry.  */
413
11511
            clusters_needed = (sectors + (media_ptr -> fx_media_sectors_per_cluster - 1)) / media_ptr -> fx_media_sectors_per_cluster;
414
415
            /* Not enough empty entries were found.  If the specified directory is a sub-directory,
416
               attempt to allocate another cluster to it.  */
417

11511
            if (((search_dir_ptr) || (media_ptr -> fx_media_32_bit_FAT)) && (media_ptr -> fx_media_available_clusters >= clusters_needed))
418
            {
419
420
                /* Search for the additional clusters we need.  */
421
11424
                first_new_cluster =  0;
422
11424
                total_clusters =     media_ptr -> fx_media_total_clusters;
423
11424
                last_cluster =       0;
424
11424
                FAT_index    =       media_ptr -> fx_media_cluster_search_start;
425
11424
                clusters =           clusters_needed;
426
427
                /* Loop to find the needed clusters.  */
428
22921
                while (clusters)
429
                {
430
431
                    /* Decrease the cluster count.  */
432
11504
                    clusters--;
433
434
                    /* Loop to find the first available cluster.  */
435
                    do
436
                    {
437
438
                        /* Make sure we stop looking after one pass through the FAT table.  */
439
11823
                        if (!total_clusters)
440
                        {
441
442
                            /* Something is wrong with the media - the desired clusters were
443
                               not found in the FAT table.  */
444
1
                            return(FX_NO_MORE_SPACE);
445
                        }
446
447
                        /* Read FAT entry.  */
448
11822
                        status =  _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
449
450
                        /* Check for a bad status.  */
451
11822
                        if (status != FX_SUCCESS)
452
                        {
453
454
                            /* Return the bad status.  */
455
1
                            return(status);
456
                        }
457
458
                        /* Decrement the total cluster count.  */
459
11821
                        total_clusters--;
460
461
                        /* Determine if the FAT entry is free.  */
462
11821
                        if (FAT_value == FX_FREE_CLUSTER)
463
                        {
464
465
                            /* Move cluster search pointer forward.  */
466
11502
                            media_ptr -> fx_media_cluster_search_start =  FAT_index + 1;
467
468
                            /* Determine if this needs to be wrapped.  */
469
11502
                            if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
470
                            {
471
472
                                /* Wrap the search to the beginning FAT entry.  */
473
2
                                media_ptr -> fx_media_cluster_search_start =  FX_FAT_ENTRY_START;
474
                            }
475
476
                            /* Break this loop.  */
477
11502
                            break;
478
                        }
479
                        else
480
                        {
481
482
                            /* FAT entry is not free... Advance the FAT index.  */
483
319
                            FAT_index++;
484
485
                            /* Determine if we need to wrap the FAT index around.  */
486
319
                            if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
487
                            {
488
489
                                /* Wrap the search to the beginning FAT entry.  */
490
12
                                FAT_index =  FX_FAT_ENTRY_START;
491
                            }
492
                        }
493
                    } while (FX_TRUE);
494
495
                    /* We found an available cluster.  We now need to clear all of entries in
496
                       each of the cluster's sectors.  */
497
498
                    /* Calculate the logical sector of this cluster.  */
499
11502
                    logical_sector =  ((ULONG) media_ptr -> fx_media_data_sector_start) +
500
11502
                                       ((((ULONG) FAT_index) - FX_FAT_ENTRY_START) *
501
11502
                                       ((ULONG) media_ptr -> fx_media_sectors_per_cluster));
502
503
                    /* Pickup the number of sectors for the next directory cluster.  */
504
11502
                    sectors =  media_ptr -> fx_media_sectors_per_cluster;
505
506
                    /* Read the logical sector just for cache reasons.  */
507
11502
                    status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
508
11502
                                                              media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
509
510
                    /* Check the return value.  */
511
11502
                    if (status != FX_SUCCESS)
512
                    {
513
514
                        /* Return the error status.  */
515
1
                        return(status);
516
                    }
517
518
                    /* Clear the entire first sector of the new sub-directory cluster.  */
519
11501
                    work_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer;
520
11501
                    i =  0;
521
379629
                    while (i < media_ptr -> fx_media_bytes_per_sector)
522
                    {
523
524
                        /* Clear 4 bytes.  */
525
368128
                        *((ULONG *)work_ptr) =  (ULONG)0;
526
527
                        /* Increment pointer.  */
528
368128
                        work_ptr =  work_ptr + sizeof(ULONG);
529
530
                        /* Increment counter.  */
531
368128
                        i =  i + (ULONG)sizeof(ULONG);
532
                    }
533
534
                    /* Write the logical sector to ensure the zeros are written.  */
535
11501
                    status =  _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
536
11501
                                                               media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
537
538
                    /* Determine if the write was successful.  */
539
11501
                    if (status != FX_SUCCESS)
540
                    {
541
542
                        /* Return the error code.  */
543
1
                        return(status);
544
                    }
545
546
                    /* Determine if there are more sectors to clear in the first cluster of the new
547
                       sub-directory.  */
548
11500
                    if (sectors > 1)
549
                    {
550
551
                        /* Yes, invalidate all cached sectors that are contained in the newly allocated first
552
                           cluster of the directory.  */
553
554
                        /* Flush the internal logical sector cache.  */
555
47
                        status =  _fx_utility_logical_sector_flush(media_ptr, (ULONG64) (logical_sector + 1), (ULONG64) (sectors - 1), FX_TRUE);
556
557
                        /* Determine if the flush was successful.  */
558
47
                        if (status != FX_SUCCESS)
559
                        {
560
561
                            /* Return the error code.  */
562
1
                            return(status);
563
                        }
564
565
                        /* Clear all additional sectors of new sub-directory.  */
566
46
                        sectors--;
567
91
                        while (sectors)
568
                        {
569
570
#ifndef FX_MEDIA_STATISTICS_DISABLE
571
572
                            /* Increment the number of driver write sector(s) requests.  */
573
46
                            media_ptr -> fx_media_driver_write_requests++;
574
#endif
575
576
                            /* Build Write request to the driver.  */
577
46
                            media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
578
46
                            media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
579
46
                            media_ptr -> fx_media_driver_buffer =           media_ptr -> fx_media_memory_buffer;
580
46
                            media_ptr -> fx_media_driver_logical_sector =   (ULONG)logical_sector + ((ULONG)sectors);
581
46
                            media_ptr -> fx_media_driver_sectors =          1;
582
46
                            media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
583
584
                            /* Set the system write flag since we are writing a directory sector.  */
585
46
                            media_ptr -> fx_media_driver_system_write =  FX_TRUE;
586
587
                            /* If trace is enabled, insert this event into the trace buffer.  */
588
                            FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, ((ULONG)logical_sector) + ((ULONG)sectors), 1, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
589
590
                            /* Invoke the driver to write the sector.  */
591
46
                            (media_ptr -> fx_media_driver_entry) (media_ptr);
592
593
                            /* Clear the system write flag.  */
594
46
                            media_ptr -> fx_media_driver_system_write =  FX_FALSE;
595
596
                            /* Determine if an error occurred.  */
597
46
                            if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
598
                            {
599
600
                                /* Return error code.  */
601
1
                                return(media_ptr -> fx_media_driver_status);
602
                            }
603
604
                            /* Decrease the number of sectors to clear.  */
605
45
                            sectors--;
606
                        }
607
                    }
608
609
                    /* Determine if we have found the first new cluster yet.  */
610
11498
                    if (first_new_cluster == 0)
611
                    {
612
613
                        /* Remember the first new cluster. */
614
11418
                        first_new_cluster =  FAT_index;
615
                    }
616
617
                    /* Check for a valid last cluster to link.  */
618
11498
                    if (last_cluster)
619
                    {
620
621
                        /* Normal condition - link the last cluster with the new
622
                           found cluster.  */
623
80
                        status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index);
624
625
                        /* Check for a bad FAT write status.  */
626
80
                        if (status !=  FX_SUCCESS)
627
                        {
628
629
                            /* Return the bad status.  */
630
1
                            return(status);
631
                        }
632
                    }
633
634
                    /* Otherwise, remember the new FAT index as the last.  */
635
11497
                    last_cluster =  FAT_index;
636
637
                    /* Move to the next FAT entry.  */
638
11497
                    FAT_index =  media_ptr -> fx_media_cluster_search_start;
639
                }
640
641
                /* Place an end-of-file marker on the last cluster.  */
642
11417
                status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
643
644
                /* Check for a bad FAT write status.  */
645
11417
                if (status !=  FX_SUCCESS)
646
                {
647
648
                    /* Return the bad status.  */
649
1
                    return(status);
650
                }
651
652
#ifdef FX_FAULT_TOLERANT
653
654
                /* Ensure the new FAT chain is properly written to the media.  */
655
656
                /* Flush the cached individual FAT entries */
657
                _fx_utility_FAT_flush(media_ptr);
658
#endif
659
660
                /* Now the new cluster needs to be linked to the sub-directory.  */
661
11416
                if (search_dir_ptr)
662
                {
663
4388
                    cluster = search_dir_ptr -> fx_dir_entry_cluster;
664
                }
665
                else
666
                {
667
7028
                    cluster = media_ptr -> fx_media_root_cluster_32;
668
                }
669
670
                /* Initialize loop variables.  */
671
11416
                last_cluster =  0;
672
11416
                i =  0;
673
674
                /* Follow the link of FAT entries.  */
675
48085
                while (cluster < media_ptr -> fx_media_fat_reserved)
676
                {
677
678
                    /* Read the current cluster entry from the FAT.  */
679
36673
                    status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
680
36673
                    i++;
681
682
                    /* Check the return value.  */
683
36673
                    if (status != FX_SUCCESS)
684
                    {
685
686
                        /* Return the error status.  */
687
1
                        return(status);
688
                    }
689
690
                    /* Determine if the FAT read was invalid.  */
691

36672
                    if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters))
692
                    {
693
694
                        /* Return the bad status.  */
695
3
                        return(FX_FAT_READ_ERROR);
696
                    }
697
698
                    /* Save the last valid cluster.  */
699
36669
                    last_cluster =  cluster;
700
701
                    /* Setup for the next cluster.  */
702
36669
                    cluster =  FAT_value;
703
                }
704
705
                /* Decrease the available clusters in the media.  */
706
11412
                media_ptr -> fx_media_available_clusters =  media_ptr -> fx_media_available_clusters - clusters_needed;
707
708
                /* Increase the number of directory entries.  */
709
11412
                directory_entries =  directory_entries + ((clusters_needed * media_ptr -> fx_media_sectors_per_cluster) * media_ptr -> fx_media_bytes_per_sector) / FX_DIR_ENTRY_SIZE;
710
711
                /* Determine if we need to reset the free entry start since we changed the
712
                   number of directory entries.  If the last entry was not free, then we
713
                   should definitely reset the free entry start.  */
714

11412
                if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)))
715
                {
716
717
                    /* Reset the free entry start to indicate we haven't found a starting free entry yet.  */
718
11134
                    free_entry_start =  directory_entries;
719
                }
720
721
                /* Update the directory size field.  */
722
11412
                directory_ptr -> fx_dir_entry_file_size =  directory_entries;
723
724
                /* Defer the update of the FAT entry and the last cluster of the current
725
                   directory entry until after the new cluster is initialized and written out.  */
726
727
                /* Determine if a FAT32 is present.  */
728

11412
                if ((media_ptr -> fx_media_32_bit_FAT) && (search_dir_ptr == FX_NULL))
729
                {
730
731
                    /* Change root directory entry count - FAT32 has a variable sized root directory.  */
732
7028
                    media_ptr -> fx_media_root_directory_entries =  directory_entries;
733
                }
734
735
                /* At this point, link up the last cluster with the new cluster.  */
736
11412
                status =  _fx_utility_FAT_entry_write(media_ptr, last_cluster, first_new_cluster);
737
738
                /* Check the return value.  */
739
11412
                if (status != FX_SUCCESS)
740
                {
741
742
                    /* Return the error status.  */
743
1
                    return(status);
744
                }
745
746
#ifdef FX_FAULT_TOLERANT
747
748
                /* Flush the cached individual FAT entries */
749
                _fx_utility_FAT_flush(media_ptr);
750
#endif
751
            }
752
        }
753
901333
    } while (directory_index < directory_entries);
754
755
    /* Return FX_NO_MORE_SPACE status to the caller.  */
756
87
    return(FX_NO_MORE_SPACE);
757
}
758