GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_truncate_release.c Lines: 154 154 100.0 %
Date: 2024-01-10 21:53:23 Branches: 68 68 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_directory.h"
31
#include "fx_file.h"
32
#include "fx_utility.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_truncate_release                  PORTABLE C      */
43
/*                                                           6.1.3        */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    William E. Lamie, Microsoft Corporation                             */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function sets the file to the specified size, if smaller than  */
51
/*    the current file size.  If the new file size is less than the       */
52
/*    current file read/write position, the internal file pointers will   */
53
/*    also be modified.  Any unused clusters are released back to the     */
54
/*    media.                                                              */
55
/*                                                                        */
56
/*  INPUT                                                                 */
57
/*                                                                        */
58
/*    file_ptr                              File control block pointer    */
59
/*    size                                  New size of the file in bytes */
60
/*                                                                        */
61
/*  OUTPUT                                                                */
62
/*                                                                        */
63
/*    return status                                                       */
64
/*                                                                        */
65
/*  CALLS                                                                 */
66
/*                                                                        */
67
/*    _fx_directory_entry_write             Write directory entry         */
68
/*    _fx_utility_exFAT_bitmap_flush        Flush exFAT allocation bitmap */
69
/*    _fx_utility_exFAT_cluster_state_set   Set cluster state             */
70
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
71
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
72
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
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
/*  RELEASE HISTORY                                                       */
85
/*                                                                        */
86
/*    DATE              NAME                      DESCRIPTION             */
87
/*                                                                        */
88
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
89
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
90
/*                                            resulting in version 6.1    */
91
/*  12-31-2020     William E. Lamie         Modified comment(s), fixed    */
92
/*                                            available cluster issue,    */
93
/*                                            resulting in version 6.1.3  */
94
/*                                                                        */
95
/**************************************************************************/
96
31
UINT  _fx_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size)
97
{
98
99
UINT                   status;
100
ULONG                  cluster;
101
ULONG                  contents;
102
ULONG                  bytes_per_cluster;
103
ULONG                  last_cluster;
104
ULONG                  cluster_count;
105
ULONG64                bytes_remaining;
106
FX_MEDIA              *media_ptr;
107
108
#ifdef FX_ENABLE_EXFAT
109
ULONG                  original_last_physical_cluster;
110
#endif /* FX_ENABLE_EXFAT */
111
112
#ifndef FX_DONT_UPDATE_OPEN_FILES
113
ULONG                  open_count;
114
FX_FILE               *search_ptr;
115
#endif
116
117
#ifdef TX_ENABLE_EVENT_TRACE
118
TX_TRACE_BUFFER_ENTRY *trace_event;
119
ULONG                  trace_timestamp;
120
#endif
121
122
123
    /* First, determine if the file is still open.  */
124
31
    if (file_ptr -> fx_file_id != FX_FILE_ID)
125
    {
126
127
        /* Return the file not open error status.  */
128
1
        return(FX_NOT_OPEN);
129
    }
130
131
#ifndef FX_MEDIA_STATISTICS_DISABLE
132
    /* Setup pointer to media structure.  */
133
30
    media_ptr =  file_ptr -> fx_file_media_ptr;
134
135
    /* Increment the number of times this service has been called.  */
136
30
    media_ptr -> fx_media_file_truncate_releases++;
137
#endif
138
139
    /* Setup pointer to associated media control block.  */
140
30
    media_ptr =  file_ptr -> fx_file_media_ptr;
141
142
    /* If trace is enabled, insert this event into the trace buffer.  */
143
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE_RELEASE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
144
145
    /* Protect against other threads accessing the media.  */
146
30
    FX_PROTECT
147
148
#ifdef FX_ENABLE_FAULT_TOLERANT
149
    /* Start transaction. */
150
    _fx_fault_tolerant_transaction_start(media_ptr);
151
#endif /* FX_ENABLE_FAULT_TOLERANT */
152
153
    /* Make sure this file is open for writing.  */
154
30
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
155
    {
156
157
#ifdef FX_ENABLE_FAULT_TOLERANT
158
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
159
#endif /* FX_ENABLE_FAULT_TOLERANT */
160
161
        /* Release media protection.  */
162
1
        FX_UNPROTECT
163
164
        /* Return the access error exception - a write was attempted from
165
           a file opened for reading!  */
166
1
        return(FX_ACCESS_ERROR);
167
    }
168
169
    /* Check for write protect at the media level (set by driver).  */
170
29
    if (media_ptr -> fx_media_driver_write_protect)
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
        /* Return write protect error.  */
181
1
        return(FX_WRITE_PROTECT);
182
    }
