GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_write.c Lines: 222 222 100.0 %
Date: 2026-03-06 18:49:02 Branches: 106 106 100.0 %

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

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

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