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