GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_media_close.c Lines: 94 94 100.0 %
Date: 2024-01-10 21:53:23 Branches: 32 32 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
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_exFAT_bitmap_flush        Flush exFAT allocation bitmap */
69
/*    _fx_utility_FAT_flush                 Flush cached FAT entries      */
70
/*    _fx_utility_FAT_map_flush             Flush primary FAT changes to  */
71
/*                                            secondary FAT(s)            */
72
/*    _fx_utility_logical_sector_flush      Flush logical sector cache    */
73
/*    _fx_utility_16_unsigned_read          Read a 16-bit value           */
74
/*    _fx_utility_32_unsigned_read          Read a 32-bit value           */
75
/*    _fx_utility_32_unsigned_write         Write a 32-bit value          */
76
/*    tx_mutex_delete                       Delete protection mutex       */
77
/*                                                                        */
78
/*  CALLED BY                                                             */
79
/*                                                                        */
80
/*    Application Code                                                    */
81
/*                                                                        */
82
/*  RELEASE HISTORY                                                       */
83
/*                                                                        */
84
/*    DATE              NAME                      DESCRIPTION             */
85
/*                                                                        */
86
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
87
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
88
/*                                            added conditional to        */
89
/*                                            disable file close          */
90
/*                                            and cache,                  */
91
/*                                            resulting in version 6.1    */
92
/*                                                                        */
93
/**************************************************************************/
94
5223
UINT  _fx_media_close(FX_MEDIA  *media_ptr)
95
{
96
97
FX_INT_SAVE_AREA
98
99
#ifndef FX_DISABLE_FILE_CLOSE
100
ULONG    open_count;
101
FX_FILE *file_ptr;
102
#endif /* FX_DISABLE_FILE_CLOSE */
103
UINT     status;
104
105
106
    /* Check the media to make sure it is open.  */
107
5223
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
108
    {
109
110
        /* Return the media not opened error.  */
111
1601
        return(FX_MEDIA_NOT_OPEN);
112
    }
113
114
    /* If trace is enabled, insert this event into the trace buffer.  */
115
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_CLOSE, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
116
117
    /* If trace is enabled, unregister this object.  */
118
    FX_TRACE_OBJECT_UNREGISTER(media_ptr)
119
120
    /* Protect against other threads accessing the media.  */
121
3622
    FX_PROTECT
122
123
#ifndef FX_DISABLE_FILE_CLOSE
124
    /* Loop through the media's open files.  */
125
3622
    open_count =  media_ptr -> fx_media_opened_file_count;
126
3622
    file_ptr =    media_ptr -> fx_media_opened_file_list;
127
15664
    while (open_count)
128
    {
129
130
        /* Look at each opened file to see if the same file is opened
131
           for writing and has been written to.  */
132
12043
        if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
133
11038
            (file_ptr -> fx_file_modified))
134
        {
135
136
            /* Lockout interrupts for time/date access.  */
137
8
            FX_DISABLE_INTS
138
139
            /* Set the new time and date.  */
140
8
            file_ptr -> fx_file_dir_entry.fx_dir_entry_time =  _fx_system_time;
141
8
            file_ptr -> fx_file_dir_entry.fx_dir_entry_date =  _fx_system_date;
142
143
            /* Restore interrupt posture.  */
144
8
            FX_RESTORE_INTS
145
146
            /* Copy the new file size into the directory entry.  */
147
8
            file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
148
8
                file_ptr -> fx_file_current_file_size;
149
150
            /* Write the directory entry to the media.  */
151
#ifdef FX_ENABLE_EXFAT
152
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
153
            {
154
155
                status = _fx_directory_exFAT_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
156
            }
157
            else
158
            {
159
#endif /* FX_ENABLE_EXFAT */
160
8
                status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
161
#ifdef FX_ENABLE_EXFAT
162
            }
163
#endif /* FX_ENABLE_EXFAT */
164
165
            /* Determine if the status was unsuccessful. */
166
8
            if (status != FX_SUCCESS)
167
            {
168
169
                /* Release media protection.  */
170
1
                FX_UNPROTECT
171
172
                /* Call the media abort routine.  */
173
1
                _fx_media_abort(media_ptr);
174
175
                /* Return the error status.  */
176
1
                return(FX_IO_ERROR);
177
            }
178
179
            /* Clear the file modified flag.  */
180
7
            file_ptr -> fx_file_modified =  FX_FALSE;
181
        }
182
183
        /* Mark the file as closed.  */
184
12042
        file_ptr -> fx_file_id =  FX_FILE_CLOSED_ID;
185
186
        /* Adjust the pointer and decrement the opened count.  */
187
12042
        file_ptr =  file_ptr -> fx_file_opened_next;
188
12042
        open_count--;
189
    }
