GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_truncate_release.c Lines: 154 154 100.0 %
Date: 2026-03-06 18:49:02 Branches: 68 68 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_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_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_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
/**************************************************************************/
83
31
UINT  _fx_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size)
84
{
85
86
UINT                   status;
87
ULONG                  cluster;
88
ULONG                  contents;
89
ULONG                  bytes_per_cluster;
90
ULONG                  last_cluster;
91
ULONG                  cluster_count;
92
ULONG64                bytes_remaining;
93
FX_MEDIA              *media_ptr;
94
95
96
#ifndef FX_DONT_UPDATE_OPEN_FILES
97
ULONG                  open_count;
98
FX_FILE               *search_ptr;
99
#endif
100
101
#ifdef TX_ENABLE_EVENT_TRACE
102
TX_TRACE_BUFFER_ENTRY *trace_event;
103
ULONG                  trace_timestamp;
104
#endif
105
106
107
    /* First, determine if the file is still open.  */
108
31
    if (file_ptr -> fx_file_id != FX_FILE_ID)
109
    {
110
111
        /* Return the file not open error status.  */
112
1
        return(FX_NOT_OPEN);
113
    }
114
115
#ifndef FX_MEDIA_STATISTICS_DISABLE
116
    /* Setup pointer to media structure.  */
117
30
    media_ptr =  file_ptr -> fx_file_media_ptr;
118
119
    /* Increment the number of times this service has been called.  */
120
30
    media_ptr -> fx_media_file_truncate_releases++;
121
#endif
122
123
    /* Setup pointer to associated media control block.  */
124
30
    media_ptr =  file_ptr -> fx_file_media_ptr;
125
126
    /* If trace is enabled, insert this event into the trace buffer.  */
127
    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)
128
129
    /* Protect against other threads accessing the media.  */
130
30
    FX_PROTECT
131
132
#ifdef FX_ENABLE_FAULT_TOLERANT
133
    /* Start transaction. */
134
    _fx_fault_tolerant_transaction_start(media_ptr);
135
#endif /* FX_ENABLE_FAULT_TOLERANT */
136
137
    /* Make sure this file is open for writing.  */
138
30
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
139
    {
140
141
#ifdef FX_ENABLE_FAULT_TOLERANT
142
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
143
#endif /* FX_ENABLE_FAULT_TOLERANT */
144
145
        /* Release media protection.  */
146
1
        FX_UNPROTECT
147
148
        /* Return the access error exception - a write was attempted from
149
           a file opened for reading!  */
150
1
        return(FX_ACCESS_ERROR);
151
    }
152
153
    /* Check for write protect at the media level (set by driver).  */
154
29
    if (media_ptr -> fx_media_driver_write_protect)
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 write protect error.  */
165
1
        return(FX_WRITE_PROTECT);
166
    }
167
168
    /* Calculate the number of bytes per cluster.  */
169
28
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
170
28
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
171
172
    /* Check for invalid value.  */
173
28
    if (bytes_per_cluster == 0)
174
    {
175
176
#ifdef FX_ENABLE_FAULT_TOLERANT
177
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
178
#endif /* FX_ENABLE_FAULT_TOLERANT */
179
180
        /* Release media protection.  */
181
1
        FX_UNPROTECT
182
183
        /* Invalid media, return error.  */
184
1
        return(FX_MEDIA_INVALID);
185
    }
186
187
    /* Setup the new file available size - if less than the current available size.  */
188
27
    if (size < file_ptr -> fx_file_current_available_size)
