fx_file_extended_seek.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /*************************************************************************** | ||
| 2 | * Copyright (c) 2024 Microsoft Corporation | ||
| 3 | * Copyright (c) 2026-present Eclipse ThreadX contributors | ||
| 4 | * | ||
| 5 | * This program and the accompanying materials are made available under the | ||
| 6 | * terms of the MIT License which is available at | ||
| 7 | * https://opensource.org/licenses/MIT. | ||
| 8 | * | ||
| 9 | * SPDX-License-Identifier: MIT | ||
| 10 | **************************************************************************/ | ||
| 11 | |||
| 12 | |||
| 13 | /**************************************************************************/ | ||
| 14 | /**************************************************************************/ | ||
| 15 | /** */ | ||
| 16 | /** FileX Component */ | ||
| 17 | /** */ | ||
| 18 | /** File */ | ||
| 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_directory.h" | ||
| 31 | #include "fx_file.h" | ||
| 32 | #include "fx_utility.h" | ||
| 33 | |||
| 34 | |||
| 35 | /**************************************************************************/ | ||
| 36 | /* */ | ||
| 37 | /* FUNCTION RELEASE */ | ||
| 38 | /* */ | ||
| 39 | /* _fx_file_extended_seek PORTABLE C */ | ||
| 40 | /* 6.1.7 */ | ||
| 41 | /* AUTHOR */ | ||
| 42 | /* */ | ||
| 43 | /* William E. Lamie, Microsoft Corporation */ | ||
| 44 | /* */ | ||
| 45 | /* DESCRIPTION */ | ||
| 46 | /* */ | ||
| 47 | /* This function positions the internal file pointers to the specified */ | ||
| 48 | /* byte offset such that the next read or write operation will be */ | ||
| 49 | /* performed there. If the byte offset is greater than the size, the */ | ||
| 50 | /* file pointers will be positioned to the end of the file. */ | ||
| 51 | /* */ | ||
| 52 | /* INPUT */ | ||
| 53 | /* */ | ||
| 54 | /* file_ptr File control block pointer */ | ||
| 55 | /* byte_offset Byte offset into the file */ | ||
| 56 | /* */ | ||
| 57 | /* OUTPUT */ | ||
| 58 | /* */ | ||
| 59 | /* return status */ | ||
| 60 | /* */ | ||
| 61 | /* CALLS */ | ||
| 62 | /* */ | ||
| 63 | /* _fx_utility_FAT_entry_read Read a FAT entry */ | ||
| 64 | /* */ | ||
| 65 | /* CALLED BY */ | ||
| 66 | /* */ | ||
| 67 | /* Application Code */ | ||
| 68 | /* */ | ||
| 69 | /**************************************************************************/ | ||
| 70 | 6631622 | UINT _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset) | |
| 71 | { | ||
| 72 | |||
| 73 | UINT status; | ||
| 74 | ULONG cluster; | ||
| 75 | 6631622 | ULONG contents = 0; | |
| 76 | ULONG bytes_per_cluster; | ||
| 77 | ULONG last_cluster; | ||
| 78 | ULONG cluster_count; | ||
| 79 | ULONG64 bytes_remaining; | ||
| 80 | FX_MEDIA *media_ptr; | ||
| 81 | |||
| 82 | |||
| 83 | /* First, determine if the file is still open. */ | ||
| 84 |
2/2✓ Branch 2 → 3 taken 13 times.
✓ Branch 2 → 4 taken 6631609 times.
|
6631622 | if (file_ptr -> fx_file_id != FX_FILE_ID) |
| 85 | { | ||
| 86 | |||
| 87 | /* Return the file not open error status. */ | ||
| 88 | 13 | return(FX_NOT_OPEN); | |
| 89 | } | ||
| 90 | |||
| 91 | #ifndef FX_MEDIA_STATISTICS_DISABLE | ||
| 92 | /* Setup pointer to media structure. */ | ||
| 93 | 6631609 | media_ptr = file_ptr -> fx_file_media_ptr; | |
| 94 | |||
| 95 | /* Increment the number of times this service has been called. */ | ||
| 96 | 6631609 | media_ptr -> fx_media_file_seeks++; | |
| 97 | #endif | ||
| 98 | |||
| 99 | /* Setup pointer to associated media control block. */ | ||
| 100 | 6631609 | media_ptr = file_ptr -> fx_file_media_ptr; | |
| 101 | |||
| 102 | /* If trace is enabled, insert this event into the trace buffer. */ | ||
| 103 | FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_SEEK, file_ptr, byte_offset, file_ptr -> fx_file_current_file_offset, 0, FX_TRACE_FILE_EVENTS, 0, 0) | ||
| 104 | |||
| 105 | /* Protect against other threads accessing the media. */ | ||
| 106 | 5016124 | FX_PROTECT | |
| 107 | |||
| 108 | /* Check if we actually have to do anything. */ | ||
| 109 |
4/4✓ Branch 4 → 5 taken 349 times.
✓ Branch 4 → 6 taken 1615136 times.
✓ Branch 5 → 6 taken 3400847 times.
✓ Branch 5 → 8 taken 1615277 times.
|
6631609 | if (byte_offset == file_ptr -> fx_file_current_file_offset) |
| 110 | { | ||
| 111 | |||
| 112 | /* Release media protection. */ | ||
| 113 | 3400847 | FX_UNPROTECT | |
| 114 | |||
| 115 | /* Seek is complete, return successful status. */ | ||
| 116 | 3401196 | return(FX_SUCCESS); | |
| 117 | } | ||
| 118 | |||
| 119 | /* Calculate the number of bytes per cluster. */ | ||
| 120 | 3230413 | bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) * | |
| 121 | 3230413 | ((ULONG)media_ptr -> fx_media_sectors_per_cluster); | |
| 122 | |||
| 123 | /* Check for invalid value. */ | ||
| 124 |
4/4✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 8 taken 1615132 times.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 11 taken 1615272 times.
|
3230413 | if (bytes_per_cluster == 0) |
| 125 | { | ||
| 126 | |||
| 127 | /* Release media protection. */ | ||
| 128 | 5 | FX_UNPROTECT | |
| 129 | |||
| 130 | /* Invalid media, return error. */ | ||
| 131 | 9 | return(FX_MEDIA_INVALID); | |
| 132 | } | ||
| 133 | |||
| 134 | /* See if we need to adjust the byte offset. */ | ||
| 135 |
4/4✓ Branch 8 → 9 taken 222 times.
✓ Branch 8 → 10 taken 1614910 times.
✓ Branch 11 → 12 taken 252 times.
✓ Branch 11 → 13 taken 1615020 times.
|
3230404 | if (byte_offset > file_ptr -> fx_file_current_file_size) |
| 136 | { | ||
| 137 | |||
| 138 | /* Adjust the byte offset down to the file size. */ | ||
| 139 | 474 | byte_offset = file_ptr -> fx_file_current_file_size; | |
| 140 | } | ||
| 141 | |||
| 142 | /* Check if the desired position within the leading consecutive clusters. */ | ||
| 143 |
4/4✓ Branch 10 → 11 taken 626162 times.
✓ Branch 10 → 29 taken 988970 times.
✓ Branch 13 → 14 taken 625830 times.
✓ Branch 13 → 34 taken 989442 times.
|
3230404 | if (byte_offset >= (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster) |
| 144 | { | ||
| 145 | |||
| 146 | /* At this point, we are ready to walk list of clusters to setup the | ||
| 147 | seek position of this file. */ | ||
| 148 | |||
| 149 | /* check if byte_offset is greater than where we were left off earlier */ | ||
| 150 |
4/4✓ Branch 11 → 12 taken 176834 times.
✓ Branch 11 → 13 taken 449328 times.
✓ Branch 14 → 15 taken 175193 times.
✓ Branch 14 → 16 taken 450637 times.
|
1251992 | if ((ULONG64)file_ptr -> fx_file_current_relative_cluster * (ULONG64)bytes_per_cluster < byte_offset) |
| 151 | { | ||
| 152 | |||
| 153 | 352027 | cluster = file_ptr -> fx_file_current_physical_cluster; | |
| 154 | |||
| 155 | 352027 | bytes_remaining = byte_offset - | |
| 156 | 352027 | file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster; | |
| 157 | |||
| 158 | 352027 | cluster_count = file_ptr -> fx_file_current_relative_cluster; | |
| 159 | } | ||
| 160 | else | ||
| 161 | { | ||
| 162 | |||
| 163 | 899965 | cluster = file_ptr -> fx_file_first_physical_cluster + | |
| 164 | 899965 | (file_ptr -> fx_file_consecutive_cluster - 1); | |
| 165 | 899965 | bytes_remaining = byte_offset - | |
| 166 | 899965 | (file_ptr -> fx_file_consecutive_cluster - 1) * bytes_per_cluster; | |
| 167 | 899965 | cluster_count = (file_ptr -> fx_file_consecutive_cluster - 1); | |
| 168 | } | ||
| 169 | |||
| 170 | |||
| 171 | /* Follow the link of FAT entries. */ | ||
| 172 |
8/8✓ Branch 25 → 26 taken 1615927 times.
✓ Branch 25 → 27 taken 4 times.
✓ Branch 26 → 15 taken 1615923 times.
✓ Branch 26 → 27 taken 4 times.
✓ Branch 29 → 30 taken 1621321 times.
✓ Branch 29 → 31 taken 5 times.
✓ Branch 30 → 18 taken 1621316 times.
✓ Branch 30 → 31 taken 5 times.
|
3237257 | while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved)) |
| 173 | { | ||
| 174 | |||
| 175 | /* Increment the number of clusters. */ | ||
| 176 | 3237239 | cluster_count++; | |
| 177 | |||
| 178 | /* Read the current cluster entry from the FAT. */ | ||
| 179 | 3237239 | status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents); | |
| 180 | |||
| 181 | /* Check the return value. */ | ||
| 182 |
4/4✓ Branch 16 → 17 taken 4 times.
✓ Branch 16 → 18 taken 1615919 times.
✓ Branch 19 → 20 taken 5 times.
✓ Branch 19 → 22 taken 1621311 times.
|
3237239 | if (status != FX_SUCCESS) |
| 183 | { | ||
| 184 | |||
| 185 | /* Release media protection. */ | ||
| 186 | 5 | FX_UNPROTECT | |
| 187 | |||
| 188 | /* Return the error status. */ | ||
| 189 | 9 | return(status); | |
| 190 | } | ||
| 191 | |||
| 192 | /* Save the last valid cluster. */ | ||
| 193 | 3237230 | last_cluster = cluster; | |
| 194 | |||
| 195 | /* Setup for the next cluster. */ | ||
| 196 | 3237230 | cluster = contents; | |
| 197 | |||
| 198 | /* Determine if this is the last written cluster. */ | ||
| 199 |
4/4✓ Branch 18 → 19 taken 989769 times.
✓ Branch 18 → 20 taken 626150 times.
✓ Branch 22 → 23 taken 995496 times.
✓ Branch 22 → 24 taken 625815 times.
|
3237230 | if (bytes_remaining > bytes_per_cluster) |
| 200 | { | ||
| 201 | |||
| 202 | /* Still more seeking, just decrement the working byte offset. */ | ||
| 203 | 1985265 | bytes_remaining = bytes_remaining - bytes_per_cluster; | |
| 204 | } | ||
| 205 | else | ||
| 206 | { | ||
| 207 | |||
| 208 | /* Remember this cluster number. */ | ||
| 209 | 1251965 | file_ptr -> fx_file_current_physical_cluster = last_cluster; | |
| 210 | |||
| 211 | /* Remember the relative cluster. */ | ||
| 212 | 1251965 | file_ptr -> fx_file_current_relative_cluster = cluster_count - 1; | |
| 213 | |||
| 214 | /* If the remaining bytes exactly fits the cluster size, check for | ||
| 215 | a possible adjustment to the next cluster. */ | ||
| 216 |
8/8✓ Branch 20 → 21 taken 219 times.
✓ Branch 20 → 24 taken 625931 times.
✓ Branch 21 → 22 taken 215 times.
✓ Branch 21 → 24 taken 4 times.
✓ Branch 24 → 25 taken 225 times.
✓ Branch 24 → 28 taken 625590 times.
✓ Branch 25 → 26 taken 220 times.
✓ Branch 25 → 28 taken 5 times.
|
1251965 | if ((bytes_remaining == bytes_per_cluster) && |
| 217 |
4/4✓ Branch 22 → 23 taken 197 times.
✓ Branch 22 → 24 taken 18 times.
✓ Branch 26 → 27 taken 198 times.
✓ Branch 26 → 28 taken 22 times.
|
435 | (cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved)) |
| 218 | { | ||
| 219 | |||
| 220 | /* We need to position to next allocated cluster. */ | ||
| 221 | 395 | file_ptr -> fx_file_current_physical_cluster = cluster; | |
| 222 | 395 | file_ptr -> fx_file_current_relative_cluster++; | |
| 223 | |||
| 224 | /* Clear the remaining bytes. */ | ||
| 225 | 395 | bytes_remaining = 0; | |
| 226 | } | ||
| 227 | |||
| 228 | /* This is the cluster that contains the seek position. */ | ||
| 229 | 1251965 | break; | |
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | /* Check for errors in traversal of the FAT chain. */ | ||
| 234 |
4/4✓ Branch 27 → 28 taken 8 times.
✓ Branch 27 → 30 taken 626150 times.
✓ Branch 31 → 32 taken 10 times.
✓ Branch 31 → 35 taken 625815 times.
|
1251983 | if (byte_offset > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count))) |
| 235 | { | ||
| 236 | |||
| 237 | /* Release media protection. */ | ||
| 238 | 10 | FX_UNPROTECT | |
| 239 | |||
| 240 | /* This is an error that suggests a corrupt file. */ | ||
| 241 | 18 | return(FX_FILE_CORRUPT); | |
| 242 | } | ||
| 243 | } | ||
| 244 | else | ||
| 245 | { | ||
| 246 | |||
| 247 | /* we should directly access the desired cluster */ | ||
| 248 | 1978412 | file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster); | |
| 249 | |||
| 250 | 1978412 | file_ptr -> fx_file_current_physical_cluster = | |
| 251 | 1978412 | file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster; | |
| 252 | |||
| 253 | 1978412 | bytes_remaining = byte_offset % bytes_per_cluster; | |
| 254 | } | ||
| 255 | |||
| 256 | |||
| 257 | /* Determine if the remaining bytes fit exactly into the cluster size. */ | ||
| 258 |
4/4✓ Branch 30 → 31 taken 22 times.
✓ Branch 30 → 32 taken 1615098 times.
✓ Branch 35 → 36 taken 27 times.
✓ Branch 35 → 37 taken 1615230 times.
|
3230377 | if (bytes_remaining == bytes_per_cluster) |
| 259 | { | ||
| 260 | |||
| 261 | /* Position to the end of the cluster. */ | ||
| 262 | 49 | file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) + | |
| 263 | 49 | (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) * | |
| 264 | 49 | ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + | |
| 265 | 49 | ((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector)); | |
| 266 | 49 | file_ptr -> fx_file_current_relative_sector = (UINT)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector)); | |
| 267 | 49 | file_ptr -> fx_file_current_file_offset = byte_offset; | |
| 268 | 49 | file_ptr -> fx_file_current_logical_offset = media_ptr -> fx_media_bytes_per_sector; | |
| 269 | } | ||
| 270 | else | ||
| 271 | { | ||
| 272 | |||
| 273 | /* Position the pointers to the new offset. */ | ||
| 274 | 3230328 | file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) + | |
| 275 | 3230328 | (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) * | |
| 276 | 3230328 | ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + | |
| 277 | 3230328 | (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector)); | |
| 278 | 3230328 | file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector)); | |
| 279 | 3230328 | file_ptr -> fx_file_current_file_offset = byte_offset; | |
| 280 | 3230328 | file_ptr -> fx_file_current_logical_offset = (ULONG)(bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector)); | |
| 281 | } | ||
| 282 | |||
| 283 | /* Release media protection. */ | ||
| 284 | 1615257 | FX_UNPROTECT | |
| 285 | |||
| 286 | /* Seek is complete, return successful status. */ | ||
| 287 | 3230377 | return(FX_SUCCESS); | |
| 288 | } | ||
| 289 | |||
| 290 |