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

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

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

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