GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_allocate.c Lines: 97 97 100.0 %
Date: 2024-01-10 21:53:23 Branches: 46 46 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_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      */
52
/*    enough clusters, the clusters are allocated and linked to the file. */
53
/*    Otherwise, if there are not enough consecutive 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
/*                                                                        */
61
/*  OUTPUT                                                                */
62
/*                                                                        */
63
/*    return status                                                       */
64
/*                                                                        */
65
/*  CALLS                                                                 */
66
/*                                                                        */
67
/*    _fx_directory_entry_write             Update directory entry        */
68
/*    _fx_utility_exFAT_bitmap_flush        Flush exFAT allocation bitmap */
69
/*    _fx_utility_exFAT_bitmap_free_cluster_find                          */
70
/*                                            Find exFAT free cluster     */
71
/*    _fx_utility_exFAT_cluster_state_get   Get cluster state             */
72
/*    _fx_utility_exFAT_cluster_state_set   Set cluster state             */
73
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
74
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
75
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
76
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
77
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
78
/*                                            transaction                 */
79
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
80
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
81
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
82
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
83
/*                                                                        */
84
/*  CALLED BY                                                             */
85
/*                                                                        */
86
/*    Application Code                                                    */
87
/*                                                                        */
88
/*  RELEASE HISTORY                                                       */
89
/*                                                                        */
90
/*    DATE              NAME                      DESCRIPTION             */
91
/*                                                                        */
92
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
93
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
94
/*                                            resulting in version 6.1    */
95
/*                                                                        */
96
/**************************************************************************/
97
27
UINT  _fx_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size)
98
{
99
100
UINT                   status;
101
ULONG                  i;
102
UINT                   found;
103
ULONG                  bytes_per_cluster;
104
ULONG                  FAT_index;
105
ULONG                  FAT_value;
106
ULONG                  clusters;
107
FX_MEDIA              *media_ptr;
108
#ifdef FX_ENABLE_EXFAT
109
UCHAR                  cluster_state;
110
#endif /* FX_ENABLE_EXFAT */
111
112
#ifdef TX_ENABLE_EVENT_TRACE
113
TX_TRACE_BUFFER_ENTRY *trace_event;
114
ULONG                  trace_timestamp;
115
#endif
116
117
118
    /* First, determine if the file is still open.  */
119
27
    if (file_ptr -> fx_file_id != FX_FILE_ID)
120
    {
121
122
        /* Return the file not open error status.  */
123
1
        return(FX_NOT_OPEN);
124
    }
125
126
    /* Setup pointer to media structure.  */
127
26
    media_ptr =  file_ptr -> fx_file_media_ptr;
128
129
#ifndef FX_MEDIA_STATISTICS_DISABLE
130
131
    /* Increment the number of times this service has been called.  */
132
26
    media_ptr -> fx_media_file_allocates++;
133
#endif
134
135
    /* Make sure this file is open for writing.  */
136
26
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
137
    {
138
139
        /* Return the access error exception - a write was attempted from
140
           a file opened for reading!  */
141
1
        return(FX_ACCESS_ERROR);
142
    }
143
144
    /* Determine if the requested allocation is for zero bytes.  */
145
25
    if (size == 0)
146
    {
147
148
        /* Return a successful completion - nothing needs to be done.  */
149
1
        return(FX_SUCCESS);
150
    }
151
152
    /* Setup pointer to associated media control block.  */
153
24
    media_ptr =  file_ptr -> fx_file_media_ptr;
154
155
    /* If trace is enabled, insert this event into the trace buffer.  */
156
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_ALLOCATE, file_ptr, size, file_ptr -> fx_file_current_available_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
157
158
    /* Protect against other threads accessing the media.  */
159
24
    FX_PROTECT
160
161
#ifdef FX_ENABLE_FAULT_TOLERANT
162
    /* Start transaction. */
163
    _fx_fault_tolerant_transaction_start(media_ptr);
164
#endif /* FX_ENABLE_FAULT_TOLERANT */
165
166
    /* Check for write protect at the media level (set by driver).  */
167
24
    if (media_ptr -> fx_media_driver_write_protect)
168
    {
169
170
#ifdef FX_ENABLE_FAULT_TOLERANT
171
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
172
#endif /* FX_ENABLE_FAULT_TOLERANT */
173
174
        /* Release media protection.  */
175
1
        FX_UNPROTECT
176
177
        /* Return write protect error.  */
178
1
        return(FX_WRITE_PROTECT);
179
    }
180
181
    /* Calculate the number of bytes per cluster.  */
182
23
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
183
23
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
184
185
    /* Check for invalid value.  */
186
23
    if (bytes_per_cluster == 0)
187
    {
188
189
#ifdef FX_ENABLE_FAULT_TOLERANT
190
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
191
#endif /* FX_ENABLE_FAULT_TOLERANT */
192
193
        /* Release media protection.  */
194
1
        FX_UNPROTECT
195
196
        /* Invalid media, return error.  */
197
1
        return(FX_MEDIA_INVALID);
198
    }
199
200
    /* Calculate the number of consecutive clusters needed to satisfy this
201
       request.  */
202
22
    clusters =  (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
203
204
    /* Determine if cluster count is 0.  */
205
22
    if (clusters == 0)
206
    {
207
208
#ifdef FX_ENABLE_FAULT_TOLERANT
209
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
210
#endif /* FX_ENABLE_FAULT_TOLERANT */
211
212
        /* Release media protection.  */
213
1
        FX_UNPROTECT
214
215
        /* Size overflow when rounding to the next cluster, return an error status.  */
216
1
        return(FX_NO_MORE_SPACE);
217
    }
218
219
    /* Determine if there are enough available clusters on the media.  */
220
21
    if (clusters > media_ptr -> fx_media_available_clusters)
221
    {
222
223
#ifdef FX_ENABLE_FAULT_TOLERANT
224
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
225
#endif /* FX_ENABLE_FAULT_TOLERANT */
226
227
        /* Release media protection.  */
228
1
        FX_UNPROTECT
229
230
        /* Not enough clusters, return an error status.  */
231
1
        return(FX_NO_MORE_SPACE);
232
    }
233
234
    /* Determine if the requested file allocation would exceed the physical limit of the file.  */
235
20
    if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
236
19
        ((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
237
    {
238
239
#ifdef FX_ENABLE_FAULT_TOLERANT
240
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
241
#endif /* FX_ENABLE_FAULT_TOLERANT */
242
243
        /* Release media protection.  */
244
2
        FX_UNPROTECT
245
246
        /* Return the no more space error, since the new file size would be larger than
247
           the 32-bit field to represent it in the file's directory entry.  */
248
2
        return(FX_NO_MORE_SPACE);
249
    }
250
251
    /* Now we need to find the consecutive clusters.  */
252
18
    FAT_index =  FX_FAT_ENTRY_START;
253
18
    found =      FX_FALSE;
254
255
#ifdef FX_ENABLE_EXFAT
256
    if ((file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1) &&
257
        (file_ptr -> fx_file_last_physical_cluster > FX_FAT_ENTRY_START) &&
258
        (file_ptr -> fx_file_last_physical_cluster < media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
259
    {
260
        found = FX_TRUE;
261
        /* Try to keep clusters consecutive.  */
262
        for (FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
263
             FAT_index < clusters + file_ptr -> fx_file_last_physical_cluster + 1;
264
             FAT_index++)
265
        {
266
267
            /* Get cluster state.  */
268
            status = _fx_utility_exFAT_cluster_state_get(media_ptr, FAT_index, &cluster_state);
269
270
            /* Check for a successful status.  */
271
            if (status != FX_SUCCESS)
272
            {
273
274
#ifdef FX_ENABLE_FAULT_TOLERANT
275
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
276
#endif /* FX_ENABLE_FAULT_TOLERANT */
277
278
                /* Release media protection.  */
279
                FX_UNPROTECT
280
281
                /* Return the error status.  */
282
                return(status);
283
            }
284
285
            /* Determine if the entry is free.  */
286
            if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
287
            {
288
                found = FX_FALSE;
289
                break;
290
            }
291
        }
292
        FAT_index = file_ptr -> fx_file_last_physical_cluster + 1;
293
    }
294
295
    if (!found)
296
    {
297
#endif /* FX_ENABLE_EXFAT */
298
299
6957
        while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
300
        {
301
302
            /* Determine if enough consecutive FAT entries are available.  */
303
6956
            i =  0;
304
305
#ifdef FX_ENABLE_EXFAT
306
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
307
            {
308
                do
309
                {
310
311
                    /* Get cluster state.  */
312
                    status = _fx_utility_exFAT_cluster_state_get(media_ptr, (FAT_index + i), &cluster_state);
313
314
                    /* Check for a successful status.  */
315
                    if (status != FX_SUCCESS)
316
                    {
317
318
#ifdef FX_ENABLE_FAULT_TOLERANT
319
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
320
#endif /* FX_ENABLE_FAULT_TOLERANT */
321
322
                        /* Release media protection.  */
323
                        FX_UNPROTECT
324
325
                        /* Return the error status.  */
326
                        return(status);
327
                    }
328
329
                    /* Determine if the entry is free.  */
330
                    if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_OCCUPIED)
331
                    {
332
                        break;
333
                    }
334
335
                    /* Otherwise, increment the consecutive FAT indices.  */
336
                    i++;
337
                } while (i < clusters);
338
            }
339
            else
340
            {
341
#endif /* FX_ENABLE_EXFAT */
342
343
                do
344
                {
345
346
                    /* Read a FAT entry.  */
347
7224
                    status =  _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
348
349
                    /* Check for a successful status.  */
350
7224
                    if (status != FX_SUCCESS)
351
                    {
352
353
#ifdef FX_ENABLE_FAULT_TOLERANT
354
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
355
#endif /* FX_ENABLE_FAULT_TOLERANT */
356
357
                        /* Release media protection.  */
358
1
                        FX_UNPROTECT
359
360
                        /* Return the error status.  */
361
1
                        return(status);
362
                    }
363
364
                    /* Determine if the entry is free.  */
365
7223
                    if (FAT_value != FX_FREE_CLUSTER)
366
                    {
367
6939
                        break;
368
                    }
369
370
                    /* Otherwise, increment the consecutive FAT indices.  */
371
284
                    i++;
372
284
                } while (i < clusters);
373
#ifdef FX_ENABLE_EXFAT
374
            }
375
#endif /* FX_ENABLE_EXFAT */
376
377
            /* Determine if we found enough FAT entries.  */
378
6955
            if (i >= clusters)
379
            {
380
381
                /* Yes, we have found enough FAT entries - set the found
382
                   flag and get out of this loop.  */
383
16
                found =  FX_TRUE;
384
16
                break;
385
            }
386
            else
387
            {
388
#ifdef FX_ENABLE_EXFAT
389
                if (media_ptr -> fx_media_FAT_type == FX_exFAT)
390
                {
391
392
                    /* Find free cluster from exFAT media.  */
393
                    status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
394
                                                                        FAT_index + i + 1,
395
                                                                        &FAT_value);
396
                    if (status != FX_SUCCESS)
397
                    {
398
#ifdef FX_ENABLE_FAULT_TOLERANT
399
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
400
#endif /* FX_ENABLE_FAULT_TOLERANT */
401
402
                        /* Release media protection.  */
403
                        FX_UNPROTECT
404
405
                        /* Return the error status.  */
406
                        return(status);
407
                    }
408
409
                    if (FAT_value < FAT_index + i + 1)
410
                    {
411
                        /* If we wrapped.  */
412
                        FAT_index = media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START;
413
                    }
414
                    else
415
                    {
416
                        FAT_index = FAT_value;
417
                    }
418
                }
419
                else
420
                {
421
#endif /* FX_ENABLE_EXFAT */
422
                    /* Position to the next possibly free FAT entry.  */
423
6939
                    FAT_index =  FAT_index + i + 1;
424
#ifdef FX_ENABLE_EXFAT
425
                }
426
#endif /* FX_ENABLE_EXFAT */
427
            }
428
        }
429
#ifdef FX_ENABLE_EXFAT
430
    }
431
#endif
432
433
    /* Determine if we found enough consecutive clusters to satisfy the
434
       request.  */
435
17
    if (found)
436
    {
437
438
#ifdef FX_ENABLE_FAULT_TOLERANT
439
        if (media_ptr -> fx_media_fault_tolerant_enabled)
440
        {
441
442
            /* Record the action that is about to take place.  This information
443
               would aid the undo process should fault condition happens. */
444
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
445
            _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
446
                                             FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
447
        }
448
#endif /* FX_ENABLE_FAULT_TOLERANT */
449
450
#ifdef FX_ENABLE_EXFAT
451
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
452
        {
453
            if ((file_ptr -> fx_file_total_clusters) &&
454
                (FAT_index != file_ptr -> fx_file_last_physical_cluster + 1))
455
            {
456
                /* Clusters are not consecutive.  */
457
                file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Set 0bit to 0 */
458
459
                /* Rebuild FAT.  */
460
                FAT_value = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster +
461
                            file_ptr -> fx_file_total_clusters - 1; /* Last cluster */
462
463
                for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < FAT_value; ++i)
464
                {
465
                    status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
466
                    if (status != FX_SUCCESS)
467
                    {
468
469
#ifdef FX_ENABLE_FAULT_TOLERANT
470
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
471
#endif /* FX_ENABLE_FAULT_TOLERANT */
472
473
                        /* Release media protection.  */
474
                        FX_UNPROTECT
475
476
                        /* Return the bad status.  */
477
                        return(status);
478
                    }
479
                }
480
481
                /* Close chain.  */
482
                status = _fx_utility_FAT_entry_write(media_ptr, FAT_value, media_ptr -> fx_media_fat_last);
483
                if (status != FX_SUCCESS)
484
                {
485
486
#ifdef FX_ENABLE_FAULT_TOLERANT
487
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
488
#endif /* FX_ENABLE_FAULT_TOLERANT */
489
490
                    /* Release media protection.  */
491
                    FX_UNPROTECT
492
493
                    /* Return the bad status.  */
494
                    return(status);
495
                }
496
497
#ifdef FX_ENABLE_FAULT_TOLERANT
498
                if (media_ptr -> fx_media_fault_tolerant_enabled)
499
                {
500
501
                    /* Clear undo phase. */
502
                    media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
503
                }
504
#endif /* FX_ENABLE_FAULT_TOLERANT */
505
506
                /* Update stream.  */
507
                status = _fx_directory_exFAT_entry_write(
508
                        media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
509
510
                if (status != FX_SUCCESS)
511
                {
512
#ifdef FX_ENABLE_FAULT_TOLERANT
513
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
514
#endif /* FX_ENABLE_FAULT_TOLERANT */
515
516
                    /* Release media protection.  */
517
                    FX_UNPROTECT
518
519
                    /* Return the bad status.  */
520
                    return(status);
521
                }
522
523
#ifdef FX_ENABLE_FAULT_TOLERANT
524
                if (media_ptr -> fx_media_fault_tolerant_enabled)
525
                {
526
527
                    /* Set undo phase. */
528
                    media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
529
                }
530
#endif /* FX_ENABLE_FAULT_TOLERANT */
531
            }
532
        }
533
#endif /* FX_ENABLE_EXFAT */
534
535
        /* Update the link pointers in the new clusters.  */
536
280
        for (i = 0; i < (clusters - 1); i++)
537
        {
538
#ifdef FX_ENABLE_EXFAT
539
            if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
540
#ifdef FX_ENABLE_FAULT_TOLERANT
541
                || (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
542
#endif /* FX_ENABLE_FAULT_TOLERANT */
543
               )
544
            {
545
#endif /* FX_ENABLE_EXFAT */
546
547
                /* Update the cluster links.  Since the allocation is
548
                   sequential, we just have to link each FAT entry to the
549
                   next one.  */
550
265
                status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
551
552
                /* Check for a bad status.  */
553
265
                if (status != FX_SUCCESS)
554
                {
555
556
#ifdef FX_ENABLE_FAULT_TOLERANT
557
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
558
#endif /* FX_ENABLE_FAULT_TOLERANT */
559
560
                    /* Release media protection.  */
561
1
                    FX_UNPROTECT
562
563
                    /* Return the error status.  */
564
1
                    return(status);
565
                }
566
#ifdef FX_ENABLE_EXFAT
567
            }
568
569
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
570
            {
571
572
                /* Mark the cluster as used.  */
573
                status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + i, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
574
575
                /* Check for a bad status.  */
576
                if (status != FX_SUCCESS)
577
                {
578
579
#ifdef FX_ENABLE_FAULT_TOLERANT
580
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
581
#endif /* FX_ENABLE_FAULT_TOLERANT */
582
583
                    /* Release media protection.  */
584
                    FX_UNPROTECT
585
586
                    /* Return the error status.  */
587
                    return(status);
588
                }
589
            }
590
#endif /* FX_ENABLE_EXFAT */
591
        }
592
#ifdef FX_ENABLE_EXFAT
593
        if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
594
        {
595
#endif /* FX_ENABLE_EXFAT */
596
597
            /* Now place an EOF in the last cluster entry.  */
598
15
            status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
599
600
            /* Check for a bad status.  */
601
15
            if (status != FX_SUCCESS)
602
            {
603
604
#ifdef FX_ENABLE_FAULT_TOLERANT
605
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
606
#endif /* FX_ENABLE_FAULT_TOLERANT */
607
608
                /* Release media protection.  */
609
1
                FX_UNPROTECT
610
611
                /* Return the error status.  */
612
1
                return(status);
613
            }
614
#ifdef FX_ENABLE_EXFAT
615
        }
616
617
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
618
        {
619
620
            /* Mark the cluster as used.  */
621
            status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index + clusters - 1, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
622
623
            /* Check for a bad status.  */
624
            if (status != FX_SUCCESS)
625
            {
626
627
#ifdef FX_ENABLE_FAULT_TOLERANT
628
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
629
#endif /* FX_ENABLE_FAULT_TOLERANT */
630
631
                /* Release media protection.  */
632
                FX_UNPROTECT
633
634
                /* Return the error status.  */
635
                return(status);
636
            }
637
        }
638
#endif /* FX_ENABLE_EXFAT */
639
640
#ifdef FX_FAULT_TOLERANT
641
642
        /* Flush the cached individual FAT entries */
643
        _fx_utility_FAT_flush(media_ptr);
644
645
#ifdef FX_ENABLE_EXFAT
646
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
647
        {
648
            _fx_utility_exFAT_bitmap_flush(media_ptr);
649
        }
650
#endif /* FX_ENABLE_EXFAT */
651
#endif
652
653
        /* Actually link up the new clusters to the file.  */
654
655
        /* Determine if there are already clusters allocated for this file.  */
656
14
        if (file_ptr -> fx_file_total_clusters)
657
        {
658
#ifdef FX_ENABLE_EXFAT
659
            if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
660
            {
661
#endif /* FX_ENABLE_EXFAT */
662
663
                /* Linkup the last cluster.  */
664
7
                status =  _fx_utility_FAT_entry_write(media_ptr,
665
                                                      file_ptr -> fx_file_last_physical_cluster, FAT_index);
666
667
                /* Check for a bad status.  */
668
7
                if (status != FX_SUCCESS)
669
                {
670
671
#ifdef FX_ENABLE_FAULT_TOLERANT
672
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
673
#endif /* FX_ENABLE_FAULT_TOLERANT */
674
675
                    /* Release media protection.  */
676
1
                    FX_UNPROTECT
677
678
                    /* Return the error status.  */
679
1
                    return(status);
680
                }
681
#ifdef FX_ENABLE_EXFAT
682
            }
683
#endif /* FX_ENABLE_EXFAT */
684
685
            /* Determine if we are adding a sector after a write filled the previously
686
               allocated cluster exactly.  */
687
6
            if ((file_ptr -> fx_file_current_relative_sector >=
688
6
                (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
689
5
                (file_ptr -> fx_file_current_logical_offset >=
690
5
                 media_ptr -> fx_media_bytes_per_sector))
691
            {
692
693
                /* Yes, we need to adjust all of the pertinent file parameters for
694
                   access into this newly allocated cluster.  */
695
3
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
696
3
                file_ptr -> fx_file_current_relative_cluster++;
697
3
                file_ptr -> fx_file_current_relative_sector =   0;
698
3
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
699
3
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
700
3
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
701
3
                file_ptr -> fx_file_current_logical_offset =    0;
702
            }
703
        }
704
        else
705
        {
706
707
            /* These new clusters are also the first!  Setup the initial
708
               file parameters.  */
709
7
            file_ptr -> fx_file_first_physical_cluster =    FAT_index;
710
7
            file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
711
7
            file_ptr -> fx_file_current_relative_cluster =  0;
712
7
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
713
7
                (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
714
7
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
715
7
            file_ptr -> fx_file_current_logical_offset =    0;
716
7
            file_ptr -> fx_file_current_file_offset =       0;
717
718
            /* Update the first cluster in the directory entry.  */
719
7
            file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
720
        }
721
722
        /* Remember the last physical cluster.  */
723
13
        file_ptr -> fx_file_last_physical_cluster =     FAT_index + clusters - 1;
724
725
#ifdef FX_ENABLE_EXFAT
726
        if (file_ptr -> fx_file_current_available_size > (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters)))
727
        {
728
            /* 64-bit wrap around condition is present.  Just set the available file size to all ones, which is
729
               the maximum file size.  */
730
            file_ptr -> fx_file_current_available_size =  0xFFFFFFFFFFFFFFFFULL;
731
        }
732
#endif /* FX_ENABLE_EXFAT */
733
734
        /* Check for wrap-around when updating the available size.  */
735
#ifdef FX_ENABLE_EXFAT
736
        if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
737
            (file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters) > 0xFFFFFFFFUL))
738
        {
739
740
            /* 32-bit wrap around condition is present.  Just set the available file size to all ones, which is
741
               the maximum file size.  */
742
            file_ptr -> fx_file_current_available_size =  ((ULONG)0xFFFFFFFF);
743
        }
744
        else
745
        {
746
747
            /* Normal condition, update the available size.  */
748
            file_ptr -> fx_file_current_available_size =
749
                file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
750
        }
751
#else
752
        /* Update the available size.  */
753
13
        file_ptr -> fx_file_current_available_size =
754
13
                file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
755
756
#endif /* FX_ENABLE_EXFAT */
757
758
        /* Increment the total clusters for this file.  */
759
13
        file_ptr -> fx_file_total_clusters =
760
13
            file_ptr -> fx_file_total_clusters + clusters;
761
762
        /* Decrease the available clusters on the media.  */
763
13
        media_ptr -> fx_media_available_clusters =
764
13
            media_ptr -> fx_media_available_clusters - clusters;
765
766
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
767
768
        /* Set the file size the current size plus what what was added.  */
769
        file_ptr -> fx_file_current_file_size +=  size;
770
771
        /* Copy the new file size into the directory entry.  */
772
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  file_ptr -> fx_file_current_file_size;
773
#endif
774
775
#ifdef FX_ENABLE_FAULT_TOLERANT
776
        if (media_ptr -> fx_media_fault_tolerant_enabled)
777
        {
778
779
            /* Clear undo phase. */
780
            media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
781
        }
782
#endif /* FX_ENABLE_FAULT_TOLERANT */
783
784
        /* Update the trace event with the new size.  */
785
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_ALLOCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size);
786
787
        /* Write the directory entry to the media.  */
788
#ifdef FX_ENABLE_EXFAT
789
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
790
        {
791
            status = _fx_directory_exFAT_entry_write(
792
                    media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
793
        }
794
        else
795
        {
796
#endif /* FX_ENABLE_EXFAT */
797
13
            status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
798
#ifdef FX_ENABLE_EXFAT
799
        }
800
#endif /* FX_ENABLE_EXFAT */
801
802
        /* Check for a good status.  */
803
13
        if (status != FX_SUCCESS)
804
        {
805
806
#ifdef FX_ENABLE_FAULT_TOLERANT
807
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
808
#endif /* FX_ENABLE_FAULT_TOLERANT */
809
810
            /* Release media protection.  */
811
1
            FX_UNPROTECT
812
813
            /* Return the error status.  */
814
1
            return(status);
815
        }
816
    }
817
    else
818
    {
819
820
#ifdef FX_ENABLE_FAULT_TOLERANT
821
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
822
#endif /* FX_ENABLE_FAULT_TOLERANT */
823
824
        /* Release media protection.  */
825
1
        FX_UNPROTECT
826
827
        /* Not enough contiguous space on the media.  Return error status.  */
828
1
        return(FX_NO_MORE_SPACE);
829
    }
830
831
#ifdef FX_FAULT_TOLERANT
832
833
    /* Flush the cached individual FAT entries */
834
    _fx_utility_FAT_flush(media_ptr);
835
#endif
836
837
    /* Flush the internal logical sector cache.  */
838
12
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
839
840
#ifdef FX_ENABLE_FAULT_TOLERANT
841
    /* Check for a bad status.  */
842
    if (status != FX_SUCCESS)
843
    {
844
845
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
846
847
        /* Release media protection.  */
848
        FX_UNPROTECT
849
850
        /* Return the bad status.  */
851
        return(status);
852
    }
853
854
    if (media_ptr -> fx_media_fault_tolerant_enabled)
855
    {
856
857
        /* Copy the new file size into the directory entry.  */
858
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
859
    }
860
861
    /* End transaction. */
862
    status = _fx_fault_tolerant_transaction_end(media_ptr);
863
#endif /* FX_ENABLE_FAULT_TOLERANT */
864
865
    /* Release media protection.  */
866
12
    FX_UNPROTECT
867
868
    /* Return status to the caller.  */
869
12
    return(status);
870
}
871