GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_file_write.c Lines: 222 222 100.0 %
Date: 2024-01-10 21:53:23 Branches: 106 106 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
10
/**************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   File                                                                */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
/* 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_exFAT_bitmap_flush        Flush exFAT allocation bitmap */
68
/*    _fx_utility_exFAT_bitmap_free_cluster_find                          */
69
/*                                          Find exFAT free cluster       */
70
/*    _fx_utility_exFAT_cluster_state_get   Get cluster state             */
71
/*    _fx_utility_exFAT_cluster_state_set   Set cluster state             */
72
/*    _fx_utility_FAT_entry_read            Read a FAT entry              */
73
/*    _fx_utility_FAT_entry_write           Write a FAT entry             */
74
/*    _fx_utility_FAT_flush                 Flush written FAT entries     */
75
/*    _fx_utility_logical_sector_flush      Flush written logical sectors */
76
/*    _fx_utility_logical_sector_read       Read a logical sector         */
77
/*    _fx_utility_logical_sector_write      Write a logical sector        */
78
/*    _fx_utility_memory_copy               Fast memory copy routine      */
79
/*    _fx_fault_tolerant_transaction_start  Start fault tolerant          */
80
/*                                            transaction                 */
81
/*    _fx_fault_tolerant_transaction_end    End fault tolerant transaction*/
82
/*    _fx_fault_tolerant_recover            Recover FAT chain             */
83
/*    _fx_fault_tolerant_reset_log_file     Reset the log file            */
84
/*    _fx_fault_tolerant_set_FAT_chain      Set data of FAT chain         */
85
/*                                                                        */
86
/*  CALLED BY                                                             */
87
/*                                                                        */
88
/*    Application Code                                                    */
89
/*                                                                        */
90
/*  RELEASE HISTORY                                                       */
91
/*                                                                        */
92
/*    DATE              NAME                      DESCRIPTION             */
93
/*                                                                        */
94
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
95
/*  09-30-2020     William E. Lamie         Modified comment(s), verified */
96
/*                                            memcpy usage,               */
97
/*                                            resulting in version 6.1    */
98
/*                                                                        */
99
/**************************************************************************/
100
599766
UINT  _fx_file_write(FX_FILE *file_ptr, VOID *buffer_ptr, ULONG size)
101
{
102
103
UINT                   status;
104
ULONG64                bytes_remaining;
105
ULONG                  i;
106
ULONG                  copy_bytes;
107
ULONG                  bytes_per_cluster;
108
UCHAR                 *source_ptr;
109
ULONG                  first_new_cluster;
110
ULONG                  last_cluster;
111
ULONG                  cluster, next_cluster;
112
ULONG                  FAT_index;
113
ULONG                  FAT_value;
114
ULONG                  clusters;
115
ULONG                  total_clusters;
116
UINT                   sectors;
117
FX_MEDIA              *media_ptr;
118
119
#ifdef FX_ENABLE_EXFAT
120
UCHAR                  cluster_state;
121
#endif /* FX_ENABLE_EXFAT */
122
123
#ifdef FX_FAULT_TOLERANT_DATA
124
FX_INT_SAVE_AREA
125
#endif
126
127
#ifndef FX_DONT_UPDATE_OPEN_FILES
128
ULONG                  open_count;
129
FX_FILE               *search_ptr;
130
#endif
131
132
#ifdef TX_ENABLE_EVENT_TRACE
133
TX_TRACE_BUFFER_ENTRY *trace_event;
134
ULONG                  trace_timestamp;
135
#endif
136
137
#ifdef FX_ENABLE_FAULT_TOLERANT
138
UCHAR                  data_append = FX_FALSE;      /* Whether or not new data would extend beyond the size of the original file.
139
                                                      Operations such as append or overwrite could cause the new file to exceed its
140
                                                      original size, resulting in data-appending operation. */
141
ULONG                  copy_head_cluster = 0;       /* The first cluster of the original chain that needs to be replaced. */
142
ULONG                  copy_tail_cluster = 0;       /* The last cluster of the original chain that needs to be replaced. */
143
ULONG                  insertion_back;              /* The insertion point (back) */
144
ULONG                  insertion_front = 0;         /* The insertion point (front) */
145
ULONG                  replace_clusters = 0;        /* The number of clusters to be replaced. */
146
UCHAR                  dont_use_fat_old = FX_FALSE; /* Used by exFAT logic to indicate whether or not the FAT table should be used. */
147
#endif /* FX_ENABLE_FAULT_TOLERANT */
148
149
150
    /* First, determine if the file is still open.  */
151
599766
    if (file_ptr -> fx_file_id != FX_FILE_ID)
152
    {
153
154
        /* Return the file not open error status.  */
155
1
        return(FX_NOT_OPEN);
156
    }
157
158
    /* Setup pointer to media structure.  */
159
599765
    media_ptr =  file_ptr -> fx_file_media_ptr;
160
161
#ifndef FX_MEDIA_STATISTICS_DISABLE
162
163
    /* Increment the number of times this service has been called.  */
164
599765
    media_ptr -> fx_media_file_writes++;
165
#endif
166
167
168
#ifdef FX_ENABLE_EXFAT
169
    if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
170
        (file_ptr -> fx_file_current_file_offset + size > 0xFFFFFFFFULL))
171
#else
172
599765
    if (file_ptr -> fx_file_current_file_offset + size > 0xFFFFFFFFULL)
173
#endif /* FX_ENABLE_EXFAT */
174
    {
175
176
        /* Return the no more space error, since the new file size would be larger than
177
           the 32-bit field to represent it in the file's directory entry.  */
178
1
        return(FX_NO_MORE_SPACE);
179
    }
180
181
#ifdef FX_ENABLE_FAULT_TOLERANT
182
    /* Initialize next cluster of tail. */
183
    insertion_back = media_ptr -> fx_media_fat_last;
184
#endif /* FX_ENABLE_FAULT_TOLERANT */
185
186
    /* If trace is enabled, insert this event into the trace buffer.  */
187
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_WRITE, file_ptr, buffer_ptr, size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
188
189
    /* Protect against other threads accessing the media.  */
190
599764
    FX_PROTECT
191
192
    /* Check for write protect at the media level (set by driver).  */
193
599764
    if (media_ptr -> fx_media_driver_write_protect)
194
    {
195
196
        /* Release media protection.  */
197
1
        FX_UNPROTECT
198
199
        /* Return write protect error.  */
200
1
        return(FX_WRITE_PROTECT);
201
    }
202
203
    /* Make sure this file is open for writing.  */
204
599763
    if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
205
    {
206
207
        /* Release media protection.  */
208
1
        FX_UNPROTECT
209
210
        /* Return the access error exception - a write was attempted from
211
           a file opened for reading!  */
212
1
        return(FX_ACCESS_ERROR);
213
    }
214
215
#ifdef FX_ENABLE_FAULT_TOLERANT
216
217
    /* Start transaction. */
218
    _fx_fault_tolerant_transaction_start(media_ptr);
219
#endif /* FX_ENABLE_FAULT_TOLERANT */
220
221
    /* Calculate the number of bytes per cluster.  */
222
599762
    bytes_per_cluster =  ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
223
599762
        ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
224
225
    /* Check for invalid value.  */
226
599762
    if (bytes_per_cluster == 0)
227
    {
228
229
#ifdef FX_ENABLE_FAULT_TOLERANT
230
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
231
#endif /* FX_ENABLE_FAULT_TOLERANT */
232
233
        /* Release media protection.  */
234
1
        FX_UNPROTECT
235
236
        /* Invalid media, return error.  */
237
1
        return(FX_MEDIA_INVALID);
238
    }
239
240
    /* Initialized first new cluster. */
241
599761
    first_new_cluster =  0;
242
243
#ifdef FX_ENABLE_FAULT_TOLERANT
244
    /* Calculate clusters need to be replaced when fault tolerant is enabled. */
245
    if (media_ptr -> fx_media_fault_tolerant_enabled)
