GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_truncate.c Lines: 63 63 100.0 %
Date: 2026-03-06 18:49:02 Branches: 28 28 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                          PORTABLE C      */
43
/*                                                           6.1          */
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.                                                   */
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_utility_FAT_entry_read            Read a FAT entry              */
67
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
68
/*                                            transaction                 */
69
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
70
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
71
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
72
/*                                                                        */
73
/*  CALLED BY                                                             */
74
/*                                                                        */
75
/*    Application Code                                                    */
76
/*                                                                        */
77
/**************************************************************************/
78
11
UINT  _fx_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size)
79
{
80
81
UINT                   status;
82
ULONG                  cluster;
83
11
ULONG                  contents = 0;
84
ULONG                  bytes_per_cluster;
85
ULONG                  last_cluster;
86
ULONG                  cluster_count;
87
ULONG64                bytes_remaining;
88
FX_MEDIA              *media_ptr;
89
90
#ifndef FX_DONT_UPDATE_OPEN_FILES
91
ULONG                  open_count;
92
FX_FILE               *search_ptr;
93
#endif
94
95
#ifdef TX_ENABLE_EVENT_TRACE
96
TX_TRACE_BUFFER_ENTRY *trace_event;
97
ULONG                  trace_timestamp;
98
#endif
99
100
101
    /* First, determine if the file is still open.  */
102
11
    if (file_ptr -> fx_file_id != FX_FILE_ID)
103
    {
104
105
        /* Return the file not open error status.  */
106
1
        return(FX_NOT_OPEN);
107
    }
108
109
#ifndef FX_MEDIA_STATISTICS_DISABLE
110
    /* Setup pointer to media structure.  */
111
10
    media_ptr =  file_ptr -> fx_file_media_ptr;
112
113
    /* Increment the number of times this service has been called.  */
114
10
    media_ptr -> fx_media_file_truncates++;
115
#endif
116
117
    /* Setup pointer to associated media control block.  */
118
10
    media_ptr =  file_ptr -> fx_file_media_ptr;
119
120
    /* If trace is enabled, insert this event into the trace buffer.  */
121
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
122
123
    /* Protect against other threads accessing the media.  */
124
10
    FX_PROTECT
125
126
    /* Make sure this file is open for writing.  */
127
10
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
128
    {
129
130
        /* Release media protection.  */
131
1
        FX_UNPROTECT
132
133
        /* Return the access error exception - a write was attempted from
134
           a file opened for reading!  */
135
1
        return(FX_ACCESS_ERROR);
136
    }
137
138
    /* Check for write protect at the media level (set by driver).  */
139
9
    if (media_ptr -> fx_media_driver_write_protect)
140
    {
141
142
        /* Release media protection.  */
143
1
        FX_UNPROTECT
144
145
        /* Return write protect error.  */
146
1
        return(FX_WRITE_PROTECT);
147
    }
148
149
    /* Setup the new file size - if less than the current size.  */
150
8
    if (size < file_ptr -> fx_file_current_file_size)
151
    {
152
153
        /* Setup the new size.  */
154
7
        file_ptr -> fx_file_current_file_size =  size;
155
156
        /* Set the modified flag as well.  */
157
7
        file_ptr -> fx_file_modified =  FX_TRUE;
158
159
        /* Update the trace event with the truncated size.  */
160
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, size)
161
    }
162
    else
163
    {
164
165
        /* Update the trace event with the truncated size.  */
166
        FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
167
168
        /* Release media protection.  */
169
1
        FX_UNPROTECT
170
171
        /* Just return, the new size is larger than the current size.  */
172
1
        return(FX_SUCCESS);
173
    }
174
175
#ifndef FX_DONT_UPDATE_OPEN_FILES
176
177
    /* Search the opened files list to see if the same file is opened for reading.  */
178
7
    open_count =  media_ptr -> fx_media_opened_file_count;
179
7
    search_ptr =  media_ptr -> fx_media_opened_file_list;
180
31
    while (open_count)
