windows-nt/Source/XPSP1/NT/base/fs/utils/subst/subst.cxx
2020-09-26 16:20:57 +08:00

438 lines
12 KiB
C++

/*++
Copyright (c) 1992-2000 Microsoft Corporation
Module Name:
subst.cxx
Abstract:
Utility to associate a path to a drive letter
Author:
THERESES 12-August-1992
Revision History:
--*/
#define _NTAPI_ULIB_
#include "ulib.hxx"
#include "arg.hxx"
#include "array.hxx"
#include "smsg.hxx"
#include "rtmsg.h"
#include "wstring.hxx"
#include "path.hxx"
#include "substrng.hxx"
#include "system.hxx"
#include "ulibcl.hxx"
#include "subst.hxx"
#include "dir.hxx"
#include "ntrtl.h"
BOOLEAN
QuerySubstedDrive(
IN DWORD DriveNumber,
OUT LPWSTR PhysicalDrive,
IN DWORD PhysicalDriveLength,
IN LPDWORD DosError
);
VOID
DisplaySubstUsage(
IN OUT PMESSAGE Message
)
/*++
Routine Description:
This routine displays the usage for the dos 5 label program.
Arguments:
Message - Supplies an outlet for the messages.
Return Value:
None.
--*/
{
Message->Set(MSG_SUBST_INFO);
Message->Display("");
Message->Set(MSG_SUBST_USAGE);
Message->Display("");
}
BOOLEAN
DeleteSubst(
IN LPWSTR Drive,
IN OUT PMESSAGE Message
)
{
BOOL Success;
FSTRING AuxString;
DWORD Status;
WCHAR Buffer[ MAX_PATH + 8 ];
Success = QuerySubstedDrive( *Drive - ( WCHAR )'@',
Buffer,
sizeof( Buffer ) / sizeof( WCHAR ),
&Status );
if( Success ) {
Success = DefineDosDevice( DDD_REMOVE_DEFINITION,
Drive,
NULL );
if( !Success ) {
Status = GetLastError();
}
}
if (!Success) {
if( Status == ERROR_ACCESS_DENIED ) {
AuxString.Initialize( Drive );
Message->Set(MSG_SUBST_ACCESS_DENIED);
Message->Display("%W",&AuxString);
} else {
AuxString.Initialize( Drive );
Message->Set(MSG_SUBST_INVALID_PARAMETER);
Message->Display("%W",&AuxString);
}
}
return Success != FALSE;
}
BOOLEAN
AddSubst(
IN LPWSTR Drive,
IN LPWSTR PhysicalDrive,
IN DWORD PhysicalDriveLength,
IN OUT PMESSAGE Message
)
{
DWORD Status;
FSTRING AuxString;
WCHAR Buffer[ MAX_PATH + 8 ];
if( !QuerySubstedDrive( Drive[0] - '@',
Buffer,
sizeof( Buffer ) / sizeof( WCHAR ),
&Status ) ) {
if( Status == ERROR_FILE_NOT_FOUND ) {
if ( wcslen(PhysicalDrive) == 3 &&
PhysicalDrive[1] == ':' &&
PhysicalDrive[2] == '\\' &&
PhysicalDrive[3] == 0 ) {
UNICODE_STRING string;
if ( !RtlDosPathNameToNtPathName_U(PhysicalDrive, &string, NULL, NULL) ) {
Status = GetLastError();
} else {
string.Buffer[string.Length/sizeof(string.Buffer[0]) - 1] = 0;
if ( !DefineDosDevice(DDD_RAW_TARGET_PATH, Drive, string.Buffer) ) {
Status = GetLastError();
} else {
Status = ERROR_SUCCESS;
}
RtlFreeUnicodeString(&string);
}
} else if( !DefineDosDevice( 0, Drive, PhysicalDrive ) ) {
Status = GetLastError();
} else {
Status = ERROR_SUCCESS;
}
}
} else {
Status = ERROR_IS_SUBSTED;
}
if( Status != ERROR_SUCCESS ) {
if( Status == ERROR_IS_SUBSTED ) {
Message->Set(MSG_SUBST_ALREADY_SUBSTED);
Message->Display("");
} else if (Status == ERROR_FILE_NOT_FOUND) {
AuxString.Initialize( PhysicalDrive );
Message->Set(MSG_SUBST_PATH_NOT_FOUND);
Message->Display("%W", &AuxString);
} else if (Status == ERROR_ACCESS_DENIED) {
AuxString.Initialize( PhysicalDrive );
Message->Set(MSG_SUBST_ACCESS_DENIED);
Message->Display("%W", &AuxString);
} else {
AuxString.Initialize( Drive );
Message->Set(MSG_SUBST_INVALID_PARAMETER);
Message->Display("%W", &AuxString );
}
return( FALSE );
} else {
return( TRUE );
}
}
BOOLEAN
QuerySubstedDrive(
IN DWORD DriveNumber,
OUT LPWSTR PhysicalDrive,
IN DWORD PhysicalDriveLength,
IN LPDWORD DosError
)
{
WCHAR DriveName[3];
FSTRING DosDevicesPattern;
FSTRING DeviceName;
CHNUM Position;
DriveName[0] = ( WCHAR )( DriveNumber + '@' );
DriveName[1] = ( WCHAR )':';
DriveName[2] = ( WCHAR )'\0';
if( QueryDosDevice( DriveName,
PhysicalDrive,
PhysicalDriveLength ) != 0 ) {
DosDevicesPattern.Initialize( (LPWSTR)L"\\??\\" );
DeviceName.Initialize( PhysicalDrive );
Position = DeviceName.Strstr( &DosDevicesPattern );
if( Position == 0 ) {
DeviceName.DeleteChAt( 0, DosDevicesPattern.QueryChCount() );
*DosError = ERROR_SUCCESS;
return( TRUE );
} else {
//
// This is not a Dos device
//
*DosError = ERROR_INVALID_PARAMETER;
return( FALSE );
}
} else {
*DosError = GetLastError();
return( FALSE );
}
}
VOID
DumpSubstedDrives (
IN OUT PMESSAGE Message
)
{
DSTRING Source;
WCHAR LinkBuffer[MAX_PATH + 8];
DWORD i;
FSTRING AuxString;
DWORD ErrorCode;
Source.Initialize(L"D:\\");
Message->Set(MSG_SUBST_SUBSTED_DRIVE);
for (i=1;i<=MAXIMUM_DRIVES;i++) {
if (QuerySubstedDrive(i,LinkBuffer,sizeof(LinkBuffer),&ErrorCode)) {
Source.SetChAt((WCHAR)(i+'@'),0);
if (wcslen(LinkBuffer) == 2 &&
LinkBuffer[1] == ':' &&
LinkBuffer[2] == 0) {
LinkBuffer[2] = '\\';
LinkBuffer[3] = 0;
}
AuxString.Initialize( LinkBuffer );
Message->Display("%W%W", &Source, &AuxString);
}
}
}
INT
__cdecl
main(
)
/*++
Routine Description:
This routine emulates the dos 5 subst command for NT.
Arguments:
None.
Return Value:
1 - An error occured.
0 - Success.
--*/
{
STREAM_MESSAGE msg;
ARGUMENT_LEXEMIZER arglex;
ARRAY lex_array;
ARRAY arg_array;
STRING_ARGUMENT progname;
PATH_ARGUMENT virtualdrive_arg;
PATH_ARGUMENT physicaldrive_arg;
FLAG_ARGUMENT help_arg;
FLAG_ARGUMENT delete_arg;
PWSTRING p;
BOOL Success=TRUE;
if (!msg.Initialize(Get_Standard_Output_Stream(),
Get_Standard_Input_Stream(),
Get_Standard_Error_Stream())) {
return 1;
}
if (!lex_array.Initialize() || !arg_array.Initialize()) {
return 1;
}
if (!arglex.Initialize(&lex_array)) {
return 1;
}
arglex.PutSwitches( "/" );
arglex.PutStartQuotes( "\"" );
arglex.PutEndQuotes( "\"" );
arglex.PutSeparators( " \t" );
arglex.SetCaseSensitive(FALSE);
if (!arglex.PrepareToParse()) {
return 1;
}
if ( !arg_array.Initialize() ) {
return 1;
}
if (!progname.Initialize("*") ||
!help_arg.Initialize("/?") ||
!virtualdrive_arg.Initialize("*", FALSE) ||
!physicaldrive_arg.Initialize("*",FALSE) ||
!delete_arg.Initialize("/D") ) {
return 1;
}
if (!arg_array.Put(&progname) ||
!arg_array.Put(&virtualdrive_arg) ||
!arg_array.Put(&physicaldrive_arg) ||
!arg_array.Put(&help_arg) ||
!arg_array.Put(&delete_arg) ) {
return 1;
}
if (!arglex.DoParsing(&arg_array)) {
if (arglex.QueryLexemeCount() > MAXIMUM_SUBST_ARGS) {
msg.Set(MSG_SUBST_TOO_MANY_PARAMETERS);
msg.Display("%W", p = arglex.GetLexemeAt(MAXIMUM_SUBST_ARGS));
} else {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", p = arglex.QueryInvalidArgument());
}
DELETE(p);
return 1;
}
if (help_arg.QueryFlag()) {
DisplaySubstUsage(&msg);
return 0;
}
if (delete_arg.IsValueSet() &&
virtualdrive_arg.IsValueSet() &&
physicaldrive_arg.IsValueSet()) {
msg.Set(MSG_SUBST_TOO_MANY_PARAMETERS);
msg.Display("%W", delete_arg.GetPattern() );
return 1;
}
if (delete_arg.IsValueSet() &&
!virtualdrive_arg.IsValueSet() &&
!physicaldrive_arg.IsValueSet()) {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", delete_arg.GetPattern());
return 1;
}
//
// Validate virtual drive
// A virtual drive MUST have the format <drive letter>:
// Anything that doesn't have this format is considered an invalid parameter
//
if( virtualdrive_arg.IsValueSet() &&
( ( virtualdrive_arg.GetPath()->GetPathString()->QueryChCount() != 2 ) ||
( virtualdrive_arg.GetPath()->GetPathString()->QueryChAt( 1 ) != ( WCHAR )':' ) )
) {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", virtualdrive_arg.GetPath()->GetPathString() );
return 1;
}
//
// Validate physical drive
// A physical drive CANNOT have the format <drive letter>:
//
if( physicaldrive_arg.IsValueSet() &&
( physicaldrive_arg.GetPath()->GetPathString()->QueryChCount() == 2 ) &&
( physicaldrive_arg.GetPath()->GetPathString()->QueryChAt( 1 ) == ( WCHAR )':' )
) {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", physicaldrive_arg.GetPath()->GetPathString() );
return 1;
}
//
if (virtualdrive_arg.IsValueSet()) {
DSTRING virtualdrivepath;
DSTRING colon;
PATH TmpPath;
PFSN_DIRECTORY Directory;
virtualdrivepath.Initialize(virtualdrive_arg.GetPath()->GetPathString());
if (virtualdrivepath.Strupr() ) {
if (delete_arg.IsValueSet()) {
Success = DeleteSubst(virtualdrivepath.QueryWSTR(),&msg);
} else if (physicaldrive_arg.IsValueSet()) {
LPWSTR physicaldrivepath;
//
// verify that the physical drive is an accessible path
//
Directory = SYSTEM::QueryDirectory( physicaldrive_arg.GetPath() );
if( !Directory ) {
msg.Set(MSG_SUBST_PATH_NOT_FOUND);
msg.Display("%W", physicaldrive_arg.GetPath()->GetPathString());
return 1;
}
DELETE( Directory );
TmpPath.Initialize( physicaldrive_arg.GetPath(), TRUE );
physicaldrivepath = ( TmpPath.GetPathString() )->QueryWSTR();
Success = AddSubst(virtualdrivepath.QueryWSTR(),
physicaldrivepath,
( TmpPath.GetPathString() )->QueryChCount(),
&msg
);
DELETE(physicaldrivepath);
} else {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", p = arglex.GetLexemeAt(1));
DELETE(p);
return 1;
}
}
} else {
if (arglex.QueryLexemeCount() > 1) {
msg.Set(MSG_SUBST_INVALID_PARAMETER);
msg.Display("%W", p = arglex.GetLexemeAt(1));
DELETE(p);
return 1;
} else {
DumpSubstedDrives(&msg);
}
}
return !Success;
}