GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_allocate.c Lines: 97 97 100.0 %
Date: 2026-03-06 18:49:02 Branches: 46 46 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_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_FAT_entry_read            Read a FAT entry              */
69
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
70
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
71
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
72
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
73
/*                                            transaction                 */
74
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
75
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
76
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
77
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
78
/*                                                                        */
79
/*  CALLED BY                                                             */
80
/*                                                                        */
81
/*    Application Code                                                    */
82
/*                                                                        */
83
/**************************************************************************/
84
27
UINT  _fx_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size)
85
{
86
87
UINT                   status;
88
ULONG                  i;
89
UINT                   found;
90
ULONG                  bytes_per_cluster;
91
ULONG                  FAT_index;
92
ULONG                  FAT_value;
93
ULONG                  clusters;
94
FX_MEDIA              *media_ptr;
95
96
#ifdef TX_ENABLE_EVENT_TRACE
97
TX_TRACE_BUFFER_ENTRY *trace_event;
98
ULONG                  trace_timestamp;
99
#endif
100
101
102
    /* First, determine if the file is still open.  */
103
27
    if (file_ptr -> fx_file_id != FX_FILE_ID)
104
    {
105
106
        /* Return the file not open error status.  */
107
1
        return(FX_NOT_OPEN);
108
    }
109
110
    /* Setup pointer to media structure.  */
111
26
    media_ptr =  file_ptr -> fx_file_media_ptr;
112
113
#ifndef FX_MEDIA_STATISTICS_DISABLE
114
115
    /* Increment the number of times this service has been called.  */
116
26
    media_ptr -> fx_media_file_allocates++;
117
#endif
118
119
    /* Make sure this file is open for writing.  */
120
26
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
121
    {
122
123
        /* Return the access error exception - a write was attempted from
124
           a file opened for reading!  */
125
1
        return(FX_ACCESS_ERROR);
126
    }
127
128
    /* Determine if the requested allocation is for zero bytes.  */
129
25
    if (size == 0)
130
    {
131
132
        /* Return a successful completion - nothing needs to be done.  */
133
1
        return(FX_SUCCESS);
134
    }
135
136
    /* Setup pointer to associated media control block.  */
137
24
    media_ptr =  file_ptr -> fx_file_media_ptr;
138
139
    /* If trace is enabled, insert this event into the trace buffer.  */
140
    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)
141
142
    /* Protect against other threads accessing the media.  */
143
24
    FX_PROTECT
144
145
#ifdef FX_ENABLE_FAULT_TOLERANT
146
    /* Start transaction. */
147
    _fx_fault_tolerant_transaction_start(media_ptr);
148
#endif /* FX_ENABLE_FAULT_TOLERANT */
149
150
    /* Check for write protect at the media level (set by driver).  */
151
24
    if (media_ptr -> fx_media_driver_write_protect)
152
    {
153
154
#ifdef FX_ENABLE_FAULT_TOLERANT
155
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
156
#endif /* FX_ENABLE_FAULT_TOLERANT */
157
158
        /* Release media protection.  */
159
1
        FX_UNPROTECT
160
161
        /* Return write protect error.  */
162
1
        return(FX_WRITE_PROTECT);
163
    }
164
165
    /* Calculate the number of bytes per cluster.  */
166
23
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
167
23
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
168
169
    /* Check for invalid value.  */
170
23
    if (bytes_per_cluster == 0)
171
    {
172
173
#ifdef FX_ENABLE_FAULT_TOLERANT
174
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
175
#endif /* FX_ENABLE_FAULT_TOLERANT */
176
177
        /* Release media protection.  */
178
1
        FX_UNPROTECT
179
180
        /* Invalid media, return error.  */
181
1
        return(FX_MEDIA_INVALID);
182
    }
183
184
    /* Calculate the number of consecutive clusters needed to satisfy this
185
       request.  */
186
22
    clusters =  (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
187
188
    /* Determine if cluster count is 0.  */
189
22
    if (clusters == 0)
190
    {
191
192
#ifdef FX_ENABLE_FAULT_TOLERANT
193
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
194
#endif /* FX_ENABLE_FAULT_TOLERANT */
195
196
        /* Release media protection.  */
197
1
        FX_UNPROTECT
198
199
        /* Size overflow when rounding to the next cluster, return an error status.  */
200
1
        return(FX_NO_MORE_SPACE);
201
    }
202
203
    /* Determine if there are enough available clusters on the media.  */
204
21
    if (clusters > media_ptr -> fx_media_available_clusters)
205
    {
206
207
#ifdef FX_ENABLE_FAULT_TOLERANT
208
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
209
#endif /* FX_ENABLE_FAULT_TOLERANT */
210
211
        /* Release media protection.  */
212
1
        FX_UNPROTECT
213
214
        /* Not enough clusters, return an error status.  */
215
1
        return(FX_NO_MORE_SPACE);
216
    }
217
218
    /* Determine if the requested file allocation would exceed the physical limit of the file.  */
219
20
    if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
220
19
        ((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) > 0xFFFFFFFFULL))
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
2
        FX_UNPROTECT
