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

687147
        if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z'))
151
        {
152
494738
            continue;
153
        }
154
        /* Check for numeric characters.  */
155

192409
        else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9'))
156
        {
157
121505
            continue;
158
        }
159
        /* Check for any lower-case characters.  */
160

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

74845
    if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0))
254
    {
255
256
        /* Initialize the total entries to 1.  */
257
73731
        total_entries = 1;
258
259
        /* Check for special instance of long file name.  */
260

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

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

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

36672
                    if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters))
716
                    {
717
718
                        /* Return the bad status.  */
719
3
                        return(FX_FAT_READ_ERROR);
720
                    }
721
722
                    /* Save the last valid cluster.  */
723
36669
                    last_cluster =  cluster;
724
725
                    /* Setup for the next cluster.  */
726
36669
                    cluster =  FAT_value;
727
                }
728
729
                /* Decrease the available clusters in the media.  */
730
11412
                media_ptr -> fx_media_available_clusters =  media_ptr -> fx_media_available_clusters - clusters_needed;
731
732
                /* Increase the number of directory entries.  */
733
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;
734
735
                /* Determine if we need to reset the free entry start since we changed the
736
                   number of directory entries.  If the last entry was not free, then we
737
                   should definitely reset the free entry start.  */
738

11412
                if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)))
739
                {
740
741
                    /* Reset the free entry start to indicate we haven't found a starting free entry yet.  */
742
11134
                    free_entry_start =  directory_entries;
743
                }
744
745
                /* Update the directory size field.  */
746
11412
                directory_ptr -> fx_dir_entry_file_size =  directory_entries;
747
748
                /* Defer the update of the FAT entry and the last cluster of the current
749
                   directory entry until after the new cluster is initialized and written out.  */
750
751
                /* Determine if a FAT32 is present.  */
752

11412
                if ((media_ptr -> fx_media_32_bit_FAT) && (search_dir_ptr == FX_NULL))
753
                {
754
755
                    /* Change root directory entry count - FAT32 has a variable sized root directory.  */
756
7028
                    media_ptr -> fx_media_root_directory_entries =  directory_entries;
757
                }
758
759
                /* At this point, link up the last cluster with the new cluster.  */
760
11412
                status =  _fx_utility_FAT_entry_write(media_ptr, last_cluster, first_new_cluster);
761
762
                /* Check the return value.  */
763
11412
                if (status != FX_SUCCESS)
764
                {
765
766
                    /* Return the error status.  */
767
1
                    return(status);
768
                }
769
770
#ifdef FX_FAULT_TOLERANT
771
772
                /* Flush the cached individual FAT entries */
773
                _fx_utility_FAT_flush(media_ptr);
774
#endif
775
            }
776
        }
777
901333
    } while (directory_index < directory_entries);
778
779
    /* Return FX_NO_MORE_SPACE status to the caller.  */
780
87
    return(FX_NO_MORE_SPACE);
781
}
782