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

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   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_FAT_entry_read            Read a FAT entry              */
70
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
71
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
72
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
73
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
74
/*                                            transaction                 */
75
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
76
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
77
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
78
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
79
/*                                                                        */
80
/*  CALLED BY                                                             */
81
/*                                                                        */
82
/*    Application Code                                                    */
83
/*                                                                        */
84
/**************************************************************************/
85
22
UINT  _fx_file_extended_best_effort_allocate(FX_FILE *file_ptr, ULONG64 size, ULONG64 *actual_size_allocated)
86
{
87
88
UINT                   status;
89
ULONG                  i;
90
UINT                   found;
91
ULONG                  bytes_per_cluster;
92
ULONG                  FAT_index, start_FAT_index;
93
ULONG                  FAT_value;
94
ULONG                  clusters, maximum_clusters;
95
FX_MEDIA              *media_ptr;
96
97
98
#ifdef TX_ENABLE_EVENT_TRACE
99
TX_TRACE_BUFFER_ENTRY *trace_event;
100
ULONG                  trace_timestamp;
101
#endif
102
103
104
    /* First, determine if the file is still open.  */
105
22
    if (file_ptr -> fx_file_id != FX_FILE_ID)
106
    {
107
108
        /* Return the file not open error status.  */
109
2
        return(FX_NOT_OPEN);
110
    }
111
112
#ifndef FX_MEDIA_STATISTICS_DISABLE
113
    /* Setup pointer to media structure.  */
114
20
    media_ptr =  file_ptr -> fx_file_media_ptr;
115
116
    /* Increment the number of times this service has been called.  */
117
20
    media_ptr -> fx_media_file_best_effort_allocates++;
118
#endif
119
120
    /* Make sure this file is open for writing.  */
121
20
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
122
    {
123
124
        /* Return the access error exception - a write was attempted from
125
           a file opened for reading!  */
126
1
        return(FX_ACCESS_ERROR);
127
    }
128
129
    /* Determine if the requested allocation is for zero bytes.  */
130
19
    if (size == 0)
131
    {
132
133
        /* Return a size allocated of zero.  */
134
1
        *actual_size_allocated =  0;
135
136
        /* Return a successful completion - nothing needs to be done.  */
137
1
        return(FX_SUCCESS);
138
    }
139
140
    /* Setup pointer to associated media control block.  */
141
18
    media_ptr =  file_ptr -> fx_file_media_ptr;
142
143
    /* If trace is enabled, insert this event into the trace buffer.  */
144
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, file_ptr, size, 0, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
145
146
    /* Protect against other threads accessing the media.  */
147
18
    FX_PROTECT
148
149
#ifdef FX_ENABLE_FAULT_TOLERANT
150
    /* Start transaction. */
151
    _fx_fault_tolerant_transaction_start(media_ptr);
152
#endif /* FX_ENABLE_FAULT_TOLERANT */
153
154
    /* Check for write protect at the media level (set by driver).  */
155
18
    if (media_ptr -> fx_media_driver_write_protect)
156
    {
157
158
#ifdef FX_ENABLE_FAULT_TOLERANT
159
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
160
#endif /* FX_ENABLE_FAULT_TOLERANT */
161
162
        /* Release media protection.  */
163
1
        FX_UNPROTECT
164
165
        /* Return write protect error.  */
166
1
        return(FX_WRITE_PROTECT);
167
    }
168
169
    /* Calculate the number of bytes per cluster.  */
170
17
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
171
17
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
172
173
    /* Check for invalid value.  */
174
17
    if (bytes_per_cluster == 0)
175
    {
176
177
#ifdef FX_ENABLE_FAULT_TOLERANT
178
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
179
#endif /* FX_ENABLE_FAULT_TOLERANT */
180
181
        /* Release media protection.  */
182
1
        FX_UNPROTECT
183
184
        /* Invalid media, return error.  */
185
1
        return(FX_MEDIA_INVALID);
186
    }
187
188
    /* Calculate the number of consecutive clusters needed to satisfy this
189
       request.  */
190
16
    clusters =  (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
191
192
    /* Determine if cluster count is 0.  */
193
16
    if (clusters == 0)
194
    {
195
196
#ifdef FX_ENABLE_FAULT_TOLERANT
197
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
198
#endif /* FX_ENABLE_FAULT_TOLERANT */
199
200
        /* Release media protection.  */
201
1
        FX_UNPROTECT
202
203
        /* Size overflow when rounding to the next cluster, return an error status.  */
204
1
        return(FX_NO_MORE_SPACE);
205
    }
206
207
    /* Determine if there are no available clusters on the media.  */
208
15
    if (!media_ptr -> fx_media_available_clusters)
209
    {
210
211
#ifdef FX_ENABLE_FAULT_TOLERANT
212
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
213
#endif /* FX_ENABLE_FAULT_TOLERANT */
214
215
        /* Release media protection.  */
216
1
        FX_UNPROTECT
217
218
        /* Return a size allocated of zero, since no clusters were available.  */
219
1
        *actual_size_allocated =  0;
220
221
        /* Not enough clusters, return an error status.  */
222
1
        return(FX_NO_MORE_SPACE);
223
    }
224
225
    /* Determine if the requested file allocation would exceed the physical limit of the file.  */
226
14
    if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
227
13
        ((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
228
    {
229
230
#ifdef FX_ENABLE_FAULT_TOLERANT
231
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
232
#endif /* FX_ENABLE_FAULT_TOLERANT */
233
234
        /* Release media protection.  */
235
2
        FX_UNPROTECT
236
237
        /* Return the no more space error, since the new file size would be larger than
238
           the 32-bit field to represent it in the file's directory entry.  */
239
2
        return(FX_NO_MORE_SPACE);
240
    }
241
242
    /* Now we need to find the consecutive clusters.  */
243
12
    found =             FX_FALSE;
244
12
    FAT_index =         FX_FAT_ENTRY_START;
245
12
    maximum_clusters =  0;
246
12
    start_FAT_index =   FAT_index;
247
248
7164
    while (FAT_index < (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
249
    {
250
251
        /* Determine if enough consecutive FAT entries are available.  */
252
7162
        i =  0;
253
254
255
        do
256
        {
257
258
            /* Read a FAT entry.  */
259
7427
            status =  _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
260
261
            /* Check for a successful status.  */
262
7427
            if (status != FX_SUCCESS)
263
            {
264
265
#ifdef FX_ENABLE_FAULT_TOLERANT
266
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
267
#endif /* FX_ENABLE_FAULT_TOLERANT */
268
269
                /* Release media protection.  */
270
1
                FX_UNPROTECT
271
272
                /* Return the error status.  */
273
1
                return(status);
274
            }
275
276
            /* Determine if the entry is free.  */
277
7426
            if (FAT_value != FX_FREE_CLUSTER)
278
            {
279
7151
                break;
280
            }
281
282
            /* Otherwise, increment the consecutive FAT indices.  */
283
275
            i++;
284

275
        } while ((i < clusters) && ((FAT_index + i) < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START));
285
286
        /* Determine if a new maximum number of clusters has been found.  */
287
7161
        if (i > maximum_clusters)
288
        {
289
290
            /* Yes, remember the maximum number of clusters and the starting
291
               cluster.  */
292
11
            maximum_clusters =      i;
293
11
            start_FAT_index =       FAT_index;
294
        }
295
296
        /* Determine if we found enough FAT entries.  */
297
7161
        if (i >= clusters)
298
        {
299
300
            /* Yes, we have found enough FAT entries - set the found
301
               flag and get out of this loop.  */
302
9
            found =  FX_TRUE;
303
9
            break;
304
        }
305
        else
306
        {
307
308
            /* Position to the next possibly free FAT entry.  */
309
7152
            FAT_index =  FAT_index + i + 1;
310
    }
311
}
312
313
    /* Determine if the total request could not be satisfied, but a partial allocation
314
       could be satisfied.  */
315
11
    if (maximum_clusters)
316
    {
317
318
        /* Yes, there was at least one cluster.  Prepare to return this
319
           to the caller.  */
320
10
        FAT_index =  start_FAT_index;
321
10
        clusters =   maximum_clusters;
322
10
        found =      FX_TRUE;
323
    }
324
325
    /* Determine if we found enough consecutive clusters to satisfy the
326
       request.  */
327
11
    if (found)
328
    {
329
330
#ifdef FX_ENABLE_FAULT_TOLERANT
331
        if (media_ptr -> fx_media_fault_tolerant_enabled)
332
        {
333
334
            /* Record the FAT chain being applied to the file system. This information aids
335
               recovery effort if fault happens. */
336
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
337
            _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
338
                                             FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
339
        }
340
#endif /* FX_ENABLE_FAULT_TOLERANT */
341
342
343
        /* Update the link pointers in the new clusters.  */
344
271
        for (i = 0; i < (clusters - 1); i++)
345
        {
346
347
            /* Update the cluster links.  Since the allocation is
348
               sequential, we just have to link each FAT entry to the
349
               next one.  */
350
262
            status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
351
352
            /* Check for a bad status.  */
353
262
            if (status != FX_SUCCESS)
354
            {
355
356
#ifdef FX_ENABLE_FAULT_TOLERANT
357
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
358
#endif /* FX_ENABLE_FAULT_TOLERANT */
359
360
                /* Release media protection.  */
361
1
                FX_UNPROTECT
362
363
                /* Return the error status.  */
364
1
                return(status);
365
            }
366
        }
367
368
369
        /* Now place an EOF in the last cluster entry.  */
370
9
        status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
371
372
        /* Check for a bad status.  */
373
9
        if (status != FX_SUCCESS)
374
        {
375
376
#ifdef FX_ENABLE_FAULT_TOLERANT
377
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
378
#endif /* FX_ENABLE_FAULT_TOLERANT */
379
380
            /* Release media protection.  */
381
1
            FX_UNPROTECT
382
383
            /* Return the error status.  */
384
1
            return(status);
385
        }
386
387
#ifdef FX_FAULT_TOLERANT
388
389
        /* Flush the cached individual FAT entries */
390
        _fx_utility_FAT_flush(media_ptr);
391
#endif
392
393
        /* Actually link up the new clusters to the file.  */
394
395
        /* Determine if there are already clusters allocated for this file.  */
396
8
        if (file_ptr -> fx_file_total_clusters)
397
        {
398
399
400
            /* Linkup the last cluster.  */
401
6
            status =  _fx_utility_FAT_entry_write(media_ptr,
402
                                                  file_ptr -> fx_file_last_physical_cluster, FAT_index);
403
404
            /* Check for a bad status.  */
405
6
            if (status != FX_SUCCESS)
406
            {
407
408
#ifdef FX_ENABLE_FAULT_TOLERANT
409
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
410
#endif /* FX_ENABLE_FAULT_TOLERANT */
411
412
                /* Release media protection.  */
413
1
                FX_UNPROTECT
414
415
                /* Return the error status.  */
416
1
                return(status);
417
            }
418
419
            /* Determine if we are adding a sector after a write filled the previously
420
               allocated cluster exactly.  */
421
5
            if ((file_ptr -> fx_file_current_relative_sector >=
422
5
                 (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
423
4
                (file_ptr -> fx_file_current_logical_offset >=
424
4
                    media_ptr -> fx_media_bytes_per_sector))
425
            {
426
427
                /* Yes, we need to adjust all of the pertinent file parameters for
428
                   access into this newly allocated cluster.  */
429
2
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
430
2
                file_ptr -> fx_file_current_relative_cluster++;
431
2
                file_ptr -> fx_file_current_relative_sector =   0;
432
2
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
433
2
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
434
2
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
435
2
                file_ptr -> fx_file_current_logical_offset =    0;
436
            }
437
        }
438
        else
439
        {
440
441
            /* These new clusters are also the first!  Setup the initial
442
               file parameters.  */
443
2
            file_ptr -> fx_file_first_physical_cluster =    FAT_index;
444
2
            file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
445
2
            file_ptr -> fx_file_current_relative_cluster =  0;
446
2
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
447
2
                (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
448
2
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
449
2
            file_ptr -> fx_file_current_logical_offset =    0;
450
2
            file_ptr -> fx_file_current_file_offset =       0;
451
452
            /* Setup the consecutive clusters at the beginning of the file.  */
453
2
            file_ptr -> fx_file_consecutive_cluster =       clusters;
454
455
            /* Update the first cluster in the directory entry.  */
456
2
            file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
457
458
#ifdef FX_ENABLE_FAULT_TOLERANT
459
            if (media_ptr -> fx_media_fault_tolerant_enabled)
460
            {
461
462
                /* Clear undo phase. */
463
                media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
464
            }
465
#endif /* FX_ENABLE_FAULT_TOLERANT */
466
        }
467
468
        /* Remember the last physical cluster.  */
469
7
        file_ptr -> fx_file_last_physical_cluster =     FAT_index + clusters - 1;
470
471
        /* Update the available size.  */
472
473
        /* Normal condition, update the available size.  */
474
7
        file_ptr -> fx_file_current_available_size =
475
7
            file_ptr -> fx_file_current_available_size + bytes_per_cluster * clusters;
476
477
        /* Increment the total clusters for this file.  */
478
7
        file_ptr -> fx_file_total_clusters =
479
7
            file_ptr -> fx_file_total_clusters + clusters;
480
481
        /* Decrease the available clusters on the media.  */
482
7
        media_ptr -> fx_media_available_clusters =
483
7
            media_ptr -> fx_media_available_clusters - clusters;
484
485
        /* Return the actual size allocated.  */
486
7
        *actual_size_allocated =  ((ULONG64)clusters) * bytes_per_cluster;
487
488
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
489
490
        /* Set the file size the current size plus what what was added.  */
491
        if (size < *actual_size_allocated)
492
        {
493
            file_ptr -> fx_file_current_file_size +=  size;
494
        }
495
        else
496
        {
497
            file_ptr -> fx_file_current_file_size +=  *actual_size_allocated;
498
        }
499
500
        /* Copy the new file size into the directory entry.  */
501
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  file_ptr -> fx_file_current_file_size;
502
#endif
503
504
        /* Update the trace event with the bytes allocated.  */
505
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_BEST_EFFORT_ALLOCATE, 0, 0, *actual_size_allocated, 0);
506
507
        /* Write the directory entry to the media.  */
508
7
        status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
509
510
        /* Check for a good status.  */
511
7
        if (status != FX_SUCCESS)
512
        {
513
514
#ifdef FX_ENABLE_FAULT_TOLERANT
515
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
516
#endif /* FX_ENABLE_FAULT_TOLERANT */
517
518
            /* Release media protection.  */
519
1
            FX_UNPROTECT
520
521
            /* Return the error status.  */
522
1
            return(status);
523
        }
524
    }
525
    else
526
    {
527
528
#ifdef FX_ENABLE_FAULT_TOLERANT
529
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
530
#endif /* FX_ENABLE_FAULT_TOLERANT */
531
532
        /* Release media protection.  */
533
1
        FX_UNPROTECT
534
535
        /* Return a size allocated of zero, since no clusters were available.  */
536
1
        *actual_size_allocated =  0;
537
538
        /* Not enough contiguous space on the media.  Return error status.  */
539
1
        return(FX_NO_MORE_SPACE);
540
    }
541
542
#ifdef FX_FAULT_TOLERANT
543
544
    /* Flush the cached individual FAT entries */
545
    _fx_utility_FAT_flush(media_ptr);
546
#endif
547
548
    /* Flush the internal logical sector cache.  */
549
6
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
550
551
#ifdef FX_ENABLE_FAULT_TOLERANT
552
    /* Check for a bad status.  */
553
    if (status != FX_SUCCESS)
554
    {
555
556
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
557
558
        /* Release media protection.  */
559
        FX_UNPROTECT
560
561
        /* Return the bad status.  */
562
        return(status);
563
    }
564
565
    /* End transaction. */
566
    status = _fx_fault_tolerant_transaction_end(media_ptr);
567
#endif /* FX_ENABLE_FAULT_TOLERANT */
568
569
    /* Release media protection.  */
570
6
    FX_UNPROTECT
571
572
    /* Return status to the caller.  */
573
6
    return(status);
574
}
575