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 /** Unicode */
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_unicode.h"
29 #include "fx_utility.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _fx_unicode_directory_entry_read PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function reads a unicode directory entry. */
45 /* */
46 /* INPUT */
47 /* */
48 /* media_ptr Pointer to media */
49 /* source_dir Pointer to source directory */
50 /* entry_ptr Entry index in the directory */
51 /* destination_ptr Destination directory */
52 /* unicode_name Destination unicode name */
53 /* unicode_size Destination unicode name size */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _fx_utility_FAT_entry_read Read a FAT entry */
62 /* _fx_utility_logical_sector_read Read a logical sector */
63 /* _fx_utility_16_unsigned_read Read a 2-byte value */
64 /* _fx_utility_32_unsigned_read Read a 4-byte value */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Unicode Utilities */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
75 /* 09-30-2020 William E. Lamie Modified comment(s), */
76 /* resulting in version 6.1 */
77 /* */
78 /**************************************************************************/
_fx_unicode_directory_entry_read(FX_MEDIA * media_ptr,FX_DIR_ENTRY * source_dir,ULONG * entry_ptr,FX_DIR_ENTRY * destination_ptr,UCHAR * unicode_name,ULONG * unicode_size)79 UINT _fx_unicode_directory_entry_read(FX_MEDIA *media_ptr, FX_DIR_ENTRY *source_dir,
80 ULONG *entry_ptr, FX_DIR_ENTRY *destination_ptr,
81 UCHAR *unicode_name, ULONG *unicode_size)
82 {
83
84 UINT i, j, k, card, dotflag, get_short_name;
85 UINT number_of_lfns;
86 UINT status;
87 ULONG cluster, next_cluster = 0;
88 UINT relative_cluster;
89 UINT relative_sector;
90 ULONG logical_sector;
91 ULONG byte_offset;
92 ULONG bytes_per_cluster;
93 UCHAR *read_ptr;
94 CHAR *short_name_ptr;
95 ULONG entry = *entry_ptr;
96 UINT u;
97
98
99 #ifndef FX_MEDIA_STATISTICS_DISABLE
100
101 /* Increment the number of directory entry read requests. */
102 media_ptr -> fx_media_directory_entry_reads++;
103 #endif
104
105 /* Calculate the byte offset of this directory entry. */
106 byte_offset = entry * FX_DIR_ENTRY_SIZE;
107
108 /* Determine if a sub-directory or FAT32 root directory is specified. */
109 if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
110 {
111
112 /* Yes, a sub-directory is present. */
113
114 /* Calculate the number of bytes per cluster. */
115 bytes_per_cluster = ((ULONG)media_ptr -> fx_media_bytes_per_sector) *
116 ((ULONG)media_ptr -> fx_media_sectors_per_cluster);
117
118 /* Check for invalid value. */
119 if (bytes_per_cluster == 0)
120 {
121
122 /* Invalid media, return error. */
123 return(FX_MEDIA_INVALID);
124 }
125
126 /* Now determine the relative cluster in the sub-directory file. */
127 relative_cluster = (UINT)(byte_offset / bytes_per_cluster);
128
129 /* Calculate the byte offset within the cluster. */
130 byte_offset = byte_offset % bytes_per_cluster;
131
132 /* Now figure out the relative sector within the cluster. */
133 relative_sector = (UINT)(byte_offset / ((ULONG)media_ptr -> fx_media_bytes_per_sector));
134
135 /* Read the directory sector into the internal memory buffer. */
136
137 /* Determine if there is a sub-directory. */
138 if (source_dir)
139 {
140
141 /* Determine if this source directory has valid information from the previous call. */
142 if ((source_dir -> fx_dir_entry_last_search_cluster) &&
143 (source_dir -> fx_dir_entry_last_search_relative_cluster <= relative_cluster) &&
144 (source_dir -> fx_dir_entry_last_search_log_sector == source_dir -> fx_dir_entry_log_sector) &&
145 (source_dir -> fx_dir_entry_last_search_byte_offset == source_dir -> fx_dir_entry_byte_offset))
146 {
147
148 /* Use the previous information to start the search. */
149 cluster = source_dir -> fx_dir_entry_last_search_cluster;
150
151 /* Setup the relative cluster index to the saved relative cluster. */
152 i = source_dir -> fx_dir_entry_last_search_relative_cluster;
153
154 /* Clear the search cluster. It will be updated prior to successful return. */
155 source_dir -> fx_dir_entry_last_search_cluster = 0;
156 }
157 else
158 {
159
160 /* Nothing from the previous directory read, just setup the starting cluster to the
161 beginning of the sub-directory. */
162 cluster = source_dir -> fx_dir_entry_cluster;
163
164 /* Setup the relative cluster index to zero. */
165 i = 0;
166 }
167 }
168 else
169 {
170
171 /* No, setup the starting cluster to the FAT32 root cluster. */
172 cluster = media_ptr -> fx_media_root_cluster_32;
173
174 /* Setup the relative cluster index to zero. */
175 i = 0;
176 }
177
178 /* Loop to position to the appropriate cluster. */
179 while (i < relative_cluster)
180 {
181
182 /* Check the value of the new cluster - it must be a valid cluster number
183 or something is really wrong! */
184 if ((cluster < FX_FAT_ENTRY_START) || (cluster > media_ptr -> fx_media_fat_reserved))
185 {
186
187 /* Send error message back to caller. */
188 return(FX_FILE_CORRUPT);
189 }
190
191 /* Read the next cluster. */
192 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
193
194 /* There is a potential for loop, but hardly anything can be done */
195
196 /* Check for I/O error. */
197 if (status != FX_SUCCESS)
198 {
199
200 /* Return error code. */
201 return(status);
202 }
203
204 /* Setup the actual cluster. */
205 cluster = next_cluster;
206
207 /* Increment the relative cluster number. */
208 i++;
209 }
210
211 /* At this point, the directory data sector needs to be read. */
212 logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
213 (((ULONG)cluster - FX_FAT_ENTRY_START) *
214 ((ULONG)media_ptr -> fx_media_sectors_per_cluster)) +
215 relative_sector;
216
217 /* Read the logical directory sector. */
218 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
219 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
220
221 /* Determine if an error occurred. */
222 if (status != FX_SUCCESS)
223 {
224
225 /* Return error code. */
226 return(status);
227 }
228
229 /* Calculate the byte offset within this sector. */
230 byte_offset = byte_offset % media_ptr -> fx_media_bytes_per_sector;
231 }
232 else
233 {
234
235 /* Read the entry from the root directory. */
236
237 /* Determine which sector the requested root directory entry is in. */
238 logical_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
239 (ULONG)media_ptr -> fx_media_root_sector_start;
240
241 /* Read the logical directory sector. */
242 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
243 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
244
245 /* Determine if an error occurred. */
246 if (status != FX_SUCCESS)
247 {
248
249 /* Return error code. */
250 return(status);
251 }
252
253 /* Set the cluster and relative variables (not used in this case) to avoid any compiler
254 warnings. */
255 relative_cluster = relative_sector = cluster = 0;
256
257 /* Now calculate the byte offset into this sector. */
258 byte_offset = byte_offset -
259 ((logical_sector - (ULONG)media_ptr -> fx_media_root_sector_start) *
260 media_ptr -> fx_media_bytes_per_sector);
261 }
262
263 /* Setup a pointer into the buffer. */
264 read_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
265
266 /* Save the logical sector and byte offset in the returned directory entry. */
267 destination_ptr -> fx_dir_entry_log_sector = logical_sector;
268 destination_ptr -> fx_dir_entry_byte_offset = byte_offset;
269
270 /* Clear the short file name information. */
271 destination_ptr -> fx_dir_entry_long_name_shorted = 0;
272 destination_ptr -> fx_dir_entry_short_name[0] = 0;
273
274 /* Setup short name pointer. */
275 short_name_ptr = destination_ptr -> fx_dir_entry_name;
276
277 /* Initialize the unicode index. */
278 u = 0;
279
280 /* Check if long file name exists. */
281 get_short_name = 0;
282 if ((*(read_ptr + 11) == (UCHAR)FX_LONG_NAME) && (*read_ptr != (UCHAR)FX_DIR_ENTRY_FREE))
283 {
284
285 /* Collate the long name. */
286
287
288 /* Save the number of LFN entries. */
289 number_of_lfns = (UINT)(*read_ptr & (UCHAR)0x1f);
290
291 if(number_of_lfns == 0)
292 {
293 /* Number of LFN cannot is 1-based. Therefore it cannot be zero. */
294 return(FX_FILE_CORRUPT);
295 }
296 else
297 {
298 /* Pickup the file name length. */
299 i = (number_of_lfns - 1) * FX_LONG_NAME_ENTRY_LEN;
300 }
301
302 /* Check the file name size. */
303 if (i >= (FX_MAX_LONG_NAME_LEN - 1))
304 {
305
306 /* Name is too big, shorten it. */
307 get_short_name = 1;
308 destination_ptr -> fx_dir_entry_long_name_shorted = (UINT)(*read_ptr & (UCHAR)0x1f);
309 }
310 else
311 {
312
313 /* Size of name is fine, save pointer to short file name. */
314 short_name_ptr = destination_ptr -> fx_dir_entry_short_name;
315
316 /* Loop to make sure the long file name is NULL terminated. */
317 j = i + FX_LONG_NAME_ENTRY_LEN + 1;
318 do
319 {
320 /* Place a NULL in the long name. */
321 destination_ptr -> fx_dir_entry_name[i] = 0;
322
323 /* Position to the next entry. */
324 i++;
325 } while ((i < j) && (i < FX_MAX_LONG_NAME_LEN));
326 }
327
328 /* Loop to pickup the rest of the name. */
329 do
330 {
331
332 /* Get the lower 5 bit containing the cardinality. */
333 card = (*read_ptr) & 0x1f;
334
335 if(card == 0)
336 {
337
338 /* Number of LFN starts from one. Therefore it cannot be zero. */
339 return(FX_FILE_CORRUPT);
340 }
341 else
342 {
343 card = card - 1;
344 }
345 /* For simplicity no checksum or cardinality checking is done */
346 if ((get_short_name == 0) || (u))
347 {
348
349 /* Loop to pickup name. */
350 for (i = 1, j = 0, k = 0; i < FX_DIR_ENTRY_SIZE; i += 2)
351 {
352
353 if ((i == 11) || (i == 26))
354 {
355 continue;
356 }
357
358 /* i = 12, 27 is not generated due to +=2 */
359 if (i == 13)
360 {
361 i = 12;
362 continue; /* this time next unicode is byte offset 14*/
363 }
364
365 /* Determine if there is an actual unicode character present. */
366 if (read_ptr[i + 1])
367 {
368
369 /* Extended byte is non-zero, make sure both bytes of the unicode entry are not
370 all ones, since this is a normal case. */
371 if ((read_ptr[i + 1] != (UCHAR)0xFF) || (read_ptr[i] != (UCHAR)0xFF))
372 {
373
374 /* Name is an actual unicode name, shorten it. */
375 get_short_name = 1;
376
377 /* Save the number of directory entries the LFN has. This will be
378 used later when updating the 8.3 portion of the LFN. */
379 destination_ptr -> fx_dir_entry_long_name_shorted = number_of_lfns;
380
381 /* Setup short name pointer. */
382 short_name_ptr = destination_ptr -> fx_dir_entry_name;
383 }
384 }
385
386 /* Determine if the character is NULL. */
387 if (((read_ptr[i] == FX_NULL) && (read_ptr[i + 1] == FX_NULL)) ||
388 ((read_ptr[i] == (UCHAR)0xFF) && (read_ptr[i + 1] == (UCHAR)0xFF)))
389 {
390 continue;
391 }
392
393 /* Determine if the name is too big. */
394 if ((card * 13 + j) >= (FX_MAX_LONG_NAME_LEN - 1))
395 {
396
397 /* Name is actually too big, shorten it. */
398 get_short_name = 1;
399
400 /* Save the number of directory entries the LFN has. This will be
401 used later when updating the 8.3 portion of the LFN. */
402 destination_ptr -> fx_dir_entry_long_name_shorted = number_of_lfns;
403
404 /* Also reposition the short name pointer. */
405 short_name_ptr = destination_ptr -> fx_dir_entry_name;
406
407 break;
408 }
409
410 /* Each entry contains 13 unicode and first byte ASCII, second byte is extended. */
411 if (get_short_name == 0)
412 {
413 destination_ptr -> fx_dir_entry_name[13 * card + j] = (CHAR)read_ptr[i];
414 }
415
416 /* Save the potential unicode characters. */
417 unicode_name[k + 26 * card + j] = read_ptr[i];
418 unicode_name[k + 26 * card + j + 1] = read_ptr[i + 1];
419 k++;
420 u++;
421
422 j++;
423 }
424 }
425
426 /* Determine if a new sector needs to be read. */
427 if (byte_offset + FX_DIR_ENTRY_SIZE >= media_ptr -> fx_media_bytes_per_sector)
428 {
429
430 /* Determine if a sub-directory or FAT32 root directory is specified. */
431 if ((source_dir) || (media_ptr -> fx_media_32_bit_FAT))
432 {
433
434 /* Determine the next sector of the directory entry. */
435 if (relative_sector < (media_ptr -> fx_media_sectors_per_cluster - 1))
436 {
437
438 /* More sectors in this cluster. */
439
440 /* Simply increment the logical sector. */
441 logical_sector++;
442
443 /* Increment the relative sector. */
444 relative_sector++;
445 }
446 else
447 {
448
449 /* We need to move to the next cluster. */
450
451 /* Pickup the next cluster. */
452 status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
453
454 /* Check for I/O error. */
455 if (status != FX_SUCCESS)
456 {
457
458 /* Return error code. */
459 return(status);
460 }
461
462 /* Copy next cluster to the current cluster. */
463 cluster = next_cluster;
464
465 /* Check the value of the new cluster - it must be a valid cluster number
466 or something is really wrong! */
467 if ((cluster < FX_FAT_ENTRY_START) || (cluster > media_ptr -> fx_media_fat_reserved))
468 {
469
470 /* Send error message back to caller. */
471 return(FX_FILE_CORRUPT);
472 }
473
474 /* Now increment the relative cluster. */
475 relative_cluster++;
476
477 /* Setup the relative sector (this is zero for subsequent cluster. */
478 relative_sector = 0;
479
480 /* Calculate the next logical sector. */
481 logical_sector = ((ULONG)media_ptr -> fx_media_data_sector_start) +
482 (((ULONG)cluster - FX_FAT_ENTRY_START) *
483 ((ULONG)media_ptr -> fx_media_sectors_per_cluster));
484 }
485 }
486 else
487 {
488
489 /* Non-FAT 32 root directory. */
490
491 /* Advance to the next sector. */
492 logical_sector++;
493
494 /* Determine if the logical sector is valid. */
495 if (logical_sector >= (ULONG)(media_ptr -> fx_media_root_sector_start + media_ptr -> fx_media_root_sectors))
496 {
497
498 /* Trying to read past root directory - send error message back to caller. */
499 return(FX_FILE_CORRUPT);
500 }
501 }
502
503 /* Read the new sector. */
504 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) logical_sector,
505 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
506
507 /* Check I/O status. */
508 if (status != FX_SUCCESS)
509 {
510 return(status);
511 }
512
513 /* Set the byte offset to 0 for new sector. */
514 byte_offset = 0;
515 }
516 else
517 {
518
519 /* Calculate the new byte offset. */
520 byte_offset += FX_DIR_ENTRY_SIZE;
521 }
522
523 /* Calculate the next read pointer. */
524 read_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
525
526 /* Move to the next entry. */
527 entry++;
528 } while (card > 0);
529
530 /* Set flag indicating long file name is present. */
531 destination_ptr -> fx_dir_entry_long_name_present = 1;
532 }
533 else
534 {
535 /* No long file name is present. */
536 get_short_name = 1;
537 }
538
539 /* Determine if we need to clear the long name flag. */
540 if (get_short_name == 1)
541 {
542
543 /* Clear the long name flag. */
544 destination_ptr -> fx_dir_entry_long_name_present = 0;
545 }
546
547 /* Store the unicode name size. */
548 *unicode_size = u;
549
550 /* Pickup the short file name. */
551 short_name_ptr[0] = 0;
552 dotflag = 0;
553 for (i = 0, j = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
554 {
555
556 /* Check for a NULL. */
557 if ((CHAR)read_ptr[i] == 0)
558 {
559 break;
560 }
561
562 /* Check for a dot. This happens for the first two directory entries, no
563 extra dot is needed. */
564 if ((CHAR)read_ptr[i] == '.')
565 {
566 dotflag = 2;
567 }
568
569 /* Check for a space. */
570 if ((CHAR)read_ptr[i] == ' ')
571 {
572 /* Put a dot if a character comes after space. */
573 if (dotflag == 0)
574 {
575 dotflag = 1;
576 }
577 continue;
578 }
579
580 /* Check for the main short file name size. */
581 if (i == FX_DIR_NAME_SIZE)
582 {
583 /* Check to see if we need to insert a dot. */
584 if (dotflag == 0)
585 {
586 dotflag = 1;
587 }
588 }
589
590 /* Check to see if we need to add a dot. */
591 if (dotflag == 1)
592 {
593 /* Add dot to short file name. */
594 short_name_ptr[j++] = '.';
595 dotflag = 2; /* no more dot for spaces */
596 }
597
598 /* Copy a character. */
599 short_name_ptr[j] = (CHAR)read_ptr[i];
600
601 /* Increment size. */
602 j++;
603 }
604
605 /* Determine if a long file name is present and its associated short file
606 name is actually free. */
607 if ((destination_ptr -> fx_dir_entry_long_name_present) && (((UCHAR)short_name_ptr[0]) == (UCHAR)FX_DIR_ENTRY_FREE))
608 {
609
610 /* Yes, the short file name is really free even though long file name entries directly precede it.
611 In this case, simply place the free directory marker at the front of the long file name. */
612 destination_ptr -> fx_dir_entry_name[0] = (CHAR)FX_DIR_ENTRY_FREE;
613 short_name_ptr[0] = (CHAR)0;
614 }
615
616 /* Determine if the short name pointer is NULL while the read pointer is
617 non-NULL. */
618 if ((short_name_ptr[0] == 0) && (read_ptr[0] == ' '))
619 {
620
621 /* This condition can occur with an all blank volume name. Simply
622 copy the volume name to the short name in this case. */
623 for (j = 0; j < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); j++)
624 {
625
626 /* Copy a byte of the volume name. */
627 short_name_ptr[j] = (CHAR)read_ptr[j];
628 }
629 }
630
631 /* Set end of string to null. */
632 short_name_ptr[j] = 0;
633
634 /* Load up the destination directory entry. */
635 read_ptr += (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE);
636
637 /* Copy the attribute into the destination. */
638 destination_ptr -> fx_dir_entry_attributes = *read_ptr++;
639
640 /* Pickup the reserved byte. */
641 destination_ptr -> fx_dir_entry_reserved = *read_ptr++;
642
643 /* Check for an undocumented NT file name feature for optimizing the storage
644 of all lower case file names that otherwise are valid 8.3 file names. The
645 following reserved bit definitions are present:
646
647 BIT3 - set if 8.3 is all in lower case and no extended filename.
648 BIT4 - set for file, clear for directory entry if no extended filename.
649
650 This is true for all NT systems. Prior to NT follows MSDOS FAT documentation and
651 is set to 0x00, all bits cleared. Therefore if BIT3 is set force lowercase. */
652 if ((get_short_name) && (destination_ptr -> fx_dir_entry_reserved & 0x08))
653 {
654
655 /* Microsoft undocumented NT file name feature... convert short name to lower
656 case. */
657 for (j = 0; j <= (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE) && (short_name_ptr[j] != 0x00); j++)
658 {
659
660 /* Determine if an upper case character is present. */
661 if ((short_name_ptr[j] >= 'A') && (short_name_ptr[j] <= 'Z'))
662 {
663
664 /* Yes, an upper case character is present. Force it to lower case. */
665 short_name_ptr[j] = (CHAR)((INT)short_name_ptr[j] + 32);
666 }
667 }
668 }
669
670 /* Pickup the created time in milliseconds. */
671 destination_ptr -> fx_dir_entry_created_time_ms = *read_ptr++;
672
673 /* Pickup the created time. */
674 destination_ptr -> fx_dir_entry_created_time = _fx_utility_16_unsigned_read(read_ptr);
675 read_ptr = read_ptr + 2; /* Always 2 bytes */
676
677 /* Pickup the created date. */
678 destination_ptr -> fx_dir_entry_created_date = _fx_utility_16_unsigned_read(read_ptr);
679 read_ptr = read_ptr + 2; /* Always 2 bytes */
680
681 /* Pickup the last accessed date. */
682 destination_ptr -> fx_dir_entry_last_accessed_date = _fx_utility_16_unsigned_read(read_ptr);
683 read_ptr = read_ptr + 2; /* Always 2 bytes */
684
685 /* read the upper 2 bytes of starting cluster - required only for 32 bit FAT */
686 if (media_ptr -> fx_media_32_bit_FAT)
687 {
688
689 /* FAT32 only. */
690 destination_ptr -> fx_dir_entry_cluster = _fx_utility_16_unsigned_read(read_ptr);
691 destination_ptr -> fx_dir_entry_cluster <<= 16;
692 }
693 else
694 {
695 /* Not required for non FAT32. */
696 destination_ptr -> fx_dir_entry_cluster = 0;
697 }
698
699 /* Advance the read pointer. */
700 read_ptr = read_ptr + 2; /* Always 2 bytes */
701
702 /* Copy the time into the destination. */
703 destination_ptr -> fx_dir_entry_time = _fx_utility_16_unsigned_read(read_ptr);
704 read_ptr = read_ptr + 2; /* Always 2 bytes */
705
706 /* Copy the date into the destination. */
707 destination_ptr -> fx_dir_entry_date = _fx_utility_16_unsigned_read(read_ptr);
708 read_ptr = read_ptr + 2; /* Always 2 bytes */
709
710 /* Copy the starting cluster into the destination. */
711 destination_ptr -> fx_dir_entry_cluster += _fx_utility_16_unsigned_read(read_ptr);
712 read_ptr = read_ptr + 2; /* Always 2 bytes */
713
714 /* Copy the file size into the destination. */
715 destination_ptr -> fx_dir_entry_file_size = _fx_utility_32_unsigned_read(read_ptr);
716
717 /* Clear the destination search specific fields. */
718 destination_ptr -> fx_dir_entry_last_search_cluster = 0;
719 destination_ptr -> fx_dir_entry_last_search_relative_cluster = 0;
720 destination_ptr -> fx_dir_entry_last_search_log_sector = 0;
721 destination_ptr -> fx_dir_entry_last_search_byte_offset = 0;
722
723 /* Remember the entry number. */
724 destination_ptr -> fx_dir_entry_number = entry;
725
726 /* Return entry number. */
727 *entry_ptr = entry;
728
729 /* Determine if we should remember the last cluster and relative cluster. */
730 if (source_dir)
731 {
732
733 /* Yes, remember the last cluster and relative cluster for a subsequent call
734 to read a directory entry. */
735 source_dir -> fx_dir_entry_last_search_cluster = cluster;
736 source_dir -> fx_dir_entry_last_search_relative_cluster = relative_cluster;
737
738 /* Also remember several other items that are unique to the directory... just to verify that the
739 search information can be used. */
740 source_dir -> fx_dir_entry_last_search_log_sector = source_dir -> fx_dir_entry_log_sector;
741 source_dir -> fx_dir_entry_last_search_byte_offset = source_dir -> fx_dir_entry_byte_offset;
742 }
743
744 /* Return success to the caller. */
745 return(FX_SUCCESS);
746 }
747
748