GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_allocate.c Lines: 97 97 100.0 %
Date: 2024-03-11 05:15:45 Branches: 46 46 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** FileX Component                                                       */
16
/**                                                                       */
17
/**   File                                                                */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define FX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "fx_api.h"
28
#include "fx_system.h"
29
#include "fx_file.h"
30
#include "fx_utility.h"
31
#include "fx_directory.h"
32
#ifdef FX_ENABLE_FAULT_TOLERANT
33
#include "fx_fault_tolerant.h"
34
#endif /* FX_ENABLE_FAULT_TOLERANT */
35
36
37
/**************************************************************************/
38
/*                                                                        */
39
/*  FUNCTION                                               RELEASE        */
40
/*                                                                        */
41
/*    _fx_file_extended_allocate                          PORTABLE C      */
42
/*                                                           6.1          */
43
/*  AUTHOR                                                                */
44
/*                                                                        */
45
/*    William E. Lamie, Microsoft Corporation                             */
46
/*                                                                        */
47
/*  DESCRIPTION                                                           */
48
/*                                                                        */
49
/*    This function attempts to allocate the number of consecutive        */
50
/*    clusters required to satisfy the user's request.  If there are      */
51
/*    enough clusters, the clusters are allocated and linked to the file. */
52
/*    Otherwise, if there are not enough consecutive clusters, an error   */
53
/*    code is returned to the caller.                                     */
54
/*                                                                        */
55
/*  INPUT                                                                 */
56
/*                                                                        */
57
/*    file_ptr                              File control block pointer    */
58
/*    size                                  Number of bytes to allocate   */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _fx_directory_entry_write             Update directory entry        */
67
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
68
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
69
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
70
/*    _fx_utility_logical_sector_flush      Flush the written log sector  */
71
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
72
/*                                            transaction                 */
73
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
74
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
75
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
76
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
77
/*                                                                        */
78
/*  CALLED BY                                                             */
79
/*                                                                        */
80
/*    Application Code                                                    */
81
/*                                                                        */
82
/*  RELEASE HISTORY                                                       */
83
/*                                                                        */
84
/*    DATE              NAME                      DESCRIPTION             */
85
/*                                                                        */
86
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
87
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
88
/*                                            resulting in version 6.1    */
89
/*                                                                        */
90
/**************************************************************************/
91
27
UINT  _fx_file_extended_allocate(FX_FILE *file_ptr, ULONG64 size)
92
{
93
94
UINT                   status;
95
ULONG                  i;
96
UINT                   found;
97
ULONG                  bytes_per_cluster;
98
ULONG                  FAT_index;
99
ULONG                  FAT_value;
100
ULONG                  clusters;
101
FX_MEDIA              *media_ptr;
102
103
#ifdef TX_ENABLE_EVENT_TRACE
104
TX_TRACE_BUFFER_ENTRY *trace_event;
105
ULONG                  trace_timestamp;
106
#endif
107
108
109
    /* First, determine if the file is still open.  */
110
27
    if (file_ptr -> fx_file_id != FX_FILE_ID)
111
    {
112
113
        /* Return the file not open error status.  */
114
1
        return(FX_NOT_OPEN);
115
    }
116
117
    /* Setup pointer to media structure.  */
118
26
    media_ptr =  file_ptr -> fx_file_media_ptr;
119
120
#ifndef FX_MEDIA_STATISTICS_DISABLE
121
122
    /* Increment the number of times this service has been called.  */
123
26
    media_ptr -> fx_media_file_allocates++;
124
#endif
125
126
    /* Make sure this file is open for writing.  */
127
26
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
128
    {
129
130
        /* Return the access error exception - a write was attempted from
131
           a file opened for reading!  */
132
1
        return(FX_ACCESS_ERROR);
133
    }
134
135
    /* Determine if the requested allocation is for zero bytes.  */
136
25
    if (size == 0)
137
    {
138
139
        /* Return a successful completion - nothing needs to be done.  */
140
1
        return(FX_SUCCESS);
141
    }
142
143
    /* Setup pointer to associated media control block.  */
144
24
    media_ptr =  file_ptr -> fx_file_media_ptr;
145
146
    /* If trace is enabled, insert this event into the trace buffer.  */
147
    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)
