You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
805 lines
24 KiB
805 lines
24 KiB
/*++
|
|
|
|
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 );
|
|
}
|