Source code of Windows XP (NT5)
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
23 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. attrib.cxx
  5. Abstract:
  6. This utility allows the user to change file attributes.
  7. It is functionaly compatible with DOS 5 attrib utility.
  8. Author:
  9. Jaime F. Sasson
  10. Environment:
  11. ULIB, User Mode
  12. --*/
  13. #include "ulib.hxx"
  14. #include "arg.hxx"
  15. #include "array.hxx"
  16. #include "path.hxx"
  17. #include "wstring.hxx"
  18. #include "substrng.hxx"
  19. #include "dir.hxx"
  20. #include "filter.hxx"
  21. #include "system.hxx"
  22. #include "arrayit.hxx"
  23. #include "stream.hxx"
  24. #include "smsg.hxx"
  25. #include "rtmsg.h"
  26. #include "attrib.hxx"
  27. PSTREAM Get_Standard_Input_Stream();
  28. PSTREAM Get_Standard_Output_Stream();
  29. extern "C" {
  30. #include <stdio.h>
  31. }
  32. DEFINE_CONSTRUCTOR( ATTRIB, PROGRAM );
  33. BOOLEAN
  34. ATTRIB::Initialize(
  35. )
  36. /*++
  37. Routine Description:
  38. Initializes an ATTRIB class.
  39. Arguments:
  40. None.
  41. Return Value:
  42. BOOLEAN - Indicates if the initialization succeeded.
  43. --*/
  44. {
  45. PWSTRING DynSubDirectory;
  46. PWSTRING DynSubFileName;
  47. ARGUMENT_LEXEMIZER ArgLex;
  48. ARRAY LexArray;
  49. ARRAY ArgumentArray;
  50. STRING_ARGUMENT ProgramNameArgument;
  51. // STRING_ARGUMENT FileNameArgument;
  52. PCWSTRING FullFileNameString;
  53. PATH DirectoryNamePath;
  54. PCWSTRING InvalidName;
  55. PCWSTRING TempPathString;
  56. DSTRING TempPathStringDrive;
  57. PATH PathDrive;
  58. DSTRING BackSlashString;
  59. STRING_ARGUMENT InvalidSwitch;
  60. STRING_ARGUMENT InvalidSwitchPlus;
  61. STRING_ARGUMENT InvalidSwitchMinus;
  62. PWSTRING InvalidArgument;
  63. DSTRING InvalidSwitchString;
  64. BOOLEAN ActOnDirectory;
  65. _InitialDirectory = NULL;
  66. //
  67. // Initialize MESSAGE object
  68. //
  69. _OutStream = Get_Standard_Output_Stream();
  70. if (_OutStream == NULL) {
  71. DebugPrintTrace(("ATTRIB: Output stream is NULL\n"));
  72. return FALSE;
  73. }
  74. _Message.Initialize( _OutStream, Get_Standard_Input_Stream() );
  75. //
  76. // Initialize string that contains End-Of-Line characters
  77. //
  78. if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
  79. DebugPrint( "_EndOfLineString.Initialize() failed" );
  80. return( FALSE );
  81. }
  82. //
  83. // Parse command line
  84. //
  85. if ( !LexArray.Initialize( ) ) {
  86. DebugPrint( "LexArray.Initialize() failed \n" );
  87. return( FALSE );
  88. }
  89. if ( !ArgLex.Initialize( &LexArray ) ) {
  90. DebugPrint( "ArgLex.Initialize() failed \n" );
  91. return( FALSE );
  92. }
  93. ArgLex.PutSwitches( "/" );
  94. ArgLex.SetCaseSensitive( FALSE );
  95. ArgLex.PutStartQuotes( "\"");
  96. ArgLex.PutEndQuotes( "\"");
  97. ArgLex.PutSeparators( " \t" );
  98. if( !ArgLex.PrepareToParse() ) {
  99. DebugPrint( "ArgLex.PrepareToParse() failed \n" );
  100. _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
  101. _Message.Display( " " );
  102. return( FALSE );
  103. }
  104. if ( !ArgumentArray.Initialize() ) {
  105. DebugPrint( "ArgumentArray.Initialize() failed \n" );
  106. return( FALSE );
  107. }
  108. if( !ProgramNameArgument.Initialize("*") ||
  109. !_FlagRemoveSystemAttribute.Initialize( "-S" ) ||
  110. !_FlagAddSystemAttribute.Initialize( "+S" ) ||
  111. !_FlagRemoveHiddenAttribute.Initialize( "-H" ) ||
  112. !_FlagAddHiddenAttribute.Initialize( "+H" ) ||
  113. !_FlagRemoveReadOnlyAttribute.Initialize( "-R" ) ||
  114. !_FlagAddReadOnlyAttribute.Initialize( "+R" ) ||
  115. !_FlagRemoveArchiveAttribute.Initialize( "-A" ) ||
  116. !_FlagAddArchiveAttribute.Initialize( "+A" ) ||
  117. !_FlagRecurseDirectories.Initialize( "/S" ) ||
  118. !_FlagActOnDirectories.Initialize( "/D" ) ||
  119. !_FlagDisplayHelp.Initialize( "/?" ) ||
  120. !InvalidSwitch.Initialize( "/*" ) ||
  121. !InvalidSwitchPlus.Initialize( "+*" ) ||
  122. !InvalidSwitchMinus.Initialize( "-*" ) ||
  123. !_FileNameArgument.Initialize( "*" ) ) {
  124. DebugPrint( "Unable to initialize flag or string arguments \n" );
  125. return( FALSE );
  126. }
  127. if( !ArgumentArray.Put( &ProgramNameArgument ) ||
  128. !ArgumentArray.Put( &_FlagRemoveSystemAttribute ) ||
  129. !ArgumentArray.Put( &_FlagAddSystemAttribute ) ||
  130. !ArgumentArray.Put( &_FlagRemoveHiddenAttribute ) ||
  131. !ArgumentArray.Put( &_FlagAddHiddenAttribute ) ||
  132. !ArgumentArray.Put( &_FlagRemoveReadOnlyAttribute ) ||
  133. !ArgumentArray.Put( &_FlagAddReadOnlyAttribute ) ||
  134. !ArgumentArray.Put( &_FlagRemoveArchiveAttribute ) ||
  135. !ArgumentArray.Put( &_FlagAddArchiveAttribute ) ||
  136. !ArgumentArray.Put( &_FlagRecurseDirectories ) ||
  137. !ArgumentArray.Put( &_FlagActOnDirectories ) ||
  138. !ArgumentArray.Put( &_FlagDisplayHelp ) ||
  139. !ArgumentArray.Put( &InvalidSwitch ) ||
  140. !ArgumentArray.Put( &InvalidSwitchPlus ) ||
  141. !ArgumentArray.Put( &InvalidSwitchMinus ) ||
  142. !ArgumentArray.Put( &_FileNameArgument ) ) {
  143. DebugPrint( "ArgumentArray.Put() failed \n" );
  144. return( FALSE );
  145. }
  146. if( !ArgLex.DoParsing( &ArgumentArray ) ) {
  147. _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
  148. _Message.Display( " " );
  149. return( FALSE );
  150. }
  151. //
  152. // Check the existance of an invalid switch
  153. //
  154. if( InvalidSwitch.IsValueSet() ||
  155. InvalidSwitchPlus.IsValueSet() ||
  156. InvalidSwitchMinus.IsValueSet() ) {
  157. if( InvalidSwitch.IsValueSet() ) {
  158. //
  159. // The invalid switch starts with '/'
  160. //
  161. if( !InvalidSwitchString.Initialize( "/" ) ) {
  162. DebugPrint( "InvalidSwitchString.Initialize( / ) failed \n" );
  163. return( FALSE );
  164. }
  165. InvalidArgument = InvalidSwitch.GetString();
  166. DebugPtrAssert( InvalidArgument );
  167. } else if ( InvalidSwitchPlus.IsValueSet() ) {
  168. //
  169. // The invalid switch starts with '+'
  170. //
  171. if( !InvalidSwitchString.Initialize( "+" ) ) {
  172. DebugPrint( "InvalidSwitchString.Initialize( + ) failed \n" );
  173. return( FALSE );
  174. }
  175. InvalidArgument = InvalidSwitchPlus.GetString();
  176. DebugPtrAssert( InvalidArgument );
  177. } else {
  178. //
  179. // The invalid switch starts with '-'
  180. //
  181. if( !InvalidSwitchString.Initialize( "-" ) ) {
  182. DebugPrint( "InvalidSwitchString.Initialize( - ) failed \n" );
  183. return( FALSE );
  184. }
  185. InvalidArgument = InvalidSwitchMinus.GetString();
  186. DebugPtrAssert( InvalidArgument );
  187. }
  188. //
  189. // Display the error message followed by the invalid switch
  190. //
  191. if( !InvalidSwitchString.Strcat( InvalidArgument ) ) {
  192. DebugPrint( "InvalidSwitchString.Strcat( InvalidArgument ) failed \n" );
  193. return( FALSE );
  194. }
  195. _Message.Set( MSG_ATTRIB_INVALID_SWITCH );
  196. _Message.Display( "%W", &InvalidSwitchString );
  197. return( FALSE );
  198. }
  199. if ( _FlagActOnDirectories.QueryFlag() &&
  200. !_FlagRecurseDirectories.QueryFlag() ) {
  201. _Message.Set( MSG_ATTRIB_INVALID_COMBINATION );
  202. _Message.Display();
  203. return( FALSE );
  204. }
  205. //
  206. // +S -S or +H -H or +R -R or +A -A are not valid
  207. // combination of arguments
  208. //
  209. if( ( _FlagRemoveSystemAttribute.QueryFlag() &&
  210. _FlagAddSystemAttribute.QueryFlag() ) ||
  211. ( _FlagRemoveHiddenAttribute.QueryFlag() &&
  212. _FlagAddHiddenAttribute.QueryFlag() ) ||
  213. ( _FlagRemoveReadOnlyAttribute.QueryFlag() &&
  214. _FlagAddReadOnlyAttribute.QueryFlag() ) ||
  215. ( _FlagRemoveArchiveAttribute.QueryFlag() &&
  216. _FlagAddArchiveAttribute.QueryFlag() ) ) {
  217. _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
  218. _Message.Display( " " );
  219. return( FALSE );
  220. }
  221. if( _FlagRemoveSystemAttribute.QueryFlag() ||
  222. _FlagAddSystemAttribute.QueryFlag() ||
  223. _FlagRemoveHiddenAttribute.QueryFlag() ||
  224. _FlagAddHiddenAttribute.QueryFlag() ||
  225. _FlagRemoveReadOnlyAttribute.QueryFlag() ||
  226. _FlagAddReadOnlyAttribute.QueryFlag() ||
  227. _FlagRemoveArchiveAttribute.QueryFlag() ||
  228. _FlagAddArchiveAttribute.QueryFlag() ) {
  229. _PrintAttribInfo = FALSE;
  230. _ResetMask = (FSN_ATTRIBUTE)0xffffffff;
  231. if( _FlagRemoveSystemAttribute.QueryFlag() ) {
  232. _ResetMask &= ~FSN_ATTRIBUTE_SYSTEM;
  233. }
  234. if( _FlagRemoveHiddenAttribute.QueryFlag() ) {
  235. _ResetMask &= ~FSN_ATTRIBUTE_HIDDEN;
  236. }
  237. if( _FlagRemoveReadOnlyAttribute.QueryFlag() ) {
  238. _ResetMask &= ~FSN_ATTRIBUTE_READONLY;
  239. }
  240. if( _FlagRemoveArchiveAttribute.QueryFlag() ) {
  241. _ResetMask &= ~FSN_ATTRIBUTE_ARCHIVE;
  242. }
  243. _MakeMask = 0;
  244. if( _FlagAddSystemAttribute.QueryFlag() ) {
  245. _MakeMask |= FSN_ATTRIBUTE_SYSTEM;
  246. }
  247. if( _FlagAddHiddenAttribute.QueryFlag() ) {
  248. _MakeMask |= FSN_ATTRIBUTE_HIDDEN;
  249. }
  250. if( _FlagAddReadOnlyAttribute.QueryFlag() ) {
  251. _MakeMask |= FSN_ATTRIBUTE_READONLY;
  252. }
  253. if( _FlagAddArchiveAttribute.QueryFlag() ) {
  254. _MakeMask |= FSN_ATTRIBUTE_ARCHIVE;
  255. }
  256. } else {
  257. _PrintAttribInfo = TRUE;
  258. }
  259. //
  260. // Get filename
  261. //
  262. if( !_FileNameArgument.IsValueSet() ) {
  263. //
  264. // User didn't specify file name. Use *.* as default
  265. //
  266. FullFileNameString = NULL;
  267. if( !_FullFileNamePath.Initialize( (LPWSTR)L"*.*", TRUE ) ) {
  268. DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
  269. return( FALSE );
  270. }
  271. } else {
  272. //
  273. // Get name specified in the command line
  274. //
  275. FullFileNameString = _FileNameArgument.GetPath()->GetPathString();
  276. DebugPtrAssert( FullFileNameString );
  277. if( !_FullFileNamePath.Initialize( FullFileNameString, TRUE ) ) {
  278. DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
  279. return( FALSE );
  280. }
  281. }
  282. //
  283. // Get prefix and verify that it exists
  284. //
  285. if( ( DynSubDirectory = _FullFileNamePath.QueryPrefix() ) == NULL ) {
  286. DebugPrint( "_FullFileNamePath.QueryPrefix() failed \n" );
  287. return( FALSE );
  288. }
  289. if( !DirectoryNamePath.Initialize( DynSubDirectory ) ) {
  290. DELETE( DynSubDirectory );
  291. DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
  292. return( FALSE );
  293. }
  294. DELETE( DynSubDirectory );
  295. //
  296. // Have to test if DirectoryNamePath is a drive, and if it is
  297. // add \ to it otherwise it won't be able to find a file that is
  298. // in the root directory, if the current directory is not the root.
  299. //
  300. if( DirectoryNamePath.IsDrive() ) {
  301. if( !BackSlashString.Initialize( "\\" ) ) {
  302. DebugPrint( "BackSlashString.Initialize() failed \n" );
  303. return( FALSE );
  304. }
  305. TempPathString = DirectoryNamePath.GetPathString();
  306. DebugPtrAssert( TempPathString );
  307. if( !TempPathStringDrive.Initialize( TempPathString ) ) {
  308. DebugPrint( "TempPathStringDrive.Initialize() failed \n" );
  309. return( FALSE );
  310. }
  311. TempPathStringDrive.Strcat( &BackSlashString );
  312. if( !PathDrive.Initialize( &TempPathStringDrive ) ) {
  313. DebugPrint( "PathDrive.Initialize() failed \n" );
  314. return( FALSE );
  315. }
  316. if( !DirectoryNamePath.Initialize( &PathDrive ) ) {
  317. DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
  318. return( FALSE );
  319. }
  320. }
  321. if( ( _InitialDirectory = SYSTEM::QueryDirectory( &DirectoryNamePath ) ) == NULL ) {
  322. InvalidName = DirectoryNamePath.GetPathString();
  323. DebugPtrAssert( InvalidName );
  324. _Message.Set( MSG_ATTRIB_PATH_NOT_FOUND );
  325. _Message.Display( "%W", InvalidName );
  326. return( FALSE );
  327. }
  328. //
  329. // Initialize filter for directories
  330. //
  331. if( !_FsnFilterDirectory.Initialize() ) {
  332. DELETE( _InitialDirectory );
  333. DebugPrint( "_FsnFilterDirectory.Initialize() failed \n" );
  334. return( FALSE );
  335. }
  336. if( !_FsnFilterDirectory.SetFileName( "*.*" ) ) {
  337. DELETE( _InitialDirectory );
  338. DebugPrint( "_FsnFilterDirectory.SetFilename() failed \n" );
  339. return( FALSE );
  340. }
  341. if( !_FsnFilterDirectory.SetAttributes( FSN_ATTRIBUTE_DIRECTORY ) ) {
  342. DELETE( _InitialDirectory );
  343. DebugPrint( "_FsnFilterDirectory.SetAttributes() failed \n" );
  344. return( FALSE );
  345. }
  346. //
  347. // Get file name and initialize filter for files
  348. //
  349. if( ( DynSubFileName = _FullFileNamePath.QueryName() ) == NULL ) {
  350. if( _FileNameArgument.IsValueSet() ) {
  351. InvalidName = _FileNameArgument.GetPath()->GetPathString();
  352. } else {
  353. InvalidName = DirectoryNamePath.GetPathString();
  354. }
  355. DebugPtrAssert( InvalidName );
  356. _Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
  357. _Message.Display( "%W", InvalidName );
  358. DELETE( _InitialDirectory );
  359. return( FALSE );
  360. }
  361. //
  362. // Determine whether attrib should act on a directory.
  363. // It will do so only if the user specify a directory name that does
  364. // not contain the characters '*' or '?'.
  365. // Also, attrib will not act on directories if the switch /S is specified.
  366. //
  367. if( _FlagRecurseDirectories.QueryFlag() ||
  368. ( FullFileNameString == NULL ) ||
  369. ( FullFileNameString->Strchr( ( WCHAR )'*' ) != INVALID_CHNUM ) ||
  370. ( FullFileNameString->Strchr( ( WCHAR )'?' ) != INVALID_CHNUM ) ) {
  371. ActOnDirectory = _FlagActOnDirectories.QueryFlag();
  372. } else {
  373. ActOnDirectory = TRUE;
  374. }
  375. if( !_FsnFilterFile.Initialize() ) {
  376. DELETE( _InitialDirectory );
  377. DELETE( DynSubFileName );
  378. DebugPrint( "FsnFilter.Initialize() failed \n" );
  379. return( FALSE );
  380. }
  381. if( !_FsnFilterFile.SetFileName( DynSubFileName ) ) {
  382. DELETE( _InitialDirectory );
  383. DELETE( DynSubFileName );
  384. DebugPrint( "FsnFilter.SetFilename() failed \n" );
  385. return( FALSE );
  386. }
  387. if( !ActOnDirectory ) {
  388. if( !_FsnFilterFile.SetAttributes( 0, 0, FSN_ATTRIBUTE_DIRECTORY ) ) {
  389. DELETE( _InitialDirectory );
  390. DELETE( DynSubFileName );
  391. DebugPrint( "FsnFilter.SetAttributes() failed \n" );
  392. return( FALSE );
  393. }
  394. } else {
  395. if( !_FsnFilterFile.SetAttributes( 0, 0, 0 ) ) {
  396. DELETE( _InitialDirectory );
  397. DELETE( DynSubFileName );
  398. DebugPrint( "FsnFilter.SetAttributes() failed \n" );
  399. return( FALSE );
  400. }
  401. }
  402. DELETE( DynSubFileName );
  403. if( _FlagDisplayHelp.QueryFlag() ) {
  404. _Message.Set( MSG_ATTRIB_HELP_MESSAGE );
  405. _Message.Display( " " );
  406. return( FALSE );
  407. }
  408. _FoundFile = FALSE;
  409. LexArray.DeleteAllMembers();
  410. return( TRUE );
  411. }
  412. VOID
  413. ATTRIB::Terminate(
  414. )
  415. /*++
  416. Routine Description:
  417. Deletes objects created during initialization.
  418. Arguments:
  419. None.
  420. Return Value:
  421. None.
  422. --*/
  423. {
  424. if( _InitialDirectory != NULL ) {
  425. DELETE( _InitialDirectory );
  426. }
  427. }
  428. VOID
  429. ATTRIB::DisplayFileNotFoundMessage(
  430. )
  431. /*++
  432. Routine Description:
  433. Displays a message indicating that no file that meets the file filter
  434. criteria was found.
  435. Arguments:
  436. None.
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. PCWSTRING FileName;
  442. if( !_FoundFile ) {
  443. if( _FileNameArgument.IsValueSet() ) {
  444. FileName = _FileNameArgument.GetPath()->GetPathString();
  445. } else {
  446. FileName = _FullFileNamePath.GetPathString();
  447. }
  448. DebugPtrAssert( FileName );
  449. _Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
  450. _Message.Display( "%W", FileName );
  451. }
  452. }
  453. VOID
  454. ATTRIB::DisplayFileAttribute (
  455. IN PCFSNODE Fsn
  456. )
  457. /*++
  458. Routine Description:
  459. Displays a filename and its attributes
  460. Arguments:
  461. Fsn - A pointer to an FSNODE that contains the information
  462. about the file.
  463. Return Value:
  464. None.
  465. --*/
  466. {
  467. // PCWC_STRING pcWcString;
  468. PCWSTRING pcWcString;
  469. WCHAR Buffer[ 12 ];
  470. DSTRING String;
  471. DebugPtrAssert( Fsn );
  472. DebugPtrAssert( Fsn->GetPath( ));
  473. pcWcString = ( Fsn->GetPath( ))->GetPathString( );
  474. DebugPtrAssert( pcWcString );
  475. swprintf( Buffer,
  476. ( LPWSTR )L"%lc %lc%lc%lc ",
  477. Fsn->IsArchived() ? ( WCHAR )'A' : ( WCHAR )' ',
  478. Fsn->IsSystem() ? ( WCHAR )'S' : ( WCHAR )' ',
  479. Fsn->IsHidden() ? ( WCHAR )'H' : ( WCHAR )' ',
  480. Fsn->IsReadOnly() ? ( WCHAR )'R' : ( WCHAR )' ' );
  481. if( !String.Initialize( Buffer ) ||
  482. !String.Strcat( pcWcString ) ||
  483. !String.Strcat( &_EndOfLineString ) ||
  484. !_OutStream->WriteString( &String ) ) {
  485. DebugPrint( "Unable to display message" );
  486. }
  487. }
  488. BOOLEAN
  489. ATTRIB::ChangeFileAttributes(
  490. IN PFSNODE FsnFile
  491. )
  492. /*++
  493. Routine Description:
  494. Changes the file attributes. The attributes will be changed depending
  495. on the argumets specified in the command line, and on the current
  496. attributes of the file.
  497. The algorithm for changing attributes is presented below:
  498. if( ( -s and -h were specified as arguments ) or
  499. ( -s and +h were specified as arguments ) or
  500. ( +s and -h were specified as arguments ) or
  501. ( +s and +h were specified as arguments ) ) {
  502. Change file attributes;
  503. } else if ( ( -h and +h were not specified as arguments ) and
  504. ( file has hidden attribute ) ) {
  505. print( "Not resetting hidden file: <filename> " );
  506. } else if ( ( -s and +s were not specified as arguments ) and
  507. ( file has system attribute ) ) {
  508. print( "Not resetting system file: <filename> " );
  509. } else {
  510. Change file attributes;
  511. }
  512. Arguments:
  513. FsnFile - A pointer to an FSNODE that contains the information
  514. about the file.
  515. Return Value:
  516. BOOLEAN - Returns FALSE if this function fails due to a failure
  517. in an API call.
  518. --*/
  519. {
  520. // BOOLEAN Result;
  521. BOOLEAN Change;
  522. DWORD Win32Error;
  523. // PCWC_STRING pcWcString;
  524. PCWSTRING pcWcString;
  525. FSN_ATTRIBUTE Attributes;
  526. DebugPtrAssert( FsnFile->GetPath( ));
  527. pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
  528. DebugPtrAssert( pcWcString );
  529. if( ( ( _FlagAddSystemAttribute.QueryFlag() ||
  530. _FlagRemoveSystemAttribute.QueryFlag() ) &&
  531. ( _FlagAddHiddenAttribute.QueryFlag() ||
  532. _FlagRemoveHiddenAttribute.QueryFlag() ) ) ) {
  533. Change = TRUE;
  534. } else if( !_FlagAddHiddenAttribute.QueryFlag() &&
  535. !_FlagRemoveHiddenAttribute.QueryFlag() &&
  536. FsnFile->IsHidden() ) {
  537. // DebugPtrAssert( FsnFile->GetPath( ));
  538. // pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
  539. // DebugPtrAssert( pcWcString );
  540. _Message.Set( MSG_ATTRIB_NOT_RESETTING_HIDDEN_FILE );
  541. _Message.Display( "%W", pcWcString );
  542. Change = FALSE;
  543. } else if( !_FlagAddSystemAttribute.QueryFlag() &&
  544. !_FlagRemoveSystemAttribute.QueryFlag() &&
  545. FsnFile->IsSystem() ) {
  546. // DebugPtrAssert( FsnFile->GetPath( ));
  547. // pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
  548. // DebugPtrAssert( pcWcString );
  549. _Message.Set( MSG_ATTRIB_NOT_RESETTING_SYS_FILE );
  550. _Message.Display( "%W", pcWcString );
  551. Change = FALSE;
  552. } else {
  553. Change = TRUE;
  554. }
  555. // Result = TRUE;
  556. if( Change ) {
  557. Attributes = FsnFile->QueryAttributes();
  558. if( !FsnFile->SetAttributes( ( Attributes & _ResetMask ) | _MakeMask,
  559. &Win32Error ) ) {
  560. if( Win32Error == ERROR_ACCESS_DENIED ) {
  561. _Message.Set( MSG_ATTRIB_ACCESS_DENIED );
  562. } else {
  563. _Message.Set( MSG_ATTRIB_UNABLE_TO_CHANGE_ATTRIBUTE );
  564. }
  565. _Message.Display( "%W", pcWcString );
  566. DebugPrint( "Unable to change file attribute \n" );
  567. return( FALSE );
  568. }
  569. }
  570. return( TRUE );
  571. }
  572. BOOLEAN
  573. ATTRIB::ExamineFiles(
  574. IN PFSN_DIRECTORY Directory
  575. )
  576. /*++
  577. Routine Description:
  578. Builds an array of files in the specified directory, and
  579. tries to change the attributes of each of these files.
  580. Does the same thing in all subdirectories, if the "recurse"
  581. flag was specified in the command line.
  582. Arguments:
  583. Directory - Pointer to an FSN_DIRECTORY that describes the
  584. directory to be examined
  585. Return Value:
  586. Boolean: TRUE if Successful.
  587. --*/
  588. {
  589. PARRAY DirectoryArray;
  590. PFSN_DIRECTORY FsnDirectory;
  591. PARRAY_ITERATOR DirectoryArrayIterator;
  592. PARRAY FileArray;
  593. PARRAY_ITERATOR FileArrayIterator;
  594. PFSNODE FsnFile;
  595. DebugPtrAssert( Directory );
  596. //
  597. // If /S was specified as argument in the command line, builds
  598. // an array of PFSN_DIRECTORY of all sub-directories in the current
  599. // directory and examines the files in each sub-directory
  600. //
  601. if( _FlagRecurseDirectories.QueryFlag() ) {
  602. if( ( DirectoryArray = Directory->QueryFsnodeArray( &_FsnFilterDirectory ) ) == NULL ) {
  603. DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterDirectory ) failed \n" );
  604. return( FALSE );
  605. }
  606. if( ( DirectoryArrayIterator =
  607. ( PARRAY_ITERATOR )( DirectoryArray->QueryIterator() ) ) == NULL ) {
  608. DebugPrint( "DirectoryArray->QueryIterator() failed \n" );
  609. return( FALSE );
  610. }
  611. while( ( FsnDirectory = ( PFSN_DIRECTORY )( DirectoryArrayIterator->GetNext( ) ) ) != NULL ) {
  612. ExamineFiles( FsnDirectory );
  613. DELETE( FsnDirectory );
  614. }
  615. DELETE( DirectoryArrayIterator );
  616. DELETE( DirectoryArray );
  617. }
  618. //
  619. // Builds an array of FSNODEs of the files tha meet the 'filter'
  620. // criteria, and change or display the attributes of these files
  621. //
  622. if( ( FileArray = Directory->QueryFsnodeArray( &_FsnFilterFile ) ) == NULL ) {
  623. DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterFile ) failed \n" );
  624. return( FALSE );
  625. }
  626. if( ( FileArrayIterator =
  627. ( PARRAY_ITERATOR )( FileArray->QueryIterator() ) ) == NULL ) {
  628. DebugPrint( "FileArray->QueryIterator() failed \n" );
  629. return( FALSE );
  630. }
  631. while( ( FsnFile = ( PFSNODE )( FileArrayIterator->GetNext( ) ) ) != NULL ) {
  632. if( _PrintAttribInfo ) {
  633. DisplayFileAttribute( FsnFile );
  634. } else {
  635. ChangeFileAttributes( FsnFile );
  636. }
  637. _FoundFile = TRUE;
  638. DELETE( FsnFile );
  639. }
  640. DELETE( FileArrayIterator );
  641. DELETE( FileArray );
  642. return( TRUE );
  643. }
  644. ULONG __cdecl
  645. main()
  646. {
  647. DEFINE_CLASS_DESCRIPTOR( ATTRIB );
  648. {
  649. ATTRIB Attrib;
  650. if( Attrib.Initialize() ) {
  651. Attrib.ExamineFiles( Attrib.GetInitialDirectory() );
  652. Attrib.DisplayFileNotFoundMessage();
  653. }
  654. Attrib.Terminate();
  655. }
  656. return( 0 );
  657. }