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.

581 lines
23 KiB

  1. /*****************************************************************************************************************
  2. FILENAME: Exclude.cpp
  3. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  4. DESCRIPTION: Handles exclusion of files.
  5. */
  6. #include "stdafx.h"
  7. #include<nt.h>
  8. #include<ntrtl.h>
  9. #include<nturtl.h>
  10. #include <windows.h>
  11. extern "C" {
  12. #include "SysStruc.h"
  13. }
  14. #include "ErrMacro.h"
  15. #include "DfrgCmn.h"
  16. #include "DfrgEngn.h"
  17. #include "DfrgNtfs.h" //Includes function prototype for CheckPagefileNameMatch which is the same in FAT.
  18. #include "Alloc.h"
  19. #include "GetReg.h"
  20. #include "LoadFile.h"
  21. #include "Exclude.h"
  22. #include "Expand.h"
  23. /*****************************************************************************************************************
  24. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  25. INPUT + OUTPUT:
  26. IN cExcludeFile - The name of the file to check for exclusion.
  27. OUT phExcludeList - Pointer to handle for memory to be alloced and filled with the list of excluded files.
  28. GLOBALS:
  29. None.
  30. RETURN:
  31. TRUE - Success.
  32. FALSE - Fatal Error.
  33. */
  34. BOOL
  35. GetExcludeFile(
  36. IN PTCHAR cExcludeFile,
  37. OUT PHANDLE phExcludeList
  38. )
  39. {
  40. HKEY hValue = NULL;
  41. TCHAR cRegValue[MAX_PATH];
  42. DWORD dwRegValueSize = sizeof(cRegValue);
  43. DWORD dwExcludeFileSize = 0;
  44. //0.0E00 Get the install path.
  45. // todo NOTE: SFP will prevent us from using the system32 folder for this purpose!
  46. EF(GetRegValue(&hValue,
  47. TEXT("SOFTWARE\\Microsoft\\Dfrg"),
  48. (PTCHAR)TEXT("PathName"),
  49. cRegValue,
  50. &dwRegValueSize) == ERROR_SUCCESS);
  51. EF_ASSERT(RegCloseKey(hValue)==ERROR_SUCCESS);
  52. //Translate any environment variables in the string.
  53. EF_ASSERT(ExpandEnvVars(cRegValue));
  54. //0.0E00 Print out the name of the exclude file.
  55. lstrcat(cRegValue, TEXT("\\"));
  56. lstrcat(cRegValue, cExcludeFile);
  57. //0.0E00 Read the file into memory.
  58. *phExcludeList = LoadFile((PTCHAR)cRegValue,
  59. &dwExcludeFileSize,
  60. FILE_SHARE_READ|FILE_SHARE_WRITE,
  61. OPEN_EXISTING);
  62. //0.0E00 Print out whether or not the file was loaded.
  63. if(*phExcludeList != NULL) {
  64. Message(TEXT("Loaded exclude file"), S_OK, cRegValue);
  65. }
  66. else {
  67. Message(TEXT("No exclude file"), S_OK, cRegValue);
  68. }
  69. Message(TEXT(""), -1, NULL);
  70. return TRUE;
  71. }
  72. /*****************************************************************************************************************
  73. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  74. ROUTINE DESCRIPTION:
  75. Check to see if this file is excluded.
  76. INPUT + OUTPUT:
  77. IN VolData.cFileName - The name of the file which is excluded.
  78. IN VolData.FileSystem - Which file system the drive is.
  79. GLOBALS:
  80. None.
  81. RETURN:
  82. TRUE - File is not excluded.
  83. FALSE - File is excluded.
  84. */
  85. BOOL
  86. CheckFileForExclude(
  87. IN CONST BOOL fAcceptNameOnly
  88. )
  89. {
  90. PTCHAR pFileName = VolData.vFileName.GetBuffer();
  91. PTCHAR pExcludeList = NULL;
  92. PTCHAR pExcludeListEnd = NULL;
  93. UINT ExcludeLength;
  94. int i;
  95. if (!pFileName) {
  96. return FALSE;
  97. }
  98. if((VolData.FileSystem == FS_FAT || VolData.FileSystem == FS_FAT32) &&
  99. (CompareString(LOCALE_INVARIANT,// locale identifier
  100. NORM_IGNORECASE, // comparison-style options
  101. TEXT("BOOTSECT.DOS"), // pointer to first string
  102. -1, // null terminated first string
  103. pFileName+3, // pointer to second string
  104. -1) == 2)){ // null terminated second string
  105. return FALSE;
  106. }
  107. // Look get the file name from after the last slash.
  108. TCHAR *cFileName = wcsrchr(VolData.vFileName.GetBuffer(), L'\\');
  109. if (fAcceptNameOnly) {
  110. if (!cFileName) {
  111. cFileName = pFileName;
  112. }
  113. }
  114. else {
  115. //If there was no path to extract, then bail.
  116. EF_ASSERT(cFileName);
  117. // start at first character after the last backslash
  118. cFileName++;
  119. }
  120. //Check to see if this is a pagefile.
  121. if(CheckPagefileNameMatch(cFileName, pPageFileNames)){
  122. return FALSE;
  123. }
  124. //sks bug#200579 removed ShellIconCache from the list
  125. // Do not move the file safeboot.fs
  126. // Moving this file can cause desktop problems.
  127. // Raffi - 20-Oct-1997 - added in Build V2.0.172
  128. if (lstrlen(pFileName) >= lstrlen(TEXT("safeboot.fs"))) {
  129. i = lstrlen(pFileName) - lstrlen(TEXT("safeboot.fs"));
  130. if(CompareString(LOCALE_INVARIANT,// locale identifier
  131. NORM_IGNORECASE, // comparison-style options
  132. TEXT("safeboot.fs"), // pointer to first string
  133. -1, // null terminated first string
  134. pFileName+i, // pointer to second string
  135. -1) == 2){ // null terminated second string
  136. Message(TEXT("Excluding safeboot.fs"), -1, pFileName);
  137. return FALSE;
  138. }
  139. }
  140. // Do not move the file safeboot.csv
  141. // Moving this file can cause desktop problems.
  142. // Raffi - 20-Oct-1997 - added in Build V2.0.172
  143. if (lstrlen(pFileName) >= lstrlen(TEXT("safeboot.csv"))) {
  144. i = lstrlen(pFileName) - lstrlen(TEXT("safeboot.csv"));
  145. if(CompareString(LOCALE_INVARIANT,// locale identifier
  146. NORM_IGNORECASE, // comparison-style options
  147. TEXT("safeboot.csv"), // pointer to first string
  148. -1, // null terminated first string
  149. pFileName+i, // pointer to second string
  150. -1) == 2){ // null terminated second string
  151. Message(TEXT("Excluding safeboot.csv"), -1, pFileName);
  152. return FALSE;
  153. }
  154. }
  155. // Do not move the file safeboot.rsv
  156. // Moving this file can cause desktop problems.
  157. // Raffi - 20-Oct-1997 - added in Build V2.0.172
  158. if (lstrlen(pFileName) >= lstrlen(TEXT("safeboot.rsv"))) {
  159. i = lstrlen(pFileName) - lstrlen(TEXT("safeboot.rsv"));
  160. if(CompareString(LOCALE_INVARIANT,// locale identifier
  161. NORM_IGNORECASE, // comparison-style options
  162. TEXT("safeboot.rsv"), // pointer to first string
  163. -1, // null terminated first string
  164. pFileName+i, // pointer to second string
  165. -1) == 2){ // null terminated second string
  166. Message(TEXT("Excluding safeboot.rsv"), -1, pFileName);
  167. return FALSE;
  168. }
  169. }
  170. // Do not move the file hiberfil.sys
  171. // Moving this file can cause problems.
  172. if (lstrlen(pFileName) >= lstrlen(TEXT("hiberfil.sys"))) {
  173. i = lstrlen(pFileName) - lstrlen(TEXT("hiberfil.sys"));
  174. if(CompareString(LOCALE_INVARIANT,// locale identifier
  175. NORM_IGNORECASE, // comparison-style options
  176. TEXT("hiberfil.sys"), // pointer to first string
  177. -1, // null terminated first string
  178. pFileName+i, // pointer to second string
  179. -1) == 2){ // null terminated second string
  180. Message(TEXT("Excluding hiberfil.sys"), -1, pFileName);
  181. return FALSE;
  182. }
  183. }
  184. // Do not move the file memory.dmp
  185. // Moving this file can cause problems.
  186. if (lstrlen(pFileName) >= lstrlen(TEXT("memory.dmp"))) {
  187. i = lstrlen(pFileName) - lstrlen(TEXT("memory.dmp"));
  188. if(CompareString(LOCALE_INVARIANT,// locale identifier
  189. NORM_IGNORECASE, // comparison-style options
  190. TEXT("memory.dmp"), // pointer to first string
  191. -1, // null terminated first string
  192. pFileName+i, // pointer to second string
  193. -1) == 2){ // null terminated second string
  194. Message(TEXT("Excluding memory.dmp"), -1, pFileName);
  195. return FALSE;
  196. }
  197. }
  198. //0.0E00 No Match
  199. if(VolData.hExcludeList == NULL){
  200. return TRUE;
  201. }
  202. BOOL bReturnValue;
  203. __try{
  204. //0.0E00 Lock the memory and get pointer to the memory
  205. pExcludeList = (PTCHAR) GlobalLock(VolData.hExcludeList);
  206. if (pExcludeList == (PTCHAR) NULL){
  207. EH_ASSERT(FALSE);
  208. bReturnValue = FALSE;
  209. __leave;
  210. }
  211. //0.0E00 Get the pointer to the end of the exclude list
  212. pExcludeListEnd = pExcludeList + GlobalSize(VolData.hExcludeList);
  213. //0.0E00 Loop until match or end of Exclude List
  214. while (pExcludeList < pExcludeListEnd){
  215. ExcludeLength = lstrlen(pExcludeList);
  216. //
  217. // if(CompareString(LOCALE_INVARIANT, // locale identifier
  218. // NORM_IGNORECASE, // comparison-style options
  219. // pExcludeList, // pointer to first string
  220. // ExcludeLength, // size, in bytes or characters, of first string
  221. // pFileName, // pointer to second string
  222. // ExcludeLength) == 2){ // size, in bytes or characters, of second string
  223. //
  224. // //0.0E00 If there is a match then this file should be excluded.
  225. // if((lstrlen(pFileName) == (int)ExcludeLength) || (pFileName[ExcludeLength] == TEXT('\\'))){
  226. // //0.0E00 Exclude the file.
  227. // Message(TEXT("Excluding File."), -1, pFileName);
  228. // return FALSE;
  229. // }
  230. // }
  231. // Check to see if it is a wild string type of exclusion *RA*
  232. // It is not case sensitive
  233. if (lStrWildCmp(pFileName, pExcludeList, FALSE)) {
  234. //0.0E00 Exclude the file.
  235. Message(TEXT("Excluding File."), -1, pFileName);
  236. bReturnValue = FALSE;
  237. __leave;
  238. }
  239. //0.0E00 Set pointer to next record
  240. pExcludeList += ExcludeLength + 2;
  241. }
  242. //0.0E00 No Match
  243. bReturnValue = TRUE;
  244. }
  245. __finally {
  246. if (pExcludeList) {
  247. GlobalUnlock(VolData.hExcludeList);
  248. }
  249. }
  250. return bReturnValue;
  251. }
  252. /*****************************************************************************************************************
  253. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  254. ROUTINE DESCRIPTION:
  255. This routine does a wild string comparison of a given Source string and a Pattern string that
  256. may contain wild string characters (*, ?).
  257. INPUT:
  258. pOrigSourceString - Pointer to null terminated Source String to check for pattern match on.
  259. pOrigPatternString - Pointer to null terminated string containing the match pattern.
  260. bCaseType - TRUE=Case Sensitive comparison, FALSE=Non-Case Sensitive comparison
  261. RETURN:
  262. Success - TRUE - It was a match.
  263. Failure - FALSE - It was NOT a match.
  264. */
  265. BOOL
  266. lStrWildCmp (
  267. IN PTCHAR pOrigSourceString,
  268. IN PTCHAR pOrigPatternString,
  269. IN BOOL bCaseType
  270. )
  271. {
  272. TCHAR cSource[500]; // Local copy of Source String
  273. TCHAR cPattern[500]; // Local copy of Match Pattern String
  274. PTCHAR pSource; // Pointer into our local Source String
  275. PTCHAR pPattern; // Pointer into our local Match Pattern String
  276. PTCHAR pEndPattern; // Pointer to the end of our local Match Pattern String
  277. DWORD dwCompareFlag=0; // Flag used in CompareString function
  278. BOOL bMatchFound;
  279. int nchars; // Number of characters in pattern section that we are checking against.
  280. int lastn; // Indicates if last char was or was not, a cWildn (0=No, 1=Yes)
  281. // Define some characters we use
  282. TCHAR cWildn = {'*'};
  283. TCHAR cWild1 = {'?'};
  284. TCHAR cEndstr = {'\0'};
  285. PTCHAR cStopset = TEXT("*?\0"); // note order is cWildn/cWild1
  286. // Verify that a valid Source and Pattern string was passed in. If not, return failure status.
  287. if ((pOrigPatternString == NULL) || (lstrlen(pOrigPatternString) == 0)) {
  288. return FALSE;
  289. }
  290. if ((pOrigSourceString == NULL) || (lstrlen(pOrigSourceString) == 0)) {
  291. return FALSE;
  292. }
  293. // Check for the simple case of No wildcards in the pattern.
  294. #ifndef UNICODE
  295. if ((strchr(pOrigPatternString, cWildn) == NULL) &&
  296. (strchr(pOrigPatternString, cWild1) == NULL)) {
  297. #else
  298. if ((wcschr(pOrigPatternString, cWildn) == NULL) &&
  299. (wcschr(pOrigPatternString, cWild1) == NULL)) {
  300. #endif
  301. // This is a simple case of a 'straight' string comparison
  302. // If the lengths do not equal, then the strings do not equal.
  303. if (lstrlen(pOrigSourceString) != lstrlen(pOrigPatternString)) {
  304. // No Match
  305. return FALSE;
  306. }
  307. else {
  308. // Set up CompareString flag for No Case-sensitive checking if selected
  309. if (bCaseType == FALSE) { dwCompareFlag = NORM_IGNORECASE; }
  310. if(!lstrcmpi(pOrigSourceString, pOrigPatternString)){
  311. // WRITE A REAL SHELL FOR COMPARESTRING!
  312. // Compare strings
  313. // if ((CompareString(LOCALE_INVARIANT,
  314. // dwCompareFlag,
  315. // pOrigSourceString,
  316. // lstrlen(pOrigSourceString),
  317. // pOrigPatternString,
  318. // lstrlen(pOrigPatternString)
  319. // )) == 2) {
  320. // Match found
  321. return TRUE;
  322. }
  323. else {
  324. // No Match found
  325. return FALSE;
  326. }
  327. }
  328. }
  329. // There was wildcard(s) in the match pattern, so it is a more complex check
  330. //
  331. // Set up data for wildcard comparisons.
  332. //
  333. // Reset indicator that last char was not a cWildn(*) character
  334. lastn = 0;
  335. // Make our own local copies of the strings
  336. if (lstrcpy(cPattern, pOrigPatternString) == NULL) { return FALSE;}
  337. if (lstrcpy(cSource, pOrigSourceString) == NULL) { return FALSE;}
  338. // If Not case-sensitive check, then make both strings upper case
  339. if (bCaseType == FALSE) {
  340. CharUpper(cPattern);
  341. CharUpper(cSource);
  342. //#ifndef UNICODE
  343. // strupr(cPattern);
  344. // strupr(cSource);
  345. //#else
  346. // wcsupr(cPattern);
  347. // wcsupr(cSource);
  348. //#endif
  349. }
  350. // Set up pointers to strings
  351. pSource = cSource;
  352. pPattern = cPattern;
  353. pEndPattern = pPattern + (lstrlen(cPattern) * sizeof(TCHAR));
  354. // This section of the code will take the pattern string and extract each pattern section, where a
  355. // string sections is seperated by one of the following:
  356. //
  357. // a) The start of the string
  358. // b) The end of the string (0 termination)
  359. // c) A wildcard character (* or ?)
  360. //
  361. // For each pattern section, it will then try to find a match in the source string. If a match is found, then
  362. // the next pattern section is extracted and the next match check is made on the source string, starting at
  363. // the source string location where the last match was found.
  364. //
  365. // There are several types of pattern sections to consider
  366. // 1) *nnn* - Section with '*' on both ends. This means that the match be anywhere in the source string.
  367. // 2) nnn* - '*' just at the section end, so the string must match starting at the current source string
  368. // location.
  369. // 3) *nnn - '*' just at the section start, so just the end of the source string is checked. For example,
  370. // *.dat
  371. // 4) ? - For single character wildcards, we just skip the next character in the source string to check.
  372. //
  373. //
  374. while (pPattern <= pEndPattern) {
  375. switch (*pPattern) {
  376. // Case 1: Next pattern char is cWildn (*) character
  377. // Indicate that last character was cWildn and continue on with check
  378. case '*' : {
  379. pPattern = pPattern + 1;
  380. lastn = 1;
  381. break;
  382. } // End Case 1
  383. // Case 2: Next pattern char is cWild1 (?) character
  384. case '?' : {
  385. // Check where we are in the source string
  386. if (*pSource != cEndstr) {
  387. // We are not at the end, so we know the next character is the Source String will be
  388. // a match, so just increment to the next character and continue on with check.
  389. pSource = pSource + 1;
  390. pPattern = pPattern + 1;
  391. lastn = 0;
  392. break;
  393. }
  394. else {
  395. // We are at the end of the Source string, so NO Match found
  396. return FALSE;
  397. }
  398. } // End Case 2
  399. // Case 3: End of the pattern string reached
  400. case '\0' : {
  401. // If we are also at the end of the Source string, then all done with a Match found
  402. if (*pSource == cEndstr) {
  403. return TRUE;
  404. }
  405. else {
  406. // If the last character was a '*', then all done with a Match found
  407. if (lastn == 1) {
  408. return TRUE;
  409. }
  410. // If the last character was NOT a '*', then all done with NO Match found
  411. else {
  412. return FALSE;
  413. }
  414. }
  415. } // End Case 3
  416. // Case 4: Anything else (NON wild or terminating character), we get
  417. // the next pattern section to check against the source string.
  418. default : {
  419. // Get number of character in next pattern section
  420. #ifndef UNICODE
  421. nchars = strcspn(pPattern, cStopset);
  422. #else
  423. nchars = wcscspn(pPattern, cStopset);
  424. #endif
  425. // If the last character was Not a cWildn (*), then just
  426. // check the pattern section starting at the current point in the source string.
  427. if (lastn == 0) {
  428. // If a match found, then reset pattern and source pointers for the next sections to
  429. // check against and start search for next section.
  430. #ifndef UNICODE
  431. if (strncmp(pPattern, pSource, nchars) == 0) {
  432. #else
  433. if (wcsncmp(pPattern, pSource, nchars) == 0) {
  434. #endif
  435. pPattern = pPattern + nchars;
  436. pSource = pSource + nchars;
  437. break;
  438. }
  439. else {
  440. // NO Match found, return back failure status
  441. return FALSE;
  442. }
  443. }
  444. // The last character was a cWildn (*), but we need to see if
  445. // the string ends the pattern and check that as a special case
  446. // Check for special case of the last pattern section
  447. if (nchars == (int)lstrlen(pPattern)) {
  448. // For the last pattern section case, if the length of the pattern section is greater
  449. // than the source string section to check against, then there cannot be a match.
  450. if ((int)lstrlen(pSource) < nchars) {
  451. return FALSE;
  452. }
  453. // For the last pattern section case, we just need to compare to the end section of the
  454. // source string, adjust the source string pointer to this location (= 'cEndstr'-nchars),
  455. // and go continue checking.
  456. pSource = pSource + (lstrlen(pSource) - nchars);
  457. lastn = 0;
  458. break;
  459. }
  460. // It was not the special case, so since the last char was a cWildn (*), the match could be anywhere.
  461. // So, we start checking at the current Source string location for a match with the pattern section.
  462. // Note: If No Match is found, then it falls out of this loop.
  463. bMatchFound = FALSE;
  464. while (*pSource != cEndstr) {
  465. // If a match found, then reset pattern and source pointers for the next sections to
  466. // check against and start search for next section.
  467. #ifndef UNICODE
  468. if (strncmp(pPattern, pSource, nchars) == 0) {
  469. #else
  470. if (wcsncmp(pPattern, pSource, nchars) == 0) {
  471. #endif
  472. pPattern = pPattern + nchars;
  473. pSource = pSource + nchars;
  474. lastn = 0;
  475. bMatchFound = TRUE;
  476. break;
  477. }
  478. else {
  479. pSource = pSource + 1;
  480. }
  481. }
  482. // If no match found, then return back failure status
  483. if (!bMatchFound) {
  484. return FALSE;
  485. }
  486. // else a match was found, so go check next pattern section
  487. break;
  488. } // End Case 4
  489. } // End Switch
  490. } // End While
  491. // It should never fall out of the while loop, because the checks within the loop should catch
  492. // when processing is completed, but just in case, it will fail if it comes out of the loop.
  493. return FALSE;
  494. }