246
    {
247
248
        if (file_ptr -> fx_file_current_file_offset == file_ptr -> fx_file_current_file_size)
249
        {
250
251
            /* Appending data. No need to replace existing clusters. */
252
            replace_clusters = 0;
253
        }
254
        else if (file_ptr -> fx_file_current_file_offset == file_ptr -> fx_file_maximum_size_used)
255
        {
256
257
            /* Similar to append data. No actual data after fx_file_maximum_size_used.
258
             * No need to replace existing clusters. */
259
            replace_clusters = 0;
260
        }
261
        else if (((file_ptr -> fx_file_current_file_offset / media_ptr -> fx_media_bytes_per_sector) ==
262
                 ((file_ptr -> fx_file_current_file_offset + size - 1) / media_ptr -> fx_media_bytes_per_sector)) &&
263
                 ((file_ptr -> fx_file_current_file_offset + size) <= file_ptr -> fx_file_current_file_size))
264
        {
265
266
            /* Overwriting data in one sector. No need to replace existing clusters. */
267
            replace_clusters = 0;
268
        }
269
        else if ((file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset) < size)
270
        {
271
272
            /* Replace all clusters from current_cluster. */
273
            replace_clusters = (UINT)(file_ptr -> fx_file_total_clusters - file_ptr -> fx_file_current_relative_cluster);
274
            copy_head_cluster = file_ptr -> fx_file_current_physical_cluster;
275
276
            data_append = FX_TRUE;
277
        }
278
        else
279
        {
280
281
            /* Replace clusters from current_cluster to the end of written cluster. */
282
            replace_clusters = (UINT)((file_ptr -> fx_file_current_file_offset + size + bytes_per_cluster - 1) / bytes_per_cluster -
283
                                      file_ptr -> fx_file_current_relative_cluster);
284
            copy_head_cluster = file_ptr -> fx_file_current_physical_cluster;
285
            data_append = FX_FALSE;
286
        }
287
    }
288
#endif /* FX_ENABLE_FAULT_TOLERANT */
289
290
    /* Next, determine if there is enough room to write the specified number of
291
       bytes to the clusters already allocated to this file.  */
292
599761
    if (((file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset) < size)
293
#ifdef FX_ENABLE_FAULT_TOLERANT
294
        || (replace_clusters)
295
#endif /* FX_ENABLE_FAULT_TOLERANT */
296
       )
