|
|
/*++
Copyright (c) 1990-2001 Microsoft Corporation
Module Name:
Argument
Abstract:
Argument processing for the XCopy directory copy utility
Author:
Ramon Juan San Andres (ramonsa) 01-May-1991
Notes:
The arguments accepted by the XCopy utility are:
Source directory.- Source path.
Dest. directory.- Destination path.
Archive switch.- Copy files that have their archive bit set
Date.- Copy files modified on or after the specifiec date.
Empty switch.- Copy directories even if empty. Subdir switch must also be set.
Modify switch.- Same as Archive switch, but turns off archive bit in the source file after copying.
Prompt switch.- Prompts before copying each file.
Subdir switch.- Copies also subdirectories, unless they are empty. (Empty directories are copied if the Empty switch is set).
Verify switch.- Verifies each copy.
Wait switch.- Wait before starting to copy the files.
Owner switch. - Copy ownership and permissions
Audit switch. - Copy auditing information.
Revision History:
--*/
#include "ulib.hxx"
#include "arg.hxx"
#include "arrayit.hxx"
#include "dir.hxx"
#include "xcopy.hxx"
#include "stringar.hxx"
#include "file.hxx"
#include "filestrm.hxx"
//
// Switch characters. Used for maintaining DOS5 compatibility when
// displaying error messages
//
#define SWITCH_CHARACTERS "dDaAeEmMpPsSvVwW?"
//
// Static variables
//
PARRAY LexArray; PPATH_ARGUMENT FirstPathArgument = NULL; PPATH_ARGUMENT FirstQuotedPathArgument = NULL; PPATH_ARGUMENT SecondPathArgument = NULL; PPATH_ARGUMENT SecondQuotedPathArgument = NULL; PFLAG_ARGUMENT ArchiveArgument = NULL; PTIMEINFO_ARGUMENT DateArgument = NULL; PFLAG_ARGUMENT DecryptArgument = NULL; PFLAG_ARGUMENT EmptyArgument = NULL; PFLAG_ARGUMENT ModifyArgument = NULL; PFLAG_ARGUMENT PromptArgument = NULL; PFLAG_ARGUMENT OverWriteArgument = NULL; PFLAG_ARGUMENT NotOverWriteArgument = NULL; PFLAG_ARGUMENT SubdirArgument = NULL; PFLAG_ARGUMENT VerifyArgument = NULL; PFLAG_ARGUMENT WaitArgument = NULL; PFLAG_ARGUMENT HelpArgument = NULL; PFLAG_ARGUMENT ContinueArgument = NULL;
PFLAG_ARGUMENT IntelligentArgument = NULL; PFLAG_ARGUMENT VerboseArgument = NULL; PFLAG_ARGUMENT OldArgument = NULL; PFLAG_ARGUMENT HiddenArgument = NULL; PFLAG_ARGUMENT ReadOnlyArgument = NULL; PFLAG_ARGUMENT SilentArgument = NULL; PFLAG_ARGUMENT NoCopyArgument = NULL; PFLAG_ARGUMENT StructureArgument = NULL; PFLAG_ARGUMENT UpdateArgument = NULL; PFLAG_ARGUMENT CopyAttrArgument = NULL; PFLAG_ARGUMENT UseShortArgument = NULL; PFLAG_ARGUMENT RestartableArgument = NULL; PFLAG_ARGUMENT OwnerArgument = NULL; PFLAG_ARGUMENT AuditArgument = NULL;
PSTRING_ARGUMENT ExclusionListArgument = NULL;
PSTRING_ARGUMENT InvalidSwitchArgument = NULL;
BOOLEAN HelpSwitch;
//
// Prototypes
//
VOID XCOPY::SetArguments( )
/*++
Routine Description:
Obtains the arguments for the XCopy utility
Arguments:
None.
Return Value:
None.
Notes:
--*/
{
PATH_ARGUMENT LocalFirstPathArgument; PATH_ARGUMENT LocalFirstQuotedPathArgument; PATH_ARGUMENT LocalSecondPathArgument; PATH_ARGUMENT LocalSecondQuotedPathArgument; FLAG_ARGUMENT LocalArchiveArgument; TIMEINFO_ARGUMENT LocalDateArgument; FLAG_ARGUMENT LocalOldArgument; FLAG_ARGUMENT LocalDecryptArgument; FLAG_ARGUMENT LocalEmptyArgument; FLAG_ARGUMENT LocalModifyArgument; FLAG_ARGUMENT LocalPromptArgument; FLAG_ARGUMENT LocalOverWriteArgument; FLAG_ARGUMENT LocalNotOverWriteArgument; FLAG_ARGUMENT LocalSubdirArgument; FLAG_ARGUMENT LocalVerifyArgument; FLAG_ARGUMENT LocalWaitArgument; FLAG_ARGUMENT LocalHelpArgument; FLAG_ARGUMENT LocalContinueArgument; FLAG_ARGUMENT LocalIntelligentArgument; FLAG_ARGUMENT LocalVerboseArgument; FLAG_ARGUMENT LocalHiddenArgument; FLAG_ARGUMENT LocalReadOnlyArgument; FLAG_ARGUMENT LocalSilentArgument; FLAG_ARGUMENT LocalNoCopyArgument; FLAG_ARGUMENT LocalStructureArgument; FLAG_ARGUMENT LocalUpdateArgument; FLAG_ARGUMENT LocalCopyAttrArgument; FLAG_ARGUMENT LocalUseShortArgument; FLAG_ARGUMENT LocalRestartableArgument; FLAG_ARGUMENT LocalOwnerArgument; FLAG_ARGUMENT LocalAuditArgument; STRING_ARGUMENT LocalExclusionListArgument;
STRING_ARGUMENT LocalInvalidSwitchArgument; ARRAY LocalLexArray;
//
// Set the static global pointers
//
FirstPathArgument = &LocalFirstPathArgument; FirstQuotedPathArgument = &LocalFirstQuotedPathArgument; SecondPathArgument = &LocalSecondPathArgument; SecondQuotedPathArgument = &LocalSecondQuotedPathArgument; ArchiveArgument = &LocalArchiveArgument; DateArgument = &LocalDateArgument; OldArgument = &LocalOldArgument; DecryptArgument = &LocalDecryptArgument; EmptyArgument = &LocalEmptyArgument; ModifyArgument = &LocalModifyArgument; PromptArgument = &LocalPromptArgument; OverWriteArgument = &LocalOverWriteArgument; NotOverWriteArgument = &LocalNotOverWriteArgument; SubdirArgument = &LocalSubdirArgument; VerifyArgument = &LocalVerifyArgument; WaitArgument = &LocalWaitArgument; HelpArgument = &LocalHelpArgument; ContinueArgument = &LocalContinueArgument; IntelligentArgument = &LocalIntelligentArgument; VerboseArgument = &LocalVerboseArgument; HiddenArgument = &LocalHiddenArgument; ReadOnlyArgument = &LocalReadOnlyArgument; SilentArgument = &LocalSilentArgument; NoCopyArgument = &LocalNoCopyArgument; StructureArgument = &LocalStructureArgument; UpdateArgument = &LocalUpdateArgument; CopyAttrArgument = &LocalCopyAttrArgument; UseShortArgument = &LocalUseShortArgument; ExclusionListArgument = &LocalExclusionListArgument; InvalidSwitchArgument = &LocalInvalidSwitchArgument; LexArray = &LocalLexArray; RestartableArgument = &LocalRestartableArgument; OwnerArgument = &LocalOwnerArgument; AuditArgument = &LocalAuditArgument;
//
// Parse the arguments
//
GetArgumentsCmd();
//
// Verify the arguments
//
CheckArgumentConsistency();
LocalLexArray.DeleteAllMembers(); }
VOID GetSourceAndDestinationPath( IN OUT PPATH_ARGUMENT FirstPathArgument, IN OUT PPATH_ARGUMENT FirstQuotedPathArgument, IN OUT PPATH_ARGUMENT SecondPathArgument, IN OUT PPATH_ARGUMENT SecondQuotedPathArgument, IN OUT PARGUMENT_LEXEMIZER ArgLex, OUT PPATH* SourcePath, OUT PPATH* DestinationPath ) /*++
Routine Description:
This routine computes the Source and Destination path from the given list of arguments.
Arguments:
FirstPathArgument - Supplies the first unquoted path argument. FirstQuotedPathArgument - Supplies the first quoted path argument. SecondPathArgument - Supplies the second unquoted path argument. SecondQuotedPathArgument - Supplies the second quoted path argument. ArgLex - Supplies the argument lexemizer. SourcePath - Returns the source path. DestinationPath - Returns the destination path.
Return Value:
None.
--*/ { BOOLEAN f, qf, s, qs; PPATH_ARGUMENT source, destination; ULONG i; PWSTRING string, qstring;
f = FirstPathArgument->IsValueSet(); qf = FirstQuotedPathArgument->IsValueSet(); s = SecondPathArgument->IsValueSet(); qs = SecondQuotedPathArgument->IsValueSet(); source = NULL; destination = NULL; *SourcePath = NULL; *DestinationPath = NULL;
if (f && !qf && s && !qs) {
source = FirstPathArgument; destination = SecondPathArgument;
} else if (!f && qf && !s && qs) {
source = FirstQuotedPathArgument; destination = SecondQuotedPathArgument;
} else if (f && qf && !s && !qs) {
string = FirstPathArgument->GetLexeme(); qstring = FirstQuotedPathArgument->GetLexeme();
for (i = 0; i < ArgLex->QueryLexemeCount(); i++) { if (!ArgLex->GetLexemeAt(i)->Strcmp(string)) { source = FirstPathArgument; destination = FirstQuotedPathArgument; break; }
if (!ArgLex->GetLexemeAt(i)->Strcmp(qstring)) { source = FirstQuotedPathArgument; destination = FirstPathArgument; break; } } } else if (f && !qf && !s && !qs) { source = FirstPathArgument; } else if (!f && qf && !s && !qs) { source = FirstQuotedPathArgument; }
if (source) { if (!(*SourcePath = NEW PATH) || !(*SourcePath)->Initialize(source->GetPath(), VerboseArgument->IsValueSet())) {
*SourcePath = NULL; } }
if (destination) { if (!(*DestinationPath = NEW PATH) || !(*DestinationPath)->Initialize(destination->GetPath(), VerboseArgument->IsValueSet())) {
*DestinationPath = NULL; } } }
VOID XCOPY::GetArgumentsCmd( )
/*++
Routine Description:
Obtains the arguments from the Command line
Arguments:
None.
Return Value:
None.
--*/
{
ARRAY ArgArray; PATH_ARGUMENT ProgramNameArgument; DSTRING CmdLine; DSTRING InvalidParms; WCHAR Ch; PWSTRING InvalidSwitch; PARGUMENT_LEXEMIZER ArgLex;
//
// Prepare for parsing
//
if (//
// Initialize the arguments
//
!(CmdLine.Initialize( GetCommandLine() )) || !(ArgArray.Initialize( 15, 15 )) || !(ProgramNameArgument.Initialize( "*" )) || !(FirstPathArgument->Initialize( "*", FALSE )) || !(FirstQuotedPathArgument->Initialize( "\"*\"", FALSE )) || !(SecondPathArgument->Initialize( "*", FALSE)) || !(SecondQuotedPathArgument->Initialize( "\"*\"", FALSE)) || !(ArchiveArgument->Initialize( "/A" )) || !(DateArgument->Initialize( "/D:*" )) || !(OldArgument->Initialize( "/D" )) || !(DecryptArgument->Initialize( "/G" )) || !(EmptyArgument->Initialize( "/E" )) || !(ModifyArgument->Initialize( "/M" )) || !(PromptArgument->Initialize( "/P" )) || !(OverWriteArgument->Initialize( "/Y" )) || !(NotOverWriteArgument->Initialize( "/-Y" )) || !(SubdirArgument->Initialize( "/S" )) || !(VerifyArgument->Initialize( "/V" )) || !(WaitArgument->Initialize( "/W" )) || !(HelpArgument->Initialize( "/?" )) || !(ContinueArgument->Initialize( "/C" )) || !(IntelligentArgument->Initialize( "/I" )) || !(VerboseArgument->Initialize( "/F" )) || !(HiddenArgument->Initialize( "/H" )) || !(ReadOnlyArgument->Initialize( "/R" )) || !(SilentArgument->Initialize( "/Q" )) || !(NoCopyArgument->Initialize( "/L" )) || !(StructureArgument->Initialize( "/T" )) || !(UpdateArgument->Initialize( "/U" )) || !(CopyAttrArgument->Initialize( "/K" )) || !(UseShortArgument->Initialize( "/N" )) || !(RestartableArgument->Initialize( "/Z" )) || !(OwnerArgument->Initialize( "/O" )) || !(AuditArgument->Initialize( "/X" )) || !(ExclusionListArgument->Initialize("/EXCLUDE:*")) || !(InvalidSwitchArgument->Initialize( "/*" )) || //
// Put the arguments in the argument array
//
!(ArgArray.Put( &ProgramNameArgument )) || !(ArgArray.Put( ArchiveArgument )) || !(ArgArray.Put( DateArgument )) || !(ArgArray.Put( OldArgument )) || !(ArgArray.Put( DecryptArgument )) || !(ArgArray.Put( EmptyArgument )) || !(ArgArray.Put( ModifyArgument )) || !(ArgArray.Put( PromptArgument )) || !(ArgArray.Put( OverWriteArgument )) || !(ArgArray.Put( NotOverWriteArgument )) || !(ArgArray.Put( SubdirArgument )) || !(ArgArray.Put( VerifyArgument )) || !(ArgArray.Put( WaitArgument )) || !(ArgArray.Put( HelpArgument )) || !(ArgArray.Put( ContinueArgument )) || !(ArgArray.Put( IntelligentArgument )) || !(ArgArray.Put( VerboseArgument )) || !(ArgArray.Put( HiddenArgument )) || !(ArgArray.Put( ReadOnlyArgument )) || !(ArgArray.Put( SilentArgument )) || !(ArgArray.Put( RestartableArgument )) || !(ArgArray.Put( OwnerArgument )) || !(ArgArray.Put( AuditArgument )) || !(ArgArray.Put( NoCopyArgument )) || !(ArgArray.Put( StructureArgument )) || !(ArgArray.Put( UpdateArgument )) || !(ArgArray.Put( CopyAttrArgument )) || !(ArgArray.Put( UseShortArgument )) || !(ArgArray.Put( ExclusionListArgument )) || !(ArgArray.Put( InvalidSwitchArgument )) || !(ArgArray.Put( FirstQuotedPathArgument )) || !(ArgArray.Put( SecondQuotedPathArgument )) || !(ArgArray.Put( FirstPathArgument )) || !(ArgArray.Put( SecondPathArgument )) ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR); }
//
// Parse the arguments
//
ArgLex = ParseArguments( &CmdLine, &ArgArray );
if ( InvalidSwitchArgument->IsValueSet() ) {
InvalidSwitch = InvalidSwitchArgument->GetString();
InvalidParms.Initialize( SWITCH_CHARACTERS );
Ch = InvalidSwitch->QueryChAt(0);
if ( Ch == 'd' || Ch == 'D' ) { Ch = InvalidSwitch->QueryChAt(1); if ( Ch == INVALID_CHAR ) { DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS, NULL, EXIT_MISC_ERROR ); } else if ( Ch != ':' || InvalidSwitch->QueryChCount() == 2 ) { DisplayMessageAndExit( XCOPY_ERROR_INVALID_SWITCH_SWITCH, InvalidSwitchArgument->GetLexeme(), EXIT_MISC_ERROR ); } } else if ( Ch == '/' ) { Ch = InvalidSwitch->QueryChAt(1); if ( Ch == ':' && InvalidSwitchArgument->GetString()->QueryChAt(2) == INVALID_CHAR ) { InvalidSwitchArgument->GetLexeme()->Truncate(1); } }
Ch = InvalidSwitch->QueryChAt(0);
if ( InvalidParms.Strchr( Ch ) != INVALID_CHNUM ) { DisplayMessageAndExit( XCOPY_ERROR_INVALID_PARAMETER, InvalidSwitchArgument->GetLexeme(), EXIT_MISC_ERROR ); } else { DisplayMessageAndExit( XCOPY_ERROR_INVALID_SWITCH_SWITCH, InvalidSwitchArgument->GetLexeme(), EXIT_MISC_ERROR ); } }
//
// Set the switches
//
_EmptySwitch = EmptyArgument->QueryFlag(); _ModifySwitch = ModifyArgument->QueryFlag();
//
// ModifySwitch implies ArchiveSwitch
//
if ( _ModifySwitch ) { _ArchiveSwitch = TRUE; } else { _ArchiveSwitch = ArchiveArgument->QueryFlag(); }
//
// Set the switches
//
_PromptSwitch = PromptArgument->QueryFlag(); _OverWriteSwitch = QueryOverWriteSwitch(); _SubdirSwitch = SubdirArgument->QueryFlag(); _VerifySwitch = VerifyArgument->QueryFlag(); _WaitSwitch = WaitArgument->QueryFlag(); _ContinueSwitch = ContinueArgument->QueryFlag(); _IntelligentSwitch = IntelligentArgument->QueryFlag(); _CopyIfOldSwitch = OldArgument->QueryFlag(); _DecryptSwitch = DecryptArgument->QueryFlag(); _VerboseSwitch = VerboseArgument->QueryFlag(); _HiddenSwitch = HiddenArgument->QueryFlag(); _ReadOnlySwitch = ReadOnlyArgument->QueryFlag(); _SilentSwitch = SilentArgument->QueryFlag(); _DontCopySwitch = NoCopyArgument->QueryFlag(); _StructureOnlySwitch= StructureArgument->QueryFlag(); _UpdateSwitch = UpdateArgument->QueryFlag(); _CopyAttrSwitch = CopyAttrArgument->QueryFlag(); _UseShortSwitch = UseShortArgument->QueryFlag(); _RestartableSwitch = RestartableArgument->QueryFlag(); _OwnerSwitch = OwnerArgument->QueryFlag(); _AuditSwitch = AuditArgument->QueryFlag(); HelpSwitch = HelpArgument->QueryFlag();
//
// Set the source and destination paths. Argument checking is
// done somewhere else, so it is ok. to set the source path to
// NULL here.
//
GetSourceAndDestinationPath(FirstPathArgument, FirstQuotedPathArgument, SecondPathArgument, SecondQuotedPathArgument, ArgLex, &_SourcePath, &_DestinationPath);
DELETE(ArgLex);
//
// Set the date argument
//
if ( DateArgument->IsValueSet() ) {
if ((_Date = NEW TIMEINFO) == NULL ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); }
_Date->Initialize( DateArgument->GetTimeInfo() );
//
// The command-line date argument is specified in local time so
// that it corresponds to the output of 'dir'. We want to compare
// it to file timestamps that we query from the file system, so
// convert the argument from local to universal time.
//
_Date->ConvertToUTC();
} else {
_Date = NULL; }
if( ExclusionListArgument->IsValueSet() ) {
InitializeExclusionList( ExclusionListArgument->GetString() ); } }
PARGUMENT_LEXEMIZER XCOPY::ParseArguments( IN PWSTRING CmdLine, OUT PARRAY ArgArray )
/*++
Routine Description:
Parses a group of arguments
Arguments:
CmdLine - Supplies pointer to a command line to parse ArgArray - Supplies pointer to array of arguments
Return Value:
Returns the argument lexemizer used which then needs to be freed by the client.
Notes:
--*/
{ PARGUMENT_LEXEMIZER ArgLex;
//
// Initialize lexeme array and the lexemizer.
//
if ( !(ArgLex = NEW ARGUMENT_LEXEMIZER) || !(LexArray->Initialize( 9, 9 )) || !(ArgLex->Initialize( LexArray )) ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); }
//
// Set our parsing preferences
//
ArgLex->PutMultipleSwitch( "/?ABMDPSEVWCIFHRQLKTUNZOXY" ); ArgLex->PutSwitches( "/" ); ArgLex->SetCaseSensitive( FALSE ); ArgLex->PutSeparators( " \t" ); ArgLex->PutStartQuotes( "\"" ); ArgLex->PutEndQuotes( "\"" ); ArgLex->SetAllowSwitchGlomming( TRUE ); ArgLex->SetNoSpcBetweenDstAndSwitch( TRUE );
//
// Parse the arguments
//
if ( !(ArgLex->PrepareToParse( CmdLine ))) {
DisplayMessageAndExit( XCOPY_ERROR_PARSE, NULL, EXIT_MISC_ERROR );
}
if ( !ArgLex->DoParsing( ArgArray ) ) {
DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS, NULL, EXIT_MISC_ERROR ); }
return ArgLex; }
VOID XCOPY::CheckArgumentConsistency ( )
/*++
Routine Description:
Checks the consistency of the arguments
Arguments:
none
Return Value:
none
Notes:
--*/
{ PFSN_DIRECTORY DirSrc = NULL; PFSN_DIRECTORY DirDst = NULL; PWSTRING DevSrc = NULL; PWSTRING DevDst = NULL; PATH PathSrc, PathSrc1; PATH PathDst, PathDst1; DSTRING Slash;
if ( HelpSwitch ) { //
// Help requested
//
Usage(); DisplayMessageAndExit( 0, NULL, EXIT_NORMAL ); }
//
// Make sure that we have a source path
//
if ( _SourcePath == NULL ) {
DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS, NULL, EXIT_MISC_ERROR ); }
//
// The empty switch implies Subdir switch (note that DOS
// requires Subdir switch explicitly).
//
//
if ( _EmptySwitch ) { _SubdirSwitch = TRUE; }
//
// The StructureOnly switch imples the subdir switch
//
if ( _StructureOnlySwitch ) { _SubdirSwitch = TRUE; }
//
// Copying audit info implies copying the rest of the security
// info.
//
_OwnerSwitch = _OwnerSwitch || _AuditSwitch;
//
// Restartable copy is not available with security because
// secure copy uses BackupRead/Write instead of CopyFileEx.
//
if (_OwnerSwitch && _RestartableSwitch) {
DisplayMessageAndExit( XCOPY_ERROR_Z_X_CONFLICT, NULL, EXIT_MISC_ERROR ); }
//
// If destination path is null, then the destination path is the
// current directory
//
if ( _DestinationPath == NULL ) {
if ( ((_DestinationPath = NEW PATH) == NULL ) || !_DestinationPath->Initialize( (LPWSTR)L".", TRUE ) ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); } }
_DestinationPath->TruncateNameAtColon();
if ( !PathSrc1.Initialize( _SourcePath, TRUE ) || !PathDst1.Initialize( _DestinationPath, TRUE ) || !(DevSrc = PathSrc1.QueryDevice()) || !(DevDst = PathDst1.QueryDevice()) || !PathSrc.Initialize( DevSrc ) || !PathDst.Initialize( DevDst ) || !Slash.Initialize( "\\" ) || !PathSrc.AppendBase( &Slash ) || !PathDst.AppendBase( &Slash ) || !(DirSrc = SYSTEM::QueryDirectory( &PathSrc )) || !(DirDst = SYSTEM::QueryDirectory( &PathDst )) ) { DisplayMessageAndExit( XCOPY_ERROR_INVALID_DRIVE, NULL, EXIT_MISC_ERROR ); } DELETE( DevSrc ); DELETE( DevDst ); DELETE( DirSrc ); DELETE( DirDst ); }
BOOLEAN XCOPY::AddToExclusionList( IN PWSTRING ExclusionListFileName ) /*++
Routine Description:
This method adds the contents of the specified file to the exclusion list.
Arguments:
ExclusionListFileName -- Supplies the name of a file which contains the exclusion list.
Return Value:
TRUE upon successful completion.
--*/ { PATH ExclusionPath; PDSTRING String; PFSN_FILE File; PFILE_STREAM Stream; CHNUM Position;
DebugPtrAssert( ExclusionListFileName );
if( !ExclusionPath.Initialize( ExclusionListFileName ) || (File = SYSTEM::QueryFile( &ExclusionPath )) == NULL || (Stream = File->QueryStream( READ_ACCESS )) == NULL ) {
DisplayMessageAndExit( MSG_COMP_UNABLE_TO_READ, ExclusionListFileName, EXIT_MISC_ERROR ); }
while( !Stream->IsAtEnd() && (String = NEW DSTRING) != NULL && Stream->ReadLine ( String ) ) {
if( String->QueryChCount() == 0 ) {
continue; }
// Convert the string to upper-case and remove
// trailing whitespace (blanks and tabs).
//
String->Strupr(); Position = String->QueryChCount() - 1;
while( Position != 0 && (String->QueryChAt( Position ) == ' ' || String->QueryChAt( Position ) == '\t') ) {
Position -= 1; }
if( String->QueryChAt( Position ) != ' ' && String->QueryChAt( Position ) != '\t' ) {
Position++; }
if( Position != String->QueryChCount() ) {
String->Truncate( Position ); }
if( String->QueryChCount() != 0 && !_ExclusionList->Put( String ) ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); } }
DELETE( Stream ); DELETE( File ); return TRUE; }
BOOLEAN XCOPY::InitializeExclusionList( IN PWSTRING ListOfFiles ) /*++
Routine Description:
This method reads the exclusion list and initializes the exclusion list array.
Arguments:
ListOfFiles -- Supplies a string containing a list of file names, separated by '+' (e.g. file1+file2+file3)
Return Value:
TRUE upon successful completion.
--*/ { DSTRING CurrentName; CHNUM LastPosition, Position;
DebugPtrAssert( ListOfFiles );
if( (_ExclusionList = NEW STRING_ARRAY) == NULL || !_ExclusionList->Initialize() || (_Iterator = _ExclusionList->QueryIterator()) == NULL ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); }
LastPosition = 0;
while( LastPosition != ListOfFiles->QueryChCount() ) {
Position = ListOfFiles->Strchr( '+', LastPosition );
if( Position == INVALID_CHNUM ) {
Position = ListOfFiles->QueryChCount(); }
if( Position != LastPosition ) {
if( !CurrentName.Initialize( ListOfFiles, LastPosition, Position - LastPosition ) ) {
DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR ); }
AddToExclusionList( &CurrentName ); }
// Advance past any separators.
//
while( Position < ListOfFiles->QueryChCount() && ListOfFiles->QueryChAt( Position ) == '+' ) {
Position += 1; }
LastPosition = Position; }
return TRUE; }
BOOLEAN XCOPY::QueryOverWriteSwitch( ) { PCHAR env; DSTRING env_str;
if (OverWriteArgument->IsValueSet() && NotOverWriteArgument->IsValueSet()) { return (OverWriteArgument->QueryArgPos() > NotOverWriteArgument->QueryArgPos()); } else if (OverWriteArgument->IsValueSet()) return OverWriteArgument->QueryFlag(); else if (NotOverWriteArgument->IsValueSet()) return !NotOverWriteArgument->QueryFlag(); else { env = getenv("COPYCMD"); if (env == NULL) return FALSE; // use default
else { if (!env_str.Initialize(env)) return FALSE; // to be on the safe side
if (env_str.Stricmp(OverWriteArgument->GetPattern()) == 0) return TRUE; return FALSE;
} } }
|