GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_write.c Lines: 222 222 100.0 %
Date: 2024-03-11 05:15:45 Branches: 106 106 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
/* Include necessary system files.  */
25
26
#include "fx_api.h"
27
#include "fx_system.h"
28
#include "fx_file.h"
29
#include "fx_directory.h"
30
#include "fx_utility.h"
31
#ifdef FX_ENABLE_FAULT_TOLERANT
32
#include "fx_fault_tolerant.h"
33
#endif /* FX_ENABLE_FAULT_TOLERANT */
34
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _fx_file_write                                      PORTABLE C      */
41
/*                                                           6.1          */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    William E. Lamie, Microsoft Corporation                             */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function writes the specified number of bytes into the file's  */
49
/*    data area.  The status of the write operation is returned to the    */
50
/*    caller.  In addition, various internal file pointers in the file    */
51
/*    control block are also updated.                                     */
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    file_ptr                              File control block pointer    */
56
/*    buffer_ptr                            Buffer pointer                */
57
/*    size                                  Number of bytes to write      */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    return status                                                       */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    _fx_directory_entry_write             Update the file's size        */
66
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
67
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
68
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
69
/*    _fx_utility_logical_sector_flush      Flush written logical sectors */
70
/*    _fx_utility_logical_sector_read       Read a logical sector         */
71
/*    _fx_utility_logical_sector_write      Write a logical sector        */
72
/*    _fx_utility_memory_copy               Fast memory copy routine      */
73
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
74
/*                                            transaction                 */
75
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
76
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
77
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
78
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
79
/*                                                                        */
80
/*  CALLED BY                                                             */
81
/*                                                                        */
82
/*    Application Code                                                    */
83
/*                                                                        */
84
/*  RELEASE HISTORY                                                       */
85
/*                                                                        */
86
/*    DATE              NAME                      DESCRIPTION             */
87
/*                                                                        */
88
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
89
/*  09-30-2020     William E. Lamie         Modified comment(s), verified */
90
/*                                            memcpy usage,               */
91
/*                                            resulting in version 6.1    */
92
/*                                                                        */
93
/**************************************************************************/
94
599766
UINT  _fx_file_write(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG size)
95
{
96
97
UINT                   status;
98
ULONG64                bytes_remaining;
99
ULONG                  i;
100
ULONG                  copy_bytes;
101
ULONG                  bytes_per_cluster;
102
UCHAR                 *source_ptr;
103
ULONG                  first_new_cluster;
104
ULONG                  last_cluster;
105
ULONG                  cluster, next_cluster;
106
ULONG                  FAT_index;
107
ULONG                  FAT_value;
108
ULONG                  clusters;
109
ULONG                  total_clusters;
110
UINT                   sectors;
111
FX_MEDIA              *media_ptr;
112
113
114
#ifdef FX_FAULT_TOLERANT_DATA
115
FX_INT_SAVE_AREA
116
#endif
117
118
#ifndef FX_DONT_UPDATE_OPEN_FILES
119
ULONG                  open_count;
120
FX_FILE               *search_ptr;
121
#endif
122
123
#ifdef TX_ENABLE_EVENT_TRACE
124
TX_TRACE_BUFFER_ENTRY *trace_event;
125
ULONG                  trace_timestamp;
126
#endif
127
128
#ifdef FX_ENABLE_FAULT_TOLERANT
129
UCHAR                  data_append = FX_FALSE;      /* Whether or not new data would extend beyond the size of the original file.
130
                                                      Operations such as append or overwrite could cause the new file to exceed its
131
                                                      original size, resulting in data-appending operation. */
132
ULONG                  copy_head_cluster = 0;       /* The first cluster of the original chain that needs to be replaced. */
133
ULONG                  copy_tail_cluster = 0;       /* The last cluster of the original chain that needs to be replaced. */
134
ULONG                  insertion_back;              /* The insertion point (back) */
135
ULONG                  insertion_front = 0;         /* The insertion point (front) */
136
ULONG                  replace_clusters = 0;        /* The number of clusters to be replaced. */
137
#endif /* FX_ENABLE_FAULT_TOLERANT */
138
139
140
    /* First, determine if the file is still open.  */
141
599766
    if (file_ptr -> fx_file_id != FX_FILE_ID)
142
    {
143
144
        /* Return the file not open error status.  */
145
1
        return(FX_NOT_OPEN);
146
    }
147
148
    /* Setup pointer to media structure.  */
149
599765
    media_ptr =  file_ptr -> fx_file_media_ptr;
150
151
#ifndef FX_MEDIA_STATISTICS_DISABLE
152
153
    /* Increment the number of times this service has been called.  */
154
599765
    media_ptr -> fx_media_file_writes++;
155
#endif
156
157
158
599765
    if (file_ptr -> fx_file_current_file_offset + size > 0xFFFFFFFFULL)
159
    {
160
161
        /* Return the no more space error, since the new file size would be larger than
162
           the 32-bit field to represent it in the file's directory entry.  */
163
1
        return(FX_NO_MORE_SPACE);
164
    }
165
166
#ifdef FX_ENABLE_FAULT_TOLERANT
167
    /* Initialize next cluster of tail. */
168
    insertion_back = media_ptr -> fx_media_fat_last;
169
#endif /* FX_ENABLE_FAULT_TOLERANT */
170
171
    /* If trace is enabled, insert this event into the trace buffer.  */
172
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_WRITE, file_ptr, buffer_ptr, size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
173
174
    /* Protect against other threads accessing the media.  */
175
599764
    FX_PROTECT
176
177
    /* Check for write protect at the media level (set by driver).  */
178
599764
    if (media_ptr -> fx_media_driver_write_protect)
179
    {
180
181
        /* Release media protection.  */
182
1
        FX_UNPROTECT
183
184
        /* Return write protect error.  */
185
1
        return(FX_WRITE_PROTECT);
186
    }
187
188
    /* Make sure this file is open for writing.  */
189
599763
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
190
    {
191
192
        /* Release media protection.  */
193
1
        FX_UNPROTECT
194
195
        /* Return the access error exception - a write was attempted from
196
           a file opened for reading!  */
197
1
        return(FX_ACCESS_ERROR);
198
    }
199
200
#ifdef FX_ENABLE_FAULT_TOLERANT
201
202
    /* Start transaction. */
203
    _fx_fault_tolerant_transaction_start(media_ptr);
204
#endif /* FX_ENABLE_FAULT_TOLERANT */
205
206
    /* Calculate the number of bytes per cluster.  */
207
599762
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
208
599762
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
209
210
    /* Check for invalid value.  */
211
599762
    if (bytes_per_cluster == 0)
212
    {
213
214
#ifdef FX_ENABLE_FAULT_TOLERANT
215
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
216
#endif /* FX_ENABLE_FAULT_TOLERANT */
217
218
        /* Release media protection.  */
219
1
        FX_UNPROTECT
220
221
        /* Invalid media, return error.  */
222
1
        return(FX_MEDIA_INVALID);
223
    }
224
225
    /* Initialized first new cluster. */
226
599761
    first_new_cluster =  0;
227
228
#ifdef FX_ENABLE_FAULT_TOLERANT
229
    /* Calculate clusters need to be replaced when fault tolerant is enabled. */
230
    if (media_ptr -> fx_media_fault_tolerant_enabled)
231
    {
232
233
        if (file_ptr -> fx_file_current_file_offset == file_ptr -> fx_file_current_file_size)
234
        {
235
236
            /* Appending data. No need to replace existing clusters. */
237
            replace_clusters = 0;
238
        }
239
        else if (file_ptr -> fx_file_current_file_offset == file_ptr -> fx_file_maximum_size_used)
240
        {
241
242
            /* Similar to append data. No actual data after fx_file_maximum_size_used.
243
             * No need to replace existing clusters. */
244
            replace_clusters = 0;
245
        }
246
        else if (((file_ptr -> fx_file_current_file_offset / media_ptr -> fx_media_bytes_per_sector) ==
247
                 ((file_ptr -> fx_file_current_file_offset + size - 1) / media_ptr -> fx_media_bytes_per_sector)) &&
248
                 ((file_ptr -> fx_file_current_file_offset + size) <= file_ptr -> fx_file_current_file_size))
249
        {
250
251
            /* Overwriting data in one sector. No need to replace existing clusters. */
252
            replace_clusters = 0;
253
        }
254
        else if ((file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset) < size)
255
        {
256
257
            /* Replace all clusters from current_cluster. */
258
            replace_clusters = (UINT)(file_ptr -> fx_file_total_clusters - file_ptr -> fx_file_current_relative_cluster);
259
            copy_head_cluster = file_ptr -> fx_file_current_physical_cluster;
260
261
            data_append = FX_TRUE;
262
        }
263
        else
264
        {
265
266
            /* Replace clusters from current_cluster to the end of written cluster. */
267
            replace_clusters = (UINT)((file_ptr -> fx_file_current_file_offset + size + bytes_per_cluster - 1) / bytes_per_cluster -
268
                                      file_ptr -> fx_file_current_relative_cluster);
269
            copy_head_cluster = file_ptr -> fx_file_current_physical_cluster;
270
            data_append = FX_FALSE;
271
        }
272
    }
273
#endif /* FX_ENABLE_FAULT_TOLERANT */
274
275
    /* Next, determine if there is enough room to write the specified number of
276
       bytes to the clusters already allocated to this file.  */
277
599761
    if (((file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset) < size)
278
#ifdef FX_ENABLE_FAULT_TOLERANT
279
        || (replace_clusters)
280
#endif /* FX_ENABLE_FAULT_TOLERANT */
281
       )
282
    {
283
284
        /* The new request will not fit within the currently allocated clusters.  */
285
286
        /* Calculate the number of additional clusters that must be allocated for this
287
           write request.  */
288
#ifdef FX_ENABLE_FAULT_TOLERANT
289
        /* Find the number of clusters that need to be replaced. */
290
        if (media_ptr -> fx_media_fault_tolerant_enabled)
291
        {
292
293
            /* Mark the recovery phase. */
294
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
295
296
            bytes_remaining = file_ptr -> fx_file_current_file_offset + size;
297
298
            if (replace_clusters > 0)
299
            {
300
301
302
                /* Find previous cluster of copy head cluster. */
303
                /* The previous cluster is not initialized. Find it. */
304
                if (copy_head_cluster != file_ptr -> fx_file_first_physical_cluster)
305
                {
306
307
                    /* The copy head cluster is not the first cluster of file. */
308
                    /* Copy head is not the first cluster of file. */
309
                    if (file_ptr -> fx_file_current_relative_cluster < file_ptr -> fx_file_consecutive_cluster)
310
                    {
311
312
                        /* Clusters before current cluster are consecutive. */
313
                        insertion_front = copy_head_cluster - 1;
314
                        bytes_remaining -= file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
315
                    }
316
                    else
317
                    {
318
319
                        /* Skip consecutive clusters first. */
320
                        cluster = file_ptr -> fx_file_first_physical_cluster;
321
322
                        /* Loop the link of FAT to find the previous cluster. */
323
                        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
324
                        {
325
326
                            /* Reduce remaining bytes. */
327
                            bytes_remaining -= bytes_per_cluster;
328
329
                            /* Read the current cluster entry from the FAT.  */
330
                            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
331
332
                            /* Check the return value.  */
333
                            if (status != FX_SUCCESS)
334
                            {
335
336
                                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
337
338
                                /* Release media protection.  */
339
                                FX_UNPROTECT
340
341
                                /* Return the error status.  */
342
                                return(status);
343
                            }
344
345
                            if (FAT_value == copy_head_cluster)
346
                            {
347
                                break;
348
                            }
349
350
                            /* Move to next cluster. */
351
                            cluster = FAT_value;
352
                        }
353
354
                        if ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
355
                        {
356
357
                            /* Find the previous cluster. */
358
                            insertion_front = cluster;
359
                        }
360
                        else
361
                        {
362
363
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
364
365
                            /* Release media protection.  */
366
                            FX_UNPROTECT
367
368
                            /* Return the error status.  */
369
                            return(FX_NOT_FOUND);
370
                        }
371
                    }
372
                }
373
374
                /* Find copy tail cluster. */
375
                if (bytes_remaining <= bytes_per_cluster)
376
                {
377
378
                    /* Only one cluster is modified. */
379
                    copy_tail_cluster = copy_head_cluster;
380
                }
381
                else if (data_append == FX_FALSE)
382
                {
383
384
                    /* Search from copy head cluster. */
385
                    cluster = copy_head_cluster;
386
                    FAT_value = FX_FAT_ENTRY_START;
387
388
                    /* Loop the link of FAT to find the previous cluster. */
389
                    while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
390
                    {
391
392
                        if (bytes_remaining <= bytes_per_cluster)
393
                        {
394
                            break;
395
                        }
396
397
                        /* Reduce remaining bytes. */
398
                        bytes_remaining -= bytes_per_cluster;
399
400
                        /* Read the current cluster entry from the FAT.  */
401
                        status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
402
403
                        /* Check the return value.  */
404
                        if (status != FX_SUCCESS)
405
                        {
406
407
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
408
409
                            /* Release media protection.  */
410
                            FX_UNPROTECT
411
412
                            /* Return the error status.  */
413
                            return(status);
414
                        }
415
416
                        /* Move to next cluster. */
417
                        cluster = FAT_value;
418
                    }
419
420
                    /* Find the previous cluster. */
421
                    copy_tail_cluster = FAT_value;
422
                }
423
424
                /* Get the cluster next to copy tail. */
425
                if (data_append == FX_FALSE)
426
                {
427
428
                    /* Read FAT entry.  */
429
                    status =  _fx_utility_FAT_entry_read(media_ptr, copy_tail_cluster, &insertion_back);
430
431
                    /* Check for a bad status.  */
432
                    if (status != FX_SUCCESS)
433
                    {
434
435
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
436
437
                        /* Release media protection.  */
438
                        FX_UNPROTECT
439
440
                        /* Return the bad status.  */
441
                        return(status);
442
                    }
443
                }
444
                else
445
                {
446
                    insertion_back = media_ptr -> fx_media_fat_last;
447
                }
448
            }
449
            else
450
            {
451
                insertion_back = media_ptr -> fx_media_fat_last;
452
            }
453
        }
454
455
        if (file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset < size)
456
        {
457
#endif /* FX_ENABLE_FAULT_TOLERANT */
458
            /* Calculate clusters that are needed for data append except ones overwritten. */
459
59282
            clusters =  (UINT)((size + (bytes_per_cluster - 1) -
460
59282
                                (file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset)) /
461
                               bytes_per_cluster);
462
#ifdef FX_ENABLE_FAULT_TOLERANT
463
        }
464
        else
465
        {
466
            clusters = 0;
467
        }
468
#endif /* FX_ENABLE_FAULT_TOLERANT */
469
470
        /* Determine if we have enough space left.  */
471
#ifdef FX_ENABLE_FAULT_TOLERANT
472
        if (clusters + replace_clusters > media_ptr -> fx_media_available_clusters)
473
#else
474
59282
        if (clusters > media_ptr -> fx_media_available_clusters)
475
#endif /* FX_ENABLE_FAULT_TOLERANT */
476
        {
477
478
#ifdef FX_ENABLE_FAULT_TOLERANT
479
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
480
#endif /* FX_ENABLE_FAULT_TOLERANT */
481
482
            /* Release media protection.  */
483
2
            FX_UNPROTECT
484
485
            /* Out of disk space.  */
486
2
            return(FX_NO_MORE_SPACE);
487
        }
488
489
        /* Update the file total cluster count.  */
490
59280
        file_ptr -> fx_file_total_clusters =  file_ptr -> fx_file_total_clusters + clusters;
491
492
        /* Check for wrap-around when updating the available size.  */
493
59280
        if (file_ptr -> fx_file_current_available_size + (ULONG64)bytes_per_cluster * (ULONG64)clusters > 0xFFFFFFFFULL)
494
        {
495
496
            /* 32-bit wrap around condition is present.  Just set the available file size to all ones, which is
497
               the maximum file size.  */
498
1
            file_ptr -> fx_file_current_available_size =  0xFFFFFFFFULL;
499
        }
500
        else
501
        {
502
503
            /* Normal condition, update the available size.  */
504
59279
            file_ptr -> fx_file_current_available_size =
505
59279
                file_ptr -> fx_file_current_available_size + (ULONG64)bytes_per_cluster * (ULONG64)clusters;
506
        }
507
508
#ifdef FX_ENABLE_FAULT_TOLERANT
509
        /* Account for newly allocated clusters. */
510
        clusters += replace_clusters;
511
#endif /* FX_ENABLE_FAULT_TOLERANT */
512
513
        /* Decrease the available clusters in the media control block. */
514
59280
        media_ptr -> fx_media_available_clusters =  media_ptr -> fx_media_available_clusters - clusters;
515
516
517
        /* Search for the additional clusters we need.  */
518
59280
        total_clusters =     media_ptr -> fx_media_total_clusters;
519
520
#ifdef FX_ENABLE_FAULT_TOLERANT
521
        if (replace_clusters > 0)
522
        {
523
524
            /* Reset consecutive cluster. */
525
            file_ptr -> fx_file_consecutive_cluster = 1;
526
527
            last_cluster =   insertion_front;
528
529
        }
530
        else
531
#endif /* FX_ENABLE_FAULT_TOLERANT */
532
        {
533
59280
            last_cluster =   file_ptr -> fx_file_last_physical_cluster;
534
        }
535
536
59280
        FAT_index    =       media_ptr -> fx_media_cluster_search_start;
537
538
        /* Loop to find the needed clusters.  */
539
122137
        while (clusters)
540
        {
541
542
            /* Decrease the cluster count.  */
543
65756
            clusters--;
544
545
            /* Loop to find the first available cluster.  */
546
            do
547
            {
548
549
                /* Make sure we stop looking after one pass through the FAT table.  */
550
68736
                if (!total_clusters)
551
                {
552
553
#ifdef FX_ENABLE_FAULT_TOLERANT
554
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
555
#endif /* FX_ENABLE_FAULT_TOLERANT */
556
557
                    /* Release media protection.  */
558
1
                    FX_UNPROTECT
559
560
                    /* Something is wrong with the media - the desired clusters were
561
                       not found in the FAT table.  */
562
1
                    return(FX_NO_MORE_SPACE);
563
                }
564
565
                /* Read FAT entry.  */
566
68735
                status =  _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
567
568
                /* Check for a bad status.  */
569
68735
                if (status != FX_SUCCESS)
570
                {
571
572
#ifdef FX_ENABLE_FAULT_TOLERANT
573
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
574
#endif /* FX_ENABLE_FAULT_TOLERANT */
575
576
                    /* Release media protection.  */
577
2897
                    FX_UNPROTECT
578
579
                    /* Return the bad status.  */
580
2897
                    return(status);
581
                }
582
583
                /* Decrement the total cluster count.  */
584
65838
                total_clusters--;
585
586
                /* Determine if the FAT entry is free.  */
587
65838
                if (FAT_value == FX_FREE_CLUSTER)
588
                {
589
590
                    /* Move cluster search pointer forward.  */
591
62858
                    media_ptr -> fx_media_cluster_search_start =  FAT_index + 1;
592
593
                    /* Determine if this needs to be wrapped.  */
594
62858
                    if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
595
                    {
596
597
                        /* Wrap the search to the beginning FAT entry.  */
598
17
                        media_ptr -> fx_media_cluster_search_start =  FX_FAT_ENTRY_START;
599
                    }
600
601
                    /* Break this loop.  */
602
62858
                    break;
603
                }
604
                else
605
                {
606
607
                    /* FAT entry is not free... Advance the FAT index.  */
608
2980
                    FAT_index++;
609
610
                    /* Determine if we need to wrap the FAT index around.  */
611
2980
                    if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
612
                    {
613
614
                        /* Wrap the search to the beginning FAT entry.  */
615
1
                        FAT_index =  FX_FAT_ENTRY_START;
616
                    }
617
                }
618
            } while (FX_TRUE);
619
620
            /* Determine if we have found the first new cluster yet.  */
621
62858
            if (first_new_cluster == 0)
622
            {
623
624
                /* Remember the first new cluster. */
625
56382
                first_new_cluster =  FAT_index;
626
627
#ifdef FX_ENABLE_FAULT_TOLERANT
628
                if (media_ptr -> fx_media_fault_tolerant_enabled)
629
                {
630
631
                    /* Set the undo log now. */
632
                    if (copy_head_cluster == 0)
633
                    {
634
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, file_ptr -> fx_file_current_physical_cluster,
635
                                                                  first_new_cluster, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
636
                    }
637
                    else
638
                    {
639
640
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, insertion_front, first_new_cluster,
641
                                                                  copy_head_cluster, insertion_back);
642
                    }
643
644
                    /* Check for good completion status.  */
645
                    if (status !=  FX_SUCCESS)
646
                    {
647
648
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
649
650
                        /* Release media protection.  */
651
                        FX_UNPROTECT
652
653
                        /* Return the error status.  */
654
                        return(status);
655
                    }
656
                }
657
#endif /* FX_ENABLE_FAULT_TOLERANT */
658
            }
659
660
            /* Make a quick check to see if an empty, cluster-less file
661
               is being written to for the first time.  */
662
62858
            if (last_cluster)
663
            {
664
665
                /* Check for the file's cluster.  We won't perform this link until the
666
                   entire FAT chain is built.  */
667
56680
                if (last_cluster != file_ptr -> fx_file_last_physical_cluster)
668
                {
669
670
                    /* Normal condition - link the last cluster with the new
671
                       found cluster.  */
672
6476
                    status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index);
673
                }
674
675
                /* Check for a bad FAT write status.  */
676
56680
                if (status !=  FX_SUCCESS)
677
                {
678
679
#ifdef FX_ENABLE_FAULT_TOLERANT
680
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
681
#endif /* FX_ENABLE_FAULT_TOLERANT */
682
683
                    /* Release media protection.  */
684
1
                    FX_UNPROTECT
685
686
                    /* Return the bad status.  */
687
1
                    return(status);
688
                }
689
690
                /* Determine if we are adding a sector after a write filled the previously
691
                   allocated cluster exactly.  */
692
56679
                if ((file_ptr -> fx_file_current_relative_sector >=
693
56679
                     (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
694
56586
                    (file_ptr -> fx_file_current_logical_offset >=
695
56586
                     media_ptr -> fx_media_bytes_per_sector))
696
                {
697
698
                    /* Yes, we need to adjust all of the pertinent file parameters for
699
                       writing into this newly allocated cluster.  */
700
36865
                    file_ptr -> fx_file_current_physical_cluster =  FAT_index;
701
36865
                    file_ptr -> fx_file_current_relative_cluster++;
702
36865
                    file_ptr -> fx_file_current_relative_sector =   0;
703
36865
                    file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
704
36865
                        (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
705
36865
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
706
36865
                    file_ptr -> fx_file_current_logical_offset =    0;
707
                }
708
            }
709
            else
710
            {
711
712
                /* This is the first cluster allocated for the file.  Just
713
                   remember it as being the first and setup the other file
714
                   pointers accordingly.  */
715
6178
                file_ptr -> fx_file_first_physical_cluster =    FAT_index;
716
6178
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
717
6178
                file_ptr -> fx_file_current_relative_cluster =  0;
718
6178
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
719
6178
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
720
6178
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
721
#ifdef FX_ENABLE_FAULT_TOLERANT
722
                if (file_ptr -> fx_file_last_physical_cluster == 0)
723
#endif /* FX_ENABLE_FAULT_TOLERANT */
724
                {
725
6178
                    file_ptr -> fx_file_current_logical_offset =    0;
726
6178
                    file_ptr -> fx_file_current_file_offset =       0;
727
                }
728
729
                /* Also remember this as the first cluster in the directory
730
                   entry.  */
731
6178
                file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
732
            }
733
734
            /* Otherwise, remember the new FAT index as the last.  */
735
62857
            last_cluster =  FAT_index;
736
737
            /* Move to the next FAT entry.  */
738
62857
            FAT_index =  media_ptr -> fx_media_cluster_search_start;
739
        }
740
741
#ifdef FX_ENABLE_FAULT_TOLERANT
742
        if (media_ptr -> fx_media_fault_tolerant_enabled)
743
        {
744
745
            /* Link the last cluster back to original FAT.  */
746
            status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, insertion_back);
747
        }
748
        else
749
#endif /* FX_ENABLE_FAULT_TOLERANT */
750
            {
751
752
            /* Place an end-of-file marker on the last cluster.  */
753
56381
            status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
754
        }
755
756
        /* Check for a bad FAT write status.  */
757
56381
        if (status !=  FX_SUCCESS)
758
        {
759
#ifdef FX_ENABLE_FAULT_TOLERANT
760
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
761
#endif /* FX_ENABLE_FAULT_TOLERANT */
762
763
            /* Release media protection.  */
764
1
            FX_UNPROTECT
765
766
            /* Return the bad status.  */
767
1
            return(status);
768
        }
769
770
771
        /* Determine if the file already had clusters.  */
772
56380
        if (file_ptr -> fx_file_last_physical_cluster)
773
        {
774
775
            /* Now, link the file's old last cluster to the first cluster of the new chain.  */
776
#ifdef FX_ENABLE_FAULT_TOLERANT
777
            if (insertion_front)
778
            {
779
                status = _fx_utility_FAT_entry_write(media_ptr, insertion_front, first_new_cluster);
780
            }
781
            else if ((media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE) ||
782
                     ((replace_clusters == 0) && (first_new_cluster)))
783
            {
784
                status = _fx_utility_FAT_entry_write(media_ptr, file_ptr -> fx_file_last_physical_cluster, first_new_cluster);
785
            }
786
#else
787
50204
            status = _fx_utility_FAT_entry_write(media_ptr, file_ptr -> fx_file_last_physical_cluster, first_new_cluster);
788
#endif /* FX_ENABLE_FAULT_TOLERANT */
789
790
            /* Check for a bad FAT write status.  */
791
50204
            if (status !=  FX_SUCCESS)
792
            {
793
#ifdef FX_ENABLE_FAULT_TOLERANT
794
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
795
#endif /* FX_ENABLE_FAULT_TOLERANT */
796
797
                /* Release media protection.  */
798
1
                FX_UNPROTECT
799
800
                /* Return the bad status.  */
801
1
                return(status);
802
            }
803
        }
804
805
#ifdef FX_FAULT_TOLERANT
806
807
808
        /* Ensure the new FAT chain is properly written to the media.  */
809
810
        /* Flush the cached individual FAT entries */
811
        _fx_utility_FAT_flush(media_ptr);
812
#endif
813
814
#ifdef FX_ENABLE_FAULT_TOLERANT
815
        if (media_ptr -> fx_media_fault_tolerant_enabled)
816
        {
817
818
            /* Clear undo phase. */
819
            media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
820
821
            /* Update the last cluster? */
822
            if (insertion_back == media_ptr -> fx_media_fat_last)
823
            {
824
825
                /* Yes. Update the file control block with the last physical cluster.  */
826
                file_ptr -> fx_file_last_physical_cluster =  last_cluster;
827
            }
828
        }
829
        else
830
#endif /* FX_ENABLE_FAULT_TOLERANT */
831
        {
832
833
            /* Update the file control block with the last physical cluster.  */
834
56379
            file_ptr -> fx_file_last_physical_cluster =  last_cluster;
835
        }
836
    }
837
838
    /* Check for a need to increment to the next sector within a previously
839
       allocated cluster.  */
840
596858
    if (file_ptr -> fx_file_current_logical_offset >=
841
596858
        media_ptr -> fx_media_bytes_per_sector)
842
    {
843
844
        /* Update the sector specific file parameters to start at the
845
           next logical sector.  */
846
4675
        file_ptr -> fx_file_current_logical_sector++;
847
4675
        file_ptr -> fx_file_current_relative_sector++;
848
4675
        file_ptr -> fx_file_current_logical_offset =  0;
849
    }
850
851
    /* At this point there is enough room to perform the file write operation.  */
852
853
    /* Setup local buffer pointer.  */
854
596858
    source_ptr =  (UCHAR *)buffer_ptr;
855
856
    /* Setup the remaining number of bytes to write.  */
857
596858
    bytes_remaining =  size;
858
859
#ifdef FX_ENABLE_FAULT_TOLERANT
860
    if (replace_clusters > 0)
861
    {
862
863
        /* Force update current cluster and sector. */
864
        file_ptr -> fx_file_current_physical_cluster = first_new_cluster;
865
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
866
            (((ULONG64)(first_new_cluster - FX_FAT_ENTRY_START)) *
867
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
868
            file_ptr -> fx_file_current_relative_sector;
869
870
        /* Copy sectors in replaced cluster but not overwritten at the front. */
871
        for (i = 0; i < file_ptr -> fx_file_current_relative_sector; i++)
872
        {
873
            status =  _fx_utility_logical_sector_read(media_ptr,
874
                                                      ((ULONG)media_ptr -> fx_media_data_sector_start) +
875
                                                      (((ULONG)(copy_head_cluster - FX_FAT_ENTRY_START)) *
876
                                                       ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
877
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
878
879
            /* Check for good completion status.  */
880
            if (status !=  FX_SUCCESS)
881
            {
882
883
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
884
885
                /* Release media protection.  */
886
                FX_UNPROTECT
887
888
                /* Return the error status.  */
889
                return(status);
890
            }
891
892
            /* Write back the current logical sector.  */
893
            status =  _fx_utility_logical_sector_write(media_ptr,
894
                                                       ((ULONG)media_ptr -> fx_media_data_sector_start) +
895
                                                       (((ULONG)(file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START)) *
896
                                                        ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
897
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
898
899
            /* Check for good completion status.  */
900
            if (status !=  FX_SUCCESS)
901
            {
902
903
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
904
905
                /* Release media protection.  */
906
                FX_UNPROTECT
907
908
                /* Return the error status.  */
909
                return(status);
910
            }
911
        }
912
    }
913
#endif /* FX_ENABLE_FAULT_TOLERANT */
914
915
    /* Loop to write all of the bytes.  */
916
1152964
    while (bytes_remaining)
917
    {
918
919
        /* Determine if a beginning or ending partial write is required.  */
920
615983
        if ((file_ptr -> fx_file_current_logical_offset) ||
921
88327
            (bytes_remaining < media_ptr -> fx_media_bytes_per_sector))
922
        {
923
924
            /* A partial sector write is required.  */
925
926
            /* Read the current logical sector.  */
927
#ifdef FX_ENABLE_FAULT_TOLERANT
928
            if (replace_clusters > 0)
929
            {
930
                if (file_ptr -> fx_file_current_physical_cluster == first_new_cluster)
931
                {
932
933
                    /* It's at beginning. */
934
                    status =  _fx_utility_logical_sector_read(media_ptr,
935
                                                              ((ULONG)media_ptr -> fx_media_data_sector_start) +
936
                                                              (((ULONG)(copy_head_cluster - FX_FAT_ENTRY_START)) *
937
                                                               ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
938
                                                              file_ptr -> fx_file_current_relative_sector,
939
                                                              media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DATA_SECTOR);
940
                }
941
                else if (data_append == FX_FALSE)
942
                {
943
944
                    /* It's at ending. */
945
                    status =  _fx_utility_logical_sector_read(media_ptr,
946
                                                              ((ULONG)media_ptr -> fx_media_data_sector_start) +
947
                                                              (((ULONG)(copy_tail_cluster - FX_FAT_ENTRY_START)) *
948
                                                               ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
949
                                                              file_ptr -> fx_file_current_relative_sector,
950
                                                              media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DATA_SECTOR);
951
                }
952
                else
953
                {
954
955
                    /* It's at ending. */
956
                    status =  _fx_utility_logical_sector_read(media_ptr,
957
                                                              file_ptr -> fx_file_current_logical_sector,
958
                                                              media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
959
                }
960
            }
961
            else
962
#endif /* FX_ENABLE_FAULT_TOLERANT */
963
            {
964
582290
                status =  _fx_utility_logical_sector_read(media_ptr,
965
                                                          file_ptr -> fx_file_current_logical_sector,
966
582290
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
967
            }
968
969
            /* Check for good completion status.  */
970
582290
            if (status !=  FX_SUCCESS)
971
            {
972
#ifdef FX_ENABLE_FAULT_TOLERANT
973
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
974
#endif /* FX_ENABLE_FAULT_TOLERANT */
975
976
                /* Release media protection.  */
977
13365
                FX_UNPROTECT
978
979
                /* Return the error status.  */
980
13365
                return(status);
981
            }
982
983
            /* Copy the appropriate number of bytes into the destination buffer.  */
984
568925
            copy_bytes =  media_ptr -> fx_media_bytes_per_sector -
985
568925
                file_ptr -> fx_file_current_logical_offset;
986
987
            /* Check to see if only a portion of the sector needs to be
988
               copied.  */
989
568925
            if (copy_bytes > bytes_remaining)
990
            {
991
992
                /* Adjust the number of bytes to copy.  */
993
524833
                copy_bytes =  (ULONG)bytes_remaining;
994
            }
995
996
            /* Actually perform the memory copy.  */
997
568925
            _fx_utility_memory_copy(source_ptr, ((UCHAR *)media_ptr -> fx_media_memory_buffer) +  /* Use case of memcpy is verified. */
998
568925
                                    file_ptr -> fx_file_current_logical_offset,
999
                                    copy_bytes);
1000
1001
            /* Write back the current logical sector.  */
1002
568925
            status =  _fx_utility_logical_sector_write(media_ptr, file_ptr -> fx_file_current_logical_sector,
1003
568925
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1004
1005
            /* Check for good completion status.  */
1006
568925
            if (status !=  FX_SUCCESS)
1007
            {
1008
#ifdef FX_ENABLE_FAULT_TOLERANT
1009
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1010
#endif /* FX_ENABLE_FAULT_TOLERANT */
1011
1012
                /* Release media protection.  */
1013
4153
                FX_UNPROTECT
1014
1015
                /* Return the error status.  */
1016
4153
                return(status);
1017
            }
1018
1019
1020
            /* Increment the logical sector byte offset.  */
1021
564772
            file_ptr -> fx_file_current_logical_offset =
1022
564772
                file_ptr -> fx_file_current_logical_offset + copy_bytes;
1023
1024
            /* Adjust the remaining bytes to read.  */
1025
564772
            bytes_remaining =  bytes_remaining - copy_bytes;
1026
1027
            /* Adjust the pointer to the source buffer.  */
1028
564772
            source_ptr =  source_ptr + copy_bytes;
1029
        }
1030
        else
1031
        {
1032
1033
            /* Attempt to write multiple sectors directly to the media.  */
1034
1035
            /* Calculate the number of whole sectors to write.  */
1036
33693
            sectors =  (UINT)(bytes_remaining / media_ptr -> fx_media_bytes_per_sector);
1037
1038
33693
            next_cluster = cluster = file_ptr -> fx_file_current_physical_cluster;
1039
1040
33693
            for (i = (media_ptr -> fx_media_sectors_per_cluster -
1041
34204
                      file_ptr -> fx_file_current_relative_sector); i < sectors; i += media_ptr -> fx_media_sectors_per_cluster)
1042
            {
1043
848
                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
1044
1045
                /* Determine if an error is present.  */
1046

848
                if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
1047
673
                    (next_cluster > media_ptr -> fx_media_fat_reserved))
1048
                {
1049
#ifdef FX_ENABLE_FAULT_TOLERANT
1050
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1051
#endif /* FX_ENABLE_FAULT_TOLERANT */
1052
1053
                    /* Release media protection.  */
1054
335
                    FX_UNPROTECT
1055
1056
                    /* Send error message back to caller.  */
1057
335
                    if (status != FX_SUCCESS)
1058
                    {
1059
174
                        return(status);
1060
                    }
1061
                    else
1062
                    {
1063
161
                        return(FX_FILE_CORRUPT);
1064
                    }
1065
                }
1066
1067
513
                if (next_cluster != cluster + 1)
1068
                {
1069
2
                    break;
1070
                }
1071
                else
1072
                {
1073
511
                    cluster = next_cluster;
1074
                }
1075
            }
1076
1077
33358
            if (i < sectors)
1078
            {
1079
2
                sectors = i;
1080
            }
1081
1082
            /* Perform the data write directly from the user's buffer of
1083
               the appropriate number of sectors.  */
1084
33358
            status =  _fx_utility_logical_sector_write(media_ptr, file_ptr -> fx_file_current_logical_sector,
1085
                                                       source_ptr, (ULONG) sectors, FX_DATA_SECTOR);
1086
1087
            /* Check for good completion status.  */
1088
33358
            if (status !=  FX_SUCCESS)
1089
            {
1090
#ifdef FX_ENABLE_FAULT_TOLERANT
1091
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1092
#endif /* FX_ENABLE_FAULT_TOLERANT */
1093
1094
                /* Release media protection.  */
1095
435
                FX_UNPROTECT
1096
1097
                /* Return the error status.  */
1098
435
                return(status);
1099
            }
1100
1101
            /* Now adjust the various file pointers.  */
1102
1103
            /* Increment the current logical sector.  Subtract one from
1104
               the sector count because we are going to use the logical
1105
               offset to do additional sector/cluster arithmetic below.  */
1106
32923
            file_ptr -> fx_file_current_logical_sector =
1107
32923
                file_ptr -> fx_file_current_logical_sector +
1108
32923
                (sectors - 1);
1109
1110
            /* Move the relative cluster and sector as well.  */
1111
32923
            file_ptr -> fx_file_current_relative_cluster = file_ptr -> fx_file_current_relative_cluster +
1112
32923
                (file_ptr -> fx_file_current_relative_sector + (sectors - 1)) /
1113
32923
                media_ptr -> fx_media_sectors_per_cluster;
1114
1115
32923
            file_ptr -> fx_file_current_relative_sector =
1116
32923
                (file_ptr -> fx_file_current_relative_sector + (sectors - 1)) %
1117
32923
                media_ptr -> fx_media_sectors_per_cluster;
1118
1119
            /* Increment the logical sector byte offset.  */
1120
32923
            file_ptr -> fx_file_current_logical_offset =
1121
32923
                media_ptr -> fx_media_bytes_per_sector;
1122
1123
32923
            file_ptr -> fx_file_current_physical_cluster = cluster;
1124
1125
            /* Adjust the remaining bytes.  */
1126
32923
            bytes_remaining =  bytes_remaining -
1127
32923
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
1128
1129
            /* Adjust the pointer to the source buffer.  */
1130
32923
            source_ptr =  source_ptr +
1131
32923
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
1132
        }
1133
1134
        /* At this point, we have either written a partial sector or have successfully
1135
           written one or more whole sectors.  Determine if we are at the end of
1136
           the current logical sector.  */
1137
597695
        if (file_ptr -> fx_file_current_logical_offset >=
1138
597695
            media_ptr -> fx_media_bytes_per_sector)
1139
        {
1140
1141
            /* Determine if we are at the exact physical end of the file.  */
1142
76022
            if ((bytes_remaining == 0) &&
1143
55700
                ((file_ptr -> fx_file_current_file_offset + size) >=
1144
55700
                 file_ptr -> fx_file_current_available_size))
1145
            {
1146
1147
                /* Skip the following file parameter adjustments.  The next write will
1148
                   detect the logical offset out of the range of the sector and reset
1149
                   all of the pertinent information.  */
1150
37229
                break;
1151
            }
1152
1153
            /* We need to move to the next logical sector, but first
1154
               determine if the next logical sector is within the same
1155
               cluster.  */
1156
1157
            /* Increment the current relative sector in the cluster.  */
1158
38793
            file_ptr -> fx_file_current_relative_sector++;
1159
1160
            /* Determine if this is in a new cluster.  */
1161
38793
            if (file_ptr -> fx_file_current_relative_sector >=
1162
38793
                media_ptr -> fx_media_sectors_per_cluster)
1163
            {
1164
1165
                /* Yes, we need to move to the next cluster.  */
1166
1167
                /* Read the FAT entry of the current cluster to find
1168
                   the next cluster.  */
1169
24692
                status =  _fx_utility_FAT_entry_read(media_ptr,
1170
                                                     file_ptr -> fx_file_current_physical_cluster, &next_cluster);
1171
1172
                /* Determine if an error is present.  */
1173

24692
                if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
1174
23907
                    (next_cluster > media_ptr -> fx_media_fat_reserved))
1175
                {
1176
#ifdef FX_ENABLE_FAULT_TOLERANT
1177
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1178
#endif /* FX_ENABLE_FAULT_TOLERANT */
1179
1180
                    /* Release media protection.  */
1181
4360
                    FX_UNPROTECT
1182
1183
                    /* Send error message back to caller.  */
1184
4360
                    if (status != FX_SUCCESS)
1185
                    {
1186
784
                        return(status);
1187
                    }
1188
                    else
1189
                    {
1190
3576
                        return(FX_FILE_CORRUPT);
1191
                    }
1192
                }
1193
1194
                /* Otherwise, we have a new cluster.  Save it in the file
1195
                   control block and calculate a new logical sector value.  */
1196
20332
                file_ptr -> fx_file_current_physical_cluster =  next_cluster;
1197
20332
                file_ptr -> fx_file_current_relative_cluster++;
1198
20332
                file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
1199
20332
                    ((((ULONG64)next_cluster) - FX_FAT_ENTRY_START) *
1200
20332
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
1201
20332
                file_ptr -> fx_file_current_relative_sector =  0;
1202
            }
1203
            else
1204
            {
1205
1206
                /* Still within the same cluster so just increment the
1207
                   logical sector.  */
1208
14101
                file_ptr -> fx_file_current_logical_sector++;
1209
            }
1210
1211
            /* In either case, we are now positioned at a new sector so
1212
               clear the logical sector offset.  */
1213
34433
            file_ptr -> fx_file_current_logical_offset =  0;
1214
        }
1215
    }
1216
1217
#ifdef FX_ENABLE_FAULT_TOLERANT
1218
    if (((replace_clusters > 0) && (data_append == FX_FALSE)) &&
1219
        (file_ptr -> fx_file_current_logical_offset || file_ptr -> fx_file_current_relative_sector))
1220
    {
1221
1222
        /* Copy sectors in replaced cluster but not overwritten at the end. */
1223
        if (file_ptr -> fx_file_current_logical_offset == 0)
1224
        {
1225
            i = file_ptr -> fx_file_current_relative_sector;
1226
        }
1227
        else
1228
        {
1229
            i = file_ptr -> fx_file_current_relative_sector + 1;
1230
        }
1231
        for (; i < media_ptr -> fx_media_sectors_per_cluster; i++)
1232
        {
1233
            status =  _fx_utility_logical_sector_read(media_ptr,
1234
                                                      ((ULONG)media_ptr -> fx_media_data_sector_start) +
1235
                                                      (((ULONG)(copy_tail_cluster - FX_FAT_ENTRY_START)) *
1236
                                                       ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1237
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1238
1239
            /* Check for good completion status.  */
1240
            if (status !=  FX_SUCCESS)
1241
            {
1242
1243
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1244
1245
                /* Release media protection.  */
1246
                FX_UNPROTECT
1247
1248
                /* Return the error status.  */
1249
                return(status);
1250
            }
1251
1252
            /* Write back the current logical sector.  */
1253
            status =  _fx_utility_logical_sector_write(media_ptr,
1254
                                                       ((ULONG)media_ptr -> fx_media_data_sector_start) +
1255
                                                       (((ULONG)(file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START)) *
1256
                                                        ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1257
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1258
1259
            /* Check for good completion status.  */
1260
            if (status !=  FX_SUCCESS)
1261
            {
1262
1263
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1264
1265
                /* Release media protection.  */
1266
                FX_UNPROTECT
1267
1268
                /* Return the error status.  */
1269
                return(status);
1270
            }
1271
        }
1272
    }
1273
#endif /* FX_ENABLE_FAULT_TOLERANT */
1274
1275
    /* Adjust the current file offset accordingly.  */
1276
574210
    file_ptr -> fx_file_current_file_offset =
1277
574210
        file_ptr -> fx_file_current_file_offset + size;
1278
1279
    /* Copy the new file size into the directory entry.  */
1280
574210
    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
1281
574210
        file_ptr -> fx_file_current_file_size;
1282
1283
    /* Determine if this write was done past the previous file size.  */
1284
574210
    if (file_ptr -> fx_file_current_file_offset >
1285
574210
        file_ptr -> fx_file_current_file_size)
1286
    {
1287
1288
        /* Yes, we have written past the previous end of the file.  Update
1289
           the file size.  */
1290
574153
        file_ptr -> fx_file_current_file_size =  file_ptr -> fx_file_current_file_offset;
1291
1292
#ifndef FX_DONT_UPDATE_OPEN_FILES
1293
1294
        /* Search the opened files list to see if the same file is opened for reading.  */
1295
574153
        open_count =  media_ptr -> fx_media_opened_file_count;
1296
574153
        search_ptr =  media_ptr -> fx_media_opened_file_list;
1297
1460301
        while (open_count)
1298
        {
1299
1300
            /* Is this file the same file opened for reading?  */
1301
886148
            if ((search_ptr != file_ptr) &&
1302
311995
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
1303
311995
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
1304
301891
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
1305
301891
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
1306
            {
1307
1308
                /* Yes, the same file is opened for reading.  */
1309
1310
                /* Setup the new size.  */
1311
72878
                search_ptr -> fx_file_current_file_size =  file_ptr -> fx_file_current_file_offset;
1312
1313
                /* Setup the new directory entry.  */
1314
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =      file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
1315
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
1316
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector =   file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
1317
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset =  file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
1318
1319
                /* Setup the last cluster. This really isn't used during reading, but it is nice to keep things
1320
                   consistent.  */
1321
72878
                search_ptr -> fx_file_last_physical_cluster =  file_ptr -> fx_file_last_physical_cluster;
1322
1323
                /* Update the available clusters as well.  */
1324
72878
                search_ptr -> fx_file_current_available_size =  file_ptr -> fx_file_current_available_size;
1325
1326
                /* Determine if an empty file was previously opened.  */
1327
72878
                if (search_ptr -> fx_file_total_clusters == 0)
1328
                {
1329
1330
                    /* Setup initial parameters.  */
1331
10
                    search_ptr -> fx_file_total_clusters =            file_ptr -> fx_file_total_clusters;
1332
10
                    search_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
1333
10
                    search_ptr -> fx_file_current_relative_cluster =  0;
1334
10
                    search_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
1335
10
                        (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
1336
10
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
1337
10
                    search_ptr -> fx_file_current_relative_sector =   0;
1338
10
                    search_ptr -> fx_file_current_logical_offset =    0;
1339
10
                    search_ptr -> fx_file_current_file_offset =       0;
1340
                }
1341
            }
1342
1343
            /* Adjust the pointer and decrement the search count.  */
1344
886148
            search_ptr =  search_ptr -> fx_file_opened_next;
1345
886148
            open_count--;
1346
        }
1347
#endif
1348
    }
1349
1350
    /* Finally, mark this file as modified.  */
1351
574210
    file_ptr -> fx_file_modified =  FX_TRUE;
1352
1353
#ifdef FX_FAULT_TOLERANT_DATA
1354
1355
    /* Ensure that all file data is flushed out.  */
1356
1357
    /* Flush the internal logical sector cache.  */
1358
    _fx_utility_logical_sector_flush(media_ptr, 1, media_ptr -> fx_media_total_sectors, FX_FALSE);
1359
1360
    /* Lockout interrupts for time/date access.  */
1361
    FX_DISABLE_INTS
1362
1363
    /* Set the new time and date.  */
1364
    file_ptr -> fx_file_dir_entry.fx_dir_entry_time =  _fx_system_time;
1365
    file_ptr -> fx_file_dir_entry.fx_dir_entry_date =  _fx_system_date;
1366
1367
    /* Restore interrupts.  */
1368
    FX_RESTORE_INTS
1369
1370
#ifdef FX_ENABLE_FAULT_TOLERANT
1371
    if (media_ptr -> fx_media_fault_tolerant_enabled)
1372
    {
1373
1374
        /* Copy the new file size into the directory entry.  */
1375
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
1376
    }
1377
#endif /* FX_ENABLE_FAULT_TOLERANT */
1378
1379
    /* Write the directory entry to the media.  */
1380
    status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
1381
1382
    /* Check for a good status.  */
1383
    if (status != FX_SUCCESS)
1384
    {
1385
#ifdef FX_ENABLE_FAULT_TOLERANT
1386
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1387
#endif /* FX_ENABLE_FAULT_TOLERANT */
1388
1389
        /* Release media protection.  */
1390
        FX_UNPROTECT
1391
1392
        /* Error writing the directory.  */
1393
        return(status);
1394
    }
1395
#endif
1396
1397
    /* Update the trace event with the bytes written.  */
1398
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_WRITE, 0, 0, 0, size)
1399
1400
#ifdef FX_ENABLE_FAULT_TOLERANT
1401
    /* End transaction. */
1402
    status = _fx_fault_tolerant_transaction_end(media_ptr);
1403
1404
    /* Check for a bad status.  */
1405
    if (status != FX_SUCCESS)
1406
    {
1407
1408
        /* Release media protection.  */
1409
        FX_UNPROTECT
1410
1411
        /* Return the bad status.  */
1412
        return(status);
1413
    }
1414
1415
    /* Update maximum size used if necessary. */
1416
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_maximum_size_used)
1417
    {
1418
        file_ptr -> fx_file_maximum_size_used = file_ptr -> fx_file_current_file_offset;
1419
    }
1420
#endif /* FX_ENABLE_FAULT_TOLERANT */
1421
1422
    /* Invoke file write callback. */
1423
574210
    if (file_ptr -> fx_file_write_notify)
1424
    {
1425
1
        file_ptr -> fx_file_write_notify(file_ptr);
1426
    }
1427
1428
    /* Release media protection.  */
1429
574210
    FX_UNPROTECT
1430
1431
    /* Return a successful status to the caller.  */
1432
574210
    return(FX_SUCCESS);
1433
}
1434