297
    {
298
299
        /* The new request will not fit within the currently allocated clusters.  */
300
301
        /* Calculate the number of additional clusters that must be allocated for this
302
           write request.  */
303
#ifdef FX_ENABLE_FAULT_TOLERANT
304
        /* Find the number of clusters that need to be replaced. */
305
        if (media_ptr -> fx_media_fault_tolerant_enabled)
306
        {
307
308
            /* Mark the recovery phase. */
309
            media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
310
311
            bytes_remaining = file_ptr -> fx_file_current_file_offset + size;
312
313
            if (replace_clusters > 0)
314
            {
315
316
#ifdef FX_ENABLE_EXFAT
317
                if ((media_ptr -> fx_media_FAT_type == FX_exFAT) && (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
318
                {
319
                    /* Find the insertion points in the exFAT with bitmap case.. this is a simple case.. */
320
                    /* The previous cluster is not initialized. Find it. */
321
                    if (copy_head_cluster != file_ptr -> fx_file_first_physical_cluster)
322
                    {
323
                        insertion_front = copy_head_cluster - 1;
324
                    }
325
326
                    /* Find copy tail cluster. */
327
                    if (data_append == FX_FALSE)
328
                    {
329
                        copy_tail_cluster = file_ptr -> fx_file_first_physical_cluster + (ULONG)((bytes_remaining - 1) / bytes_per_cluster);
330
                        if (copy_tail_cluster != file_ptr -> fx_file_last_physical_cluster)
331
                        {
332
                            insertion_back = copy_tail_cluster + 1;
333
                        }
334
                    }
335
                }
336
                else
337
                {
338
#endif /* FX_ENABLE_EXFAT */
339
340
                    /* Find previous cluster of copy head cluster. */
341
                    /* The previous cluster is not initialized. Find it. */
342
                    if (copy_head_cluster != file_ptr -> fx_file_first_physical_cluster)
343
                    {
344
345
                        /* The copy head cluster is not the first cluster of file. */
346
                        /* Copy head is not the first cluster of file. */
347
                        if (file_ptr -> fx_file_current_relative_cluster < file_ptr -> fx_file_consecutive_cluster)
348
                        {
349
350
                            /* Clusters before current cluster are consecutive. */
351
                            insertion_front = copy_head_cluster - 1;
352
                            bytes_remaining -= file_ptr -> fx_file_current_relative_cluster * bytes_per_cluster;
353
                        }
354
                        else
355
                        {
356
357
                            /* Skip consecutive clusters first. */
358
                            cluster = file_ptr -> fx_file_first_physical_cluster;
359
360
                            /* Loop the link of FAT to find the previous cluster. */
361
                            while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
362
                            {
363
364
                                /* Reduce remaining bytes. */
365
                                bytes_remaining -= bytes_per_cluster;
366
367
                                /* Read the current cluster entry from the FAT.  */
368
                                status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
369
370
                                /* Check the return value.  */
371
                                if (status != FX_SUCCESS)
372
                                {
373
374
                                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
375
376
                                    /* Release media protection.  */
377
                                    FX_UNPROTECT
378
379
                                    /* Return the error status.  */
380
                                    return(status);
381
                                }
382
383
                                if (FAT_value == copy_head_cluster)
384
                                {
385
                                    break;
386
                                }
387
388
                                /* Move to next cluster. */
389
                                cluster = FAT_value;
390
                            }
391
392
                            if ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
393
                            {
394
395
                                /* Find the previous cluster. */
396
                                insertion_front = cluster;
397
                            }
398
                            else
399
                            {
400
401
                                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
402
403
                                /* Release media protection.  */
404
                                FX_UNPROTECT
405
406
                                /* Return the error status.  */
407
                                return(FX_NOT_FOUND);
408
                            }
409
                        }
410
                    }
411
412
                    /* Find copy tail cluster. */
413
                    if (bytes_remaining <= bytes_per_cluster)
414
                    {
415
416
                        /* Only one cluster is modified. */
417
                        copy_tail_cluster = copy_head_cluster;
418
                    }
419
                    else if (data_append == FX_FALSE)
420
                    {
421
422
                        /* Search from copy head cluster. */
423
                        cluster = copy_head_cluster;
424
                        FAT_value = FX_FAT_ENTRY_START;
425
426
                        /* Loop the link of FAT to find the previous cluster. */
427
                        while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
428
                        {
429
430
                            if (bytes_remaining <= bytes_per_cluster)
431
                            {
432
                                break;
433
                            }
434
435
                            /* Reduce remaining bytes. */
436
                            bytes_remaining -= bytes_per_cluster;
437
438
                            /* Read the current cluster entry from the FAT.  */
439
                            status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
440
441
                            /* Check the return value.  */
442
                            if (status != FX_SUCCESS)
443
                            {
444
445
                                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
446
447
                                /* Release media protection.  */
448
                                FX_UNPROTECT
449
450
                                /* Return the error status.  */
451
                                return(status);
452
                            }
453
454
                            /* Move to next cluster. */
455
                            cluster = FAT_value;
456
                        }
457
458
                        /* Find the previous cluster. */
459
                        copy_tail_cluster = FAT_value;
460
                    }
461
462
                    /* Get the cluster next to copy tail. */
463
                    if (data_append == FX_FALSE)
464
                    {
465
466
                        /* Read FAT entry.  */
467
                        status =  _fx_utility_FAT_entry_read(media_ptr, copy_tail_cluster, &insertion_back);
468
469
                        /* Check for a bad status.  */
470
                        if (status != FX_SUCCESS)
471
                        {
472
473
                            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
474
475
                            /* Release media protection.  */
476
                            FX_UNPROTECT
477
478
                            /* Return the bad status.  */
479
                            return(status);
480
                        }
481
                    }
482
                    else
483
                    {
484
                        insertion_back = media_ptr -> fx_media_fat_last;
485
                    }
486
#ifdef FX_ENABLE_EXFAT
487
                }
488
#endif /* FX_ENABLE_EXFAT */
489
            }
490
            else
491
            {
492
                insertion_back = media_ptr -> fx_media_fat_last;
493
            }
494
        }
495
496
        if (file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset < size)
497
        {
498
#endif /* FX_ENABLE_FAULT_TOLERANT */
499
            /* Calculate clusters that are needed for data append except ones overwritten. */
500
59282
            clusters =  (UINT)((size + (bytes_per_cluster - 1) -
501
59282
                                (file_ptr -> fx_file_current_available_size - file_ptr -> fx_file_current_file_offset)) /
502
                               bytes_per_cluster);
503
#ifdef FX_ENABLE_FAULT_TOLERANT
504
        }
505
        else
506
        {
507
            clusters = 0;
508
        }
509
#endif /* FX_ENABLE_FAULT_TOLERANT */
510
511
        /* Determine if we have enough space left.  */
512
#ifdef FX_ENABLE_FAULT_TOLERANT
513
        if (clusters + replace_clusters > media_ptr -> fx_media_available_clusters)
514
#else
515
59282
        if (clusters > media_ptr -> fx_media_available_clusters)
516
#endif /* FX_ENABLE_FAULT_TOLERANT */
517
        {
518
519
#ifdef FX_ENABLE_FAULT_TOLERANT
520
            FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
521
#endif /* FX_ENABLE_FAULT_TOLERANT */
522
523
            /* Release media protection.  */
524
2
            FX_UNPROTECT
525
526
            /* Out of disk space.  */
527
2
            return(FX_NO_MORE_SPACE);
528
        }
529
530
        /* Update the file total cluster count.  */
531
59280
        file_ptr -> fx_file_total_clusters =  file_ptr -> fx_file_total_clusters + clusters;
532
533
        /* Check for wrap-around when updating the available size.  */
534
#ifdef FX_ENABLE_EXFAT
535
        if ((media_ptr -> fx_media_FAT_type != FX_exFAT) &&
536
            (file_ptr -> fx_file_current_available_size + (ULONG64)bytes_per_cluster * (ULONG64)clusters > 0xFFFFFFFFULL))
537
#else
538
59280
        if (file_ptr -> fx_file_current_available_size + (ULONG64)bytes_per_cluster * (ULONG64)clusters > 0xFFFFFFFFULL)
539
#endif /* FX_ENABLE_EXFAT */
540
        {
541
542
            /* 32-bit wrap around condition is present.  Just set the available file size to all ones, which is
543
               the maximum file size.  */
544
1
            file_ptr -> fx_file_current_available_size =  0xFFFFFFFFULL;
545
        }
546
        else
547
        {
548
549
            /* Normal condition, update the available size.  */
550
59279
            file_ptr -> fx_file_current_available_size =
551
59279
                file_ptr -> fx_file_current_available_size + (ULONG64)bytes_per_cluster * (ULONG64)clusters;
552
        }
553
554
#ifdef FX_ENABLE_FAULT_TOLERANT
555
        /* Account for newly allocated clusters. */
556
        clusters += replace_clusters;
557
#endif /* FX_ENABLE_FAULT_TOLERANT */
558
559
        /* Decrease the available clusters in the media control block. */
560
59280
        media_ptr -> fx_media_available_clusters =  media_ptr -> fx_media_available_clusters - clusters;
561
562
#if defined(FX_ENABLE_EXFAT) && defined(FX_ENABLE_FAULT_TOLERANT)
563
        /* Get dont_use_fat value. */
564
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
565
        {
566
            dont_use_fat_old = (UCHAR)file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat;
567
        }
568
#endif /* FX_ENABLE_EXFAT && FX_ENABLE_FAULT_TOLERANT */
569
570
        /* Search for the additional clusters we need.  */
571
59280
        total_clusters =     media_ptr -> fx_media_total_clusters;
572
573
#ifdef FX_ENABLE_FAULT_TOLERANT
574
        if (replace_clusters > 0)
575
        {
576
577
            /* Reset consecutive cluster. */
578
            file_ptr -> fx_file_consecutive_cluster = 1;
579
580
            last_cluster =   insertion_front;
581
582
#ifdef FX_ENABLE_EXFAT
583
            if ((file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1) &&
584
                (file_ptr -> fx_file_total_clusters > replace_clusters))
585
            {
586
587
                /* Now we should use FAT.  */
588
                file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Clear bit 0.  */
589
590
                /* Build FAT chain.  */
591
                for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < file_ptr -> fx_file_last_physical_cluster; ++i)
592
                {
593
594
                    status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
595
596
                    if (status != FX_SUCCESS)
597
                    {
598
599
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
600
601
                        /* Release media protection.  */
602
                        FX_UNPROTECT
603
604
                        /* Return the bad status.  */
605
                        return(status);
606
                    }
607
                }
608
609
                /* Write the last cluster FAT entry.  */
610
                status = _fx_utility_FAT_entry_write(media_ptr, i, FX_LAST_CLUSTER_exFAT);
611
                if (status != FX_SUCCESS)
612
                {
613
614
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
615
616
                    /* Release media protection.  */
617
                    FX_UNPROTECT
618
619
                    /* Return the bad status.  */
620
                    return(status);
621
                }
622
            }
623
#endif /* FX_ENABLE_EXFAT */
624
        }
625
        else
626
#endif /* FX_ENABLE_FAULT_TOLERANT */
627
        {
628
59280
            last_cluster =   file_ptr -> fx_file_last_physical_cluster;
629
        }
630
631
59280
        FAT_index    =       media_ptr -> fx_media_cluster_search_start;
632
633
        /* Loop to find the needed clusters.  */
634
122137
        while (clusters)
635
        {
636
637
            /* Decrease the cluster count.  */
638
65756
            clusters--;
639
#ifdef FX_ENABLE_EXFAT
640
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
641
            {
642
643
                /* Find a free cluster.  */
644
                if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
645
                {
646
647
                    if (last_cluster)
648
                    {
649
650
                        cluster_state = FX_EXFAT_BITMAP_CLUSTER_OCCUPIED;
651
                        FAT_index = last_cluster + 1;
652
653
                        if (FAT_index < media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START)
654
                        {
655
656
                            /* Get the state of the cluster.  */
657
                            status = _fx_utility_exFAT_cluster_state_get(media_ptr, FAT_index, &cluster_state);
658
659
                            if (status != FX_SUCCESS)
660
                            {
661
662
#ifdef FX_ENABLE_FAULT_TOLERANT
663
                                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
664
#endif /* FX_ENABLE_FAULT_TOLERANT */
665
666
                                /* Release media protection.  */
667
                                FX_UNPROTECT
668
669
                                /* Return the bad status.  */
670
                                return(status);
671
                            }
672
                        }
673
674
                        /* Check if we still can do not use FAT.  */
675
                        if (cluster_state == FX_EXFAT_BITMAP_CLUSTER_FREE)
676
                        {
677
678
                            /* Clusters are still consecutive.  */
679
                            file_ptr -> fx_file_consecutive_cluster++;
680
                        }
681
                        else
682
                        {
683
684
                            /* Now we should use FAT.  */
685
                            file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat &= (CHAR)0xfe; /* Clear bit 0.  */
686
687
                            /* Build FAT chain.  */
688
                            for (i = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster; i < last_cluster; ++i)
689
                            {
690
691
                                status = _fx_utility_FAT_entry_write(media_ptr, i, i + 1);
692
693
                                if (status != FX_SUCCESS)
694
                                {
695
696
#ifdef FX_ENABLE_FAULT_TOLERANT
697
                                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
698
#endif /* FX_ENABLE_FAULT_TOLERANT */
699
700
                                    /* Release media protection.  */
701
                                    FX_UNPROTECT
702
703
                                    /* Return the bad status.  */
704
                                    return(status);
705
                                }
706
                            }
707
708
                            /* Write the last cluster FAT entry.  */
709
                            status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FX_LAST_CLUSTER_exFAT);
710
                            if (status != FX_SUCCESS)
711
                            {
712
713
#ifdef FX_ENABLE_FAULT_TOLERANT
714
                                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
715
#endif /* FX_ENABLE_FAULT_TOLERANT */
716
717
                                /* Release media protection.  */
718
                                FX_UNPROTECT
719
720
                                /* Return the bad status.  */
721
                                return(status);
722
                            }
723
724
                            /* Find free cluster from exFAT media.  */
725
                            status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
726
                                                                                media_ptr -> fx_media_cluster_search_start,
727
                                                                                &FAT_index);
728
                        }
729
                    }
730
                    else
731
                    {
732
733
                        /* Find the first cluster for file.  */
734
                        status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
735
                                                                            media_ptr -> fx_media_cluster_search_start,
736
                                                                            &FAT_index);
737
                    }
738
                }
739
                else
740
                {
741
742
                    /* Find free cluster from exFAT media.  */
743
                    status = _fx_utility_exFAT_bitmap_free_cluster_find(media_ptr,
744
                                                                        media_ptr -> fx_media_cluster_search_start,
745
                                                                        &FAT_index);
746
                }
747
748
                if (status != FX_SUCCESS)
749
                {
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
                    FX_UNPROTECT
757
758
                    /* Return the bad status.  */
759
                    return(status);
760
                }
761
            }
