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