189
    {
190
191
        /* Yes, the file needs to be truncated.  */
192
193
        /* Update the available file size.  */
194
26
        file_ptr -> fx_file_current_available_size =  ((size + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
195
196
        /* Is the new available size less than the actual file size?  */
197
26
        if (size < file_ptr -> fx_file_current_file_size)
198
        {
199
200
            /* Setup the new file size.  */
201
24
            file_ptr -> fx_file_current_file_size =  size;
202
203
            /* Set the modified flag.  */
204
24
            file_ptr -> fx_file_modified =  FX_TRUE;
205
206
            /* Copy the new file size into the directory entry.  */
207
24
            file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =  size;
208
209
            /* Set the first cluster to NULL.  */
210
24
            if (size == 0)
211
            {
212
213
                /* Yes, the first cluster needs to be cleared since the entire
214
                   file is going to be truncated.  */
215
10
                file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FX_NULL;
216
            }
217
218
            /* Write the directory entry to the media.  */
219
24
            status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
220
221
            /* Check for a good status.  */
222
24
            if (status != FX_SUCCESS)
223
            {
224
225
#ifdef FX_ENABLE_FAULT_TOLERANT
226
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
227
#endif /* FX_ENABLE_FAULT_TOLERANT */
228
229
                /* Release media protection.  */
230
1
                FX_UNPROTECT
231
232
                /* Error writing the directory.  */
233
1
                return(status);
234
            }
235
        }
236
237
        /* Update the trace event with the truncated size.  */
238
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
239
    }
240
    else
241
    {
242
243
        /* Update the trace event with the truncated size.  */
244
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
245
246
#ifdef FX_ENABLE_FAULT_TOLERANT
247
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
248
#endif /* FX_ENABLE_FAULT_TOLERANT */
249
250
        /* Release media protection.  */
251
1
        FX_UNPROTECT
252
253
        /* Just return, the truncate size is larger than the available size.  */
254
1
        return(FX_SUCCESS);
255
    }
256
257
    /* Calculate the number of bytes per cluster.  */
258
25
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
259
25
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
260
261
    /* Now check to see if the read/write internal file pointers need
262
       to be adjusted.  */
263
25
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
264
    {
265
266
267
        /* At this point, we are ready to walk list of clusters to setup the
268
           seek position of this file.  */
269
23
        cluster =           file_ptr -> fx_file_first_physical_cluster;
270
23
        bytes_remaining =   size;
271
23
        last_cluster =      0;
272
23
        cluster_count =     0;
273
274
        /* Follow the link of FAT entries.  */
275

338
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
276
        {
277
278
            /* Increment the number of clusters.  */
279
336
            cluster_count++;
280
281
282
            /* Read the current cluster entry from the FAT.  */
283
336
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
284
285
            /* Check the return value.  */
286
336
            if (status != FX_SUCCESS)
287
            {
288
289
#ifdef FX_ENABLE_FAULT_TOLERANT
290
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
291
#endif /* FX_ENABLE_FAULT_TOLERANT */
292
293
                /* Release media protection.  */
294
1
                FX_UNPROTECT
295
296
                /* Return the error status.  */
297
1
                return(status);
298
            }
299
300
            /* Save the last valid cluster.  */
301
335
            last_cluster =  cluster;
302
303
            /* Setup for the next cluster.  */
304
335
            cluster =  contents;
305
306
            /* Determine if this is the last written cluster.  */
307
335
            if (bytes_remaining >= bytes_per_cluster)
308
            {
309
310
                /* Still more seeking, just decrement the working byte offset.  */
311
315
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
312
            }
313
            else
314
            {
315
316
                /* This is the cluster that contains the seek position.  */
317
20
                break;
318
            }
319
        }
320
321
        /* Check for errors in traversal of the FAT chain.  */
322
22
        if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
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
2
            FX_UNPROTECT
331
332
            /* This is an error that suggests a corrupt file.  */
333
2
            return(FX_FILE_CORRUPT);
334
        }
335
336
        /* Position the pointers to the new offset.  */
337
20
        file_ptr -> fx_file_current_physical_cluster =  last_cluster;
338
20
        file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
339
20
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
340
20
            (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
341
20
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
342
20
            (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
343
20
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
344
20
        file_ptr -> fx_file_current_file_offset =       size;
345
20
        file_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
346
    }
347
348
    /* Determine how many clusters are actually in-use now.  */
349
22
    cluster_count =  (ULONG) (file_ptr -> fx_file_current_available_size + (((ULONG64) bytes_per_cluster) - ((ULONG64) 1)))/bytes_per_cluster;
350
351
    /* Save the number of clusters in-use.  */
352
22
    file_ptr -> fx_file_total_clusters =  cluster_count;
353
354
    /* At this point, we are ready to walk list of clusters to find the clusters
355
       that can be released.  */
356
22
    cluster =           file_ptr -> fx_file_first_physical_cluster;
357
358
#ifdef FX_ENABLE_FAULT_TOLERANT
359
    /* Is this the last used cluster?  */
360
    if ((cluster_count == 0) && (media_ptr -> fx_media_fault_tolerant_enabled))
361
    {
362
363
        /* Set undo log. */
364
        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, FX_FREE_CLUSTER,
365
                                                  media_ptr -> fx_media_fat_last, cluster, media_ptr -> fx_media_fat_last);
366
367
        /* Determine if the write was successful.  */
368
        if (status != FX_SUCCESS)
369
        {
370
371
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
372
373
            /* Release media protection.  */
374
            FX_UNPROTECT
375
376
            /* Return the error code.  */
377
            return(status);
378
        }
379
380
        file_ptr -> fx_file_last_physical_cluster =  cluster;
381
    }
382
#endif /* FX_ENABLE_FAULT_TOLERANT */
383
384
    /* Follow the link of FAT entries.  */
385

14647
    while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
386
    {
387
388
        /* Read the current cluster entry from the FAT.  */
389
14628
        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
390
391
        /* Check the return value.  */
392
14628
        if (status != FX_SUCCESS)
393
        {
394
395
#ifdef FX_ENABLE_FAULT_TOLERANT
396
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
397
#endif /* FX_ENABLE_FAULT_TOLERANT */
398
399
            /* Release media protection.  */
400
1
            FX_UNPROTECT
401
402
            /* Return the error status.  */
403
1
            return(status);
404
        }
405
406
        /* Determine if are more clusters to release.  */
407
14627
        if (cluster_count > 0)
408
        {
409
410
            /* Decrement the number of clusters.  */
411
322
            cluster_count--;
412
413
            /* Is this the last used cluster?  */
414
322
            if (cluster_count == 0)
415
            {
416
                {
417
418
#ifdef FX_ENABLE_FAULT_TOLERANT
419
                    if (media_ptr -> fx_media_fault_tolerant_enabled)
420
                    {
421
422
                        /* Set undo phase. */
423
                        media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
424
425
                        /* Read the current cluster entry from the FAT.  */
426
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
427
428
                        /* Check the return value.  */
429
                        if (status != FX_SUCCESS)
430
                        {
431
432
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
433
434
                            /* Release media protection.  */
435
                            FX_UNPROTECT
436
437
                            /* Return the error status.  */
438
                            return(status);
439
                        }
440
441
                        /* Set undo log. */
442
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, cluster,
443
                                                                  media_ptr -> fx_media_fat_last, contents, media_ptr -> fx_media_fat_last);
444
445
                        /* Determine if the write was successful.  */
446
                        if (status != FX_SUCCESS)
447
                        {
448
449
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
450
451
                            /* Release media protection.  */
452
                            FX_UNPROTECT
453
454
                            /* Return the error code.  */
455
                            return(status);
456
                        }
457
                    }
458
#endif /* FX_ENABLE_FAULT_TOLERANT */
459
460
                    /* Yes, it should be designated as last cluster.  */
461
10
                    status = _fx_utility_FAT_entry_write(media_ptr, cluster, media_ptr -> fx_media_fat_last);
462
463
                    /* Check the return value.  */
464
10
                    if (status)
465
                    {
466
467
#ifdef FX_ENABLE_FAULT_TOLERANT
468
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
469
#endif /* FX_ENABLE_FAULT_TOLERANT */
470
471
                        /* Release media protection.  */
472
1
                        FX_UNPROTECT
473
474
                        /* Return the error status.  */
475
1
                        return(status);
476
                    }
477
478
#ifdef FX_ENABLE_FAULT_TOLERANT
479
                    if (media_ptr -> fx_media_fault_tolerant_enabled)
480
                    {
481
482
                        /* Clear undo phase. */
483
                        media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
484
                    }
485
#endif /* FX_ENABLE_FAULT_TOLERANT */
486
                }
487
488
9
                file_ptr -> fx_file_last_physical_cluster =  cluster;
489
490
#ifdef FX_FAULT_TOLERANT
491
492
                /* Flush the cached individual FAT entries.  */
493
                status = _fx_utility_FAT_flush(media_ptr);
494
495
                /* Check the return value.  */
496
                if (status)
497
                {
498
499
#ifdef FX_ENABLE_FAULT_TOLERANT
500
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
501
#endif /* FX_ENABLE_FAULT_TOLERANT */
502
503
                    /* Release media protection.  */
504
                    FX_UNPROTECT
505
506
                    /* Return the error status.  */
507
                    return(status);
508
                }
509
#endif
510
            }
511
        }
512
        else
513
        {
514
515
            /* This is a cluster after the clusters used by the file, release
516
               it back to the media.  */
517
518
#ifdef FX_ENABLE_FAULT_TOLERANT
519
            if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
520
            {
521
#endif /* FX_ENABLE_FAULT_TOLERANT */
522
523
14305
                status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
524
525
                /* Check the return value.  */
526
14305
                if (status)
527
                {
528
529
#ifdef FX_ENABLE_FAULT_TOLERANT
530
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
531
#endif /* FX_ENABLE_FAULT_TOLERANT */
532
533
                    /* Release media protection.  */
534
1
                    FX_UNPROTECT
535
536
                    /* Return the error status.  */
537
1
                    return(status);
538
                }
539
540
                /* Increment the number of available clusters.  */
541
14304
                media_ptr -> fx_media_available_clusters++;
542
543
#ifdef FX_ENABLE_FAULT_TOLERANT
544
            }
545
#endif /* FX_ENABLE_FAULT_TOLERANT */
546
        }
547
548
        /* Setup for the next cluster.  */
549
14625
        cluster =  contents;
550
    }
551
552
    /* Determine if we need to adjust the number of leading consecutive clusters.  */
553
19
    if (file_ptr -> fx_file_consecutive_cluster > file_ptr -> fx_file_total_clusters)
554
    {
555
556
        /* Adjust the leading consecutive cluster count. */
557
10
        file_ptr -> fx_file_consecutive_cluster =  file_ptr -> fx_file_total_clusters;
558
    }
559
560
    /* Determine if the file available size has been truncated to zero.  */
561
19
    if (file_ptr -> fx_file_current_available_size == 0)
562
    {
563
564
        /* Yes, the first cluster has already been released.  Update the file info
565
           to indicate the file has no clusters.  */
566
10
        file_ptr -> fx_file_last_physical_cluster =     0;
567
10
        file_ptr -> fx_file_first_physical_cluster =    0;
568
10
        file_ptr -> fx_file_current_physical_cluster =  0;
569
10
        file_ptr -> fx_file_current_logical_sector =    0;
570
10
        file_ptr -> fx_file_current_relative_cluster =  0;
571
10
        file_ptr -> fx_file_current_relative_sector =   0;
572
10
        file_ptr -> fx_file_current_available_size =    0;
573
10
        file_ptr -> fx_file_consecutive_cluster =       1;
574
    }
575
576
#ifndef FX_DONT_UPDATE_OPEN_FILES
577
578
    /* Search the opened files list to see if the same file is opened for reading.  */
579
19
    open_count =  media_ptr -> fx_media_opened_file_count;
580
19
    search_ptr =  media_ptr -> fx_media_opened_file_list;
581
54
    while (open_count)
582
    {
583
584
        /* Is this file the same file opened for reading?  */
585
38
        if ((search_ptr != file_ptr) &&
586
19
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
587
19
             file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
588
15
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
589
15
             file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
590
        {
591
592
            /* Yes, the same file is opened for reading.  */
593
594
            /* Setup the new file size.  */
595
9
            search_ptr -> fx_file_current_file_size =  size;
596
597
            /* Setup the new total clusters.  */
598
9
            search_ptr -> fx_file_total_clusters =  file_ptr -> fx_file_total_clusters;
599
600
            /* Copy the directory entry.  */
601
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =      file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
602
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
603
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector =   file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
604
9
            search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset =  file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
605
606
            /* Setup the other file parameters.  */
607
9
            search_ptr -> fx_file_last_physical_cluster =     file_ptr -> fx_file_last_physical_cluster;
608
9
            search_ptr -> fx_file_first_physical_cluster =    file_ptr -> fx_file_first_physical_cluster;
609
9
            search_ptr -> fx_file_current_available_size =    file_ptr -> fx_file_current_available_size;
610
9
            search_ptr -> fx_file_consecutive_cluster =       file_ptr -> fx_file_consecutive_cluster;
611
612
            /* Determine if the truncated file is smaller than the current file offset.  */
613
9
            if (search_ptr -> fx_file_current_file_offset > size)
614
            {
615
616
                /* Yes, the current file parameters need to be changed since the file was
617
                   truncated to a position prior to the current file position.  */
618
619
                /* Calculate the number of bytes per cluster.  */
620
7
                bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
621
7
                    ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
622
623
                /* At this point, we are ready to walk list of clusters to setup the
624
                   seek position of this file.  */
625
7
                cluster =           search_ptr -> fx_file_first_physical_cluster;
626
7
                bytes_remaining =   size;
627
7
                last_cluster =      0;
628
7
                cluster_count =     0;
629
630
                /* Follow the link of FAT entries.  */
631

38
                while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
632
                {
633
634
                    /* Increment the number of clusters.  */
635
35
                    cluster_count++;
636
637
638
                    /* Read the current cluster entry from the FAT.  */
639
35
                    status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
640
641
                    /* Check the return value.  */
642
35
                    if (status != FX_SUCCESS)
643
                    {
644
645
#ifdef FX_ENABLE_FAULT_TOLERANT
646
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
647
#endif /* FX_ENABLE_FAULT_TOLERANT */
648
649
                        /* Release media protection.  */
650
1
                        FX_UNPROTECT
651
652
                        /* Return the error status.  */
653
1
                        return(status);
654
                    }
655
656
                    /* Save the last valid cluster.  */
657
34
                    last_cluster =  cluster;
658
659
                    /* Setup for the next cluster.  */
660
34
                    cluster =  contents;
661
662
                    /* Determine if this is the last written cluster.  */
663
34
                    if (bytes_remaining >= bytes_per_cluster)
664
                    {
665
666
                        /* Still more seeking, just decrement the working byte offset.  */
667
31
                        bytes_remaining =  bytes_remaining - bytes_per_cluster;
668
                    }
669
                    else
670
                    {
671
672
                        /* This is the cluster that contains the seek position.  */
673
3
                        break;
674
                    }
675
                }
676
677
                /* Check for errors in traversal of the FAT chain.  */
678
6
                if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
679
                {
680
681
#ifdef FX_ENABLE_FAULT_TOLERANT
682
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
683
#endif /* FX_ENABLE_FAULT_TOLERANT */
684
685
                    /* Release media protection.  */
686
2
                    FX_UNPROTECT
687
688
                    /* This is an error that suggests a corrupt file.  */
689
2
                    return(FX_FILE_CORRUPT);
690
                }
691
692
                /* Position the pointers to the new offset.  */
693
694
                /* Determine if there is at least one cluster.  */
695
4
                if (cluster_count)
696
                {
697
698
                    /* Calculate real file parameters.  */
699
3
                    search_ptr -> fx_file_current_physical_cluster =  last_cluster;
700
3
                    search_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
701
3
                    search_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
702
3
                        (((ULONG64)search_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
703
3
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
704
3
                        (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
705
3
                    search_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
706
3
                    search_ptr -> fx_file_current_file_offset =       size;
707
3
                    search_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
708
                }
709
                else
710
                {
711
712
                    /* Calculate zero-length file parameters.  */
713
1
                    search_ptr -> fx_file_current_physical_cluster =  0;
714
1
                    search_ptr -> fx_file_current_relative_cluster =  0;
715
1
                    search_ptr -> fx_file_current_logical_sector =    0;
716
1
                    search_ptr -> fx_file_current_relative_sector =   0;
717
1
                    search_ptr -> fx_file_current_file_offset =       0;
718
1
                    search_ptr -> fx_file_current_logical_offset =    0;
719
                }
720
            }
721
        }
722
723
        /* Adjust the pointer and decrement the search count.  */
724
35
        search_ptr =  search_ptr -> fx_file_opened_next;
725
35
        open_count--;
726
    }
727
#endif
728
729
#ifdef FX_FAULT_TOLERANT
730
731
    /* Flush the cached individual FAT entries */
732
    status = _fx_utility_FAT_flush(media_ptr);
733
734
    /* Check the return value.  */
735
    if (status)
736
    {
737
738
#ifdef FX_ENABLE_FAULT_TOLERANT
739
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
740
#endif /* FX_ENABLE_FAULT_TOLERANT */
741
742
        /* Release media protection.  */
743
        FX_UNPROTECT
744
745
        /* Return the error status.  */
746
        return(status);
747
    }
748
749
#endif
750
751
#ifdef FX_ENABLE_FAULT_TOLERANT
752
    if (media_ptr -> fx_media_fault_tolerant_enabled &&
753
        (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
754
    {
755
756
        /* Copy the new file size into the directory entry.  */
757
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
758
    }
759
760
    /* Write the directory entry to the media.  */
761
    status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
762
763
    /* Check for a good status.  */
764
    if (status != FX_SUCCESS)
765
    {
766
767
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
768
769
        /* Release media protection.  */
770
        FX_UNPROTECT
771
772
        /* Error writing the directory.  */
773
        return(status);
774
    }
775
776
    /* End transaction. */
777
    status = _fx_fault_tolerant_transaction_end(media_ptr);
778
779
    /* Check for a bad status.  */
780
    if (status != FX_SUCCESS)
781
    {
782
783
        /* Release media protection.  */
784
        FX_UNPROTECT
785
786
        /* Return the bad status.  */
787
        return(status);
788
    }
789
790
    /* Update maximum size used if necessary. */
791
    if (size < file_ptr -> fx_file_maximum_size_used)
792
    {
793
        file_ptr -> fx_file_maximum_size_used = size;
794
    }
795
#endif /* FX_ENABLE_FAULT_TOLERANT */
796
797
    /* Release media protection.  */
798
16
    FX_UNPROTECT
799
800
    /* Truncate is complete, return successful status.  */
801
16
    return(FX_SUCCESS);
802
}
803