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