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

806 lines
23 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991-2000 Microsoft Corporation
Module Name:
attrib.cxx
Abstract:
This utility allows the user to change file attributes.
It is functionaly compatible with DOS 5 attrib utility.
Author:
Jaime F. Sasson
Environment:
ULIB, User Mode
--*/
#include "ulib.hxx"
#include "arg.hxx"
#include "array.hxx"
#include "path.hxx"
#include "wstring.hxx"
#include "substrng.hxx"
#include "dir.hxx"
#include "filter.hxx"
#include "system.hxx"
#include "arrayit.hxx"
#include "stream.hxx"
#include "smsg.hxx"
#include "rtmsg.h"
#include "attrib.hxx"
PSTREAM Get_Standard_Input_Stream();
PSTREAM Get_Standard_Output_Stream();
extern "C" {
#include <stdio.h>
}
DEFINE_CONSTRUCTOR( ATTRIB, PROGRAM );
BOOLEAN
ATTRIB::Initialize(
)
/*++
Routine Description:
Initializes an ATTRIB class.
Arguments:
None.
Return Value:
BOOLEAN - Indicates if the initialization succeeded.
--*/
{
PWSTRING DynSubDirectory;
PWSTRING DynSubFileName;
ARGUMENT_LEXEMIZER ArgLex;
ARRAY LexArray;
ARRAY ArgumentArray;
STRING_ARGUMENT ProgramNameArgument;
// STRING_ARGUMENT FileNameArgument;
PCWSTRING FullFileNameString;
PATH DirectoryNamePath;
PCWSTRING InvalidName;
PCWSTRING TempPathString;
DSTRING TempPathStringDrive;
PATH PathDrive;
DSTRING BackSlashString;
STRING_ARGUMENT InvalidSwitch;
STRING_ARGUMENT InvalidSwitchPlus;
STRING_ARGUMENT InvalidSwitchMinus;
PWSTRING InvalidArgument;
DSTRING InvalidSwitchString;
BOOLEAN ActOnDirectory;
_InitialDirectory = NULL;
//
// Initialize MESSAGE object
//
_OutStream = Get_Standard_Output_Stream();
if (_OutStream == NULL) {
DebugPrintTrace(("ATTRIB: Output stream is NULL\n"));
return FALSE;
}
_Message.Initialize( _OutStream, Get_Standard_Input_Stream() );
//
// Initialize string that contains End-Of-Line characters
//
if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
DebugPrint( "_EndOfLineString.Initialize() failed" );
return( FALSE );
}
//
// Parse command line
//
if ( !LexArray.Initialize( ) ) {
DebugPrint( "LexArray.Initialize() failed \n" );
return( FALSE );
}
if ( !ArgLex.Initialize( &LexArray ) ) {
DebugPrint( "ArgLex.Initialize() failed \n" );
return( FALSE );
}
ArgLex.PutSwitches( "/" );
ArgLex.SetCaseSensitive( FALSE );
ArgLex.PutStartQuotes( "\"");
ArgLex.PutEndQuotes( "\"");
ArgLex.PutSeparators( " \t" );
if( !ArgLex.PrepareToParse() ) {
DebugPrint( "ArgLex.PrepareToParse() failed \n" );
_Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
_Message.Display( " " );
return( FALSE );
}
if ( !ArgumentArray.Initialize() ) {
DebugPrint( "ArgumentArray.Initialize() failed \n" );
return( FALSE );
}
if( !ProgramNameArgument.Initialize("*") ||
!_FlagRemoveSystemAttribute.Initialize( "-S" ) ||
!_FlagAddSystemAttribute.Initialize( "+S" ) ||
!_FlagRemoveHiddenAttribute.Initialize( "-H" ) ||
!_FlagAddHiddenAttribute.Initialize( "+H" ) ||
!_FlagRemoveReadOnlyAttribute.Initialize( "-R" ) ||
!_FlagAddReadOnlyAttribute.Initialize( "+R" ) ||
!_FlagRemoveArchiveAttribute.Initialize( "-A" ) ||
!_FlagAddArchiveAttribute.Initialize( "+A" ) ||
!_FlagRecurseDirectories.Initialize( "/S" ) ||
!_FlagActOnDirectories.Initialize( "/D" ) ||
!_FlagDisplayHelp.Initialize( "/?" ) ||
!InvalidSwitch.Initialize( "/*" ) ||
!InvalidSwitchPlus.Initialize( "+*" ) ||
!InvalidSwitchMinus.Initialize( "-*" ) ||
!_FileNameArgument.Initialize( "*" ) ) {
DebugPrint( "Unable to initialize flag or string arguments \n" );
return( FALSE );
}
if( !ArgumentArray.Put( &ProgramNameArgument ) ||
!ArgumentArray.Put( &_FlagRemoveSystemAttribute ) ||
!ArgumentArray.Put( &_FlagAddSystemAttribute ) ||
!ArgumentArray.Put( &_FlagRemoveHiddenAttribute ) ||
!ArgumentArray.Put( &_FlagAddHiddenAttribute ) ||
!ArgumentArray.Put( &_FlagRemoveReadOnlyAttribute ) ||
!ArgumentArray.Put( &_FlagAddReadOnlyAttribute ) ||
!ArgumentArray.Put( &_FlagRemoveArchiveAttribute ) ||
!ArgumentArray.Put( &_FlagAddArchiveAttribute ) ||
!ArgumentArray.Put( &_FlagRecurseDirectories ) ||
!ArgumentArray.Put( &_FlagActOnDirectories ) ||
!ArgumentArray.Put( &_FlagDisplayHelp ) ||
!ArgumentArray.Put( &InvalidSwitch ) ||
!ArgumentArray.Put( &InvalidSwitchPlus ) ||
!ArgumentArray.Put( &InvalidSwitchMinus ) ||
!ArgumentArray.Put( &_FileNameArgument ) ) {
DebugPrint( "ArgumentArray.Put() failed \n" );
return( FALSE );
}
if( !ArgLex.DoParsing( &ArgumentArray ) ) {
_Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
_Message.Display( " " );
return( FALSE );
}
//
// Check the existance of an invalid switch
//
if( InvalidSwitch.IsValueSet() ||
InvalidSwitchPlus.IsValueSet() ||
InvalidSwitchMinus.IsValueSet() ) {
if( InvalidSwitch.IsValueSet() ) {
//
// The invalid switch starts with '/'
//
if( !InvalidSwitchString.Initialize( "/" ) ) {
DebugPrint( "InvalidSwitchString.Initialize( / ) failed \n" );
return( FALSE );
}
InvalidArgument = InvalidSwitch.GetString();
DebugPtrAssert( InvalidArgument );
} else if ( InvalidSwitchPlus.IsValueSet() ) {
//
// The invalid switch starts with '+'
//
if( !InvalidSwitchString.Initialize( "+" ) ) {
DebugPrint( "InvalidSwitchString.Initialize( + ) failed \n" );
return( FALSE );
}
InvalidArgument = InvalidSwitchPlus.GetString();
DebugPtrAssert( InvalidArgument );
} else {
//
// The invalid switch starts with '-'
//
if( !InvalidSwitchString.Initialize( "-" ) ) {
DebugPrint( "InvalidSwitchString.Initialize( - ) failed \n" );
return( FALSE );
}
InvalidArgument = InvalidSwitchMinus.GetString();
DebugPtrAssert( InvalidArgument );
}
//
// Display the error message followed by the invalid switch
//
if( !InvalidSwitchString.Strcat( InvalidArgument ) ) {
DebugPrint( "InvalidSwitchString.Strcat( InvalidArgument ) failed \n" );
return( FALSE );
}
_Message.Set( MSG_ATTRIB_INVALID_SWITCH );
_Message.Display( "%W", &InvalidSwitchString );
return( FALSE );
}
if ( _FlagActOnDirectories.QueryFlag() &&
!_FlagRecurseDirectories.QueryFlag() ) {
_Message.Set( MSG_ATTRIB_INVALID_COMBINATION );
_Message.Display();
return( FALSE );
}
//
// +S -S or +H -H or +R -R or +A -A are not valid
// combination of arguments
//
if( ( _FlagRemoveSystemAttribute.QueryFlag() &&
_FlagAddSystemAttribute.QueryFlag() ) ||
( _FlagRemoveHiddenAttribute.QueryFlag() &&
_FlagAddHiddenAttribute.QueryFlag() ) ||
( _FlagRemoveReadOnlyAttribute.QueryFlag() &&
_FlagAddReadOnlyAttribute.QueryFlag() ) ||
( _FlagRemoveArchiveAttribute.QueryFlag() &&
_FlagAddArchiveAttribute.QueryFlag() ) ) {
_Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
_Message.Display( " " );
return( FALSE );
}
if( _FlagRemoveSystemAttribute.QueryFlag() ||
_FlagAddSystemAttribute.QueryFlag() ||
_FlagRemoveHiddenAttribute.QueryFlag() ||
_FlagAddHiddenAttribute.QueryFlag() ||
_FlagRemoveReadOnlyAttribute.QueryFlag() ||
_FlagAddReadOnlyAttribute.QueryFlag() ||
_FlagRemoveArchiveAttribute.QueryFlag() ||
_FlagAddArchiveAttribute.QueryFlag() ) {
_PrintAttribInfo = FALSE;
_ResetMask = (FSN_ATTRIBUTE)0xffffffff;
if( _FlagRemoveSystemAttribute.QueryFlag() ) {
_ResetMask &= ~FSN_ATTRIBUTE_SYSTEM;
}
if( _FlagRemoveHiddenAttribute.QueryFlag() ) {
_ResetMask &= ~FSN_ATTRIBUTE_HIDDEN;
}
if( _FlagRemoveReadOnlyAttribute.QueryFlag() ) {
_ResetMask &= ~FSN_ATTRIBUTE_READONLY;
}
if( _FlagRemoveArchiveAttribute.QueryFlag() ) {
_ResetMask &= ~FSN_ATTRIBUTE_ARCHIVE;
}
_MakeMask = 0;
if( _FlagAddSystemAttribute.QueryFlag() ) {
_MakeMask |= FSN_ATTRIBUTE_SYSTEM;
}
if( _FlagAddHiddenAttribute.QueryFlag() ) {
_MakeMask |= FSN_ATTRIBUTE_HIDDEN;
}
if( _FlagAddReadOnlyAttribute.QueryFlag() ) {
_MakeMask |= FSN_ATTRIBUTE_READONLY;
}
if( _FlagAddArchiveAttribute.QueryFlag() ) {
_MakeMask |= FSN_ATTRIBUTE_ARCHIVE;
}
} else {
_PrintAttribInfo = TRUE;
}
//
// Get filename
//
if( !_FileNameArgument.IsValueSet() ) {
//
// User didn't specify file name. Use *.* as default
//
FullFileNameString = NULL;
if( !_FullFileNamePath.Initialize( (LPWSTR)L"*.*", TRUE ) ) {
DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
return( FALSE );
}
} else {
//
// Get name specified in the command line
//
FullFileNameString = _FileNameArgument.GetPath()->GetPathString();
DebugPtrAssert( FullFileNameString );
if( !_FullFileNamePath.Initialize( FullFileNameString, TRUE ) ) {
DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
return( FALSE );
}
}
//
// Get prefix and verify that it exists
//
if( ( DynSubDirectory = _FullFileNamePath.QueryPrefix() ) == NULL ) {
DebugPrint( "_FullFileNamePath.QueryPrefix() failed \n" );
return( FALSE );
}
if( !DirectoryNamePath.Initialize( DynSubDirectory ) ) {
DELETE( DynSubDirectory );
DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
return( FALSE );
}
DELETE( DynSubDirectory );
//
// Have to test if DirectoryNamePath is a drive, and if it is
// add \ to it otherwise it won't be able to find a file that is
// in the root directory, if the current directory is not the root.
//
if( DirectoryNamePath.IsDrive() ) {
if( !BackSlashString.Initialize( "\\" ) ) {
DebugPrint( "BackSlashString.Initialize() failed \n" );
return( FALSE );
}
TempPathString = DirectoryNamePath.GetPathString();
DebugPtrAssert( TempPathString );
if( !TempPathStringDrive.Initialize( TempPathString ) ) {
DebugPrint( "TempPathStringDrive.Initialize() failed \n" );
return( FALSE );
}
TempPathStringDrive.Strcat( &BackSlashString );
if( !PathDrive.Initialize( &TempPathStringDrive ) ) {
DebugPrint( "PathDrive.Initialize() failed \n" );
return( FALSE );
}
if( !DirectoryNamePath.Initialize( &PathDrive ) ) {
DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
return( FALSE );
}
}
if( ( _InitialDirectory = SYSTEM::QueryDirectory( &DirectoryNamePath ) ) == NULL ) {
InvalidName = DirectoryNamePath.GetPathString();
DebugPtrAssert( InvalidName );
_Message.Set( MSG_ATTRIB_PATH_NOT_FOUND );
_Message.Display( "%W", InvalidName );
return( FALSE );
}
//
// Initialize filter for directories
//
if( !_FsnFilterDirectory.Initialize() ) {
DELETE( _InitialDirectory );
DebugPrint( "_FsnFilterDirectory.Initialize() failed \n" );
return( FALSE );
}
if( !_FsnFilterDirectory.SetFileName( "*.*" ) ) {
DELETE( _InitialDirectory );
DebugPrint( "_FsnFilterDirectory.SetFilename() failed \n" );
return( FALSE );
}
if( !_FsnFilterDirectory.SetAttributes( FSN_ATTRIBUTE_DIRECTORY ) ) {
DELETE( _InitialDirectory );
DebugPrint( "_FsnFilterDirectory.SetAttributes() failed \n" );
return( FALSE );
}
//
// Get file name and initialize filter for files
//
if( ( DynSubFileName = _FullFileNamePath.QueryName() ) == NULL ) {
if( _FileNameArgument.IsValueSet() ) {
InvalidName = _FileNameArgument.GetPath()->GetPathString();
} else {
InvalidName = DirectoryNamePath.GetPathString();
}
DebugPtrAssert( InvalidName );
_Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
_Message.Display( "%W", InvalidName );
DELETE( _InitialDirectory );
return( FALSE );
}
//
// Determine whether attrib should act on a directory.
// It will do so only if the user specify a directory name that does
// not contain the characters '*' or '?'.
// Also, attrib will not act on directories if the switch /S is specified.
//
if( _FlagRecurseDirectories.QueryFlag() ||
( FullFileNameString == NULL ) ||
( FullFileNameString->Strchr( ( WCHAR )'*' ) != INVALID_CHNUM ) ||
( FullFileNameString->Strchr( ( WCHAR )'?' ) != INVALID_CHNUM ) ) {
ActOnDirectory = _FlagActOnDirectories.QueryFlag();
} else {
ActOnDirectory = TRUE;
}
if( !_FsnFilterFile.Initialize() ) {
DELETE( _InitialDirectory );
DELETE( DynSubFileName );
DebugPrint( "FsnFilter.Initialize() failed \n" );
return( FALSE );
}
if( !_FsnFilterFile.SetFileName( DynSubFileName ) ) {
DELETE( _InitialDirectory );
DELETE( DynSubFileName );
DebugPrint( "FsnFilter.SetFilename() failed \n" );
return( FALSE );
}
if( !ActOnDirectory ) {
if( !_FsnFilterFile.SetAttributes( 0, 0, FSN_ATTRIBUTE_DIRECTORY ) ) {
DELETE( _InitialDirectory );
DELETE( DynSubFileName );
DebugPrint( "FsnFilter.SetAttributes() failed \n" );
return( FALSE );
}
} else {
if( !_FsnFilterFile.SetAttributes( 0, 0, 0 ) ) {
DELETE( _InitialDirectory );
DELETE( DynSubFileName );
DebugPrint( "FsnFilter.SetAttributes() failed \n" );
return( FALSE );
}
}
DELETE( DynSubFileName );
if( _FlagDisplayHelp.QueryFlag() ) {
_Message.Set( MSG_ATTRIB_HELP_MESSAGE );
_Message.Display( " " );
return( FALSE );
}
_FoundFile = FALSE;
LexArray.DeleteAllMembers();
return( TRUE );
}
VOID
ATTRIB::Terminate(
)
/*++
Routine Description:
Deletes objects created during initialization.
Arguments:
None.
Return Value:
None.
--*/
{
if( _InitialDirectory != NULL ) {
DELETE( _InitialDirectory );
}
}
VOID
ATTRIB::DisplayFileNotFoundMessage(
)
/*++
Routine Description:
Displays a message indicating that no file that meets the file filter
criteria was found.
Arguments:
None.
Return Value:
None.
--*/
{
PCWSTRING FileName;
if( !_FoundFile ) {
if( _FileNameArgument.IsValueSet() ) {
FileName = _FileNameArgument.GetPath()->GetPathString();
} else {
FileName = _FullFileNamePath.GetPathString();
}
DebugPtrAssert( FileName );
_Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
_Message.Display( "%W", FileName );
}
}
VOID
ATTRIB::DisplayFileAttribute (
IN PCFSNODE Fsn
)
/*++
Routine Description:
Displays a filename and its attributes
Arguments:
Fsn - A pointer to an FSNODE that contains the information
about the file.
Return Value:
None.
--*/
{
// PCWC_STRING pcWcString;
PCWSTRING pcWcString;
WCHAR Buffer[ 12 ];
DSTRING String;
DebugPtrAssert( Fsn );
DebugPtrAssert( Fsn->GetPath( ));
pcWcString = ( Fsn->GetPath( ))->GetPathString( );
DebugPtrAssert( pcWcString );
swprintf( Buffer,
( LPWSTR )L"%lc %lc%lc%lc ",
Fsn->IsArchived() ? ( WCHAR )'A' : ( WCHAR )' ',
Fsn->IsSystem() ? ( WCHAR )'S' : ( WCHAR )' ',
Fsn->IsHidden() ? ( WCHAR )'H' : ( WCHAR )' ',
Fsn->IsReadOnly() ? ( WCHAR )'R' : ( WCHAR )' ' );
if( !String.Initialize( Buffer ) ||
!String.Strcat( pcWcString ) ||
!String.Strcat( &_EndOfLineString ) ||
!_OutStream->WriteString( &String ) ) {
DebugPrint( "Unable to display message" );
}
}
BOOLEAN
ATTRIB::ChangeFileAttributes(
IN PFSNODE FsnFile
)
/*++
Routine Description:
Changes the file attributes. The attributes will be changed depending
on the argumets specified in the command line, and on the current
attributes of the file.
The algorithm for changing attributes is presented below:
if( ( -s and -h were specified as arguments ) or
( -s and +h were specified as arguments ) or
( +s and -h were specified as arguments ) or
( +s and +h were specified as arguments ) ) {
Change file attributes;
} else if ( ( -h and +h were not specified as arguments ) and
( file has hidden attribute ) ) {
print( "Not resetting hidden file: <filename> " );
} else if ( ( -s and +s were not specified as arguments ) and
( file has system attribute ) ) {
print( "Not resetting system file: <filename> " );
} else {
Change file attributes;
}
Arguments:
FsnFile - A pointer to an FSNODE that contains the information
about the file.
Return Value:
BOOLEAN - Returns FALSE if this function fails due to a failure
in an API call.
--*/
{
// BOOLEAN Result;
BOOLEAN Change;
DWORD Win32Error;
// PCWC_STRING pcWcString;
PCWSTRING pcWcString;
FSN_ATTRIBUTE Attributes;
DebugPtrAssert( FsnFile->GetPath( ));
pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
DebugPtrAssert( pcWcString );
if( ( ( _FlagAddSystemAttribute.QueryFlag() ||
_FlagRemoveSystemAttribute.QueryFlag() ) &&
( _FlagAddHiddenAttribute.QueryFlag() ||
_FlagRemoveHiddenAttribute.QueryFlag() ) ) ) {
Change = TRUE;
} else if( !_FlagAddHiddenAttribute.QueryFlag() &&
!_FlagRemoveHiddenAttribute.QueryFlag() &&
FsnFile->IsHidden() ) {
// DebugPtrAssert( FsnFile->GetPath( ));
// pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
// DebugPtrAssert( pcWcString );
_Message.Set( MSG_ATTRIB_NOT_RESETTING_HIDDEN_FILE );
_Message.Display( "%W", pcWcString );
Change = FALSE;
} else if( !_FlagAddSystemAttribute.QueryFlag() &&
!_FlagRemoveSystemAttribute.QueryFlag() &&
FsnFile->IsSystem() ) {
// DebugPtrAssert( FsnFile->GetPath( ));
// pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
// DebugPtrAssert( pcWcString );
_Message.Set( MSG_ATTRIB_NOT_RESETTING_SYS_FILE );
_Message.Display( "%W", pcWcString );
Change = FALSE;
} else {
Change = TRUE;
}
// Result = TRUE;
if( Change ) {
Attributes = FsnFile->QueryAttributes();
if( !FsnFile->SetAttributes( ( Attributes & _ResetMask ) | _MakeMask,
&Win32Error ) ) {
if( Win32Error == ERROR_ACCESS_DENIED ) {
_Message.Set( MSG_ATTRIB_ACCESS_DENIED );
} else {
_Message.Set( MSG_ATTRIB_UNABLE_TO_CHANGE_ATTRIBUTE );
}
_Message.Display( "%W", pcWcString );
DebugPrint( "Unable to change file attribute \n" );
return( FALSE );
}
}
return( TRUE );
}
BOOLEAN
ATTRIB::ExamineFiles(
IN PFSN_DIRECTORY Directory
)
/*++
Routine Description:
Builds an array of files in the specified directory, and
tries to change the attributes of each of these files.
Does the same thing in all subdirectories, if the "recurse"
flag was specified in the command line.
Arguments:
Directory - Pointer to an FSN_DIRECTORY that describes the
directory to be examined
Return Value:
Boolean: TRUE if Successful.
--*/
{
PARRAY DirectoryArray;
PFSN_DIRECTORY FsnDirectory;
PARRAY_ITERATOR DirectoryArrayIterator;
PARRAY FileArray;
PARRAY_ITERATOR FileArrayIterator;
PFSNODE FsnFile;
DebugPtrAssert( Directory );
//
// If /S was specified as argument in the command line, builds
// an array of PFSN_DIRECTORY of all sub-directories in the current
// directory and examines the files in each sub-directory
//
if( _FlagRecurseDirectories.QueryFlag() ) {
if( ( DirectoryArray = Directory->QueryFsnodeArray( &_FsnFilterDirectory ) ) == NULL ) {
DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterDirectory ) failed \n" );
return( FALSE );
}
if( ( DirectoryArrayIterator =
( PARRAY_ITERATOR )( DirectoryArray->QueryIterator() ) ) == NULL ) {
DebugPrint( "DirectoryArray->QueryIterator() failed \n" );
return( FALSE );
}
while( ( FsnDirectory = ( PFSN_DIRECTORY )( DirectoryArrayIterator->GetNext( ) ) ) != NULL ) {
ExamineFiles( FsnDirectory );
DELETE( FsnDirectory );
}
DELETE( DirectoryArrayIterator );
DELETE( DirectoryArray );
}
//
// Builds an array of FSNODEs of the files tha meet the 'filter'
// criteria, and change or display the attributes of these files
//
if( ( FileArray = Directory->QueryFsnodeArray( &_FsnFilterFile ) ) == NULL ) {
DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterFile ) failed \n" );
return( FALSE );
}
if( ( FileArrayIterator =
( PARRAY_ITERATOR )( FileArray->QueryIterator() ) ) == NULL ) {
DebugPrint( "FileArray->QueryIterator() failed \n" );
return( FALSE );
}
while( ( FsnFile = ( PFSNODE )( FileArrayIterator->GetNext( ) ) ) != NULL ) {
if( _PrintAttribInfo ) {
DisplayFileAttribute( FsnFile );
} else {
ChangeFileAttributes( FsnFile );
}
_FoundFile = TRUE;
DELETE( FsnFile );
}
DELETE( FileArrayIterator );
DELETE( FileArray );
return( TRUE );
}
ULONG __cdecl
main()
{
DEFINE_CLASS_DESCRIPTOR( ATTRIB );
{
ATTRIB Attrib;
if( Attrib.Initialize() ) {
Attrib.ExamineFiles( Attrib.GetInitialDirectory() );
Attrib.DisplayFileNotFoundMessage();
}
Attrib.Terminate();
}
return( 0 );
}