GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 77 / 0 / 77
Functions: 100.0% 1 / 0 / 1
Branches: 100.0% 70 / 0 / 70

fx_file_extended_truncate.c
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 127 UINT _fx_file_extended_truncate(FX_FILE *file_ptr, ULONG64 size)
79 {
80
81 UINT status;
82 ULONG cluster;
83 127 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
2/2
✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 4 taken 118 times.
127 if (file_ptr -> fx_file_id != FX_FILE_ID)
103 {
104
105 /* Return the file not open error status. */
106 9 return(FX_NOT_OPEN);
107 }
108
109 #ifndef FX_MEDIA_STATISTICS_DISABLE
110 /* Setup pointer to media structure. */
111 118 media_ptr = file_ptr -> fx_file_media_ptr;
112
113 /* Increment the number of times this service has been called. */
114 118 media_ptr -> fx_media_file_truncates++;
115 #endif
116
117 /* Setup pointer to associated media control block. */
118 118 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 64 FX_PROTECT
125
126 /* Make sure this file is open for writing. */
127
4/4
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 50 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 8 taken 59 times.
118 if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
128 {
129
130 /* Release media protection. */
131 5 FX_UNPROTECT
132
133 /* Return the access error exception - a write was attempted from
134 a file opened for reading! */
135 9 return(FX_ACCESS_ERROR);
136 }
137
138 /* Check for write protect at the media level (set by driver). */
139
4/4
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 8 taken 46 times.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 11 taken 54 times.
109 if (media_ptr -> fx_media_driver_write_protect)
140 {
141
142 /* Release media protection. */
143 5 FX_UNPROTECT
144
145 /* Return write protect error. */
146 9 return(FX_WRITE_PROTECT);
147 }
148
149 /* Setup the new file size - if less than the current size. */
150
4/4
✓ Branch 8 → 9 taken 42 times.
✓ Branch 8 → 10 taken 4 times.
✓ Branch 11 → 12 taken 49 times.
✓ Branch 11 → 13 taken 5 times.
100 if (size < file_ptr -> fx_file_current_file_size)
151 {
152
153 /* Setup the new size. */
154 91 file_ptr -> fx_file_current_file_size = size;
155
156 /* Set the modified flag as well. */
157 91 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 5 FX_UNPROTECT
170
171 /* Just return, the new size is larger than the current size. */
172 9 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 91 open_count = media_ptr -> fx_media_opened_file_count;
179 91 search_ptr = media_ptr -> fx_media_opened_file_list;
180
4/4
✓ Branch 17 → 12 taken 110 times.
✓ Branch 17 → 18 taken 42 times.
✓ Branch 21 → 16 taken 134 times.
✓ Branch 21 → 22 taken 49 times.
335 while (open_count)
181 {
182
183 /* Is this file the same file opened for reading? */
184
4/4
✓ Branch 12 → 13 taken 68 times.
✓ Branch 12 → 16 taken 42 times.
✓ Branch 16 → 17 taken 85 times.
✓ Branch 16 → 20 taken 49 times.
244 if ((search_ptr != file_ptr) &&
185 153 (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
186
4/4
✓ Branch 13 → 14 taken 48 times.
✓ Branch 13 → 16 taken 20 times.
✓ Branch 17 → 18 taken 60 times.
✓ Branch 17 → 20 taken 25 times.
153 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
187 108 (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
188
4/4
✓ Branch 14 → 15 taken 20 times.
✓ Branch 14 → 16 taken 28 times.
✓ Branch 18 → 19 taken 25 times.
✓ Branch 18 → 20 taken 35 times.
108 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 45 search_ptr -> fx_file_current_file_size = size;
195 45 search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
196 }
197
198 /* Adjust the pointer and decrement the search count. */
199 244 search_ptr = search_ptr -> fx_file_opened_next;
200 244 open_count--;
201 }
202 #endif
203
204 /* Now check to see if the read/write internal file pointers need
205 to be adjusted. */
206
4/4
✓ Branch 18 → 19 taken 32 times.
✓ Branch 18 → 31 taken 10 times.
✓ Branch 22 → 23 taken 38 times.
✓ Branch 22 → 37 taken 11 times.
91 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 70 bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
211 70 ((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 70 cluster = file_ptr -> fx_file_first_physical_cluster;
216 70 bytes_remaining = size;
217 70 last_cluster = 0;
218 70 cluster_count = 0;
219
220 /* Follow the link of FAT entries. */
221
8/8
✓ Branch 26 → 27 taken 1084 times.
✓ Branch 26 → 28 taken 4 times.
✓ Branch 27 → 20 taken 1080 times.
✓ Branch 27 → 28 taken 4 times.
✓ Branch 31 → 32 taken 1353 times.
✓ Branch 31 → 33 taken 5 times.
✓ Branch 32 → 24 taken 1348 times.
✓ Branch 32 → 33 taken 5 times.
2446 while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
222 {
223
224 /* Increment the number of clusters. */
225 2428 cluster_count++;
226
227 /* Read the current cluster entry from the FAT. */
228 2428 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
229
230 /* Check the return value. */
231
4/4
✓ Branch 21 → 22 taken 4 times.
✓ Branch 21 → 23 taken 1076 times.
✓ Branch 25 → 26 taken 5 times.
✓ Branch 25 → 28 taken 1343 times.
2428 if (status != FX_SUCCESS)
232 {
233
234 /* Release media protection. */
235 5 FX_UNPROTECT
236
237 /* Return the error status. */
238 9 return(status);
239 }
240
241 /* Save the last valid cluster. */
242 2419 last_cluster = cluster;
243
244 /* Setup for the next cluster. */
245 2419 cluster = contents;
246
247 /* Determine if this is the last written cluster. */
248
4/4
✓ Branch 23 → 24 taken 1056 times.
✓ Branch 23 → 25 taken 20 times.
✓ Branch 28 → 29 taken 1320 times.
✓ Branch 28 → 30 taken 23 times.
2419 if (bytes_remaining >= bytes_per_cluster)
249 {
250
251 /* Still more seeking, just decrement the working byte offset. */
252 2376 bytes_remaining = bytes_remaining - bytes_per_cluster;
253 }
254 else
255 {
256
257 /* This is the cluster that contains the seek position. */
258 43 break;
259 }
260 }
261
262 /* Check for errors in traversal of the FAT chain. */
263
4/4
✓ Branch 28 → 29 taken 8 times.
✓ Branch 28 → 30 taken 20 times.
✓ Branch 33 → 34 taken 10 times.
✓ Branch 33 → 36 taken 23 times.
61 if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
264 {
265
266 /* Release media protection. */
267 10 FX_UNPROTECT
268
269 /* This is an error that suggests a corrupt file. */
270 18 return(FX_FILE_CORRUPT);
271 }
272
273 /* Position the pointers to the new offset. */
274 43 file_ptr -> fx_file_current_physical_cluster = last_cluster;
275 43 file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
276 43 file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
277 43 (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
278 43 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
279 43 (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
280 43 file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
281 43 file_ptr -> fx_file_current_file_offset = size;
282 43 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
4/4
✓ Branch 31 → 32 taken 14 times.
✓ Branch 31 → 42 taken 8 times.
✓ Branch 37 → 38 taken 14 times.
✓ Branch 37 → 50 taken 8 times.
44 if (media_ptr -> fx_media_fault_tolerant_enabled)
287 {
288
289 /* Start transaction. */
290 28 _fx_fault_tolerant_transaction_start(media_ptr);
291
292 /* Copy the new file size into the directory entry. */
293 28 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 28 status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
297
298 /* Check for a good status. */
299
4/4
✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 37 taken 12 times.
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 44 taken 12 times.
28 if (status != FX_SUCCESS)
300 {
301
302 4 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
303
304 /* Release media protection. */
305 2 FX_UNPROTECT
306
307 /* Error writing the directory. */
308 4 return(status);
309 }
310
311 /* End transaction. */
312 24 status = _fx_fault_tolerant_transaction_end(media_ptr);
313
314 /* Check for a good status. */
315
4/4
✓ Branch 38 → 39 taken 2 times.
✓ Branch 38 → 40 taken 4 times.
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 48 taken 4 times.
12 if (status != FX_SUCCESS)
316 {
317
318 /* Release media protection. */
319 2 FX_UNPROTECT
320
321 /* Error writing the directory. */
322 4 return(status);
323 }
324
325 /* Update maximum size used if necessary. */
326
4/4
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 42 taken 2 times.
✓ Branch 48 → 49 taken 2 times.
✓ Branch 48 → 50 taken 2 times.
8 if (size < file_ptr -> fx_file_maximum_size_used)
327 {
328 4 file_ptr -> fx_file_maximum_size_used = size;
329 }
330 }
331 #endif /* FX_ENABLE_FAULT_TOLERANT */
332
333 /* Release media protection. */
334 24 FX_UNPROTECT
335
336 /* Truncate is complete, return successful status. */
337 44 return(FX_SUCCESS);
338 }
339
340