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_file.h"
31 #include "fx_utility.h"
32 #ifdef FX_ENABLE_FAULT_TOLERANT
33 #include "fx_fault_tolerant.h"
34 #endif /* FX_ENABLE_FAULT_TOLERANT */
35
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _fx_directory_create PORTABLE C */
42 /* 6.1 */
43 /* AUTHOR */
44 /* */
45 /* William E. Lamie, Microsoft Corporation */
46 /* */
47 /* DESCRIPTION */
48 /* */
49 /* This function first attempts to find the specified directory. */
50 /* If found, the create request is invalid and an error is returned */
51 /* to the caller. After the file name verification is made, a search */
52 /* for a free directory entry will be made. If nothing is available, */
53 /* an error will be returned to the caller. Otherwise, if all is */
54 /* okay, an empty directory will be created. */
55 /* */
56 /* INPUT */
57 /* */
58 /* media_ptr Media control block pointer */
59 /* directory_name Directory name */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* return status */
64 /* */
65 /* CALLS */
66 /* */
67 /* _fx_directory_entry_write Write the new directory entry */
68 /* _fx_directory_name_extract Pickup next part of name */
69 /* _fx_directory_search Search for the file name in */
70 /* the directory structure */
71 /* _fx_directory_free_search Search for a free directory */
72 /* entry */
73 /* _fx_utility_FAT_flush Flush written FAT entries */
74 /* _fx_utility_FAT_entry_read Read a FAT entry */
75 /* _fx_utility_FAT_entry_write Write a FAT entry */
76 /* _fx_utility_logical_sector_flush Flush the written log sector */
77 /* _fx_utility_logical_sector_read Read logical sector */
78 /* _fx_fault_tolerant_transaction_start Start fault tolerant */
79 /* transaction */
80 /* _fx_fault_tolerant_transaction_end End fault tolerant transaction*/
81 /* _fx_fault_tolerant_recover Recover FAT chain */
82 /* _fx_fault_tolerant_reset_log_file Reset the log file */
83 /* */
84 /* CALLED BY */
85 /* */
86 /* Application Code */
87 /* */
88 /* RELEASE HISTORY */
89 /* */
90 /* DATE NAME DESCRIPTION */
91 /* */
92 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
93 /* 09-30-2020 William E. Lamie Modified comment(s), */
94 /* resulting in version 6.1 */
95 /* */
96 /**************************************************************************/
_fx_directory_create(FX_MEDIA * media_ptr,CHAR * directory_name)97 UINT _fx_directory_create(FX_MEDIA *media_ptr, CHAR *directory_name)
98 {
99
100 UINT status;
101 ULONG FAT_index;
102 ULONG FAT_value;
103 UINT sectors;
104 ULONG total_clusters;
105 CHAR *work_ptr;
106 ULONG64 logical_sector;
107 ULONG i;
108 FX_DIR_ENTRY dir_entry;
109 FX_DIR_ENTRY sub_dir_entry;
110 FX_DIR_ENTRY search_directory;
111
112 FX_INT_SAVE_AREA
113
114
115 #ifndef FX_MEDIA_STATISTICS_DISABLE
116
117 /* Increment the number of times this service has been called. */
118 media_ptr -> fx_media_directory_creates++;
119 #endif
120
121 /* Determine if the supplied name is less than the maximum supported name size. The
122 maximum name (FX_MAX_LONG_NAME_LEN) is defined in fx_api.h. */
123 i = 0;
124 work_ptr = (CHAR *)directory_name;
125 while (*work_ptr && (i < FX_MAX_LONG_NAME_LEN))
126 {
127
128 /* Determine if the character designates a new path. */
129 if ((*work_ptr == '\\') || (*work_ptr == '/'))
130 {
131 /* Yes, reset the name size. */
132 i = 0;
133 }
134 /* Check for leading spaces. */
135 else if ((*work_ptr != ' ') || (i != 0))
136 {
137
138 /* No leading spaces, increment the name size. */
139 i++;
140 }
141
142 /* Move to the next character. */
143 work_ptr++;
144 }
145
146 /* Determine if the supplied name is valid. */
147 if ((i == 0) || (i >= FX_MAX_LONG_NAME_LEN))
148 {
149
150 /* Return an invalid name value. */
151 return(FX_INVALID_NAME);
152 }
153
154 /* Setup pointer to media name buffer. */
155 dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN;
156
157 /* Setup search directory pointer to another media name buffer. */
158 search_directory.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + FX_MAX_LONG_NAME_LEN * 2;
159
160 /* Clear the short name string. */
161 dir_entry.fx_dir_entry_short_name[0] = 0;
162
163 /* Clear the search short name string. */
164 search_directory.fx_dir_entry_short_name[0] = 0;
165
166 /* Check the media to make sure it is open. */
167 if (media_ptr -> fx_media_id != FX_MEDIA_ID)
168 {
169
170 /* Return the media not opened error. */
171 return(FX_MEDIA_NOT_OPEN);
172 }
173
174 /* If trace is enabled, insert this event into the trace buffer. */
175 FX_TRACE_IN_LINE_INSERT(FX_TRACE_DIRECTORY_CREATE, media_ptr, directory_name, 0, 0, FX_TRACE_DIRECTORY_EVENTS, 0, 0)
176
177 /* Protect against other threads accessing the media. */
178 FX_PROTECT
179
180 /* Check for write protect at the media level (set by driver). */
181 if (media_ptr -> fx_media_driver_write_protect)
182 {
183
184 /* Release media protection. */
185 FX_UNPROTECT
186
187 /* Return write protect error. */
188 return(FX_WRITE_PROTECT);
189 }
190
191 /* Make sure there is at least one cluster remaining for the new file. */
192 if (!media_ptr -> fx_media_available_clusters)
193 {
194
195 /* Release media protection. */
196 FX_UNPROTECT
197
198 /* Return a no-space error. */
199 return(FX_NO_MORE_SPACE);
200 }
201
202 /* Search the system for the supplied directory name. */
203 status = _fx_directory_search(media_ptr, directory_name, &dir_entry, &search_directory, &work_ptr);
204
205 /* Determine if the search was successful. */
206 if (status == FX_SUCCESS)
207 {
208
209 /* Release media protection. */
210 FX_UNPROTECT
211
212 /* Directory found - Return the error code. */
213 return(FX_ALREADY_CREATED);
214 }
215
216 /* Determine if there is anything left after the name. */
217 if (_fx_directory_name_extract(work_ptr, &dir_entry.fx_dir_entry_name[0]))
218 {
219
220 /* Release media protection. */
221 FX_UNPROTECT
222
223 /* Extra information after the file name, return an invalid name
224 error. */
225 return(FX_INVALID_PATH);
226 }
227
228
229 #ifdef FX_ENABLE_FAULT_TOLERANT
230 /* Start transaction. */
231 _fx_fault_tolerant_transaction_start(media_ptr);
232 #endif /* FX_ENABLE_FAULT_TOLERANT */
233
234 /* Find a free slot for the new directory. */
235 status = _fx_directory_free_search(media_ptr, &search_directory, &dir_entry);
236
237 /* Determine if the search was successful. */
238 if (status != FX_SUCCESS)
239 {
240
241 #ifdef FX_ENABLE_FAULT_TOLERANT
242 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
243 #endif /* FX_ENABLE_FAULT_TOLERANT */
244
245 /* Release media protection. */
246 FX_UNPROTECT
247
248 /* Return the error code. */
249 return(status);
250 }
251
252 /* Now allocate a cluster for our new sub-directory entry. */
253
254 FAT_index = media_ptr -> fx_media_cluster_search_start;
255 total_clusters = media_ptr -> fx_media_total_clusters;
256
257 /* Loop to find the first available cluster. */
258 do
259 {
260
261 /* Make sure we don't go past the FAT table. */
262 if (!total_clusters)
263 {
264
265 #ifdef FX_ENABLE_FAULT_TOLERANT
266 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
267 #endif /* FX_ENABLE_FAULT_TOLERANT */
268
269 /* Release media protection. */
270 FX_UNPROTECT
271
272 /* Something is wrong with the media - the desired clusters were
273 not found in the FAT table. */
274 return(FX_NO_MORE_SPACE);
275 }
276
277 /* Read FAT entry. */
278 status = _fx_utility_FAT_entry_read(media_ptr, FAT_index, &FAT_value);
279
280 /* Check for a bad status. */
281 if (status != FX_SUCCESS)
282 {
283
284 #ifdef FX_ENABLE_FAULT_TOLERANT
285 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
286 #endif /* FX_ENABLE_FAULT_TOLERANT */
287
288 /* Release media protection. */
289 FX_UNPROTECT
290
291 /* Return the bad status. */
292 return(status);
293 }
294
295 /* Decrement the total cluster count. */
296 total_clusters--;
297
298 /* Determine if the FAT entry is free. */
299 if (FAT_value == FX_FREE_CLUSTER)
300 {
301
302 /* Move cluster search pointer forward. */
303 media_ptr -> fx_media_cluster_search_start = FAT_index + 1;
304
305 /* Determine if this needs to be wrapped. */
306 if (media_ptr -> fx_media_cluster_search_start >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
307 {
308
309 /* Wrap the search to the beginning FAT entry. */
310 media_ptr -> fx_media_cluster_search_start = FX_FAT_ENTRY_START;
311 }
312
313 /* Break this loop. */
314 break;
315 }
316 else
317 {
318
319 /* FAT entry is not free... Advance the FAT index. */
320 FAT_index++;
321
322 /* Determine if we need to wrap the FAT index around. */
323 if (FAT_index >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
324 {
325
326 /* Wrap the search to the beginning FAT entry. */
327 FAT_index = FX_FAT_ENTRY_START;
328 }
329 }
330 } while (FX_TRUE);
331
332 /* Decrease the number of available clusters for the media. */
333 media_ptr -> fx_media_available_clusters--;
334
335 /* Defer the writing of the FAT entry until the directory's first sector
336 has been properly written. If a power loss occurs prior to writing
337 the FAT entry, it will not result in a lost cluster. */
338
339 /* Populate the directory entry. */
340
341 /* Isolate the file name. */
342 _fx_directory_name_extract(work_ptr, &dir_entry.fx_dir_entry_name[0]);
343
344 /* Lockout interrupts for time/date access. */
345 FX_DISABLE_INTS
346
347 /* Set time and date stamps. */
348 dir_entry.fx_dir_entry_time = _fx_system_time;
349 dir_entry.fx_dir_entry_date = _fx_system_date;
350
351 /* Restore interrupts. */
352 FX_RESTORE_INTS
353
354 /* Set the attributes for the file. */
355 dir_entry.fx_dir_entry_attributes = FX_DIRECTORY;
356
357
358 /* Set file size to 0. */
359 dir_entry.fx_dir_entry_file_size = 0;
360
361
362 /* Set the cluster to EOF. */
363 dir_entry.fx_dir_entry_cluster = FAT_index;
364
365 /* Is there a leading dot? */
366 if (dir_entry.fx_dir_entry_name[0] == '.')
367 {
368
369 /* Yes, toggle the hidden attribute bit. */
370 dir_entry.fx_dir_entry_attributes |= FX_HIDDEN;
371 }
372
373 /* In previous versions, the new directory was written here. It
374 is now at the bottom of the file - after the FAT and the initial
375 sub-directory is written out. This makes the directory create
376 more fault tolerant. */
377
378 /* Calculate the first sector of the sub-directory file. */
379 logical_sector = ((ULONG) media_ptr -> fx_media_data_sector_start) +
380 (((ULONG64) FAT_index - FX_FAT_ENTRY_START) *
381 ((ULONG) media_ptr -> fx_media_sectors_per_cluster));
382
383 /* Pickup the number of sectors for the initial sub-directory cluster. */
384 sectors = media_ptr -> fx_media_sectors_per_cluster;
385
386 /* Read the first logical sector associated with the allocated
387 cluster. */
388 status = _fx_utility_logical_sector_read(media_ptr, logical_sector,
389 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_DIRECTORY_SECTOR);
390
391 /* Determine if an error occurred. */
392 if (status != FX_SUCCESS)
393 {
394
395 #ifdef FX_ENABLE_FAULT_TOLERANT
396 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
397 #endif /* FX_ENABLE_FAULT_TOLERANT */
398
399 /* Release media protection. */
400 FX_UNPROTECT
401
402 /* Return error code. */
403 return(status);
404 }
405
406 /* Clear the entire first sector of the new sub-directory cluster. */
407 work_ptr = (CHAR *)media_ptr -> fx_media_memory_buffer;
408 i = 0;
409 while (i < media_ptr -> fx_media_bytes_per_sector)
410 {
411
412 /* Clear 4 bytes. */
413 *((ULONG *)work_ptr) = (ULONG)0;
414
415 /* Increment pointer. */
416 work_ptr = work_ptr + sizeof(ULONG);
417
418 /* Increment counter. */
419 i = i + (ULONG)sizeof(ULONG);
420 }
421
422 #ifdef FX_ENABLE_FAULT_TOLERANT
423 if (media_ptr -> fx_media_fault_tolerant_enabled == FX_TRUE)
424 {
425
426 /* Write back. */
427 status = _fx_utility_logical_sector_write(media_ptr, logical_sector,
428 media_ptr -> fx_media_memory_buffer, (ULONG)1, FX_DIRECTORY_SECTOR);
429
430 /* Determine if an error occurred. */
431 if (status != FX_SUCCESS)
432 {
433 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
434
435 /* Release media protection. */
436 FX_UNPROTECT
437
438 /* Return error code. */
439 return(status);
440 }
441
442 /* Force flush the internal logical sector cache. */
443 status = _fx_utility_logical_sector_flush(media_ptr, logical_sector, sectors, FX_TRUE);
444
445 /* Determine if the write was successful. */
446 if (status != FX_SUCCESS)
447 {
448 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
449
450 /* Release media protection. */
451 FX_UNPROTECT
452
453 /* Return the error code. */
454 return(status);
455 }
456 }
457 #endif /* FX_ENABLE_FAULT_TOLERANT */
458
459 /* Determine if there are more sectors to clear in the first cluster of the new
460 sub-directory. */
461 if (sectors > 1)
462 {
463
464 /* Yes, invalidate all cached sectors that are contained in the newly allocated first
465 cluster of the directory. */
466
467 #ifdef FX_ENABLE_FAULT_TOLERANT
468 if (media_ptr -> fx_media_fault_tolerant_enabled == FX_FALSE)
469 #endif /* FX_ENABLE_FAULT_TOLERANT */
470 {
471
472 /* Flush the internal logical sector cache. */
473 status = _fx_utility_logical_sector_flush(media_ptr, logical_sector + 1, ((ULONG64)(sectors - 1)), FX_TRUE);
474
475 /* Determine if the write was successful. */
476 if (status != FX_SUCCESS)
477 {
478
479 #ifdef FX_ENABLE_FAULT_TOLERANT
480 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
481 #endif /* FX_ENABLE_FAULT_TOLERANT */
482
483 /* Release media protection. */
484 FX_UNPROTECT
485
486 /* Return the error code. */
487 return(status);
488 }
489 }
490
491 /* Clear all additional sectors of new sub-directory. */
492 sectors--;
493 while (sectors)
494 {
495
496 #ifndef FX_MEDIA_STATISTICS_DISABLE
497
498 /* Increment the number of driver write sector(s) requests. */
499 media_ptr -> fx_media_driver_write_requests++;
500 #endif
501
502 /* Build Write request to the driver. */
503 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
504 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
505 media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
506 #ifdef FX_DRIVER_USE_64BIT_LBA
507 media_ptr -> fx_media_driver_logical_sector = logical_sector + ((ULONG)sectors);
508 #else
509 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector + ((ULONG)sectors);
510 #endif
511 media_ptr -> fx_media_driver_sectors = 1;
512 media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR;
513
514 /* Set the system write flag since we are writing a directory sector. */
515 media_ptr -> fx_media_driver_system_write = FX_TRUE;
516
517 /* If trace is enabled, insert this event into the trace buffer. */
518 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)
519
520 /* Invoke the driver to write the sector. */
521 (media_ptr -> fx_media_driver_entry) (media_ptr);
522
523 /* Clear the system write flag. */
524 media_ptr -> fx_media_driver_system_write = FX_FALSE;
525
526 /* Determine if an error occurred. */
527 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
528 {
529
530 #ifdef FX_ENABLE_FAULT_TOLERANT
531 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
532 #endif /* FX_ENABLE_FAULT_TOLERANT */
533
534 /* Release media protection. */
535 FX_UNPROTECT
536
537 /* Return error code. */
538 return(media_ptr -> fx_media_driver_status);
539 }
540
541 /* Decrease the number of sectors to clear. */
542 sectors--;
543 }
544 }
545
546
547 /* Now setup the first sector with the initial sub-directory information. */
548
549 /* Copy the base directory entry to the sub-directory entry. */
550 sub_dir_entry = dir_entry;
551
552 /* Setup pointer to media name buffer. */
553 sub_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + (FX_MAX_LONG_NAME_LEN * 3);
554
555 /* Set the directory entry name to all blanks. */
556 work_ptr = &sub_dir_entry.fx_dir_entry_name[0];
557 for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
558 {
559 *work_ptr++ = ' ';
560 }
561
562 sub_dir_entry.fx_dir_entry_long_name_present = 0;
563
564 /* Now build the "." directory entry. */
565 sub_dir_entry.fx_dir_entry_name[0] = '.';
566 sub_dir_entry.fx_dir_entry_name[1] = 0;
567 sub_dir_entry.fx_dir_entry_log_sector = logical_sector;
568 sub_dir_entry.fx_dir_entry_byte_offset = 0;
569
570 /* Write the directory's first entry. */
571 status = _fx_directory_entry_write(media_ptr, &sub_dir_entry);
572
573 /* Check for error condition. */
574 if (status != FX_SUCCESS)
575 {
576
577 #ifdef FX_ENABLE_FAULT_TOLERANT
578 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
579 #endif /* FX_ENABLE_FAULT_TOLERANT */
580
581 /* Release media protection. */
582 FX_UNPROTECT
583
584 /* Return error status. */
585 return(status);
586 }
587
588 /* Now build the ".." directory entry. */
589
590 /* Determine if the search directory is the root. */
591 if (search_directory.fx_dir_entry_name[0])
592 {
593
594 /* Previous directory is not the root directory. */
595
596 /* Copy into the working directory entry. */
597 sub_dir_entry = search_directory;
598
599 /* Copy the date and time from the actual sub-directory. */
600 sub_dir_entry.fx_dir_entry_time = dir_entry.fx_dir_entry_time;
601 sub_dir_entry.fx_dir_entry_date = dir_entry.fx_dir_entry_date;
602
603 /* Adjust pointer to media name buffer. */
604 sub_dir_entry.fx_dir_entry_name = media_ptr -> fx_media_name_buffer + (FX_MAX_LONG_NAME_LEN * 3);
605
606 /* Change the name to ".." */
607 work_ptr = &sub_dir_entry.fx_dir_entry_name[0];
608 for (i = 0; i < (FX_DIR_NAME_SIZE + FX_DIR_EXT_SIZE); i++)
609 {
610 *work_ptr++ = ' ';
611 }
612
613 sub_dir_entry.fx_dir_entry_name[0] = '.';
614 sub_dir_entry.fx_dir_entry_name[1] = '.';
615 sub_dir_entry.fx_dir_entry_name[2] = 0;
616
617 sub_dir_entry.fx_dir_entry_long_name_present = 0;
618
619 /* Set file size to 0. */
620 sub_dir_entry.fx_dir_entry_file_size = 0;
621
622 /* Change the logical sector for this entry. */
623 sub_dir_entry.fx_dir_entry_log_sector = logical_sector;
624 }
625 else
626 {
627
628 /* Just modify the current directory since the parent
629 directory is the root. */
630 sub_dir_entry.fx_dir_entry_name[1] = '.';
631 sub_dir_entry.fx_dir_entry_name[2] = 0;
632
633 /* Clear the cluster to indicate the root directory. */
634 sub_dir_entry.fx_dir_entry_cluster = 0;
635 }
636
637 /* Setup the byte offset. */
638 sub_dir_entry.fx_dir_entry_byte_offset = FX_DIR_ENTRY_SIZE;
639
640 /* Write the directory's second entry. */
641 status = _fx_directory_entry_write(media_ptr, &sub_dir_entry);
642
643 /* Check for error condition. */
644 if (status != FX_SUCCESS)
645 {
646
647 #ifdef FX_ENABLE_FAULT_TOLERANT
648 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
649 #endif /* FX_ENABLE_FAULT_TOLERANT */
650
651 /* Release media protection. */
652 FX_UNPROTECT
653
654 /* Return error status. */
655 return(status);
656 }
657
658 /* Write an EOF in the found FAT entry. */
659 status = _fx_utility_FAT_entry_write(media_ptr, FAT_index, media_ptr -> fx_media_fat_last);
660
661 /* Check for a bad status. */
662 if (status != FX_SUCCESS)
663 {
664
665 #ifdef FX_ENABLE_FAULT_TOLERANT
666 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
667 #endif /* FX_ENABLE_FAULT_TOLERANT */
668
669 /* Release media protection. */
670 FX_UNPROTECT
671
672 /* Return the bad status. */
673 return(status);
674 }
675
676
677 #ifdef FX_FAULT_TOLERANT
678
679 /* Flush the cached individual FAT entries */
680 _fx_utility_FAT_flush(media_ptr);
681 #endif
682
683 /* Now write out the new directory entry. */
684
685 status = _fx_directory_entry_write(media_ptr, &dir_entry);
686
687 #ifdef FX_ENABLE_FAULT_TOLERANT
688 /* Check for a bad status. */
689 if (status != FX_SUCCESS)
690 {
691 FX_FAULT_TOLERANT_TRANSACTION_FAIL(media_ptr);
692
693 /* Release media protection. */
694 FX_UNPROTECT
695
696 /* Return the bad status. */
697 return(status);
698 }
699
700 /* End transaction. */
701 status = _fx_fault_tolerant_transaction_end(media_ptr);
702 #endif /* FX_ENABLE_FAULT_TOLERANT */
703
704 /* Release media protection. */
705 FX_UNPROTECT
706
707 /* Directory create is complete, return status. */
708 return(status);
709 }
710
711