GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_open.c Lines: 137 137 100.0 %
Date: 2024-03-11 05:15:45 Branches: 64 64 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_open                                       PORTABLE C      */
39
/*                                                           6.1          */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    William E. Lamie, Microsoft Corporation                             */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function first attempts to find the specified file.  If found, */
47
/*    the open request is validated and the file is opened.  During the   */
48
/*    opening process, all of the FAT entries for this file are examined  */
49
/*    for their integrity.                                                */
50
/*                                                                        */
51
/*  INPUT                                                                 */
52
/*                                                                        */
53
/*    media_ptr                             Media control block pointer   */
54
/*    file_ptr                              File control block pointer    */
55
/*    file_name                             Name pointer                  */
56
/*    open_type                             Type of open requested        */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _fx_directory_search                  Search for the file name in   */
65
/*                                          the directory structure       */
66
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
67
/*                                                                        */
68
/*  CALLED BY                                                             */
69
/*                                                                        */
70
/*    Application Code                                                    */
71
/*                                                                        */
72
/*  RELEASE HISTORY                                                       */
73
/*                                                                        */
74
/*    DATE              NAME                      DESCRIPTION             */
75
/*                                                                        */
76
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
77
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
78
/*                                            added conditional to        */
79
/*                                            disable fast open and       */
80
/*                                            consecutive detect,         */
81
/*                                            resulting in version 6.1    */
82
/*                                                                        */
83
/**************************************************************************/
84
18457
UINT  _fx_file_open(FX_MEDIA *media_ptr, FX_FILE *file_ptr, CHAR *file_name, UINT open_type)
85
{
86
87
UINT     status;
88
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
89
UINT     leading_consecutive;
90
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
91
ULONG    cluster;
92
18457
ULONG    contents = 0;
93
ULONG    open_count;
94
FX_FILE *tail_ptr;
95
FX_FILE *search_ptr;
96
ULONG    bytes_per_cluster;
97
UINT     last_cluster;
98
ULONG    cluster_count;
99
ULONG64  bytes_available;
100
ULONG64  bytes_remaining;
101
ULONG    fat_last;
102
#ifndef FX_DISABLE_FAST_OPEN
103
UINT     fast_open;
104
#endif /* FX_DISABLE_FAST_OPEN */
105
UCHAR    not_a_file_attr;
106
107
108
    /* Check the media to make sure it is open.  */
109
18457
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
110
    {
111
112
        /* Return the media not opened error.  */
113
136
        return(FX_MEDIA_NOT_OPEN);
114
    }
115
116
#ifndef FX_MEDIA_STATISTICS_DISABLE
117
118
    /* Increment the number of times this service has been called.  */
119
18321
    media_ptr -> fx_media_file_opens++;
120
#endif
121
122
    /* Clear the notify function. */
123
18321
    file_ptr -> fx_file_write_notify = FX_NULL;
124
125
    /* Determine the type of FAT and setup variables accordingly.  */
126
18321
    if (media_ptr -> fx_media_32_bit_FAT)
127
    {
128
3032
        fat_last        = FX_LAST_CLUSTER_1_32;
129
3032
        not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
130
    }
131
    else
132
    {
133
15289
        fat_last        = FX_LAST_CLUSTER_1;
134
15289
        not_a_file_attr = FX_DIRECTORY | FX_VOLUME;
135
    }
136
137
#ifndef FX_DISABLE_FAST_OPEN
138
    /* Determine if a fast open is selected.  */
139
18321
    if (open_type == FX_OPEN_FOR_READ_FAST)
140
    {
141
142
        /* Yes, convert the open type to a standard read.  */
143
2
        open_type =  FX_OPEN_FOR_READ;
144
145
        /* Set the open fast flag.  */
146
2
        fast_open =  FX_TRUE;
147
    }
148
    else
149
    {
150
151
        /* A fast open is not selected, set the flag to false.  */
152
18319
        fast_open =  FX_FALSE;
153
    }
154
#endif /* FX_DISABLE_FAST_OPEN */
155
156
    /* If trace is enabled, register this object.  */
157
    FX_TRACE_OBJECT_REGISTER(FX_TRACE_OBJECT_TYPE_FILE, file_ptr, file_name, 0, 0)
158
159
    /* If trace is enabled, insert this event into the trace buffer.  */
160
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_OPEN, media_ptr, file_ptr, file_name, open_type, FX_TRACE_FILE_EVENTS, 0, 0)
161
162
    /* Protect against other threads accessing the media.  */
163
18321
    FX_PROTECT
164
165
    /* Setup file name pointer.  */
166
18321
    file_ptr -> fx_file_dir_entry.fx_dir_entry_name =  file_ptr -> fx_file_name_buffer;
