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 /**   Fault Tolerant                                                      */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define FX_SOURCE_CODE
23 
24 #include "fx_api.h"
25 #include "fx_utility.h"
26 #include "fx_fault_tolerant.h"
27 
28 
29 #ifdef FX_ENABLE_FAULT_TOLERANT
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _fx_fault_tolerant_apply_logs                       PORTABLE C      */
35 /*                                                           6.2.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    William E. Lamie, Microsoft Corporation                             */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function applies changes to the file system.  The changes are  */
43 /*    already recorded in the fault tolerant log file.  Therefore this    */
44 /*    function reads the content of the log entries and apply these       */
45 /*    changes to the file system.                                         */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    media_ptr                             Media control block pointer   */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    return status                                                       */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _fx_utility_logical_sector_write      Write a logical sector        */
58 /*    _fx_utility_logical_sector_read       Read a logical sector         */
59 /*    _fx_utility_16_unsigned_read          Read a USHORT from memory     */
60 /*    _fx_utility_32_unsigned_read          Read a ULONG from memory      */
61 /*    _fx_utility_64_unsigned_read          Read a ULONG64 from memory    */
62 /*    _fx_utility_FAT_entry_write           Write a FAT entry             */
63 /*    _fx_fault_tolerant_cleanup_FAT_chain  Cleanup FAT chain             */
64 /*    memcpy                                Memory Copy                   */
65 /*    _fx_utility_FAT_flush                 Flush written FAT entries     */
66 /*    _fx_utility_logical_sector_flush      Flush written logical sectors */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    _fx_fault_tolerant_enable                                           */
71 /*    _fx_fault_tolerant_transaction_end                                  */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
78 /*  09-30-2020     William E. Lamie         Modified comment(s), verified */
79 /*                                            memcpy usage,               */
80 /*                                            resulting in version 6.1    */
81 /*  10-31-2022     Tiejun Zhou              Modified comment(s), fixed    */
82 /*                                            overflow in log size check, */
83 /*                                            resulting in version 6.2.0  */
84 /*                                                                        */
85 /**************************************************************************/
_fx_fault_tolerant_apply_logs(FX_MEDIA * media_ptr)86 UINT _fx_fault_tolerant_apply_logs(FX_MEDIA *media_ptr)
87 {
88 UINT                           status;
89 ULONG64                        log_sector;
90 ULONG                          remaining_logs;
91 ULONG                          copy_size;
92 ULONG                          copy_offset;
93 UCHAR                         *current_ptr;
94 ULONG                          size;
95 USHORT                         log_type;
96 ULONG                          log_len;
97 FX_FAULT_TOLERANT_LOG_HEADER  *log_header;
98 FX_FAULT_TOLERANT_FAT_CHAIN   *FAT_chain;
99 FX_FAULT_TOLERANT_LOG_CONTENT *log_content;
100 FX_FAULT_TOLERANT_FAT_LOG     *fat_log;
101 FX_FAULT_TOLERANT_DIR_LOG     *dir_log;
102 
103     /* Set log header, FAT chain and log content pointer. */
104     log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
105     FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
106     log_content = (FX_FAULT_TOLERANT_LOG_CONTENT *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
107                                                     FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET);
108 
109     /* Find the size of the log file. */
110     size = _fx_utility_16_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size);
111 
112     /* Extended port-specific processing macro, which is by default defined to white space.  */
113     FX_FAULT_TOLERANT_APPLY_LOGS_EXTENSION
114 
115     size -= FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
116 
117     /* Find the number of log entries. */
118     remaining_logs = _fx_utility_16_unsigned_read((UCHAR *)&log_content -> fx_fault_tolerant_log_content_count);
119 
120     /* Get start address of logs. */
121     current_ptr = (UCHAR *)log_content + FX_FAULT_TOLERANT_LOG_CONTENT_HEADER_SIZE;
122 
123     /* Loop through all the logs to apply the changes. */
124     while (remaining_logs)
125     {
126 
127         /* Obtain log type of this entry. */
128         log_type = (USHORT)_fx_utility_16_unsigned_read(current_ptr);
129 
130         /* Read log length.  */
131         log_len = _fx_utility_16_unsigned_read(current_ptr + 2);
132 
133 
134         /* Validate log entry size. */
135         if (log_len > size)
136         {
137 
138             /* Something wrong with log file. */
139             return(FX_FILE_CORRUPT);
140         }
141 
142         /* Reduce the total log file size. */
143         size -= log_len;
144 
145         /* Process log entry by type. */
146         switch (log_type)
147         {
148         case FX_FAULT_TOLERANT_FAT_LOG_TYPE:
149 
150             /* This is a FAT log. */
151             fat_log = (FX_FAULT_TOLERANT_FAT_LOG *)current_ptr;
152 
153             /* Write FAT entry. */
154             status = _fx_utility_FAT_entry_write(media_ptr,
155                                                  _fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_cluster),
156                                                  _fx_utility_32_unsigned_read((UCHAR *)&fat_log -> fx_fault_tolerant_FAT_log_value));
157 
158             if (status != FX_SUCCESS)
159             {
160 
161                 /* Return the error status.  */
162                 return(status);
163             }
164             break;
165 
166         case FX_FAULT_TOLERANT_DIR_LOG_TYPE:
167 
168             /* This is a DIR log. */
169             dir_log = (FX_FAULT_TOLERANT_DIR_LOG *)current_ptr;
170 
171             log_sector = _fx_utility_64_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_sector);
172 
173             /* Get the destination sector. */
174             status =  _fx_utility_logical_sector_read(media_ptr,
175                                                       log_sector,
176                                                       media_ptr -> fx_media_memory_buffer,
177                                                       ((ULONG) 1), FX_DATA_SECTOR);
178 
179             if (status != FX_SUCCESS)
180             {
181 
182                 /* Return the error status.  */
183                 return(status);
184             }
185 
186             /* Set copy information. */
187             copy_offset = _fx_utility_32_unsigned_read((UCHAR *)&dir_log -> fx_fault_tolerant_dir_log_offset);
188 
189 
190             copy_size = log_len - FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE;
191 
192             if (((ULONG64)copy_offset + (ULONG64)copy_size) > (ULONG64)(media_ptr -> fx_media_memory_size))
193             {
194                 return(FX_FILE_CORRUPT);
195             }
196 
197             /* Copy data into destination sector. */
198             memcpy(media_ptr -> fx_media_memory_buffer + copy_offset, /* Use case of memcpy is verified. */
199                    current_ptr + FX_FAULT_TOLERANT_DIR_LOG_ENTRY_SIZE, copy_size);
200 
201 
202             /* Write back the current logical sector.  */
203             status = _fx_utility_logical_sector_write(media_ptr,
204                                                       log_sector,
205                                                       media_ptr -> fx_media_memory_buffer,
206                                                       ((ULONG) 1), FX_DIRECTORY_SECTOR);
207 
208             if (status != FX_SUCCESS)
209             {
210 
211                 /* Return the error status.  */
212                 return(status);
213             }
214             break;
215 
216         default:
217 
218             /* Wrong type.  */
219             return(FX_SECTOR_INVALID);
220         }
221 
222         /* Decrement the remaining log counter.  */
223         remaining_logs--;
224 
225         /* Move to start position of next log entry. */
226         current_ptr += log_len;
227     }
228 
229     /* Check whether or not to process FAT chain. */
230     if (FAT_chain -> fx_fault_tolerant_FAT_chain_flag & FX_FAULT_TOLERANT_FLAG_FAT_CHAIN_VALID)
231     {
232 
233         /* Free old link of FAT. */
234         status = _fx_fault_tolerant_cleanup_FAT_chain(media_ptr, FX_FAULT_TOLERANT_FAT_CHAIN_CLEANUP);
235         if (status != FX_SUCCESS)
236         {
237 
238             /* Return the error status.  */
239             return(status);
240         }
241     }
242 
243     /* Flush the internal logical sector cache.  */
244     status =  _fx_utility_logical_sector_flush(media_ptr, 1, (ULONG64) media_ptr -> fx_media_total_sectors, FX_FALSE);
245 
246     /* Check for a bad status.  */
247     if (status != FX_SUCCESS)
248     {
249 
250         /* Return the bad status.  */
251         return(status);
252     }
253 
254     /* Flush FAT table. */
255 #ifdef FX_FAULT_TOLERANT
256 
257     /* Ensure the new FAT chain is properly written to the media.  */
258 
259     /* Flush the cached individual FAT entries */
260     _fx_utility_FAT_flush(media_ptr);
261 #endif
262 
263     /* Return success. */
264     return(FX_SUCCESS);
265 }
266 #endif /* FX_ENABLE_FAULT_TOLERANT */
267 
268