GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_extended_seek.c Lines: 71 71 100.0 %
Date: 2024-01-10 21:53:23 Branches: 30 30 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
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
/*  RELEASE HISTORY                                                       */
70
/*                                                                        */
71
/*    DATE              NAME                      DESCRIPTION             */
72
/*                                                                        */
73
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
74
/*  09-30-2020     William E. Lamie         Modified comment(s),          */
75
/*                                            resulting in version 6.1    */
76
/*  06-02-2021     Bhupendra Naphade        Modified comment(s), fixed    */
77
/*                                            relative cluster logic,     */
78
/*                                            resulting in version 6.1.7  */
79
/*                                                                        */
80
/**************************************************************************/
81
181
UINT  _fx_file_extended_seek(FX_FILE *file_ptr, ULONG64 byte_offset)
82
{
83
84
UINT      status;
85
ULONG     cluster;
86
181
ULONG     contents = 0;
87
ULONG     bytes_per_cluster;
88
ULONG     last_cluster;
89
ULONG     cluster_count;
90
ULONG64   bytes_remaining;
91
FX_MEDIA *media_ptr;
92
93
94
    /* First, determine if the file is still open.  */
95
181
    if (file_ptr -> fx_file_id != FX_FILE_ID)
96
    {
97
98
        /* Return the file not open error status.  */
99
1
        return(FX_NOT_OPEN);
100
    }
101
102
#ifndef FX_MEDIA_STATISTICS_DISABLE
103
    /* Setup pointer to media structure.  */
104
180
    media_ptr =  file_ptr -> fx_file_media_ptr;
105
106
    /* Increment the number of times this service has been called.  */
107
180
    media_ptr -> fx_media_file_seeks++;
108
#endif
109
110
    /* Setup pointer to associated media control block.  */
111
180
    media_ptr =  file_ptr -> fx_file_media_ptr;
112
113
    /* If trace is enabled, insert this event into the trace buffer.  */
114
    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)
115
116
    /* Protect against other threads accessing the media.  */
117
180
    FX_PROTECT
118
119
    /* Check if we actually have to do anything.  */
120
180
    if (byte_offset == file_ptr -> fx_file_current_file_offset)
121
    {
122
123
        /* Release media protection.  */
124
38
        FX_UNPROTECT
125
126
        /* Seek is complete, return successful status.  */
127
38
        return(FX_SUCCESS);
128
    }
129
130
    /* Calculate the number of bytes per cluster.  */
131
142
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
132
142
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
133
134
    /* Check for invalid value.  */
135
142
    if (bytes_per_cluster == 0)
136
    {
137
138
        /* Release media protection.  */
139
1
        FX_UNPROTECT
140
141
        /* Invalid media, return error.  */
142
1
        return(FX_MEDIA_INVALID);
143
    }
144
145
    /* See if we need to adjust the byte offset.  */
146
141
    if (byte_offset > file_ptr -> fx_file_current_file_size)
147
    {
148
149
        /* Adjust the byte offset down to the file size. */
150
30
        byte_offset =  file_ptr -> fx_file_current_file_size;
151
    }
152
153
    /* Check if the desired position within the leading consecutive clusters.  */