148
149
    /* Protect against other threads accessing the media.  */
150
24
    FX_PROTECT
151
152
#ifdef FX_ENABLE_FAULT_TOLERANT
153
    /* Start transaction. */
154
    _fx_fault_tolerant_transaction_start(media_ptr);
155
#endif /* FX_ENABLE_FAULT_TOLERANT */
156
157
    /* Check for write protect at the media level (set by driver).  */
158
24
    if (media_ptr -> fx_media_driver_write_protect)
159
    {
160
161
#ifdef FX_ENABLE_FAULT_TOLERANT
162
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
163
#endif /* FX_ENABLE_FAULT_TOLERANT */
164
165
        /* Release media protection.  */
166
1
        FX_UNPROTECT
167
168
        /* Return write protect error.  */
169
1
        return(FX_WRITE_PROTECT);
170
    }
171
172
    /* Calculate the number of bytes per cluster.  */
173
23
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
174
23
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
175
176
    /* Check for invalid value.  */
177
23
    if (bytes_per_cluster == 0)
178
    {
179
180
#ifdef FX_ENABLE_FAULT_TOLERANT
181
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
182
#endif /* FX_ENABLE_FAULT_TOLERANT */
183
184
        /* Release media protection.  */
185
1
        FX_UNPROTECT
186
187
        /* Invalid media, return error.  */
188
1
        return(FX_MEDIA_INVALID);
189
    }
190
191
    /* Calculate the number of consecutive clusters needed to satisfy this
192
       request.  */
193
22
    clusters =  (ULONG)(((size + bytes_per_cluster - 1) / bytes_per_cluster));
194
195
    /* Determine if cluster count is 0.  */
196
22
    if (clusters == 0)
197
    {
198
199
#ifdef FX_ENABLE_FAULT_TOLERANT
200
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
201
#endif /* FX_ENABLE_FAULT_TOLERANT */
202
203
        /* Release media protection.  */
204
1
        FX_UNPROTECT
205
206
        /* Size overflow when rounding to the next cluster, return an error status.  */
207
1
        return(FX_NO_MORE_SPACE);
208
    }
209
210
    /* Determine if there are enough available clusters on the media.  */
211
21
    if (clusters > media_ptr -> fx_media_available_clusters)