167
18321
    file_ptr -> fx_file_dir_entry.fx_dir_entry_short_name[0] =  0;
168
169
    /* Search the system for the supplied file name.  */
170
18321
    status =  _fx_directory_search(media_ptr, file_name, &(file_ptr -> fx_file_dir_entry), FX_NULL, FX_NULL);
171
172
    /* Determine if the search was successful.  */
173
18321
    if (status != FX_SUCCESS)
174
    {
175
176
        /* Release media protection.  */
177
5
        FX_UNPROTECT
178
179
        /* Return the error code.  */
180
5
        return(status);
181
    }
182
183
    /* Check to make sure the found entry is a file.  */
184
18316
    if (file_ptr -> fx_file_dir_entry.fx_dir_entry_attributes & not_a_file_attr)
185
    {
186
187
        /* Release media protection.  */
188
1
        FX_UNPROTECT
189
190
        /* Return the not a file error code.  */
191
1
        return(FX_NOT_A_FILE);
192
    }
193
194
#ifdef FX_SINGLE_OPEN_LEGACY
195
    /* Check to make sure the access is okay.  */
196
    if (open_type == FX_OPEN_FOR_READ)
197
    {
198
199
        /* Check the list of open files for others open for writing.  */
200
        open_count =  media_ptr -> fx_media_opened_file_count;
201
        search_ptr =  media_ptr -> fx_media_opened_file_list;
202
        while (open_count)
203
        {
204
205
            /* Look at each opened file to see if the same file is opened
206
               for writing.  */
207
            if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
208
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
209
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
210
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset) &&
211
                (search_ptr -> fx_file_open_mode))
212
            {
213
214
                /* Release media protection.  */
215
                FX_UNPROTECT
216
217
                /* The file has been opened for writing by a previous call.  */
218
                return(FX_ACCESS_ERROR);
219
            }
220
221
            /* Adjust the pointer and decrement the search count.  */
222
            search_ptr =  search_ptr -> fx_file_opened_next;
223
            open_count--;
224
        }
225
    }
226
    else
227
#else
228
18315
    if (open_type == FX_OPEN_FOR_WRITE)
229
#endif
230
    {
231
232
        /* A open for write request is present, check the file attributes
233
           and the list of open files for any other open instance of
234
           this file.  */
235
17242
        if (media_ptr -> fx_media_driver_write_protect)
236
        {
237
238
            /* Release media protection.  */
239
1
            FX_UNPROTECT
240
241
            /* Return write protect error.  */
242
1
            return(FX_WRITE_PROTECT);
243
        }
244
245
17241
        if (file_ptr -> fx_file_dir_entry.fx_dir_entry_attributes & (UCHAR)(FX_READ_ONLY))
246
        {
247
248
            /* Release media protection.  */
249
1
            FX_UNPROTECT
250
251
            /* Return the not a file error code.  */
252
1
            return(FX_ACCESS_ERROR);
253
        }
254
255
        /* Also search the opened files to see if this file is currently
256
           opened.  */
257
17240
        open_count =  media_ptr -> fx_media_opened_file_count;
258
17240
        search_ptr =  media_ptr -> fx_media_opened_file_list;
259
84298
        while (open_count)
260
        {
261
262
            /* Look at each opened file to see if the same file is already opened.  */
263
#ifdef FX_SINGLE_OPEN_LEGACY
264
            if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
265
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
266
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
267
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
268
#else
269
            /* Look at each opened file to see if the same file is already opened
270
               for writing.  */
271
67059
            if ((search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
272
67059
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
273
66062
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
274
66062
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset) &&
275
7
                (search_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE))
276
#endif
277
            {
278
279
                /* Release media protection.  */
280
1
                FX_UNPROTECT
281
282
                /* The file is currently open.  */
283
1
                return(FX_ACCESS_ERROR);
284
            }
285
286
            /* Adjust the pointer and decrement the search count.  */
287
67058
            search_ptr =  search_ptr -> fx_file_opened_next;
288
67058
            open_count--;
289
        }
290
    }
291
292
    /* At this point, we are ready to walk list of clusters to setup the
293
       initial condition of this file as well as to verify its integrity.  */
294
18312
    cluster =           file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
295
18312
    bytes_remaining =   file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
296
18312
    bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
297
18312
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
298
18312
    file_ptr -> fx_file_current_physical_cluster =  0;
299
300
    /* Check for invalid value.  */
301
18312
    if (bytes_per_cluster == 0)
302
    {
303
304
        /* Release media protection.  */
305
1
        FX_UNPROTECT
306
307
        /* Invalid media, return error.  */
308
1
        return(FX_MEDIA_INVALID);
309
    }
