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.

772 lines
22 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. exclproc.cpp
  5. Abstract:
  6. Exclude processing mechanism. Processes the FilesNotToBackup key and
  7. zero or more exclude files with exclude rules.
  8. Author:
  9. Stefan R. Steiner [ssteiner] 03-21-2000
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #include "match.h"
  14. #include <shlobj.h>
  15. static VOID
  16. FsdExpandEnvironmentStrings(
  17. IN LPCWSTR pwszInput,
  18. OUT CBsString &cwsExpandedStr
  19. );
  20. static BOOL
  21. FsdEnsureLongNames(
  22. IN OUT CBsString& exclude_spec
  23. );
  24. SFsdExcludeRule::~SFsdExcludeRule()
  25. {
  26. delete( psVolId );
  27. psVolId = NULL;
  28. }
  29. /*++
  30. Routine Description:
  31. Prints out information about one rule. If the rule caused files to be excluded
  32. it prints out those file too.
  33. Arguments:
  34. Return Value:
  35. <Enter return values here>
  36. --*/
  37. VOID
  38. SFsdExcludeRule::PrintRule(
  39. IN FILE *fpOut,
  40. IN BOOL bInvalidRulePrint
  41. )
  42. {
  43. if ( bInvalidRulePrint )
  44. {
  45. if ( bInvalidRule )
  46. fwprintf( fpOut, L"%-24s %-32s '%s'\n",
  47. cwsExcludeFromSource.c_str(), cwsExcludeDescription.c_str(), cwsExcludeRule.c_str() );
  48. }
  49. else
  50. {
  51. //
  52. // Iterate though excluded file list
  53. //
  54. CBsString cwsExcludedFile;
  55. CVssDLListIterator< CBsString > cExcludedFilesIter( cExcludedFileList );
  56. if ( cExcludedFilesIter.GetNext( cwsExcludedFile ) )
  57. {
  58. //
  59. // At least one file excluded, print the header for the rule
  60. //
  61. fwprintf( fpOut, L"%-24s %-32s '%s'\n",
  62. cwsExcludeFromSource.c_str(), cwsExcludeDescription.c_str(), cwsExcludeRule.c_str() );
  63. //
  64. // Now iterate
  65. //
  66. do
  67. {
  68. fwprintf( fpOut, L"\t%s\n", cwsExcludedFile.c_str() );
  69. } while( cExcludedFilesIter.GetNext( cwsExcludedFile ) );
  70. }
  71. }
  72. }
  73. CFsdExclusionManager::CFsdExclusionManager(
  74. IN CDumpParameters *pcDumpParameters
  75. ) : m_pcParams( pcDumpParameters )
  76. {
  77. if ( !m_pcParams->m_bDontUseRegistryExcludes )
  78. {
  79. ProcessRegistryExcludes( HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" );
  80. ProcessRegistryExcludes( HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" );
  81. }
  82. CBsString cwsEXEFileStreamExcludeFile( m_pcParams->m_cwsArgv0 + L":ExcludeList" );
  83. if ( ProcessOneExcludeFile( cwsEXEFileStreamExcludeFile ) == FALSE )
  84. m_pcParams->DumpPrint( L" NOTE: Exclude file: '%s' not found",
  85. cwsEXEFileStreamExcludeFile.c_str() );
  86. ProcessExcludeFiles( m_pcParams->m_cwsFullPathToEXE );
  87. CompileExclusionRules();
  88. }
  89. CFsdExclusionManager::~CFsdExclusionManager()
  90. {
  91. SFsdExcludeRule *pER;
  92. //
  93. // Iterate through the exclude rule list and delete each element
  94. //
  95. CVssDLListIterator< SFsdExcludeRule * > cExclRuleIter( m_cCompleteExcludeList );
  96. while( cExclRuleIter.GetNext( pER ) )
  97. delete pER;
  98. }
  99. VOID
  100. CFsdExclusionManager::ProcessRegistryExcludes(
  101. IN HKEY hKey,
  102. IN LPCWSTR pwszFromSource
  103. )
  104. {
  105. LPWSTR buffer ;
  106. HKEY key = NULL ;
  107. DWORD stat ;
  108. DWORD dwDisposition ;
  109. DWORD dwDataSize;
  110. DWORD dwIndex = 0;
  111. HRESULT hr = S_OK;
  112. m_pcParams->DumpPrint( L" Processing FilesNotToBackup reg key in %s", pwszFromSource );
  113. buffer = new WCHAR[ FSD_MAX_PATH ];
  114. if ( buffer == NULL )
  115. throw E_OUTOFMEMORY;
  116. try
  117. {
  118. stat = ::RegOpenKeyEx( hKey,
  119. FSD_REG_EXCLUDE_PATH,
  120. 0,
  121. KEY_READ,
  122. &key ) ;
  123. dwIndex = 0 ;
  124. while ( stat == ERROR_SUCCESS )
  125. {
  126. WCHAR pwszValue[ MAX_PATH ];
  127. DWORD dwValSize = MAX_PATH; // prefix #118830
  128. DWORD dwType;
  129. dwDataSize = FSD_MAX_PATH; // prefix #118830
  130. stat = ::RegEnumValueW( key,
  131. dwIndex,
  132. pwszValue,
  133. &dwValSize,
  134. NULL,
  135. &dwType,
  136. (LPBYTE)buffer,
  137. &dwDataSize ) ;
  138. dwIndex++;
  139. if ( ( stat == ERROR_SUCCESS ) && ( dwType == REG_MULTI_SZ ) )
  140. {
  141. LPWSTR p = buffer;
  142. while ( *p )
  143. {
  144. SFsdExcludeRule *psExclRule;
  145. //
  146. // Now load up the exclude rule with the unprocessed
  147. // information
  148. //
  149. psExclRule = new SFsdExcludeRule;
  150. if ( psExclRule == NULL )
  151. throw E_OUTOFMEMORY;
  152. psExclRule->cwsExcludeFromSource = pwszFromSource;
  153. psExclRule->cwsExcludeDescription = pwszValue;
  154. psExclRule->cwsExcludeRule = p;
  155. if ( m_pcParams->m_bPrintDebugInfo || m_pcParams->m_bNoHeaderFooter )
  156. {
  157. m_pcParams->DumpPrint( L" \"%s\" \"%s\"",
  158. pwszValue, p );
  159. }
  160. m_cCompleteExcludeList.AddTail( psExclRule );
  161. p += ::wcslen( p ) + 1;
  162. }
  163. }
  164. }
  165. }
  166. catch ( HRESULT hrCaught )
  167. {
  168. hr = hrCaught;
  169. }
  170. catch ( ... )
  171. {
  172. hr = E_UNEXPECTED;
  173. }
  174. if ( key != NULL )
  175. {
  176. ::RegCloseKey( key ) ;
  177. key = NULL ;
  178. }
  179. delete [] buffer ;
  180. if ( FAILED( hr ) )
  181. throw hr;
  182. }
  183. VOID
  184. CFsdExclusionManager::ProcessExcludeFiles(
  185. IN const CBsString& cwsPathToExcludeFiles
  186. )
  187. {
  188. HANDLE hFind = INVALID_HANDLE_VALUE;
  189. try
  190. {
  191. //
  192. // Iterate through all files in the directory looking for
  193. // files with .exclude extensions
  194. //
  195. DWORD dwRet;
  196. WIN32_FIND_DATAW sFindData;
  197. hFind = ::FindFirstFileExW(
  198. cwsPathToExcludeFiles + L"*.exclude",
  199. FindExInfoStandard,
  200. &sFindData,
  201. FindExSearchNameMatch,
  202. NULL,
  203. 0 );
  204. if ( hFind == INVALID_HANDLE_VALUE )
  205. {
  206. dwRet = ::GetLastError();
  207. if ( dwRet == ERROR_NO_MORE_FILES || dwRet == ERROR_FILE_NOT_FOUND )
  208. return;
  209. else
  210. {
  211. m_pcParams->ErrPrint( L"CFsdExclusionManager::ProcessExcludeFiles - FindFirstFileEx( '%s' ) returned: dwRet: %d, skipping looking for .exclude files",
  212. cwsPathToExcludeFiles.c_str(), ::GetLastError() );
  213. return;
  214. }
  215. }
  216. //
  217. // Now run through the directory
  218. //
  219. do
  220. {
  221. // Check and make sure the file such as ".", ".." and dirs are not considered
  222. if( ::wcscmp( sFindData.cFileName, L".") != 0 &&
  223. ::wcscmp( sFindData.cFileName, L"..") != 0 &&
  224. !( sFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  225. {
  226. ProcessOneExcludeFile( cwsPathToExcludeFiles + sFindData.cFileName );
  227. }
  228. } while ( ::FindNextFile( hFind, &sFindData ) );
  229. }
  230. catch ( ... )
  231. {
  232. m_pcParams->ErrPrint( L"CFsdExclusionManager::ProcessExcludeFiles: Caught an unknown exception, dirPath: '%s'", cwsPathToExcludeFiles.c_str() );
  233. }
  234. if ( hFind != INVALID_HANDLE_VALUE )
  235. ::FindClose( hFind );
  236. }
  237. BOOL
  238. CFsdExclusionManager::ProcessOneExcludeFile(
  239. IN const CBsString& cwsExcludeFileName
  240. )
  241. {
  242. FILE *fpExclFile;
  243. fpExclFile = ::_wfopen( cwsExcludeFileName, L"r" );
  244. if ( fpExclFile == NULL )
  245. {
  246. return FALSE;
  247. }
  248. m_pcParams->DumpPrint( L" Processing exclude file: '%s'", cwsExcludeFileName.c_str() );
  249. CBsString cwsInputLine;
  250. while( ::fgetws( cwsInputLine.GetBuffer( FSD_MAX_PATH), FSD_MAX_PATH, fpExclFile ) )
  251. {
  252. cwsInputLine.ReleaseBuffer();
  253. cwsInputLine = cwsInputLine.Left( cwsInputLine.GetLength() - 1 ); // get rid of '\n'
  254. cwsInputLine.TrimLeft();
  255. cwsInputLine.TrimRight();
  256. //
  257. // See if it is a comment, either // or #
  258. //
  259. if ( cwsInputLine[ 0 ] == L'#' || cwsInputLine.Left( 2 ) == L"//"
  260. || cwsInputLine.IsEmpty() )
  261. continue;
  262. if ( m_pcParams->m_bPrintDebugInfo || m_pcParams->m_bNoHeaderFooter )
  263. {
  264. m_pcParams->DumpPrint( L" %s", cwsInputLine.c_str() );
  265. }
  266. CBsString cwsLine( cwsInputLine );
  267. SFsdExcludeRule *psExclRule;
  268. psExclRule = new SFsdExcludeRule;
  269. if ( psExclRule == NULL )
  270. {
  271. ::fclose( fpExclFile );
  272. throw E_OUTOFMEMORY;
  273. }
  274. INT iLeft;
  275. INT iRight;
  276. //
  277. // This is gross. With the updated string class, this can
  278. // be simplified.
  279. //
  280. iLeft = cwsLine.Find( L'\"' );
  281. if ( iLeft != -1 )
  282. {
  283. cwsLine = cwsLine.Mid( iLeft + 1 );
  284. iRight = cwsLine.Find( L'\"' );
  285. if ( iRight != -1 )
  286. {
  287. psExclRule->cwsExcludeDescription = cwsLine.Left( iRight );
  288. cwsLine = cwsLine.Mid( iRight + 1 );
  289. iLeft = cwsLine.Find( L'\"' );
  290. if ( iLeft != -1 )
  291. {
  292. cwsLine = cwsLine.Mid( iLeft + 1 );
  293. iRight = cwsLine.Find( L'\"' );
  294. if ( iRight != -1 )
  295. {
  296. psExclRule->cwsExcludeRule = cwsLine.Left( iRight );
  297. psExclRule->cwsExcludeFromSource = cwsExcludeFileName.c_str() + cwsExcludeFileName.ReverseFind( L'\\' ) + 1;
  298. m_cCompleteExcludeList.AddTail( psExclRule );
  299. continue;
  300. }
  301. }
  302. }
  303. }
  304. else
  305. {
  306. m_pcParams->ErrPrint( L"Parse error in exclusion rule file '%s', rule text '%s', skipping",
  307. cwsExcludeFileName.c_str(), cwsInputLine.c_str() );
  308. }
  309. delete psExclRule;
  310. }
  311. ::fclose( fpExclFile );
  312. return TRUE;
  313. }
  314. VOID
  315. CFsdExclusionManager::CompileExclusionRules()
  316. {
  317. SFsdExcludeRule *psER;
  318. //
  319. // Iterate through the exclude rule list and compile each rule
  320. //
  321. CVssDLListIterator< SFsdExcludeRule * > cExclRuleIter( m_cCompleteExcludeList );
  322. CBsString cws;
  323. if ( m_pcParams->m_bPrintDebugInfo )
  324. wprintf( L"Exclusion rule debug info:\n" );
  325. while( cExclRuleIter.GetNext( psER ) )
  326. {
  327. INT i;
  328. ::FsdExpandEnvironmentStrings( psER->cwsExcludeRule, cws );
  329. if ( m_pcParams->m_bPrintDebugInfo )
  330. {
  331. wprintf( L"\t%s : %s : %s : %s", psER->cwsExcludeFromSource.c_str(),
  332. psER->cwsExcludeDescription.c_str(), psER->cwsExcludeRule.c_str(),
  333. cws.c_str() );
  334. }
  335. //
  336. // Get rid of leading spaces and lower case the whole mess
  337. //
  338. cws.TrimLeft();
  339. cws.MakeUpper();
  340. //
  341. // First see if /s is at end of string
  342. //
  343. i = cws.Find( L"/S" );
  344. if ( i > 0 )
  345. {
  346. cws = cws.Left( i );
  347. psER->bInclSubDirs = TRUE;
  348. }
  349. cws.TrimRight();
  350. //
  351. // Now see if there are any wildcards
  352. //
  353. i = cws.FindOneOf( L"*?" );
  354. if ( i != -1 )
  355. {
  356. psER->bWCInFileName = TRUE;
  357. }
  358. //
  359. // Now see if this is for any volume
  360. //
  361. if ( cws.GetLength() >= 2 && cws[0] == L'\\' && cws[1] != L'\\' )
  362. psER->bAnyVol = TRUE;
  363. else if ( cws.GetLength() >= 2 && cws[1] != L':' )
  364. psER->bAnyVol = TRUE;
  365. if ( psER->bAnyVol )
  366. {
  367. if ( cws[0] == L'\\' )
  368. {
  369. // Get rid of first '\'
  370. cws = cws.Mid( 1 );
  371. }
  372. }
  373. else
  374. {
  375. //
  376. // Specific volume case
  377. //
  378. CBsString cwsVolPath;
  379. psER->psVolId = new SFsdVolumeId;
  380. if ( psER->psVolId == NULL ) // Prefix 118832
  381. {
  382. m_pcParams->ErrPrint( L"CFsdExclusionManager::CompileExclusionRules - out of memory" );
  383. throw E_OUTOFMEMORY; // Prefix #118832
  384. }
  385. if ( CFsdVolumeStateManager::GetVolumeIdAndPath( m_pcParams, cws, psER->psVolId, cwsVolPath ) != ERROR_SUCCESS )
  386. psER->bInvalidRule = TRUE;
  387. else
  388. {
  389. //
  390. // Slice off the volume part of the path
  391. //
  392. cws = cws.Mid( cwsVolPath.GetLength() );
  393. }
  394. }
  395. INT iFileNameOffset;
  396. iFileNameOffset = cws.ReverseFind( L'\\' );
  397. if ( iFileNameOffset == -1 )
  398. {
  399. //
  400. // No dirpath
  401. //
  402. // psER->cwsDirPath = L"\\";
  403. psER->cwsFileNamePattern = cws;
  404. }
  405. else
  406. {
  407. psER->cwsFileNamePattern = cws.Mid( iFileNameOffset + 1 );
  408. psER->cwsDirPath = cws.Left( iFileNameOffset + 1 );
  409. }
  410. //
  411. // Now convert the file name pattern into a form that the pattern matcher
  412. // can use.
  413. //
  414. ::FsdRtlConvertWildCards( psER->cwsFileNamePattern );
  415. if ( m_pcParams->m_bPrintDebugInfo )
  416. {
  417. if ( psER->bInclSubDirs )
  418. wprintf( L" - SubDir" );
  419. if ( psER->bWCInFileName )
  420. wprintf( L" - WC" );
  421. if ( psER->bAnyVol )
  422. wprintf( L" - AnyVol" );
  423. wprintf( L" - VolId: 0x%08x, DirPath: '%s', FileName: '%s'",
  424. ( psER->psVolId ) ? psER->psVolId->m_dwVolSerialNumber : 0xFFFFFFFF,
  425. psER->cwsDirPath.c_str(), psER->cwsFileNamePattern.c_str() );
  426. if ( psER->bInvalidRule )
  427. wprintf( L" - ERROR, invalid rule" );
  428. wprintf( L"\n" );
  429. }
  430. }
  431. }
  432. VOID
  433. CFsdExclusionManager::GetFileSystemExcludeProcessor(
  434. IN CBsString cwsVolumePath,
  435. IN SFsdVolumeId *psVolId,
  436. OUT CFsdFileSystemExcludeProcessor **ppcFSExcludeProcessor
  437. )
  438. {
  439. CFsdFileSystemExcludeProcessor *pExclProc;
  440. *ppcFSExcludeProcessor = NULL;
  441. //
  442. // Get a new exclude processor for the file system
  443. //
  444. pExclProc = new CFsdFileSystemExcludeProcessor( m_pcParams, cwsVolumePath, psVolId );
  445. if ( pExclProc == NULL )
  446. {
  447. m_pcParams->ErrPrint( L"CFsdExclusionManager::CFsdGetFileSystemExcludeProcessor - Could not new a CFsdFileSystemExcludeProcessor object" );
  448. throw E_OUTOFMEMORY;
  449. }
  450. SFsdExcludeRule *pER;
  451. //
  452. // Now go through the complete exclude list to find exclude rules that are relevant to
  453. // this file system
  454. //
  455. CVssDLListIterator< SFsdExcludeRule * > cExclRuleIter( m_cCompleteExcludeList );
  456. while( cExclRuleIter.GetNext( pER ) )
  457. {
  458. if ( !pER->bInvalidRule )
  459. {
  460. if ( pER->bAnyVol || pER->psVolId->IsEqual( psVolId ) )
  461. {
  462. pExclProc->m_cFSExcludeList.AddTail( pER );
  463. }
  464. }
  465. }
  466. *ppcFSExcludeProcessor = pExclProc;
  467. }
  468. /*++
  469. Routine Description:
  470. Goes through the list of exclusion rules and dumps information about each.
  471. Arguments:
  472. Return Value:
  473. <Enter return values here>
  474. --*/
  475. VOID
  476. CFsdExclusionManager::PrintExclusionInformation()
  477. {
  478. SFsdExcludeRule *pER;
  479. CVssDLListIterator< SFsdExcludeRule * > cExclRuleIter( m_cCompleteExcludeList );
  480. m_pcParams->DumpPrint( L"" );
  481. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  482. m_pcParams->DumpPrint( L"Invalid exclusion rules (invalid because volume not found or parsing error)" );
  483. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  484. m_pcParams->DumpPrint( L"From Application Exclusion rule" );
  485. while( cExclRuleIter.GetNext( pER ) )
  486. pER->PrintRule( m_pcParams->GetDumpFile(), TRUE );
  487. m_pcParams->DumpPrint( L"" );
  488. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  489. m_pcParams->DumpPrint( L"Files excluded by valid exclusion rule" );
  490. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  491. m_pcParams->DumpPrint( L"From Application Exclusion rule" );
  492. cExclRuleIter.Reset();
  493. while( cExclRuleIter.GetNext( pER ) )
  494. pER->PrintRule( m_pcParams->GetDumpFile(), FALSE );
  495. }
  496. CFsdFileSystemExcludeProcessor::CFsdFileSystemExcludeProcessor(
  497. IN CDumpParameters *pcDumpParameters,
  498. IN const CBsString& cwsVolumePath,
  499. IN SFsdVolumeId *psVolId
  500. ) : m_pcParams( pcDumpParameters ),
  501. m_cwsVolumePath( cwsVolumePath),
  502. m_psVolId( NULL )
  503. {
  504. m_psVolId = new SFsdVolumeId;
  505. if ( m_psVolId == NULL ) // Prefix #118829
  506. throw E_OUTOFMEMORY;
  507. *m_psVolId = *psVolId;
  508. }
  509. CFsdFileSystemExcludeProcessor::~CFsdFileSystemExcludeProcessor()
  510. {
  511. delete m_psVolId;
  512. }
  513. BOOL
  514. CFsdFileSystemExcludeProcessor::IsExcludedFile(
  515. IN const CBsString &cwsFullDirPath,
  516. IN DWORD dwEndOfVolMountPointOffset,
  517. IN const CBsString &cwsFileName
  518. )
  519. {
  520. BOOL bFoundMatch = FALSE;
  521. SFsdExcludeRule *pER;
  522. CBsString cwsUpperFileName( cwsFileName );
  523. CBsString cwsDirPath( cwsFullDirPath.Mid( dwEndOfVolMountPointOffset ) );
  524. cwsUpperFileName.MakeUpper(); // Make uppercased for match check
  525. cwsDirPath.MakeUpper();
  526. // wprintf( L"Exclude proc: DirPath: %s, fileName: %s\n", cwsDirPath.c_str(), cwsUpperFileName.c_str() );
  527. CVssDLListIterator< SFsdExcludeRule * > cExclRuleIter( m_cFSExcludeList );
  528. while( !bFoundMatch && cExclRuleIter.GetNext( pER ) )
  529. {
  530. if ( pER->bInclSubDirs )
  531. {
  532. //
  533. // First check most common case \XXX /s
  534. //
  535. if ( pER->cwsDirPath.GetLength() != 0 )
  536. {
  537. if ( ::wcsncmp( pER->cwsDirPath.c_str(), cwsDirPath.c_str(), pER->cwsDirPath.GetLength() ) != 0 )
  538. continue;
  539. }
  540. }
  541. else
  542. {
  543. //
  544. // Fixed path check
  545. //
  546. if ( pER->cwsDirPath != cwsDirPath )
  547. {
  548. continue;
  549. }
  550. }
  551. if ( pER->bWCInFileName )
  552. {
  553. //
  554. // Pattern match check
  555. //
  556. if ( ::FsdRtlIsNameInExpression( pER->cwsFileNamePattern, cwsUpperFileName ) )
  557. bFoundMatch = TRUE;
  558. }
  559. else
  560. {
  561. //
  562. // Constant string match
  563. //
  564. if ( pER->cwsFileNamePattern == cwsUpperFileName )
  565. bFoundMatch = TRUE;
  566. }
  567. }
  568. if ( bFoundMatch )
  569. {
  570. pER->cExcludedFileList.AddTail( cwsFullDirPath + cwsFileName );
  571. if ( m_pcParams->m_bPrintDebugInfo )
  572. wprintf( L" EXCLUDING: %s%s\n", cwsFullDirPath.c_str(), cwsFileName.c_str() );
  573. }
  574. return bFoundMatch;
  575. }
  576. static VOID
  577. FsdExpandEnvironmentStrings(
  578. IN LPCWSTR pwszInput,
  579. OUT CBsString &cwsExpandedStr
  580. )
  581. {
  582. BOOL isOK = FALSE;
  583. LPWSTR pwszBuffer;
  584. DWORD dwSize = ::ExpandEnvironmentStringsW( pwszInput, NULL, 0 ) ;
  585. if ( pwszBuffer = cwsExpandedStr.GetBufferSetLength( dwSize + 1 ) )
  586. {
  587. isOK = ( 0 != ::ExpandEnvironmentStringsW( pwszInput, pwszBuffer, dwSize ) ) ;
  588. cwsExpandedStr.ReleaseBuffer( ) ;
  589. }
  590. if ( !isOK )
  591. {
  592. // have never seen ExpandEnvironmentStrings fail... even with undefined env var... but just in case
  593. cwsExpandedStr = pwszInput ;
  594. }
  595. ::FsdEnsureLongNames( cwsExpandedStr );
  596. }
  597. /*++
  598. Routine Description:
  599. Originally from NtBackup.
  600. This takes a path with short name components and expands them to long
  601. name components. The path obviously has to exist on the system to expand
  602. short names.
  603. Uses a little shell magic (yuck) to translate it into a long name.
  604. Arguments:
  605. Return Value:
  606. TRUE if expanded properly
  607. --*/
  608. static BOOL
  609. FsdEnsureLongNames(
  610. IN OUT CBsString& exclude_spec
  611. )
  612. {
  613. IShellFolder * desktop ;
  614. ITEMIDLIST * id_list ;
  615. ULONG parsed_ct = 0 ;
  616. BOOL isOK = FALSE ; // initialize it, prefix bug # 180281
  617. CBsString path ;
  618. int last_slash ;
  619. // strip off the filename, and all that other detritus...
  620. path = exclude_spec ;
  621. if ( -1 != ( last_slash = path.ReverseFind( TEXT( '\\' ) ) ) )
  622. {
  623. path = path.Left( last_slash ) ;
  624. if ( SUCCEEDED( SHGetDesktopFolder( &desktop ) ) )
  625. {
  626. WCHAR * ptr = path.GetBufferSetLength( FSD_MAX_PATH ) ;
  627. if ( SUCCEEDED( desktop->ParseDisplayName( NULL, NULL, ptr, &parsed_ct, &id_list, NULL ) ) )
  628. {
  629. IMalloc * imalloc ;
  630. isOK = SHGetPathFromIDList( id_list, ptr ) ;
  631. SHGetMalloc( &imalloc ) ;
  632. imalloc->Free( id_list ) ;
  633. imalloc->Release( ) ;
  634. }
  635. path.ReleaseBuffer( ) ;
  636. desktop->Release( ) ;
  637. }
  638. if ( isOK )
  639. {
  640. // put it back together with the new & improved path...
  641. exclude_spec = path + exclude_spec.Mid( last_slash ) ;
  642. }
  643. }
  644. return isOK;
  645. }