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 #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_directory_entry_write PORTABLE C */
41 /* 6.1.5 */
42 /* AUTHOR */
43 /* */
44 /* William E. Lamie, Microsoft Corporation */
45 /* */
46 /* DESCRIPTION */
47 /* */
48 /* This function writes the supplied directory entry to the specified */
49 /* logical sector and offset. */
50 /* */
51 /* INPUT */
52 /* */
53 /* media_ptr Media control block pointer */
54 /* entry_ptr Pointer to directory entry */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* return status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _fx_utility_FAT_entry_read Read a new FAT entry */
63 /* _fx_utility_logical_sector_read Read directory sector */
64 /* _fx_utility_logical_sector_write Write directory sector */
65 /* _fx_utility_16_unsigned_write Write a UINT from memory */
66 /* _fx_utility_32_unsigned_write Write a ULONG from memory */
67 /* _fx_fault_tolerant_add_dir_log Add directory redo log */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* FileX System Functions */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
78 /* 09-30-2020 William E. Lamie Modified comment(s), */
79 /* resulting in version 6.1 */
80 /* 03-02-2021 William E. Lamie Modified comment(s), */
81 /* resulting in version 6.1.5 */
82 /* */
83 /**************************************************************************/
_fx_directory_entry_write(FX_MEDIA * media_ptr,FX_DIR_ENTRY * entry_ptr)84 UINT _fx_directory_entry_write(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr)
85 {
86
87 UCHAR *work_ptr, *sector_base_ptr;
88 UINT status, temp, entry, delete_flag;
89 UINT i, j, k, l, card, len, dotfound, dotpos, match;
90 UCHAR checksum, eof_marker;
91 CHAR alpha;
92 CHAR shortname[FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE + 1];
93 ULONG logical_sector, relative_sector;
94 ULONG byte_offset;
95 ULONG cluster, next_cluster;
96
97
98 #ifdef FX_ENABLE_FAULT_TOLERANT
99 UCHAR *changed_ptr;
100 UINT changed_size;
101 ULONG changed_offset;
102 #endif /* FX_ENABLE_FAULT_TOLERANT */
103
104
105 #ifndef FX_MEDIA_STATISTICS_DISABLE
106
107 /* Increment the number of directory entry write requests. */
108 media_ptr -> fx_media_directory_entry_writes++;
109 #endif
110
111 /* Extended port-specific processing macro, which is by default defined to white space. */
112 FX_DIRECTORY_ENTRY_WRITE_EXTENSION
113
114 /* If trace is enabled, insert this event into the trace buffer. */
115 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_DIR_ENTRY_WRITE, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
116
117 /* Determine if this is entry is being deleted. */
118 if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) &&
119 ((UCHAR)entry_ptr -> fx_dir_entry_short_name[0] == (UCHAR)FX_DIR_ENTRY_FREE))
120 {
121
122 /* Yes, this is a request to delete the entry. Set the flag to remember this. */
123 delete_flag = FX_TRUE;
124
125 /* Null the short file name. */
126 entry_ptr -> fx_dir_entry_short_name[0] = 0;
127 }
128 else
129 {
130
131 /* Not a deleted entry. Set the flag to false. */
132 delete_flag = FX_FALSE;
133 }
134
135 /* Pickup the byte offset of the entry. */
136 byte_offset = entry_ptr -> fx_dir_entry_byte_offset;
137
138 /* Pickup the logical sector of the entry. */
139 logical_sector = (ULONG)entry_ptr -> fx_dir_entry_log_sector;
140
141 /* Figure out where what cluster we are in. */
142 if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
143 {
144
145 /* Calculate the cluster that this logical sector is in. */
146 cluster = (logical_sector - media_ptr -> fx_media_data_sector_start) / (media_ptr -> fx_media_sectors_per_cluster) + FX_FAT_ENTRY_START;
147
148 /* Calculate the relative cluster. */
149 relative_sector = logical_sector - (((ULONG)media_ptr -> fx_media_data_sector_start) +
150 (((ULONG)cluster - FX_FAT_ENTRY_START) *
151 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)));
152 }
153 else
154 {
155
156 /* Clear the cluster and the relative sector. */
157 cluster = 0;
158 relative_sector = 0;
159 }
160
161 /* Read the logical directory sector. */
162 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) entry_ptr -> fx_dir_entry_log_sector,
163 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
164
165 /* Determine if an error occurred. */
166 if (status != FX_SUCCESS)
167 {
168
169 /* Return the error status. */
170 return(status);
171 }
172
173 /* Setup a pointer into the buffer. */
174 sector_base_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
175 work_ptr = sector_base_ptr + (UINT)entry_ptr -> fx_dir_entry_byte_offset;
176
177 #ifdef FX_ENABLE_FAULT_TOLERANT
178 /* Initialize data for fault tolerant. */
179 changed_ptr = work_ptr;
180 changed_size = 0;
181 changed_offset = entry_ptr -> fx_dir_entry_byte_offset;
182 #endif /* FX_ENABLE_FAULT_TOLERANT */
183
184 /* Determine if a long file name is present. */
185 if (entry_ptr -> fx_dir_entry_long_name_present)
186 {
187
188 /* Yes, long name is present - prepare short name and write out this name. */
189 for (len = 0, i = 0, dotpos = 0, dotfound = 0; entry_ptr -> fx_dir_entry_name[len]; len++)
190 {
191
192 /* Check for a dot. */
193 if (entry_ptr -> fx_dir_entry_name[len] == '.')
194 {
195
196 /* Check for leading dot. */
197 if (len == 0)
198 {
199 /* Yes, this is a leading dot. */
200 continue;
201 }
202
203 /* Yes, a dot is present. From this position the extension will
204 be written. */
205 dotfound = i;
206 dotpos = len + 1;
207 continue;
208 }
209
210 /* Check for non-space and within the short file name length. */
211 if ((entry_ptr -> fx_dir_entry_name[len] != ' ') && (i < 8))
212 {
213
214 /* Copy characters into the short file name area. */
215 shortname[i] = entry_ptr -> fx_dir_entry_name[len];
216 i++;
217 }
218 }
219
220 /* Fill remaining short file name with spaces. */
221 for (j = i; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; j++)
222 {
223 shortname[j] = ' ';
224 }
225
226 /* Determine if a dot was encountered. */
227 if (dotpos)
228 {
229
230 /* Process relative to the dot position. */
231 if (entry_ptr -> fx_dir_entry_name[dotpos])
232 {
233 shortname[8] = entry_ptr -> fx_dir_entry_name[dotpos++];
234 }
235 if (entry_ptr -> fx_dir_entry_name[dotpos])
236 {
237 shortname[9] = entry_ptr -> fx_dir_entry_name[dotpos++];
238 }
239 if (entry_ptr -> fx_dir_entry_name[dotpos])
240 {
241 shortname[10] = entry_ptr -> fx_dir_entry_name[dotpos++];
242 }
243
244 /* Determine if additional spaces are needed. */
245 i = dotfound;
246
247 for (; dotfound <= 7; dotfound++)
248 {
249 /* Add space... */
250 shortname[dotfound] = ' ';
251 }
252 }
253
254 /* Each entry contains 13 unicode entries. Calculate the remainder. */
255 if (len % 13 == 0)
256 {
257 card = len / 13;
258 }
259 else
260 {
261 card = len / 13 + 1;
262 }
263
264 /* Default the name match to true. */
265 match = FX_TRUE;
266
267 /* Loop through the newly derived short name and the original name and look
268 for a non-matching character. */
269 l = 0;
270 k = 0;
271 while (k < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE)
272 {
273
274 /* Determine if a space is detected in the short name. If so,
275 advance to the extension index. */
276 if (shortname[k] == ' ')
277 {
278
279 /* The first pad space was detected. First, check for a name
280 without an extension. */
281 if (entry_ptr -> fx_dir_entry_name[l] == FX_NULL)
282 {
283
284 /* All is okay, get out of the loop! */
285 break;
286 }
287
288 /* Now check for a period in the long name... if not, there is a non-match! */
289 if (entry_ptr -> fx_dir_entry_name[l] != '.')
290 {
291
292 /* Set the match flag to false and exit the loop. */
293 match = FX_FALSE;
294 break;
295 }
296
297 /* Otherwise move short file name index to the extension area and
298 increment the long file name index. */
299 k = 8;
300 l++;
301
302 /* Restart the loop at the top. */
303 continue;
304 }
305
306 /* Check for the dot for the 8.3 match... it is no longer in the
307 shortname but possibly still present in the long name. */
308 if ((k == 8) && (entry_ptr -> fx_dir_entry_name[l] == '.'))
309 {
310
311 /* Yes, handle the implicit dot in the shortname by
312 positioning past it in the long name. */
313 l++;
314 }
315
316 /* Do the names match? */
317 if (shortname[k] != entry_ptr -> fx_dir_entry_name[l])
318 {
319
320 /* No, the names do not match, set the match flag to false and
321 exit the loop. */
322 match = FX_FALSE;
323 break;
324 }
325
326 /* Move the indices forward. */
327 k++;
328 l++;
329 }
330
331 /* Check if there is a dot in the name, but no extension in the short name. In this case,
332 we should create a mangled short name. */
333 if ((dotpos) && (shortname[8] == ' '))
334 {
335
336 /* Something left.. the names do not match! */
337 match = FX_FALSE;
338 }
339
340 /* One final check to make sure there is nothing left on the long file name. */
341 if (entry_ptr -> fx_dir_entry_name[l])
342 {
343
344 /* Something left.. the names do not match! */
345 match = FX_FALSE;
346 }
347
348 /* Determine if the derived short name matches exactly the long file name. If so
349 we don't need to mangle the name with a numeric value based on its entry. */
350 if (match == FX_FALSE)
351 {
352
353 /* Name does not match, create a mangled name. */
354
355 /* Generate short file name from LFN. */
356 entry = entry_ptr -> fx_dir_entry_number;
357
358 /* Name suffice is between 000 and FFFF in hex, calculate this short file
359 name's numeric component. */
360 entry = entry % 0x10000;
361
362 /* Build short name of the format xxx~NNNN.ext. */
363 if (i > 3)
364 {
365 i = 3;
366 }
367 shortname[i++] = '~';
368
369 /* Loop to build the numeric part of the name. */
370 for (l = 0; l < 4; l++)
371 {
372
373 /* Shift down the entry number based on the numeric position. */
374 if (l == 0)
375 {
376 temp = ((entry >> 12) & 0xf);
377 }
378 else if (l == 1)
379 {
380 temp = ((entry >> 8) & 0xf);
381 }
382 else if (l == 2)
383 {
384 temp = ((entry >> 4) & 0xf);
385 }
386 else
387 {
388 temp = ((entry) & 0xf);
389 }
390
391 /* Now build hex value. */
392 if (temp > 9)
393 shortname[i++] = (CHAR)('A' + (temp - 10));
394 else
395 shortname[i++] = (CHAR)('0' + temp);
396 }
397 }
398
399 /* Set end of short string to NULL. */
400 shortname[11] = 0;
401
402 /* Determine if the first character of the short file name is the directory free
403 value. If so, it must be changed. */
404 if (((UCHAR)shortname[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (delete_flag == FX_FALSE))
405 {
406
407 /* Change to 0x8F to be compatible with what DOS does. */
408 shortname[0] = (CHAR)0x8F;
409 }
410
411 /* Loop to convert the new short file name to upper case. */
412 for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
413 {
414
415 /* Pickup shortname character. */
416 alpha = shortname[i];
417
418 /* Determine if character is lower case. */
419 if ((alpha >= 'a') && (alpha <= 'z'))
420 {
421
422 /* Store the character - converted to upper case. */
423 alpha = (CHAR)(alpha - ((CHAR)0x20));
424 }
425
426 /* Now store the short name character. */
427 shortname[i] = alpha;
428 }
429
430 /* Determine if there already is a short name and we are not deleting the entry. */
431 if (entry_ptr -> fx_dir_entry_short_name[0] != 0)
432 {
433
434 /* Yes, override the calculated shortname with the original 8.3 name. */
435
436 /* Clear the short file name area. */
437 for (i = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
438 {
439 shortname[i] = ' ';
440 }
441
442 /* Loop to copy the original short file name. */
443 for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
444 {
445
446 /* Check for end of copy conditions. */
447 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == '.')
448 {
449 break;
450 }
451 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
452 {
453 break;
454 }
455
456 /* Pickup the character. */
457 alpha = entry_ptr -> fx_dir_entry_short_name[i];
458
459 /* Copy file name character. */
460 shortname[j] = alpha;
461 }
462
463 /* Determine if there is anything left in the short file name. */
464 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] != 0)
465 {
466
467 /* Pickup remaining characters. */
468 for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
469 {
470
471 /* If NULL is encountered, stop the copying. */
472 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
473 {
474 break;
475 }
476
477 /* Pickup the character. */
478 alpha = entry_ptr -> fx_dir_entry_short_name[i];
479
480 /* Copy file name character. */
481 shortname[j] = alpha;
482 }
483 }
484
485 /* Loop to make sure the short name is upper case. */
486 for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
487 {
488
489 /* Pickup the character. */
490 alpha = shortname[j];
491
492 /* Determine if character is lower case. */
493 if ((alpha >= 'a') && (alpha <= 'z'))
494 {
495
496 /* Store the character - converted to upper case. */
497 alpha = (CHAR)(alpha - ((CHAR)0x20));
498 }
499
500 /* Copy file name character. */
501 shortname[j] = alpha;
502 }
503
504 /* Determine if the first character of the short file name is the directory free
505 value. If so, it must be changed. */
506 if (((UCHAR)shortname[0]) == ((UCHAR)FX_DIR_ENTRY_FREE))
507 {
508
509 /* Change to 0x8F to be compatible with what DOS does. */
510 shortname[0] = (CHAR)0x8F;
511 }
512 }
513
514 /* Loop to calculate the checksum. */
515 for (i = checksum = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
516 {
517
518 /* Calculate the checksum. */
519 checksum = (UCHAR)((UCHAR)(((checksum & 1) << 7) | ((checksum & (UCHAR)0xfe) >> 1)) + shortname[i]);
520 }
521
522 /* Set the last entry mark. */
523 work_ptr[0] = (UCHAR)(0x40 | card);
524
525 /* Loop to process remainder of long file name entry. */
526 while (card > 0)
527 {
528
529 /* Clear eof marker. */
530 eof_marker = 0;
531
532 /* Determine if the entry is free. */
533 if ((UCHAR)shortname[0] == (UCHAR)FX_DIR_ENTRY_FREE)
534 {
535 /* Yes, place delete marker. */
536 work_ptr[0] = (UCHAR)FX_DIR_ENTRY_FREE;
537 }
538
539 /* Setup various long file name fields. */
540 work_ptr[11] = FX_LONG_NAME;
541 work_ptr[12] = 0;
542 work_ptr[13] = checksum;
543 work_ptr[26] = 0;
544 work_ptr[27] = 0;
545
546 /* Loop through file name fields. */
547 for (i = 1, j = 13 * (card - 1); i < FX_DIR_ENTRY_SIZE; i += 2)
548 {
549
550 /* Process relative to specific fields. */
551 if ((i == 11) || (i == 26))
552 {
553 continue;
554 }
555
556 if (i == 13)
557 {
558 i = 12;
559 continue;
560 }
561
562 /* Determine if the EOF marker is present. */
563 if (eof_marker)
564 {
565
566 work_ptr[i] = eof_marker;
567 work_ptr[i + 1] = eof_marker;
568 }
569 else
570 {
571 work_ptr[i] = (UCHAR)entry_ptr -> fx_dir_entry_name[j];
572 work_ptr[i + 1] = 0;
573 }
574
575 if (entry_ptr -> fx_dir_entry_name[j] == 0)
576 {
577
578 /* end of name, pad with 0xff. */
579 eof_marker = (UCHAR)0xff;
580 }
581
582 j++;
583 }
584
585 /* Move to the next directory entry. */
586 work_ptr += FX_DIR_ENTRY_SIZE;
587 byte_offset += FX_DIR_ENTRY_SIZE;
588
589 #ifdef FX_ENABLE_FAULT_TOLERANT
590 /* Update changed_size. */
591 changed_size += FX_DIR_ENTRY_SIZE;
592 #endif /* FX_ENABLE_FAULT_TOLERANT */
593
594 /* Determine if the entry overlaps into the next sector. */
595 if (byte_offset >= media_ptr -> fx_media_bytes_per_sector)
596 {
597 #ifdef FX_ENABLE_FAULT_TOLERANT
598 if (media_ptr -> fx_media_fault_tolerant_enabled)
599 {
600
601 /* Redirect this request to log file. */
602 status = _fx_fault_tolerant_add_dir_log(media_ptr, logical_sector, changed_offset, changed_ptr, changed_size);
603 }
604 else
605 {
606 #endif /* FX_ENABLE_FAULT_TOLERANT */
607
608 /* Write current logical sector out. */
609 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
610 sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
611 #ifdef FX_ENABLE_FAULT_TOLERANT
612 }
613 #endif /* FX_ENABLE_FAULT_TOLERANT */
614
615 /* Determine if an error occurred. */
616 if (status != FX_SUCCESS)
617 {
618
619 /* Return the error status. */
620 return(status);
621 }
622
623 /* Determine if we are in the root directory. */
624 if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
625 {
626
627 /* Determine the next sector of the directory entry. */
628 if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
629 {
630
631 /* More sectors in this cluster. */
632
633 /* Simply increment the logical sector. */
634 logical_sector++;
635
636 /* Increment the relative sector. */
637 relative_sector++;
638 }
639 else
640 {
641
642 /* We need to move to the next cluster. */
643
644 /* Pickup the next cluster. */
645 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
646
647 /* Check for I/O error. */
648 if (status != FX_SUCCESS)
649 {
650
651 /* Return error code. */
652 return(status);
653 }
654
655 /* Copy next cluster to the current cluster. */
656 cluster = next_cluster;
657
658 /* Check the value of the new cluster - it must be a valid cluster number
659 or something is really wrong! */
660 if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
661 {
662
663 /* Send error message back to caller. */
664 return(FX_FILE_CORRUPT);
665 }
666
667 /* Setup the relative sector (this is zero for subsequent cluster. */
668 relative_sector = 0;
669
670 /* Calculate the next logical sector. */
671 logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
672 (((ULONG)cluster - FX_FAT_ENTRY_START) *
673 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
674 }
675 }
676 else
677 {
678
679 /* Increment the logical sector. */
680 logical_sector++;
681
682 /* Determine if the logical sector is valid. */
683 if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
684 {
685
686 /* We have exceeded the root directory. */
687
688 /* Send error message back to caller. */
689 return(FX_FILE_CORRUPT);
690 }
691 }
692
693 /* Read the sector. */
694 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
695 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
696
697 /* Determine if an error occurred. */
698 if (status != FX_SUCCESS)
699 {
700
701 /* Return the error status. */
702 return(status);
703 }
704
705 /* Setup logical sector. */
706 sector_base_ptr = media_ptr -> fx_media_memory_buffer;
707
708 /* Setup a fresh byte offset. */
709 byte_offset = 0;
710
711 /* Setup a new pointer into the buffer. */
712 work_ptr = sector_base_ptr;
713
714 #ifdef FX_ENABLE_FAULT_TOLERANT
715 /* Initialize data for fault tolerant. */
716 changed_ptr = work_ptr;
717 changed_size = 0;
718 changed_offset = 0;
719 #endif /* FX_ENABLE_FAULT_TOLERANT */
720 }
721
722 /* Decrement loop control. */
723 card--;
724 work_ptr[0] = (UCHAR)card;
725 }
726
727 /* Determine if there is a short name. */
728 if (entry_ptr -> fx_dir_entry_short_name[0] == 0)
729 {
730
731 /* Loop to copy the new short file name. */
732 for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
733 {
734
735 /* Pickup shortname character. */
736 alpha = shortname[i];
737
738 /* Now store the short name character. */
739 *work_ptr++ = (UCHAR)alpha;
740 }
741 }
742 else
743 {
744
745 /* Clear the short file name area. */
746 for (i = 0; i < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++)
747 {
748 work_ptr[i] = ' ';
749 }
750
751 /* Loop to copy the old short file name. */
752 for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
753 {
754
755 /* Check for end of copy conditions. */
756 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == '.')
757 {
758 break;
759 }
760 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
761 {
762 break;
763 }
764
765 /* Copy file name character. */
766 work_ptr[j] = (UCHAR)entry_ptr -> fx_dir_entry_short_name[i];
767 }
768
769 /* Determine if there is anything left in the short file name. */
770 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] != 0)
771 {
772
773 /* Pickup remaining characters. */
774 for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
775 {
776
777 /* If NULL is encountered, stop the copying. */
778 if ((UCHAR)entry_ptr -> fx_dir_entry_short_name[i] == 0)
779 {
780 break;
781 }
782
783 /* Copy file name character. */
784 work_ptr[j] = (UCHAR)entry_ptr -> fx_dir_entry_short_name[i];
785 }
786 }
787
788 /* Adjust the work pointer accordingly. */
789 work_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
790 }
791 }
792 else
793 {
794
795 /* Determine if long name was shorted. */
796 if (entry_ptr -> fx_dir_entry_long_name_shorted > 0)
797 {
798
799 /* Check for a valid short name. */
800 if ((UCHAR)(0x40 | entry_ptr -> fx_dir_entry_long_name_shorted) == (UCHAR)(*work_ptr))
801 {
802
803 /* Loop through the file name. */
804 for (j = 0; j < entry_ptr -> fx_dir_entry_long_name_shorted; j++)
805 {
806
807 /* Check for a free entry to be written. */
808 if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE)
809 {
810 /* Delete long parts. */
811 work_ptr[0] = (UCHAR)FX_DIR_ENTRY_FREE;
812 }
813
814 /* Setup pointers for the name write. */
815 work_ptr += FX_DIR_ENTRY_SIZE;
816 byte_offset += FX_DIR_ENTRY_SIZE;
817
818 #ifdef FX_ENABLE_FAULT_TOLERANT
819 /* Update changed_size. */
820 changed_size += FX_DIR_ENTRY_SIZE;
821 #endif /* FX_ENABLE_FAULT_TOLERANT */
822
823 /* Determine if the write is within the current sector. */
824 if (byte_offset >= media_ptr -> fx_media_bytes_per_sector)
825 {
826 #ifdef FX_ENABLE_FAULT_TOLERANT
827 if (media_ptr -> fx_media_fault_tolerant_enabled)
828 {
829
830 /* Redirect this request to log file. */
831 status = _fx_fault_tolerant_add_dir_log(media_ptr, (ULONG64) logical_sector, changed_offset, changed_ptr, changed_size);
832 }
833 else
834 {
835 #endif /* FX_ENABLE_FAULT_TOLERANT */
836
837 /* Write the current sector out. */
838 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
839 sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
840 #ifdef FX_ENABLE_FAULT_TOLERANT
841 }
842 #endif /* FX_ENABLE_FAULT_TOLERANT */
843
844 /* Determine if an error occurred. */
845 if (status != FX_SUCCESS)
846 {
847
848 /* Return the error status. */
849 return(status);
850 }
851
852 /* Determine if we are in the root directory. */
853 if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
854 {
855
856 /* Determine the next sector of the directory entry. */
857 if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
858 {
859
860 /* More sectors in this cluster. */
861
862 /* Simply increment the logical sector. */
863 logical_sector++;
864
865 /* Increment the relative sector. */
866 relative_sector++;
867 }
868 else
869 {
870
871 /* We need to move to the next cluster. */
872
873 /* Pickup the next cluster. */
874 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
875
876 /* Check for I/O error. */
877 if (status != FX_SUCCESS)
878 {
879
880 /* Return error code. */
881 return(status);
882 }
883
884 /* Copy next cluster to the current cluster. */
885 cluster = next_cluster;
886
887 /* Check the value of the new cluster - it must be a valid cluster number
888 or something is really wrong! */
889 if ((cluster < FX_FAT_ENTRY_START) || (cluster >= media_ptr -> fx_media_fat_reserved))
890 {
891
892 /* Send error message back to caller. */
893 return(FX_FILE_CORRUPT);
894 }
895
896 /* Setup the relative sector (this is zero for subsequent cluster. */
897 relative_sector = 0;
898
899 /* Calculate the next logical sector. */
900 logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
901 (((ULONG)cluster - FX_FAT_ENTRY_START) *
902 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
903 }
904 }
905 else
906 {
907
908 /* Increment the logical sector. */
909 logical_sector++;
910
911 /* Determine if the logical sector is valid. */
912 if (logical_sector >= (ULONG)(media_ptr -> fx_media_data_sector_start))
913 {
914
915 /* We have exceeded the root directory. */
916
917 /* Send error message back to caller. */
918 return(FX_FILE_CORRUPT);
919 }
920 }
921
922 /* Read the next logical sector. */
923 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
924 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
925
926 /* Determine if an error occurred. */
927 if (status != FX_SUCCESS)
928 {
929
930 /* Return the error status. */
931 return(status);
932 }
933
934 /* Move to the next sector buffer. */
935 sector_base_ptr = media_ptr -> fx_media_memory_buffer;
936
937 /* Setup new buffer pointers. */
938 byte_offset = 0;
939 work_ptr = sector_base_ptr;
940
941 #ifdef FX_ENABLE_FAULT_TOLERANT
942 /* Initialize data for fault tolerant. */
943 changed_ptr = work_ptr;
944 changed_size = 0;
945 changed_offset = 0;
946 #endif /* FX_ENABLE_FAULT_TOLERANT */
947 }
948 }
949 }
950 }
951
952 /* This is an 8.3 name. First clear the directory name. */
953 for (j = 0; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; j++)
954 {
955 work_ptr[j] = ' ';
956 }
957
958 /* Copy leading dots in case of first two entries of a directory. */
959 for (i = 0; (UCHAR)entry_ptr -> fx_dir_entry_name[i] == '.'; i++)
960 {
961 work_ptr[i] = '.';
962 }
963
964 /* Determine if there are more characters to copy. */
965 if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] != 0)
966 {
967
968 /* Copy directory name. */
969 for (i = 0, j = 0; j < FX_DIR_NAME_SIZE; i++, j++)
970 {
971
972 /* Check for end of copy conditions. */
973 if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == '.')
974 {
975 break;
976 }
977 if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == 0)
978 {
979 break;
980 }
981
982 /* Pickup shortname character. */
983 alpha = entry_ptr -> fx_dir_entry_name[i];
984
985 /* Determine if character is lower case. */
986 if ((alpha >= 'a') && (alpha <= 'z'))
987 {
988
989 /* Store the character - converted to upper case. */
990 alpha = (CHAR)(alpha - ((CHAR)0x20));
991 }
992
993 /* Copy a name character. */
994 work_ptr[j] = (UCHAR)alpha;
995 }
996 }
997
998 /* Determine if there are more characters in the name. */
999 if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] != 0)
1000 {
1001
1002 /* Loop to copy the remainder of the name. */
1003 for (i++, j = FX_DIR_NAME_SIZE; j < FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE; i++, j++)
1004 {
1005
1006 /* Check for end of copy conditions. */
1007 if ((UCHAR)entry_ptr -> fx_dir_entry_name[i] == 0)
1008 {
1009 break;
1010 }
1011
1012 /* Pickup shortname character. */
1013 alpha = entry_ptr -> fx_dir_entry_name[i];
1014
1015 /* Determine if character is lower case. */
1016 if ((alpha >= 'a') && (alpha <= 'z'))
1017 {
1018
1019 /* Store the character - converted to upper case. */
1020 alpha = (CHAR)(alpha - ((CHAR)0x20));
1021 }
1022
1023 /* Copy a name character. */
1024 work_ptr[j] = (UCHAR)alpha;
1025 }
1026 }
1027
1028 /* Move to the next entry. */
1029 work_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
1030 }
1031
1032 /* Write out the 8.3 part of the name. */
1033
1034 /* Copy the attribute into the destination. */
1035 *work_ptr++ = entry_ptr -> fx_dir_entry_attributes;
1036
1037 /* Copy the reserved byte. */
1038 *work_ptr++ = entry_ptr -> fx_dir_entry_reserved;
1039
1040 /* Copy the created time in milliseconds. */
1041 *work_ptr++ = entry_ptr -> fx_dir_entry_created_time_ms;
1042
1043 /* Copy the created time. */
1044 _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_created_time);
1045 work_ptr = work_ptr + 2; /* Always 2 bytes */
1046
1047 /* Copy the created date. */
1048 _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_created_date);
1049 work_ptr = work_ptr + 2; /* Always 2 bytes */
1050
1051 /* Copy the last accessed date. */
1052 _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_last_accessed_date);
1053 work_ptr = work_ptr + 2; /* Always 2 bytes */
1054
1055 /* Determine if a FAT32 entry is present. */
1056 if (media_ptr -> fx_media_32_bit_FAT)
1057 {
1058
1059 /* Yes, FAT32 is present, store upper half of cluster. */
1060 temp = (entry_ptr -> fx_dir_entry_cluster >> 16);
1061 _fx_utility_16_unsigned_write(work_ptr, temp);
1062 }
1063 else
1064 {
1065
1066 /* No, FAT16 or FAT12 is present, just write a 0 for
1067 the upper half of the cluster. */
1068 _fx_utility_16_unsigned_write(work_ptr, 0);
1069 }
1070
1071 /* Advance the entry pointer. */
1072 work_ptr = work_ptr + 2; /* Always 2 bytes */
1073
1074 /* Copy the time into the destination. */
1075 _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_time);
1076 work_ptr = work_ptr + 2; /* Always 2 bytes */
1077
1078 /* Copy the date into the destination. */
1079 _fx_utility_16_unsigned_write(work_ptr, entry_ptr -> fx_dir_entry_date);
1080 work_ptr = work_ptr + 2; /* Always 2 bytes */
1081
1082 /* Copy the starting cluster into the destination. */
1083 _fx_utility_16_unsigned_write(work_ptr, (UINT)entry_ptr -> fx_dir_entry_cluster);
1084 work_ptr = work_ptr + 2; /* Always 2 bytes */
1085
1086 /* Copy the file size into the destination. */
1087 _fx_utility_32_unsigned_write(work_ptr, (ULONG)entry_ptr -> fx_dir_entry_file_size);
1088
1089 #ifdef FX_ENABLE_FAULT_TOLERANT
1090 /* Update changed_size. */
1091 changed_size += FX_DIR_ENTRY_SIZE;
1092
1093 if (media_ptr -> fx_media_fault_tolerant_enabled &&
1094 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
1095 {
1096
1097 /* Redirect this request to log file. */
1098 status = _fx_fault_tolerant_add_dir_log(media_ptr, (ULONG64) logical_sector, changed_offset, changed_ptr, changed_size);
1099 }
1100 else
1101 {
1102 #endif /* FX_ENABLE_FAULT_TOLERANT */
1103
1104 /* Write the directory sector to the media. */
1105 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) logical_sector,
1106 sector_base_ptr, ((ULONG) 1), FX_DIRECTORY_SECTOR);
1107 #ifdef FX_ENABLE_FAULT_TOLERANT
1108 }
1109 #endif /* FX_ENABLE_FAULT_TOLERANT */
1110
1111 /* Determine if an error occurred. */
1112 if (status != FX_SUCCESS)
1113 {
1114
1115 /* Return the error status. */
1116 return(status);
1117 }
1118
1119 #ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
1120
1121 /* Determine if there is a previously found directory entry in the directory
1122 search cache. */
1123 if (media_ptr -> fx_media_last_found_name[0])
1124 {
1125
1126 /* Determine if the cached search directory entry matches the directory entry being
1127 written. */
1128 if ((entry_ptr -> fx_dir_entry_log_sector == media_ptr -> fx_media_last_found_entry.fx_dir_entry_log_sector) &&
1129 (entry_ptr -> fx_dir_entry_byte_offset == media_ptr -> fx_media_last_found_entry.fx_dir_entry_byte_offset))
1130 {
1131
1132 /* Yes, this entry is the same as the one currently in the directory search cache.
1133 Update various fields in the directory search cache with the information being
1134 written now. */
1135 media_ptr -> fx_media_last_found_entry.fx_dir_entry_cluster = entry_ptr -> fx_dir_entry_cluster;
1136 media_ptr -> fx_media_last_found_entry.fx_dir_entry_file_size = entry_ptr -> fx_dir_entry_file_size;
1137 media_ptr -> fx_media_last_found_entry.fx_dir_entry_attributes = entry_ptr -> fx_dir_entry_attributes;
1138 media_ptr -> fx_media_last_found_entry.fx_dir_entry_time = entry_ptr -> fx_dir_entry_time;
1139 media_ptr -> fx_media_last_found_entry.fx_dir_entry_date = entry_ptr -> fx_dir_entry_date;
1140 media_ptr -> fx_media_last_found_entry.fx_dir_entry_reserved = entry_ptr -> fx_dir_entry_reserved;
1141 media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time_ms = entry_ptr -> fx_dir_entry_created_time_ms;
1142 media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_time = entry_ptr -> fx_dir_entry_created_time;
1143 media_ptr -> fx_media_last_found_entry.fx_dir_entry_created_date = entry_ptr -> fx_dir_entry_created_date;
1144 }
1145 }
1146 #endif
1147
1148 /* Return success to the caller. */
1149 return(FX_SUCCESS);
1150 }
1151
1152