310
311
18311
    last_cluster =      0;
312
18311
    cluster_count =     0;
313
314
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
315
18311
    leading_consecutive = 1;
316
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
317
18311
    file_ptr -> fx_file_consecutive_cluster = 1;
318
#ifndef FX_DISABLE_FAST_OPEN
319
320
    /* Determine if the file is being open for reading with the fast option.  */
321
18311
    if (fast_open)
322
    {
323
324
        /* Calculate the bytes available.  */
325
2
        bytes_available =  ((bytes_remaining + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
326
327
    }
328
    else
329
#endif /* FX_DISABLE_FAST_OPEN */
330
    {
331
332
        /* Follow the link of FAT entries.  */
333

36798
        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
334
        {
335
336
            /* Increment the number of clusters.  */
337
18492
            cluster_count++;
338
339
            /* Read the current cluster entry from the FAT.  */
340
18492
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
341
342
            /* Check the return value.  */
343
18492
            if (status != FX_SUCCESS)
344
            {
345
346
                /* Release media protection.  */
347
1
                FX_UNPROTECT
348
349
                /* Return the error status.  */
350
1
                return(status);
351
            }
352
353
            /* Determine if the cluster is invalid (points to itself) or the count exceeds the total number of clusters.  */
354

18491
            if ((cluster == contents) || (cluster_count > media_ptr -> fx_media_total_clusters))
355
            {
356
357
                /* Release media protection.  */
358
2
                FX_UNPROTECT
359
360
                /* Return the bad status.  */
361
2
                return(FX_FAT_READ_ERROR);
362
            }
363
364
#ifndef FX_DISABLE_CONSECUTIVE_DETECT
365
366
            /* Check if present and next clusters are consecutive */
367
18489
            if (cluster + 1 == contents)
368
            {
369
370
                /* Determine if clusters are consecutive so far.  */
371
1115
                if (leading_consecutive)
372
                {
373
374
                    /* Yes, increment the number of leading consecutive clusters.  */
375
1101
                    file_ptr -> fx_file_consecutive_cluster++;
376
                }
377
            }
378
            else
379
            {
380
381
                /* The clusters are no longer consecutive, clear the consecutive flag.  */
382
17374
                leading_consecutive = 0;
383
            }
384
#endif /* FX_DISABLE_CONSECUTIVE_DETECT */
385
386
            /* Save the last valid cluster.  */
387
18489
            last_cluster =  cluster;
388
389
            /* Setup for the next cluster.  */
390
18489
            cluster =  contents;
391
392
            /* Determine if this is the last written cluster.  We need to remember this
393
               for open for writing.  */
394
18489
            if (bytes_remaining > bytes_per_cluster)
395
            {
396
397
                /* Still more written clusters, just decrement the counter.  */
398
6476
                bytes_remaining =  bytes_remaining - bytes_per_cluster;
399
            }
400
12013
            else if (!file_ptr -> fx_file_current_physical_cluster)
401
            {
402
403
                /* Remember this cluster number.  */
404
12011
                file_ptr -> fx_file_current_physical_cluster =  last_cluster;
405
406
                /* Remember the relative cluster.  */
407
12011
                file_ptr -> fx_file_current_relative_cluster =  cluster_count - 1;
408
409
                /* If the remaining bytes exactly fits the cluster size, check for
410
                   a possible adjustment to the next cluster.  */
411

12011
                if ((bytes_remaining == bytes_per_cluster) &&
412
1020
                    (cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
413
                {
414
415
                    /* We need to position to next allocated cluster.  */
416
1
                    file_ptr -> fx_file_current_physical_cluster =  cluster;
417
1
                    file_ptr -> fx_file_current_relative_cluster++;
418
419
                    /* Clear the remaining bytes.  */
420
1
                    bytes_remaining =  0;
421
                }
422
            }
423
        }
424
425
        /* Determine if the number of clusters is large enough to support the
426
           specified file size.  */
427
18306
        bytes_available =  ((ULONG64)media_ptr -> fx_media_bytes_per_sector) *
428
18306
            ((ULONG64)media_ptr -> fx_media_sectors_per_cluster) *
429
18306
            ((ULONG64)cluster_count);
430
431
        /* Check the bytes available in the cluster chain against the directory entry file size.  */
432

18306
        if ((bytes_available < file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size) ||
433
12011
            ((cluster_count) && (contents < fat_last)))
434
        {
435
            /* File is corrupt, release media protection.  */
436
4
            FX_UNPROTECT
437
438
            /* Return a corrupt file error status.  */
439
4
            return(FX_FILE_CORRUPT);
440
        }
441
    }
442
443
    /* The file is okay, populate the file control block and complete the
444
       file open process.  */
445
18304
    file_ptr -> fx_file_id =                        FX_FILE_ID;
446
18304
    file_ptr -> fx_file_name =                      file_ptr -> fx_file_name_buffer;
447
18304
    file_ptr -> fx_file_media_ptr =                 media_ptr;
448
18304
    file_ptr -> fx_file_open_mode =                 open_type;
449
18304
    file_ptr -> fx_file_modified =                  FX_FALSE;
450
18304
    file_ptr -> fx_file_total_clusters =            cluster_count;
451
18304
    file_ptr -> fx_file_first_physical_cluster =    file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
452
18304
    file_ptr -> fx_file_last_physical_cluster =     last_cluster;
453
18304
    file_ptr -> fx_file_current_file_size =         file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
454
18304
    file_ptr -> fx_file_current_available_size =    bytes_available;
455
18304
    file_ptr -> fx_file_disable_burst_cache =       FX_FALSE;
456
457
    /* Set the current settings based on how the file was opened.  */
458
18304
    if (open_type == FX_OPEN_FOR_READ)
459
    {
460
461
        /* Position the pointers to the beginning of the file.  */
462
1073
        file_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
463
1073
        file_ptr -> fx_file_current_relative_cluster =  0;
464
1073
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
465
1073
            (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
466
1073
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
467
1073
        file_ptr -> fx_file_current_relative_sector =   0;
468
1073
        file_ptr -> fx_file_current_logical_offset =    0;
469
1073
        file_ptr -> fx_file_current_file_offset =       0;
470
    }
471
    else
472
    {
473
474
        /* Open for writing - position the pointers to the end of the file.  */
475
476
        /* Determine if the remaining bytes fit exactly into the cluster size.  */
477
17231
        if (bytes_remaining == bytes_per_cluster)
478
        {
479
480
            /* Position to the end of the cluster.  */
481
17
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
482
17
                (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
483
17
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
484
17
                ((ULONG)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector)));
485
17
            file_ptr -> fx_file_current_relative_sector =   (ULONG)(((bytes_remaining - 1) / (ULONG)media_ptr -> fx_media_bytes_per_sector));
486
17
            file_ptr -> fx_file_current_file_offset =       file_ptr -> fx_file_current_file_size;
487
17
            file_ptr -> fx_file_current_logical_offset =    media_ptr -> fx_media_bytes_per_sector;
488
        }
489
        else
490
        {
491
492
            /* Position file parameters at end of last cluster allocation.  */
493
17214
            file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
494
17214
                (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
495
17214
                 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
496
17214
                ((ULONG)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector)));
497
17214
            file_ptr -> fx_file_current_relative_sector =   (ULONG)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
498
17214
            file_ptr -> fx_file_current_file_offset =       file_ptr -> fx_file_current_file_size;
499
17214
            file_ptr -> fx_file_current_logical_offset =    (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
500
        }
501
    }
502
503
#ifdef FX_ENABLE_FAULT_TOLERANT
504
    /* By default, the whole file is used. */
505
    file_ptr -> fx_file_maximum_size_used = file_ptr -> fx_file_current_file_size;
506
#endif /* FX_ENABLE_FAULT_TOLERANT */
507
508
    /* Place newly opened file on the list of open files for
509
       this media.  First, check for an empty list.  */
510
18304
    if (media_ptr -> fx_media_opened_file_list)
511
    {
512
513
        /* Pickup tail pointer.  */
514
11093
        tail_ptr =  (media_ptr -> fx_media_opened_file_list) -> fx_file_opened_previous;
515
516
        /* Place the new file in the list.  */
517
11093
        (media_ptr -> fx_media_opened_file_list) -> fx_file_opened_previous =  file_ptr;
518
11093
        tail_ptr -> fx_file_opened_next =  file_ptr;
519
520
        /* Setup this file's opened links.  */
521
11093
        file_ptr -> fx_file_opened_previous =  tail_ptr;
522
11093
        file_ptr -> fx_file_opened_next =      media_ptr -> fx_media_opened_file_list;
523
    }
524
    else
525
    {
526
527
        /* The opened media list is empty.  Add the media to empty list.  */
528
7211
        media_ptr -> fx_media_opened_file_list =   file_ptr;
529
7211
        file_ptr ->  fx_file_opened_next =         file_ptr;
530
7211
        file_ptr ->  fx_file_opened_previous =     file_ptr;
531
    }
532
533
    /* Increment the opened file counter.  */
534
18304
    media_ptr -> fx_media_opened_file_count++;
535
536
    /* Release media protection.  */
537
18304
    FX_UNPROTECT
538
539
    /* Open is complete, return successful status.  */
540
18304
    return(FX_SUCCESS);
541
}
542