229
230
        /* Return the no more space error, since the new file size would be larger than
231
           the 32-bit field to represent it in the file's directory entry.  */
232
2
        return(FX_NO_MORE_SPACE);
233
    }
234
235
    /* Now we need to find the consecutive clusters.  */
236
18
    FAT_index =  FX_FAT_ENTRY_START;
237
18
    found =      FX_FALSE;
238
239
240
6957
    while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
241
    {
242
243
        /* Determine if enough consecutive FAT entries are available.  */
244
6956
        i =  0;
245
246
247
        do
248
        {
249
250
            /* Read a FAT entry.  */
251
7224
            status =  _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
252
253
            /* Check for a successful status.  */
254
7224
            if (status != FX_SUCCESS)
255
            {
256
257
#ifdef FX_ENABLE_FAULT_TOLERANT
258
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
259
#endif /* FX_ENABLE_FAULT_TOLERANT */
260
261
                /* Release media protection.  */
262
1
                FX_UNPROTECT
263
264
                /* Return the error status.  */
265
1
                return(status);
266
            }
267
268
            /* Determine if the entry is free.  */
269
7223
            if (FAT_value != FX_FREE_CLUSTER)
270
            {
271
6939
                break;
272
            }
273
274
            /* Otherwise, increment the consecutive FAT indices.  */
275
284
            i++;
276
284
        } while (i < clusters);
277
278
        /* Determine if we found enough FAT entries.  */
279
6955
        if (i >= clusters)
280
        {
281
282
            /* Yes, we have found enough FAT entries - set the found
283
               flag and get out of this loop.  */
284
16
            found =  FX_TRUE;
285
16
            break;
286
        }
287
        else
288
        {
289
            /* Position to the next possibly free FAT entry.  */
290
6939
            FAT_index =  FAT_index + i + 1;
291
    }
292
}
293
294
    /* Determine if we found enough consecutive clusters to satisfy the
295
       request.  */
296
17
    if (found)
