GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_seek.c Lines: 71 71 100.0 %
Date: 2026-03-06 18:49:02 Branches: 30 30 100.0 %

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
181
UINT  _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset)
71
{
72
73
UINT      status;
74
ULONG     cluster;
75
181
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
181
    if (file_ptr -> fx_file_id != FX_FILE_ID)
85
    {
86
87
        /* Return the file not open error status.  */
88
1
        return(FX_NOT_OPEN);
89
    }
90
91
#ifndef FX_MEDIA_STATISTICS_DISABLE
92
    /* Setup pointer to media structure.  */
93
180
    media_ptr =  file_ptr -> fx_file_media_ptr;
94
95
    /* Increment the number of times this service has been called.  */
96
180
    media_ptr -> fx_media_file_seeks++;
97
#endif
98
99
    /* Setup pointer to associated media control block.  */
100
180
    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
180
    FX_PROTECT
107
108
    /* Check if we actually have to do anything.  */
109
180
    if (byte_offset == file_ptr -> fx_file_current_file_offset)
110
    {
111
112
        /* Release media protection.  */
113
38
        FX_UNPROTECT
114
115
        /* Seek is complete, return successful status.  */
116
38
        return(FX_SUCCESS);
117
    }
118
119
    /* Calculate the number of bytes per cluster.  */
120
142
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
121
142
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
122
123
    /* Check for invalid value.  */
124
142
    if (bytes_per_cluster == 0)
125
    {
126
127
        /* Release media protection.  */
128
1
        FX_UNPROTECT
129
130
        /* Invalid media, return error.  */
131
1
        return(FX_MEDIA_INVALID);
132
    }
133
134
    /* See if we need to adjust the byte offset.  */
135
141
    if (byte_offset > file_ptr -> fx_file_current_file_size)
136
    {
137
138
        /* Adjust the byte offset down to the file size. */
139
30
        byte_offset =  file_ptr -> fx_file_current_file_size;
140
    }
141
142
    /* Check if the desired position within the leading consecutive clusters.  */
143
141
    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
90
        if ((ULONG64)file_ptr -> fx_file_current_relative_cluster * (ULONG64)bytes_per_cluster < byte_offset)
151
        {
152
153
62
            cluster =    file_ptr -> fx_file_current_physical_cluster;
154
155
62
            bytes_remaining =   byte_offset -
156
62
                file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
157
158
62
            cluster_count = file_ptr -> fx_file_current_relative_cluster;
159
        }
160
        else
161
        {
162
163
28
            cluster =    file_ptr -> fx_file_first_physical_cluster +
164
28
                (file_ptr -> fx_file_consecutive_cluster - 1);
165
28
            bytes_remaining =   byte_offset -
166
28
                (file_ptr -> fx_file_consecutive_cluster - 1) * bytes_per_cluster;
167
28
            cluster_count =     (file_ptr -> fx_file_consecutive_cluster - 1);
168
        }
169
170
171
        /* Follow the link of FAT entries.  */
172

3455
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
173
        {
174
175
            /* Increment the number of clusters.  */
176
3453
            cluster_count++;
177
178
            /* Read the current cluster entry from the FAT.  */
179
3453
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
180
181
            /* Check the return value.  */
182
3453
            if (status != FX_SUCCESS)
183
            {
184
185
                /* Release media protection.  */
186
1
                FX_UNPROTECT
187
188
                /* Return the error status.  */
189
1
                return(status);
190
            }
191
192
            /* Save the last valid cluster.  */
193
3452
            last_cluster =  cluster;
194
195
            /* Setup for the next cluster.  */
196
3452
            cluster =  contents;
197
198
            /* Determine if this is the last written cluster.  */
199
3452
            if (bytes_remaining > bytes_per_cluster)
200
            {
201
202
                /* Still more seeking, just decrement the working byte offset.  */
203
3365
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
204
            }
205
            else
206
            {
207
208
                /* Remember this cluster number.  */
209
87
                file_ptr -> fx_file_current_physical_cluster =  last_cluster;
210
211
                /* Remember the relative cluster.  */
212
87
                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

87
                if ((bytes_remaining == bytes_per_cluster) &&
217
6
                    (cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
218
                {
219
220
                    /* We need to position to next allocated cluster.  */
221
2
                    file_ptr -> fx_file_current_physical_cluster =  cluster;
222
2
                    file_ptr -> fx_file_current_relative_cluster++;
223
224
                    /* Clear the remaining bytes.  */
225
2
                    bytes_remaining =  0;
226
                }
227
228
                /* This is the cluster that contains the seek position.  */
229
87
                break;
230
            }
231
        }
232
233
        /* Check for errors in traversal of the FAT chain.  */
234
89
        if (byte_offset > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
235
        {
236
237
            /* Release media protection.  */
238
2
            FX_UNPROTECT
239
240
            /* This is an error that suggests a corrupt file.  */
241
2
            return(FX_FILE_CORRUPT);
242
        }
243
    }
244
    else
245
    {
246
247
        /* we should directly access the desired cluster */
248
51
        file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster);
249
250
51
        file_ptr -> fx_file_current_physical_cluster =
251
51
            file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
252
253
51
        bytes_remaining =  byte_offset % bytes_per_cluster;
254
    }
255
256
257
    /* Determine if the remaining bytes fit exactly into the cluster size.  */
258
138
    if (bytes_remaining == bytes_per_cluster)
259
    {
260
261
        /* Position to the end of the cluster.  */
262
5
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
263
5
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
264
5
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
265
5
                                                             ((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
266
5
        file_ptr -> fx_file_current_relative_sector =   (UINT)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
267
5
        file_ptr -> fx_file_current_file_offset =       byte_offset;
268
5
        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
133
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
275
133
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
276
133
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
277
133
                                                             (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
278
133
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
279
133
        file_ptr -> fx_file_current_file_offset =       byte_offset;
280
133
        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
138
    FX_UNPROTECT
285
286
    /* Seek is complete, return successful status.  */
287
138
    return(FX_SUCCESS);
288
}
289