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 /** Directory */
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_utility.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _fx_directory_free_search PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* William E. Lamie, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function searches the media for a free directory entry. */
46 /* */
47 /* INPUT */
48 /* */
49 /* media_ptr Media control block pointer */
50 /* directory_ptr Pointer to directory to */
51 /* search in */
52 /* entry_ptr Pointer to directory entry */
53 /* record */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* return status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _fx_directory_entry_read Read entries from directory */
62 /* _fx_directory_entry_write Write entries to directory */
63 /* _fx_utility_FAT_entry_read Read a FAT entry */
64 /* _fx_utility_FAT_entry_write Write a FAT entry */
65 /* _fx_utility_FAT_flush Flush written FAT entries */
66 /* _fx_utility_logical_sector_flush Flush logical sector cache */
67 /* _fx_utility_logical_sector_read Read logical sector */
68 /* _fx_utility_logical_sector_write Write logical sector */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* FileX System Functions */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
79 /* 09-30-2020 William E. Lamie Modified comment(s), */
80 /* resulting in version 6.1 */
81 /* 07-29-2022 Bhupendra Naphade Modified comment(s), */
82 /* updated available cluster */
83 /* check for sub directory, */
84 /* resulting in version 6.1.12 */
85 /* */
86 /**************************************************************************/
_fx_directory_free_search(FX_MEDIA * media_ptr,FX_DIR_ENTRY * directory_ptr,FX_DIR_ENTRY * entry_ptr)87 UINT _fx_directory_free_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *directory_ptr, FX_DIR_ENTRY *entry_ptr)
88 {
89
90 ULONG i, j;
91 UCHAR *work_ptr;
92 UINT status, total_entries;
93 ULONG entry_sector, entry_offset;
94 ULONG FAT_index, FAT_value;
95 ULONG cluster, total_clusters, clusters_needed;
96 ULONG first_new_cluster, last_cluster, clusters;
97 ULONG directory_index;
98 ULONG directory_entries;
99 ULONG logical_sector;
100 FX_DIR_ENTRY *search_dir_ptr;
101 ULONG free_entry_start;
102 UINT sectors;
103
104 FX_INT_SAVE_AREA
105
106
107
108 #ifndef FX_MEDIA_STATISTICS_DISABLE
109
110 /* Increment the number of directory free entry search requests. */
111 media_ptr -> fx_media_directory_free_searches++;
112 #endif
113
114 /* Initialize the entry sector values. */
115 entry_sector = entry_offset = 0;
116
117 /* Set the long file name flag to false. */
118 entry_ptr -> fx_dir_entry_long_name_present = 0;
119
120 /* Are there leading dots? */
121 if (entry_ptr -> fx_dir_entry_name[0] == '.')
122 {
123
124 /* Is there more than 1 dot? */
125 if (entry_ptr -> fx_dir_entry_name[1] == '.')
126 {
127 /* Yes, consider the name invalid. */
128 return(FX_INVALID_NAME);
129 }
130 }
131
132 /* Determine if a long file name is present. */
133 for (i = 0, j = 0; entry_ptr -> fx_dir_entry_name[i]; i++)
134 {
135
136 /* Check for upper-case characters. */
137 if ((entry_ptr -> fx_dir_entry_name[i] >= 'A') && (entry_ptr -> fx_dir_entry_name[i] <= 'Z'))
138 {
139 continue;
140 }
141 /* Check for numeric characters. */
142 else if ((entry_ptr -> fx_dir_entry_name[i] >= '0') && (entry_ptr -> fx_dir_entry_name[i] <= '9'))
143 {
144 continue;
145 }
146 /* Check for any lower-case characters. */
147 else if ((entry_ptr -> fx_dir_entry_name[i] >= 'a') && (entry_ptr -> fx_dir_entry_name[i] <= 'z'))
148 {
149 entry_ptr -> fx_dir_entry_long_name_present = 1;
150 }
151 /* Check for a space in the middle of the name. */
152 else if (entry_ptr -> fx_dir_entry_name[i] == ' ')
153 {
154 entry_ptr -> fx_dir_entry_long_name_present = 1;
155 }
156 /* Check for a dot in the name. */
157 else if (entry_ptr -> fx_dir_entry_name[i] == '.')
158 {
159 /* Determine if this is the first dot detected. */
160 if (j == 0)
161 {
162 /* First dot, remember where it was. */
163 j = i;
164
165 /* Determine if this is a leading dot. */
166 if (i == 0)
167 {
168
169 /* Leading dot detected, treat as a long filename. */
170 entry_ptr -> fx_dir_entry_long_name_present = 1;
171 }
172 }
173 else
174 {
175 /* Second dot detected, must have a long file name. */
176 entry_ptr -> fx_dir_entry_long_name_present = 1;
177 }
178 }
179 /* Check for a special 0xE5 character. */
180 else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == (UCHAR)0xE5)
181 {
182 entry_ptr -> fx_dir_entry_long_name_present = 1;
183 }
184 /* Check for code point value greater than 127. */
185 else if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] > (UCHAR)127)
186 {
187 continue;
188 }
189 /* Check for any special characters. */
190 else if ((entry_ptr -> fx_dir_entry_name[i] == '~') ||
191 (entry_ptr -> fx_dir_entry_name[i] == '-') ||
192 (entry_ptr -> fx_dir_entry_name[i] == '_') ||
193 (entry_ptr -> fx_dir_entry_name[i] == '}') ||
194 (entry_ptr -> fx_dir_entry_name[i] == '{') ||
195 (entry_ptr -> fx_dir_entry_name[i] == '(') ||
196 (entry_ptr -> fx_dir_entry_name[i] == ')') ||
197 (entry_ptr -> fx_dir_entry_name[i] == '`') ||
198 (entry_ptr -> fx_dir_entry_name[i] == '\'') ||
199 (entry_ptr -> fx_dir_entry_name[i] == '!') ||
200 (entry_ptr -> fx_dir_entry_name[i] == '#') ||
201 (entry_ptr -> fx_dir_entry_name[i] == '$') ||
202 (entry_ptr -> fx_dir_entry_name[i] == '&') ||
203 (entry_ptr -> fx_dir_entry_name[i] == '@') ||
204 (entry_ptr -> fx_dir_entry_name[i] == '^') ||
205 (entry_ptr -> fx_dir_entry_name[i] == '%'))
206 {
207 continue;
208 }
209 /* Check for long filename special characters. */
210 else if ((entry_ptr -> fx_dir_entry_name[i] == '+') ||
211 (entry_ptr -> fx_dir_entry_name[i] == ',') ||
212 (entry_ptr -> fx_dir_entry_name[i] == ';') ||
213 (entry_ptr -> fx_dir_entry_name[i] == '=') ||
214 (entry_ptr -> fx_dir_entry_name[i] == '[') ||
215 (entry_ptr -> fx_dir_entry_name[i] == ']'))
216 {
217 entry_ptr -> fx_dir_entry_long_name_present = 1;
218 }
219 /* Something is wrong with the supplied name. */
220 else
221 {
222 return(FX_INVALID_NAME);
223 }
224 }
225
226 /* Determine if a dot was found. */
227 if (j != 0)
228 {
229
230 /* Yes, Determine if the extension exceeds a 3 character extension. */
231 if ((i - j) > 4)
232 {
233
234 /* Yes, long file name is present. */
235 entry_ptr -> fx_dir_entry_long_name_present = 1;
236 }
237 }
238
239 /* Calculate the total entries needed. */
240 if ((i <= 12) && (entry_ptr -> fx_dir_entry_long_name_present == 0))
241 {
242
243 /* Initialize the total entries to 1. */
244 total_entries = 1;
245
246 /* Check for special instance of long file name. */
247 if ((j >= 9) || ((i - j) >= 9))
248 {
249
250 /* The dot is after 8 character or there is no dot and the name
251 is greater than 8 character. */
252 entry_ptr -> fx_dir_entry_long_name_present = 1;
253 total_entries = 2;
254 }
255 }
256 else
257 {
258
259 /* Long file name is present, calculate how many entries are needed
260 to represent it. */
261 if (i % 13 == 0)
262 {
263 /* Exact fit, just add one for the 8.3 short name. */
264 total_entries = i / 13 + 1;
265 }
266 else
267 {
268 /* Non-exact fit, add two for 8.3 short name and overlap. */
269 total_entries = i / 13 + 2;
270 }
271 }
272
273 /* Determine if the search is in the root directory or in a
274 sub-directory. Note: the directory search function clears the
275 first character of the name for the root directory. */
276 if (directory_ptr -> fx_dir_entry_name[0])
277 {
278
279 /* Search for a free entry in a sub-directory. */
280
281 /* Pickup the number of entries in this directory. This was placed
282 into the unused file size field. */
283 directory_entries = (ULONG)directory_ptr -> fx_dir_entry_file_size;
284
285 /* Point the search directory pointer to this entry. */
286 search_dir_ptr = directory_ptr;
287
288 /* Ensure that the search directory's last search cluster is cleared. */
289 search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
290
291 /* Set the initial index to 2, since the first two directory entries are
292 always allocated. */
293 directory_index = 2;
294 }
295 else
296 {
297
298 /* Find a free entry in the root directory. */
299
300 /* Setup the number of directory entries. */
301 directory_entries = (ULONG)media_ptr -> fx_media_root_directory_entries;
302
303 /* Set the search pointer to NULL since we are working off of the
304 root directory. */
305 search_dir_ptr = FX_NULL;
306
307 /* Set the initial index to 0, since the first entry of the root directory is valid. */
308 directory_index = 0;
309 }
310
311 /* Loop through entries in the search directory. Yes, this is a
312 linear search! */
313 free_entry_start = directory_entries;
314 do
315 {
316
317 /* Read an entry from the directory. */
318 status = _fx_directory_entry_read(media_ptr, search_dir_ptr, &directory_index, entry_ptr);
319
320 /* Check for error status. */
321 if (status != FX_SUCCESS)
322 {
323 return(status);
324 }
325
326 /* Determine if this is an empty entry. */
327 if ((((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)) ||
328 ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE))
329 {
330
331 /* Determine how many entries are needed. */
332 if (total_entries > 1)
333 {
334
335 /* Multiple entries are needed for long file names. Mark this
336 entry as free. */
337 if (entry_ptr -> fx_dir_entry_name[0] == FX_DIR_ENTRY_DONE)
338 {
339
340 entry_ptr -> fx_dir_entry_long_name_present = 0;
341 entry_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
342 entry_ptr -> fx_dir_entry_name[1] = (CHAR)0;
343
344 /* Write out the directory entry. */
345 status = _fx_directory_entry_write(media_ptr, entry_ptr);
346 if(status != FX_SUCCESS)
347 {
348 return(status);
349 }
350
351 /* Note that for long names we need to avoid holes in the middle,
352 i.e. entries must be logically contiguous. */
353 }
354 }
355
356 /* Determine if we are at the first free entry. */
357 if (free_entry_start == directory_entries)
358 {
359
360 /* Remember the start of the free entry. */
361 free_entry_start = directory_index;
362 entry_sector = (ULONG)entry_ptr -> fx_dir_entry_log_sector;
363 entry_offset = entry_ptr -> fx_dir_entry_byte_offset;
364 }
365
366 /* Determine if there are enough free entries to satisfy the request. */
367 if ((directory_index - free_entry_start + 1) >= total_entries)
368 {
369
370 /* Found an empty slot. Most pertinent information is already
371 in the entry structure. */
372
373 /* Setup the the sector and the offset. */
374 entry_ptr -> fx_dir_entry_log_sector = entry_sector;
375 entry_ptr -> fx_dir_entry_byte_offset = entry_offset;
376
377 /* Initialize the additional directory entries. */
378 entry_ptr -> fx_dir_entry_reserved = 0;
379 entry_ptr -> fx_dir_entry_created_time_ms = 0;
380
381 /* Lockout interrupts for time/date access. */
382 FX_DISABLE_INTS
383
384 entry_ptr -> fx_dir_entry_created_time = _fx_system_time;
385 entry_ptr -> fx_dir_entry_created_date = _fx_system_date;
386 entry_ptr -> fx_dir_entry_last_accessed_date = _fx_system_date;
387
388 /* Restore interrupts. */
389 FX_RESTORE_INTS
390
391 /* Determine if a long file name is present. */
392 if (total_entries == 1)
393 {
394 entry_ptr -> fx_dir_entry_long_name_present = 0;
395 }
396 else
397 {
398 entry_ptr -> fx_dir_entry_long_name_present = 1;
399 }
400
401 /* Return a successful completion. */
402 return(FX_SUCCESS);
403 }
404 }
405 else
406 {
407
408 /* Reset the free entry start. */
409 free_entry_start = directory_entries;
410 }
411
412 /* Move to the next entry. */
413 directory_index++;
414
415 /* Determine if we have exceeded the number of entries in the current directory. */
416 if (directory_index >= directory_entries)
417 {
418
419 /* Calculate how many sectors we need for the new directory entry. */
420 sectors = ((total_entries * FX_DIR_ENTRY_SIZE) + (media_ptr -> fx_media_bytes_per_sector - 1))/
421 media_ptr -> fx_media_bytes_per_sector;
422
423 /* Now calculate how many clusters we need for the new directory entry. */
424 clusters_needed = (sectors + (media_ptr -> fx_media_sectors_per_cluster - 1)) / media_ptr -> fx_media_sectors_per_cluster;
425
426 /* Not enough empty entries were found. If the specified directory is a sub-directory,
427 attempt to allocate another cluster to it. */
428 if (((search_dir_ptr) || (media_ptr -> fx_media_32_bit_FAT)) && (media_ptr -> fx_media_available_clusters >= clusters_needed))
429 {
430
431 /* Search for the additional clusters we need. */
432 first_new_cluster = 0;
433 total_clusters = media_ptr -> fx_media_total_clusters;
434 last_cluster = 0;
435 FAT_index = media_ptr -> fx_media_cluster_search_start;
436 clusters = clusters_needed;
437
438 /* Loop to find the needed clusters. */
439 while (clusters)
440 {
441
442 /* Decrease the cluster count. */
443 clusters--;
444
445 /* Loop to find the first available cluster. */
446 do
447 {
448
449 /* Make sure we stop looking after one pass through the FAT table. */
450 if (!total_clusters)
451 {
452
453 /* Something is wrong with the media - the desired clusters were
454 not found in the FAT table. */
455 return(FX_NO_MORE_SPACE);
456 }
457
458 /* Read FAT entry. */
459 status = _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
460
461 /* Check for a bad status. */
462 if (status != FX_SUCCESS)
463 {
464
465 /* Return the bad status. */
466 return(status);
467 }
468
469 /* Decrement the total cluster count. */
470 total_clusters--;
471
472 /* Determine if the FAT entry is free. */
473 if (FAT_value == FX_FREE_CLUSTER)
474 {
475
476 /* Move cluster search pointer forward. */
477 media_ptr -> fx_media_cluster_search_start = FAT_index + 1;
478
479 /* Determine if this needs to be wrapped. */
480 if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
481 {
482
483 /* Wrap the search to the beginning FAT entry. */
484 media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START;
485 }
486
487 /* Break this loop. */
488 break;
489 }
490 else
491 {
492
493 /* FAT entry is not free... Advance the FAT index. */
494 FAT_index++;
495
496 /* Determine if we need to wrap the FAT index around. */
497 if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
498 {
499
500 /* Wrap the search to the beginning FAT entry. */
501 FAT_index = FX_FAT_ENTRY_START;
502 }
503 }
504 } while (FX_TRUE);
505
506 /* We found an available cluster. We now need to clear all of entries in
507 each of the cluster's sectors. */
508
509 /* Calculate the logical sector of this cluster. */
510 logical_sector = ((ULONG) media_ptr -> fx_media_data_sector_start) +
511 ((((ULONG) FAT_index) - FX_FAT_ENTRY_START) *
512 ((ULONG) media_ptr -> fx_media_sectors_per_cluster));
513
514 /* Pickup the number of sectors for the next directory cluster. */
515 sectors = media_ptr -> fx_media_sectors_per_cluster;
516
517 /* Read the logical sector just for cache reasons. */
518 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
519 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
520
521 /* Check the return value. */
522 if (status != FX_SUCCESS)
523 {
524
525 /* Return the error status. */
526 return(status);
527 }
528
529 /* Clear the entire first sector of the new sub-directory cluster. */
530 work_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
531 i = 0;
532 while (i < media_ptr -> fx_media_bytes_per_sector)
533 {
534
535 /* Clear 4 bytes. */
536 *((ULONG *)work_ptr) = (ULONG)0;
537
538 /* Increment pointer. */
539 work_ptr = work_ptr + sizeof(ULONG);
540
541 /* Increment counter. */
542 i = i + (ULONG)sizeof(ULONG);
543 }
544
545 /* Write the logical sector to ensure the zeros are written. */
546 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
547 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
548
549 /* Determine if the write was successful. */
550 if (status != FX_SUCCESS)
551 {
552
553 /* Return the error code. */
554 return(status);
555 }
556
557 /* Determine if there are more sectors to clear in the first cluster of the new
558 sub-directory. */
559 if (sectors > 1)
560 {
561
562 /* Yes, invalidate all cached sectors that are contained in the newly allocated first
563 cluster of the directory. */
564
565 /* Flush the internal logical sector cache. */
566 status = _fx_utility_logical_sector_flush(media_ptr, (ULONG64) (logical_sector + 1), (ULONG64) (sectors - 1), FX_TRUE);
567
568 /* Determine if the flush was successful. */
569 if (status != FX_SUCCESS)
570 {
571
572 /* Return the error code. */
573 return(status);
574 }
575
576 /* Clear all additional sectors of new sub-directory. */
577 sectors--;
578 while (sectors)
579 {
580
581 #ifndef FX_MEDIA_STATISTICS_DISABLE
582
583 /* Increment the number of driver write sector(s) requests. */
584 media_ptr -> fx_media_driver_write_requests++;
585 #endif
586
587 /* Build Write request to the driver. */
588 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
589 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
590 media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
591 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector + ((ULONG)sectors);
592 media_ptr -> fx_media_driver_sectors = 1;
593 media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
594
595 /* Set the system write flag since we are writing a directory sector. */
596 media_ptr -> fx_media_driver_system_write = FX_TRUE;
597
598 /* If trace is enabled, insert this event into the trace buffer. */
599 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, ((ULONG)logical_sector) + ((ULONG)sectors), 1, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
600
601 /* Invoke the driver to write the sector. */
602 (media_ptr -> fx_media_driver_entry) (media_ptr);
603
604 /* Clear the system write flag. */
605 media_ptr -> fx_media_driver_system_write = FX_FALSE;
606
607 /* Determine if an error occurred. */
608 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
609 {
610
611 /* Return error code. */
612 return(media_ptr -> fx_media_driver_status);
613 }
614
615 /* Decrease the number of sectors to clear. */
616 sectors--;
617 }
618 }
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
628 /* Check for a valid last cluster to link. */
629 if (last_cluster)
630 {
631
632 /* Normal condition - link the last cluster with the new
633 found cluster. */
634 status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, FAT_index);
635
636 /* Check for a bad FAT write status. */
637 if (status != FX_SUCCESS)
638 {
639
640 /* Return the bad status. */
641 return(status);
642 }
643 }
644
645 /* Otherwise, remember the new FAT index as the last. */
646 last_cluster = FAT_index;
647
648 /* Move to the next FAT entry. */
649 FAT_index = media_ptr -> fx_media_cluster_search_start;
650 }
651
652 /* Place an end-of-file marker on the last cluster. */
653 status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, media_ptr -> fx_media_fat_last);
654
655 /* Check for a bad FAT write status. */
656 if (status != FX_SUCCESS)
657 {
658
659 /* Return the bad status. */
660 return(status);
661 }
662
663 #ifdef FX_FAULT_TOLERANT
664
665 /* Ensure the new FAT chain is properly written to the media. */
666
667 /* Flush the cached individual FAT entries */
668 _fx_utility_FAT_flush(media_ptr);
669 #endif
670
671 /* Now the new cluster needs to be linked to the sub-directory. */
672 if (search_dir_ptr)
673 {
674 cluster = search_dir_ptr -> fx_dir_entry_cluster;
675 }
676 else
677 {
678 cluster = media_ptr -> fx_media_root_cluster_32;
679 }
680
681 /* Initialize loop variables. */
682 last_cluster = 0;
683 i = 0;
684
685 /* Follow the link of FAT entries. */
686 while (cluster < media_ptr -> fx_media_fat_reserved)
687 {
688
689 /* Read the current cluster entry from the FAT. */
690 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &FAT_value);
691 i++;
692
693 /* Check the return value. */
694 if (status != FX_SUCCESS)
695 {
696
697 /* Return the error status. */
698 return(status);
699 }
700
701 /* Determine if the FAT read was invalid. */
702 if ((cluster < FX_FAT_ENTRY_START) || (cluster == FAT_value) || (i > media_ptr -> fx_media_total_clusters))
703 {
704
705 /* Return the bad status. */
706 return(FX_FAT_READ_ERROR);
707 }
708
709 /* Save the last valid cluster. */
710 last_cluster = cluster;
711
712 /* Setup for the next cluster. */
713 cluster = FAT_value;
714 }
715
716 /* Decrease the available clusters in the media. */
717 media_ptr -> fx_media_available_clusters = media_ptr -> fx_media_available_clusters - clusters_needed;
718
719 /* Increase the number of directory entries. */
720 directory_entries = directory_entries + ((clusters_needed * media_ptr -> fx_media_sectors_per_cluster) * media_ptr -> fx_media_bytes_per_sector) / FX_DIR_ENTRY_SIZE;
721
722 /* Determine if we need to reset the free entry start since we changed the
723 number of directory entries. If the last entry was not free, then we
724 should definitely reset the free entry start. */
725 if (!(((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR) FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0)))
726 {
727
728 /* Reset the free entry start to indicate we haven't found a starting free entry yet. */
729 free_entry_start = directory_entries;
730 }
731
732 /* Update the directory size field. */
733 directory_ptr -> fx_dir_entry_file_size = directory_entries;
734
735 /* Defer the update of the FAT entry and the last cluster of the current
736 directory entry until after the new cluster is initialized and written out. */
737
738 /* Determine if a FAT32 is present. */
739 if ((media_ptr -> fx_media_32_bit_FAT) && (search_dir_ptr == FX_NULL))
740 {
741
742 /* Change root directory entry count - FAT32 has a variable sized root directory. */
743 media_ptr -> fx_media_root_directory_entries = directory_entries;
744 }
745
746 /* At this point, link up the last cluster with the new cluster. */
747 status = _fx_utility_FAT_entry_write(media_ptr, last_cluster, first_new_cluster);
748
749 /* Check the return value. */
750 if (status != FX_SUCCESS)
751 {
752
753 /* Return the error status. */
754 return(status);
755 }
756
757 #ifdef FX_FAULT_TOLERANT
758
759 /* Flush the cached individual FAT entries */
760 _fx_utility_FAT_flush(media_ptr);
761 #endif
762 }
763 }
764 } while (directory_index < directory_entries);
765
766 /* Return FX_NO_MORE_SPACE status to the caller. */
767 return(FX_NO_MORE_SPACE);
768 }
769
770