183
184
    /* Calculate the number of bytes per cluster.  */
185
28
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
186
28
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
187
188
    /* Check for invalid value.  */
189
28
    if (bytes_per_cluster == 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
        /* Invalid media, return error.  */
200
1
        return(FX_MEDIA_INVALID);
201
    }
202
203
    /* Setup the new file available size - if less than the current available size.  */
204
27
    if (size < file_ptr -> fx_file_current_available_size)
205
    {
206
207
        /* Yes, the file needs to be truncated.  */
208
209
        /* Update the available file size.  */
210
26
        file_ptr -> fx_file_current_available_size =  ((size + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
211
212
        /* Is the new available size less than the actual file size?  */
213
26
        if (size < file_ptr -> fx_file_current_file_size)
214
        {
215
216
            /* Setup the new file size.  */
217
24
            file_ptr -> fx_file_current_file_size =  size;
218
219
            /* Set the modified flag.  */
220
24
            file_ptr -> fx_file_modified =  FX_TRUE;
221
222
            /* Copy the new file size into the directory entry.  */
223
24
            file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  size;
224
225
            /* Set the first cluster to NULL.  */
226
24
            if (size == 0)
227
            {
228
229
                /* Yes, the first cluster needs to be cleared since the entire
230
                   file is going to be truncated.  */
231
10
                file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FX_NULL;
232
            }
233
234
            /* Write the directory entry to the media.  */
235
#ifdef FX_ENABLE_EXFAT
236
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
237
            {
238
                status = _fx_directory_exFAT_entry_write(
239
                        media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
240
            }
241
            else
242
            {
243
#endif /* FX_ENABLE_EXFAT */
244
24
                status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
245
#ifdef FX_ENABLE_EXFAT
246
            }
247
#endif /* FX_ENABLE_EXFAT */
248
249
            /* Check for a good status.  */
250
24
            if (status != FX_SUCCESS)
251
            {
252
253
#ifdef FX_ENABLE_FAULT_TOLERANT
254
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
255
#endif /* FX_ENABLE_FAULT_TOLERANT */
256
257
                /* Release media protection.  */
258
1
                FX_UNPROTECT
259
260
                /* Error writing the directory.  */
261
1
                return(status);
262
            }
263
        }
264
265
        /* Update the trace event with the truncated size.  */
266
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
267
    }
268
    else
269
    {
270
271
        /* Update the trace event with the truncated size.  */
272
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
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
1
        FX_UNPROTECT
280
281
        /* Just return, the truncate size is larger than the available size.  */
282
1
        return(FX_SUCCESS);
283
    }
284
285
    /* Calculate the number of bytes per cluster.  */
286
25
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
287
25
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
288
289
    /* Now check to see if the read/write internal file pointers need
290
       to be adjusted.  */
291
25
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
292
    {
293
294
295
        /* At this point, we are ready to walk list of clusters to setup the
296
           seek position of this file.  */
297
23
        cluster =           file_ptr -> fx_file_first_physical_cluster;
298
23
        bytes_remaining =   size;
299
23
        last_cluster =      0;
300
23
        cluster_count =     0;
301
302
        /* Follow the link of FAT entries.  */
303

338
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
304
        {
305
306
            /* Increment the number of clusters.  */
307
336
            cluster_count++;
308
309
#ifdef FX_ENABLE_EXFAT
310
            if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
311
            {
312
                if (cluster >= file_ptr -> fx_file_last_physical_cluster)
313
                {
314
                    contents = FX_LAST_CLUSTER_exFAT;
315
                }
316
                else
317
                {
318
                    contents = cluster + 1;
319
                }
320
            }
321
            else
322
            {
323
#endif /* FX_ENABLE_EXFAT */
324
325
                /* Read the current cluster entry from the FAT.  */
326
336
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
327
328
                /* Check the return value.  */
329
336
                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
#ifdef FX_ENABLE_EXFAT
343
            }
344
#endif /* FX_ENABLE_EXFAT */
345
346
            /* Save the last valid cluster.  */
347
335
            last_cluster =  cluster;
348
349
            /* Setup for the next cluster.  */
350
335
            cluster =  contents;
351
352
            /* Determine if this is the last written cluster.  */
353
335
            if (bytes_remaining >= bytes_per_cluster)
354
            {
355
356
                /* Still more seeking, just decrement the working byte offset.  */
357
315
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
358
            }
359
            else
360
            {
361
362
                /* This is the cluster that contains the seek position.  */
363
20
                break;
364
            }
365
        }
366
367
        /* Check for errors in traversal of the FAT chain.  */
368
22
        if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
369
        {
370
371
#ifdef FX_ENABLE_FAULT_TOLERANT
372
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
373
#endif /* FX_ENABLE_FAULT_TOLERANT */
374
375
            /* Release media protection.  */
376
2
            FX_UNPROTECT
377
378
            /* This is an error that suggests a corrupt file.  */
379
2
            return(FX_FILE_CORRUPT);
380
        }
381
382
        /* Position the pointers to the new offset.  */
383
20
        file_ptr -> fx_file_current_physical_cluster =  last_cluster;
384
20
        file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
385
20
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
386
20
            (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
387
20
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
388
20
            (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
389
20
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
390
20
        file_ptr -> fx_file_current_file_offset =       size;
391
20
        file_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
392
    }
393
394
    /* Determine how many clusters are actually in-use now.  */
395
22
    cluster_count =  (ULONG) (file_ptr -> fx_file_current_available_size + (((ULONG64) bytes_per_cluster) - ((ULONG64) 1)))/bytes_per_cluster;
396
397
    /* Save the number of clusters in-use.  */
398
22
    file_ptr -> fx_file_total_clusters =  cluster_count;
399
400
    /* At this point, we are ready to walk list of clusters to find the clusters
401
       that can be released.  */
402
22
    cluster =           file_ptr -> fx_file_first_physical_cluster;
403
#ifdef FX_ENABLE_EXFAT
404
    original_last_physical_cluster = file_ptr -> fx_file_last_physical_cluster;
405
#endif /* FX_ENABLE_EXFAT */
406
407
#ifdef FX_ENABLE_FAULT_TOLERANT
408
    /* Is this the last used cluster?  */
409
    if ((cluster_count == 0) && (media_ptr -> fx_media_fault_tolerant_enabled))
410
    {
411
#ifdef FX_ENABLE_EXFAT
412
        if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
413
        {
414
#endif /* FX_ENABLE_EXFAT */
415
416
            /* Set undo log. */
417
            status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, FX_FREE_CLUSTER,
418
                                                      media_ptr -> fx_media_fat_last, cluster, media_ptr -> fx_media_fat_last);
419
420
            /* Determine if the write was successful.  */
421
            if (status != FX_SUCCESS)
422
            {
423
424
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
425
426
                /* Release media protection.  */
427
                FX_UNPROTECT
428
429
                /* Return the error code.  */
430
                return(status);
431
            }
432
#ifdef FX_ENABLE_EXFAT
433
        }
434
        else
435
        {
436
437
            /* Set undo log. */
438
            status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_TRUE, FX_FREE_CLUSTER,
439
                                                      media_ptr -> fx_media_fat_last, cluster, file_ptr -> fx_file_last_physical_cluster + 1);
440
441
            /* Determine if the write was successful.  */
442
            if (status != FX_SUCCESS)
443
            {
444
445
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
446
447
                /* Release media protection.  */
448
                FX_UNPROTECT
449
450
                /* Return the error code.  */
451
                return(status);
452
            }
453
        }
454
#endif /* FX_ENABLE_EXFAT && FX_ENABLE_FAULT_TOLERANT */
455
456
        file_ptr -> fx_file_last_physical_cluster =  cluster;
457
    }
458
#endif /* FX_ENABLE_FAULT_TOLERANT */
459
460
    /* Follow the link of FAT entries.  */
461

14647
    while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
462
    {
463
#ifdef FX_ENABLE_EXFAT
464
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
465
        {
466
            if (cluster >= original_last_physical_cluster)
467
            {
468
                contents = FX_LAST_CLUSTER_exFAT;
469
            }
470
            else
471
            {
472
                contents = cluster + 1;
473
            }
474
        }
475
        else
476
        {
477
#endif /* FX_ENABLE_EXFAT */
478
479
            /* Read the current cluster entry from the FAT.  */
480
14628
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
481
482
            /* Check the return value.  */
483
14628
            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
1
                FX_UNPROTECT
492
493
                /* Return the error status.  */
494
1
                return(status);
495
            }
496
#ifdef FX_ENABLE_EXFAT
497
        }
498
#endif /* FX_ENABLE_EXFAT */
499
500
        /* Determine if are more clusters to release.  */
501
14627
        if (cluster_count > 0)
502
        {
503
504
            /* Decrement the number of clusters.  */
505
322
            cluster_count--;
506
507
            /* Is this the last used cluster?  */
508
322
            if (cluster_count == 0)
509
            {
510
#ifdef FX_ENABLE_EXFAT
511
                if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
512
#endif /* FX_ENABLE_EXFAT */
513
                {
514
515
#ifdef FX_ENABLE_FAULT_TOLERANT
516
                    if (media_ptr -> fx_media_fault_tolerant_enabled)
517
                    {
518
519
                        /* Set undo phase. */
520
                        media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
521
522
                        /* Read the current cluster entry from the FAT.  */
523
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
524
525
                        /* Check the return value.  */
526
                        if (status != FX_SUCCESS)
527
                        {
528
529
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
530
531
                            /* Release media protection.  */
532
                            FX_UNPROTECT
533
534
                            /* Return the error status.  */
535
                            return(status);
536
                        }
537
538
                        /* Set undo log. */
539
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, cluster,
540
                                                                  media_ptr -> fx_media_fat_last, contents, media_ptr -> fx_media_fat_last);
541
542
                        /* Determine if the write was successful.  */
543
                        if (status != FX_SUCCESS)
544
                        {
545
546
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
547
548
                            /* Release media protection.  */
549
                            FX_UNPROTECT
550
551
                            /* Return the error code.  */
552
                            return(status);
553
                        }
554
                    }
555
#endif /* FX_ENABLE_FAULT_TOLERANT */
556
557
                    /* Yes, it should be designated as last cluster.  */
558
10
                    status = _fx_utility_FAT_entry_write(media_ptr, cluster, media_ptr -> fx_media_fat_last);
559
560
                    /* Check the return value.  */
561
10
                    if (status)
562
                    {
563
564
#ifdef FX_ENABLE_FAULT_TOLERANT
565
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
566
#endif /* FX_ENABLE_FAULT_TOLERANT */
567
568
                        /* Release media protection.  */
569
1
                        FX_UNPROTECT
570
571
                        /* Return the error status.  */
572
1
                        return(status);
573
                    }
574
575
#ifdef FX_ENABLE_FAULT_TOLERANT
576
                    if (media_ptr -> fx_media_fault_tolerant_enabled)
577
                    {
578
579
                        /* Clear undo phase. */
580
                        media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
581
                    }
582
#endif /* FX_ENABLE_FAULT_TOLERANT */
583
                }
584
#if defined(FX_ENABLE_EXFAT) && defined(FX_ENABLE_FAULT_TOLERANT)
585
                else if (media_ptr -> fx_media_fault_tolerant_enabled)
586
                {
587
588
                    /* Set undo log. */
589
                    status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_TRUE, cluster,
590
                                                              media_ptr -> fx_media_fat_last, contents, file_ptr -> fx_file_last_physical_cluster + 1);
591
592
                    /* Determine if the write was successful.  */
593
                    if (status != FX_SUCCESS)
594
                    {
595
596
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
597
598
                        /* Release media protection.  */
599
                        FX_UNPROTECT
600
601
                        /* Return the error code.  */
602
                        return(status);
603
                    }
604
                }
605
#endif /* FX_ENABLE_EXFAT && FX_ENABLE_FAULT_TOLERANT */
606
607
9
                file_ptr -> fx_file_last_physical_cluster =  cluster;
608
609
#ifdef FX_FAULT_TOLERANT
610
611
                /* Flush the cached individual FAT entries.  */
612
                status = _fx_utility_FAT_flush(media_ptr);
613
614
                /* Check the return value.  */
615
                if (status)
616
                {
617
618
#ifdef FX_ENABLE_FAULT_TOLERANT
619
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
620
#endif /* FX_ENABLE_FAULT_TOLERANT */
621
622
                    /* Release media protection.  */
623
                    FX_UNPROTECT
624
625
                    /* Return the error status.  */
626
                    return(status);
627
                }
628
#endif
629
            }
630
        }
631
        else
632
        {
633
634
            /* This is a cluster after the clusters used by the file, release
635
               it back to the media.  */
636
637
#ifdef FX_ENABLE_FAULT_TOLERANT
638
            if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
639
            {
640
#endif /* FX_ENABLE_FAULT_TOLERANT */
641
642
#ifdef FX_ENABLE_EXFAT
643
                if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
644
                {
645
#endif /* FX_ENABLE_EXFAT */
646
14305
                    status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
647
648
                    /* Check the return value.  */
649
14305
                    if (status)
650
                    {
651
652
#ifdef FX_ENABLE_FAULT_TOLERANT
653
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
654
#endif /* FX_ENABLE_FAULT_TOLERANT */
655
656
                        /* Release media protection.  */
657
1
                        FX_UNPROTECT
658
659
                        /* Return the error status.  */
660
1
                        return(status);
661
                    }
662
#ifdef FX_ENABLE_EXFAT
663
                }
664
665
                if (media_ptr -> fx_media_FAT_type == FX_exFAT)
666
                {
667
668
                    /* Mark the cluster as free.  */
669
                    _fx_utility_exFAT_cluster_state_set(media_ptr, cluster, FX_EXFAT_BITMAP_CLUSTER_FREE);
670
                }
671
#endif /* FX_ENABLE_EXFAT */
672
673
                /* Increment the number of available clusters.  */
674
14304
                media_ptr -> fx_media_available_clusters++;
675
676
#ifdef FX_ENABLE_FAULT_TOLERANT
677
            }
678
#endif /* FX_ENABLE_FAULT_TOLERANT */
679
        }
680
681
        /* Setup for the next cluster.  */
682
14625
        cluster =  contents;
683
    }
