2017-05-22 01:09:35 +00:00
/*
* PROJECT : ReactOS Setup Library
* LICENSE : GPL - 2.0 + ( https : //spdx.org/licenses/GPL-2.0+)
* PURPOSE : ARC path to - and - from NT path resolver .
* COPYRIGHT : Copyright 2017 - 2018 Hermes Belusca - Maito
*/
/*
* 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&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
* - 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
*
* 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
* concerning which values of disk ( ) or rdisk ( ) are valid when either scsi ( ) or multi ( ) adapters are specified .
*/
/* INCLUDES *****************************************************************/
# include "precomp.h"
2017-05-23 11:39:12 +00:00
# include "filesup.h"
2017-05-22 01:09:35 +00:00
# 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 )
{
2017-05-23 11:39:12 +00:00
NTSTATUS Status ;
2017-05-22 01:09:35 +00:00
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 */
2017-05-22 15:55:16 +00:00
while ( isspace ( * p ) ) + + p ;
2017-05-22 01:09:35 +00:00
/* 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 */
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCopyNA ( TokenSpecifier - > Buffer ,
TokenSpecifier - > MaximumLength ,
ArcPath , SpecifierLength ) ;
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
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 )
{
2017-05-23 11:39:12 +00:00
NTSTATUS Status ;
2017-05-22 01:09:35 +00:00
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 ) ;
/* Skip any trailing whitespace */
2017-05-22 15:55:16 +00:00
while ( iswspace ( * p ) ) + + p ;
2017-05-22 01:09:35 +00:00
/* 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 */
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCopyNW ( TokenSpecifier - > Buffer ,
TokenSpecifier - > MaximumLength ,
ArcPath , SpecifierLength ) ;
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
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 )
{
2017-05-23 11:39:12 +00:00
NTSTATUS Status ;
2017-05-22 01:09:35 +00:00
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
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCopyNW ( NormalizedArcPath - > Buffer ,
NormalizedArcPath - > MaximumLength ,
ArcPath , ( p - ArcPath ) * sizeof ( WCHAR ) ) ;
2017-05-22 01:09:35 +00:00
# else
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCatNW ( NormalizedArcPath - > Buffer ,
NormalizedArcPath - > MaximumLength ,
ArcPath , ( p - ArcPath ) * sizeof ( WCHAR ) ) ;
2017-05-22 01:09:35 +00:00
# endif
2017-05-23 11:39:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
return FALSE ;
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCatW ( NormalizedArcPath - > Buffer ,
NormalizedArcPath - > MaximumLength ,
L " (0) " ) ;
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
return FALSE ;
#if 0
NormalizedArcPath - > Buffer + = wcslen ( NormalizedArcPath - > Buffer ) ;
# endif
ArcPath = p + 2 ;
}
2017-05-23 11:39:12 +00:00
Status = RtlStringCbCatW ( NormalizedArcPath - > Buffer ,
NormalizedArcPath - > MaximumLength ,
ArcPath ) ;
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
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 )
{
2017-05-23 11:39:12 +00:00
NTSTATUS Status ;
2017-05-22 01:09:35 +00:00
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 ;
}
2017-05-23 11:39:12 +00:00
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ Ramdisk%lu " , AdapterKey ) ;
2017-05-22 01:09:35 +00:00
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
2017-05-23 11:39:12 +00:00
{
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ Scsi \\ CdRom%lu " , ControllerKey ) ;
}
2017-05-22 01:09:35 +00:00
else
/* Now, ControllerType == DiskController */
if ( PeripheralType = = CdRomPeripheral )
2017-05-23 11:39:12 +00:00
{
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ CdRom%lu " , PeripheralKey ) ;
}
2017-05-22 01:09:35 +00:00
else
if ( PeripheralType = = FDiskPeripheral )
2017-05-23 11:39:12 +00:00
{
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ Floppy%lu " , PeripheralKey ) ;
}
2017-05-22 01:09:35 +00:00
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 ) ;
}
2017-05-23 11:39:12 +00:00
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ Harddisk%lu \\ Partition%lu " ,
DiskEntry - > DiskNumber , PartitionNumber ) ;
2017-05-22 01:09:35 +00:00
}
#if 0
else
if ( PeripheralType = = VDiskPeripheral )
{
// TODO: Check how Win 7+ deals with virtual disks.
2017-05-23 11:39:12 +00:00
Status = RtlStringCbPrintfW ( NtName - > Buffer , NtName - > MaximumLength ,
L " \\ Device \\ VirtualHarddisk%lu \\ Partition%lu " ,
PeripheralKey , PartitionNumber ) ;
2017-05-22 01:09:35 +00:00
}
# endif
Quit :
2017-05-23 11:39:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
return Status ;
2017-05-22 01:09:35 +00:00
* ArcNamePath = p ;
return STATUS_SUCCESS ;
}
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 )
{
2017-05-23 22:30:54 +00:00
Status = ConcatPaths ( NtPath - > Buffer , NtPath - > MaximumLength / sizeof ( WCHAR ) , 1 , BeginOfPath ) ;
2017-05-23 11:39:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
2017-05-22 01:09:35 +00:00
{
/* 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 */