762
            else
763
            {
764
#endif /* FX_ENABLE_EXFAT */
765
766
                /* Loop to find the first available cluster.  */
767
                do
768
                {
769
770
                    /* Make sure we stop looking after one pass through the FAT table.  */
771
68736
                    if (!total_clusters)
772
                    {
773
774
#ifdef FX_ENABLE_FAULT_TOLERANT
775
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
776
#endif /* FX_ENABLE_FAULT_TOLERANT */
777
778
                        /* Release media protection.  */
779
1
                        FX_UNPROTECT
780
781
                        /* Something is wrong with the media - the desired clusters were
782
                           not found in the FAT table.  */
783
1
                        return(FX_NO_MORE_SPACE);
784
                    }
785
786
                    /* Read FAT entry.  */
787
68735
                    status =  _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
788
789
                    /* Check for a bad status.  */
790
68735
                    if (status != FX_SUCCESS)
791
                    {
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
2897
                        FX_UNPROTECT
799
800
                        /* Return the bad status.  */
801
2897
                        return(status);
802
                    }
803
804
                    /* Decrement the total cluster count.  */
805
65838
                    total_clusters--;
806
807
                    /* Determine if the FAT entry is free.  */
808
65838
                    if (FAT_value == FX_FREE_CLUSTER)
809
                    {
810
811
                        /* Move cluster search pointer forward.  */
812
62858
                        media_ptr -> fx_media_cluster_search_start =  FAT_index + 1;
813
814
                        /* Determine if this needs to be wrapped.  */
815
62858
                        if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
816
                        {
817
818
                            /* Wrap the search to the beginning FAT entry.  */
819
17
                            media_ptr -> fx_media_cluster_search_start =  FX_FAT_ENTRY_START;
820
                        }
821
822
                        /* Break this loop.  */
823
62858
                        break;
824
                    }
825
                    else
826
                    {
827
828
                        /* FAT entry is not free... Advance the FAT index.  */
829
2980
                        FAT_index++;
830
831
                        /* Determine if we need to wrap the FAT index around.  */
832
2980
                        if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
833
                        {
834
835
                            /* Wrap the search to the beginning FAT entry.  */
836
1
                            FAT_index =  FX_FAT_ENTRY_START;
837
                        }
838
                    }
839
                } while (FX_TRUE);
840
#ifdef FX_ENABLE_EXFAT
841
            }
842
#endif /* FX_ENABLE_EXFAT */
843
844
            /* Determine if we have found the first new cluster yet.  */
845
62858
            if (first_new_cluster == 0)
846
            {
847
848
                /* Remember the first new cluster. */
849
56382
                first_new_cluster =  FAT_index;
850
851
#ifdef FX_ENABLE_FAULT_TOLERANT
852
                if (media_ptr -> fx_media_fault_tolerant_enabled)
853
                {
854
855
                    /* Set the undo log now. */
856
                    if (copy_head_cluster == 0)
857
                    {
858
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, dont_use_fat_old, file_ptr -> fx_file_current_physical_cluster,
859
                                                                  first_new_cluster, media_ptr -> fx_media_fat_last, media_ptr -> fx_media_fat_last);
860
                    }
861
#ifdef FX_ENABLE_EXFAT
862
                    else if (dont_use_fat_old && (insertion_back == media_ptr -> fx_media_fat_last))
863
                    {
864
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, dont_use_fat_old, insertion_front, first_new_cluster,
865
                                                                  copy_head_cluster, file_ptr -> fx_file_last_physical_cluster + 1);
866
                    }
867
#endif /* FX_ENABLE_EXFAT */
868
                    else
869
                    {
870
871
                        status = _fx_fault_tolerant_set_FAT_chain(media_ptr, dont_use_fat_old, insertion_front, first_new_cluster,
872
                                                                  copy_head_cluster, insertion_back);
873
                    }
874
875
                    /* Check for good completion status.  */
876
                    if (status !=  FX_SUCCESS)
877
                    {
878
879
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
880
881
                        /* Release media protection.  */
882
                        FX_UNPROTECT
883
884
                        /* Return the error status.  */
885
                        return(status);
886
                    }
887
                }
888
#endif /* FX_ENABLE_FAULT_TOLERANT */
889
            }
890
891
            /* Make a quick check to see if an empty, cluster-less file
892
               is being written to for the first time.  */
893
62858
            if (last_cluster)
894
            {
895
896
                /* Check for the file's cluster.  We won't perform this link until the
897
                   entire FAT chain is built.  */
898
56680
                if (last_cluster != file_ptr -> fx_file_last_physical_cluster)
899
                {
900
#ifdef FX_ENABLE_EXFAT
901
                    if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
902
#ifdef FX_ENABLE_FAULT_TOLERANT
903
                        || (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
904
#endif /* FX_ENABLE_FAULT_TOLERANT */
905
                       )
906
                    {
907
#endif /* FX_ENABLE_EXFAT */
908
909
                        /* Normal condition - link the last cluster with the new
910
                           found cluster.  */
911
6476
                        status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index);
912
#ifdef FX_ENABLE_EXFAT
913
                    }
914
#endif /* FX_ENABLE_EXFAT */
915
                }
916
917
                /* Check for a bad FAT write status.  */
918
56680
                if (status !=  FX_SUCCESS)
919
                {
920
921
#ifdef FX_ENABLE_FAULT_TOLERANT
922
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
923
#endif /* FX_ENABLE_FAULT_TOLERANT */
924
925
                    /* Release media protection.  */
926
1
                    FX_UNPROTECT
927
928
                    /* Return the bad status.  */
929
1
                    return(status);
930
                }
931
932
                /* Determine if we are adding a sector after a write filled the previously
933
                   allocated cluster exactly.  */
934
56679
                if ((file_ptr -> fx_file_current_relative_sector >=
935
56679
                     (media_ptr -> fx_media_sectors_per_cluster - 1)) &&
936
56586
                    (file_ptr -> fx_file_current_logical_offset >=
937
56586
                     media_ptr -> fx_media_bytes_per_sector))
938
                {
939
940
                    /* Yes, we need to adjust all of the pertinent file parameters for
941
                       writing into this newly allocated cluster.  */
942
36865
                    file_ptr -> fx_file_current_physical_cluster =  FAT_index;
943
36865
                    file_ptr -> fx_file_current_relative_cluster++;
944
36865
                    file_ptr -> fx_file_current_relative_sector =   0;
945
36865
                    file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
946
36865
                        (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
947
36865
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
948
36865
                    file_ptr -> fx_file_current_logical_offset =    0;
949
                }
950
            }
951
            else