190
#endif /* FX_DISABLE_FILE_CLOSE */
191
192
    /* Flush the cached individual FAT entries */
193
3621
    _fx_utility_FAT_flush(media_ptr);
194
195
    /* Flush changed sector(s) in the primary FAT to secondary FATs.  */
196
3621
    _fx_utility_FAT_map_flush(media_ptr);
197
198
#ifdef FX_ENABLE_EXFAT
199
    if ((media_ptr -> fx_media_FAT_type == FX_exFAT) &&
200
        (FX_TRUE == media_ptr -> fx_media_exfat_bitmap_cache_dirty))
201
    {
202
203
        /* Flush bitmap.  */
204
        _fx_utility_exFAT_bitmap_flush(media_ptr);
205
    }
206
#endif /* FX_ENABLE_EXFAT */
207
208
    /* Flush the internal logical sector cache.  */
209
3621
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
210
211
    /* Determine if the flush was unsuccessful. */
212
3621
    if (status != FX_SUCCESS)
213
    {
214
215
        /* Release media protection.  */
216
1
        FX_UNPROTECT
217
218
        /* Call the media abort routine.  */
219
1
        _fx_media_abort(media_ptr);
220
221
        /* Return the error status.  */
222
1
        return(FX_IO_ERROR);
223
    }
224
225
    /* Determine if the media needs to have the additional information sector updated. This will
226
       only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
227
       available cluster count is different that the currently available clusters.  */
228
3620
    if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
229
3029
        (media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters) &&
230
1010
        (media_ptr -> fx_media_driver_write_protect == FX_FALSE))
231
    {
232
233
    UCHAR *buffer_ptr;
234
    ULONG  signature;
235
236
237
#ifndef FX_DISABLE_CACHE
238
        /* Setup a pointer to the first cached entry's buffer.  */
239
1009
        buffer_ptr =  (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
240
241
        /* Invalidate this cache entry.  */
242
1009
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector =  (~(ULONG64)0);
243
1009
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid =  FX_FALSE;
244
#else
245
        buffer_ptr =  media_ptr -> fx_media_memory_buffer;
246
#endif /* FX_DISABLE_CACHE */
247
248
        /* Read the FAT32 additional information sector from the device.  */
249
1009
        media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
250
1009
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
251
1009
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
252
1009
        media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
253
1009
        media_ptr -> fx_media_driver_sectors =          1;
254
1009
        media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
255
256
#ifndef FX_MEDIA_STATISTICS_DISABLE
257
258
        /* Increment the number of driver read sector(s) requests.  */
259
1009
        media_ptr -> fx_media_driver_read_requests++;
260
#endif
261
262
        /* If trace is enabled, insert this event into the trace buffer.  */
263
        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)
264
265
        /* Invoke the driver to read the FAT32 additional information sector.  */
266
1009
        (media_ptr -> fx_media_driver_entry) (media_ptr);
267
268
        /* Determine if the FAT32 sector was read correctly. */
269
1009
        if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
270
        {
271
272
            /* Release media protection.  */
273
228
            FX_UNPROTECT
274
275
            /* Call the media abort routine.  */
276
228
            _fx_media_abort(media_ptr);
277
278
            /* Return the error status.  */
279
228
            return(FX_IO_ERROR);
280
        }
281
282
        /* Setup a pointer into the FAT32 additional information sector.  */
283
781
        buffer_ptr =  media_ptr -> fx_media_driver_buffer;
284
285
        /* Pickup the first signature long word.  */
286
781
        signature =  _fx_utility_32_unsigned_read(&buffer_ptr[0]);
287
288
        /* Determine if the signature is correct.  */
289
781
        if (signature == 0x41615252)
290
        {
291
292
            /* Yes, the first signature is correct, now pickup the next signature.  */
293
780
            signature =  _fx_utility_32_unsigned_read(&buffer_ptr[484]);
294
295
            /* Determine if this signature is correct.  */
296
780
            if (signature == 0x61417272)
297
            {
298
299
                /* Yes, we have a good FAT32 additional information sector.  */
300
301
                /* Set the free cluster count to the available clusters in the media control block.  */
302
779
                _fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters);
303
304
                /* Set the next free cluster number hint to starting search cluster in the media control block.  */
305
779
                _fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start);
306
307
                /* Now write the sector back out to the media.  */
308
779
                media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
309
779
                media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
310
779
                media_ptr -> fx_media_driver_buffer =           buffer_ptr;
311
779
                media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
312
779
                media_ptr -> fx_media_driver_sectors =          1;
313
779
                media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
314
315
                /* Set the system write flag since we are writing a directory sector.  */
316
779
                media_ptr -> fx_media_driver_system_write =  FX_TRUE;
317
318
#ifndef FX_MEDIA_STATISTICS_DISABLE
319
320
                /* Increment the number of driver write sector(s) requests.  */
321
779
                media_ptr -> fx_media_driver_write_requests++;
322
#endif
323
324
                /* If trace is enabled, insert this event into the trace buffer.  */
325
                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)
