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 /**   Utility                                                             */
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_utility.h"
30 #ifdef FX_ENABLE_FAULT_TOLERANT
31 #include "fx_fault_tolerant.h"
32 #endif /* FX_ENABLE_FAULT_TOLERANT */
33 
34 
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _fx_utility_FAT_entry_read                          PORTABLE C      */
40 /*                                                           6.2.0        */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    William E. Lamie, Microsoft Corporation                             */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function reads the supplied FAT entry from the first FAT of    */
48 /*    the media.  12-bit, 16-bit, and 32-bit FAT reading is supported.    */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    media_ptr                             Media control block pointer   */
53 /*    cluster                               Cluster entry number          */
54 /*    entry_ptr                             Pointer to destination for    */
55 /*                                            the FAT entry               */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    return status                                                       */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    _fx_utility_16_unsigned_read          Read a UINT from FAT buffer   */
64 /*    _fx_utility_32_unsigned_read          Read a ULONG form FAT buffer  */
65 /*    _fx_utility_FAT_flush                 Flush FAT entry cache         */
66 /*    _fx_utility_logical_sector_read       Read FAT sector into memory   */
67 /*    _fx_fault_tolerant_read_FAT           Read FAT entry from log file  */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    FileX System Functions                                              */
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), and      */
79 /*                                            added conditional to        */
80 /*                                            disable fat entry refresh,  */
81 /*                                            resulting in version 6.1    */
82 /*  10-31-2022     Tiejun Zhou              Modified comment(s), and      */
83 /*                                            fixed compiler warning,     */
84 /*                                            resulting in version 6.2.0  */
85 /*                                                                        */
86 /**************************************************************************/
_fx_utility_FAT_entry_read(FX_MEDIA * media_ptr,ULONG cluster,ULONG * entry_ptr)87 UINT  _fx_utility_FAT_entry_read(FX_MEDIA *media_ptr, ULONG cluster, ULONG *entry_ptr)
88 {
89 
90 ULONG               FAT_sector;
91 ULONG               byte_offset, entry32;
92 UCHAR              *FAT_ptr;
93 UINT                entry, index;
94 UINT                status;
95 FX_FAT_CACHE_ENTRY *cache_entry_ptr;
96 #ifndef FX_DISABLE_FAT_ENTRY_REFRESH
97 FX_FAT_CACHE_ENTRY  temp_cache_entry;
98 #endif /* FX_DISABLE_FAT_ENTRY_REFRESH */
99 
100 
101 #ifdef FX_ENABLE_FAULT_TOLERANT
102     if (media_ptr -> fx_media_fault_tolerant_enabled &&
103         (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
104     {
105 
106         /* Redirect this request to log file. */
107         status = _fx_fault_tolerant_read_FAT(media_ptr, cluster, entry_ptr, FX_FAULT_TOLERANT_FAT_LOG_TYPE);
108 
109         /* Return on success. */
110         if (status != FX_READ_CONTINUE)
111         {
112             return(status);
113         }
114     }
115 #endif /* FX_ENABLE_FAULT_TOLERANT */
116 
117 #ifndef FX_MEDIA_STATISTICS_DISABLE
118 /* Increment the number of FAT entry reads and cache hits.  */
119 media_ptr -> fx_media_fat_entry_reads++;
120 media_ptr -> fx_media_fat_entry_cache_read_hits++;
121 #endif
122 
123 /* Extended port-specific processing macro, which is by default defined to white space.  */
124 FX_UTILITY_FAT_ENTRY_READ_EXTENSION
125 
126 /* Calculate the area of the cache for this FAT entry.  */
127     index =  (cluster & FX_FAT_CACHE_HASH_MASK) * FX_FAT_CACHE_DEPTH;
128 
129     /* Build a pointer to the cache entry.  */
130     cache_entry_ptr =  &media_ptr -> fx_media_fat_cache[index];
131 
132 #ifndef FX_DISABLE_FAT_ENTRY_REFRESH
133     /* Determine if the FAT entry is in the cache - assuming the depth of the FAT cache is
134        4 entries.  */
135     if ((cache_entry_ptr -> fx_fat_cache_entry_cluster) == cluster)
136     {
137 
138         /* Yes, return the cached value.  */
139         *entry_ptr =  cache_entry_ptr -> fx_fat_cache_entry_value;
140 
141         /* Don't move anything since we found the entry.  */
142 
143         /* Return a successful status.  */
144         return(FX_SUCCESS);
145     }
146     else if (((cache_entry_ptr + 1) -> fx_fat_cache_entry_cluster) == cluster)
147     {
148 
149         /* Yes, return the cached value.  */
150         *entry_ptr =  (cache_entry_ptr + 1) -> fx_fat_cache_entry_value;
151 
152         /* Just swap the first and second entry.  */
153         temp_cache_entry =        *(cache_entry_ptr);
154         *(cache_entry_ptr) =      *(cache_entry_ptr + 1);
155         *(cache_entry_ptr + 1) =  temp_cache_entry;
156 
157         /* Return a successful status.  */
158         return(FX_SUCCESS);
159     }
160     else if (((cache_entry_ptr + 2) -> fx_fat_cache_entry_cluster) == cluster)
161     {
162 
163         /* Yes, return the cached value.  */
164         *entry_ptr =  (cache_entry_ptr + 2) -> fx_fat_cache_entry_value;
165 
166         /* Move the third entry to the top and the first two entries down.  */
167         temp_cache_entry =        *(cache_entry_ptr);
168         *(cache_entry_ptr) =      *(cache_entry_ptr + 2);
169         *(cache_entry_ptr + 2) =  *(cache_entry_ptr + 1);
170         *(cache_entry_ptr + 1) =  temp_cache_entry;
171 
172         /* Return a successful status.  */
173         return(FX_SUCCESS);
174     }
175     else if (((cache_entry_ptr + 3) -> fx_fat_cache_entry_cluster) == cluster)
176     {
177 
178         /* Yes, return the cached value.  */
179         *entry_ptr =  (cache_entry_ptr + 3) -> fx_fat_cache_entry_value;
180 
181         /* Move the last entry to the top and the first three entries down.  */
182         temp_cache_entry =        *(cache_entry_ptr);
183         *(cache_entry_ptr) =      *(cache_entry_ptr + 3);
184         *(cache_entry_ptr + 3) =  *(cache_entry_ptr + 2);
185         *(cache_entry_ptr + 2) =  *(cache_entry_ptr + 1);
186         *(cache_entry_ptr + 1) =  temp_cache_entry;
187 
188         /* Return a successful status.  */
189         return(FX_SUCCESS);
190     }
191 #else
192 for(UINT i = 0; i < 4; i++)
193     {
194         if (((cache_entry_ptr + i) -> fx_fat_cache_entry_cluster) == cluster)
195         {
196             *entry_ptr =  (cache_entry_ptr + i) -> fx_fat_cache_entry_value;
197 
198             /* Return a successful status.  */
199             return(FX_SUCCESS);
200         }
201     }
202 #endif /* FX_DISABLE_FAT_ENTRY_REFRESH */
203 
204     /* Determine if the oldest entry was modified, i.e. whether or not it is
205        dirty.  */
206     if (media_ptr -> fx_media_fat_cache[index + 3].fx_fat_cache_entry_dirty)
207     {
208 
209         /* Yes, the entry is dirty and needs to be flushed out.  */
210         status = _fx_utility_FAT_flush(media_ptr);
211 
212         /* Check for completion status.  */
213         if (status != FX_SUCCESS)
214         {
215 
216             /* Return error status.  */
217             return(status);
218         }
219     }
220 
221     /* If we get here, the entry was not found in the FAT entry cache.  We need to
222        actually read the FAT entry.  */
223 
224 #ifndef FX_MEDIA_STATISTICS_DISABLE
225 
226     /* Decrement the number of cache hits.  */
227     media_ptr -> fx_media_fat_entry_cache_read_hits--;
228 
229     /* Increment the number of cache misses.  */
230     media_ptr -> fx_media_fat_entry_cache_read_misses++;
231 #endif
232 
233     /* Determine which type of FAT is present.  */
234     if (media_ptr -> fx_media_12_bit_FAT)
235     {
236 
237         /* Calculate the byte offset to the cluster entry.  */
238         byte_offset =  (((ULONG)cluster << 1) + cluster) >> 1;
239 
240         /* Calculate the FAT sector the requested FAT entry resides in.  */
241         FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
242             (ULONG)media_ptr -> fx_media_reserved_sectors;
243 
244         /* Read the sector in.  */
245         status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
246                                                   media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
247 
248         /* Determine if an error occurred.  */
249         if (status != FX_SUCCESS)
250         {
251             /* Return the error status.  */
252             return(status);
253         }
254 
255         /* Now calculate the byte offset into this FAT sector.  */
256         byte_offset =  byte_offset -
257             ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
258              media_ptr -> fx_media_bytes_per_sector);
259 
260         /* Setup a pointer into the buffer.  */
261         FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
262 
263         /* Determine if the cluster entry is odd or even.  */
264         if (cluster & 1)
265         {
266 
267             /* Odd cluster number.  */
268 
269             /* Pickup the lower nibble of the FAT entry.  */
270             entry =  (((UINT)*FAT_ptr) & 0xF0) >> 4;
271 
272             /* Move to the next byte of the FAT entry.  */
273             FAT_ptr++;
274 
275             /* Determine if we are now past the end of the FAT buffer in memory.  */
276             if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
277             {
278 
279                 /* Yes, we need to read the next sector.  */
280                 FAT_sector++;
281                 status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
282                                                           media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
283 
284                 /* Determine if an error occurred.  */
285                 if (status != FX_SUCCESS)
286                 {
287 
288                     /* Return the error status.  */
289                     return(status);
290                 }
291 
292                 /* Setup a pointer into the buffer.  */
293                 FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer;
294             }
295 
296             /* Pickup the upper 8 bits of the FAT entry.  */
297             entry =  entry | (((UINT)*FAT_ptr) << 4);
298         }
299         else
300         {
301 
302             /* Even cluster number.  */
303 
304             /* Pickup the lower byte of the FAT entry.  */
305             entry =  (UINT)(((UINT)*FAT_ptr) & 0xFF);
306 
307             /* Move to the next nibble of the FAT entry.  */
308             FAT_ptr++;
309 
310             /* Determine if we are now past the end of the FAT buffer in memory.  */
311             if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
312             {
313 
314                 /* Yes, we need to read the next sector.  */
315                 FAT_sector++;
316                 status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
317                                                           media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
318 
319                 /* Determine if an error occurred.  */
320                 if (status != FX_SUCCESS)
321                 {
322                     return(status);
323                 }
324 
325                 /* Setup a pointer into the buffer.  */
326                 FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer;
327             }
328 
329             /* Pickup the upper 4 bits of the FAT entry.  */
330             entry =  entry | ((((UINT)*FAT_ptr) & 0x0F) << 8);
331         }
332 
333         /* Determine if we need to do sign extension on the 12-bit eof value.  */
334         if (entry >= FX_MAX_12BIT_CLUST)
335         {
336 
337             /* Yes, we need to sign extend.  */
338             entry =  entry | FX_SIGN_EXTEND;
339         }
340 
341         *entry_ptr =  entry;
342     }
343 
344     /* Check for a 16-bit FAT.  */
345     else if (!media_ptr -> fx_media_32_bit_FAT)
346     {
347 
348         /* 16-bit FAT is present.  */
349 
350         /* Calculate the byte offset to the cluster entry.  */
351         byte_offset =  (((ULONG)cluster) * 2);
352 
353         /* Calculate the FAT sector the requested FAT entry resides in.  */
354         FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
355             (ULONG)media_ptr -> fx_media_reserved_sectors;
356 
357         /* Read the FAT sector.  */
358         status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
359                                                   media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
360 
361         /* Determine if an error occurred.  */
362         if (status != FX_SUCCESS)
363         {
364 
365             /* Return the error code.  */
366             return(status);
367         }
368 
369         /* Now calculate the byte offset into this FAT sector.  */
370         byte_offset =  byte_offset -
371             ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
372              media_ptr -> fx_media_bytes_per_sector);
373 
374         /* Setup a pointer into the buffer.  */
375         FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
376 
377         /* Pickup the FAT entry.  */
378         entry =  _fx_utility_16_unsigned_read(FAT_ptr);
379 
380         *entry_ptr =  entry;
381     }
382     else
383     {
384 
385         /* Otherwise, a 32 bit FAT present.  */
386         byte_offset =  (((ULONG)cluster) * 4);
387 
388         /* Calculate the FAT sector the requested FAT entry resides in.  */
389         FAT_sector =  (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
390             (ULONG)media_ptr -> fx_media_reserved_sectors;
391 
392         /* Calculate the byte offset to the FAT entry.  */
393         byte_offset = (byte_offset % media_ptr -> fx_media_bytes_per_sector);
394 
395         /* Read the appropriate FAT sector.  */
396         status =  _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
397                                                   media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
398 
399         /* Determine if an error occurred.  */
400         if (status != FX_SUCCESS)
401         {
402 
403             /* Return the error code.  */
404             return(status);
405         }
406 
407         /* Setup a pointer into the buffer.  */
408         FAT_ptr =  (UCHAR *)media_ptr -> fx_media_memory_buffer + (ULONG)byte_offset;
409 
410         /* Pickup the FAT entry.  */
411         entry32 =  _fx_utility_32_unsigned_read(FAT_ptr);
412 
413 
414         /* Clear upper nibble.  */
415         entry32 = entry32 & 0x0FFFFFFF;
416 
417         *entry_ptr =  entry32;
418     }
419 
420     /* Move all the cache entries down so the oldest is at the bottom.  */
421     *(cache_entry_ptr + 3) =  *(cache_entry_ptr + 2);
422     *(cache_entry_ptr + 2) =  *(cache_entry_ptr + 1);
423     *(cache_entry_ptr + 1) =  *(cache_entry_ptr);
424 
425     /* Setup the new FAT entry in the cache.  */
426     cache_entry_ptr -> fx_fat_cache_entry_cluster =  cluster;
427     cache_entry_ptr -> fx_fat_cache_entry_value   =  *entry_ptr;
428 
429     /* Return success to the caller.  */
430     return(FX_SUCCESS);
431 }
432 
433