GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_seek.c Lines: 71 71 100.0 %
Date: 2024-03-11 05:15:45 Branches: 30 30 100.0 %

Line Branch Exec Source
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
/**   File                                                                */
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_directory.h"
30
#include "fx_file.h"
31
#include "fx_utility.h"
32
33
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _fx_file_extended_seek                              PORTABLE C      */
39
/*                                                           6.1.7        */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    William E. Lamie, Microsoft Corporation                             */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function positions the internal file pointers to the specified */
47
/*    byte offset such that the next read or write operation will be      */
48
/*    performed there.  If the byte offset is greater than the size, the  */
49
/*    file pointers will be positioned to the end of the file.            */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    file_ptr                              File control block pointer    */
54
/*    byte_offset                           Byte offset into the file     */
55
/*                                                                        */
56
/*  OUTPUT                                                                */
57
/*                                                                        */
58
/*    return status                                                       */
59
/*                                                                        */
60
/*  CALLS                                                                 */
61
/*                                                                        */
62
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    Application Code                                                    */
67
/*                                                                        */
68
/*  RELEASE HISTORY                                                       */
69
/*                                                                        */
70
/*    DATE              NAME                      DESCRIPTION             */
71
/*                                                                        */
72
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
73
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
74
/*                                            resulting in version 6.1    */
75
/*  06-02-2021     Bhupendra Naphade        Modified comment(s), fixed    */
76
/*                                            relative cluster logic,     */
77
/*                                            resulting in version 6.1.7  */
78
/*                                                                        */
79
/**************************************************************************/
80
181
UINT  _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset)
81
{
82
83
UINT      status;
84
ULONG     cluster;
85
181
ULONG     contents = 0;
86
ULONG     bytes_per_cluster;
87
ULONG     last_cluster;
88
ULONG     cluster_count;
89
ULONG64   bytes_remaining;
90
FX_MEDIA *media_ptr;
91
92
93
    /* First, determine if the file is still open.  */
94
181
    if (file_ptr -> fx_file_id != FX_FILE_ID)
95
    {
96
97
        /* Return the file not open error status.  */
98
1
        return(FX_NOT_OPEN);
99
    }
100
101
#ifndef FX_MEDIA_STATISTICS_DISABLE
102
    /* Setup pointer to media structure.  */
103
180
    media_ptr =  file_ptr -> fx_file_media_ptr;
104
105
    /* Increment the number of times this service has been called.  */
106
180
    media_ptr -> fx_media_file_seeks++;
107
#endif
108
109
    /* Setup pointer to associated media control block.  */
110
180
    media_ptr =  file_ptr -> fx_file_media_ptr;
111
112
    /* If trace is enabled, insert this event into the trace buffer.  */
113
    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)
114
115
    /* Protect against other threads accessing the media.  */
116
180
    FX_PROTECT
117
118
    /* Check if we actually have to do anything.  */
119
180
    if (byte_offset == file_ptr -> fx_file_current_file_offset)
120
    {
121
122
        /* Release media protection.  */
123
38
        FX_UNPROTECT
124
125
        /* Seek is complete, return successful status.  */
126
38
        return(FX_SUCCESS);
127
    }
128
129
    /* Calculate the number of bytes per cluster.  */
130
142
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
131
142
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
132
133
    /* Check for invalid value.  */
134
142
    if (bytes_per_cluster == 0)
135
    {
136
137
        /* Release media protection.  */
138
1
        FX_UNPROTECT
139
140
        /* Invalid media, return error.  */
141
1
        return(FX_MEDIA_INVALID);
142
    }
143
144
    /* See if we need to adjust the byte offset.  */
145
141
    if (byte_offset > file_ptr -> fx_file_current_file_size)
146
    {
147
148
        /* Adjust the byte offset down to the file size. */
149
30
        byte_offset =  file_ptr -> fx_file_current_file_size;
150
    }
151
152
    /* Check if the desired position within the leading consecutive clusters.  */
