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