Author: hbelusca
Date: Mon May 22 01:09:35 2017
New Revision: 74621
URL:
http://svn.reactos.org/svn/reactos?rev=74621&view=rev
Log:
[USETUP]: SetupLib: Add an ARC path to (and from) NT path resolver. It allows mapping
between an ARC path as specified in freeldr.ini / boot.ini , to its corresponding NT path,
if possible.
Currently, only the mapping direction "ARC to NT" is implemented. It will be
used wherever such mappings are needed, for example when identifying the ReactOS / Windows
installations from the available freeldr.ini / boot.ini entries (for upgrading / repair
purposes).
The resolver supports the usual ARC paths: multi()disk()[r|f]disk()[partition()] ;
eisa()disk()[r|f]disk()[partition()] ; multi()disk()cdrom() ;
scsi()disk()[r|f]disk()[partition()] ; scsi()cdrom()fdisk() ; ramdisk(x) ; net(x)
(actually reported as "unsupported" since it would map to some path on some
network), and the newly-introduced Win2k signature()disk()rdisk()[partition()].
Code is in progress, I need to clean up the references list.
I also add some validation tests I used during implementing the resolver.
Added:
branches/setup_improvements/base/setup/lib/arcname.c (with props)
branches/setup_improvements/base/setup/lib/arcname.h (with props)
branches/setup_improvements/base/setup/lib/arcname_tests.c (with props)
Modified:
branches/setup_improvements/base/setup/lib/CMakeLists.txt
branches/setup_improvements/base/setup/lib/setuplib.h
Modified: branches/setup_improvements/base/setup/lib/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/l…
==============================================================================
--- branches/setup_improvements/base/setup/lib/CMakeLists.txt [iso-8859-1] (original)
+++ branches/setup_improvements/base/setup/lib/CMakeLists.txt [iso-8859-1] Mon May 22
01:09:35 2017
@@ -1,5 +1,6 @@
list(APPEND SOURCE
+ arcname.c
fsutil.c
genlist.c
ntverrsrc.c
Added: branches/setup_improvements/base/setup/lib/arcname.c
URL:
http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/l…
==============================================================================
--- branches/setup_improvements/base/setup/lib/arcname.c (added)
+++ branches/setup_improvements/base/setup/lib/arcname.c [iso-8859-1] Mon May 22 01:09:35
2017
@@ -0,0 +1,861 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS text-mode setup
+ * FILE: base/setup/lib/arcname.c
+ * PURPOSE: ARC path to-and-from NT path resolver.
+ * PROGRAMMER: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+/*
+ * References:
+ *
+ * - ARC Specification v1.2:
http://netbsd.org./docs/Hardware/Machines/ARC/riscspec.pdf
+ * - "Setup and Startup", MSDN article:
https://technet.microsoft.com/en-us/library/cc977184.aspx
+ * - Answer for "How do I determine the ARC path for a particular drive letter in
Windows?":
https://serverfault.com/a/5929
+ * - ARC - LinuxMIPS:
https://www.linux-mips.org/wiki/ARC
+ * - ARCLoad - LinuxMIPS:
https://www.linux-mips.org/wiki/ARCLoad
+ * - Inside Windows 2000 Server:
https://books.google.fr/books?id=kYT7gKnwUQ8C&pg=PA71&lpg=PA71&…
+ * - Inside Windows Server 2003:
https://books.google.fr/books?id=zayrcM9ZYdAC&pg=PA61&lpg=PA61&…
+ *
+ * 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-Nami…
+ * concerning which values of disk() or rdisk() are valid when either scsi() or multi()
adapters are specified.
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "precomp.h"
+
+#include "partlist.h"
+#include "arcname.h"
+
+#define NDEBUG
+#include <debug.h>
+
+
+/* Supported adapter types */
+typedef enum _ADAPTER_TYPE
+{
+ EisaAdapter,
+ ScsiAdapter,
+ MultiAdapter,
+ NetAdapter,
+ RamdiskAdapter,
+ AdapterTypeMax
+} ADAPTER_TYPE, *PADAPTER_TYPE;
+const PCSTR AdapterTypes_A[] =
+{
+ "eisa",
+ "scsi",
+ "multi",
+ "net",
+ "ramdisk",
+ NULL
+};
+const PCWSTR AdapterTypes_U[] =
+{
+ L"eisa",
+ L"scsi",
+ L"multi",
+ L"net",
+ L"ramdisk",
+ NULL
+};
+
+/* Supported controller types */
+typedef enum _CONTROLLER_TYPE
+{
+ DiskController,
+ CdRomController,
+ ControllerTypeMax
+} CONTROLLER_TYPE, *PCONTROLLER_TYPE;
+const PCSTR ControllerTypes_A[] =
+{
+ "disk",
+ "cdrom",
+ NULL
+};
+const PCWSTR ControllerTypes_U[] =
+{
+ L"disk",
+ L"cdrom",
+ NULL
+};
+
+/* Supported peripheral types */
+typedef enum _PERIPHERAL_TYPE
+{
+// VDiskPeripheral,
+ RDiskPeripheral,
+ FDiskPeripheral,
+ CdRomPeripheral,
+ PeripheralTypeMax
+} PERIPHERAL_TYPE, *PPERIPHERAL_TYPE;
+const PCSTR PeripheralTypes_A[] =
+{
+// "vdisk", // Enable this when we'll support boot from virtual disks!
+ "rdisk",
+ "fdisk",
+ "cdrom",
+ NULL
+};
+const PCWSTR PeripheralTypes_U[] =
+{
+// L"vdisk", // Enable this when we'll support boot from virtual disks!
+ L"rdisk",
+ L"fdisk",
+ L"cdrom",
+ NULL
+};
+
+
+/* FUNCTIONS ****************************************************************/
+
+PCSTR
+ArcGetNextTokenA(
+ IN PCSTR ArcPath,
+ OUT PANSI_STRING TokenSpecifier,
+ OUT PULONG Key)
+{
+ HRESULT hr;
+ PCSTR p = ArcPath;
+ ULONG SpecifierLength;
+ ULONG KeyValue;
+
+ /*
+ * We must have a valid "specifier(key)" string, where 'specifier'
+ * cannot be the empty string, and is followed by '('.
+ */
+ p = strchr(p, '(');
+ if (p == NULL)
+ return NULL; /* No '(' found */
+ if (p == ArcPath)
+ return NULL; /* Path starts with '(' and is thus invalid */
+
+ SpecifierLength = (p - ArcPath) * sizeof(CHAR);
+
+ /*
+ * The strtoul function skips any leading whitespace.
+ *
+ * Note that if the token is "specifier()" then strtoul won't perform
+ * any conversion and return 0, therefore effectively making the token
+ * equivalent to "specifier(0)", as it should be.
+ */
+ // KeyValue = atoi(p);
+ KeyValue = strtoul(p, (PSTR*)&p, 10);
+
+ /* Skip any trailing whitespace */
+ while (*p && isspace(*p)) ++p;
+
+ /* The token must terminate with ')' */
+ if (*p != ')')
+ return NULL;
+#if 0
+ p = strchr(p, ')');
+ if (p == NULL)
+ return NULL;
+#endif
+
+ /* We should have succeeded, copy the token specifier in the buffer */
+ hr = StringCbCopyNA(TokenSpecifier->Buffer, TokenSpecifier->MaximumLength,
+ ArcPath, SpecifierLength);
+ if (FAILED(hr))
+ return NULL;
+
+ TokenSpecifier->Length = strlen(TokenSpecifier->Buffer) * sizeof(CHAR);
+
+ /* We succeeded, return the token key value */
+ *Key = KeyValue;
+
+ /* Next token starts just after */
+ return ++p;
+}
+
+PCWSTR
+ArcGetNextTokenU(
+ IN PCWSTR ArcPath,
+ OUT PUNICODE_STRING TokenSpecifier,
+ OUT PULONG Key)
+{
+ HRESULT hr;
+ PCWSTR p = ArcPath;
+ ULONG SpecifierLength;
+ ULONG KeyValue;
+
+ /*
+ * We must have a valid "specifier(key)" string, where 'specifier'
+ * cannot be the empty string, and is followed by '('.
+ */
+ p = wcschr(p, L'(');
+ if (p == NULL)
+ return NULL; /* No '(' found */
+ if (p == ArcPath)
+ return NULL; /* Path starts with '(' and is thus invalid */
+
+ SpecifierLength = (p - ArcPath) * sizeof(WCHAR);
+
+ ++p;
+
+ /*
+ * The strtoul function skips any leading whitespace.
+ *
+ * Note that if the token is "specifier()" then strtoul won't perform
+ * any conversion and return 0, therefore effectively making the token
+ * equivalent to "specifier(0)", as it should be.
+ */
+ // KeyValue = _wtoi(p);
+ KeyValue = wcstoul(p, (PWSTR*)&p, 10);
+ ASSERT(p);
+
+ /* Skip any trailing whitespace */
+ while (*p && iswspace(*p)) ++p;
+
+ /* The token must terminate with ')' */
+ if (*p != L')')
+ return NULL;
+#if 0
+ p = wcschr(p, L')');
+ if (p == NULL)
+ return NULL;
+#endif
+
+ /* We should have succeeded, copy the token specifier in the buffer */
+ hr = StringCbCopyNW(TokenSpecifier->Buffer, TokenSpecifier->MaximumLength,
+ ArcPath, SpecifierLength);
+ if (FAILED(hr))
+ return NULL;
+
+ TokenSpecifier->Length = wcslen(TokenSpecifier->Buffer) * sizeof(WCHAR);
+
+ /* We succeeded, return the token key value */
+ *Key = KeyValue;
+
+ /* Next token starts just after */
+ return ++p;
+}
+
+
+ULONG
+ArcMatchTokenA(
+ IN PCSTR CandidateToken,
+ IN const PCSTR* TokenTable)
+{
+ ULONG Index = 0;
+
+ while (TokenTable[Index] && _stricmp(CandidateToken, TokenTable[Index]) !=
0)
+ {
+ ++Index;
+ }
+
+ return Index;
+}
+
+ULONG
+ArcMatchTokenU(
+ IN PCWSTR CandidateToken,
+ IN const PCWSTR* TokenTable)
+{
+ ULONG Index = 0;
+
+ while (TokenTable[Index] && _wcsicmp(CandidateToken, TokenTable[Index]) !=
0)
+ {
+ ++Index;
+ }
+
+ return Index;
+}
+
+ULONG
+ArcMatchToken_UStr(
+ IN PCUNICODE_STRING CandidateToken,
+ IN const PCWSTR* TokenTable)
+{
+ ULONG Index = 0;
+#if 0
+ SIZE_T Length;
+#else
+ UNICODE_STRING Token;
+#endif
+
+ while (TokenTable[Index])
+ {
+#if 0
+ Length = wcslen(TokenTable[Index])*sizeof(WCHAR);
+ if (RtlCompareMemory(CandidateToken->Buffer, TokenTable[Index], Length) ==
Length)
+ break;
+#else
+ RtlInitUnicodeString(&Token, TokenTable[Index]);
+ // if (RtlCompareUnicodeString(CandidateToken, &Token, TRUE) == 0)
+ if (RtlEqualUnicodeString(CandidateToken, &Token, TRUE))
+ break;
+#endif
+
+ ++Index;
+ }
+
+ return Index;
+}
+
+
+BOOLEAN
+ArcPathNormalize(
+ OUT PUNICODE_STRING NormalizedArcPath,
+ IN PCWSTR ArcPath)
+{
+ HRESULT hr;
+ PCWSTR EndOfArcName;
+ PCWSTR p;
+
+ if (NormalizedArcPath->MaximumLength < sizeof(UNICODE_NULL))
+ return FALSE;
+
+ *NormalizedArcPath->Buffer = UNICODE_NULL;
+ NormalizedArcPath->Length = 0;
+
+ EndOfArcName = wcschr(ArcPath, OBJ_NAME_PATH_SEPARATOR);
+ if (!EndOfArcName)
+ EndOfArcName = ArcPath + wcslen(ArcPath);
+
+ while ((p = wcsstr(ArcPath, L"()")) && (p < EndOfArcName))
+ {
+#if 0
+ hr = StringCbCopyNW(NormalizedArcPath->Buffer,
NormalizedArcPath->MaximumLength,
+ ArcPath, (p - ArcPath) * sizeof(WCHAR));
+#else
+ hr = StringCbCatNW(NormalizedArcPath->Buffer,
NormalizedArcPath->MaximumLength,
+ ArcPath, (p - ArcPath) * sizeof(WCHAR));
+#endif
+ if (FAILED(hr))
+ return FALSE;
+ hr = StringCbCatW(NormalizedArcPath->Buffer,
NormalizedArcPath->MaximumLength, L"(0)");
+ if (FAILED(hr))
+ return FALSE;
+#if 0
+ NormalizedArcPath->Buffer += wcslen(NormalizedArcPath->Buffer);
+#endif
+ ArcPath = p + 2;
+ }
+ hr = StringCbCatW(NormalizedArcPath->Buffer, NormalizedArcPath->MaximumLength,
ArcPath);
+ if (FAILED(hr))
+ return FALSE;
+
+ NormalizedArcPath->Length = wcslen(NormalizedArcPath->Buffer) * sizeof(WCHAR);
+ return TRUE;
+}
+
+
+/*
+ * ArcName:
+ * ARC name (counted string) to be resolved into a NT device name.
+ * The caller should have already delimited it from within an ARC path
+ * (usually by finding where the first path separator appears in the path).
+ *
+ * NtName:
+ * Receives the resolved NT name. The buffer is NULL-terminated.
+ */
+static NTSTATUS
+ResolveArcNameNtSymLink(
+ OUT PUNICODE_STRING NtName,
+ IN PUNICODE_STRING ArcName)
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE DirectoryHandle, LinkHandle;
+ UNICODE_STRING ArcNameDir;
+
+ if (NtName->MaximumLength < sizeof(UNICODE_NULL))
+ return STATUS_BUFFER_TOO_SMALL;
+
+#if 0
+ *NtName->Buffer = UNICODE_NULL;
+ NtName->Length = 0;
+#endif
+
+ /* Open the \ArcName object directory */
+ RtlInitUnicodeString(&ArcNameDir, L"\\ArcName");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ArcNameDir,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ Status = NtOpenDirectoryObject(&DirectoryHandle,
+ DIRECTORY_ALL_ACCESS,
+ &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenDirectoryObject(%wZ) failed, Status 0x%08lx\n",
&ArcNameDir, Status);
+ return Status;
+ }
+
+ /* Open the ARC name link */
+ InitializeObjectAttributes(&ObjectAttributes,
+ ArcName,
+ OBJ_CASE_INSENSITIVE,
+ DirectoryHandle,
+ NULL);
+ Status = NtOpenSymbolicLinkObject(&LinkHandle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &ObjectAttributes);
+
+ /* Close the \ArcName object directory handle */
+ NtClose(DirectoryHandle);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed, Status 0x%08lx\n",
ArcName, Status);
+ return Status;
+ }
+
+ /* Reserve one WCHAR for the NULL-termination */
+ NtName->MaximumLength -= sizeof(UNICODE_NULL);
+
+ /* Resolve the link */
+ Status = NtQuerySymbolicLinkObject(LinkHandle, NtName, NULL);
+
+ /* Restore the NULL-termination */
+ NtName->MaximumLength += sizeof(UNICODE_NULL);
+
+ /* Check for success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, don't touch NtName */
+ DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed, Status 0x%08lx\n",
ArcName, Status);
+ }
+ else
+ {
+ /* We succeeded, NULL-terminate NtName */
+ NtName->Buffer[NtName->Length / sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+ NtClose(LinkHandle);
+ return Status;
+}
+
+/*
+ * ArcNamePath:
+ * In input, pointer to an ARC path (NULL-terminated) starting by an ARC name
+ * to be resolved into a NT device name.
+ * In opposition to ResolveArcNameNtSymLink(), the caller does not have to
+ * delimit the ARC name from within an ARC path. The real ARC name is deduced
+ * after parsing the ARC path, and, in output, ArcNamePath points to the
+ * beginning of the path after the ARC name part.
+ *
+ * NtName:
+ * Receives the resolved NT name. The buffer is NULL-terminated.
+ *
+ * PartList:
+ * (Optional) partition list that helps in resolving the paths pointing
+ * to hard disks.
+ */
+static NTSTATUS
+ResolveArcNameManually(
+ OUT PUNICODE_STRING NtName,
+ IN OUT PCWSTR* ArcNamePath,
+ IN PPARTLIST PartList OPTIONAL)
+{
+ HRESULT hr;
+ WCHAR TokenBuffer[50];
+ UNICODE_STRING Token;
+ PCWSTR p, q;
+ ULONG AdapterKey;
+ ULONG ControllerKey;
+ ULONG PeripheralKey;
+ ULONG PartitionNumber;
+ ADAPTER_TYPE AdapterType;
+ CONTROLLER_TYPE ControllerType;
+ PERIPHERAL_TYPE PeripheralType;
+ BOOLEAN UseSignature = FALSE;
+
+ PDISKENTRY DiskEntry;
+ PPARTENTRY PartEntry = NULL;
+
+ if (NtName->MaximumLength < sizeof(UNICODE_NULL))
+ return STATUS_BUFFER_TOO_SMALL;
+
+#if 0
+ *NtName->Buffer = UNICODE_NULL;
+ NtName->Length = 0;
+#endif
+
+ /*
+ * The format of ArcName is:
+ * adapter(www)[controller(xxx)peripheral(yyy)[partition(zzz)][filepath]] ,
+ * where the [filepath] part is not being parsed.
+ */
+
+ RtlInitEmptyUnicodeString(&Token, TokenBuffer, sizeof(TokenBuffer));
+
+ p = *ArcNamePath;
+
+ /* Retrieve the adapter */
+ p = ArcGetNextTokenU(p, &Token, &AdapterKey);
+ if (!p)
+ {
+ DPRINT1("No adapter specified!\n");
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+
+ /* Check for the 'signature()' pseudo-adapter, introduced in Windows 2000 */
+ if (_wcsicmp(Token.Buffer, L"signature") == 0)
+ {
+ /*
+ * We've got a signature! Remember this for later, and set the adapter type
to SCSI.
+ * We however check that the rest of the ARC path is valid by parsing the other
tokens.
+ * AdapterKey stores the disk signature value (that holds in a ULONG).
+ */
+ UseSignature = TRUE;
+ AdapterType = ScsiAdapter;
+ }
+ else
+ {
+ /* Check for regular adapters */
+ AdapterType =
(ADAPTER_TYPE)/*ArcMatchTokenU*/ArcMatchToken_UStr(/*Token.Buffer*/&Token,
AdapterTypes_U);
+ if (AdapterType >= AdapterTypeMax)
+ {
+ DPRINT1("Invalid adapter type %wZ\n", &Token);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /* Check for adapters that don't take any extra controller or peripheral
nodes */
+ if (AdapterType == NetAdapter || AdapterType == RamdiskAdapter)
+ {
+ // if (*p)
+ // return STATUS_OBJECT_PATH_SYNTAX_BAD;
+
+ if (AdapterType == NetAdapter)
+ {
+ DPRINT1("%S(%lu) path is not supported!\n",
AdapterTypes_U[AdapterType], AdapterKey);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\Ramdisk%lu", AdapterKey);
+ goto Quit;
+ }
+ }
+
+ /* Here, we have either an 'eisa', a 'scsi/signature', or a
'multi' adapter */
+
+ /* Check for a valid controller */
+ p = ArcGetNextTokenU(p, &Token, &ControllerKey);
+ if (!p)
+ {
+ DPRINT1("%S(%lu) adapter doesn't have a controller!\n",
AdapterTypes_U[AdapterType], AdapterKey);
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+ ControllerType =
(CONTROLLER_TYPE)/*ArcMatchTokenU*/ArcMatchToken_UStr(/*Token.Buffer*/&Token,
ControllerTypes_U);
+ if (ControllerType >= ControllerTypeMax)
+ {
+ DPRINT1("Invalid controller type %wZ\n", &Token);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /* Here the controller can only be either a disk or a CDROM */
+
+ /*
+ * Ignore the controller in case we have a 'multi' adapter.
+ * I guess a similar condition holds for the 'eisa' adapter too...
+ *
+ * For SignatureAdapter, as similar for ScsiAdapter, the controller key corresponds
+ * to the disk target ID. Note that actually, the implementation just ignores the
+ * target ID, as well as the LUN, and just loops over all the available disks and
+ * searches for the one having the correct signature.
+ */
+ if ((AdapterType == MultiAdapter /* || AdapterType == EisaAdapter */) &&
ControllerKey != 0)
+ {
+ DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
+ AdapterTypes_U[AdapterType], AdapterKey,
+ ControllerTypes_U[ControllerType], ControllerKey);
+ ControllerKey = 0;
+ }
+
+ /*
+ * Only the 'scsi' adapter supports a direct 'cdrom' controller.
+ * For the others, we need a 'disk' controller to which a 'cdrom'
peripheral can talk to.
+ */
+ if ((AdapterType != ScsiAdapter) && (ControllerType == CdRomController))
+ {
+ DPRINT1("%S(%lu) adapter cannot have a CDROM controller!\n",
AdapterTypes_U[AdapterType], AdapterKey);
+ return STATUS_OBJECT_PATH_INVALID;
+ }
+
+ /* Check for a valid peripheral */
+ p = ArcGetNextTokenU(p, &Token, &PeripheralKey);
+ if (!p)
+ {
+ DPRINT1("%S(%lu)%S(%lu) adapter-controller doesn't have a
peripheral!\n",
+ AdapterTypes_U[AdapterType], AdapterKey,
+ ControllerTypes_U[ControllerType], ControllerKey);
+ return STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+ PeripheralType =
(PERIPHERAL_TYPE)/*ArcMatchTokenU*/ArcMatchToken_UStr(/*Token.Buffer*/&Token,
PeripheralTypes_U);
+ if (PeripheralType >= PeripheralTypeMax)
+ {
+ DPRINT1("Invalid peripheral type %wZ\n", &Token);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /*
+ * If we had a 'cdrom' controller already, the corresponding peripheral can
only be 'fdisk'
+ * (see for example the ARC syntax for SCSI CD-ROMs: scsi(x)cdrom(y)fdisk(z) where z
== 0).
+ */
+ if ((ControllerType == CdRomController) && (PeripheralType !=
FDiskPeripheral))
+ {
+ DPRINT1("%S(%lu) controller cannot have a %S(%lu) peripheral! (note that we
haven't check whether the adapter was SCSI or not)\n",
+ ControllerTypes_U[ControllerType], ControllerKey,
+ PeripheralTypes_U[PeripheralType], PeripheralKey);
+ return STATUS_OBJECT_PATH_INVALID;
+ }
+
+ /* For a 'scsi' adapter, the possible peripherals are only 'rdisk' or
'fdisk' */
+ if (AdapterType == ScsiAdapter && !(PeripheralType == RDiskPeripheral ||
PeripheralType == FDiskPeripheral))
+ {
+ DPRINT1("%S(%lu)%S(%lu) SCSI adapter-controller has an invalid peripheral
%S(%lu) !\n",
+ AdapterTypes_U[AdapterType], AdapterKey,
+ ControllerTypes_U[ControllerType], ControllerKey,
+ PeripheralTypes_U[PeripheralType], PeripheralKey);
+ return STATUS_OBJECT_PATH_INVALID;
+ }
+
+#if 0
+ if (AdapterType == SignatureAdapter && PeripheralKey != 0)
+ {
+ DPRINT1("%S(%lu) adapter with %S(%lu non-zero), ignored!\n",
+ AdapterTypes_U[AdapterType], AdapterKey,
+ PeripheralTypes_U[PeripheralType], PeripheralKey);
+ PeripheralKey = 0;
+ }
+#endif
+
+ /* Check for the optional 'partition' specifier */
+ q = ArcGetNextTokenU(p, &Token, &PartitionNumber);
+ if (q && _wcsicmp(Token.Buffer, L"partition") == 0)
+ {
+ /* We've got a partition! */
+ p = q;
+ }
+ else
+ {
+ /*
+ * Either no other ARC token was found, or we've got something else
+ * (possibly invalid or not)...
+ */
+ PartitionNumber = 0;
+ }
+
+
+ // TODO: Check the partition number in case of fdisks and cdroms??
+
+
+ if (ControllerType == CdRomController) // and so, AdapterType == ScsiAdapter and
PeripheralType == FDiskPeripheral
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\Scsi\\CdRom%lu", ControllerKey);
+ else
+ /* Now, ControllerType == DiskController */
+ if (PeripheralType == CdRomPeripheral)
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\CdRom%lu", PeripheralKey);
+ else
+ if (PeripheralType == FDiskPeripheral)
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\Floppy%lu", PeripheralKey);
+ else
+ if (PeripheralType == RDiskPeripheral)
+ {
+ if (UseSignature)
+ {
+ /* The disk signature is stored in AdapterKey */
+ DiskEntry = GetDiskBySignature(PartList, AdapterKey);
+ }
+ else
+ {
+ DiskEntry = GetDiskBySCSI(PartList, AdapterKey,
+ ControllerKey, PeripheralKey);
+ }
+ if (!DiskEntry)
+ return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_NOT_FOUND;
+
+ if (PartitionNumber != 0)
+ {
+ PartEntry = GetPartition(DiskEntry, PartitionNumber);
+ if (!PartEntry)
+ return STATUS_OBJECT_PATH_NOT_FOUND; // STATUS_DEVICE_NOT_PARTITIONED;
+ ASSERT(PartEntry->DiskEntry == DiskEntry);
+ }
+
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\Harddisk%lu\\Partition%lu",
+ DiskEntry->DiskNumber, PartitionNumber);
+ }
+#if 0
+ else
+ if (PeripheralType == VDiskPeripheral)
+ {
+ // TODO: Check how Win 7+ deals with virtual disks.
+ hr = StringCbPrintfW(NtName->Buffer, NtName->MaximumLength,
L"\\Device\\VirtualHarddisk%lu\\Partition%lu",
+ PeripheralKey, PartitionNumber);
+ }
+#endif
+
+Quit:
+ if (FAILED(hr))
+ {
+ /*
+ * We can directly cast the HRESULTs into NTSTATUS since the error codes
+ * returned by StringCbPrintfW:
+ * STRSAFE_E_INVALID_PARAMETER == 0x80070057,
+ * STRSAFE_E_INSUFFICIENT_BUFFER == 0x8007007a,
+ * do not have assigned values in the NTSTATUS space.
+ */
+ return (NTSTATUS)hr;
+ }
+
+ *ArcNamePath = p;
+ return STATUS_SUCCESS;
+}
+
+
+/**** FIXME: Redundant with filesup.c ! ****\
+|** (but filesup.c is not yet included in **|
+\** setuplib, hence this code copy) **/
+
+static
+HRESULT
+ConcatPaths(
+ IN OUT PWSTR PathElem1,
+ IN SIZE_T cchPathSize,
+ IN PCWSTR PathElem2 OPTIONAL)
+{
+ HRESULT hr;
+ SIZE_T cchPathLen;
+
+ if (!PathElem2)
+ return S_OK;
+ if (cchPathSize <= 1)
+ return S_OK;
+
+ cchPathLen = min(cchPathSize, wcslen(PathElem1));
+
+ if (PathElem2[0] != L'\\' && cchPathLen > 0 &&
PathElem1[cchPathLen-1] != L'\\')
+ {
+ /* PathElem2 does not start with '\' and PathElem1 does not end with
'\' */
+ hr = StringCchCatW(PathElem1, cchPathSize, L"\\");
+ if (FAILED(hr))
+ return hr;
+ }
+ else if (PathElem2[0] == L'\\' && cchPathLen > 0 &&
PathElem1[cchPathLen-1] == L'\\')
+ {
+ /* PathElem2 starts with '\' and PathElem1 ends with '\' */
+ while (*PathElem2 == L'\\')
+ ++PathElem2; // Skip any backslash
+ }
+ hr = StringCchCatW(PathElem1, cchPathSize, PathElem2);
+ return hr;
+}
+
+/*******************************************/
+
+
+BOOLEAN
+ArcPathToNtPath(
+ OUT PUNICODE_STRING NtPath,
+ IN PCWSTR ArcPath,
+ IN PPARTLIST PartList OPTIONAL)
+{
+ NTSTATUS Status;
+ PCWSTR BeginOfPath;
+ UNICODE_STRING ArcName;
+
+ /* TODO: We should "normalize" the path, i.e. expand all the xxx() into
xxx(0) */
+
+ if (NtPath->MaximumLength < sizeof(UNICODE_NULL))
+ return FALSE;
+
+ *NtPath->Buffer = UNICODE_NULL;
+ NtPath->Length = 0;
+
+ /*
+ * - First, check whether the ARC path is already inside \\ArcName
+ * and if so, map it to the corresponding NT path.
+ * - Only then, if we haven't found any ArcName, try to build a
+ * NT path by deconstructing the ARC path, using its disk and
+ * partition numbers. We may use here our disk/partition list.
+ *
+ * See also freeldr/arcname.c
+ *
+ * Note that it would be nice to maintain a cache of these mappings.
+ */
+
+ /*
+ * Initialize the ARC name to resolve, by cutting the ARC path at the first
+ * NT path separator. The ARC name therefore ends where the NT path part starts.
+ */
+ RtlInitUnicodeString(&ArcName, ArcPath);
+ BeginOfPath = wcschr(ArcName.Buffer, OBJ_NAME_PATH_SEPARATOR);
+ if (BeginOfPath)
+ ArcName.Length = (ULONG_PTR)BeginOfPath - (ULONG_PTR)ArcName.Buffer;
+
+ /* Resolve the ARC name via NT SymLinks. Note that NtPath is returned
NULL-terminated. */
+ Status = ResolveArcNameNtSymLink(NtPath, &ArcName);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, attempt a manual resolution */
+ DPRINT1("ResolveArcNameNtSymLink(ArcName = '%wZ') for ArcPath =
'%S' failed, Status 0x%08lx\n", &ArcName, ArcPath, Status);
+
+ /*
+ * We failed at directly resolving the ARC path, and we cannot perform
+ * a manual resolution because we don't have any disk/partition list,
+ * we therefore fail here.
+ */
+ if (!PartList)
+ {
+ DPRINT1("PartList == NULL, cannot perform a manual resolution\n");
+ return FALSE;
+ }
+
+ *NtPath->Buffer = UNICODE_NULL;
+ NtPath->Length = 0;
+
+ BeginOfPath = ArcPath;
+ Status = ResolveArcNameManually(NtPath, &BeginOfPath, PartList);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We really failed this time, bail out */
+ DPRINT1("ResolveArcNameManually(ArcPath = '%S') failed, Status
0x%08lx\n", ArcPath, Status);
+ return FALSE;
+ }
+ }
+
+ /*
+ * We succeeded. Concatenate the rest of the system-specific path. We know the path
is going
+ * to be inside the NT namespace, therefore we can use the path string concatenation
function
+ * that uses '\\' as the path separator.
+ */
+ if (BeginOfPath && *BeginOfPath)
+ {
+ HRESULT hr;
+ hr = ConcatPaths(NtPath->Buffer, NtPath->MaximumLength / sizeof(WCHAR),
BeginOfPath);
+ if (FAILED(hr))
+ {
+ /* Buffer not large enough, or whatever...: just bail out */
+ return FALSE;
+ }
+ }
+ NtPath->Length = wcslen(NtPath->Buffer) * sizeof(WCHAR);
+ return TRUE;
+}
+
+#if 0
+PWSTR
+NtPathToArcPath(
+ IN PWSTR NtPath)
+{
+ /*
+ * - First, check whether any of the ARC paths inside \\ArcName
+ * map to the corresponding NT path. If so, we are OK.
+ * - Only then, if we haven't found any ArcName, try to build an
+ * ARC path by deconstructing the NT path, using its disk and
+ * partition numbers. We may use here our disk/partition list.
+ *
+ * See also freeldr/arcname.c
+ *
+ * Note that it would be nice to maintain a cache of these mappings.
+ */
+}
+#endif
+
+/* EOF */
Propchange: branches/setup_improvements/base/setup/lib/arcname.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: branches/setup_improvements/base/setup/lib/arcname.h
URL:
http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/l…
==============================================================================
--- branches/setup_improvements/base/setup/lib/arcname.h (added)
+++ branches/setup_improvements/base/setup/lib/arcname.h [iso-8859-1] Mon May 22 01:09:35
2017
@@ -0,0 +1,22 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS text-mode setup
+ * FILE: base/setup/lib/arcname.h
+ * PURPOSE: ARC path to-and-from NT path resolver.
+ * PROGRAMMER: Hermes Belusca-Maito (hermes.belusca(a)sfr.fr)
+ */
+
+#pragma once
+
+BOOLEAN
+ArcPathNormalize(
+ OUT PUNICODE_STRING NormalizedArcPath,
+ IN PCWSTR ArcPath);
+
+BOOLEAN
+ArcPathToNtPath(
+ OUT PUNICODE_STRING NtPath,
+ IN PCWSTR ArcPath,
+ IN PPARTLIST PartList OPTIONAL);
+
+/* EOF */
Propchange: branches/setup_improvements/base/setup/lib/arcname.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: branches/setup_improvements/base/setup/lib/arcname_tests.c
URL:
http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/l…
==============================================================================
--- branches/setup_improvements/base/setup/lib/arcname_tests.c (added)
+++ branches/setup_improvements/base/setup/lib/arcname_tests.c [iso-8859-1] Mon May 22
01:09:35 2017
@@ -0,0 +1,142 @@
+/*
+ * Tests for the arcname.c functions:
+ * - ArcPathNormalize(),
+ * - ArcPathToNtPath().
+ *
+ * You should certainly fix the included headers before being able
+ * to compile this file (as I didn't bother to have it compilable
+ * under our (P/N)DK, but just under VS).
+ */
+
+#include <stdio.h>
+#include <tchar.h>
+#include <conio.h>
+
+#define WIN32_NO_STATUS
+#include <windows.h>
+#include <winternl.h>
+#undef WIN32_NO_STATUS
+
+#include <ntstatus.h>
+
+#include <strsafe.h>
+
+#include "arcname.h"
+
+
+BOOLEAN
+NTAPI
+RtlEqualUnicodeString(
+ IN CONST UNICODE_STRING *s1,
+ IN CONST UNICODE_STRING *s2,
+ IN BOOLEAN CaseInsensitive);
+
+#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\')
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ WCHAR ArcPath[MAX_PATH] = L"multi(5)disk()rdisk(1)partition()\\ReactOS";
+ WCHAR NormalizedArcPathBuffer[MAX_PATH];
+ UNICODE_STRING NormalizedArcPath;
+ WCHAR NtPathBuffer[MAX_PATH];
+ UNICODE_STRING NtPath;
+
+ NormalizedArcPath.Buffer = NormalizedArcPathBuffer;
+ NormalizedArcPath.Length = 0;
+ NormalizedArcPath.MaximumLength = sizeof(NormalizedArcPathBuffer);
+
+ ArcPathNormalize(&NormalizedArcPath, ArcPath);
+ wprintf(L"ArcPath = '%s' ; Normalized = '%wZ'\n", ArcPath,
&NormalizedArcPath);
+
+ NtPath.Buffer = NtPathBuffer;
+ NtPath.Length = 0;
+ NtPath.MaximumLength = sizeof(NtPathBuffer);
+
+ ArcPathToNtPath(&NtPath, NormalizedArcPath.Buffer);
+ // wprintf(L"ArcPath = '%s' ; NtPath = '%wZ'\n", ArcPath,
&NtPath);
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"ramdisk(0)"); // OK
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath,
L"ramdisk(0)\\ReactOS\\system32\\ntoskrnl.exe"); // OK
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"net(0)\\Foobar"); // OK but not
supported
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"net(0)disk(1)\\Foobar"); // Bad
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)disk(1)rdisk(3)"); // OK
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)disk(1)fdisk(3)"); // OK
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)cdrom(1)"); // Bad: missing
fdisk
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)cdrom(1)cdrom(0)"); // Bad: twice
cdrom
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)cdrom(1)fdisk(0)"); // OK
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"scsi(2)cdrom(1)rdisk(0)"); // Bad; cdrom
controller and rdisk peripheral
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(2)cdrom(1)fdisk(0)"); // Bad: multi
adapter cannot have cdrom controller
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(2)rdisk(1)cdrom(1)fdisk(0)"); // Bad:
rdisk is not a controller
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(2)disk(1)cdrom(1)fdisk(0)"); // OK
(disk(1) ignored)
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(2)disk(1)rdisk(1)fdisk(0)"); // Same
(and also fdisk is not considered as part of ARC path)
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(2)disk(1)rdisk(1)partition(3)"); //
OK (disk(1) ignored)
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+
+ _getch();
+
+ /* All these are OK */
+ ArcPathToNtPath(&NtPath,
L"scsi(0)disk(3)rdisk(0)partition(1)\\OS.DIR");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath,
L"scsi(1)disk(3)rdisk(3)partition(2)\\OS\\ARCOS\\LOADER");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+
+ _getch();
+
+ /* All these are OK */
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(0)partition(1)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(0)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)cdrom(3)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"ramdisk(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"net(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)fdisk(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(1)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(1)partition(3)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(1)partition(1)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)rdisk(0)partition(3)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)fdisk(1)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)fdisk(0)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)disk(0)fdisk(1)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"eisa(0)disk(0)fdisk(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"eisa(0)disk(0)fdisk(1)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"eisa(0)disk(0)fdisk(0)partition(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+
+ /* These are invalid storage ARC paths (but otherwise are valid ARC names) */
+ ArcPathToNtPath(&NtPath, L"multi(0)video(0)monitor(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+ ArcPathToNtPath(&NtPath, L"multi(0)key(0)keyboard(0)");
+ wprintf(L"NtPath = '%wZ'\n", &NtPath);
+
+ _getch();
+ return 0;
+}
Propchange: branches/setup_improvements/base/setup/lib/arcname_tests.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: branches/setup_improvements/base/setup/lib/setuplib.h
URL:
http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/l…
==============================================================================
--- branches/setup_improvements/base/setup/lib/setuplib.h [iso-8859-1] (original)
+++ branches/setup_improvements/base/setup/lib/setuplib.h [iso-8859-1] Mon May 22 01:09:35
2017
@@ -29,8 +29,10 @@
#include "errorcode.h"
#include "linklist.h"
#include "ntverrsrc.h"
+// #include "arcname.h"
#include "fsutil.h"
#include "genlist.h"
#include "partlist.h"
+#include "arcname.h"
/* EOF */