154
141
    if (byte_offset >= (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster)
155
    {
156
#ifdef FX_ENABLE_EXFAT
157
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
158
        {
159
            if (byte_offset == (ULONG64)file_ptr -> fx_file_consecutive_cluster * (ULONG64)bytes_per_cluster)
160
            {
161
                /* If the file bytes exactly fits the cluster size */
162
                bytes_remaining = bytes_per_cluster;
163
164
                file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster - 1);
165
166
                file_ptr -> fx_file_current_physical_cluster =
167
                    file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
168
            }
169
            else
170
            {
171
172
                /* We shouldn't be here if don't using FAT!  */
173
                FX_UNPROTECT
174
175
                return(FX_FILE_CORRUPT);
176
            }
177
        }
178
        else
179
        {
180
#endif /* FX_ENABLE_EXFAT */
181
182
            /* At this point, we are ready to walk list of clusters to setup the
183
               seek position of this file.  */
184
185
            /* check if byte_offset is greater than where we were left off earlier */
186
90
            if ((ULONG64)file_ptr -> fx_file_current_relative_cluster * (ULONG64)bytes_per_cluster < byte_offset)
187
            {
188
189
62
                cluster =    file_ptr -> fx_file_current_physical_cluster;
190
191
62
                bytes_remaining =   byte_offset -
192
62
                    file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
193
194
62
                cluster_count = file_ptr -> fx_file_current_relative_cluster;
195
            }
196
            else
197
            {
198
199
28
                cluster =    file_ptr -> fx_file_first_physical_cluster +
200
28
                    (file_ptr -> fx_file_consecutive_cluster - 1);
201
28
                bytes_remaining =   byte_offset -
202
28
                    (file_ptr -> fx_file_consecutive_cluster - 1) * bytes_per_cluster;
203
28
                cluster_count =     (file_ptr -> fx_file_consecutive_cluster - 1);
204
            }
205
206
207
            /* Follow the link of FAT entries.  */
208

3455
            while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
209
            {
210
211
                /* Increment the number of clusters.  */
212
3453
                cluster_count++;
213
214
                /* Read the current cluster entry from the FAT.  */
215
3453
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
216
217
                /* Check the return value.  */
218
3453
                if (status != FX_SUCCESS)
219
                {
220
221
                    /* Release media protection.  */
222
1
                    FX_UNPROTECT
223
224
                    /* Return the error status.  */
225
1
                    return(status);
226
                }
227
228
                /* Save the last valid cluster.  */
229
3452
                last_cluster =  cluster;
230
231
                /* Setup for the next cluster.  */
232
3452
                cluster =  contents;
233
234
                /* Determine if this is the last written cluster.  */
235
3452
                if (bytes_remaining > bytes_per_cluster)
236
                {
237
238
                    /* Still more seeking, just decrement the working byte offset.  */
239
3365
                    bytes_remaining =  bytes_remaining - bytes_per_cluster;
240
                }
241
                else
242
                {
243
244
                    /* Remember this cluster number.  */
245
87
                    file_ptr -> fx_file_current_physical_cluster =  last_cluster;
246
247
                    /* Remember the relative cluster.  */
248
87
                    file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
249
250
                    /* If the remaining bytes exactly fits the cluster size, check for
251
                       a possible adjustment to the next cluster.  */
252

87
                    if ((bytes_remaining == bytes_per_cluster) &&
253
6
                        (cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
254
                    {
255
256
                        /* We need to position to next allocated cluster.  */
257
2
                        file_ptr -> fx_file_current_physical_cluster =  cluster;
258
2
                        file_ptr -> fx_file_current_relative_cluster++;
259
260
                        /* Clear the remaining bytes.  */
261
2
                        bytes_remaining =  0;
262
                    }
263
264
                    /* This is the cluster that contains the seek position.  */
265
87
                    break;
266
                }
267
            }
268
269
            /* Check for errors in traversal of the FAT chain.  */
270
89
            if (byte_offset > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
271
            {
272
273
                /* Release media protection.  */
274
2
                FX_UNPROTECT
275
276
                /* This is an error that suggests a corrupt file.  */
277
2
                return(FX_FILE_CORRUPT);
278
            }
279
#ifdef FX_ENABLE_EXFAT
280
        }
281
#endif /* FX_ENABLE_EXFAT */
282
    }
283
    else
284
    {
285
286
        /* we should directly access the desired cluster */
287
51
        file_ptr -> fx_file_current_relative_cluster = (ULONG)(byte_offset / bytes_per_cluster);
288
289
51
        file_ptr -> fx_file_current_physical_cluster =
290
51
            file_ptr -> fx_file_first_physical_cluster + file_ptr -> fx_file_current_relative_cluster;
291
292
51
        bytes_remaining =  byte_offset % bytes_per_cluster;
293
    }
294
295
296
    /* Determine if the remaining bytes fit exactly into the cluster size.  */
297
138
    if (bytes_remaining == bytes_per_cluster)
298
    {
299
300
        /* Position to the end of the cluster.  */
301
5
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
302
5
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
303
5
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
304
5
                                                             ((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
305
5
        file_ptr -> fx_file_current_relative_sector =   (UINT)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
306
5
        file_ptr -> fx_file_current_file_offset =       byte_offset;
307
5
        file_ptr -> fx_file_current_logical_offset =    media_ptr -> fx_media_bytes_per_sector;
308
    }
309
    else
310
    {
311
312
        /* Position the pointers to the new offset.  */
313
133
        file_ptr -> fx_file_current_logical_sector = (ULONG)(((ULONG)media_ptr -> fx_media_data_sector_start) +
314
133
                                                             (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
315
133
                                                              ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
316
133
                                                             (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
317
133
        file_ptr -> fx_file_current_relative_sector =   (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
318
133
        file_ptr -> fx_file_current_file_offset =       byte_offset;
319
133
        file_ptr -> fx_file_current_logical_offset =    (ULONG)(bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector));
320
    }
321
322
    /* Release media protection.  */
323
138
    FX_UNPROTECT
324
325
    /* Seek is complete, return successful status.  */
326
138
    return(FX_SUCCESS);
327
}
328