GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_read.c Lines: 109 109 100.0 %
Date: 2026-03-06 18:49:02 Branches: 52 52 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_file.h"
31
#include "fx_utility.h"
32
33
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _fx_file_read                                       PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    William E. Lamie, Microsoft Corporation                             */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function reads the specified number of bytes (or as many as    */
47
/*    possible into the buffer supplied by the caller.  The actual number */
48
/*    of bytes and the status of the read operation is returned to the    */
49
/*    caller.  In addition, various internal file pointers in the file    */
50
/*    control block are also updated.                                     */
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    file_ptr                              File control block pointer    */
55
/*    buffer_ptr                            Buffer pointer                */
56
/*    request_size                          Number of bytes requested     */
57
/*    actual_size                           Pointer to variable for the   */
58
/*                                            number of bytes read        */
59
/*                                                                        */
60
/*  OUTPUT                                                                */
61
/*                                                                        */
62
/*    return status                                                       */
63
/*                                                                        */
64
/*  CALLS                                                                 */
65
/*                                                                        */
66
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
67
/*    _fx_utility_logical_sector_read       Read a logical sector         */
68
/*    _fx_utility_memory_copy               Fast memory copy routine      */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    Application Code                                                    */
73
/*                                                                        */
74
/**************************************************************************/
75
178683
UINT  _fx_file_read(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG request_size, ULONG *actual_size)
76
{
77
78
UINT                   status;
79
ULONG                  bytes_remaining, i;
80
ULONG                  copy_bytes;
81
UCHAR                 *destination_ptr;
82
ULONG                  cluster, next_cluster;
83
UINT                   sectors;
84
FX_MEDIA              *media_ptr;
85
86
#ifdef TX_ENABLE_EVENT_TRACE
87
TX_TRACE_BUFFER_ENTRY *trace_event;
88
ULONG                  trace_timestamp;
89
#endif
90
91
92
    /* First, determine if the file is still open.  */
93
178683
    if (file_ptr -> fx_file_id != FX_FILE_ID)
94
    {
95
96
        /* Return the file not open error status.  */
97
1
        return(FX_NOT_OPEN);
98
    }
99
100
#ifndef FX_MEDIA_STATISTICS_DISABLE
101
    /* Setup pointer to media structure.  */
102
178682
    media_ptr =  file_ptr -> fx_file_media_ptr;
103
104
    /* Increment the number of times this service has been called.  */
105
178682
    media_ptr -> fx_media_file_reads++;
106
#endif
107
108
    /* Setup pointer to associated media control block.  */
109
178682
    media_ptr =  file_ptr -> fx_file_media_ptr;
110
111
    /* If trace is enabled, insert this event into the trace buffer.  */
112
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_READ, file_ptr, buffer_ptr, request_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
113
114
    /* Protect against other threads accessing the media.  */
115
178682
    FX_PROTECT
116
117
    /* Next, determine if there is any more bytes to read in the file.  */
118
178682
    if (file_ptr -> fx_file_current_file_offset >=
119
178682
        file_ptr -> fx_file_current_file_size)
120
    {
121
122
        /* Release media protection.  */
123
13
        FX_UNPROTECT
124
125
        /* The file is at the end, return the proper status and set the
126
           actual size to 0.  */
127
13
        *actual_size =  0;
128
13
        return(FX_END_OF_FILE);
129
    }
130
131
    /* At this point there is something to read.  */
132
133
    /* Setup local buffer pointer.  */
134
178669
    destination_ptr =  (UCHAR *)buffer_ptr;
135
136
    /* Determine if there are less bytes left in the file than that specified
137
       by the request.  If so, adjust the requested size.  */
138
178669
    if ((ULONG64)request_size >
139
178669
        (file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset))
140
    {
141
142
        /* Adjust the bytes remaining to what's available.  */
143
14
        request_size =  (ULONG)(file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset);
144
    }
145
146
    /* Setup the remaining number of bytes to read.  */
147
178669
    bytes_remaining =  request_size;
148
149
    /* Loop to read all of the bytes.  */
150
310134
    while (bytes_remaining)
151
    {
152
153
        /* Determine if a beginning or ending partial read is required.  */
154
201774
        if ((file_ptr -> fx_file_current_logical_offset) ||
155
35408
            (bytes_remaining < media_ptr -> fx_media_bytes_per_sector))
156
        {
157
158
            /* A partial sector read is required.  */
159
160
            /* Read the current logical sector.  */
161
171332
            status =  _fx_utility_logical_sector_read(media_ptr,
162
                                                      file_ptr -> fx_file_current_logical_sector,
163
171332
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
164
165
            /* Check for good completion status.  */
166
171332
            if (status !=  FX_SUCCESS)
167
            {
168
169
                /* Release media protection.  */
170
23211
                FX_UNPROTECT
171
172
                /* Return the error status.  */
173
23211
                return(status);
174
            }
175
176
            /* Copy the appropriate number of bytes into the destination buffer.  */
177
148121
            copy_bytes =  media_ptr -> fx_media_bytes_per_sector -
178
148121
                file_ptr -> fx_file_current_logical_offset;
179
180
            /* Check to see if only a portion of the read sector needs to be
181
               copied.  */
182
148121
            if (copy_bytes > bytes_remaining)
183
            {
184
185
                /* Adjust the number of bytes to copy.  */
186
97440
                copy_bytes =  bytes_remaining;
187
            }
188
189
            /* Actually perform the memory copy.  */
190
148121
            _fx_utility_memory_copy(((UCHAR *)media_ptr -> fx_media_memory_buffer) + /* Use case of memcpy is verified. */
191
148121
                                    file_ptr -> fx_file_current_logical_offset,
192
                                    destination_ptr, copy_bytes);
193
194
            /* Increment the logical sector byte offset.  */
195
148121
            file_ptr -> fx_file_current_logical_offset =
196
148121
                file_ptr -> fx_file_current_logical_offset + copy_bytes;
197
198
            /* Adjust the remaining bytes to read.  */
199
148121
            bytes_remaining =  bytes_remaining - copy_bytes;
200
201
            /* Adjust the pointer to the destination buffer.  */
202
148121
            destination_ptr =  destination_ptr + copy_bytes;
203
        }
204
        else
205
        {
206
207
            /* Attempt to read multiple sectors directly into the destination
208
               buffer.  */
209
210
            /* Calculate the number of whole sectors to read directly into
211
               the destination buffer.  */
212
30442
            sectors =  (UINT)(bytes_remaining / media_ptr -> fx_media_bytes_per_sector);
213
214
215
30442
            next_cluster = cluster = file_ptr -> fx_file_current_physical_cluster;
216
30442
            for (i = (media_ptr -> fx_media_sectors_per_cluster -
217
31210
                      file_ptr -> fx_file_current_relative_sector); i < sectors; i += media_ptr -> fx_media_sectors_per_cluster)
218
            {
219
1515
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
220
221
                /* Determine if an error is present.  */
222

1515
                if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
223
1513
                    (next_cluster > media_ptr -> fx_media_fat_reserved))
224
                {
225
226
                    /* Release media protection.  */
227
3
                    FX_UNPROTECT
228
229
                    /* Send error message back to caller.  */
230
3
                    if (status != FX_SUCCESS)
231
                    {
232
1
                        return(status);
233
                    }
234
                    else
235
                    {
236
2
                        return(FX_FILE_CORRUPT);
237
                    }
238
                }
239
240
1512
                if (next_cluster != cluster + 1)
241
                {
242
744
                    break;
243
                }
244
                else
245
                {
246
768
                    cluster = next_cluster;
247
                }
248
            }
249
250
30439
            if (i < sectors)
251
            {
252
744
                sectors = i;
253
            }
254
255
            /* Determine if this is a single sector read request.  If so, read the sector so it will
256
               come from the internal cache.  */
257
30439
            if (sectors == 1)
258
            {
259
260
                /* Read the current logical sector.  */
261
29188
                status =  _fx_utility_logical_sector_read(media_ptr,
262
                                                          file_ptr -> fx_file_current_logical_sector,
263
29188
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
264
265
                /* Check for good completion status.  */
266
29188
                if (status !=  FX_SUCCESS)
267
                {
268
269
                    /* Release media protection.  */
270
1054
                    FX_UNPROTECT
271
272
                    /* Return the error status.  */
273
1054
                    return(status);
274
                }
275
276
                /* Actually perform the memory copy.  */
277
28134
                _fx_utility_memory_copy((UCHAR *)media_ptr -> fx_media_memory_buffer, destination_ptr, media_ptr -> fx_media_bytes_per_sector); /* Use case of memcpy is verified. */
278
            }
279
            else
280
            {
281
282
                /* Multiple sector read request.  Read all the sectors at once.  */
283
284
                /* Perform the data read directly into the user's buffer of
285
                   the appropriate number of sectors.  */
286
1251
                media_ptr -> fx_media_disable_burst_cache = file_ptr -> fx_file_disable_burst_cache;
287
1251
                status =  _fx_utility_logical_sector_read(media_ptr, file_ptr -> fx_file_current_logical_sector,
288
                                                          destination_ptr, (ULONG) sectors, FX_DATA_SECTOR);
289
1251
                media_ptr -> fx_media_disable_burst_cache = FX_FALSE;
290
291
                /* Check for good completion status.  */
292
1251
                if (status !=  FX_SUCCESS)
293
                {
294
295
                    /* Release media protection.  */
296
1
                    FX_UNPROTECT
297
298
                    /* Return the error status.  */
299
1
                    return(status);
300
                }
301
            }
302
303
            /* Now adjust the various file pointers.  */
304
305
            /* Increment the current logical sector.  Subtract one from
306
               the sector count because we are going to use the logical
307
               offset to do additional sector/cluster arithmetic below.  */
308
29384
            file_ptr -> fx_file_current_logical_sector =
309
29384
                file_ptr -> fx_file_current_logical_sector +
310
29384
                (sectors - 1);
311
312
            /* Move the relative sector and cluster as well.  */
313
29384
            file_ptr -> fx_file_current_relative_cluster = file_ptr -> fx_file_current_relative_cluster +
314
29384
                (file_ptr -> fx_file_current_relative_sector + (sectors - 1)) /
315
29384
                media_ptr -> fx_media_sectors_per_cluster;
316
317
29384
            file_ptr -> fx_file_current_relative_sector =
318
29384
                (file_ptr -> fx_file_current_relative_sector +
319
29384
                 (sectors - 1)) % media_ptr -> fx_media_sectors_per_cluster;
320
321
            /* Increment the logical sector byte offset.  */
322
29384
            file_ptr -> fx_file_current_logical_offset =
323
29384
                media_ptr -> fx_media_bytes_per_sector;
324
325
29384
            file_ptr -> fx_file_current_physical_cluster = cluster;
326
327
            /* Adjust the remaining bytes.  */
328
29384
            bytes_remaining =  bytes_remaining -
329
29384
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
330
331
            /* Adjust the pointer to the destination buffer.  */
332
29384
            destination_ptr =  destination_ptr +
333
29384
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
334
        }
335
336
        /* At this point, we have either read a partial sector or have successfully
337
           read one or more whole sectors.  Determine if we are at the end of
338
           the current logical sector.  */
339
177505
        if (file_ptr -> fx_file_current_logical_offset >=
340
177505
            media_ptr -> fx_media_bytes_per_sector)
341
        {
342
343
            /* Determine if we are at the exact physical end of the file at the end of reading.  */
344
80065
            if ((bytes_remaining == 0) && ((file_ptr -> fx_file_current_file_offset + (ULONG64)request_size) >=
345
32390
                                           file_ptr -> fx_file_current_available_size))
346
            {
347
348
                /* Skip the following file parameter adjustments.  The next write will
349
                   detect the logical offset out of the range of the sector and reset
350
                   all of the pertinent information.  */
351
17802
                break;
352
            }
353
354
            /* We need to move to the next logical sector, but first
355
               determine if the next logical sector is within the same
356
               cluster.  */
357
358
            /* Increment the current relative sector in the cluster.  */
359
62263
            file_ptr -> fx_file_current_relative_sector++;
360
361
            /* Determine if this is in a new cluster.  */
362
62263
            if (file_ptr -> fx_file_current_relative_sector >=
363
62263
                media_ptr -> fx_media_sectors_per_cluster)
364
            {
365
366
                /* Read the FAT entry of the current cluster to find
367
                   the next cluster.  */
368
55719
                status =  _fx_utility_FAT_entry_read(media_ptr,
369
                                                     file_ptr -> fx_file_current_physical_cluster, &next_cluster);
370
371
                /* Determine if an error is present.  */
372

55719
                if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
373
51754
                    (next_cluster > media_ptr -> fx_media_fat_reserved))
374
                {
375
376
                    /* Release media protection.  */
377
28238
                    FX_UNPROTECT
378
379
                    /* Send error message back to caller.  */
380
28238
                    if (status != FX_SUCCESS)
381
                    {
382
3964
                        return(status);
383
                    }
384
                    else
385
                    {
386
24274
                        return(FX_FILE_CORRUPT);
387
                    }
388
                }
389
390
                /* Otherwise, we have a new cluster.  Save it in the file
391
                   control block and calculate a new logical sector value.  */
392
27481
                file_ptr -> fx_file_current_physical_cluster =  next_cluster;
393
27481
                file_ptr -> fx_file_current_relative_cluster++;
394
27481
                file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
395
27481
                    ((((ULONG64)next_cluster) - FX_FAT_ENTRY_START) *
396
27481
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
397
27481
                file_ptr -> fx_file_current_relative_sector =  0;
398
            }
399
            else
400
            {
401
402
                /* Still within the same cluster so just increment the
403
                   logical sector.  */
404
6544
                file_ptr -> fx_file_current_logical_sector++;
405
            }
406
407
            /* In either case, we are now positioned at a new sector so
408
               clear the logical sector offset.  */
409
34025
            file_ptr -> fx_file_current_logical_offset =  0;
410
        }
411
    }
412
413
    /* Adjust the current file offset accordingly.  */
414
126162
    file_ptr -> fx_file_current_file_offset =
415
126162
        file_ptr -> fx_file_current_file_offset + (ULONG64)request_size;
416
417
    /* Store the number of bytes actually read.  */
418
126162
    *actual_size =  request_size;
419
420
    /* Update the trace event with the bytes read.  */
421
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_READ, 0, 0, 0, request_size)
422
423
    /* Update the last accessed date.  */
424
126162
    file_ptr -> fx_file_dir_entry.fx_dir_entry_last_accessed_date =  _fx_system_date;
425
426
    /* Release media protection.  */
427
126162
    FX_UNPROTECT
428
429
    /* Return a successful status to the caller.  */
430
126162
    return(FX_SUCCESS);
431
}
432