952
            {
953
954
                /* This is the first cluster allocated for the file.  Just
955
                   remember it as being the first and setup the other file
956
                   pointers accordingly.  */
957
6178
                file_ptr -> fx_file_first_physical_cluster =    FAT_index;
958
6178
                file_ptr -> fx_file_current_physical_cluster =  FAT_index;
959
6178
                file_ptr -> fx_file_current_relative_cluster =  0;
960
6178
                file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
961
6178
                    (((ULONG64)(FAT_index - FX_FAT_ENTRY_START)) *
962
6178
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
963
#ifdef FX_ENABLE_FAULT_TOLERANT
964
                if (file_ptr -> fx_file_last_physical_cluster == 0)
965
#endif /* FX_ENABLE_FAULT_TOLERANT */
966
                {
967
6178
                    file_ptr -> fx_file_current_logical_offset =    0;
968
6178
                    file_ptr -> fx_file_current_file_offset =       0;
969
                }
970
971
                /* Also remember this as the first cluster in the directory
972
                   entry.  */
973
6178
                file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =  FAT_index;
974
            }
975
#ifdef FX_ENABLE_EXFAT
976
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
977
            {
978
979
                /* Update Bitmap */
980
                status = _fx_utility_exFAT_cluster_state_set(media_ptr, FAT_index, FX_EXFAT_BITMAP_CLUSTER_OCCUPIED);
981
982
                if (status !=  FX_SUCCESS)
983
                {
984
#ifdef FX_ENABLE_FAULT_TOLERANT
985
                    FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
986
#endif /* FX_ENABLE_FAULT_TOLERANT */
987
988
                    /* Release media protection.  */
989
                    FX_UNPROTECT
990
991
                    /* Return the bad status.  */
992
                    return(status);
993
                }
994
995
                /* Move cluster search pointer forward. */
996
                media_ptr -> fx_media_cluster_search_start = FAT_index + 1;
997
998
                /* Determine if this needs to be wrapped. */
999
                if (media_ptr -> fx_media_cluster_search_start >= media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START)
1000
                {
1001
1002
                    /* Wrap the search to the beginning FAT entry. */
1003
                    media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START;
1004
                }
1005
            }
1006
#endif /* FX_ENABLE_EXFAT */
1007
1008
            /* Otherwise, remember the new FAT index as the last.  */
1009
62857
            last_cluster =  FAT_index;
1010
1011
            /* Move to the next FAT entry.  */
1012
62857
            FAT_index =  media_ptr -> fx_media_cluster_search_start;
1013
        }
1014
#ifdef FX_ENABLE_EXFAT
1015
        if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
1016
#ifdef FX_ENABLE_FAULT_TOLERANT
1017
            || (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
1018
#endif /* FX_ENABLE_FAULT_TOLERANT */
1019
           )
1020
        {
1021
#endif /* FX_ENABLE_EXFAT */
1022
1023
#ifdef FX_ENABLE_FAULT_TOLERANT
1024
            if (media_ptr -> fx_media_fault_tolerant_enabled)
1025
            {
1026
1027
                /* Link the last cluster back to original FAT.  */
1028
                status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, insertion_back);
1029
            }
1030
            else
1031
#endif /* FX_ENABLE_FAULT_TOLERANT */
1032
            {
1033
1034
                /* Place an end-of-file marker on the last cluster.  */
1035
56381
                status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
1036
            }
1037
1038
            /* Check for a bad FAT write status.  */
1039
56381
            if (status !=  FX_SUCCESS)
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
1
                FX_UNPROTECT
1047
1048
                /* Return the bad status.  */
1049
1
                return(status);
1050
            }
1051
1052
#ifdef FX_ENABLE_EXFAT
1053
        }
1054
#endif /* FX_ENABLE_EXFAT */
1055
1056
        /* Determine if the file already had clusters.  */
1057
56380
        if (file_ptr -> fx_file_last_physical_cluster)
1058
        {
1059
#ifdef FX_ENABLE_EXFAT
1060
            if (!(file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1))
1061
            {
1062
#endif /* FX_ENABLE_EXFAT */
1063
1064
                /* Now, link the file's old last cluster to the first cluster of the new chain.  */
1065
#ifdef FX_ENABLE_FAULT_TOLERANT
1066
                if (insertion_front)
1067
                {
1068
                    status = _fx_utility_FAT_entry_write(media_ptr, insertion_front, first_new_cluster);
1069
                }
1070
                else if ((media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE) ||
1071
                         ((replace_clusters == 0) && (first_new_cluster)))
1072
                {
1073
                    status = _fx_utility_FAT_entry_write(media_ptr, file_ptr -> fx_file_last_physical_cluster, first_new_cluster);
1074
                }
1075
#else
1076
50204
                status = _fx_utility_FAT_entry_write(media_ptr, file_ptr -> fx_file_last_physical_cluster, first_new_cluster);
1077
#endif /* FX_ENABLE_FAULT_TOLERANT */
1078
1079
                /* Check for a bad FAT write status.  */
1080
50204
                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
1
                    FX_UNPROTECT
1088
1089
                    /* Return the bad status.  */
1090
1
                    return(status);
1091
                }
1092
#ifdef FX_ENABLE_EXFAT
1093
            }
1094
#endif /* FX_ENABLE_EXFAT */
1095
        }
1096
1097
#ifdef FX_FAULT_TOLERANT
1098
1099
#ifdef FX_ENABLE_EXFAT
1100
        if (media_ptr -> fx_media_FAT_type == FX_exFAT)
1101
        {
1102
1103
            /* Flush exFAT bitmap.  */
1104
            _fx_utility_exFAT_bitmap_flush(media_ptr);
1105
        }
1106
#endif /* FX_ENABLE_EXFAT */
1107
1108
        /* Ensure the new FAT chain is properly written to the media.  */
1109
1110
        /* Flush the cached individual FAT entries */
1111
        _fx_utility_FAT_flush(media_ptr);
1112
#endif
1113
1114
#ifdef FX_ENABLE_FAULT_TOLERANT
1115
        if (media_ptr -> fx_media_fault_tolerant_enabled)
1116
        {
1117
1118
            /* Clear undo phase. */
1119
            media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
1120
1121
            /* Update the last cluster? */
1122
            if (insertion_back == media_ptr -> fx_media_fat_last)
1123
            {
1124
1125
                /* Yes. Update the file control block with the last physical cluster.  */
1126
                file_ptr -> fx_file_last_physical_cluster =  last_cluster;
1127
            }
1128
        }
1129
        else
1130
#endif /* FX_ENABLE_FAULT_TOLERANT */
1131
        {
1132
1133
            /* Update the file control block with the last physical cluster.  */
1134
56379
            file_ptr -> fx_file_last_physical_cluster =  last_cluster;
1135
        }
1136
    }
1137
1138
    /* Check for a need to increment to the next sector within a previously
1139
       allocated cluster.  */
1140
596858
    if (file_ptr -> fx_file_current_logical_offset >=
1141
596858
        media_ptr -> fx_media_bytes_per_sector)
1142
    {
1143
1144
        /* Update the sector specific file parameters to start at the
1145
           next logical sector.  */
1146
4675
        file_ptr -> fx_file_current_logical_sector++;
1147
4675
        file_ptr -> fx_file_current_relative_sector++;
1148
4675
        file_ptr -> fx_file_current_logical_offset =  0;
1149
    }
1150
1151
    /* At this point there is enough room to perform the file write operation.  */
1152
1153
    /* Setup local buffer pointer.  */
1154
596858
    source_ptr =  (UCHAR *)buffer_ptr;
1155
1156
    /* Setup the remaining number of bytes to write.  */
1157
596858
    bytes_remaining =  size;
1158
1159
#ifdef FX_ENABLE_FAULT_TOLERANT
1160
    if (replace_clusters > 0)
