GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_directory_free_search.c Lines: 204 204 100.0 %
Date: 2024-03-11 05:15:45 Branches: 176 176 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
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _fx_directory_free_search                           PORTABLE C      */
38
/*                                                           6.1.12       */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    William E. Lamie, Microsoft Corporation                             */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function searches the media for a free directory entry.        */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    media_ptr                             Media control block pointer   */
50
/*    directory_ptr                         Pointer to directory to       */
51
/*                                            search in                   */
52
/*    entry_ptr                             Pointer to directory entry    */
53
/*                                            record                      */
54
/*                                                                        */
55
/*  OUTPUT                                                                */
56
/*                                                                        */
57
/*    return status                                                       */
58
/*                                                                        */
59
/*  CALLS                                                                 */
60
/*                                                                        */
61
/*    _fx_directory_entry_read              Read entries from directory   */
62
/*    _fx_directory_entry_write             Write entries to directory    */
63
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
64
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
65
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
66
/*    _fx_utility_logical_sector_flush      Flush logical sector cache    */
67
/*    _fx_utility_logical_sector_read       Read logical sector           */
68
/*    _fx_utility_logical_sector_write      Write logical sector          */
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
/*  07-29-2022     Bhupendra Naphade        Modified comment(s),          */
82
/*                                            updated available cluster   */
83
/*                                            check for sub directory,    */
84
/*                                            resulting in version 6.1.12 */
85
/*                                                                        */
86
/**************************************************************************/
87
74847
UINT  _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr)
88
{
89
90
ULONG         i, j;
91
UCHAR        *work_ptr;
92
UINT          status, total_entries;
93
ULONG         entry_sector, entry_offset;
94
ULONG         FAT_index, FAT_value;
95
ULONG         cluster, total_clusters, clusters_needed;
96
ULONG         first_new_cluster, last_cluster, clusters;
97
ULONG         directory_index;
98
ULONG         directory_entries;
99
ULONG         logical_sector;
100
FX_DIR_ENTRY *search_dir_ptr;
101
ULONG         free_entry_start;
102
UINT          sectors;
103
104
FX_INT_SAVE_AREA
105
106
107
108
#ifndef FX_MEDIA_STATISTICS_DISABLE
109
110
    /* Increment the number of directory free entry search requests.  */
111
74847
    media_ptr -> fx_media_directory_free_searches++;
112
#endif
113
114
    /* Initialize the entry sector values.  */
115
74847
    entry_sector = entry_offset = 0;
116
117
    /* Set the long file name flag to false.  */
118
74847
    entry_ptr -> fx_dir_entry_long_name_present =  0;
119
120
    /* Are there leading dots?  */
121
74847
    if (entry_ptr -> fx_dir_entry_name[0] == '.')
122
    {
123
124
        /* Is there more than 1 dot?  */
125
7
        if (entry_ptr -> fx_dir_entry_name[1] == '.')
126
        {
127
            /* Yes, consider the name invalid.  */
128
1
            return(FX_INVALID_NAME);
129
        }
130
    }
131
132
    /* Determine if a long file name is present.  */
133
761992
    for (i = 0, j = 0; entry_ptr -> fx_dir_entry_name[i]; i++)
134
    {
135
136
        /* Check for upper-case characters.  */
137

687147
        if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z'))
138
        {
139
494738
            continue;
140
        }
141
        /* Check for numeric characters.  */
142

192409
        else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9'))
143
        {
144
121505
            continue;
145
        }
146
        /* Check for any lower-case characters.  */
147

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

74845
    if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0))
241
    {
242
243
        /* Initialize the total entries to 1.  */
244
73731
        total_entries = 1;
245
246
        /* Check for special instance of long file name.  */
247

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

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

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

36672
                    if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters))
703
                    {
704
705
                        /* Return the bad status.  */
706
3
                        return(FX_FAT_READ_ERROR);
707
                    }
708
709
                    /* Save the last valid cluster.  */
710
36669
                    last_cluster =  cluster;
711
712
                    /* Setup for the next cluster.  */
713
36669
                    cluster =  FAT_value;
714
                }
715
716
                /* Decrease the available clusters in the media.  */
717
11412
                media_ptr -> fx_media_available_clusters =  media_ptr -> fx_media_available_clusters - clusters_needed;
718
719
                /* Increase the number of directory entries.  */
720
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;
721
722
                /* Determine if we need to reset the free entry start since we changed the
723
                   number of directory entries.  If the last entry was not free, then we
724
                   should definitely reset the free entry start.  */
725

11412
                if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)))
726
                {
727
728
                    /* Reset the free entry start to indicate we haven't found a starting free entry yet.  */
729
11134
                    free_entry_start =  directory_entries;
730
                }
731
732
                /* Update the directory size field.  */
733
11412
                directory_ptr -> fx_dir_entry_file_size =  directory_entries;
734
735
                /* Defer the update of the FAT entry and the last cluster of the current
736
                   directory entry until after the new cluster is initialized and written out.  */
737
738
                /* Determine if a FAT32 is present.  */
739

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