684
685
    /* Determine if we need to adjust the number of leading consecutive clusters.  */
686
19
    if (file_ptr -> fx_file_consecutive_cluster > file_ptr -> fx_file_total_clusters)
687
    {
688
689
        /* Adjust the leading consecutive cluster count. */
690
10
        file_ptr -> fx_file_consecutive_cluster =  file_ptr -> fx_file_total_clusters;
691
    }
692
693
    /* Determine if the file available size has been truncated to zero.  */
694
19
    if (file_ptr -> fx_file_current_available_size == 0)
695
    {
696
697
        /* Yes, the first cluster has already been released.  Update the file info
698
           to indicate the file has no clusters.  */
699
10
        file_ptr -> fx_file_last_physical_cluster =     0;
700
10
        file_ptr -> fx_file_first_physical_cluster =    0;
701
10
        file_ptr -> fx_file_current_physical_cluster =  0;
702
10
        file_ptr -> fx_file_current_logical_sector =    0;
703
10
        file_ptr -> fx_file_current_relative_cluster =  0;
704
10
        file_ptr -> fx_file_current_relative_sector =   0;
705
10
        file_ptr -> fx_file_current_available_size =    0;
706
10
        file_ptr -> fx_file_consecutive_cluster =       1;
707
    }
708
709
#ifndef FX_DONT_UPDATE_OPEN_FILES
710
711
    /* Search the opened files list to see if the same file is opened for reading.  */
