GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_media_flush.c Lines: 78 78 100.0 %
Date: 2024-03-11 05:15:45 Branches: 28 28 100.0 %

Line Branch Exec Source
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
/**************************************************************************/
86
33016
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
33016
    media_ptr -> fx_media_flushes++;
99
#endif
100
101
    /* Check the media to make sure it is open.  */
102
33016
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
103
    {
104
105
        /* Return the media not opened error.  */
106
1
        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
33015
    FX_PROTECT
114
115
    /* Check for write protect at the media level (set by driver).  */
116
33015
    if (media_ptr -> fx_media_driver_write_protect)
117
    {
118
119
        /* Release media protection.  */
120
1
        FX_UNPROTECT
121
122
        /* Return write protect error.  */
123
1
        return(FX_WRITE_PROTECT);
124
    }
125
126
    /* Loop through the media's open files.  */
127
33014
    open_count =  media_ptr -> fx_media_opened_file_count;
128
33014
    file_ptr =    media_ptr -> fx_media_opened_file_list;
129
124145
    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
91132
        if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
135
55581
            (file_ptr -> fx_file_modified))
136
        {
137
138
            /* Protect against update.  */
139
20899
            FX_DISABLE_INTS
140
141
            /* Set the new time and date.  */
142
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_time =  _fx_system_time;
143
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_date =  _fx_system_date;
144
145
            /* Restore interrupts.  */
146
20899
            FX_RESTORE_INTS
147
148
            /* Copy the new file size into the directory entry.  */
149
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
150
20899
                file_ptr -> fx_file_current_file_size;
151
152
            /* Write the directory entry to the media.  */
153
20899
            status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
154
155
            /* Check for a good status.  */
156
20899
            if (status != FX_SUCCESS)
157
            {
158
159
                /* Release media protection.  */
160
1
                FX_UNPROTECT
161
162
                /* Error writing the directory.  */
163
1
                return(status);
164
            }
165
166
            /* Clear the file modified flag.  */
167
20898
            file_ptr -> fx_file_modified =  FX_FALSE;
168
        }
169
170
        /* Adjust the pointer and decrement the opened count.  */
171
91131
        file_ptr =  file_ptr -> fx_file_opened_next;
172
91131
        open_count--;
173
    }
174
175
    /* Flush the cached individual FAT entries */
176
33013
    _fx_utility_FAT_flush(media_ptr);
177
178
    /* Flush changed sector(s) in the primary FAT to secondary FATs.  */
179
33013
    _fx_utility_FAT_map_flush(media_ptr);
180
181
182
    /* Flush the internal logical sector cache.  */
183
33013
    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
33013
    if (status != FX_SUCCESS)
187
    {
188
189
        /* Release media protection.  */
190
1
        FX_UNPROTECT
191
192
        /* Error writing the directory.  */
193
1
        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
33012
    if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
200
1027
        (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
1008
        buffer_ptr =  (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
210
211
        /* Invalidate this cache entry.  */
212
1008
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector =  (~(ULONG64)0);
213
1008
        (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
1008
        media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
220
1008
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
221
1008
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
222
1008
        media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
223
1008
        media_ptr -> fx_media_driver_sectors =          1;
224
1008
        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
1008
        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
1008
        (media_ptr -> fx_media_driver_entry) (media_ptr);
237
238
        /* Determine if the FAT32 sector was read correctly. */
239
1008
        if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
240
        {
241
242
            /* Release media protection.  */
243
205
            FX_UNPROTECT
244
245
            /* Return the error status.  */
246
205
            return(FX_IO_ERROR);
247
        }
248
249
        /* Setup a pointer into the FAT32 additional information sector.  */
250
803
        buffer_ptr =  media_ptr -> fx_media_driver_buffer;
251
252
        /* Pickup the first signature long word.  */
253
803
        signature =  _fx_utility_32_unsigned_read(&buffer_ptr[0]);
254
255
        /* Determine if the signature is correct.  */
256
803
        if (signature == 0x41615252)
257
        {
258
259
            /* Yes, the first signature is correct, now pickup the next signature.  */
260
801
            signature =  _fx_utility_32_unsigned_read(&buffer_ptr[484]);
261
262
            /* Determine if this signature is correct.  */
263
801
            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
800
                _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
800
                _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
800
                media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
276
800
                media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
277
800
                media_ptr -> fx_media_driver_buffer =           buffer_ptr;
278
800
                media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
279
800
                media_ptr -> fx_media_driver_sectors =          1;
280
800
                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
800
                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
800
                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
800
                (media_ptr -> fx_media_driver_entry) (media_ptr);
296
297
                /* Clear the system write flag.  */
298
800
                media_ptr -> fx_media_driver_system_write =  FX_FALSE;
299
300
                /* Determine if the FAT32 sector was written correctly. */
301
800
                if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
302
                {
303
304
                    /* Release media protection.  */
305
90
                    FX_UNPROTECT
306
307
                    /* Return the sector IO error status.  */
308
90
                    return(FX_IO_ERROR);
309
                }
310
311
                /* Successful update of the FAT32 additional information sector. Update the
312
                   last written available cluster count.  */
313
710
                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
32717
    media_ptr -> fx_media_driver_flush_requests++;
322
#endif
323
324
    /* Build the "flush" I/O driver request.  */
325
32717
    media_ptr -> fx_media_driver_request =      FX_DRIVER_FLUSH;
326
32717
    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
32717
    (media_ptr -> fx_media_driver_entry) (media_ptr);
333
334
    /* Determine if the I/O driver flushed successfully.  */
335
32717
    if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
336
    {
337
338
        /* Release media protection.  */
339
100
        FX_UNPROTECT
340
341
        /* Return the driver error status.  */
342
100
        return(FX_IO_ERROR);
343
    }
344
345
    /* Release media protection.  */
346
32617
    FX_UNPROTECT
347
348
    /* If we get here, return successful status to the caller.  */
349
32617
    return(FX_SUCCESS);
350
}
351