326
327
                /* Invoke the driver to write the FAT32 additional information sector.  */
328
779
                (media_ptr -> fx_media_driver_entry) (media_ptr);
329
330
                /* Clear the system write flag.  */
331
779
                media_ptr -> fx_media_driver_system_write =  FX_FALSE;
332
333
                /* Determine if the FAT32 sector was written correctly. */
334
779
                if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
335
                {
336
337
                    /* Release media protection.  */
338
95
                    FX_UNPROTECT
339
340
                    /* Call the media abort routine.  */
341
95
                    _fx_media_abort(media_ptr);
342
343
                    /* Return the sector IO error status.  */
344
95
                    return(FX_IO_ERROR);
345
                }
346
347
                /* Successful update of the FAT32 additional information sector. Update the
348
                   last written available cluster count.  */
349
684
                media_ptr -> fx_media_FAT32_additional_info_last_available =  media_ptr -> fx_media_available_clusters;
350
            }
351
        }
352
    }
353
354
#ifndef FX_MEDIA_STATISTICS_DISABLE
355
356
    /* Increment the number of driver flush requests.  */
357
3297
    media_ptr -> fx_media_driver_flush_requests++;
358
#endif
359
360
    /* Build the "flush" I/O driver request.  */
361
3297
    media_ptr -> fx_media_driver_request =      FX_DRIVER_FLUSH;
362
3297
    media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
363
364
    /* If trace is enabled, insert this event into the trace buffer.  */
365
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
366
367
    /* Call the specified I/O driver with the flush request.  */
368
3297
    (media_ptr -> fx_media_driver_entry) (media_ptr);
369
370
    /* Build the "uninitialize" I/O driver request.  */
371
3297
    media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
372
3297
    media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
373
374
    /* If trace is enabled, insert this event into the trace buffer.  */
375
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
376
377
    /* Call the specified I/O driver with the uninitialize request.  */
378
3297
    (media_ptr -> fx_media_driver_entry) (media_ptr);
379
380
    /* Now remove this media from the open list.  */
381
382
    /* Lockout interrupts for media removal.  */
383
3297
    FX_DISABLE_INTS
384
385
    /* See if the media is the only one on the media opened list.  */
386
3297
    if (_fx_system_media_opened_count == ((ULONG) 1))
387
    {
388
389
        /* Only opened media, just set the opened list to NULL.  */
390
3294
        _fx_system_media_opened_ptr =  FX_NULL;
391
    }
392
    else
393
    {
394
395
        /* Otherwise, not the only opened media, link-up the neighbors.  */
396
3
        (media_ptr -> fx_media_opened_next) -> fx_media_opened_previous =
397
3
            media_ptr -> fx_media_opened_previous;
398
3
        (media_ptr -> fx_media_opened_previous) -> fx_media_opened_next =
399
3
            media_ptr -> fx_media_opened_next;
400
401
        /* See if we have to update the opened list head pointer.  */
402
3
        if (_fx_system_media_opened_ptr == media_ptr)
403
        {
404
405
            /* Yes, move the head pointer to the next opened media. */
406
2
            _fx_system_media_opened_ptr =  media_ptr -> fx_media_opened_next;
407
        }
408
    }
409
410
    /* Decrement the opened media counter.  */
411
3297
    _fx_system_media_opened_count--;
412
413
    /* Finally, Indicate that this media is closed.  */
414
3297
    media_ptr -> fx_media_id =  FX_MEDIA_CLOSED_ID;
415
416
    /* Restore interrupt posture.  */
417
3297
    FX_RESTORE_INTS
418
419
    /* Delete the media protection structure if FX_SINGLE_THREAD is not
420
       defined.  */
421
#ifndef FX_SINGLE_THREAD
422
423
#ifndef FX_DONT_CREATE_MUTEX
424
425
    /* Note that the protection is never released. The mutex delete
426
       service will handle all threads waiting access to this media
427
       control block.  */
428
3297
    tx_mutex_delete(& (media_ptr -> fx_media_protect));
429
#endif
430
#endif
431
432
    /* Invoke media close callback. */
433
3297
    if (media_ptr -> fx_media_close_notify)
434
    {
435
1
        media_ptr -> fx_media_close_notify(media_ptr);
436
    }
437
438
#ifdef FX_DONT_CREATE_MUTEX
439
440
    /* Release media protection.  */
441
    FX_UNPROTECT
442
#endif
443
444
    /* Return success status to the caller.  */
445
3297
    return(FX_SUCCESS);
446
}
447