712
19
    open_count =  media_ptr -> fx_media_opened_file_count;
713
19
    search_ptr =  media_ptr -> fx_media_opened_file_list;
714
54
    while (open_count)
715
    {
716
717
        /* Is this file the same file opened for reading?  */
718
38
        if ((search_ptr != file_ptr) &&
719
19
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
720
19
             file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
721
15
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
722
15
             file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
723
        {
724
725
            /* Yes, the same file is opened for reading.  */
726
727
            /* Setup the new file size.  */
728
9
            search_ptr -> fx_file_current_file_size =  size;
729
730
            /* Setup the new total clusters.  */
731
9
            search_ptr -> fx_file_total_clusters =  file_ptr -> fx_file_total_clusters;
732
733
            /* Copy the directory entry.  */
734
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =      file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
735
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
736
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector =   file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
737
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset =  file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
738
739
            /* Setup the other file parameters.  */
740
9
            search_ptr -> fx_file_last_physical_cluster =     file_ptr -> fx_file_last_physical_cluster;
741
9
            search_ptr -> fx_file_first_physical_cluster =    file_ptr -> fx_file_first_physical_cluster;
742
9
            search_ptr -> fx_file_current_available_size =    file_ptr -> fx_file_current_available_size;
743
9
            search_ptr -> fx_file_consecutive_cluster =       file_ptr -> fx_file_consecutive_cluster;
744
745
            /* Determine if the truncated file is smaller than the current file offset.  */
746
9
            if (search_ptr -> fx_file_current_file_offset > size)
747
            {
748
749
                /* Yes, the current file parameters need to be changed since the file was
750
                   truncated to a position prior to the current file position.  */
751
752
                /* Calculate the number of bytes per cluster.  */
753
7
                bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
754
7
                    ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
755
756
                /* At this point, we are ready to walk list of clusters to setup the
757
                   seek position of this file.  */
758
7
                cluster =           search_ptr -> fx_file_first_physical_cluster;
759
7
                bytes_remaining =   size;
760
7
                last_cluster =      0;
761
7
                cluster_count =     0;
762
763
                /* Follow the link of FAT entries.  */
764

38
                while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
765
                {
766
767
                    /* Increment the number of clusters.  */
768
35
                    cluster_count++;
769
770
#ifdef FX_ENABLE_EXFAT
771
                    if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
772
                    {
773
                        if (cluster >= file_ptr -> fx_file_last_physical_cluster)
774
                        {
775
                            contents = FX_LAST_CLUSTER_exFAT;
776
                        }
777
                        else
778
                        {
779
                            contents = cluster + 1;
780
                        }
781
                    }
782
                    else
783
                    {
784
#endif /* FX_ENABLE_EXFAT */
785
786
                        /* Read the current cluster entry from the FAT.  */
787
35
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
788
789
                        /* Check the return value.  */
790
35
                        if (status != FX_SUCCESS)
791
                        {
792
793
#ifdef FX_ENABLE_FAULT_TOLERANT
794
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
795
#endif /* FX_ENABLE_FAULT_TOLERANT */
796
797
                            /* Release media protection.  */
798
1
                            FX_UNPROTECT
799
800
                            /* Return the error status.  */
801
1
                            return(status);
802
                        }
803
#ifdef FX_ENABLE_EXFAT
804
                    }
805
#endif /* FX_ENABLE_EXFAT */
806
807
                    /* Save the last valid cluster.  */
808
34
                    last_cluster =  cluster;
809
810
                    /* Setup for the next cluster.  */
811
34
                    cluster =  contents;
812
813
                    /* Determine if this is the last written cluster.  */
814
34
                    if (bytes_remaining >= bytes_per_cluster)
815
                    {
816
817
                        /* Still more seeking, just decrement the working byte offset.  */
818
31
                        bytes_remaining =  bytes_remaining - bytes_per_cluster;
819
                    }
820
                    else
821
                    {
822
823
                        /* This is the cluster that contains the seek position.  */
824
3
                        break;
825
                    }
826
                }
827
828
                /* Check for errors in traversal of the FAT chain.  */
829
6
                if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
830
                {
831
832
#ifdef FX_ENABLE_FAULT_TOLERANT
833
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
834
#endif /* FX_ENABLE_FAULT_TOLERANT */
835
836
                    /* Release media protection.  */
837
2
                    FX_UNPROTECT
838
839
                    /* This is an error that suggests a corrupt file.  */
840
2
                    return(FX_FILE_CORRUPT);
841
                }
842
843
                /* Position the pointers to the new offset.  */
844
845
                /* Determine if there is at least one cluster.  */
846
4
                if (cluster_count)
847
                {
848
849
                    /* Calculate real file parameters.  */
850
3
                    search_ptr -> fx_file_current_physical_cluster =  last_cluster;
851
3
                    search_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
852
3
                    search_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
853
3
                        (((ULONG64)search_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
854
3
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
855
3
                        (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
856
3
                    search_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
857
3
                    search_ptr -> fx_file_current_file_offset =       size;
858
3
                    search_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
859
                }
860
                else
861
                {
862
863
                    /* Calculate zero-length file parameters.  */
864
1
                    search_ptr -> fx_file_current_physical_cluster =  0;
865
1
                    search_ptr -> fx_file_current_relative_cluster =  0;
866
1
                    search_ptr -> fx_file_current_logical_sector =    0;
867
1
                    search_ptr -> fx_file_current_relative_sector =   0;
868
1
                    search_ptr -> fx_file_current_file_offset =       0;
869
1
                    search_ptr -> fx_file_current_logical_offset =    0;
870
                }
871
            }
872
        }
873
874
        /* Adjust the pointer and decrement the search count.  */
875
35
        search_ptr =  search_ptr -> fx_file_opened_next;
876
35
        open_count--;
877
    }
878
#endif
879
880
#ifdef FX_FAULT_TOLERANT
881
882
    /* Flush the cached individual FAT entries */
883
    status = _fx_utility_FAT_flush(media_ptr);
884
885
    /* Check the return value.  */
886
    if (status)
887
    {
888
889
#ifdef FX_ENABLE_FAULT_TOLERANT
890
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
891
#endif /* FX_ENABLE_FAULT_TOLERANT */
892
893
        /* Release media protection.  */
894
        FX_UNPROTECT
895
896
        /* Return the error status.  */
897
        return(status);
898
    }
899
#ifdef FX_ENABLE_EXFAT
900
    /* Flush Bit Map.  */
901
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
902
    {
903
        _fx_utility_exFAT_bitmap_flush(media_ptr);
904
    }
905
#endif /* FX_ENABLE_EXFAT */
906
907
#endif
908
909
#ifdef FX_ENABLE_FAULT_TOLERANT
910
    if (media_ptr -> fx_media_fault_tolerant_enabled &&
911
        (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
912
    {
913
914
        /* Copy the new file size into the directory entry.  */
915
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
916
    }
917
918
    /* Write the directory entry to the media.  */
919
#ifdef FX_ENABLE_EXFAT
920
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
921
    {
922
923
        status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
924
    }
925
    else
926
    {
927
#endif /* FX_ENABLE_EXFAT */
928
        status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
929
#ifdef FX_ENABLE_EXFAT
930
    }
931
#endif /* FX_ENABLE_EXFAT */
932
933
    /* Check for a good status.  */
934
    if (status != FX_SUCCESS)
935
    {
936
937
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
938
939
        /* Release media protection.  */
940
        FX_UNPROTECT
941
942
        /* Error writing the directory.  */
943
        return(status);
944
    }
945
946
    /* End transaction. */
947
    status = _fx_fault_tolerant_transaction_end(media_ptr);
948
949
    /* Check for a bad status.  */
950
    if (status != FX_SUCCESS)
951
    {
952
953
        /* Release media protection.  */
954
        FX_UNPROTECT
955
956
        /* Return the bad status.  */
957
        return(status);
958
    }
959
960
    /* Update maximum size used if necessary. */
961
    if (size < file_ptr -> fx_file_maximum_size_used)
962
    {
963
        file_ptr -> fx_file_maximum_size_used = size;
964
    }
965
#endif /* FX_ENABLE_FAULT_TOLERANT */
966
967
    /* Release media protection.  */
968
16
    FX_UNPROTECT
969
970
    /* Truncate is complete, return successful status.  */
971
16
    return(FX_SUCCESS);
972
}
973