181
    {
182
183
        /* Is this file the same file opened for reading?  */
184
24
        if ((search_ptr != file_ptr) &&
185
17
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
186
17
             file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
187
12
            (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
188
12
             file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
189
        {
190
191
            /* Yes, the same file is opened for reading.  */
192
193
            /* Setup the new file size.  */
194
5
            search_ptr -> fx_file_current_file_size =  size;
195
5
            search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
196
        }
197
198
        /* Adjust the pointer and decrement the search count.  */
199
24
        search_ptr =  search_ptr -> fx_file_opened_next;
200
24
        open_count--;
201
    }
202
#endif
203
204
    /* Now check to see if the read/write internal file pointers need
205
       to be adjusted.  */
206
7
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
207
    {
208
209
        /* Calculate the number of bytes per cluster.  */
210
6
        bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
211
6
            ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
212
213
        /* At this point, we are ready to walk list of clusters to setup the
214
           seek position of this file.  */
215
6
        cluster =           file_ptr -> fx_file_first_physical_cluster;
216
6
        bytes_remaining =   size;
217
6
        last_cluster =      0;
218
6
        cluster_count =     0;
219
220
        /* Follow the link of FAT entries.  */
221

270
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
222
        {
223
224
            /* Increment the number of clusters.  */
225
268
            cluster_count++;
226
227
            /* Read the current cluster entry from the FAT.  */
228
268
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
229
230
            /* Check the return value.  */
231
268
            if (status != FX_SUCCESS)
232
            {
233
234
                /* Release media protection.  */
235
1
                FX_UNPROTECT
236
237
                /* Return the error status.  */
238
1
                return(status);
239
            }
240
241
            /* Save the last valid cluster.  */
242
267
            last_cluster =  cluster;
243
244
            /* Setup for the next cluster.  */
245
267
            cluster =  contents;
246
247
            /* Determine if this is the last written cluster.  */
248
267
            if (bytes_remaining >= bytes_per_cluster)
249
            {
250
251
                /* Still more seeking, just decrement the working byte offset.  */
252
264
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
253
            }
254
            else
255
            {
256
257
                /* This is the cluster that contains the seek position.  */
258
3
                break;
259
            }
260
        }
261
262
        /* Check for errors in traversal of the FAT chain.  */
263
5
        if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
264
        {
265
266
            /* Release media protection.  */
267
2
            FX_UNPROTECT
268
269
            /* This is an error that suggests a corrupt file.  */
270
2
            return(FX_FILE_CORRUPT);
271
        }
272
273
        /* Position the pointers to the new offset.  */
274
3
        file_ptr -> fx_file_current_physical_cluster =  last_cluster;
275
3
        file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
276
3
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
277
3
            (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
278
3
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
279
3
            (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
280
3
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
281
3
        file_ptr -> fx_file_current_file_offset =       size;
282
3
        file_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
283
    }
284
285
#ifdef FX_ENABLE_FAULT_TOLERANT
286
    if (media_ptr -> fx_media_fault_tolerant_enabled)
287
    {
288
289
        /* Start transaction. */
290
        _fx_fault_tolerant_transaction_start(media_ptr);
291
292
        /* Copy the new file size into the directory entry.  */
293
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
294
295
        /* Write the directory entry to the media.  */
296
        status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
297
298
        /* Check for a good status.  */
299
        if (status != FX_SUCCESS)
300
        {
301
302
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
303
304
            /* Release media protection.  */
305
            FX_UNPROTECT
306
307
            /* Error writing the directory.  */
308
            return(status);
309
        }
310
311
        /* End transaction. */
312
        status = _fx_fault_tolerant_transaction_end(media_ptr);
313
314
        /* Check for a good status.  */
315
        if (status != FX_SUCCESS)
316
        {
317
318
            /* Release media protection.  */
319
            FX_UNPROTECT
320
321
            /* Error writing the directory.  */
322
            return(status);
323
        }
324
325
        /* Update maximum size used if necessary. */
326
        if (size < file_ptr -> fx_file_maximum_size_used)
327
        {
328
            file_ptr -> fx_file_maximum_size_used = size;
329
        }
330
    }
331
#endif /* FX_ENABLE_FAULT_TOLERANT */
332
333
    /* Release media protection.  */
334
4
    FX_UNPROTECT
335
336
    /* Truncate is complete, return successful status.  */
337
4
    return(FX_SUCCESS);
338
}
339