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
25 /* Include necessary system files. */
26
27 #include "fx_api.h"
28 #include "fx_system.h"
29 #include "fx_directory.h"
30 #include "fx_file.h"
31 #include "fx_utility.h"
32 #ifdef FX_ENABLE_FAULT_TOLERANT
33 #include "fx_fault_tolerant.h"
34 #endif /* FX_ENABLE_FAULT_TOLERANT */
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _fx_file_extended_truncate_release PORTABLE C */
42 /* 6.1.3 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function sets the file to the specified size, if smaller than */
50 /* the current file size. If the new file size is less than the */
51 /* current file read/write position, the internal file pointers will */
52 /* also be modified. Any unused clusters are released back to the */
53 /* media. */
54 /* */
55 /* INPUT */
56 /* */
57 /* file_ptr File control block pointer */
58 /* size New size of the file in bytes */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* return status */
63 /* */
64 /* CALLS */
65 /* */
66 /* _fx_directory_entry_write Write directory entry */
67 /* _fx_utility_FAT_entry_read Read a FAT entry */
68 /* _fx_utility_FAT_entry_write Write a FAT entry */
69 /* _fx_utility_FAT_flush Flush written FAT entries */
70 /* _fx_fault_tolerant_transaction_start Start fault tolerant */
71 /* transaction */
72 /* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
73 /* _fx_fault_tolerant_recover Recover FAT chain */
74 /* _fx_fault_tolerant_reset_log_file Reset the log file */
75 /* _fx_fault_tolerant_set_FAT_chain Set data of FAT chain */
76 /* */
77 /* CALLED BY */
78 /* */
79 /* Application Code */
80 /* */
81 /* RELEASE HISTORY */
82 /* */
83 /* DATE NAME DESCRIPTION */
84 /* */
85 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
86 /* 09-30-2020 William E. Lamie Modified comment(s), */
87 /* resulting in version 6.1 */
88 /* 12-31-2020 William E. Lamie Modified comment(s), fixed */
89 /* available cluster issue, */
90 /* resulting in version 6.1.3 */
91 /* */
92 /**************************************************************************/
_fx_file_extended_truncate_release(FX_FILE * file_ptr,ULONG64 size)93 UINT _fx_file_extended_truncate_release(FX_FILE *file_ptr, ULONG64 size)
94 {
95
96 UINT status;
97 ULONG cluster;
98 ULONG contents;
99 ULONG bytes_per_cluster;
100 ULONG last_cluster;
101 ULONG cluster_count;
102 ULONG64 bytes_remaining;
103 FX_MEDIA *media_ptr;
104
105
106 #ifndef FX_DONT_UPDATE_OPEN_FILES
107 ULONG open_count;
108 FX_FILE *search_ptr;
109 #endif
110
111 #ifdef TX_ENABLE_EVENT_TRACE
112 TX_TRACE_BUFFER_ENTRY *trace_event;
113 ULONG trace_timestamp;
114 #endif
115
116
117 /* First, determine if the file is still open. */
118 if (file_ptr -> fx_file_id != FX_FILE_ID)
119 {
120
121 /* Return the file not open error status. */
122 return(FX_NOT_OPEN);
123 }
124
125 #ifndef FX_MEDIA_STATISTICS_DISABLE
126 /* Setup pointer to media structure. */
127 media_ptr = file_ptr -> fx_file_media_ptr;
128
129 /* Increment the number of times this service has been called. */
130 media_ptr -> fx_media_file_truncate_releases++;
131 #endif
132
133 /* Setup pointer to associated media control block. */
134 media_ptr = file_ptr -> fx_file_media_ptr;
135
136 /* If trace is enabled, insert this event into the trace buffer. */
137 FX_TRACE_IN_LINE_INSERT(FX_TRACE_FILE_TRUNCATE_RELEASE, file_ptr, size, file_ptr -> fx_file_current_file_size, 0, FX_TRACE_FILE_EVENTS, &trace_event, &trace_timestamp)
138
139 /* Protect against other threads accessing the media. */
140 FX_PROTECT
141
142 #ifdef FX_ENABLE_FAULT_TOLERANT
143 /* Start transaction. */
144 _fx_fault_tolerant_transaction_start(media_ptr);
145 #endif /* FX_ENABLE_FAULT_TOLERANT */
146
147 /* Make sure this file is open for writing. */
148 if (file_ptr -> fx_file_open_mode != FX_OPEN_FOR_WRITE)
149 {
150
151 #ifdef FX_ENABLE_FAULT_TOLERANT
152 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
153 #endif /* FX_ENABLE_FAULT_TOLERANT */
154
155 /* Release media protection. */
156 FX_UNPROTECT
157
158 /* Return the access error exception - a write was attempted from
159 a file opened for reading! */
160 return(FX_ACCESS_ERROR);
161 }
162
163 /* Check for write protect at the media level (set by driver). */
164 if (media_ptr -> fx_media_driver_write_protect)
165 {
166
167 #ifdef FX_ENABLE_FAULT_TOLERANT
168 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
169 #endif /* FX_ENABLE_FAULT_TOLERANT */
170
171 /* Release media protection. */
172 FX_UNPROTECT
173
174 /* Return write protect error. */
175 return(FX_WRITE_PROTECT);
176 }
177
178 /* Calculate the number of bytes per cluster. */
179 bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
180 ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
181
182 /* Check for invalid value. */
183 if (bytes_per_cluster == 0)
184 {
185
186 #ifdef FX_ENABLE_FAULT_TOLERANT
187 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
188 #endif /* FX_ENABLE_FAULT_TOLERANT */
189
190 /* Release media protection. */
191 FX_UNPROTECT
192
193 /* Invalid media, return error. */
194 return(FX_MEDIA_INVALID);
195 }
196
197 /* Setup the new file available size - if less than the current available size. */
198 if (size < file_ptr -> fx_file_current_available_size)
199 {
200
201 /* Yes, the file needs to be truncated. */
202
203 /* Update the available file size. */
204 file_ptr -> fx_file_current_available_size = ((size + bytes_per_cluster - 1) / bytes_per_cluster) * bytes_per_cluster;
205
206 /* Is the new available size less than the actual file size? */
207 if (size < file_ptr -> fx_file_current_file_size)
208 {
209
210 /* Setup the new file size. */
211 file_ptr -> fx_file_current_file_size = size;
212
213 /* Set the modified flag. */
214 file_ptr -> fx_file_modified = FX_TRUE;
215
216 /* Copy the new file size into the directory entry. */
217 file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = size;
218
219 /* Set the first cluster to NULL. */
220 if (size == 0)
221 {
222
223 /* Yes, the first cluster needs to be cleared since the entire
224 file is going to be truncated. */
225 file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = FX_NULL;
226 }
227
228 /* Write the directory entry to the media. */
229 status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
230
231 /* Check for a good status. */
232 if (status != FX_SUCCESS)
233 {
234
235 #ifdef FX_ENABLE_FAULT_TOLERANT
236 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
237 #endif /* FX_ENABLE_FAULT_TOLERANT */
238
239 /* Release media protection. */
240 FX_UNPROTECT
241
242 /* Error writing the directory. */
243 return(status);
244 }
245 }
246
247 /* Update the trace event with the truncated size. */
248 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
249 }
250 else
251 {
252
253 /* Update the trace event with the truncated size. */
254 FX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, FX_TRACE_FILE_TRUNCATE_RELEASE, 0, 0, 0, file_ptr -> fx_file_current_file_size)
255
256 #ifdef FX_ENABLE_FAULT_TOLERANT
257 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
258 #endif /* FX_ENABLE_FAULT_TOLERANT */
259
260 /* Release media protection. */
261 FX_UNPROTECT
262
263 /* Just return, the truncate size is larger than the available size. */
264 return(FX_SUCCESS);
265 }
266
267 /* Calculate the number of bytes per cluster. */
268 bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
269 ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
270
271 /* Now check to see if the read/write internal file pointers need
272 to be adjusted. */
273 if (file_ptr -> fx_file_current_file_offset > file_ptr -> fx_file_current_file_size)
274 {
275
276
277 /* At this point, we are ready to walk list of clusters to setup the
278 seek position of this file. */
279 cluster = file_ptr -> fx_file_first_physical_cluster;
280 bytes_remaining = size;
281 last_cluster = 0;
282 cluster_count = 0;
283
284 /* Follow the link of FAT entries. */
285 while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
286 {
287
288 /* Increment the number of clusters. */
289 cluster_count++;
290
291
292 /* Read the current cluster entry from the FAT. */
293 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
294
295 /* Check the return value. */
296 if (status != FX_SUCCESS)
297 {
298
299 #ifdef FX_ENABLE_FAULT_TOLERANT
300 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
301 #endif /* FX_ENABLE_FAULT_TOLERANT */
302
303 /* Release media protection. */
304 FX_UNPROTECT
305
306 /* Return the error status. */
307 return(status);
308 }
309
310 /* Save the last valid cluster. */
311 last_cluster = cluster;
312
313 /* Setup for the next cluster. */
314 cluster = contents;
315
316 /* Determine if this is the last written cluster. */
317 if (bytes_remaining >= bytes_per_cluster)
318 {
319
320 /* Still more seeking, just decrement the working byte offset. */
321 bytes_remaining = bytes_remaining - bytes_per_cluster;
322 }
323 else
324 {
325
326 /* This is the cluster that contains the seek position. */
327 break;
328 }
329 }
330
331 /* Check for errors in traversal of the FAT chain. */
332 if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
333 {
334
335 #ifdef FX_ENABLE_FAULT_TOLERANT
336 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
337 #endif /* FX_ENABLE_FAULT_TOLERANT */
338
339 /* Release media protection. */
340 FX_UNPROTECT
341
342 /* This is an error that suggests a corrupt file. */
343 return(FX_FILE_CORRUPT);
344 }
345
346 /* Position the pointers to the new offset. */
347 file_ptr -> fx_file_current_physical_cluster = last_cluster;
348 file_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
349 file_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
350 (((ULONG64)file_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
351 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
352 (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
353 file_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
354 file_ptr -> fx_file_current_file_offset = size;
355 file_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
356 }
357
358 /* Determine how many clusters are actually in-use now. */
359 cluster_count = (ULONG) (file_ptr -> fx_file_current_available_size + (((ULONG64) bytes_per_cluster) - ((ULONG64) 1)))/bytes_per_cluster;
360
361 /* Save the number of clusters in-use. */
362 file_ptr -> fx_file_total_clusters = cluster_count;
363
364 /* At this point, we are ready to walk list of clusters to find the clusters
365 that can be released. */
366 cluster = file_ptr -> fx_file_first_physical_cluster;
367
368 #ifdef FX_ENABLE_FAULT_TOLERANT
369 /* Is this the last used cluster? */
370 if ((cluster_count == 0) && (media_ptr -> fx_media_fault_tolerant_enabled))
371 {
372
373 /* Set undo log. */
374 status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, FX_FREE_CLUSTER,
375 media_ptr -> fx_media_fat_last, cluster, media_ptr -> fx_media_fat_last);
376
377 /* Determine if the write was successful. */
378 if (status != FX_SUCCESS)
379 {
380
381 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
382
383 /* Release media protection. */
384 FX_UNPROTECT
385
386 /* Return the error code. */
387 return(status);
388 }
389
390 file_ptr -> fx_file_last_physical_cluster = cluster;
391 }
392 #endif /* FX_ENABLE_FAULT_TOLERANT */
393
394 /* Follow the link of FAT entries. */
395 while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
396 {
397
398 /* Read the current cluster entry from the FAT. */
399 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
400
401 /* Check the return value. */
402 if (status != FX_SUCCESS)
403 {
404
405 #ifdef FX_ENABLE_FAULT_TOLERANT
406 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
407 #endif /* FX_ENABLE_FAULT_TOLERANT */
408
409 /* Release media protection. */
410 FX_UNPROTECT
411
412 /* Return the error status. */
413 return(status);
414 }
415
416 /* Determine if are more clusters to release. */
417 if (cluster_count > 0)
418 {
419
420 /* Decrement the number of clusters. */
421 cluster_count--;
422
423 /* Is this the last used cluster? */
424 if (cluster_count == 0)
425 {
426 {
427
428 #ifdef FX_ENABLE_FAULT_TOLERANT
429 if (media_ptr -> fx_media_fault_tolerant_enabled)
430 {
431
432 /* Set undo phase. */
433 media_ptr -> fx_media_fault_tolerant_state |= FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN;
434
435 /* Read the current cluster entry from the FAT. */
436 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
437
438 /* Check the return value. */
439 if (status != FX_SUCCESS)
440 {
441
442 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
443
444 /* Release media protection. */
445 FX_UNPROTECT
446
447 /* Return the error status. */
448 return(status);
449 }
450
451 /* Set undo log. */
452 status = _fx_fault_tolerant_set_FAT_chain(media_ptr, FX_FALSE, cluster,
453 media_ptr -> fx_media_fat_last, contents, media_ptr -> fx_media_fat_last);
454
455 /* Determine if the write was successful. */
456 if (status != FX_SUCCESS)
457 {
458
459 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
460
461 /* Release media protection. */
462 FX_UNPROTECT
463
464 /* Return the error code. */
465 return(status);
466 }
467 }
468 #endif /* FX_ENABLE_FAULT_TOLERANT */
469
470 /* Yes, it should be designated as last cluster. */
471 status = _fx_utility_FAT_entry_write(media_ptr, cluster, media_ptr -> fx_media_fat_last);
472
473 /* Check the return value. */
474 if (status)
475 {
476
477 #ifdef FX_ENABLE_FAULT_TOLERANT
478 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
479 #endif /* FX_ENABLE_FAULT_TOLERANT */
480
481 /* Release media protection. */
482 FX_UNPROTECT
483
484 /* Return the error status. */
485 return(status);
486 }
487
488 #ifdef FX_ENABLE_FAULT_TOLERANT
489 if (media_ptr -> fx_media_fault_tolerant_enabled)
490 {
491
492 /* Clear undo phase. */
493 media_ptr -> fx_media_fault_tolerant_state &= (UCHAR)(~FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN & 0xff);
494 }
495 #endif /* FX_ENABLE_FAULT_TOLERANT */
496 }
497
498 file_ptr -> fx_file_last_physical_cluster = cluster;
499
500 #ifdef FX_FAULT_TOLERANT
501
502 /* Flush the cached individual FAT entries. */
503 status = _fx_utility_FAT_flush(media_ptr);
504
505 /* Check the return value. */
506 if (status)
507 {
508
509 #ifdef FX_ENABLE_FAULT_TOLERANT
510 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
511 #endif /* FX_ENABLE_FAULT_TOLERANT */
512
513 /* Release media protection. */
514 FX_UNPROTECT
515
516 /* Return the error status. */
517 return(status);
518 }
519 #endif
520 }
521 }
522 else
523 {
524
525 /* This is a cluster after the clusters used by the file, release
526 it back to the media. */
527
528 #ifdef FX_ENABLE_FAULT_TOLERANT
529 if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
530 {
531 #endif /* FX_ENABLE_FAULT_TOLERANT */
532
533 status = _fx_utility_FAT_entry_write(media_ptr, cluster, FX_FREE_CLUSTER);
534
535 /* Check the return value. */
536 if (status)
537 {
538
539 #ifdef FX_ENABLE_FAULT_TOLERANT
540 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
541 #endif /* FX_ENABLE_FAULT_TOLERANT */
542
543 /* Release media protection. */
544 FX_UNPROTECT
545
546 /* Return the error status. */
547 return(status);
548 }
549
550 /* Increment the number of available clusters. */
551 media_ptr -> fx_media_available_clusters++;
552
553 #ifdef FX_ENABLE_FAULT_TOLERANT
554 }
555 #endif /* FX_ENABLE_FAULT_TOLERANT */
556 }
557
558 /* Setup for the next cluster. */
559 cluster = contents;
560 }
561
562 /* Determine if we need to adjust the number of leading consecutive clusters. */
563 if (file_ptr -> fx_file_consecutive_cluster > file_ptr -> fx_file_total_clusters)
564 {
565
566 /* Adjust the leading consecutive cluster count. */
567 file_ptr -> fx_file_consecutive_cluster = file_ptr -> fx_file_total_clusters;
568 }
569
570 /* Determine if the file available size has been truncated to zero. */
571 if (file_ptr -> fx_file_current_available_size == 0)
572 {
573
574 /* Yes, the first cluster has already been released. Update the file info
575 to indicate the file has no clusters. */
576 file_ptr -> fx_file_last_physical_cluster = 0;
577 file_ptr -> fx_file_first_physical_cluster = 0;
578 file_ptr -> fx_file_current_physical_cluster = 0;
579 file_ptr -> fx_file_current_logical_sector = 0;
580 file_ptr -> fx_file_current_relative_cluster = 0;
581 file_ptr -> fx_file_current_relative_sector = 0;
582 file_ptr -> fx_file_current_available_size = 0;
583 file_ptr -> fx_file_consecutive_cluster = 1;
584 }
585
586 #ifndef FX_DONT_UPDATE_OPEN_FILES
587
588 /* Search the opened files list to see if the same file is opened for reading. */
589 open_count = media_ptr -> fx_media_opened_file_count;
590 search_ptr = media_ptr -> fx_media_opened_file_list;
591 while (open_count)
592 {
593
594 /* Is this file the same file opened for reading? */
595 if ((search_ptr != file_ptr) &&
596 (search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector ==
597 file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector) &&
598 (search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset ==
599 file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset))
600 {
601
602 /* Yes, the same file is opened for reading. */
603
604 /* Setup the new file size. */
605 search_ptr -> fx_file_current_file_size = size;
606
607 /* Setup the new total clusters. */
608 search_ptr -> fx_file_total_clusters = file_ptr -> fx_file_total_clusters;
609
610 /* Copy the directory entry. */
611 search_ptr -> fx_file_dir_entry.fx_dir_entry_cluster = file_ptr -> fx_file_dir_entry.fx_dir_entry_cluster;
612 search_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size;
613 search_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector = file_ptr -> fx_file_dir_entry.fx_dir_entry_log_sector;
614 search_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset = file_ptr -> fx_file_dir_entry.fx_dir_entry_byte_offset;
615
616 /* Setup the other file parameters. */
617 search_ptr -> fx_file_last_physical_cluster = file_ptr -> fx_file_last_physical_cluster;
618 search_ptr -> fx_file_first_physical_cluster = file_ptr -> fx_file_first_physical_cluster;
619 search_ptr -> fx_file_current_available_size = file_ptr -> fx_file_current_available_size;
620 search_ptr -> fx_file_consecutive_cluster = file_ptr -> fx_file_consecutive_cluster;
621
622 /* Determine if the truncated file is smaller than the current file offset. */
623 if (search_ptr -> fx_file_current_file_offset > size)
624 {
625
626 /* Yes, the current file parameters need to be changed since the file was
627 truncated to a position prior to the current file position. */
628
629 /* Calculate the number of bytes per cluster. */
630 bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
631 ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
632
633 /* At this point, we are ready to walk list of clusters to setup the
634 seek position of this file. */
635 cluster = search_ptr -> fx_file_first_physical_cluster;
636 bytes_remaining = size;
637 last_cluster = 0;
638 cluster_count = 0;
639
640 /* Follow the link of FAT entries. */
641 while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
642 {
643
644 /* Increment the number of clusters. */
645 cluster_count++;
646
647
648 /* Read the current cluster entry from the FAT. */
649 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &contents);
650
651 /* Check the return value. */
652 if (status != FX_SUCCESS)
653 {
654
655 #ifdef FX_ENABLE_FAULT_TOLERANT
656 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
657 #endif /* FX_ENABLE_FAULT_TOLERANT */
658
659 /* Release media protection. */
660 FX_UNPROTECT
661
662 /* Return the error status. */
663 return(status);
664 }
665
666 /* Save the last valid cluster. */
667 last_cluster = cluster;
668
669 /* Setup for the next cluster. */
670 cluster = contents;
671
672 /* Determine if this is the last written cluster. */
673 if (bytes_remaining >= bytes_per_cluster)
674 {
675
676 /* Still more seeking, just decrement the working byte offset. */
677 bytes_remaining = bytes_remaining - bytes_per_cluster;
678 }
679 else
680 {
681
682 /* This is the cluster that contains the seek position. */
683 break;
684 }
685 }
686
687 /* Check for errors in traversal of the FAT chain. */
688 if (size > (((ULONG64) bytes_per_cluster) * ((ULONG64) cluster_count)))
689 {
690
691 #ifdef FX_ENABLE_FAULT_TOLERANT
692 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
693 #endif /* FX_ENABLE_FAULT_TOLERANT */
694
695 /* Release media protection. */
696 FX_UNPROTECT
697
698 /* This is an error that suggests a corrupt file. */
699 return(FX_FILE_CORRUPT);
700 }
701
702 /* Position the pointers to the new offset. */
703
704 /* Determine if there is at least one cluster. */
705 if (cluster_count)
706 {
707
708 /* Calculate real file parameters. */
709 search_ptr -> fx_file_current_physical_cluster = last_cluster;
710 search_ptr -> fx_file_current_relative_cluster = cluster_count - 1;
711 search_ptr -> fx_file_current_logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
712 (((ULONG64)search_ptr -> fx_file_current_physical_cluster - FX_FAT_ENTRY_START) *
713 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
714 (bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector);
715 search_ptr -> fx_file_current_relative_sector = (UINT)((bytes_remaining / (ULONG)media_ptr -> fx_media_bytes_per_sector));
716 search_ptr -> fx_file_current_file_offset = size;
717 search_ptr -> fx_file_current_logical_offset = (ULONG)bytes_remaining % ((ULONG)media_ptr -> fx_media_bytes_per_sector);
718 }
719 else
720 {
721
722 /* Calculate zero-length file parameters. */
723 search_ptr -> fx_file_current_physical_cluster = 0;
724 search_ptr -> fx_file_current_relative_cluster = 0;
725 search_ptr -> fx_file_current_logical_sector = 0;
726 search_ptr -> fx_file_current_relative_sector = 0;
727 search_ptr -> fx_file_current_file_offset = 0;
728 search_ptr -> fx_file_current_logical_offset = 0;
729 }
730 }
731 }
732
733 /* Adjust the pointer and decrement the search count. */
734 search_ptr = search_ptr -> fx_file_opened_next;
735 open_count--;
736 }
737 #endif
738
739 #ifdef FX_FAULT_TOLERANT
740
741 /* Flush the cached individual FAT entries */
742 status = _fx_utility_FAT_flush(media_ptr);
743
744 /* Check the return value. */
745 if (status)
746 {
747
748 #ifdef FX_ENABLE_FAULT_TOLERANT
749 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
750 #endif /* FX_ENABLE_FAULT_TOLERANT */
751
752 /* Release media protection. */
753 FX_UNPROTECT
754
755 /* Return the error status. */
756 return(status);
757 }
758
759 #endif
760
761 #ifdef FX_ENABLE_FAULT_TOLERANT
762 if (media_ptr -> fx_media_fault_tolerant_enabled &&
763 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
764 {
765
766 /* Copy the new file size into the directory entry. */
767 file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = file_ptr -> fx_file_current_file_size;
768 }
769
770 /* Write the directory entry to the media. */
771 status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
772
773 /* Check for a good status. */
774 if (status != FX_SUCCESS)
775 {
776
777 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
778
779 /* Release media protection. */
780 FX_UNPROTECT
781
782 /* Error writing the directory. */
783 return(status);
784 }
785
786 /* End transaction. */
787 status = _fx_fault_tolerant_transaction_end(media_ptr);
788
789 /* Check for a bad status. */
790 if (status != FX_SUCCESS)
791 {
792
793 /* Release media protection. */
794 FX_UNPROTECT
795
796 /* Return the bad status. */
797 return(status);
798 }
799
800 /* Update maximum size used if necessary. */
801 if (size < file_ptr -> fx_file_maximum_size_used)
802 {
803 file_ptr -> fx_file_maximum_size_used = size;
804 }
805 #endif /* FX_ENABLE_FAULT_TOLERANT */
806
807 /* Release media protection. */
808 FX_UNPROTECT
809
810 /* Truncate is complete, return successful status. */
811 return(FX_SUCCESS);
812 }
813
814