153
141
    if (byte_offset >= (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster)
154
    {
155
156
        /* At this point, we are ready to walk list of clusters to setup the
157
           seek position of this file.  */
158
159
        /* check if byte_offset is greater than where we were left off earlier */
160
90
        if ((ULONG64)file_ptr -> fx_file_current_relative_cluster * (ULONG64)bytes_per_cluster < byte_offset)
161
        {
162
163
62
            cluster =    file_ptr -> fx_file_current_physical_cluster;
164
165
62
            bytes_remaining =   byte_offset -
166
62
                file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
167
168
62
            cluster_count = file_ptr -> fx_file_current_relative_cluster;
169
        }
170
        else
171
        {
172
173
28
            cluster =    file_ptr -> fx_file_first_physical_cluster +
174
28
                (file_ptr -> fx_file_consecutive_cluster - 1);
175
28
            bytes_remaining =   byte_offset -
176
28
                (file_ptr -> fx_file_consecutive_cluster - 1) * bytes_per_cluster;
177
28
            cluster_count =     (file_ptr -> fx_file_consecutive_cluster - 1);
178
        }
179
180
181
        /* Follow the link of FAT entries.  */
182

3455
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
183
        {
184
185
            /* Increment the number of clusters.  */
186
3453
            cluster_count++;
187
188
            /* Read the current cluster entry from the FAT.  */
189
3453
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
190
191
            /* Check the return value.  */
192
3453
            if (status != FX_SUCCESS)
193
            {
194
195
                /* Release media protection.  */
196
1
                FX_UNPROTECT
197
198
                /* Return the error status.  */
199
1
                return(status);
200
            }
201
202
            /* Save the last valid cluster.  */
203
3452
            last_cluster =  cluster;
204
205
            /* Setup for the next cluster.  */
206
3452
            cluster =  contents;
207
208
            /* Determine if this is the last written cluster.  */
209
3452
            if (bytes_remaining > bytes_per_cluster)
210
            {
211
212
                /* Still more seeking, just decrement the working byte offset.  */
213
3365
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
214
            }
215
            else
216
            {
217
218
                /* Remember this cluster number.  */
219
87
                file_ptr -> fx_file_current_physical_cluster =  last_cluster;
220
221
                /* Remember the relative cluster.  */
222
87
                file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
223
224
                /* If the remaining bytes exactly fits the cluster size, check for
225
                   a possible adjustment to the next cluster.  */
226

87
                if ((bytes_remaining == bytes_per_cluster) &&
227
6
                    (cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
228
                {
229
230
                    /* We need to position to next allocated cluster.  */
231
2
                    file_ptr -> fx_file_current_physical_cluster =  cluster;
232
2
                    file_ptr -> fx_file_current_relative_cluster++;
233
234
                    /* Clear the remaining bytes.  */
235
2
                    bytes_remaining =  0;
236
                }
237
238
                /* This is the cluster that contains the seek position.  */
239
87
                break;
240
            }
241
        }
242
243
        /* Check for errors in traversal of the FAT chain.  */
244
89
        if (byte_offset > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
245
        {
246
247
            /* Release media protection.  */
248
2
            FX_UNPROTECT
249
250
            /* This is an error that suggests a corrupt file.  */
251
2
            return(FX_FILE_CORRUPT);
252
        }
253
    }
254
    else
255
    {
256
257
        /* we should directly access the desired cluster */
258
51
        file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster);
259
260
51
        file_ptr -> fx_file_current_physical_cluster =
261
51
            file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
262
263
51
        bytes_remaining =  byte_offset % bytes_per_cluster;
264
    }
265
266
267
    /* Determine if the remaining bytes fit exactly into the cluster size.  */
268
138
    if (bytes_remaining == bytes_per_cluster)
269
    {
270
271
        /* Position to the end of the cluster.  */
272
5
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
273
5
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
274
5
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
275
5
                                                             ((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
276
5
        file_ptr -> fx_file_current_relative_sector =   (UINT)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
277
5
        file_ptr -> fx_file_current_file_offset =       byte_offset;
278
5
        file_ptr -> fx_file_current_logical_offset =    media_ptr -> fx_media_bytes_per_sector;
279
    }
280
    else
281
    {
282
283
        /* Position the pointers to the new offset.  */
284
133
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
285
133
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
286
133
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
287
133
                                                             (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
288
133
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
289
133
        file_ptr -> fx_file_current_file_offset =       byte_offset;
290
133
        file_ptr -> fx_file_current_logical_offset =    (ULONG)(bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector));
291
    }
292
293
    /* Release media protection.  */
294
138
    FX_UNPROTECT
295
296
    /* Seek is complete, return successful status.  */
297
138
    return(FX_SUCCESS);
298
}
299