212
    {
213
214
#ifdef FX_ENABLE_FAULT_TOLERANT
215
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
216
#endif /* FX_ENABLE_FAULT_TOLERANT */
217
218
        /* Release media protection.  */
219
1
        FX_UNPROTECT
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
20
    if (((file_ptr -> fx_file_current_available_size + (((ULONG64) clusters) * ((ULONG64) bytes_per_cluster))) < file_ptr -> fx_file_current_available_size) ||
227
19
        ((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
18
    FAT_index =  FX_FAT_ENTRY_START;
244
18
    found =      FX_FALSE;
245
246
247
6957
    while (FAT_index <= (media_ptr -> fx_media_total_clusters - clusters + FX_FAT_ENTRY_START))
248
    {
249
250
        /* Determine if enough consecutive FAT entries are available.  */
251
6956
        i =  0;
252
253
254
        do
255
        {
256
257
            /* Read a FAT entry.  */
258
7224
            status =  _fx_utility_FAT_entry_read(media_ptr, (FAT_index + i), &FAT_value);
259
260
            /* Check for a successful status.  */
261
7224
            if (status != FX_SUCCESS)
262
            {
263
264
#ifdef FX_ENABLE_FAULT_TOLERANT
265
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
266
#endif /* FX_ENABLE_FAULT_TOLERANT */
267
268
                /* Release media protection.  */
269
1
                FX_UNPROTECT
270
271
                /* Return the error status.  */
272
1
                return(status);
273
            }
274
275
            /* Determine if the entry is free.  */
276
7223
            if (FAT_value != FX_FREE_CLUSTER)
277
            {
278
6939
                break;
279
            }
280
281
            /* Otherwise, increment the consecutive FAT indices.  */
282
284
            i++;
283
284
        } while (i < clusters);
284
285
        /* Determine if we found enough FAT entries.  */
286
6955
        if (i >= clusters)
287
        {
288
289
            /* Yes, we have found enough FAT entries - set the found
290
               flag and get out of this loop.  */
291
16
            found =  FX_TRUE;
292
16
            break;
293
        }
294
        else
295
        {
296
            /* Position to the next possibly free FAT entry.  */
297
6939
            FAT_index =  FAT_index + i + 1;
298
    }
299
}
300
301
    /* Determine if we found enough consecutive clusters to satisfy the
302
       request.  */
303
17
    if (found)
304
    {
305
306
#ifdef FX_ENABLE_FAULT_TOLERANT
307
        if (media_ptr -> fx_media_fault_tolerant_enabled)
308
        {
309
310
            /* Record the action that is about to take place.  This information
311
               would aid the undo process should fault condition happens. */
312
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
313
            _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_last_physical_cluster,
314
                                             FAT_index, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
315
        }
316
#endif /* FX_ENABLE_FAULT_TOLERANT */
317
318
319
        /* Update the link pointers in the new clusters.  */
320
280
        for (i = 0; i < (clusters - 1); i++)
321
        {
322
323
            /* Update the cluster links.  Since the allocation is
324
               sequential, we just have to link each FAT entry to the
325
               next one.  */
326
265
            status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + i, FAT_index + i + 1);
327
328
            /* Check for a bad status.  */
329
265
            if (status != FX_SUCCESS)
330
            {
331
332
#ifdef FX_ENABLE_FAULT_TOLERANT
333
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
334
#endif /* FX_ENABLE_FAULT_TOLERANT */
335
336
                /* Release media protection.  */
337
1
                FX_UNPROTECT
338
339
                /* Return the error status.  */
340
1
                return(status);
341
            }
342
        }
343
344
        /* Now place an EOF in the last cluster entry.  */
345
15
        status =  _fx_utility_FAT_entry_write(media_ptr, FAT_index + clusters - 1, media_ptr -> fx_media_fat_last);
346
347
        /* Check for a bad status.  */
348
15
        if (status != FX_SUCCESS)
349
        {
350
351
#ifdef FX_ENABLE_FAULT_TOLERANT
352
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
353
#endif /* FX_ENABLE_FAULT_TOLERANT */
354
355
            /* Release media protection.  */
356
1
            FX_UNPROTECT
357
358
            /* Return the error status.  */
359
1
            return(status);
360
        }
361
362
#ifdef FX_FAULT_TOLERANT
363
364
        /* Flush the cached individual FAT entries */
365
        _fx_utility_FAT_flush(media_ptr);
366
367
#endif
368
369
        /* Actually link up the new clusters to the file.  */
370
371
        /* Determine if there are already clusters allocated for this file.  */
372
14
        if (file_ptr -> fx_file_total_clusters)
373
        {
374
375
            /* Linkup the last cluster.  */
376
7
            status =  _fx_utility_FAT_entry_write(media_ptr,
377
                                                  file_ptr -> fx_file_last_physical_cluster, FAT_index);
378
379
            /* Check for a bad status.  */
380
7
            if (status != FX_SUCCESS)
381
            {
382
383
#ifdef FX_ENABLE_FAULT_TOLERANT
384
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
385
#endif /* FX_ENABLE_FAULT_TOLERANT */
386
387
                /* Release media protection.  */
388
1
                FX_UNPROTECT
389
390
                /* Return the error status.  */
391
1
                return(status);
392
            }
393
394
            /* Determine if we are adding a sector after a write filled the previously
395
               allocated cluster exactly.  */
396
6
            if ((file_ptr -> fx_file_current_relative_sector >=
397
6
                (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
398
5
                (file_ptr -> fx_file_current_logical_offset >=
399
5
                 media_ptr -> fx_media_bytes_per_sector))
400
            {
401
402
                /* Yes, we need to adjust all of the pertinent file parameters for
403
                   access into this newly allocated cluster.  */
404
3
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
405
3
                file_ptr -> fx_file_current_relative_cluster++;
406
3
                file_ptr -> fx_file_current_relative_sector =   0;
407
3
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
408
3
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
409
3
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
410
3
                file_ptr -> fx_file_current_logical_offset =    0;
411
            }
412
        }
413
        else
414
        {
415
416
            /* These new clusters are also the first!  Setup the initial
417
               file parameters.  */
418
7
            file_ptr -> fx_file_first_physical_cluster =    FAT_index;
419
7
            file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
420
7
            file_ptr -> fx_file_current_relative_cluster =  0;
421
7
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
422
7
                (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
423
7
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
424
7
            file_ptr -> fx_file_current_logical_offset =    0;
425
7
            file_ptr -> fx_file_current_file_offset =       0;
426
427
            /* Update the first cluster in the directory entry.  */
428
7
            file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
429
        }
430
431
        /* Remember the last physical cluster.  */
432
13
        file_ptr -> fx_file_last_physical_cluster =     FAT_index + clusters - 1;
433
434
435
        /* Check for wrap-around when updating the available size.  */
436
        /* Update the available size.  */
437
13
        file_ptr -> fx_file_current_available_size =
438
13
                file_ptr -> fx_file_current_available_size + (bytes_per_cluster * clusters);
439
440
441
        /* Increment the total clusters for this file.  */
442
13
        file_ptr -> fx_file_total_clusters =
443
13
            file_ptr -> fx_file_total_clusters + clusters;
444
445
        /* Decrease the available clusters on the media.  */
446
13
        media_ptr -> fx_media_available_clusters =
447
13
            media_ptr -> fx_media_available_clusters - clusters;
448
449
#if defined(FX_UPDATE_FILE_SIZE_ON_ALLOCATE) || defined(FX_ENABLE_FAULT_TOLERANT)
450
451
        /* Set the file size the current size plus what what was added.  */
452
        file_ptr -> fx_file_current_file_size +=  size;
453
454
        /* Copy the new file size into the directory entry.  */
455
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  file_ptr -> fx_file_current_file_size;
456
#endif
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
        /* Update the trace event with the new size.  */
468
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_ALLOCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size);
469
470
        /* Write the directory entry to the media.  */
471
13
        status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
472
473
        /* Check for a good status.  */
474
13
        if (status != FX_SUCCESS)
475
        {
476
477
#ifdef FX_ENABLE_FAULT_TOLERANT
478
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
479
#endif /* FX_ENABLE_FAULT_TOLERANT */
480
481
            /* Release media protection.  */
482
1
            FX_UNPROTECT
483
484
            /* Return the error status.  */
485
1
            return(status);
486
        }
487
    }
488
    else
489
    {
490
491
#ifdef FX_ENABLE_FAULT_TOLERANT
492
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
493
#endif /* FX_ENABLE_FAULT_TOLERANT */
494
495
        /* Release media protection.  */
496
1
        FX_UNPROTECT
497
498
        /* Not enough contiguous space on the media.  Return error status.  */
499
1
        return(FX_NO_MORE_SPACE);
500
    }
501
502
#ifdef FX_FAULT_TOLERANT
503
504
    /* Flush the cached individual FAT entries */
505
    _fx_utility_FAT_flush(media_ptr);
506
#endif
507
508
    /* Flush the internal logical sector cache.  */
509
12
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64)(media_ptr -> fx_media_sectors_per_FAT), FX_FALSE);
510
511
#ifdef FX_ENABLE_FAULT_TOLERANT
512
    /* Check for a bad status.  */
513
    if (status != FX_SUCCESS)
514
    {
515
516
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
517
518
        /* Release media protection.  */
519
        FX_UNPROTECT
520
521
        /* Return the bad status.  */
522
        return(status);
523
    }
524
525
    if (media_ptr -> fx_media_fault_tolerant_enabled)
526
    {
527
528
        /* Copy the new file size into the directory entry.  */
529
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
530
    }
531
532
    /* End transaction. */
533
    status = _fx_fault_tolerant_transaction_end(media_ptr);
534
#endif /* FX_ENABLE_FAULT_TOLERANT */
535
536
    /* Release media protection.  */
537
12
    FX_UNPROTECT
538
539
    /* Return status to the caller.  */
540
12
    return(status);
541
}
542