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 /** Media */
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_media.h"
30 #include "fx_file.h"
31 #include "fx_directory.h"
32 #include "fx_utility.h"
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _fx_media_flush PORTABLE C */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function examines the list of open files for this media and */
48 /* "flushes" each written open file to the underlying media. After */
49 /* the open files have been flushed, the internal logical sector is */
50 /* flushed. Finally, the attached driver is sent a flush command so */
51 /* that it can flush its sector cache (if any) to the media. */
52 /* */
53 /* INPUT */
54 /* */
55 /* media_ptr Media control block pointer */
56 /* */
57 /* OUTPUT */
58 /* */
59 /* return status */
60 /* */
61 /* CALLS */
62 /* */
63 /* _fx_directory_entry_write Write the directory entry */
64 /* _fx_utility_FAT_flush Flush cached FAT entries */
65 /* _fx_utility_FAT_map_flush Flush primary FAT changes to */
66 /* secondary FAT(s) */
67 /* _fx_utility_logical_sector_flush Flush logical sector cache */
68 /* _fx_utility_32_unsigned_read Read 32-bit unsigned */
69 /* _fx_utility_32_unsigned_write Write 32-bit unsigned */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* Application Code */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
80 /* 09-30-2020 William E. Lamie Modified comment(s), and */
81 /* added conditional to */
82 /* disable cache, */
83 /* resulting in version 6.1 */
84 /* */
85 /**************************************************************************/
_fx_media_flush(FX_MEDIA * media_ptr)86 UINT _fx_media_flush(FX_MEDIA *media_ptr)
87 {
88
89 UINT status;
90 ULONG open_count;
91 FX_FILE *file_ptr;
92 FX_INT_SAVE_AREA
93
94
95 #ifndef FX_MEDIA_STATISTICS_DISABLE
96
97 /* Increment the number of times this service has been called. */
98 media_ptr -> fx_media_flushes++;
99 #endif
100
101 /* Check the media to make sure it is open. */
102 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
103 {
104
105 /* Return the media not opened error. */
106 return(FX_MEDIA_NOT_OPEN);
107 }
108
109 /* If trace is enabled, insert this event into the trace buffer. */
110 FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
111
112 /* Protect against other threads accessing the media. */
113 FX_PROTECT
114
115 /* Check for write protect at the media level (set by driver). */
116 if (media_ptr -> fx_media_driver_write_protect)
117 {
118
119 /* Release media protection. */
120 FX_UNPROTECT
121
122 /* Return write protect error. */
123 return(FX_WRITE_PROTECT);
124 }
125
126 /* Loop through the media's open files. */
127 open_count = media_ptr -> fx_media_opened_file_count;
128 file_ptr = media_ptr -> fx_media_opened_file_list;
129 while (open_count)
130 {
131
132 /* Look at each opened file to see if the same file is opened
133 for writing and has been written to. */
134 if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
135 (file_ptr -> fx_file_modified))
136 {
137
138 /* Protect against update. */
139 FX_DISABLE_INTS
140
141 /* Set the new time and date. */
142 file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time;
143 file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date;
144
145 /* Restore interrupts. */
146 FX_RESTORE_INTS
147
148 /* Copy the new file size into the directory entry. */
149 file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
150 file_ptr -> fx_file_current_file_size;
151
152 /* Write the directory entry to the media. */
153 status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
154
155 /* Check for a good status. */
156 if (status != FX_SUCCESS)
157 {
158
159 /* Release media protection. */
160 FX_UNPROTECT
161
162 /* Error writing the directory. */
163 return(status);
164 }
165
166 /* Clear the file modified flag. */
167 file_ptr -> fx_file_modified = FX_FALSE;
168 }
169
170 /* Adjust the pointer and decrement the opened count. */
171 file_ptr = file_ptr -> fx_file_opened_next;
172 open_count--;
173 }
174
175 /* Flush the cached individual FAT entries */
176 _fx_utility_FAT_flush(media_ptr);
177
178 /* Flush changed sector(s) in the primary FAT to secondary FATs. */
179 _fx_utility_FAT_map_flush(media_ptr);
180
181
182 /* Flush the internal logical sector cache. */
183 status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
184
185 /* Check for a good status. */
186 if (status != FX_SUCCESS)
187 {
188
189 /* Release media protection. */
190 FX_UNPROTECT
191
192 /* Error writing the directory. */
193 return(status);
194 }
195
196 /* Determine if the media needs to have the additional information sector updated. This will
197 only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
198 available cluster count is different that the currently available clusters. */
199 if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
200 (media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters))
201 {
202
203 UCHAR *buffer_ptr;
204 ULONG signature;
205
206 #ifndef FX_DISABLE_CACHE
207
208 /* Setup a pointer to the first cached entry's buffer. */
209 buffer_ptr = (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
210
211 /* Invalidate this cache entry. */
212 (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector = (~(ULONG64)0);
213 (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid = FX_FALSE;
214 #else
215 buffer_ptr = media_ptr -> fx_media_memory_buffer;
216 #endif /* FX_DISABLE_CACHE */
217
218 /* Read the FAT32 additional information sector from the device. */
219 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
220 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
221 media_ptr -> fx_media_driver_buffer = buffer_ptr;
222 media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
223 media_ptr -> fx_media_driver_sectors = 1;
224 media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
225
226 #ifndef FX_MEDIA_STATISTICS_DISABLE
227
228 /* Increment the number of driver read sector(s) requests. */
229 media_ptr -> fx_media_driver_read_requests++;
230 #endif
231
232 /* If trace is enabled, insert this event into the trace buffer. */
233 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)
234
235 /* Invoke the driver to read the FAT32 additional information sector. */
236 (media_ptr -> fx_media_driver_entry) (media_ptr);
237
238 /* Determine if the FAT32 sector was read correctly. */
239 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
240 {
241
242 /* Release media protection. */
243 FX_UNPROTECT
244
245 /* Return the error status. */
246 return(FX_IO_ERROR);
247 }
248
249 /* Setup a pointer into the FAT32 additional information sector. */
250 buffer_ptr = media_ptr -> fx_media_driver_buffer;
251
252 /* Pickup the first signature long word. */
253 signature = _fx_utility_32_unsigned_read(&buffer_ptr[0]);
254
255 /* Determine if the signature is correct. */
256 if (signature == 0x41615252)
257 {
258
259 /* Yes, the first signature is correct, now pickup the next signature. */
260 signature = _fx_utility_32_unsigned_read(&buffer_ptr[484]);
261
262 /* Determine if this signature is correct. */
263 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 _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 _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 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
276 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
277 media_ptr -> fx_media_driver_buffer = buffer_ptr;
278 media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector;
279 media_ptr -> fx_media_driver_sectors = 1;
280 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 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 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 (media_ptr -> fx_media_driver_entry) (media_ptr);
296
297 /* Clear the system write flag. */
298 media_ptr -> fx_media_driver_system_write = FX_FALSE;
299
300 /* Determine if the FAT32 sector was written correctly. */
301 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
302 {
303
304 /* Release media protection. */
305 FX_UNPROTECT
306
307 /* Return the sector IO error status. */
308 return(FX_IO_ERROR);
309 }
310
311 /* Successful update of the FAT32 additional information sector. Update the
312 last written available cluster count. */
313 media_ptr -> fx_media_FAT32_additional_info_last_available = media_ptr -> fx_media_available_clusters;
314 }
315 }
316 }
317
318 #ifndef FX_MEDIA_STATISTICS_DISABLE
319
320 /* Increment the number of driver flush requests. */
321 media_ptr -> fx_media_driver_flush_requests++;
322 #endif
323
324 /* Build the "flush" I/O driver request. */
325 media_ptr -> fx_media_driver_request = FX_DRIVER_FLUSH;
326 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
327
328 /* If trace is enabled, insert this event into the trace buffer. */
329 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
330
331 /* Call the specified I/O driver with the flush request. */
332 (media_ptr -> fx_media_driver_entry) (media_ptr);
333
334 /* Determine if the I/O driver flushed successfully. */
335 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
336 {
337
338 /* Release media protection. */
339 FX_UNPROTECT
340
341 /* Return the driver error status. */
342 return(FX_IO_ERROR);
343 }
344
345 /* Release media protection. */
346 FX_UNPROTECT
347
348 /* If we get here, return successful status to the caller. */
349 return(FX_SUCCESS);
350 }
351
352