GCC Code Coverage Report


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

fx_media_close.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 /** Media */
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_media.h"
31 #include "fx_file.h"
32 #include "fx_directory.h"
33 #include "fx_utility.h"
34
35
36 /**************************************************************************/
37 /* */
38 /* FUNCTION RELEASE */
39 /* */
40 /* _fx_media_close PORTABLE C */
41 /* 6.1 */
42 /* AUTHOR */
43 /* */
44 /* William E. Lamie, Microsoft Corporation */
45 /* */
46 /* DESCRIPTION */
47 /* */
48 /* This function examines the list of open files for this media and */
49 /* closes each file. If a file has been written to, the file's */
50 /* directory information is also written out to the media. After */
51 /* the files have been closed, the internal logical sector is */
52 /* flushed and a flush command is sent to the attached driver. */
53 /* Finally, this media control block is removed from the list of */
54 /* opened media control blocks and is marked as closed. */
55 /* */
56 /* INPUT */
57 /* */
58 /* media_ptr Media control block pointer */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* return status */
63 /* */
64 /* CALLS */
65 /* */
66 /* _fx_directory_entry_write Write the directory entry */
67 /* _fx_media_abort Abort the media on error */
68 /* _fx_utility_FAT_flush Flush cached FAT entries */
69 /* _fx_utility_FAT_map_flush Flush primary FAT changes to */
70 /* secondary FAT(s) */
71 /* _fx_utility_logical_sector_flush Flush logical sector cache */
72 /* _fx_utility_16_unsigned_read Read a 16-bit value */
73 /* _fx_utility_32_unsigned_read Read a 32-bit value */
74 /* _fx_utility_32_unsigned_write Write a 32-bit value */
75 /* tx_mutex_delete Delete protection mutex */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code */
80 /* */
81 /**************************************************************************/
82 48395 UINT _fx_media_close(FX_MEDIA *media_ptr)
83 {
84
85 FX_INT_SAVE_AREA
86
87 #ifndef FX_DISABLE_FILE_CLOSE
88 ULONG open_count;
89 FX_FILE *file_ptr;
90 #endif /* FX_DISABLE_FILE_CLOSE */
91 UINT status;
92
93
94 /* Check the media to make sure it is open. */
95
2/2
✓ Branch 2 → 3 taken 14409 times.
✓ Branch 2 → 4 taken 33986 times.
48395 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
96 {
97
98 /* Return the media not opened error. */
99 14409 return(FX_MEDIA_NOT_OPEN);
100 }
101
102 /* If trace is enabled, insert this event into the trace buffer. */
103 FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CLOSE, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
104
105 /* If trace is enabled, unregister this object. */
106 FX_TRACE_OBJECT_UNREGISTER(media_ptr)
107
108 /* Protect against other threads accessing the media. */
109 18838 FX_PROTECT
110
111 #ifndef FX_DISABLE_FILE_CLOSE
112 /* Loop through the media's open files. */
113 33986 open_count = media_ptr -> fx_media_opened_file_count;
114 33986 file_ptr = media_ptr -> fx_media_opened_file_list;
115
4/4
✓ Branch 13 → 5 taken 48184 times.
✓ Branch 13 → 14 taken 15144 times.
✓ Branch 17 → 6 taken 60229 times.
✓ Branch 17 → 18 taken 18833 times.
142390 while (open_count)
116 {
117
118 /* Look at each opened file to see if the same file is opened
119 for writing and has been written to. */
120
4/4
✓ Branch 5 → 6 taken 44164 times.
✓ Branch 5 → 12 taken 4020 times.
✓ Branch 6 → 7 taken 55204 times.
✓ Branch 6 → 16 taken 5025 times.
108413 if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
121
4/4
✓ Branch 6 → 7 taken 38 times.
✓ Branch 6 → 12 taken 44126 times.
✓ Branch 7 → 8 taken 48 times.
✓ Branch 7 → 16 taken 55156 times.
99368 (file_ptr -> fx_file_modified))
122 {
123
124 /* Lockout interrupts for time/date access. */
125 48 FX_DISABLE_INTS
126
127 /* Set the new time and date. */
128 86 file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time;
129 86 file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date;
130
131 /* Restore interrupt posture. */
132 48 FX_RESTORE_INTS
133
134 /* Copy the new file size into the directory entry. */
135 86 file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
136 86 file_ptr -> fx_file_current_file_size;
137
138 /* Write the directory entry to the media. */
139 86 status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
140
141 /* Determine if the status was unsuccessful. */
142
4/4
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 11 taken 34 times.
✓ Branch 11 → 12 taken 5 times.
✓ Branch 11 → 15 taken 43 times.
86 if (status != FX_SUCCESS)
143 {
144
145 /* Release media protection. */
146 5 FX_UNPROTECT
147
148 /* Call the media abort routine. */
149 9 _fx_media_abort(media_ptr);
150
151 /* Return the error status. */
152 9 return(FX_IO_ERROR);
153 }
154
155 /* Clear the file modified flag. */
156 77 file_ptr -> fx_file_modified = FX_FALSE;
157 }
158
159 /* Mark the file as closed. */
160 108404 file_ptr -> fx_file_id = FX_FILE_CLOSED_ID;
161
162 /* Adjust the pointer and decrement the opened count. */
163 108404 file_ptr = file_ptr -> fx_file_opened_next;
164 108404 open_count--;
165 }
166 #endif /* FX_DISABLE_FILE_CLOSE */
167
168 /* Flush the cached individual FAT entries */
169 33977 _fx_utility_FAT_flush(media_ptr);
170
171 /* Flush changed sector(s) in the primary FAT to secondary FATs. */
172 33977 _fx_utility_FAT_map_flush(media_ptr);
173
174
175 /* Flush the internal logical sector cache. */
176 33977 status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
177
178 /* Determine if the flush was unsuccessful. */
179
4/4
✓ Branch 17 → 18 taken 4 times.
✓ Branch 17 → 20 taken 15140 times.
✓ Branch 21 → 22 taken 5 times.
✓ Branch 21 → 25 taken 18828 times.
33977 if (status != FX_SUCCESS)
180 {
181
182 /* Release media protection. */
183 5 FX_UNPROTECT
184
185 /* Call the media abort routine. */
186 9 _fx_media_abort(media_ptr);
187
188 /* Return the error status. */
189 9 return(FX_IO_ERROR);
190 }
191
192 /* Determine if the media needs to have the additional information sector updated. This will
193 only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
194 available cluster count is different that the currently available clusters. */
195
4/4
✓ Branch 20 → 21 taken 12150 times.
✓ Branch 20 → 38 taken 2990 times.
✓ Branch 25 → 26 taken 15183 times.
✓ Branch 25 → 45 taken 3645 times.
33968 if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
196
4/4
✓ Branch 21 → 22 taken 4074 times.
✓ Branch 21 → 38 taken 8076 times.
✓ Branch 26 → 27 taken 5084 times.
✓ Branch 26 → 45 taken 10099 times.
27333 (media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters) &&
197
4/4
✓ Branch 22 → 23 taken 4070 times.
✓ Branch 22 → 38 taken 4 times.
✓ Branch 27 → 28 taken 5079 times.
✓ Branch 27 → 45 taken 5 times.
9158 (media_ptr -> fx_media_driver_write_protect == FX_FALSE))
198 {
199
200 UCHAR *buffer_ptr;
201 ULONG signature;
202
203
204 #ifndef FX_DISABLE_CACHE
205 /* Setup a pointer to the first cached entry's buffer. */
206 5079 buffer_ptr = (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
207
208 /* Invalidate this cache entry. */
209 5079 (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector = (~(ULONG64)0);
210 5079 (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid = FX_FALSE;
211 #else
212 4070 buffer_ptr = media_ptr -> fx_media_memory_buffer;
213 #endif /* FX_DISABLE_CACHE */
214
215 /* Read the FAT32 additional information sector from the device. */
216 9149 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
217 9149 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
218 9149 media_ptr -> fx_media_driver_buffer = buffer_ptr;
219 9149 media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
220 9149 media_ptr -> fx_media_driver_sectors = 1;
221 9149 media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
222
223 #ifndef FX_MEDIA_STATISTICS_DISABLE
224
225 /* Increment the number of driver read sector(s) requests. */
226 9149 media_ptr -> fx_media_driver_read_requests++;
227 #endif
228
229 /* If trace is enabled, insert this event into the trace buffer. */
230 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
231
232 /* Invoke the driver to read the FAT32 additional information sector. */
233 9149 (media_ptr -> fx_media_driver_entry) (media_ptr);
234
235 /* Determine if the FAT32 sector was read correctly. */
236
4/4
✓ Branch 24 → 25 taken 912 times.
✓ Branch 24 → 27 taken 3158 times.
✓ Branch 29 → 30 taken 1140 times.
✓ Branch 29 → 33 taken 3939 times.
9149 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
237 {
238
239 /* Release media protection. */
240 1140 FX_UNPROTECT
241
242 /* Call the media abort routine. */
243 2052 _fx_media_abort(media_ptr);
244
245 /* Return the error status. */
246 2052 return(FX_IO_ERROR);
247 }
248
249 /* Setup a pointer into the FAT32 additional information sector. */
250 7097 buffer_ptr = media_ptr -> fx_media_driver_buffer;
251
252 /* Pickup the first signature long word. */
253 7097 signature = _fx_utility_32_unsigned_read(&buffer_ptr[0]);
254
255 /* Determine if the signature is correct. */
256
4/4
✓ Branch 28 → 29 taken 3154 times.
✓ Branch 28 → 38 taken 4 times.
✓ Branch 34 → 35 taken 3934 times.
✓ Branch 34 → 45 taken 5 times.
7097 if (signature == 0x41615252)
257 {
258
259 /* Yes, the first signature is correct, now pickup the next signature. */
260 7088 signature = _fx_utility_32_unsigned_read(&buffer_ptr[484]);
261
262 /* Determine if this signature is correct. */
263
4/4
✓ Branch 30 → 31 taken 3150 times.
✓ Branch 30 → 38 taken 4 times.
✓ Branch 36 → 37 taken 3929 times.
✓ Branch 36 → 45 taken 5 times.
7088 if (signature == 0x61417272)
264 {
265
266 /* Yes, we have a good FAT32 additional information sector. */
267
268 /* Set the free cluster count to the available clusters in the media control block. */
269 7079 _fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters);
270
271 /* Set the next free cluster number hint to starting search cluster in the media control block. */
272 7079 _fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start);
273
274 /* Now write the sector back out to the media. */
275 7079 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
276 7079 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
277 7079 media_ptr -> fx_media_driver_buffer = buffer_ptr;
278 7079 media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
279 7079 media_ptr -> fx_media_driver_sectors = 1;
280 7079 media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
281
282 /* Set the system write flag since we are writing a directory sector. */
283 7079 media_ptr -> fx_media_driver_system_write = FX_TRUE;
284
285 #ifndef FX_MEDIA_STATISTICS_DISABLE
286
287 /* Increment the number of driver write sector(s) requests. */
288 7079 media_ptr -> fx_media_driver_write_requests++;
289 #endif
290
291 /* If trace is enabled, insert this event into the trace buffer. */
292 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
293
294 /* Invoke the driver to write the FAT32 additional information sector. */
295 7079 (media_ptr -> fx_media_driver_entry) (media_ptr);
296
297 /* Clear the system write flag. */
298 7079 media_ptr -> fx_media_driver_system_write = FX_FALSE;
299
300 /* Determine if the FAT32 sector was written correctly. */
301
4/4
✓ Branch 34 → 35 taken 380 times.
✓ Branch 34 → 37 taken 2770 times.
✓ Branch 40 → 41 taken 475 times.
✓ Branch 40 → 44 taken 3454 times.
7079 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
302 {
303
304 /* Release media protection. */
305 475 FX_UNPROTECT
306
307 /* Call the media abort routine. */
308 855 _fx_media_abort(media_ptr);
309
310 /* Return the sector IO error status. */
311 855 return(FX_IO_ERROR);
312 }
313
314 /* Successful update of the FAT32 additional information sector. Update the
315 last written available cluster count. */
316 6224 media_ptr -> fx_media_FAT32_additional_info_last_available = media_ptr -> fx_media_available_clusters;
317 }
318 }
319 }
320
321 #ifndef FX_MEDIA_STATISTICS_DISABLE
322
323 /* Increment the number of driver flush requests. */
324 31061 media_ptr -> fx_media_driver_flush_requests++;
325 #endif
326
327 /* Build the "flush" I/O driver request. */
328 31061 media_ptr -> fx_media_driver_request = FX_DRIVER_FLUSH;
329 31061 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
330
331 /* If trace is enabled, insert this event into the trace buffer. */
332 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
333
334 /* Call the specified I/O driver with the flush request. */
335 31061 (media_ptr -> fx_media_driver_entry) (media_ptr);
336
337 /* Build the "uninitialize" I/O driver request. */
338 31061 media_ptr -> fx_media_driver_request = FX_DRIVER_UNINIT;
339 31061 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
340
341 /* If trace is enabled, insert this event into the trace buffer. */
342 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
343
344 /* Call the specified I/O driver with the uninitialize request. */
345 31061 (media_ptr -> fx_media_driver_entry) (media_ptr);
346
347 /* Now remove this media from the open list. */
348
349 /* Lockout interrupts for media removal. */
350 17213 FX_DISABLE_INTS
351
352 /* See if the media is the only one on the media opened list. */
353
4/4
✓ Branch 40 → 41 taken 13836 times.
✓ Branch 40 → 42 taken 12 times.
✓ Branch 48 → 49 taken 17198 times.
✓ Branch 48 → 50 taken 15 times.
31061 if (_fx_system_media_opened_count == ((ULONG) 1))
354 {
355
356 /* Only opened media, just set the opened list to NULL. */
357 31034 _fx_system_media_opened_ptr = FX_NULL;
358 }
359 else
360 {
361
362 /* Otherwise, not the only opened media, link-up the neighbors. */
363 27 (media_ptr -> fx_media_opened_next) -> fx_media_opened_previous =
364 27 media_ptr -> fx_media_opened_previous;
365 27 (media_ptr -> fx_media_opened_previous) -> fx_media_opened_next =
366 27 media_ptr -> fx_media_opened_next;
367
368 /* See if we have to update the opened list head pointer. */
369
4/4
✓ Branch 42 → 43 taken 8 times.
✓ Branch 42 → 44 taken 4 times.
✓ Branch 50 → 51 taken 10 times.
✓ Branch 50 → 52 taken 5 times.
27 if (_fx_system_media_opened_ptr == media_ptr)
370 {
371
372 /* Yes, move the head pointer to the next opened media. */
373 18 _fx_system_media_opened_ptr = media_ptr -> fx_media_opened_next;
374 }
375 }
376
377 /* Decrement the opened media counter. */
378 31061 _fx_system_media_opened_count--;
379
380 /* Finally, Indicate that this media is closed. */
381 31061 media_ptr -> fx_media_id = FX_MEDIA_CLOSED_ID;
382
383 /* Restore interrupt posture. */
384 17213 FX_RESTORE_INTS
385
386 /* Delete the media protection structure if FX_SINGLE_THREAD is not
387 defined. */
388 #ifndef FX_SINGLE_THREAD
389
390 #ifndef FX_DONT_CREATE_MUTEX
391
392 /* Note that the protection is never released. The mutex delete
393 service will handle all threads waiting access to this media
394 control block. */
395 17213 tx_mutex_delete(& (media_ptr -> fx_media_protect));
396 #endif
397 #endif
398
399 /* Invoke media close callback. */
400
4/4
✓ Branch 44 → 45 taken 4 times.
✓ Branch 44 → 46 taken 13844 times.
✓ Branch 54 → 55 taken 5 times.
✓ Branch 54 → 56 taken 17208 times.
31061 if (media_ptr -> fx_media_close_notify)
401 {
402 9 media_ptr -> fx_media_close_notify(media_ptr);
403 }
404
405 #ifdef FX_DONT_CREATE_MUTEX
406
407 /* Release media protection. */
408 FX_UNPROTECT
409 #endif
410
411 /* Return success status to the caller. */
412 31061 return(FX_SUCCESS);
413 }
414
415