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