1161
    {
1162
1163
        /* Force update current cluster and sector. */
1164
        file_ptr -> fx_file_current_physical_cluster = first_new_cluster;
1165
        file_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
1166
            (((ULONG64)(first_new_cluster - FX_FAT_ENTRY_START)) *
1167
             ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
1168
            file_ptr -> fx_file_current_relative_sector;
1169
1170
        /* Copy sectors in replaced cluster but not overwritten at the front. */
1171
        for (i = 0; i < file_ptr -> fx_file_current_relative_sector; i++)
1172
        {
1173
            status =  _fx_utility_logical_sector_read(media_ptr,
1174
                                                      ((ULONG)media_ptr -> fx_media_data_sector_start) +
1175
                                                      (((ULONG)(copy_head_cluster - FX_FAT_ENTRY_START)) *
1176
                                                       ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1177
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1178
1179
            /* Check for good completion status.  */
1180
            if (status !=  FX_SUCCESS)
1181
            {
1182
1183
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1184
1185
                /* Release media protection.  */
1186
                FX_UNPROTECT
1187
1188
                /* Return the error status.  */
1189
                return(status);
1190
            }
1191
1192
            /* Write back the current logical sector.  */
1193
            status =  _fx_utility_logical_sector_write(media_ptr,
1194
                                                       ((ULONG)media_ptr -> fx_media_data_sector_start) +
1195
                                                       (((ULONG)(file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START)) *
1196
                                                        ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1197
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1198
1199
            /* Check for good completion status.  */
1200
            if (status !=  FX_SUCCESS)
1201
            {
1202
1203
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1204
1205
                /* Release media protection.  */
1206
                FX_UNPROTECT
1207
1208
                /* Return the error status.  */
1209
                return(status);
1210
            }
1211
        }
1212
    }
1213
#endif /* FX_ENABLE_FAULT_TOLERANT */
1214
1215
    /* Loop to write all of the bytes.  */
1216
1152964
    while (bytes_remaining)
1217
    {
1218
1219
        /* Determine if a beginning or ending partial write is required.  */
1220
615983
        if ((file_ptr -> fx_file_current_logical_offset) ||
1221
88327
            (bytes_remaining < media_ptr -> fx_media_bytes_per_sector))
1222
        {
1223
1224
            /* A partial sector write is required.  */
1225
1226
            /* Read the current logical sector.  */
1227
#ifdef FX_ENABLE_FAULT_TOLERANT
1228
            if (replace_clusters > 0)
1229
            {
1230
                if (file_ptr -> fx_file_current_physical_cluster == first_new_cluster)
1231
                {
1232
1233
                    /* It's at beginning. */
1234
                    status =  _fx_utility_logical_sector_read(media_ptr,
1235
                                                              ((ULONG)media_ptr -> fx_media_data_sector_start) +
1236
                                                              (((ULONG)(copy_head_cluster - FX_FAT_ENTRY_START)) *
1237
                                                               ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
1238
                                                              file_ptr -> fx_file_current_relative_sector,
1239
                                                              media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DATA_SECTOR);
1240
                }
1241
                else if (data_append == FX_FALSE)
1242
                {
1243
1244
                    /* It's at ending. */
1245
                    status =  _fx_utility_logical_sector_read(media_ptr,
1246
                                                              ((ULONG)media_ptr -> fx_media_data_sector_start) +
1247
                                                              (((ULONG)(copy_tail_cluster - FX_FAT_ENTRY_START)) *
1248
                                                               ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
1249
                                                              file_ptr -> fx_file_current_relative_sector,
1250
                                                              media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DATA_SECTOR);
1251
                }
1252
                else
1253
                {
1254
1255
                    /* It's at ending. */
1256
                    status =  _fx_utility_logical_sector_read(media_ptr,
1257
                                                              file_ptr -> fx_file_current_logical_sector,
1258
                                                              media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1259
                }
1260
            }
1261
            else
1262
#endif /* FX_ENABLE_FAULT_TOLERANT */
1263
            {
1264
582290
                status =  _fx_utility_logical_sector_read(media_ptr,
1265
                                                          file_ptr -> fx_file_current_logical_sector,
1266
582290
                                                          media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1267
            }
1268
1269
            /* Check for good completion status.  */
1270
582290
            if (status !=  FX_SUCCESS)
1271
            {
1272
#ifdef FX_ENABLE_FAULT_TOLERANT
1273
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1274
#endif /* FX_ENABLE_FAULT_TOLERANT */
1275
1276
                /* Release media protection.  */
1277
13365
                FX_UNPROTECT
1278
1279
                /* Return the error status.  */
1280
13365
                return(status);
1281
            }
1282
1283
            /* Copy the appropriate number of bytes into the destination buffer.  */
1284
568925
            copy_bytes =  media_ptr -> fx_media_bytes_per_sector -
1285
568925
                file_ptr -> fx_file_current_logical_offset;
1286
1287
            /* Check to see if only a portion of the sector needs to be
1288
               copied.  */
1289
568925
            if (copy_bytes > bytes_remaining)
1290
            {
1291
1292
                /* Adjust the number of bytes to copy.  */
1293
524833
                copy_bytes =  (ULONG)bytes_remaining;
1294
            }
1295
1296
            /* Actually perform the memory copy.  */
1297
568925
            _fx_utility_memory_copy(source_ptr, ((UCHAR *)media_ptr -> fx_media_memory_buffer) +  /* Use case of memcpy is verified. */
1298
568925
                                    file_ptr -> fx_file_current_logical_offset,
1299
                                    copy_bytes);
1300
1301
            /* Write back the current logical sector.  */
1302
568925
            status =  _fx_utility_logical_sector_write(media_ptr, file_ptr -> fx_file_current_logical_sector,
1303
568925
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1304
1305
            /* Check for good completion status.  */
1306
568925
            if (status !=  FX_SUCCESS)
1307
            {
1308
#ifdef FX_ENABLE_FAULT_TOLERANT
1309
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1310
#endif /* FX_ENABLE_FAULT_TOLERANT */
1311
1312
                /* Release media protection.  */
1313
4153
                FX_UNPROTECT
1314
1315
                /* Return the error status.  */
1316
4153
                return(status);
1317
            }
1318
1319
1320
            /* Increment the logical sector byte offset.  */
1321
564772
            file_ptr -> fx_file_current_logical_offset =
1322
564772
                file_ptr -> fx_file_current_logical_offset + copy_bytes;
1323
1324
            /* Adjust the remaining bytes to read.  */
1325
564772
            bytes_remaining =  bytes_remaining - copy_bytes;
1326
1327
            /* Adjust the pointer to the source buffer.  */
1328
564772
            source_ptr =  source_ptr + copy_bytes;
1329
        }
1330
        else
1331
        {
1332
1333
            /* Attempt to write multiple sectors directly to the media.  */
1334
1335
            /* Calculate the number of whole sectors to write.  */
1336
33693
            sectors =  (UINT)(bytes_remaining / media_ptr -> fx_media_bytes_per_sector);
1337
1338
33693
            next_cluster = cluster = file_ptr -> fx_file_current_physical_cluster;
1339
1340
33693
            for (i = (media_ptr -> fx_media_sectors_per_cluster -
1341
34204
                      file_ptr -> fx_file_current_relative_sector); i < sectors; i += media_ptr -> fx_media_sectors_per_cluster)
1342
            {
1343
#ifdef FX_ENABLE_EXFAT
1344
                if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
1345
                {
1346
                    cluster++;
1347
                }
1348
                else
1349
                {
1350
#endif /* FX_ENABLE_EXFAT */
1351
848
                    status =  _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
1352
1353
                    /* Determine if an error is present.  */
1354

848
                    if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
1355
673
                        (next_cluster > media_ptr -> fx_media_fat_reserved))
1356
                    {
1357
#ifdef FX_ENABLE_FAULT_TOLERANT
1358
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1359
#endif /* FX_ENABLE_FAULT_TOLERANT */
1360
1361
                        /* Release media protection.  */
1362
335
                        FX_UNPROTECT
1363
1364
                        /* Send error message back to caller.  */
1365
335
                        if (status != FX_SUCCESS)
1366
                        {
1367
174
                            return(status);
1368
                        }
1369
                        else
1370
                        {
1371
161
                            return(FX_FILE_CORRUPT);
1372
                        }
1373
                    }
1374
1375
513
                    if (next_cluster != cluster + 1)
1376
                    {
1377
2
                        break;
1378
                    }
1379
                    else
1380
                    {
1381
511
                        cluster = next_cluster;
1382
                    }
1383
#ifdef FX_ENABLE_EXFAT
1384
                }
1385
#endif /* FX_ENABLE_EXFAT */
1386
            }
1387
1388
33358
            if (i < sectors)
1389
            {
1390
2
                sectors = i;
1391
            }
1392
1393
            /* Perform the data write directly from the user's buffer of
1394
               the appropriate number of sectors.  */
1395
33358
            status =  _fx_utility_logical_sector_write(media_ptr, file_ptr -> fx_file_current_logical_sector,
1396
                                                       source_ptr, (ULONG) sectors, FX_DATA_SECTOR);
1397
1398
            /* Check for good completion status.  */
1399
33358
            if (status !=  FX_SUCCESS)
1400
            {
1401
#ifdef FX_ENABLE_FAULT_TOLERANT
1402
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1403
#endif /* FX_ENABLE_FAULT_TOLERANT */
1404
1405
                /* Release media protection.  */
1406
435
                FX_UNPROTECT
1407
1408
                /* Return the error status.  */
1409
435
                return(status);
1410
            }
1411
1412
            /* Now adjust the various file pointers.  */
1413
1414
            /* Increment the current logical sector.  Subtract one from
1415
               the sector count because we are going to use the logical
1416
               offset to do additional sector/cluster arithmetic below.  */
1417
32923
            file_ptr -> fx_file_current_logical_sector =
1418
32923
                file_ptr -> fx_file_current_logical_sector +
1419
32923
                (sectors - 1);
1420
1421
            /* Move the relative cluster and sector as well.  */
1422
32923
            file_ptr -> fx_file_current_relative_cluster = file_ptr -> fx_file_current_relative_cluster +
1423
32923
                (file_ptr -> fx_file_current_relative_sector + (sectors - 1)) /
1424
32923
                media_ptr -> fx_media_sectors_per_cluster;
1425
1426
32923
            file_ptr -> fx_file_current_relative_sector =
1427
32923
                (file_ptr -> fx_file_current_relative_sector + (sectors - 1)) %
1428
32923
                media_ptr -> fx_media_sectors_per_cluster;
1429
1430
            /* Increment the logical sector byte offset.  */
1431
32923
            file_ptr -> fx_file_current_logical_offset =
1432
32923
                media_ptr -> fx_media_bytes_per_sector;
1433
1434
32923
            file_ptr -> fx_file_current_physical_cluster = cluster;
1435
1436
            /* Adjust the remaining bytes.  */
1437
32923
            bytes_remaining =  bytes_remaining -
1438
32923
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
1439
1440
            /* Adjust the pointer to the source buffer.  */
1441
32923
            source_ptr =  source_ptr +
1442
32923
                (((ULONG)media_ptr -> fx_media_bytes_per_sector) * sectors);
1443
        }
1444
1445
        /* At this point, we have either written a partial sector or have successfully
1446
           written one or more whole sectors.  Determine if we are at the end of
1447
           the current logical sector.  */
1448
597695
        if (file_ptr -> fx_file_current_logical_offset >=
1449
597695
            media_ptr -> fx_media_bytes_per_sector)
1450
        {
1451
1452
            /* Determine if we are at the exact physical end of the file.  */
1453
76022
            if ((bytes_remaining == 0) &&
1454
55700
                ((file_ptr -> fx_file_current_file_offset + size) >=
1455
55700
                 file_ptr -> fx_file_current_available_size))
1456
            {
1457
1458
                /* Skip the following file parameter adjustments.  The next write will
1459
                   detect the logical offset out of the range of the sector and reset
1460
                   all of the pertinent information.  */
1461
37229
                break;
1462
            }
1463
1464
            /* We need to move to the next logical sector, but first
1465
               determine if the next logical sector is within the same
1466
               cluster.  */
1467
1468
            /* Increment the current relative sector in the cluster.  */
1469
38793
            file_ptr -> fx_file_current_relative_sector++;
1470
1471
            /* Determine if this is in a new cluster.  */
1472
38793
            if (file_ptr -> fx_file_current_relative_sector >=
1473
38793
                media_ptr -> fx_media_sectors_per_cluster)
1474
            {
1475
1476
                /* Yes, we need to move to the next cluster.  */
1477
#ifdef FX_ENABLE_EXFAT
1478
                if (file_ptr -> fx_file_dir_entry.fx_dir_entry_dont_use_fat & 1)
1479
                {
1480
1481
                    next_cluster = file_ptr -> fx_file_current_physical_cluster + 1;
1482
                }
1483
                else
1484
                {
1485
#endif /* FX_ENABLE_EXFAT */
1486
1487
                    /* Read the FAT entry of the current cluster to find
1488
                       the next cluster.  */
1489
24692
                    status =  _fx_utility_FAT_entry_read(media_ptr,
1490
                                                         file_ptr -> fx_file_current_physical_cluster, &next_cluster);
1491
1492
                    /* Determine if an error is present.  */
1493

24692
                    if ((status != FX_SUCCESS) || (next_cluster < FX_FAT_ENTRY_START) ||
1494
23907
                        (next_cluster > media_ptr -> fx_media_fat_reserved))
1495
                    {
1496
#ifdef FX_ENABLE_FAULT_TOLERANT
1497
                        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1498
#endif /* FX_ENABLE_FAULT_TOLERANT */
1499
1500
                        /* Release media protection.  */
1501
4360
                        FX_UNPROTECT
1502
1503
                        /* Send error message back to caller.  */
1504
4360
                        if (status != FX_SUCCESS)
1505
                        {
1506
784
                            return(status);
1507
                        }
1508
                        else
1509
                        {
1510
3576
                            return(FX_FILE_CORRUPT);
1511
                        }
1512
                    }
1513
#ifdef FX_ENABLE_EXFAT
1514
                }
1515
#endif /* FX_ENABLE_EXFAT */
1516
1517
                /* Otherwise, we have a new cluster.  Save it in the file
1518
                   control block and calculate a new logical sector value.  */
1519
20332
                file_ptr -> fx_file_current_physical_cluster =  next_cluster;
1520
20332
                file_ptr -> fx_file_current_relative_cluster++;
1521
20332
                file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
1522
20332
                    ((((ULONG64)next_cluster) - FX_FAT_ENTRY_START) *
1523
20332
                     ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
1524
20332
                file_ptr -> fx_file_current_relative_sector =  0;
1525
            }
1526
            else
1527
            {
1528
1529
                /* Still within the same cluster so just increment the
1530
                   logical sector.  */
1531
14101
                file_ptr -> fx_file_current_logical_sector++;
1532
            }
1533
1534
            /* In either case, we are now positioned at a new sector so
1535
               clear the logical sector offset.  */
1536
34433
            file_ptr -> fx_file_current_logical_offset =  0;
1537
        }
1538
    }
1539
1540
#ifdef FX_ENABLE_FAULT_TOLERANT
1541
    if (((replace_clusters > 0) && (data_append == FX_FALSE)) &&
1542
        (file_ptr -> fx_file_current_logical_offset || file_ptr -> fx_file_current_relative_sector))
1543
    {
1544
1545
        /* Copy sectors in replaced cluster but not overwritten at the end. */
1546
        if (file_ptr -> fx_file_current_logical_offset == 0)
1547
        {
1548
            i = file_ptr -> fx_file_current_relative_sector;
1549
        }
1550
        else
1551
        {
1552
            i = file_ptr -> fx_file_current_relative_sector + 1;
1553
        }
1554
        for (; i < media_ptr -> fx_media_sectors_per_cluster; i++)
1555
        {
1556
            status =  _fx_utility_logical_sector_read(media_ptr,
1557
                                                      ((ULONG)media_ptr -> fx_media_data_sector_start) +
1558
                                                      (((ULONG)(copy_tail_cluster - FX_FAT_ENTRY_START)) *
1559
                                                       ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1560
                                                      media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1561
1562
            /* Check for good completion status.  */
1563
            if (status !=  FX_SUCCESS)
1564
            {
1565
1566
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1567
1568
                /* Release media protection.  */
1569
                FX_UNPROTECT
1570
1571
                /* Return the error status.  */
1572
                return(status);
1573
            }
1574
1575
            /* Write back the current logical sector.  */
1576
            status =  _fx_utility_logical_sector_write(media_ptr,
1577
                                                       ((ULONG)media_ptr -> fx_media_data_sector_start) +
1578
                                                       (((ULONG)(file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START)) *
1579
                                                        ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) + i,
1580
                                                       media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DATA_SECTOR);
1581
1582
            /* Check for good completion status.  */
1583
            if (status !=  FX_SUCCESS)
1584
            {
1585
1586
                FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1587
1588
                /* Release media protection.  */
1589
                FX_UNPROTECT
1590
1591
                /* Return the error status.  */
1592
                return(status);
1593
            }
1594
        }
1595
    }
1596
#endif /* FX_ENABLE_FAULT_TOLERANT */
1597
1598
    /* Adjust the current file offset accordingly.  */
1599
574210
    file_ptr -> fx_file_current_file_offset =
1600
574210
        file_ptr -> fx_file_current_file_offset + size;
1601
1602
    /* Copy the new file size into the directory entry.  */
1603
574210
    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
1604
574210
        file_ptr -> fx_file_current_file_size;
1605
1606
    /* Determine if this write was done past the previous file size.  */
1607
574210
    if (file_ptr -> fx_file_current_file_offset >
1608
574210
        file_ptr -> fx_file_current_file_size)
1609
    {
1610
1611
        /* Yes, we have written past the previous end of the file.  Update
1612
           the file size.  */
1613
574153
        file_ptr -> fx_file_current_file_size =  file_ptr -> fx_file_current_file_offset;
1614
1615
#ifndef FX_DONT_UPDATE_OPEN_FILES
1616
1617
        /* Search the opened files list to see if the same file is opened for reading.  */
1618
574153
        open_count =  media_ptr -> fx_media_opened_file_count;
1619
574153
        search_ptr =  media_ptr -> fx_media_opened_file_list;
1620
1460301
        while (open_count)
1621
        {
1622
1623
            /* Is this file the same file opened for reading?  */
1624
886148
            if ((search_ptr != file_ptr) &&
1625
311995
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
1626
311995
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
1627
301891
                (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
1628
301891
                 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
1629
            {
1630
1631
                /* Yes, the same file is opened for reading.  */
1632
1633
                /* Setup the new size.  */
1634
72878
                search_ptr -> fx_file_current_file_size =  file_ptr -> fx_file_current_file_offset;
1635
1636
                /* Setup the new directory entry.  */
1637
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster =      file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
1638
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =    file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
1639
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector =   file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
1640
72878
                search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset =  file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
1641
1642
                /* Setup the last cluster. This really isn't used during reading, but it is nice to keep things
1643
                   consistent.  */
1644
72878
                search_ptr -> fx_file_last_physical_cluster =  file_ptr -> fx_file_last_physical_cluster;
1645
1646
                /* Update the available clusters as well.  */
1647
72878
                search_ptr -> fx_file_current_available_size =  file_ptr -> fx_file_current_available_size;
1648
1649
                /* Determine if an empty file was previously opened.  */
1650
72878
                if (search_ptr -> fx_file_total_clusters == 0)
1651
                {
1652
1653
                    /* Setup initial parameters.  */
1654
10
                    search_ptr -> fx_file_total_clusters =            file_ptr -> fx_file_total_clusters;
1655
10
                    search_ptr -> fx_file_current_physical_cluster =  file_ptr -> fx_file_first_physical_cluster;
1656
10
                    search_ptr -> fx_file_current_relative_cluster =  0;
1657
10
                    search_ptr -> fx_file_current_logical_sector =    ((ULONG)media_ptr -> fx_media_data_sector_start) +
1658
10
                        (((ULONG64)(file_ptr -> fx_file_first_physical_cluster - FX_FAT_ENTRY_START)) *
1659
10
                         ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
1660
10
                    search_ptr -> fx_file_current_relative_sector =   0;
1661
10
                    search_ptr -> fx_file_current_logical_offset =    0;
1662
10
                    search_ptr -> fx_file_current_file_offset =       0;
1663
                }
1664
            }
1665
1666
            /* Adjust the pointer and decrement the search count.  */
1667
886148
            search_ptr =  search_ptr -> fx_file_opened_next;
1668
886148
            open_count--;
1669
        }
1670
#endif
1671
    }
1672
1673
    /* Finally, mark this file as modified.  */
1674
574210
    file_ptr -> fx_file_modified =  FX_TRUE;
1675
1676
#ifdef FX_FAULT_TOLERANT_DATA
1677
1678
    /* Ensure that all file data is flushed out.  */
1679
1680
    /* Flush the internal logical sector cache.  */
1681
    _fx_utility_logical_sector_flush(media_ptr, 1, media_ptr -> fx_media_total_sectors, FX_FALSE);
1682
1683
    /* Lockout interrupts for time/date access.  */
1684
    FX_DISABLE_INTS
1685
1686
    /* Set the new time and date.  */
1687
    file_ptr -> fx_file_dir_entry.fx_dir_entry_time =  _fx_system_time;
1688
    file_ptr -> fx_file_dir_entry.fx_dir_entry_date =  _fx_system_date;
1689
1690
    /* Restore interrupts.  */
1691
    FX_RESTORE_INTS
1692
1693
#ifdef FX_ENABLE_FAULT_TOLERANT
1694
    if (media_ptr -> fx_media_fault_tolerant_enabled)
1695
    {
1696
1697
        /* Copy the new file size into the directory entry.  */
1698
        file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
1699
    }
1700
#endif /* FX_ENABLE_FAULT_TOLERANT */
1701
1702
    /* Write the directory entry to the media.  */
1703
#ifdef FX_ENABLE_EXFAT
1704
    if (media_ptr -> fx_media_FAT_type == FX_exFAT)
1705
    {
1706
1707
        status = _fx_directory_exFAT_entry_write(
1708
                media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
1709
    }
1710
    else
1711
    {
1712
#endif /* FX_ENABLE_EXFAT */
1713
        status =  _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
1714
#ifdef FX_ENABLE_EXFAT
1715
    }
1716
#endif /* FX_ENABLE_EXFAT */
1717
1718
    /* Check for a good status.  */
1719
    if (status != FX_SUCCESS)
1720
    {
1721
#ifdef FX_ENABLE_FAULT_TOLERANT
1722
        FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
1723
#endif /* FX_ENABLE_FAULT_TOLERANT */
1724
1725
        /* Release media protection.  */
1726
        FX_UNPROTECT
1727
1728
        /* Error writing the directory.  */
1729
        return(status);
1730
    }
1731
#endif
1732
1733
    /* Update the trace event with the bytes written.  */
1734
    FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_WRITE, 0, 0, 0, size)
1735
1736
#ifdef FX_ENABLE_FAULT_TOLERANT
1737
    /* End transaction. */
1738
    status = _fx_fault_tolerant_transaction_end(media_ptr);
1739
1740
    /* Check for a bad status.  */
1741
    if (status != FX_SUCCESS)
1742
    {
1743
1744
        /* Release media protection.  */
1745
        FX_UNPROTECT
1746
1747
        /* Return the bad status.  */
1748
        return(status);
1749
    }
1750
1751
    /* Update maximum size used if necessary. */
1752
    if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_maximum_size_used)
1753
    {
1754
        file_ptr -> fx_file_maximum_size_used = file_ptr -> fx_file_current_file_offset;
1755
    }
1756
#endif /* FX_ENABLE_FAULT_TOLERANT */
1757
1758
    /* Invoke file write callback. */
1759
574210
    if (file_ptr -> fx_file_write_notify)
1760
    {
1761
1
        file_ptr -> fx_file_write_notify(file_ptr);
1762
    }
1763
1764
    /* Release media protection.  */
1765
574210
    FX_UNPROTECT
1766
1767
    /* Return a successful status to the caller.  */
1768
574210
    return(FX_SUCCESS);
1769
}
1770