GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_read.c Lines: 109 109 100.0 %
Date: 2024-01-10 21:53:23 Branches: 52 52 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_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
/*  RELEASE HISTORY                                                       */
75
/*                                                                        */
76
/*    DATE              NAME                      DESCRIPTION             */
77
/*                                                                        */
78
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
79
/*  09-30-2020     William E. Lamie         Modified comment(s), verified */
80
/*                                            memcpy usage,               */
81
/*                                            resulting in version 6.1    */
82
/*                                                                        */
83
/**************************************************************************/
84
178683
UINT  _fx_file_read(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG request_size, ULONG *actual_size)
85
{
86
87
UINT                   status;
88
ULONG                  bytes_remaining, i;
89
ULONG                  copy_bytes;
90
UCHAR                 *destination_ptr;
91
ULONG                  cluster, next_cluster;
92
UINT                   sectors;
93
FX_MEDIA              *media_ptr;
94
95
#ifdef TX_ENABLE_EVENT_TRACE
96
TX_TRACE_BUFFER_ENTRY *trace_event;
97
ULONG                  trace_timestamp;
98
#endif
99
100
101
    /* First, determine if the file is still open.  */
102
178683
    if (file_ptr -> fx_file_id != FX_FILE_ID)
103
    {
104
105
        /* Return the file not open error status.  */
106
1
        return(FX_NOT_OPEN);
107
    }
108
109
#ifndef FX_MEDIA_STATISTICS_DISABLE
110
    /* Setup pointer to media structure.  */
111
178682
    media_ptr =  file_ptr -> fx_file_media_ptr;
112
113
    /* Increment the number of times this service has been called.  */
114
178682
    media_ptr -> fx_media_file_reads++;
115
#endif
116
117
    /* Setup pointer to associated media control block.  */
118
178682
    media_ptr =  file_ptr -> fx_file_media_ptr;
119
120
    /* If trace is enabled, insert this event into the trace buffer.  */
121
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_READ, file_ptr, buffer_ptr, request_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
122
123
    /* Protect against other threads accessing the media.  */
124
178682
    FX_PROTECT
125
126
    /* Next, determine if there is any more bytes to read in the file.  */
127
178682
    if (file_ptr -> fx_file_current_file_offset >=
128
178682
        file_ptr -> fx_file_current_file_size)
129
    {
130
131
        /* Release media protection.  */
132
13
        FX_UNPROTECT
133
134
        /* The file is at the end, return the proper status and set the
135
           actual size to 0.  */
136
13
        *actual_size =  0;
137
13
        return(FX_END_OF_FILE);
138
    }
139
140
    /* At this point there is something to read.  */
141
142
    /* Setup local buffer pointer.  */
143
178669
    destination_ptr =  (UCHAR *)buffer_ptr;
144
145
    /* Determine if there are less bytes left in the file than that specified
146
       by the request.  If so, adjust the requested size.  */
147
178669
    if ((ULONG64)request_size >
148
178669
        (file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset))
149
    {
150
151
        /* Adjust the bytes remaining to what's available.  */
152
14
        request_size =  (ULONG)(file_ptr -> fx_file_current_file_size - file_ptr -> fx_file_current_file_offset);
153
    }
154
155
    /* Setup the remaining number of bytes to read.  */
156
178669
    bytes_remaining =  request_size;
157
158
    /* Loop to read all of the bytes.  */
159
310134
    while (bytes_remaining)
160
    {
161
162
        /* Determine if a beginning or ending partial read is required.  */
163
201774
        if ((file_ptr -> fx_file_current_logical_offset) ||
164
35408
            (bytes_remaining < media_ptr -> fx_media_bytes_per_sector))
165
        {
166
167
            /* A partial sector read is required.  */
168
169
            /* Read the current logical sector.  */
170
171332
            status =  _fx_utility_logical_sector_read(media_ptr,
171
                                                      file_ptr -> fx_file_current_logical_sector,
172
171332
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
173
174
            /* Check for good completion status.  */
175
171332
            if (status !=  FX_SUCCESS)
176
            {
177
178
                /* Release media protection.  */
179
23211
                FX_UNPROTECT
180
181
                /* Return the error status.  */
182
23211
                return(status);
183
            }
184
185
            /* Copy the appropriate number of bytes into the destination buffer.  */
186
148121
            copy_bytes =  media_ptr -> fx_media_bytes_per_sector -
187
148121
                file_ptr -> fx_file_current_logical_offset;
188
189
            /* Check to see if only a portion of the read sector needs to be
190
               copied.  */
191
148121
            if (copy_bytes > bytes_remaining)
192
            {
193
194
                /* Adjust the number of bytes to copy.  */
195
97440
                copy_bytes =  bytes_remaining;
196
            }
197
198
            /* Actually perform the memory copy.  */
199
148121
            _fx_utility_memory_copy(((UCHAR *)media_ptr -> fx_media_memory_buffer) + /* Use case of memcpy is verified. */
200
148121
                                    file_ptr -> fx_file_current_logical_offset,
201
                                    destination_ptr, copy_bytes);
202
203
            /* Increment the logical sector byte offset.  */
204
148121
            file_ptr -> fx_file_current_logical_offset =
205
148121
                file_ptr -> fx_file_current_logical_offset + copy_bytes;
206
207
            /* Adjust the remaining bytes to read.  */
208
148121
            bytes_remaining =  bytes_remaining - copy_bytes;
209
210
            /* Adjust the pointer to the destination buffer.  */
211
148121
            destination_ptr =  destination_ptr + copy_bytes;
212
        }
213
        else
214
        {
215
216
            /* Attempt to read multiple sectors directly into the destination
217
               buffer.  */
218
219
            /* Calculate the number of whole sectors to read directly into
220
               the destination buffer.  */
221
30442
            sectors =  (UINT)(bytes_remaining / media_ptr -> fx_media_bytes_per_sector);
222
223
224
30442
            next_cluster = cluster = file_ptr -> fx_file_current_physical_cluster;
225
30442
            for (i = (media_ptr -> fx_media_sectors_per_cluster -
226
31210
                      file_ptr -> fx_file_current_relative_sector); i < sectors; i += media_ptr -> fx_media_sectors_per_cluster)
227
            {
228
#ifdef FX_ENABLE_EXFAT
229
                if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
230
                {
231
                    cluster++;
232
                }
233
                else
234
                {
235
#endif /* FX_ENABLE_EXFAT */
236
1515
                    status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
237
238
                    /* Determine if an error is present.  */
239

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

55719
                    if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
401
51754
                        (next_cluster > media_ptr -> fx_media_fat_reserved))
402
                    {
403
404
                        /* Release media protection.  */
405
28238
                        FX_UNPROTECT
406
407
                        /* Send error message back to caller.  */
408
28238
                        if (status != FX_SUCCESS)
409
                        {
410
3964
                            return(status);
411
                        }
412
                        else
413
                        {
414
24274
                            return(FX_FILE_CORRUPT);
415
                        }
416
                    }
417
#ifdef FX_ENABLE_EXFAT
418
                }
419
#endif /* FX_ENABLE_EXFAT */
420
421
                /* Otherwise, we have a new cluster.  Save it in the file
422
                   control block and calculate a new logical sector value.  */
423
27481
                file_ptr -> fx_file_current_physical_cluster =  next_cluster;
424
27481
                file_ptr -> fx_file_current_relative_cluster++;
425
27481
                file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
426
27481
                    ((((ULONG64)next_cluster) - FX_FAT_ENTRY_START) *
427
27481
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
428
27481
                file_ptr -> fx_file_current_relative_sector =  0;
429
            }
430
            else
431
            {
432
433
                /* Still within the same cluster so just increment the
434
                   logical sector.  */
435
6544
                file_ptr -> fx_file_current_logical_sector++;
436
            }
437
438
            /* In either case, we are now positioned at a new sector so
439
               clear the logical sector offset.  */
440
34025
            file_ptr -> fx_file_current_logical_offset =  0;
441
        }
442
    }
443
444
    /* Adjust the current file offset accordingly.  */
445
126162
    file_ptr -> fx_file_current_file_offset =
446
126162
        file_ptr -> fx_file_current_file_offset + (ULONG64)request_size;
447
448
    /* Store the number of bytes actually read.  */
449
126162
    *actual_size =  request_size;
450
451
    /* Update the trace event with the bytes read.  */
452
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_READ, 0, 0, 0, request_size)
453
454
    /* Update the last accessed date.  */
455
126162
    file_ptr -> fx_file_dir_entry.fx_dir_entry_last_accessed_date =  _fx_system_date;
456
457
    /* Release media protection.  */
458
126162
    FX_UNPROTECT
459
460
    /* Return a successful status to the caller.  */
461
126162
    return(FX_SUCCESS);
462
}
463