297
    {
298
299
#ifdef FX_ENABLE_FAULT_TOLERANT
300
        if (media_ptr -> fx_media_fault_tolerant_enabled)
301
        {
302
303
            /* Record the action that is about to take place.  This information
304
               would aid the undo process should fault condition happens. */
305
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
306
            _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
307
                                             FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
308
        }
309
#endif /* FX_ENABLE_FAULT_TOLERANT */
310
311
312
        /* Update the link pointers in the new clusters.  */
313
280
        for (i = 0; i < (clusters - 1); i++)
314
        {
315
316
            /* Update the cluster links.  Since the allocation is
317
               sequential, we just have to link each FAT entry to the
318
               next one.  */
319
265
            status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
320
321
            /* Check for a bad status.  */
322
265
            if (status != FX_SUCCESS)
323
            {
324
325
#ifdef FX_ENABLE_FAULT_TOLERANT
326
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
327
#endif /* FX_ENABLE_FAULT_TOLERANT */
328
329
                /* Release media protection.  */
330
1
                FX_UNPROTECT
331
332
                /* Return the error status.  */
333
1
                return(status);
334
            }
335
        }
336
337
        /* Now place an EOF in the last cluster entry.  */
338
15
        status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
339
340
        /* Check for a bad status.  */
341
15
        if (status != FX_SUCCESS)
342
        {
343
344
#ifdef FX_ENABLE_FAULT_TOLERANT
345
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
346
#endif /* FX_ENABLE_FAULT_TOLERANT */
347
348
            /* Release media protection.  */
349
1
            FX_UNPROTECT
350
351
            /* Return the error status.  */
352
1
            return(status);
353
        }
354
355
#ifdef FX_FAULT_TOLERANT
356
357
        /* Flush the cached individual FAT entries */
358
        _fx_utility_FAT_flush(media_ptr);
359
360
#endif
361
362
        /* Actually link up the new clusters to the file.  */
363
364
        /* Determine if there are already clusters allocated for this file.  */
365
14
        if (file_ptr -> fx_file_total_clusters)
366
        {
367
368
            /* Linkup the last cluster.  */
369
7
            status =  _fx_utility_FAT_entry_write(media_ptr,
370
                                                  file_ptr -> fx_file_last_physical_cluster, FAT_index);
371
372
            /* Check for a bad status.  */
373
7
            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
            /* Determine if we are adding a sector after a write filled the previously
388
               allocated cluster exactly.  */
389
6
            if ((file_ptr -> fx_file_current_relative_sector >=
390
6
                (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
391
5
                (file_ptr -> fx_file_current_logical_offset >=
392
5
                 media_ptr -> fx_media_bytes_per_sector))
393
            {
394
395
                /* Yes, we need to adjust all of the pertinent file parameters for
396
                   access into this newly allocated cluster.  */
397
3
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
398
3
                file_ptr -> fx_file_current_relative_cluster++;
399
3
                file_ptr -> fx_file_current_relative_sector =   0;
400
3
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
401
3
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
402
3
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
403
3
                file_ptr -> fx_file_current_logical_offset =    0;
404
            }
405
        }
406
        else
407
        {
408
409
            /* These new clusters are also the first!  Setup the initial
410
               file parameters.  */
411
7
            file_ptr -> fx_file_first_physical_cluster =    FAT_index;
412
7
            file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
413
7
            file_ptr -> fx_file_current_relative_cluster =  0;
414
7
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
415
7
                (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
416
7
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
417
7
            file_ptr -> fx_file_current_logical_offset =    0;
418
7
            file_ptr -> fx_file_current_file_offset =       0;
419
420
            /* Update the first cluster in the directory entry.  */
421
7
            file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
422
        }
423
424
        /* Remember the last physical cluster.  */
425
13
        file_ptr -> fx_file_last_physical_cluster =     FAT_index + clusters - 1;
426
427
428
        /* Check for wrap-around when updating the available size.  */
429
        /* Update the available size.  */
430
13
        file_ptr -> fx_file_current_available_size =
431
13
                file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
432
433
434
        /* Increment the total clusters for this file.  */
435
13
        file_ptr -> fx_file_total_clusters =
436
13
            file_ptr -> fx_file_total_clusters + clusters;
437
438
        /* Decrease the available clusters on the media.  */
439
13
        media_ptr -> fx_media_available_clusters =
440
13
            media_ptr -> fx_media_available_clusters - clusters;
441
442
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
443
444
        /* Set the file size the current size plus what what was added.  */
445
        file_ptr -> fx_file_current_file_size +=  size;
446
447
        /* Copy the new file size into the directory entry.  */
448
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  file_ptr -> fx_file_current_file_size;
449
#endif
450
451
#ifdef FX_ENABLE_FAULT_TOLERANT
452
        if (media_ptr -> fx_media_fault_tolerant_enabled)
453
        {
454
455
            /* Clear undo phase. */
456
            media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
457
        }
458
#endif /* FX_ENABLE_FAULT_TOLERANT */
459
460
        /* Update the trace event with the new size.  */
461
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_ALLOCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size);
462
463
        /* Write the directory entry to the media.  */
464
13
        status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
465
466
        /* Check for a good status.  */
467
13
        if (status != FX_SUCCESS)
468
        {
469
470
#ifdef FX_ENABLE_FAULT_TOLERANT
471
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
472
#endif /* FX_ENABLE_FAULT_TOLERANT */
473
474
            /* Release media protection.  */
475
1
            FX_UNPROTECT
476
477
            /* Return the error status.  */
478
1
            return(status);
479
        }
480
    }
481
    else
482
    {
483
484
#ifdef FX_ENABLE_FAULT_TOLERANT
485
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
486
#endif /* FX_ENABLE_FAULT_TOLERANT */
487
488
        /* Release media protection.  */
489
1
        FX_UNPROTECT
490
491
        /* Not enough contiguous space on the media.  Return error status.  */
492
1
        return(FX_NO_MORE_SPACE);
493
    }
494
495
#ifdef FX_FAULT_TOLERANT
496
497
    /* Flush the cached individual FAT entries */
498
    _fx_utility_FAT_flush(media_ptr);
499
#endif
500
501
    /* Flush the internal logical sector cache.  */
502
12
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
503
504
#ifdef FX_ENABLE_FAULT_TOLERANT
505
    /* Check for a bad status.  */
506
    if (status != FX_SUCCESS)
507
    {
508
509
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
510
511
        /* Release media protection.  */
512
        FX_UNPROTECT
513
514
        /* Return the bad status.  */
515
        return(status);
516
    }
517
518
    if (media_ptr -> fx_media_fault_tolerant_enabled)
519
    {
520
521
        /* Copy the new file size into the directory entry.  */
522
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
523
    }
524
525
    /* End transaction. */
526
    status = _fx_fault_tolerant_transaction_end(media_ptr);
527
#endif /* FX_ENABLE_FAULT_TOLERANT */
528
529
    /* Release media protection.  */
530
12
    FX_UNPROTECT
531
532
    /* Return status to the caller.  */
533
12
    return(status);
534
}
535