GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_best_effort_allocate.c Lines: 111 111 100.0 %
Date: 2024-01-10 21:53:23 Branches: 52 52 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
/**   File                                                                */
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_file.h"
31
#include "fx_utility.h"
32
#include "fx_directory.h"
33
#ifdef FX_ENABLE_FAULT_TOLERANT
34
#include "fx_fault_tolerant.h"
35
#endif /* FX_ENABLE_FAULT_TOLERANT */
36
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _fx_file_extended_best_effort_allocate              PORTABLE C      */
43
/*                                                           6.1          */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    William E. Lamie, Microsoft Corporation                             */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function attempts to allocate the number of consecutive        */
51
/*    clusters required to satisfy the user's request.  If there are not  */
52
/*    enough clusters, the largest set of clusters are allocated and      */
53
/*    linked to the file.  If there are no free clusters, an error        */
54
/*    code is returned to the caller.                                     */
55
/*                                                                        */
56
/*  INPUT                                                                 */
57
/*                                                                        */
58
/*    file_ptr                              File control block pointer    */
59
/*    size                                  Number of bytes to allocate   */
60
/*    actual_size_allocated                 Number of bytes allocated     */
61
/*                                                                        */
62
/*  OUTPUT                                                                */
63
/*                                                                        */
64
/*    return status                                                       */
65
/*                                                                        */
66
/*  CALLS                                                                 */
67
/*                                                                        */
68
/*    _fx_directory_entry_write             Update directory entry        */
69
/*    _fx_utility_exFAT_bitmap_flush        Flush exFAT allocation bitmap */
70
/*    _fx_utility_exFAT_bitmap_free_cluster_find                          */
71
/*                                            Find exFAT free cluster     */
72
/*    _fx_utility_exFAT_cluster_state_get   Get cluster state             */
73
/*    _fx_utility_exFAT_cluster_state_set   Set cluster state             */
74
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
75
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
76
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
77
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
78
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
79
/*                                            transaction                 */
80
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
81
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
82
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
83
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
84
/*                                                                        */
85
/*  CALLED BY                                                             */
86
/*                                                                        */
87
/*    Application Code                                                    */
88
/*                                                                        */
89
/*  RELEASE HISTORY                                                       */
90
/*                                                                        */
91
/*    DATE              NAME                      DESCRIPTION             */
92
/*                                                                        */
93
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
94
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
95
/*                                            resulting in version 6.1    */
96
/*                                                                        */
97
/**************************************************************************/
98
22
UINT  _fx_file_extended_best_effort_allocate(FX_FILE *file_ptr, ULONG64 size, ULONG64 *actual_size_allocated)
99
{
100
101
UINT                   status;
102
ULONG                  i;
103
UINT                   found;
104
ULONG                  bytes_per_cluster;
105
ULONG                  FAT_index, start_FAT_index;
106
ULONG                  FAT_value;
107
ULONG                  clusters, maximum_clusters;
108
FX_MEDIA              *media_ptr;
109
110
#ifdef FX_ENABLE_EXFAT
111
UCHAR                  cluster_state;
112
#endif /* FX_ENABLE_EXFAT */
113
114
#ifdef TX_ENABLE_EVENT_TRACE
115
TX_TRACE_BUFFER_ENTRY *trace_event;
116
ULONG                  trace_timestamp;
117
#endif
118
119
120
    /* First, determine if the file is still open.  */
121
22
    if (file_ptr -> fx_file_id != FX_FILE_ID)
122
    {
123
124
        /* Return the file not open error status.  */
125
2
        return(FX_NOT_OPEN);
126
    }
127
128
#ifndef FX_MEDIA_STATISTICS_DISABLE
129
    /* Setup pointer to media structure.  */
130
20
    media_ptr =  file_ptr -> fx_file_media_ptr;
131
132
    /* Increment the number of times this service has been called.  */
133
20
    media_ptr -> fx_media_file_best_effort_allocates++;
134
#endif
135
136
    /* Make sure this file is open for writing.  */
137
20
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
138
    {
139
140
        /* Return the access error exception - a write was attempted from
141
           a file opened for reading!  */
142
1
        return(FX_ACCESS_ERROR);
143
    }
144
145
    /* Determine if the requested allocation is for zero bytes.  */
146
19
    if (size == 0)
147
    {
148
149
        /* Return a size allocated of zero.  */
150
1
        *actual_size_allocated =  0;
151
152
        /* Return a successful completion - nothing needs to be done.  */
153
1
        return(FX_SUCCESS);
154
    }
155
156
    /* Setup pointer to associated media control block.  */
157
18
    media_ptr =  file_ptr -> fx_file_media_ptr;
158
159
    /* If trace is enabled, insert this event into the trace buffer.  */
160
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, file_ptr, size, 0, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
161
162
    /* Protect against other threads accessing the media.  */
163
18
    FX_PROTECT
164
165
#ifdef FX_ENABLE_FAULT_TOLERANT
166
    /* Start transaction. */
167
    _fx_fault_tolerant_transaction_start(media_ptr);
168
#endif /* FX_ENABLE_FAULT_TOLERANT */
169
170
    /* Check for write protect at the media level (set by driver).  */
171
18
    if (media_ptr -> fx_media_driver_write_protect)
172
    {
173
174
#ifdef FX_ENABLE_FAULT_TOLERANT
175
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
176
#endif /* FX_ENABLE_FAULT_TOLERANT */
177
178
        /* Release media protection.  */
179
1
        FX_UNPROTECT
180
181
        /* Return write protect error.  */
182
1
        return(FX_WRITE_PROTECT);
183
    }
184
185
    /* Calculate the number of bytes per cluster.  */
186
17
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
187
17
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
188
189
    /* Check for invalid value.  */
190
17
    if (bytes_per_cluster == 0)
191
    {
192
193
#ifdef FX_ENABLE_FAULT_TOLERANT
194
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
195
#endif /* FX_ENABLE_FAULT_TOLERANT */
196
197
        /* Release media protection.  */
198
1
        FX_UNPROTECT
199
200
        /* Invalid media, return error.  */
201
1
        return(FX_MEDIA_INVALID);
202
    }
203
204
    /* Calculate the number of consecutive clusters needed to satisfy this
205
       request.  */
206
16
    clusters =  (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
207
208
    /* Determine if cluster count is 0.  */
209
16
    if (clusters == 0)
210
    {
211
212
#ifdef FX_ENABLE_FAULT_TOLERANT
213
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
214
#endif /* FX_ENABLE_FAULT_TOLERANT */
215
216
        /* Release media protection.  */
217
1
        FX_UNPROTECT
218
219
        /* Size overflow when rounding to the next cluster, return an error status.  */
220
1
        return(FX_NO_MORE_SPACE);
221
    }
222
223
    /* Determine if there are no available clusters on the media.  */
224
15
    if (!media_ptr -> fx_media_available_clusters)
225
    {
226
227
#ifdef FX_ENABLE_FAULT_TOLERANT
228
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
229
#endif /* FX_ENABLE_FAULT_TOLERANT */
230
231
        /* Release media protection.  */
232
1
        FX_UNPROTECT
233
234
        /* Return a size allocated of zero, since no clusters were available.  */
235
1
        *actual_size_allocated =  0;
236
237
        /* Not enough clusters, return an error status.  */
238
1
        return(FX_NO_MORE_SPACE);
239
    }
240
241
    /* Determine if the requested file allocation would exceed the physical limit of the file.  */
242
14
    if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
243
13
        ((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
244
    {
245
246
#ifdef FX_ENABLE_FAULT_TOLERANT
247
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
248
#endif /* FX_ENABLE_FAULT_TOLERANT */
249
250
        /* Release media protection.  */
251
2
        FX_UNPROTECT
252
253
        /* Return the no more space error, since the new file size would be larger than
254
           the 32-bit field to represent it in the file's directory entry.  */
255
2
        return(FX_NO_MORE_SPACE);
256
    }
257
258
    /* Now we need to find the consecutive clusters.  */
259
12
    found =             FX_FALSE;
260
#ifdef FX_ENABLE_EXFAT
261
    if ((file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1) &&
262
        (file_ptr -> fx_file_last_physical_cluster > FX_FAT_ENTRY_START) &&
263
        (file_ptr -> fx_file_last_physical_cluster < media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
264
    {
265
        found = FX_TRUE;
266
267
        /* Try to keep clusters consecutive.  */
268
        for (FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
269
             FAT_index < clusters + file_ptr -> fx_file_last_physical_cluster + 1;
270
             FAT_index++)
271
        {
272
273
            /* Get cluster state.  */
274
            status = _fx_utility_exFAT_cluster_state_get(media_ptr, FAT_index, &cluster_state);
275
276
            /* Check for a successful status.  */
277
            if (status != FX_SUCCESS)
278
            {
279
280
#ifdef FX_ENABLE_FAULT_TOLERANT
281
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
282
#endif /* FX_ENABLE_FAULT_TOLERANT */
283
284
                /* Release media protection.  */
285
                FX_UNPROTECT
286
287
                /* Return the error status.  */
288
                return(status);
289
            }
290
291
            /* Determine if the entry is free.  */
292
            if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
293
            {
294
                found = FX_FALSE;
295
                break;
296
            }
297
        }
298
        FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
299
    }
300
301
    if (!found)
302
    {
303
#endif /* FX_ENABLE_EXFAT */
304
12
        FAT_index =         FX_FAT_ENTRY_START;
305
12
        maximum_clusters =  0;
306
12
        start_FAT_index =   FAT_index;
307
308
7164
        while (FAT_index < (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
309
        {
310
311
            /* Determine if enough consecutive FAT entries are available.  */
312
7162
            i =  0;
313
314
#ifdef FX_ENABLE_EXFAT
315
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
316
            {
317
                do
318
                {
319
320
                    /* Get cluster state.  */
321
                    status = _fx_utility_exFAT_cluster_state_get(media_ptr, (FAT_index + i), &cluster_state);
322
323
                    /* Check for a successful status.  */
324
                    if (status != FX_SUCCESS)
325
                    {
326
327
#ifdef FX_ENABLE_FAULT_TOLERANT
328
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
329
#endif /* FX_ENABLE_FAULT_TOLERANT */
330
331
                        /* Release media protection.  */
332
                        FX_UNPROTECT
333
334
                        /* Return the error status.  */
335
                        return(status);
336
                    }
337
338
                    /* Determine if the entry is free.  */
339
                    if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
340
                    {
341
                        break;
342
                    }
343
344
                    /* Otherwise, increment the consecutive FAT indices.  */
345
                    i++;
346
                } while ((i < clusters) && ((FAT_index + i) < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START));
347
            }
348
            else
349
            {
350
#endif /* FX_ENABLE_EXFAT */
351
352
                do
353
                {
354
355
                    /* Read a FAT entry.  */
356
7427
                    status =  _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
357
358
                    /* Check for a successful status.  */
359
7427
                    if (status != FX_SUCCESS)
360
                    {
361
362
#ifdef FX_ENABLE_FAULT_TOLERANT
363
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
364
#endif /* FX_ENABLE_FAULT_TOLERANT */
365
366
                        /* Release media protection.  */
367
1
                        FX_UNPROTECT
368
369
                        /* Return the error status.  */
370
1
                        return(status);
371
                    }
372
373
                    /* Determine if the entry is free.  */
374
7426
                    if (FAT_value != FX_FREE_CLUSTER)
375
                    {
376
7151
                        break;
377
                    }
378
379
                    /* Otherwise, increment the consecutive FAT indices.  */
380
275
                    i++;
381

275
                } while ((i < clusters) && ((FAT_index + i) < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START));
382
#ifdef FX_ENABLE_EXFAT
383
            }
384
#endif /* FX_ENABLE_EXFAT */
385
386
            /* Determine if a new maximum number of clusters has been found.  */
387
7161
            if (i > maximum_clusters)
388
            {
389
390
                /* Yes, remember the maximum number of clusters and the starting
391
                   cluster.  */
392
11
                maximum_clusters =      i;
393
11
                start_FAT_index =       FAT_index;
394
            }
395
396
            /* Determine if we found enough FAT entries.  */
397
7161
            if (i >= clusters)
398
            {
399
400
                /* Yes, we have found enough FAT entries - set the found
401
                   flag and get out of this loop.  */
402
9
                found =  FX_TRUE;
403
9
                break;
404
            }
405
            else
406
            {
407
#ifdef FX_ENABLE_EXFAT
408
                if (media_ptr -> fx_media_FAT_type == FX_exFAT)
409
                {
410
411
                    /* Find free cluster from exFAT media.  */
412
                    status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
413
                                                                        FAT_index + i + 1,
414
                                                                        &FAT_value);
415
                    if (status != FX_SUCCESS)
416
                    {
417
418
#ifdef FX_ENABLE_FAULT_TOLERANT
419
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
420
#endif /* FX_ENABLE_FAULT_TOLERANT */
421
422
                        /* Release media protection.  */
423
                        FX_UNPROTECT
424
425
                        /* Return the error status.  */
426
                        return(status);
427
                    }
428
429
                    if (FAT_value < FAT_index + i + 1)
430
                    {
431
432
                        /* If we wrapped.  */
433
                        FAT_index = media_ptr -> fx_media_total_clusters  + FX_FAT_ENTRY_START;
434
                    }
435
                    else
436
                    {
437
                        FAT_index = FAT_value;
438
                    }
439
                }
440
                else
441
                {
442
#endif /* FX_ENABLE_EXFAT */
443
444
                    /* Position to the next possibly free FAT entry.  */
445
7152
                    FAT_index =  FAT_index + i + 1;
446
#ifdef FX_ENABLE_EXFAT
447
                }
448
#endif /* FX_ENABLE_EXFAT */
449
            }
450
        }
451
452
        /* Determine if the total request could not be satisfied, but a partial allocation
453
           could be satisfied.  */
454
11
        if (maximum_clusters)
455
        {
456
457
            /* Yes, there was at least one cluster.  Prepare to return this
458
               to the caller.  */
459
10
            FAT_index =  start_FAT_index;
460
10
            clusters =   maximum_clusters;
461
10
            found =      FX_TRUE;
462
        }
463
#ifdef FX_ENABLE_EXFAT
464
    }
465
#endif
466
467
    /* Determine if we found enough consecutive clusters to satisfy the
468
       request.  */
469
11
    if (found)
470
    {
471
472
#ifdef FX_ENABLE_FAULT_TOLERANT
473
        if (media_ptr -> fx_media_fault_tolerant_enabled)
474
        {
475
476
            /* Record the FAT chain being applied to the file system. This information aids
477
               recovery effort if fault happens. */
478
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
479
            _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
480
                                             FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
481
        }
482
#endif /* FX_ENABLE_FAULT_TOLERANT */
483
484
#ifdef FX_ENABLE_EXFAT
485
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
486
        {
487
            if ((file_ptr -> fx_file_total_clusters) &&
488
                (FAT_index != file_ptr -> fx_file_last_physical_cluster + 1))
489
            {
490
491
                /* Clusters are not consecutive.  */
492
                file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Set 0bit to 0.  */
493
494
                /* Rebuild FAT.  */
495
                FAT_value = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster +
496
                            file_ptr -> fx_file_total_clusters - 1; /* Last cluster */
497
498
                for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < FAT_value; ++i)
499
                {
500
                    status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
501
                    if (status != FX_SUCCESS)
502
                    {
503
504
#ifdef FX_ENABLE_FAULT_TOLERANT
505
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
506
#endif /* FX_ENABLE_FAULT_TOLERANT */
507
508
                        /* Release media protection.  */
509
                        FX_UNPROTECT
510
511
                        /* Return the bad status.  */
512
                        return(status);
513
                    }
514
                }
515
516
                /* Close chain.  */
517
                status = _fx_utility_FAT_entry_write(media_ptr, FAT_value, media_ptr -> fx_media_fat_last);
518
                if (status != FX_SUCCESS)
519
                {
520
521
#ifdef FX_ENABLE_FAULT_TOLERANT
522
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
523
#endif /* FX_ENABLE_FAULT_TOLERANT */
524
525
                    /* Release media protection.  */
526
                    FX_UNPROTECT
527
528
                    /* Return the bad status.  */
529
                    return(status);
530
                }
531
532
#ifdef FX_ENABLE_FAULT_TOLERANT
533
                if (media_ptr -> fx_media_fault_tolerant_enabled)
534
                {
535
536
                    /* Clear the Fault Tolerant Set FAT Chain flag. */
537
                    media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
538
                }
539
#endif /* FX_ENABLE_FAULT_TOLERANT */
540
541
                /* Update stream.  */
542
                status = _fx_directory_exFAT_entry_write(
543
                        media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
544
545
                if (status != FX_SUCCESS)
546
                {
547
548
#ifdef FX_ENABLE_FAULT_TOLERANT
549
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
550
#endif /* FX_ENABLE_FAULT_TOLERANT */
551
552
                    /* Release media protection.  */
553
                    FX_UNPROTECT
554
555
                    /* Return the bad status.  */
556
                    return(status);
557
                }
558
559
#ifdef FX_ENABLE_FAULT_TOLERANT
560
                if (media_ptr -> fx_media_fault_tolerant_enabled)
561
                {
562
563
                    /* Set undo phase. */
564
                    media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
565
                }
566
#endif /* FX_ENABLE_FAULT_TOLERANT */
567
            }
568
        }
569
#endif /* FX_ENABLE_EXFAT */
570
571
        /* Update the link pointers in the new clusters.  */
572
271
        for (i = 0; i < (clusters - 1); i++)
573
        {
574
#ifdef FX_ENABLE_EXFAT
575
            if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
576
#ifdef FX_ENABLE_FAULT_TOLERANT
577
                || (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
578
#endif /* FX_ENABLE_FAULT_TOLERANT */
579
               )
580
            {
581
#endif /* FX_ENABLE_EXFAT */
582
583
                /* Update the cluster links.  Since the allocation is
584
                   sequential, we just have to link each FAT entry to the
585
                   next one.  */
586
262
                status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
587
588
                /* Check for a bad status.  */
589
262
                if (status != FX_SUCCESS)
590
                {
591
592
#ifdef FX_ENABLE_FAULT_TOLERANT
593
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
594
#endif /* FX_ENABLE_FAULT_TOLERANT */
595
596
                    /* Release media protection.  */
597
1
                    FX_UNPROTECT
598
599
                    /* Return the error status.  */
600
1
                    return(status);
601
                }
602
#ifdef FX_ENABLE_EXFAT
603
            }
604
605
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
606
            {
607
608
                /* Mark the cluster as used.  */
609
                status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + i, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
610
611
                /* Check for a bad status.  */
612
                if (status != FX_SUCCESS)
613
                {
614
615
#ifdef FX_ENABLE_FAULT_TOLERANT
616
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
617
#endif /* FX_ENABLE_FAULT_TOLERANT */
618
619
                    /* Release media protection.  */
620
                    FX_UNPROTECT
621
622
                    /* Return the error status.  */
623
                    return(status);
624
                }
625
            }
626
#endif /* FX_ENABLE_EXFAT */
627
        }
628
629
#ifdef FX_ENABLE_EXFAT
630
        if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
631
        {
632
#endif /* FX_ENABLE_EXFAT */
633
634
            /* Now place an EOF in the last cluster entry.  */
635
9
            status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
636
637
            /* Check for a bad status.  */
638
9
            if (status != FX_SUCCESS)
639
            {
640
641
#ifdef FX_ENABLE_FAULT_TOLERANT
642
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
643
#endif /* FX_ENABLE_FAULT_TOLERANT */
644
645
                /* Release media protection.  */
646
1
                FX_UNPROTECT
647
648
                /* Return the error status.  */
649
1
                return(status);
650
            }
651
#ifdef FX_ENABLE_EXFAT
652
        }
653
654
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
655
        {
656
657
            /* Mark the cluster as used.  */
658
            status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + clusters - 1, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
659
660
            /* Check for a bad status.  */
661
            if (status != FX_SUCCESS)
662
            {
663
664
#ifdef FX_ENABLE_FAULT_TOLERANT
665
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
666
#endif /* FX_ENABLE_FAULT_TOLERANT */
667
668
                /* Release media protection.  */
669
                FX_UNPROTECT
670
671
                /* Return the error status.  */
672
                return(status);
673
            }
674
        }
675
#endif /* FX_ENABLE_EXFAT */
676
677
#ifdef FX_FAULT_TOLERANT
678
679
        /* Flush the cached individual FAT entries */
680
        _fx_utility_FAT_flush(media_ptr);
681
#ifdef FX_ENABLE_EXFAT
682
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
683
        {
684
            _fx_utility_exFAT_bitmap_flush(media_ptr);
685
        }
686
#endif /* FX_ENABLE_EXFAT */
687
#endif
688
689
        /* Actually link up the new clusters to the file.  */
690
691
        /* Determine if there are already clusters allocated for this file.  */
692
8
        if (file_ptr -> fx_file_total_clusters)
693
        {
694
695
#ifdef FX_ENABLE_EXFAT
696
            if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
697
            {
698
#endif /* FX_ENABLE_EXFAT */
699
700
                /* Linkup the last cluster.  */
701
6
                status =  _fx_utility_FAT_entry_write(media_ptr,
702
                                                      file_ptr -> fx_file_last_physical_cluster, FAT_index);
703
704
                /* Check for a bad status.  */
705
6
                if (status != FX_SUCCESS)
706
                {
707
708
#ifdef FX_ENABLE_FAULT_TOLERANT
709
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
710
#endif /* FX_ENABLE_FAULT_TOLERANT */
711
712
                    /* Release media protection.  */
713
1
                    FX_UNPROTECT
714
715
                    /* Return the error status.  */
716
1
                    return(status);
717
                }
718
#ifdef FX_ENABLE_EXFAT
719
            }
720
#endif /* FX_ENABLE_EXFAT */
721
722
            /* Determine if we are adding a sector after a write filled the previously
723
               allocated cluster exactly.  */
724
5
            if ((file_ptr -> fx_file_current_relative_sector >=
725
5
                 (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
726
4
                (file_ptr -> fx_file_current_logical_offset >=
727
4
                    media_ptr -> fx_media_bytes_per_sector))
728
            {
729
730
                /* Yes, we need to adjust all of the pertinent file parameters for
731
                   access into this newly allocated cluster.  */
732
2
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
733
2
                file_ptr -> fx_file_current_relative_cluster++;
734
2
                file_ptr -> fx_file_current_relative_sector =   0;
735
2
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
736
2
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
737
2
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
738
2
                file_ptr -> fx_file_current_logical_offset =    0;
739
            }
740
        }
741
        else
742
        {
743
744
            /* These new clusters are also the first!  Setup the initial
745
               file parameters.  */
746
2
            file_ptr -> fx_file_first_physical_cluster =    FAT_index;
747
2
            file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
748
2
            file_ptr -> fx_file_current_relative_cluster =  0;
749
2
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
750
2
                (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
751
2
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
752
2
            file_ptr -> fx_file_current_logical_offset =    0;
753
2
            file_ptr -> fx_file_current_file_offset =       0;
754
755
            /* Setup the consecutive clusters at the beginning of the file.  */
756
2
            file_ptr -> fx_file_consecutive_cluster =       clusters;
757
758
            /* Update the first cluster in the directory entry.  */
759
2
            file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
760
761
#ifdef FX_ENABLE_FAULT_TOLERANT
762
            if (media_ptr -> fx_media_fault_tolerant_enabled)
763
            {
764
765
                /* Clear undo phase. */
766
                media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
767
            }
768
#endif /* FX_ENABLE_FAULT_TOLERANT */
769
        }
770
771
        /* Remember the last physical cluster.  */
772
7
        file_ptr -> fx_file_last_physical_cluster =     FAT_index + clusters - 1;
773
774
        /* Update the available size.  */
775
#ifdef FX_ENABLE_EXFAT
776
        if (file_ptr -> fx_file_current_available_size > (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters)))
777
        {
778
            /* 64-bit wrap around condition is present.  Just set the available file size to all ones, which is
779
               the maximum file size.  */
780
            file_ptr -> fx_file_current_available_size =  0xFFFFFFFFFFFFFFFFULL;
781
        }
782
783
        /* Check for wrap-around when updating the available size.  */
784
        if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
785
            (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters) > 0xFFFFFFFFUL))
786
        {
787
788
            /* 32-bit wrap around condition is present.  Just set the available file size to all ones, which is
789
               the maximum file size.  */
790
            file_ptr -> fx_file_current_available_size =  0xFFFFFFFFUL;
791
        }
792
        else
793
        {
794
#endif /* FX_ENABLE_EXFAT */
795
796
            /* Normal condition, update the available size.  */
797
7
            file_ptr -> fx_file_current_available_size =
798
7
                file_ptr -> fx_file_current_available_size + bytes_per_cluster * clusters;
799
#ifdef FX_ENABLE_EXFAT
800
        }
801
802
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
803
        {
804
            file_ptr -> fx_file_consecutive_cluster += clusters;
805
        }
806
#endif /* FX_ENABLE_EXFAT */
807
808
        /* Increment the total clusters for this file.  */
809
7
        file_ptr -> fx_file_total_clusters =
810
7
            file_ptr -> fx_file_total_clusters + clusters;
811
812
        /* Decrease the available clusters on the media.  */
813
7
        media_ptr -> fx_media_available_clusters =
814
7
            media_ptr -> fx_media_available_clusters - clusters;
815
816
        /* Return the actual size allocated.  */
817
7
        *actual_size_allocated =  ((ULONG64)clusters) * bytes_per_cluster;
818
819
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
820
821
        /* Set the file size the current size plus what what was added.  */
822
        if (size < *actual_size_allocated)
823
        {
824
            file_ptr -> fx_file_current_file_size +=  size;
825
        }
826
        else
827
        {
828
            file_ptr -> fx_file_current_file_size +=  *actual_size_allocated;
829
        }
830
831
        /* Copy the new file size into the directory entry.  */
832
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  file_ptr -> fx_file_current_file_size;
833
#endif
834
835
        /* Update the trace event with the bytes allocated.  */
836
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, 0, 0, *actual_size_allocated, 0);
837
838
        /* Write the directory entry to the media.  */
839
#ifdef FX_ENABLE_EXFAT
840
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
841
        {
842
            status = _fx_directory_exFAT_entry_write(
843
                    media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
844
        }
845
        else
846
        {
847
#endif /* FX_ENABLE_EXFAT */
848
7
            status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
849
#ifdef FX_ENABLE_EXFAT
850
        }
851
#endif /* FX_ENABLE_EXFAT */
852
853
        /* Check for a good status.  */
854
7
        if (status != FX_SUCCESS)
855
        {
856
857
#ifdef FX_ENABLE_FAULT_TOLERANT
858
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
859
#endif /* FX_ENABLE_FAULT_TOLERANT */
860
861
            /* Release media protection.  */
862
1
            FX_UNPROTECT
863
864
            /* Return the error status.  */
865
1
            return(status);
866
        }
867
    }
868
    else
869
    {
870
871
#ifdef FX_ENABLE_FAULT_TOLERANT
872
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
873
#endif /* FX_ENABLE_FAULT_TOLERANT */
874
875
        /* Release media protection.  */
876
1
        FX_UNPROTECT
877
878
        /* Return a size allocated of zero, since no clusters were available.  */
879
1
        *actual_size_allocated =  0;
880
881
        /* Not enough contiguous space on the media.  Return error status.  */
882
1
        return(FX_NO_MORE_SPACE);
883
    }
884
885
#ifdef FX_FAULT_TOLERANT
886
887
    /* Flush the cached individual FAT entries */
888
    _fx_utility_FAT_flush(media_ptr);
889
#endif
890
891
    /* Flush the internal logical sector cache.  */
892
6
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
893
894
#ifdef FX_ENABLE_FAULT_TOLERANT
895
    /* Check for a bad status.  */
896
    if (status != FX_SUCCESS)
897
    {
898
899
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
900
901
        /* Release media protection.  */
902
        FX_UNPROTECT
903
904
        /* Return the bad status.  */
905
        return(status);
906
    }
907
908
    /* End transaction. */
909
    status = _fx_fault_tolerant_transaction_end(media_ptr);
910
#endif /* FX_ENABLE_FAULT_TOLERANT */
911
912
    /* Release media protection.  */
913
6
    FX_UNPROTECT
914
915
    /* Return status to the caller.  */
916
6
    return(status);
917
}
918