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

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

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