2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: ARC path to-and-from NT path resolver.
5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
10 * - ARC Specification v1.2: http://netbsd.org./docs/Hardware/Machines/ARC/riscspec.pdf
11 * - "Setup and Startup", MSDN article: https://technet.microsoft.com/en-us/library/cc977184.aspx
12 * - Answer for "How do I determine the ARC path for a particular drive letter in Windows?": https://serverfault.com/a/5929
13 * - ARC - LinuxMIPS: https://www.linux-mips.org/wiki/ARC
14 * - ARCLoad - LinuxMIPS: https://www.linux-mips.org/wiki/ARCLoad
15 * - Inside Windows 2000 Server: https://books.google.fr/books?id=kYT7gKnwUQ8C&pg=PA71&lpg=PA71&dq=nt+arc+path&source=bl&ots=K8I1F_KQ_u&sig=EJq5t-v2qQk-QB7gNSREFj7pTVo&hl=en&sa=X&redir_esc=y#v=onepage&q=nt%20arc%20path&f=false
16 * - Inside Windows Server 2003: https://books.google.fr/books?id=zayrcM9ZYdAC&pg=PA61&lpg=PA61&dq=arc+path+to+nt+path&source=bl&ots=x2JSWfp2MA&sig=g9mufN6TCOrPejDov6Rjp0Jrldo&hl=en&sa=X&redir_esc=y#v=onepage&q=arc%20path%20to%20nt%20path&f=false
18 * Stuff to read: http://www.adminxp.com/windows2000/index.php?aid=46 and http://www.trcb.com/Computers-and-Technology/Windows-XP/Windows-XP-ARC-Naming-Conventions-1432.htm
19 * concerning which values of disk() or rdisk() are valid when either scsi() or multi() adapters are specified.
22 /* INCLUDES *****************************************************************/
34 /* TYPEDEFS *****************************************************************/
36 /* Supported adapter types */
37 typedef enum _ADAPTER_TYPE
45 } ADAPTER_TYPE
, *PADAPTER_TYPE
;
46 const PCSTR AdapterTypes_A
[] =
55 const PCWSTR AdapterTypes_U
[] =
65 /* Supported controller types */
66 typedef enum _CONTROLLER_TYPE
71 } CONTROLLER_TYPE
, *PCONTROLLER_TYPE
;
72 const PCSTR ControllerTypes_A
[] =
78 const PCWSTR ControllerTypes_U
[] =
85 /* Supported peripheral types */
86 typedef enum _PERIPHERAL_TYPE
93 } PERIPHERAL_TYPE
, *PPERIPHERAL_TYPE
;
94 const PCSTR PeripheralTypes_A
[] =
96 // "vdisk", // Enable this when we'll support boot from virtual disks!
102 const PCWSTR PeripheralTypes_U
[] =
104 // L"vdisk", // Enable this when we'll support boot from virtual disks!
112 /* FUNCTIONS ****************************************************************/
117 OUT PANSI_STRING TokenSpecifier
,
122 ULONG SpecifierLength
;
126 * We must have a valid "specifier(key)" string, where 'specifier'
127 * cannot be the empty string, and is followed by '('.
131 return NULL
; /* No '(' found */
133 return NULL
; /* Path starts with '(' and is thus invalid */
135 SpecifierLength
= (p
- ArcPath
) * sizeof(CHAR
);
138 * The strtoul function skips any leading whitespace.
140 * Note that if the token is "specifier()" then strtoul won't perform
141 * any conversion and return 0, therefore effectively making the token
142 * equivalent to "specifier(0)", as it should be.
144 // KeyValue = atoi(p);
145 KeyValue
= strtoul(p
, (PSTR
*)&p
, 10);
147 /* Skip any trailing whitespace */
148 while (isspace(*p
)) ++p
;
150 /* The token must terminate with ')' */
159 /* We should have succeeded, copy the token specifier in the buffer */
160 Status
= RtlStringCbCopyNA(TokenSpecifier
->Buffer
,
161 TokenSpecifier
->MaximumLength
,
162 ArcPath
, SpecifierLength
);
163 if (!NT_SUCCESS(Status
))
166 TokenSpecifier
->Length
= strlen(TokenSpecifier
->Buffer
) * sizeof(CHAR
);
168 /* We succeeded, return the token key value */
171 /* Next token starts just after */
178 OUT PUNICODE_STRING TokenSpecifier
,
183 ULONG SpecifierLength
;
187 * We must have a valid "specifier(key)" string, where 'specifier'
188 * cannot be the empty string, and is followed by '('.
192 return NULL
; /* No '(' found */
194 return NULL
; /* Path starts with '(' and is thus invalid */
196 SpecifierLength
= (p
- ArcPath
) * sizeof(WCHAR
);
201 * The strtoul function skips any leading whitespace.
203 * Note that if the token is "specifier()" then strtoul won't perform
204 * any conversion and return 0, therefore effectively making the token
205 * equivalent to "specifier(0)", as it should be.
207 // KeyValue = _wtoi(p);
208 KeyValue
= wcstoul(p
, (PWSTR
*)&p
, 10);
210 /* Skip any trailing whitespace */
211 while (iswspace(*p
)) ++p
;
213 /* The token must terminate with ')' */
222 /* We should have succeeded, copy the token specifier in the buffer */
223 Status
= RtlStringCbCopyNW(TokenSpecifier
->Buffer
,
224 TokenSpecifier
->MaximumLength
,
225 ArcPath
, SpecifierLength
);
226 if (!NT_SUCCESS(Status
))
229 TokenSpecifier
->Length
= wcslen(TokenSpecifier
->Buffer
) * sizeof(WCHAR
);
231 /* We succeeded, return the token key value */
234 /* Next token starts just after */
241 IN PCSTR CandidateToken
,
242 IN
const PCSTR
* TokenTable
)
246 while (TokenTable
[Index
] && _stricmp(CandidateToken
, TokenTable
[Index
]) != 0)
256 IN PCWSTR CandidateToken
,
257 IN
const PCWSTR
* TokenTable
)
261 while (TokenTable
[Index
] && _wcsicmp(CandidateToken
, TokenTable
[Index
]) != 0)
271 IN PCUNICODE_STRING CandidateToken
,
272 IN
const PCWSTR
* TokenTable
)
278 UNICODE_STRING Token
;
281 while (TokenTable
[Index
])
284 Length
= wcslen(TokenTable
[Index
]);
285 if ((Length
== CandidateToken
->Length
/ sizeof(WCHAR
)) &&
286 (_wcsnicmp(CandidateToken
->Buffer
, TokenTable
[Index
], Length
) == 0))
291 RtlInitUnicodeString(&Token
, TokenTable
[Index
]);
292 if (RtlEqualUnicodeString(CandidateToken
, &Token
, TRUE
))
305 OUT PUNICODE_STRING NormalizedArcPath
,
312 if (NormalizedArcPath
->MaximumLength
< sizeof(UNICODE_NULL
))
315 *NormalizedArcPath
->Buffer
= UNICODE_NULL
;
316 NormalizedArcPath
->Length
= 0;
318 EndOfArcName
= wcschr(ArcPath
, OBJ_NAME_PATH_SEPARATOR
);
320 EndOfArcName
= ArcPath
+ wcslen(ArcPath
);
322 while ((p
= wcsstr(ArcPath
, L
"()")) && (p
< EndOfArcName
))
325 Status
= RtlStringCbCopyNW(NormalizedArcPath
->Buffer
,
326 NormalizedArcPath
->MaximumLength
,
327 ArcPath
, (p
- ArcPath
) * sizeof(WCHAR
));
329 Status
= RtlStringCbCatNW(NormalizedArcPath
->Buffer
,
330 NormalizedArcPath
->MaximumLength
,
331 ArcPath
, (p
- ArcPath
) * sizeof(WCHAR
));
333 if (!NT_SUCCESS(Status
))
336 Status
= RtlStringCbCatW(NormalizedArcPath
->Buffer
,
337 NormalizedArcPath
->MaximumLength
,
339 if (!NT_SUCCESS(Status
))
342 NormalizedArcPath
->Buffer
+= wcslen(NormalizedArcPath
->Buffer
);
347 Status
= RtlStringCbCatW(NormalizedArcPath
->Buffer
,
348 NormalizedArcPath
->MaximumLength
,
350 if (!NT_SUCCESS(Status
))
353 NormalizedArcPath
->Length
= wcslen(NormalizedArcPath
->Buffer
) * sizeof(WCHAR
);
360 * In input, pointer to an ARC path (NULL-terminated) starting by an
361 * ARC name to be parsed into its different components.
362 * In output, ArcNamePath points to the beginning of the path after
367 IN OUT PCWSTR
* ArcNamePath
,
368 OUT PULONG pAdapterKey
,
369 OUT PULONG pControllerKey
,
370 OUT PULONG pPeripheralKey
,
371 OUT PULONG pPartitionNumber
,
372 OUT PADAPTER_TYPE pAdapterType
,
373 OUT PCONTROLLER_TYPE pControllerType
,
374 OUT PPERIPHERAL_TYPE pPeripheralType
,
375 OUT PBOOLEAN pUseSignature
)
378 WCHAR TokenBuffer
[50];
379 UNICODE_STRING Token
;
381 ULONG AdapterKey
= 0;
382 ULONG ControllerKey
= 0;
383 ULONG PeripheralKey
= 0;
384 ULONG PartitionNumber
= 0;
385 ADAPTER_TYPE AdapterType
= AdapterTypeMax
;
386 CONTROLLER_TYPE ControllerType
= ControllerTypeMax
;
387 PERIPHERAL_TYPE PeripheralType
= PeripheralTypeMax
;
388 BOOLEAN UseSignature
= FALSE
;
391 * The format of ArcName is:
392 * adapter(www)[controller(xxx)peripheral(yyy)[partition(zzz)][filepath]] ,
393 * where the [filepath] part is not being parsed.
396 RtlInitEmptyUnicodeString(&Token
, TokenBuffer
, sizeof(TokenBuffer
));
400 /* Retrieve the adapter */
401 p
= ArcGetNextTokenU(p
, &Token
, &AdapterKey
);
404 DPRINT1("No adapter specified!\n");
405 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
408 /* Check for the 'signature()' pseudo-adapter, introduced in Windows 2000 */
409 if (_wcsicmp(Token
.Buffer
, L
"signature") == 0)
412 * We've got a signature! Remember this for later, and set the adapter type to SCSI.
413 * We however check that the rest of the ARC path is valid by parsing the other tokens.
414 * AdapterKey stores the disk signature value (that holds in a ULONG).
417 AdapterType
= ScsiAdapter
;
421 /* Check for regular adapters */
422 // ArcMatchTokenU(Token.Buffer, AdapterTypes_U);
423 AdapterType
= (ADAPTER_TYPE
)ArcMatchToken_UStr(&Token
, AdapterTypes_U
);
424 if (AdapterType
>= AdapterTypeMax
)
426 DPRINT1("Invalid adapter type %wZ\n", &Token
);
427 return STATUS_OBJECT_NAME_INVALID
;
430 /* Check for adapters that don't take any extra controller or peripheral nodes */
431 if (AdapterType
== NetAdapter
|| AdapterType
== RamdiskAdapter
)
434 // return STATUS_OBJECT_PATH_SYNTAX_BAD;
436 if (AdapterType
== NetAdapter
)
438 DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U
[AdapterType
], AdapterKey
);
439 return STATUS_NOT_SUPPORTED
;
446 /* Here, we have either an 'eisa', a 'scsi/signature', or a 'multi' adapter */
448 /* Check for a valid controller */
449 p
= ArcGetNextTokenU(p
, &Token
, &ControllerKey
);
452 DPRINT1("%S(%lu) adapter doesn't have a controller!\n", AdapterTypes_U
[AdapterType
], AdapterKey
);
453 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
455 // ArcMatchTokenU(Token.Buffer, ControllerTypes_U);
456 ControllerType
= (CONTROLLER_TYPE
)ArcMatchToken_UStr(&Token
, ControllerTypes_U
);
457 if (ControllerType
>= ControllerTypeMax
)
459 DPRINT1("Invalid controller type %wZ\n", &Token
);
460 return STATUS_OBJECT_NAME_INVALID
;
463 /* Here the controller can only be either a disk or a CDROM */
466 * Ignore the controller in case we have a 'multi' adapter.
467 * I guess a similar condition holds for the 'eisa' adapter too...
469 * For SignatureAdapter, as similar for ScsiAdapter, the controller key corresponds
470 * to the disk target ID. Note that actually, the implementation just ignores the
471 * target ID, as well as the LUN, and just loops over all the available disks and
472 * searches for the one having the correct signature.
474 if ((AdapterType
== MultiAdapter
/* || AdapterType == EisaAdapter */) && ControllerKey
!= 0)
476 DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
477 AdapterTypes_U
[AdapterType
], AdapterKey
,
478 ControllerTypes_U
[ControllerType
], ControllerKey
);
483 * Only the 'scsi' adapter supports a direct 'cdrom' controller.
484 * For the others, we need a 'disk' controller to which a 'cdrom' peripheral can talk to.
486 if ((AdapterType
!= ScsiAdapter
) && (ControllerType
== CdRomController
))
488 DPRINT1("%S(%lu) adapter cannot have a CDROM controller!\n", AdapterTypes_U
[AdapterType
], AdapterKey
);
489 return STATUS_OBJECT_PATH_INVALID
;
492 /* Check for a valid peripheral */
493 p
= ArcGetNextTokenU(p
, &Token
, &PeripheralKey
);
496 DPRINT1("%S(%lu)%S(%lu) adapter-controller doesn't have a peripheral!\n",
497 AdapterTypes_U
[AdapterType
], AdapterKey
,
498 ControllerTypes_U
[ControllerType
], ControllerKey
);
499 return STATUS_OBJECT_PATH_SYNTAX_BAD
;
501 // ArcMatchTokenU(Token.Buffer, PeripheralTypes_U);
502 PeripheralType
= (PERIPHERAL_TYPE
)ArcMatchToken_UStr(&Token
, PeripheralTypes_U
);
503 if (PeripheralType
>= PeripheralTypeMax
)
505 DPRINT1("Invalid peripheral type %wZ\n", &Token
);
506 return STATUS_OBJECT_NAME_INVALID
;
510 * If we had a 'cdrom' controller already, the corresponding peripheral can only be 'fdisk'
511 * (see for example the ARC syntax for SCSI CD-ROMs: scsi(x)cdrom(y)fdisk(z) where z == 0).
513 if ((ControllerType
== CdRomController
) && (PeripheralType
!= FDiskPeripheral
))
515 DPRINT1("%S(%lu) controller cannot have a %S(%lu) peripheral! (note that we haven't check whether the adapter was SCSI or not)\n",
516 ControllerTypes_U
[ControllerType
], ControllerKey
,
517 PeripheralTypes_U
[PeripheralType
], PeripheralKey
);
518 return STATUS_OBJECT_PATH_INVALID
;
521 /* For a 'scsi' adapter, the possible peripherals are only 'rdisk' or 'fdisk' */
522 if (AdapterType
== ScsiAdapter
&& !(PeripheralType
== RDiskPeripheral
|| PeripheralType
== FDiskPeripheral
))
524 DPRINT1("%S(%lu)%S(%lu) SCSI adapter-controller has an invalid peripheral %S(%lu) !\n",
525 AdapterTypes_U
[AdapterType
], AdapterKey
,
526 ControllerTypes_U
[ControllerType
], ControllerKey
,
527 PeripheralTypes_U
[PeripheralType
], PeripheralKey
);
528 return STATUS_OBJECT_PATH_INVALID
;
532 if (AdapterType
== SignatureAdapter
&& PeripheralKey
!= 0)
534 DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
535 AdapterTypes_U
[AdapterType
], AdapterKey
,
536 PeripheralTypes_U
[PeripheralType
], PeripheralKey
);
541 /* Check for the optional 'partition' specifier */
542 q
= ArcGetNextTokenU(p
, &Token
, &PartitionNumber
);
543 if (q
&& _wcsicmp(Token
.Buffer
, L
"partition") == 0)
545 /* We've got a partition! */
551 * Either no other ARC token was found, or we've got something else
552 * (possibly invalid or not)...
557 // TODO: Check the partition number in case of fdisks and cdroms??
560 /* Return the results */
562 *pAdapterKey
= AdapterKey
;
563 *pControllerKey
= ControllerKey
;
564 *pPeripheralKey
= PeripheralKey
;
565 *pPartitionNumber
= PartitionNumber
;
566 *pAdapterType
= AdapterType
;
567 *pControllerType
= ControllerType
;
568 *pPeripheralType
= PeripheralType
;
569 *pUseSignature
= UseSignature
;
571 return STATUS_SUCCESS
;
576 * ARC name (counted string) to be resolved into a NT device name.
577 * The caller should have already delimited it from within an ARC path
578 * (usually by finding where the first path separator appears in the path).
581 * Receives the resolved NT name. The buffer is NULL-terminated.
584 ResolveArcNameNtSymLink(
585 OUT PUNICODE_STRING NtName
,
586 IN PUNICODE_STRING ArcName
)
589 OBJECT_ATTRIBUTES ObjectAttributes
;
590 HANDLE DirectoryHandle
, LinkHandle
;
591 UNICODE_STRING ArcNameDir
;
593 if (NtName
->MaximumLength
< sizeof(UNICODE_NULL
))
594 return STATUS_BUFFER_TOO_SMALL
;
596 /* Open the \ArcName object directory */
597 RtlInitUnicodeString(&ArcNameDir
, L
"\\ArcName");
598 InitializeObjectAttributes(&ObjectAttributes
,
600 OBJ_CASE_INSENSITIVE
,
603 Status
= NtOpenDirectoryObject(&DirectoryHandle
,
604 DIRECTORY_ALL_ACCESS
,
606 if (!NT_SUCCESS(Status
))
608 DPRINT1("NtOpenDirectoryObject(%wZ) failed, Status 0x%08lx\n", &ArcNameDir
, Status
);
612 /* Open the ARC name link */
613 InitializeObjectAttributes(&ObjectAttributes
,
615 OBJ_CASE_INSENSITIVE
,
618 Status
= NtOpenSymbolicLinkObject(&LinkHandle
,
619 SYMBOLIC_LINK_ALL_ACCESS
,
622 /* Close the \ArcName object directory handle */
623 NtClose(DirectoryHandle
);
625 /* Check for success */
626 if (!NT_SUCCESS(Status
))
628 DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName
, Status
);
632 /* Reserve one WCHAR for the NULL-termination */
633 NtName
->MaximumLength
-= sizeof(UNICODE_NULL
);
635 /* Resolve the link */
636 Status
= NtQuerySymbolicLinkObject(LinkHandle
, NtName
, NULL
);
638 /* Restore the NULL-termination */
639 NtName
->MaximumLength
+= sizeof(UNICODE_NULL
);
641 /* Check for success */
642 if (!NT_SUCCESS(Status
))
644 /* We failed, don't touch NtName */
645 DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed, Status 0x%08lx\n", ArcName
, Status
);
649 /* We succeeded, NULL-terminate NtName */
650 NtName
->Buffer
[NtName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
659 * In input, pointer to an ARC path (NULL-terminated) starting by an
660 * ARC name to be resolved into a NT device name.
661 * In opposition to ResolveArcNameNtSymLink(), the caller does not have
662 * to delimit the ARC name from within an ARC path. The real ARC name is
663 * deduced after parsing the ARC path, and, in output, ArcNamePath points
664 * to the beginning of the path after the ARC name part.
667 * Receives the resolved NT name. The buffer is NULL-terminated.
670 * (Optional) partition list that helps in resolving the paths pointing
674 ResolveArcNameManually(
675 OUT PUNICODE_STRING NtName
,
676 IN OUT PCWSTR
* ArcNamePath
,
677 IN PPARTLIST PartList
)
683 ULONG PartitionNumber
;
684 ADAPTER_TYPE AdapterType
;
685 CONTROLLER_TYPE ControllerType
;
686 PERIPHERAL_TYPE PeripheralType
;
687 BOOLEAN UseSignature
;
689 PDISKENTRY DiskEntry
;
690 PPARTENTRY PartEntry
= NULL
;
692 if (NtName
->MaximumLength
< sizeof(UNICODE_NULL
))
693 return STATUS_BUFFER_TOO_SMALL
;
695 /* Parse the ARC path */
696 Status
= ParseArcName(ArcNamePath
,
705 if (!NT_SUCCESS(Status
))
708 // TODO: Check the partition number in case of fdisks and cdroms??
710 /* Check for adapters that don't take any extra controller or peripheral node */
711 if (AdapterType
== NetAdapter
|| AdapterType
== RamdiskAdapter
)
713 if (AdapterType
== NetAdapter
)
715 DPRINT1("%S(%lu) path is not supported!\n", AdapterTypes_U
[AdapterType
], AdapterKey
);
716 return STATUS_NOT_SUPPORTED
;
719 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
720 L
"\\Device\\Ramdisk%lu", AdapterKey
);
723 if (ControllerType
== CdRomController
) // and so, AdapterType == ScsiAdapter and PeripheralType == FDiskPeripheral
725 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
726 L
"\\Device\\Scsi\\CdRom%lu", ControllerKey
);
729 /* Now, ControllerType == DiskController */
730 if (PeripheralType
== CdRomPeripheral
)
732 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
733 L
"\\Device\\CdRom%lu", PeripheralKey
);
736 if (PeripheralType
== FDiskPeripheral
)
738 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
739 L
"\\Device\\Floppy%lu", PeripheralKey
);
742 if (PeripheralType
== RDiskPeripheral
)
746 /* The disk signature is stored in AdapterKey */
747 DiskEntry
= GetDiskBySignature(PartList
, AdapterKey
);
751 DiskEntry
= GetDiskBySCSI(PartList
, AdapterKey
,
752 ControllerKey
, PeripheralKey
);
755 return STATUS_OBJECT_PATH_NOT_FOUND
; // STATUS_NOT_FOUND;
757 if (PartitionNumber
!= 0)
759 PartEntry
= GetPartition(DiskEntry
, PartitionNumber
);
761 return STATUS_OBJECT_PATH_NOT_FOUND
; // STATUS_DEVICE_NOT_PARTITIONED;
762 ASSERT(PartEntry
->DiskEntry
== DiskEntry
);
765 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
766 L
"\\Device\\Harddisk%lu\\Partition%lu",
767 DiskEntry
->DiskNumber
, PartitionNumber
);
769 #if 0 // FIXME: Not implemented yet!
771 if (PeripheralType
== VDiskPeripheral
)
773 // TODO: Check how Win 7+ deals with virtual disks.
774 Status
= RtlStringCbPrintfW(NtName
->Buffer
, NtName
->MaximumLength
,
775 L
"\\Device\\VirtualHarddisk%lu\\Partition%lu",
776 PeripheralKey
, PartitionNumber
);
780 if (!NT_SUCCESS(Status
))
782 /* Returned NtName is invalid, so zero it out */
783 *NtName
->Buffer
= UNICODE_NULL
;
789 /* Update NtName length */
790 NtName
->Length
= wcslen(NtName
->Buffer
) * sizeof(WCHAR
);
792 return STATUS_SUCCESS
;
798 OUT PUNICODE_STRING NtPath
,
800 IN PPARTLIST PartList OPTIONAL
)
804 UNICODE_STRING ArcName
;
806 /* TODO: We should "normalize" the path, i.e. expand all the xxx() into xxx(0) */
808 if (NtPath
->MaximumLength
< sizeof(UNICODE_NULL
))
811 *NtPath
->Buffer
= UNICODE_NULL
;
815 * - First, check whether the ARC path is already inside \\ArcName
816 * and if so, map it to the corresponding NT path.
817 * - Only then, if we haven't found any ArcName, try to build a
818 * NT path by deconstructing the ARC path, using its disk and
819 * partition numbers. We may use here our disk/partition list.
821 * See also freeldr/arcname.c
823 * Note that it would be nice to maintain a cache of these mappings.
827 * Initialize the ARC name to resolve, by cutting the ARC path at the first
828 * NT path separator. The ARC name therefore ends where the NT path part starts.
830 RtlInitUnicodeString(&ArcName
, ArcPath
);
831 BeginOfPath
= wcschr(ArcName
.Buffer
, OBJ_NAME_PATH_SEPARATOR
);
833 ArcName
.Length
= (ULONG_PTR
)BeginOfPath
- (ULONG_PTR
)ArcName
.Buffer
;
835 /* Resolve the ARC name via NT SymLinks. Note that NtPath is returned NULL-terminated. */
836 Status
= ResolveArcNameNtSymLink(NtPath
, &ArcName
);
837 if (!NT_SUCCESS(Status
))
839 /* We failed, attempt a manual resolution */
840 DPRINT1("ResolveArcNameNtSymLink(ArcName = '%wZ') for ArcPath = '%S' failed, Status 0x%08lx\n", &ArcName
, ArcPath
, Status
);
843 * We failed at directly resolving the ARC path, and we cannot perform
844 * a manual resolution because we don't have any disk/partition list,
845 * we therefore fail here.
849 DPRINT1("PartList == NULL, cannot perform a manual resolution\n");
853 *NtPath
->Buffer
= UNICODE_NULL
;
856 BeginOfPath
= ArcPath
;
857 Status
= ResolveArcNameManually(NtPath
, &BeginOfPath
, PartList
);
858 if (!NT_SUCCESS(Status
))
860 /* We really failed this time, bail out */
861 DPRINT1("ResolveArcNameManually(ArcPath = '%S') failed, Status 0x%08lx\n", ArcPath
, Status
);
867 * We succeeded. Concatenate the rest of the system-specific path. We know the path is going
868 * to be inside the NT namespace, therefore we can use the path string concatenation function
869 * that uses '\\' as the path separator.
871 if (BeginOfPath
&& *BeginOfPath
)
873 Status
= ConcatPaths(NtPath
->Buffer
, NtPath
->MaximumLength
/ sizeof(WCHAR
), 1, BeginOfPath
);
874 if (!NT_SUCCESS(Status
))
876 /* Buffer not large enough, or whatever...: just bail out */
880 NtPath
->Length
= wcslen(NtPath
->Buffer
) * sizeof(WCHAR
);
885 #if 0 // FIXME: Not implemented yet!
891 * - First, check whether any of the ARC paths inside \\ArcName
892 * map to the corresponding NT path. If so, we are OK.
893 * - Only then, if we haven't found any ArcName, try to build an
894 * ARC path by deconstructing the NT path, using its disk and
895 * partition numbers. We may use here our disk/partition list.
897 * See also freeldr/arcname.c
899 * Note that it would be nice to maintain a cache of these mappings.