Leaked source code of windows server 2003
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.

1978 lines
60 KiB

  1. /*
  2. **++
  3. **
  4. ** Copyright (c) 2000-2001 Microsoft Corporation
  5. **
  6. ** Module Name:
  7. **
  8. ** wrtrrsm.cpp
  9. **
  10. **
  11. ** Abstract:
  12. **
  13. ** Writer shim module for RSM
  14. **
  15. **
  16. ** Author:
  17. **
  18. ** Brian Berkowitz [brianb]
  19. **
  20. **
  21. ** Revision History:
  22. **
  23. ** X-11 MCJ Michael C. Johnson 19-Sep-2000
  24. ** 215218: Wildcard name of log files returned by OnIdentify()
  25. ** 215390: Incorporate multiple '.' fix in MatchFileName from NtBackup
  26. **
  27. ** X-10 MCJ Michael C. Johnson 19-Sep-2000
  28. ** 176860: Add the missing calling convention specifiers
  29. **
  30. ** X-9 MCJ Michael C. Johnson 21-Aug-2000
  31. ** Added copyright and edit history
  32. ** 161899: Don't add a component for a database file in the
  33. ** exclude list.
  34. ** 165873: Remove trailing '\' from metadata file paths
  35. ** 165913: Deallocate memory on class destruction
  36. **
  37. **
  38. **--
  39. */
  40. #include <stdafx.h>
  41. #include <esent.h>
  42. #include <vss.h>
  43. #include <vswriter.h>
  44. #include <jetwriter.h>
  45. #include "vs_inc.hxx"
  46. #include "ijetwriter.h"
  47. ////////////////////////////////////////////////////////////////////////
  48. // Standard foo for file name aliasing. This code block must be after
  49. // all includes of VSS header files.
  50. //
  51. #ifdef VSS_FILE_ALIAS
  52. #undef VSS_FILE_ALIAS
  53. #endif
  54. #define VSS_FILE_ALIAS "JTWIJTWC"
  55. //
  56. ////////////////////////////////////////////////////////////////////////
  57. /////////////////////////////////////////////////////////////////////////////
  58. // local functions
  59. #define UMAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
  60. #define EXECUTEIF(_bSuccess, _fn) ((_bSuccess) ? (_fn) : (_bSuccess))
  61. #define GET_STATUS_FROM_BOOL(_bSucceed) ((_bSucceed) ? NOERROR : HRESULT_FROM_WIN32 (GetLastError()))
  62. typedef struct _ExpandedPathInfo
  63. {
  64. LIST_ENTRY leQueueHead;
  65. PWCHAR pwszOriginalFilePath;
  66. PWCHAR pwszOriginalFileName;
  67. PWCHAR pwszExpandedFilePath;
  68. PWCHAR pwszExpandedFileName;
  69. bool bRecurseIntoSubdirectories;
  70. } EXPANDEDPATHINFO, *PEXPANDEDPATHINFO, **PPEXPANDEDPATHINFO;
  71. static void RemoveAnyTrailingSeparator (PCHAR szPath)
  72. {
  73. ULONG ulPathLength = strlen (szPath);
  74. if ('\\' == szPath [ulPathLength - 1])
  75. {
  76. szPath [ulPathLength - 1] = '\0';
  77. }
  78. }
  79. static void RemoveAnyTrailingSeparator (PWCHAR wszPath)
  80. {
  81. ULONG ulPathLength = wcslen (wszPath);
  82. if (L'\\' == wszPath [ulPathLength - 1])
  83. {
  84. wszPath [ulPathLength - 1] = UNICODE_NULL;
  85. }
  86. }
  87. static bool ConvertName (PCHAR szSourceName,
  88. ULONG ulTargetBufferLengthInChars,
  89. PWCHAR wszTargetBuffer)
  90. {
  91. bool bSucceeded = true;
  92. wszTargetBuffer [0] = L'\0';
  93. /*
  94. ** Only need to do the conversion for non-zero length
  95. ** strings. Returning a zero length string for a zero length
  96. ** argument is an ok thing to do.
  97. */
  98. if ('\0' != szSourceName [0])
  99. {
  100. bSucceeded = (0 != MultiByteToWideChar (CP_OEMCP,
  101. 0,
  102. szSourceName,
  103. -1,
  104. wszTargetBuffer,
  105. ulTargetBufferLengthInChars));
  106. }
  107. return (bSucceeded);
  108. } /* ConvertName () */
  109. static bool ConvertNameAndSeparateFilePaths (PCHAR pszSourcePath,
  110. ULONG ulTargetBufferLength,
  111. PWCHAR pwszTargetPath,
  112. PWCHAR& pwszTargetFileSpec)
  113. {
  114. bool bSucceeded;
  115. PWCHAR pwchLastSlash;
  116. bSucceeded = ConvertName (pszSourcePath, ulTargetBufferLength, pwszTargetPath);
  117. if (bSucceeded)
  118. {
  119. /*
  120. ** Scan backwards from the end of the target path, zap the
  121. ** end-most '\' and point the file spec at the character
  122. ** following where the '\' used to be.
  123. */
  124. pwchLastSlash = wcsrchr (pwszTargetPath, L'\\');
  125. bSucceeded = (NULL != pwchLastSlash);
  126. }
  127. if (bSucceeded)
  128. {
  129. pwszTargetFileSpec = pwchLastSlash + 1;
  130. *pwchLastSlash = UNICODE_NULL;
  131. }
  132. return (bSucceeded);
  133. } /* ConvertNameAndSeparateFilePaths () */
  134. static void ConvertPathToLogicalPath(PWCHAR wszSource, ULONG lMaxSize, PWCHAR wszDest)
  135. {
  136. const WCHAR Slash = L'\\';
  137. const WCHAR Score = L'_';
  138. // copy the string
  139. memset(wszDest, 0, lMaxSize * sizeof(WCHAR));
  140. wcsncpy(wszDest, wszSource, lMaxSize - 1);
  141. // replace all slashes with underscores
  142. WCHAR* nextSlash = wcschr(wszDest, Slash);
  143. while (nextSlash != NULL)
  144. {
  145. *nextSlash = Score;
  146. nextSlash = wcschr(nextSlash + 1, Slash);
  147. }
  148. return;
  149. }
  150. /*
  151. ** This routine breaks out the next path and filespec from a list of
  152. ** filespecs. The expected format of the input string is
  153. **
  154. ** path\[filespec] [/s]
  155. **
  156. **
  157. ** The list can contain an arbitrary number of filespecs each
  158. ** separated by a semi-colon.
  159. */
  160. static bool DetermineNextPathWorker (LPCWSTR pwszFileList,
  161. LPCWSTR& pwszReturnedCursor,
  162. ULONG& ulReturnedDirectoryStart,
  163. ULONG& ulReturnedDirectoryLength,
  164. ULONG& ulReturnedFilenameStart,
  165. ULONG& ulReturnedFilenameLength,
  166. bool& bReturnedRecurseIntoSubdirectories,
  167. bool& bReturnedFoundSpec)
  168. {
  169. bool bSucceeded = true;
  170. bool bFoundSpec = false;
  171. ULONG ulPathNameLength;
  172. ULONG ulFileNameLength;
  173. ULONG ulIndex;
  174. ULONG ulIndexSubDirectory = 0;
  175. ULONG ulIndexLastDirectorySeparator = 0;
  176. ULONG ulIndexFirstCharInSpec = 0;
  177. ULONG ulIndexLastCharInSpec = 0;
  178. const ULONG ulLengthFileList = wcslen (pwszFileList);
  179. /*
  180. ** The format of the string we are expecting is "filename.ext /s
  181. ** ;nextname", ie a list of semi-colon separated names with an
  182. ** optional trailing '/s'. There can be an arbitrary number of
  183. ** spaces before the '/' and before the ';': these will be
  184. ** stripped out and discarded. So we start by scanning for the
  185. ** first '/' or ';' characters.
  186. **
  187. ** Look for a ';' first to determine the end point.
  188. */
  189. if ((NULL == pwszFileList) ||
  190. (UNICODE_NULL == pwszFileList [0]))
  191. {
  192. bFoundSpec = false;
  193. }
  194. else if (( L';' == pwszFileList [0]) ||
  195. ( L'/' == pwszFileList [0]) ||
  196. ((L'\\' == pwszFileList [0]) && (UNICODE_NULL == pwszFileList [1])))
  197. {
  198. bSucceeded = false;
  199. bFoundSpec = false;
  200. }
  201. else
  202. {
  203. bFoundSpec = true;
  204. }
  205. if (bSucceeded && bFoundSpec)
  206. {
  207. while (L' ' == pwszFileList [ulIndexFirstCharInSpec])
  208. {
  209. ulIndexFirstCharInSpec++;
  210. }
  211. for (ulIndex = ulIndexFirstCharInSpec; ulIndex < ulLengthFileList; ulIndex++)
  212. {
  213. if ((UNICODE_NULL == pwszFileList [ulIndex]) ||
  214. (L';' == pwszFileList [ulIndex]))
  215. {
  216. /*
  217. ** We found the end of this specification
  218. */
  219. break;
  220. }
  221. else if (L'\\' == pwszFileList [ulIndex])
  222. {
  223. /*
  224. ** Found a backslash? Record it's location. We'll want
  225. ** this later when determining what the file name is
  226. ** and so on.
  227. */
  228. ulIndexLastDirectorySeparator = ulIndex;
  229. }
  230. else if ((L'/' == pwszFileList [ulIndex]) &&
  231. (L's' == towlower (pwszFileList [ulIndex + 1])))
  232. {
  233. ulIndexSubDirectory = ulIndex;
  234. }
  235. }
  236. ulIndexLastCharInSpec = (0 == ulIndexSubDirectory) ? ulIndex - 1 : ulIndexSubDirectory - 1;
  237. while (L' ' == pwszFileList [ulIndexLastCharInSpec])
  238. {
  239. ulIndexLastCharInSpec--;
  240. }
  241. _ASSERTE (ulIndex > ulIndexSubDirectory);
  242. _ASSERTE (ulIndexSubDirectory == 0 ||
  243. ulIndexSubDirectory > ulIndexLastCharInSpec);
  244. _ASSERTE (ulIndexLastCharInSpec >= ulIndexLastDirectorySeparator);
  245. _ASSERTE (ulIndexLastDirectorySeparator > ulIndexFirstCharInSpec);
  246. /*
  247. ** We may have an illegal spec here with a missing '\'. Come
  248. ** on folks, there ought to be at least one. one measly '\' is
  249. ** all I'm after.
  250. */
  251. bSucceeded = (0 < ulIndexLastDirectorySeparator);
  252. }
  253. if (bSucceeded)
  254. {
  255. if (bFoundSpec)
  256. {
  257. ulPathNameLength = ulIndexLastDirectorySeparator - ulIndexFirstCharInSpec;
  258. ulFileNameLength = ulIndexLastCharInSpec - ulIndexLastDirectorySeparator;
  259. pwszReturnedCursor = (UNICODE_NULL == pwszFileList [ulIndex])
  260. ? &pwszFileList [ulIndex]
  261. : &pwszFileList [ulIndex + 1];
  262. ulReturnedDirectoryStart = ulIndexFirstCharInSpec;
  263. ulReturnedDirectoryLength = ulPathNameLength;
  264. ulReturnedFilenameStart = ulIndexLastDirectorySeparator + 1;
  265. ulReturnedFilenameLength = ulFileNameLength;
  266. bReturnedRecurseIntoSubdirectories = (0 != ulIndexSubDirectory);
  267. bReturnedFoundSpec = true;
  268. }
  269. else
  270. {
  271. pwszReturnedCursor = pwszFileList;
  272. ulReturnedDirectoryStart = 0;
  273. ulReturnedDirectoryLength = 0;
  274. ulReturnedFilenameStart = 0;
  275. ulReturnedFilenameLength = 0;
  276. bReturnedRecurseIntoSubdirectories = false;
  277. bReturnedFoundSpec = false;
  278. }
  279. }
  280. return (bSucceeded);
  281. } /* DetermineNextPathWorker () */
  282. static bool DetermineNextPathLengths (LPCWSTR pwszFileList,
  283. ULONG& ulReturnedLengthDirectory,
  284. ULONG& ulReturnedLengthFilename,
  285. bool& bReturnedRecurseIntoSubdirectories,
  286. bool& bReturnedFoundSpec)
  287. {
  288. bool bSucceeded;
  289. LPCWSTR pwszUpdatedCursor;
  290. ULONG ulIndexDirectoryStart;
  291. ULONG ulIndexFilenameStart;
  292. bSucceeded = DetermineNextPathWorker (pwszFileList,
  293. pwszUpdatedCursor,
  294. ulIndexDirectoryStart,
  295. ulReturnedLengthDirectory,
  296. ulIndexFilenameStart,
  297. ulReturnedLengthFilename,
  298. bReturnedRecurseIntoSubdirectories,
  299. bReturnedFoundSpec);
  300. return (bSucceeded);
  301. } /* DetermineNextPathLengths () */
  302. static bool DetermineNextPath (LPCWSTR pwszFileList,
  303. LPCWSTR& pwszReturnedCursor,
  304. ULONG ulLengthBufferDirectory,
  305. PWCHAR pwszBufferDirectory,
  306. ULONG ulLengthBufferFilename,
  307. PWCHAR pwszBufferFilename,
  308. bool& bReturnedRecurseIntoSubdirectories,
  309. bool& bReturnedFoundSpec)
  310. {
  311. bool bSucceeded = true;
  312. bool bRecurseIntoSubdirectories;
  313. bool bFoundSpec;
  314. bool bWildcardFilename;
  315. LPCWSTR pwszUpdatedCursor;
  316. ULONG ulLengthDirectory;
  317. ULONG ulLengthFilename;
  318. ULONG ulIndexDirectoryStart;
  319. ULONG ulIndexFilenameStart;
  320. bSucceeded = DetermineNextPathWorker (pwszFileList,
  321. pwszUpdatedCursor,
  322. ulIndexDirectoryStart,
  323. ulLengthDirectory,
  324. ulIndexFilenameStart,
  325. ulLengthFilename,
  326. bRecurseIntoSubdirectories,
  327. bFoundSpec);
  328. if (bSucceeded && bFoundSpec)
  329. {
  330. if ((ulLengthBufferDirectory < ((sizeof (WCHAR) * ulLengthDirectory) + sizeof (UNICODE_NULL))) ||
  331. (ulLengthBufferFilename < ((sizeof (WCHAR) * ulLengthFilename) + sizeof (UNICODE_NULL))))
  332. {
  333. /*
  334. ** Oops, buffer overflow would occur if we were to proceed
  335. ** with the copy.
  336. */
  337. bSucceeded = false;
  338. }
  339. }
  340. if (bSucceeded)
  341. {
  342. bReturnedRecurseIntoSubdirectories = bRecurseIntoSubdirectories;
  343. bReturnedFoundSpec = bFoundSpec;
  344. pwszReturnedCursor = pwszUpdatedCursor;
  345. if (bFoundSpec)
  346. {
  347. /*
  348. ** Everything up to, but excluding the last directory
  349. ** separator is the path. Everything after the last directory
  350. ** separator up to and including the last char is the
  351. ** filespec. If the filespec is zero length, then add the '*'
  352. ** wildcard.
  353. */
  354. bWildcardFilename = (0 == ulLengthFilename);
  355. ulLengthFilename += bWildcardFilename ? 1 : 0;
  356. memcpy (pwszBufferDirectory,
  357. &pwszFileList [ulIndexDirectoryStart],
  358. sizeof (WCHAR) * ulLengthDirectory);
  359. memcpy (pwszBufferFilename,
  360. (bWildcardFilename) ? L"*" : &pwszFileList [ulIndexFilenameStart],
  361. sizeof (WCHAR) * ulLengthFilename);
  362. pwszBufferDirectory [ulLengthDirectory] = UNICODE_NULL;
  363. pwszBufferFilename [ulLengthFilename] = UNICODE_NULL;
  364. }
  365. }
  366. return (bSucceeded);
  367. } /* DetermineNextPath () */
  368. static bool ValidateIncludeExcludeList (LPCWSTR pwszFileList)
  369. {
  370. LPCWSTR pwszCursor = pwszFileList;
  371. bool bSucceeded = true;
  372. bool bFoundFiles = true;
  373. bool bRecurseIntoSubdirectories;
  374. ULONG ulIndexDirectoryStart;
  375. ULONG ulIndexFilenameStart;
  376. ULONG ulLengthDirectory;
  377. ULONG ulLengthFilename;
  378. while (bSucceeded && bFoundFiles)
  379. {
  380. bSucceeded = EXECUTEIF (bSucceeded, (DetermineNextPathWorker (pwszCursor,
  381. pwszCursor,
  382. ulIndexDirectoryStart,
  383. ulLengthDirectory,
  384. ulIndexFilenameStart,
  385. ulLengthFilename,
  386. bRecurseIntoSubdirectories,
  387. bFoundFiles)));
  388. }
  389. return (bSucceeded);
  390. } /* ValidateIncludeExcludeList () */
  391. /*
  392. ** Based on MatchFname() from \nt\base\fs\utils\ntback50\be\bsdmatch.cpp
  393. */
  394. static bool MatchFilename (LPCWSTR pwszPattern, /* I - file name (with wildcards) */
  395. LPCWSTR pwszFilename) /* I - file name (without wildcards ) */
  396. {
  397. ULONG ulIndexPattern; /* index for pwszPattern */
  398. ULONG ulIndexFilename; /* index for pwszFilename */
  399. ULONG ulLengthPattern;
  400. const ULONG ulLengthFilename = wcslen (pwszFilename);
  401. bool bSucceeded = true;
  402. PWCHAR pwszNameBufferAllocated = NULL; /* allocated temp name buffer */
  403. PWCHAR pwszNameBufferTemp; /* pointer to one of the above */
  404. PWCHAR pwchTemp;
  405. WCHAR pwszNameBufferStatic [256]; /* static temp name buffer */
  406. WCHAR wchSavedChar ;
  407. ulIndexFilename = 0;
  408. if (wcscmp (pwszPattern, L"*") && wcscmp (pwszPattern, L"*.*"))
  409. {
  410. bool bTryWithDot = false;
  411. do
  412. {
  413. if (bTryWithDot)
  414. {
  415. /*
  416. ** Size of name_buff minus a null, minus a dot for the
  417. ** "bTryWithDot" code below. If the name is longer than the
  418. ** static buffer, allocate one from the heap.
  419. */
  420. if (((ulLengthFilename + 2) * sizeof (WCHAR)) > sizeof (pwszNameBufferStatic))
  421. {
  422. pwszNameBufferAllocated = new WCHAR [ulLengthFilename + 2];
  423. pwszNameBufferTemp = pwszNameBufferAllocated;
  424. }
  425. else
  426. {
  427. pwszNameBufferTemp = pwszNameBufferStatic;
  428. }
  429. if (pwszNameBufferTemp != NULL)
  430. {
  431. wcscpy (pwszNameBufferTemp, pwszFilename);
  432. wcscat (pwszNameBufferTemp, L".");
  433. pwszFilename = pwszNameBufferTemp;
  434. ulIndexFilename = 0;
  435. bSucceeded = true;
  436. }
  437. bTryWithDot = false;
  438. }
  439. else if (wcschr (pwszFilename, L'.') == NULL)
  440. {
  441. bTryWithDot = true;
  442. }
  443. for (ulIndexPattern = 0; (pwszPattern [ulIndexPattern] != 0) && (bSucceeded) ; ulIndexPattern++)
  444. {
  445. switch (pwszPattern [ulIndexPattern])
  446. {
  447. case L'*':
  448. while (pwszPattern [ulIndexPattern + 1] != UNICODE_NULL)
  449. {
  450. if (pwszPattern [ulIndexPattern + 1] == L'?')
  451. {
  452. if (pwszFilename [++ulIndexFilename] == UNICODE_NULL)
  453. {
  454. break ;
  455. }
  456. }
  457. else if (pwszPattern [ulIndexPattern + 1] != L'*')
  458. {
  459. break ;
  460. }
  461. ulIndexPattern++ ;
  462. }
  463. pwchTemp = wcspbrk (&pwszPattern [ulIndexPattern + 1], L"*?");
  464. if (pwchTemp != NULL)
  465. {
  466. wchSavedChar = *pwchTemp;
  467. *pwchTemp = UNICODE_NULL;
  468. ulLengthPattern = wcslen (&pwszPattern [ulIndexPattern + 1]);
  469. while (pwszFilename [ulIndexFilename] &&
  470. _wcsnicmp (&pwszFilename [ulIndexFilename],
  471. &pwszPattern [ulIndexPattern + 1],
  472. ulLengthPattern))
  473. {
  474. ulIndexFilename++;
  475. }
  476. ulIndexPattern += ulLengthPattern;
  477. *pwchTemp = wchSavedChar;
  478. if (pwszFilename [ulIndexFilename] == UNICODE_NULL)
  479. {
  480. bSucceeded = false;
  481. }
  482. else
  483. {
  484. ulIndexFilename++;
  485. }
  486. }
  487. else
  488. {
  489. if (pwszPattern [ulIndexPattern + 1] == UNICODE_NULL)
  490. {
  491. ulIndexFilename = wcslen (pwszFilename);
  492. break;
  493. }
  494. else
  495. {
  496. pwchTemp = wcschr (&pwszFilename [ulIndexFilename],
  497. pwszPattern [ulIndexPattern + 1]);
  498. if (pwchTemp != NULL)
  499. {
  500. ulIndexFilename += (ULONG)(pwchTemp - &pwszFilename [ulIndexFilename]);
  501. }
  502. else
  503. {
  504. bSucceeded = false;
  505. }
  506. }
  507. }
  508. break;
  509. case L'?' :
  510. if (pwszFilename [ulIndexFilename] != UNICODE_NULL)
  511. {
  512. ulIndexFilename++;
  513. }
  514. break;
  515. default:
  516. if (pwszFilename [ulIndexFilename] == UNICODE_NULL)
  517. {
  518. bSucceeded = false;
  519. }
  520. else if (towupper (pwszFilename [ulIndexFilename]) != towupper (pwszPattern [ulIndexPattern]))
  521. {
  522. ULONG ulIndexPreviousStar = ulIndexPattern;
  523. /*
  524. ** Set the index back to the last '*'
  525. */
  526. bSucceeded = false;
  527. do
  528. {
  529. if (pwszPattern [ulIndexPreviousStar] == L'*')
  530. {
  531. ulIndexPattern = ulIndexPreviousStar;
  532. ulIndexFilename++;
  533. bSucceeded = true;
  534. break;
  535. }
  536. } while (ulIndexPreviousStar-- > 0);
  537. }
  538. else
  539. {
  540. ulIndexFilename++;
  541. }
  542. }
  543. }
  544. if (pwszFilename [ulIndexFilename] != UNICODE_NULL)
  545. {
  546. bSucceeded = false;
  547. }
  548. } while ((!bSucceeded) && (bTryWithDot));
  549. }
  550. delete [] pwszNameBufferAllocated;
  551. return (bSucceeded);
  552. } /* MatchFilename () */
  553. /////////////////////////////////////////////////////////////////////////////
  554. // class CVssIJetWriter
  555. //
  556. // logical path == dbpathname (with slashes turned to underscores)
  557. // component name == dbfilename (minus the extension?)
  558. // caption == display name
  559. //
  560. //
  561. // add db and slv files as database files
  562. // add the per-instance log file to each database even though is is the same each time.
  563. STDMETHODCALLTYPE CVssIJetWriter::~CVssIJetWriter()
  564. {
  565. PostProcessIncludeExcludeLists (true );
  566. PostProcessIncludeExcludeLists (false);
  567. delete m_wszWriterName;
  568. delete m_wszFilesToInclude;
  569. delete m_wszFilesToExclude;
  570. }
  571. BOOL CVssIJetWriter::CheckExcludedFileListForMatch (LPCWSTR pwszDatabaseFilePath,
  572. LPCWSTR pwszDatabaseFileSpec)
  573. {
  574. BOOL bMatchFound = false;
  575. PLIST_ENTRY pleElement = m_leFilesToExcludeEntries.Flink;
  576. UNICODE_STRING ucsExcludedFilePath;
  577. UNICODE_STRING ucsDatabaseFilePath;
  578. PEXPANDEDPATHINFO pepnPathInfomation;
  579. RtlInitUnicodeString (&ucsDatabaseFilePath, pwszDatabaseFilePath);
  580. while ((&m_leFilesToExcludeEntries != pleElement) && !bMatchFound)
  581. {
  582. pepnPathInfomation = (PEXPANDEDPATHINFO)((PBYTE) pleElement - offsetof (EXPANDEDPATHINFO, leQueueHead));
  583. RtlInitUnicodeString (&ucsExcludedFilePath,
  584. pepnPathInfomation->pwszExpandedFilePath);
  585. if (pepnPathInfomation->bRecurseIntoSubdirectories)
  586. {
  587. bMatchFound = RtlPrefixUnicodeString (&ucsExcludedFilePath,
  588. &ucsDatabaseFilePath,
  589. true);
  590. }
  591. else
  592. {
  593. bMatchFound = RtlEqualUnicodeString (&ucsExcludedFilePath, &ucsDatabaseFilePath, true) &&
  594. MatchFilename (pepnPathInfomation->pwszExpandedFileName, pwszDatabaseFileSpec);
  595. }
  596. pleElement = pleElement->Flink;
  597. }
  598. return (bMatchFound);
  599. } /* CVssIJetWriter::CheckExcludedFileListForMatch () */
  600. bool CVssIJetWriter::ProcessJetInstance (JET_INSTANCE_INFO *pInstanceInfo)
  601. {
  602. JET_ERR jetStatus;
  603. HRESULT hrStatus;
  604. DWORD dwStatus;
  605. bool bSucceeded;
  606. bool bRestoreMetadata = false;
  607. bool bNotifyOnBackupComplete = false;
  608. bool bSelectable = false;
  609. bool bIncludeComponent;
  610. CHAR szPathShortName [MAX_PATH];
  611. CHAR szPathFullName [MAX_PATH];
  612. WCHAR wszInstanceName [MAX_PATH];
  613. WCHAR wszDatabaseName [MAX_PATH];
  614. WCHAR wszDatabaseLogicalPath [MAX_PATH];
  615. WCHAR wszDatabaseDisplayName [MAX_PATH];
  616. WCHAR wszDatabaseFilePath [MAX_PATH];
  617. WCHAR wszDatabaseSLVFilePath [MAX_PATH];
  618. WCHAR wszLogFilePath [MAX_PATH];
  619. WCHAR wszLogFileName [MAX_PATH];
  620. WCHAR wszCheckpointFilePath [MAX_PATH];
  621. WCHAR wszCheckpointFileName [MAX_PATH];
  622. PWCHAR pwszDatabaseFileName = L"";
  623. PWCHAR pwszDatabaseSLVFileName = L"";
  624. /*
  625. ** A valid instance will have an instance Id, but if it's not
  626. ** actually being used for anything it may well not have a name,
  627. ** any log or database files.
  628. **
  629. ** See if we can get hold of the name of the log file for this
  630. ** instance.
  631. */
  632. bSucceeded = (JET_errSuccess <= JetGetSystemParameter (pInstanceInfo->hInstanceId,
  633. JET_sesidNil,
  634. JET_paramLogFilePath,
  635. NULL,
  636. szPathShortName,
  637. sizeof (szPathShortName)));
  638. if (bSucceeded)
  639. {
  640. dwStatus = GetFullPathNameA (szPathShortName,
  641. sizeof (szPathFullName),
  642. szPathFullName,
  643. NULL);
  644. bSucceeded = (dwStatus > 0);
  645. }
  646. if (bSucceeded)
  647. {
  648. RemoveAnyTrailingSeparator (szPathFullName);
  649. bSucceeded = ConvertName (szPathFullName,
  650. MAX_PATH,
  651. wszLogFilePath);
  652. }
  653. BsDebugTrace (0,
  654. DEBUG_TRACE_VSS_WRITER,
  655. (L"CVssIJetWriter::ProcessJetInstance - "
  656. L"%s calling JetGetSystemParameter() with instance Log file path '%S' (shortname) or '%s' full name",
  657. bSucceeded ? L"Succeeded" : L"FAILED",
  658. szPathShortName,
  659. wszLogFilePath));
  660. /*
  661. ** Ok, now get the SystemPath which we will need to construct the
  662. ** path for the checkpoint file.
  663. */
  664. bSucceeded = (JET_errSuccess <= JetGetSystemParameter (pInstanceInfo->hInstanceId,
  665. JET_sesidNil,
  666. JET_paramSystemPath,
  667. NULL,
  668. szPathShortName,
  669. sizeof (szPathShortName)));
  670. if (bSucceeded)
  671. {
  672. dwStatus = GetFullPathNameA (szPathShortName,
  673. sizeof (szPathFullName),
  674. szPathFullName,
  675. NULL);
  676. bSucceeded = (dwStatus > 0);
  677. }
  678. if (bSucceeded)
  679. {
  680. RemoveAnyTrailingSeparator (szPathFullName);
  681. bSucceeded = ConvertName (szPathFullName,
  682. MAX_PATH,
  683. wszCheckpointFilePath);
  684. }
  685. BsDebugTrace (0,
  686. DEBUG_TRACE_VSS_WRITER,
  687. (L"CVssIJetWriter::ProcessJetInstance - "
  688. L"%s calling JetGetSystemParameter() with checkpoint file path '%S' (shortname) or '%s' full name",
  689. bSucceeded ? L"Succeeded" : L"FAILED",
  690. szPathShortName,
  691. wszCheckpointFilePath));
  692. /*
  693. ** Ok, now get the base name which we will need to construct the
  694. ** file spec for the log and checkpoint files. Note that we expect
  695. ** this to be just 3 chars long.
  696. */
  697. bSucceeded = (JET_errSuccess <= JetGetSystemParameter (pInstanceInfo->hInstanceId,
  698. JET_sesidNil,
  699. JET_paramBaseName,
  700. NULL,
  701. szPathShortName,
  702. sizeof (szPathShortName)));
  703. if (bSucceeded)
  704. {
  705. /*
  706. ** Convert to wide char ensuring that we leave a little room
  707. ** for the "*.log"/".chk" strings to be appended to form the
  708. ** log file spec and the checkpoint file specs respectively.
  709. */
  710. bSucceeded = ConvertName (szPathShortName,
  711. MAX_PATH - sizeof ("*.log"),
  712. wszCheckpointFileName);
  713. }
  714. if (bSucceeded)
  715. {
  716. wcscpy (wszLogFileName, wszCheckpointFileName);
  717. wcscat (wszCheckpointFileName, L".chk" );
  718. wcscat (wszLogFileName, L"*.log");
  719. }
  720. BsDebugTrace (0,
  721. DEBUG_TRACE_VSS_WRITER,
  722. (L"CVssIJetWriter::ProcessJetInstance - "
  723. L"%s calling JetGetSystemParameter() for base name '%S' to form LogFileName '%s' and CheckpointFileName '%s'",
  724. bSucceeded ? L"Succeeded" : L"FAILED",
  725. szPathShortName,
  726. wszLogFileName,
  727. wszCheckpointFileName));
  728. if (bSucceeded && (pInstanceInfo->cDatabases > 0))
  729. {
  730. /*
  731. ** Ok, we think we have an instance that is actually being
  732. ** used for something. so go ahead and construct a 'component'
  733. ** for it.
  734. */
  735. if ((NULL == pInstanceInfo->szInstanceName) ||
  736. ('\0' == pInstanceInfo->szInstanceName [0]))
  737. {
  738. /*
  739. ** We seem to have a NULL pointer or a zero length
  740. ** string. Just set to a zero length unicode string.
  741. */
  742. wszInstanceName [0] = UNICODE_NULL;
  743. }
  744. else
  745. {
  746. bSucceeded = ConvertName (pInstanceInfo->szInstanceName,
  747. MAX_PATH,
  748. wszInstanceName);
  749. }
  750. for (ULONG ulDatabase = 0; bSucceeded && (ulDatabase < pInstanceInfo->cDatabases); ulDatabase++)
  751. {
  752. bSucceeded = ConvertNameAndSeparateFilePaths (pInstanceInfo->szDatabaseFileName [ulDatabase],
  753. MAX_PATH,
  754. wszDatabaseFilePath,
  755. pwszDatabaseFileName);
  756. /*
  757. ** Convert the database display name to unicode but allow
  758. ** for a possible NULL pointer or a non-zero length file
  759. ** spec.
  760. */
  761. if (bSucceeded)
  762. {
  763. if ((NULL == pInstanceInfo->szDatabaseDisplayName [ulDatabase]) ||
  764. ('\0' == pInstanceInfo->szDatabaseDisplayName [ulDatabase][0]))
  765. {
  766. wszDatabaseDisplayName [0] = UNICODE_NULL;
  767. }
  768. else
  769. {
  770. bSucceeded = ConvertName (pInstanceInfo->szDatabaseDisplayName [ulDatabase],
  771. MAX_PATH,
  772. wszDatabaseDisplayName);
  773. }
  774. }
  775. /*
  776. ** Convert the SLV filename to unicode but allow for a
  777. ** possible NULL pointer or a non-zero length file spec.
  778. */
  779. if (bSucceeded)
  780. {
  781. if ((NULL == pInstanceInfo->szDatabaseSLVFileName [ulDatabase]) ||
  782. ('\0' == pInstanceInfo->szDatabaseSLVFileName [ulDatabase][0]))
  783. {
  784. wszDatabaseSLVFilePath [0] = UNICODE_NULL;
  785. pwszDatabaseSLVFileName = wszDatabaseSLVFilePath;
  786. }
  787. else
  788. {
  789. bSucceeded = ConvertNameAndSeparateFilePaths (pInstanceInfo->szDatabaseSLVFileName [ulDatabase],
  790. MAX_PATH,
  791. wszDatabaseSLVFilePath,
  792. pwszDatabaseSLVFileName);
  793. }
  794. }
  795. /*
  796. ** We've now done all the name conversions to unicode so
  797. ** add a component and the log and database files where
  798. ** they're available.
  799. */
  800. if (bSucceeded)
  801. {
  802. bIncludeComponent = !CheckExcludedFileListForMatch (wszDatabaseFilePath,
  803. pwszDatabaseFileName);
  804. }
  805. if (bSucceeded && bIncludeComponent)
  806. {
  807. PWCHAR pwchLastDot = wcsrchr (pwszDatabaseFileName, L'.');
  808. ULONG ulDatabaseNameLength = (ULONG) (pwchLastDot - pwszDatabaseFileName);
  809. wcsncpy (wszDatabaseName, pwszDatabaseFileName, ulDatabaseNameLength);
  810. wszDatabaseName [ulDatabaseNameLength] = '\0';
  811. ConvertPathToLogicalPath(wszDatabaseFilePath, MAX_PATH, wszDatabaseLogicalPath);
  812. hrStatus = m_pIMetadata->AddComponent (VSS_CT_DATABASE,
  813. wszDatabaseLogicalPath,
  814. wszDatabaseName,
  815. wszDatabaseDisplayName,
  816. NULL,
  817. 0,
  818. bRestoreMetadata,
  819. bNotifyOnBackupComplete,
  820. bSelectable);
  821. bSucceeded = SUCCEEDED (hrStatus);
  822. BsDebugTrace (0,
  823. DEBUG_TRACE_VSS_WRITER,
  824. (L"CVssIJetWriter::ProcessJetInstance - "
  825. L"%s adding component '%s\\%s' for jet instance '%s' database '%s' with display name '%s'",
  826. bSucceeded ? L"Succeeded" : L"FAILED",
  827. wszDatabaseLogicalPath,
  828. wszDatabaseName,
  829. wszInstanceName,
  830. wszDatabaseName,
  831. wszDatabaseDisplayName));
  832. }
  833. if (bSucceeded && bIncludeComponent)
  834. {
  835. hrStatus = m_pIMetadata->AddDatabaseFiles (wszDatabaseLogicalPath,
  836. wszDatabaseName,
  837. wszDatabaseFilePath,
  838. pwszDatabaseFileName);
  839. bSucceeded = SUCCEEDED (hrStatus);
  840. BsDebugTrace (0,
  841. DEBUG_TRACE_VSS_WRITER,
  842. (L"CVssIJetWriter::ProcessJetInstance - "
  843. L"%s adding database files for instance '%s', database '%s', database file '%s\\%s'",
  844. bSucceeded ? L"Succeeded" : L"FAILED",
  845. wszInstanceName,
  846. wszDatabaseName,
  847. wszDatabaseFilePath,
  848. pwszDatabaseFileName));
  849. }
  850. /*
  851. ** May not have an SLV file so only add it if we have a
  852. ** non-zero length file spec
  853. */
  854. if (bSucceeded && bIncludeComponent && (UNICODE_NULL != pwszDatabaseSLVFileName [0]))
  855. {
  856. hrStatus = m_pIMetadata->AddDatabaseFiles (wszDatabaseLogicalPath,
  857. wszDatabaseName,
  858. wszDatabaseSLVFilePath,
  859. pwszDatabaseSLVFileName);
  860. bSucceeded = SUCCEEDED (hrStatus);
  861. BsDebugTrace (0,
  862. DEBUG_TRACE_VSS_WRITER,
  863. (L"CVssIJetWriter::ProcessJetInstance - "
  864. L"%s adding SLV file for instance '%s', database '%s', SLV file '%s\\%s'",
  865. bSucceeded ? L"Succeeded" : L"FAILED",
  866. wszInstanceName,
  867. wszDatabaseName,
  868. wszDatabaseSLVFilePath,
  869. pwszDatabaseSLVFileName));
  870. }
  871. /*
  872. ** May not have an instance log file so only add it if we
  873. ** have a non-zero length file path
  874. */
  875. if (bSucceeded && bIncludeComponent && (UNICODE_NULL != wszLogFilePath [0]))
  876. {
  877. hrStatus = m_pIMetadata->AddDatabaseLogFiles (wszDatabaseLogicalPath,
  878. wszDatabaseName,
  879. wszLogFilePath,
  880. wszLogFileName);
  881. bSucceeded = SUCCEEDED (hrStatus);
  882. BsDebugTrace (0,
  883. DEBUG_TRACE_VSS_WRITER,
  884. (L"CVssIJetWriter::ProcessJetInstance - "
  885. L"%s adding log file for instance '%s', database '%s', log file '%s\\%s'",
  886. bSucceeded ? L"Succeeded" : L"FAILED",
  887. wszInstanceName,
  888. wszDatabaseName,
  889. wszLogFilePath,
  890. wszLogFileName));
  891. }
  892. /*
  893. ** May not have a checkpoint file so only add it if we
  894. ** have a non-zero length file path
  895. */
  896. if (bSucceeded && bIncludeComponent && (UNICODE_NULL != wszCheckpointFilePath [0]))
  897. {
  898. hrStatus = m_pIMetadata->AddDatabaseLogFiles (wszDatabaseLogicalPath,
  899. wszDatabaseName,
  900. wszCheckpointFilePath,
  901. wszCheckpointFileName);
  902. bSucceeded = SUCCEEDED (hrStatus);
  903. BsDebugTrace (0,
  904. DEBUG_TRACE_VSS_WRITER,
  905. (L"CVssIJetWriter::ProcessJetInstance - "
  906. L"%s adding checkpoint file for instance '%s', database '%s', checkpoint file '%s\\%s'",
  907. bSucceeded ? L"Succeeded" : L"FAILED",
  908. wszInstanceName,
  909. wszDatabaseName,
  910. wszCheckpointFilePath,
  911. wszCheckpointFileName));
  912. }
  913. }
  914. }
  915. return (bSucceeded);
  916. } /* CVssIJetWriter::ProcessJetInstance () */
  917. bool CVssIJetWriter::PreProcessIncludeExcludeLists (bool bProcessingIncludeList)
  918. {
  919. /*
  920. ** Parse the m_wszFilesToInclude and m_wszFilesToExclude adding
  921. ** and enty to the appropriate list as necessary. This will
  922. ** minimize the number of passes over the un-processed lists.
  923. */
  924. ULONG ulPathLength;
  925. ULONG ulNameLength;
  926. bool bRecurseIntoSubdirectories;
  927. bool bSucceeded = true;
  928. bool bFoundFiles = true;
  929. PEXPANDEDPATHINFO pepnPathInfomation = NULL;
  930. PWCHAR pwszCursor = bProcessingIncludeList
  931. ? m_wszFilesToInclude
  932. : m_wszFilesToExclude;
  933. while (bSucceeded && bFoundFiles)
  934. {
  935. bSucceeded = DetermineNextPathLengths (pwszCursor,
  936. ulPathLength,
  937. ulNameLength,
  938. bRecurseIntoSubdirectories,
  939. bFoundFiles);
  940. if (bSucceeded && bFoundFiles)
  941. {
  942. pepnPathInfomation = new EXPANDEDPATHINFO;
  943. bSucceeded = (NULL != pepnPathInfomation);
  944. }
  945. else
  946. {
  947. /*
  948. ** We either failed and/or found no files. In either case
  949. ** there is no point in continuing.
  950. */
  951. break;
  952. }
  953. if (bSucceeded)
  954. {
  955. InitializeListHead (&pepnPathInfomation->leQueueHead);
  956. if (0 == ulNameLength)
  957. {
  958. /*
  959. ** If the filename component is zero length, then it
  960. ** will be turned into a "*" so add a character to the
  961. ** buffer to make room.
  962. */
  963. ulNameLength++;
  964. }
  965. /*
  966. ** Allow extra space for terminating UNICODE_NULL
  967. */
  968. ulPathLength++;
  969. ulNameLength++;
  970. pepnPathInfomation->pwszExpandedFilePath = NULL;
  971. pepnPathInfomation->pwszExpandedFileName = NULL;
  972. pepnPathInfomation->pwszOriginalFilePath = new WCHAR [ulPathLength];
  973. pepnPathInfomation->pwszOriginalFileName = new WCHAR [ulNameLength];
  974. bSucceeded = ((NULL != pepnPathInfomation->pwszOriginalFilePath) &&
  975. (NULL != pepnPathInfomation->pwszOriginalFileName));
  976. }
  977. if (bSucceeded)
  978. {
  979. bSucceeded = DetermineNextPath (pwszCursor,
  980. pwszCursor,
  981. ulPathLength * sizeof (WCHAR),
  982. pepnPathInfomation->pwszOriginalFilePath,
  983. ulNameLength * sizeof (WCHAR),
  984. pepnPathInfomation->pwszOriginalFileName,
  985. pepnPathInfomation->bRecurseIntoSubdirectories,
  986. bFoundFiles);
  987. BS_ASSERT (bFoundFiles && L"Second attempt to locate files failed unexpectedly");
  988. }
  989. if (bSucceeded)
  990. {
  991. ulPathLength = ExpandEnvironmentStringsW (pepnPathInfomation->pwszOriginalFilePath, NULL, 0);
  992. ulNameLength = ExpandEnvironmentStringsW (pepnPathInfomation->pwszOriginalFileName, NULL, 0);
  993. bSucceeded = (0 < ulPathLength) && (0 < ulNameLength);
  994. }
  995. if (bSucceeded)
  996. {
  997. pepnPathInfomation->pwszExpandedFilePath = new WCHAR [ulPathLength];
  998. pepnPathInfomation->pwszExpandedFileName = new WCHAR [ulNameLength];
  999. bSucceeded = ((NULL != pepnPathInfomation->pwszExpandedFilePath) &&
  1000. (NULL != pepnPathInfomation->pwszExpandedFileName));
  1001. }
  1002. if (bSucceeded)
  1003. {
  1004. ExpandEnvironmentStringsW (pepnPathInfomation->pwszOriginalFilePath,
  1005. pepnPathInfomation->pwszExpandedFilePath,
  1006. ulPathLength);
  1007. ExpandEnvironmentStringsW (pepnPathInfomation->pwszOriginalFileName,
  1008. pepnPathInfomation->pwszExpandedFileName,
  1009. ulNameLength);
  1010. }
  1011. if (bSucceeded)
  1012. {
  1013. InsertTailList (bProcessingIncludeList ? &m_leFilesToIncludeEntries : &m_leFilesToExcludeEntries,
  1014. &pepnPathInfomation->leQueueHead);
  1015. pepnPathInfomation = NULL;
  1016. }
  1017. if (NULL != pepnPathInfomation)
  1018. {
  1019. delete [] pepnPathInfomation->pwszOriginalFilePath;
  1020. delete [] pepnPathInfomation->pwszOriginalFileName;
  1021. delete [] pepnPathInfomation->pwszExpandedFilePath;
  1022. delete [] pepnPathInfomation->pwszExpandedFileName;
  1023. delete pepnPathInfomation;
  1024. pepnPathInfomation = NULL;
  1025. }
  1026. }
  1027. return (bSucceeded);
  1028. } /* CVssIJetWriter::PreProcessIncludeExcludeLists () */
  1029. bool CVssIJetWriter::ProcessIncludeExcludeLists (bool bProcessingIncludeList)
  1030. {
  1031. /*
  1032. ** parse the m_wszFilesToInclude and m_wszFilesToExclude
  1033. ** calling the m_pIMetadata->IncludeFiles() and/or
  1034. ** m_pIMetadata->ExcludeFiles() routines as necessary
  1035. */
  1036. HRESULT hrStatus;
  1037. bool bSucceeded = true;
  1038. const PLIST_ENTRY pleQueueHead = bProcessingIncludeList ? &m_leFilesToIncludeEntries : &m_leFilesToExcludeEntries;
  1039. PLIST_ENTRY pleElement = pleQueueHead->Flink;
  1040. PEXPANDEDPATHINFO pepnPathInfomation;
  1041. while (bSucceeded && (pleQueueHead != pleElement))
  1042. {
  1043. pepnPathInfomation = (PEXPANDEDPATHINFO)((PBYTE) pleElement - offsetof (EXPANDEDPATHINFO, leQueueHead));
  1044. if (bProcessingIncludeList)
  1045. {
  1046. hrStatus = m_pIMetadata->AddIncludeFiles (pepnPathInfomation->pwszOriginalFilePath,
  1047. pepnPathInfomation->pwszOriginalFileName,
  1048. pepnPathInfomation->bRecurseIntoSubdirectories,
  1049. NULL);
  1050. }
  1051. else
  1052. {
  1053. hrStatus = m_pIMetadata->AddExcludeFiles (pepnPathInfomation->pwszOriginalFilePath,
  1054. pepnPathInfomation->pwszOriginalFileName,
  1055. pepnPathInfomation->bRecurseIntoSubdirectories);
  1056. }
  1057. bSucceeded = SUCCEEDED (hrStatus);
  1058. pleElement = pleElement->Flink;
  1059. }
  1060. return (bSucceeded);
  1061. } /* CVssIJetWriter::ProcessIncludeExcludeLists () */
  1062. void CVssIJetWriter::PostProcessIncludeExcludeLists (bool bProcessingIncludeList)
  1063. {
  1064. PEXPANDEDPATHINFO pepnPathInfomation;
  1065. PLIST_ENTRY pleElement;
  1066. const PLIST_ENTRY pleQueueHead = bProcessingIncludeList
  1067. ? &m_leFilesToIncludeEntries
  1068. : &m_leFilesToExcludeEntries;
  1069. while (!IsListEmpty (pleQueueHead))
  1070. {
  1071. pleElement = RemoveHeadList (pleQueueHead);
  1072. BS_ASSERT (NULL != pleElement);
  1073. pepnPathInfomation = (PEXPANDEDPATHINFO)((PBYTE) pleElement - offsetof (EXPANDEDPATHINFO, leQueueHead));
  1074. delete [] pepnPathInfomation->pwszOriginalFilePath;
  1075. delete [] pepnPathInfomation->pwszOriginalFileName;
  1076. delete [] pepnPathInfomation->pwszExpandedFilePath;
  1077. delete [] pepnPathInfomation->pwszExpandedFileName;
  1078. delete pepnPathInfomation;
  1079. }
  1080. } /* CVssIJetWriter::PostProcessIncludeExcludeLists () */
  1081. bool STDMETHODCALLTYPE CVssIJetWriter::OnIdentify (IN IVssCreateWriterMetadata *pMetadata)
  1082. {
  1083. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnIdentify");
  1084. JET_ERR jetStatus;
  1085. HRESULT hrStatus;
  1086. bool bSucceeded = true;
  1087. ULONG ulInstanceInfoCount = 0;
  1088. JET_INSTANCE_INFO *pInstanceInfo;
  1089. m_pIMetadata = pMetadata;
  1090. /**
  1091. ** Set up a restore method
  1092. */
  1093. hrStatus = m_pIMetadata->SetRestoreMethod (
  1094. VSS_RME_RESTORE_AT_REBOOT, // restore at reboot
  1095. NULL,
  1096. NULL,
  1097. VSS_WRE_NEVER, // writer not invoked during restore
  1098. true); // reboot is required
  1099. bSucceeded = SUCCEEDED (hrStatus);
  1100. /*
  1101. ** Set up list of include and exclude files. ready for use in
  1102. ** filtering Jet databases and adding include/exclude files lists.
  1103. */
  1104. bSucceeded = EXECUTEIF (bSucceeded, (PreProcessIncludeExcludeLists (true )));
  1105. bSucceeded = EXECUTEIF (bSucceeded, (PreProcessIncludeExcludeLists (false)));
  1106. bSucceeded = EXECUTEIF (bSucceeded, (JET_errSuccess <= JetGetInstanceInfo (&ulInstanceInfoCount,
  1107. &pInstanceInfo)));
  1108. for (ULONG ulInstanceIndex = 0; ulInstanceIndex < ulInstanceInfoCount; ulInstanceIndex++)
  1109. {
  1110. bSucceeded = EXECUTEIF (bSucceeded, (ProcessJetInstance (pInstanceInfo + ulInstanceIndex)));
  1111. }
  1112. bSucceeded = EXECUTEIF (bSucceeded, (ProcessIncludeExcludeLists (true )));
  1113. bSucceeded = EXECUTEIF (bSucceeded, (ProcessIncludeExcludeLists (false)));
  1114. bSucceeded = EXECUTEIF (bSucceeded, (m_pwrapper->OnIdentify (pMetadata)));
  1115. PostProcessIncludeExcludeLists (true );
  1116. PostProcessIncludeExcludeLists (false);
  1117. m_pIMetadata = NULL;
  1118. return (bSucceeded);
  1119. } /* CVssIJetWriter::OnIdentify () */
  1120. bool STDMETHODCALLTYPE CVssIJetWriter::OnPrepareBackup (IN IVssWriterComponents *pIVssWriterComponents)
  1121. {
  1122. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnPrepareBackup");
  1123. bool bSucceeded;
  1124. bSucceeded = m_pwrapper->OnPrepareBackupBegin (pIVssWriterComponents);
  1125. bSucceeded = EXECUTEIF (bSucceeded, (m_pwrapper->OnPrepareBackupEnd (pIVssWriterComponents, bSucceeded)));
  1126. if (!bSucceeded)
  1127. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1128. return (bSucceeded);
  1129. } /* CVssIJetWriter::OnPrepareBackup () */
  1130. bool STDMETHODCALLTYPE CVssIJetWriter::OnBackupComplete (IN IVssWriterComponents *pIVssWriterComponents)
  1131. {
  1132. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnBackupComplete");
  1133. bool bSucceeded;
  1134. bSucceeded = m_pwrapper->OnBackupCompleteBegin (pIVssWriterComponents);
  1135. bSucceeded = EXECUTEIF (bSucceeded, (m_pwrapper->OnBackupCompleteEnd (pIVssWriterComponents, bSucceeded)));
  1136. if (!bSucceeded)
  1137. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1138. return (bSucceeded);
  1139. } /* CVssIJetWriter::OnBackupComplete () */
  1140. // log jet error and translate jet error into an appropriate writer error
  1141. JET_ERR CVssIJetWriter::TranslateJetError(JET_ERR err, CVssFunctionTracer &ft, CVssDebugInfo &dbgInfo)
  1142. {
  1143. ft.LogGenericWarning(dbgInfo, L"ESENT ERROR " WSTR_GUID_FMT L" %s: %ld",
  1144. GUID_PRINTF_ARG(m_idWriter), m_wszWriterName, (LONG)err);
  1145. if (err >= JET_errSuccess)
  1146. return err;
  1147. switch (err)
  1148. {
  1149. case JET_errOSSnapshotInvalidSequence:
  1150. default:
  1151. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1152. break;
  1153. case JET_errOutOfThreads:
  1154. case JET_errTooManyIO:
  1155. case errPMOutOfPageSpace:
  1156. case errSPOutOfAvailExtCacheSpace:
  1157. case errSPOutOfOwnExtCacheSpace:
  1158. case JET_errSPAvailExtCacheOutOfMemory:
  1159. case JET_errOutOfMemory:
  1160. case JET_errOutOfDatabaseSpace:
  1161. case JET_errOutOfCursors:
  1162. case JET_errOutOfBuffers:
  1163. case JET_errOutOfFileHandles:
  1164. case JET_errVersionStoreOutOfMemory:
  1165. case JET_errCurrencyStackOutOfMemory:
  1166. case JET_errTooManyMempoolEntries:
  1167. case JET_errOutOfSessions:
  1168. SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES);
  1169. break;
  1170. case JET_errOSSnapshotTimeOut:
  1171. SetWriterFailure(VSS_E_WRITERERROR_TIMEOUT);
  1172. break;
  1173. case JET_errOSSnapshotNotAllowed:
  1174. SetWriterFailure(VSS_E_WRITERERROR_RETRYABLE);
  1175. break;
  1176. }
  1177. return err;
  1178. }
  1179. bool STDMETHODCALLTYPE CVssIJetWriter::OnPrepareSnapshot()
  1180. {
  1181. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnPrepareSnapshot");
  1182. if (!m_pwrapper->OnPrepareSnapshotBegin())
  1183. {
  1184. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1185. return false;
  1186. }
  1187. // go to Jet level directly
  1188. JET_ERR err = JetOSSnapshotPrepare( &m_idJet , 0 );
  1189. bool fSuccess = JET_errSuccess <= err;
  1190. if (!fSuccess)
  1191. TranslateJetError(err, ft, VSSDBG_GEN);
  1192. if (!m_pwrapper->OnPrepareSnapshotEnd(fSuccess))
  1193. {
  1194. if (fSuccess)
  1195. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1196. return false;
  1197. }
  1198. return fSuccess;
  1199. } /* CVssIJetWriter::OnPrepareSnapshot () */
  1200. bool STDMETHODCALLTYPE CVssIJetWriter::OnFreeze()
  1201. {
  1202. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnFreeze");
  1203. unsigned long cInstanceInfo = 0;
  1204. JET_INSTANCE_INFO * aInstanceInfo = NULL;
  1205. bool fDependence = true;
  1206. if (!m_pwrapper->OnFreezeBegin())
  1207. {
  1208. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1209. return false;
  1210. }
  1211. // we need to freeze at Jet level, then check from this DLL the dependencies
  1212. // (as here we hagve the snapshot object implementation and COM registration)
  1213. bool fSuccess = true;
  1214. JET_ERR err = JetOSSnapshotFreeze( m_idJet , &cInstanceInfo, &aInstanceInfo, 0 );
  1215. if ( JET_errSuccess > err)
  1216. {
  1217. fSuccess = false;
  1218. TranslateJetError(err, ft, VSSDBG_GEN);
  1219. }
  1220. else
  1221. {
  1222. // return false if some instances are only partialy affected
  1223. fDependence = FCheckVolumeDependencies(cInstanceInfo, aInstanceInfo);
  1224. (void)JetFreeBuffer( (char *)aInstanceInfo );
  1225. if ( !fDependence )
  1226. {
  1227. SetWriterFailure(VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT);
  1228. // on error, stop the snapshot, return false
  1229. JetOSSnapshotThaw( m_idJet , 0 );
  1230. }
  1231. }
  1232. if (!m_pwrapper->OnFreezeEnd(fSuccess && fDependence))
  1233. {
  1234. if (fDependence && fSuccess)
  1235. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1236. return false;
  1237. }
  1238. return fSuccess && fDependence;
  1239. } /* CVssIJetWriter::OnFreeze () */
  1240. bool STDMETHODCALLTYPE CVssIJetWriter::OnThaw()
  1241. {
  1242. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnThaw");
  1243. bool fSuccess1 = m_pwrapper->OnThawBegin();
  1244. // go to Jet level directly. It will eventualy return timeout errors
  1245. JET_ERR err = JetOSSnapshotThaw( m_idJet , 0 );
  1246. bool fSuccess2 = JET_errSuccess <= err;
  1247. if (!fSuccess2)
  1248. TranslateJetError(err, ft, VSSDBG_GEN);
  1249. if (fSuccess1)
  1250. {
  1251. if (!m_pwrapper->OnThawEnd(fSuccess2))
  1252. {
  1253. if (fSuccess2)
  1254. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1255. return false;
  1256. }
  1257. }
  1258. return fSuccess1 && fSuccess2;
  1259. } /* CVssIJetWriter::OnThaw () */
  1260. bool STDMETHODCALLTYPE CVssIJetWriter::OnPostSnapshot
  1261. (
  1262. IN IVssWriterComponents *pIVssWriterComponents
  1263. )
  1264. {
  1265. if (!m_pwrapper->OnPostSnapshot(pIVssWriterComponents))
  1266. {
  1267. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1268. return false;
  1269. }
  1270. return true;
  1271. }
  1272. bool STDMETHODCALLTYPE CVssIJetWriter::OnAbort()
  1273. {
  1274. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnAbort");
  1275. m_pwrapper->OnAbortBegin();
  1276. JET_ERR err = JetOSSnapshotAbort( m_idJet , 0 );
  1277. if (err < JET_errSuccess)
  1278. TranslateJetError(err, ft, VSSDBG_GEN);
  1279. m_pwrapper->OnAbortEnd();
  1280. return true;
  1281. } /* CVssIJetWriter::OnAbort () */
  1282. bool STDMETHODCALLTYPE CVssIJetWriter::OnPreRestore
  1283. (
  1284. IN IVssWriterComponents *pIVssWriterComponents
  1285. )
  1286. {
  1287. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnPostRestore");
  1288. if (!m_pwrapper->OnPreRestoreBegin(pIVssWriterComponents))
  1289. {
  1290. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1291. return false;
  1292. }
  1293. if (!m_pwrapper->OnPreRestoreEnd(pIVssWriterComponents, true))
  1294. {
  1295. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1296. return false;
  1297. }
  1298. return true;
  1299. } /* CVssIJetWriter::OnPreRestore () */
  1300. bool STDMETHODCALLTYPE CVssIJetWriter::OnPostRestore
  1301. (
  1302. IN IVssWriterComponents *pIVssWriterComponents
  1303. )
  1304. {
  1305. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::OnPostRestore");
  1306. if (!m_pwrapper->OnPostRestoreBegin(pIVssWriterComponents))
  1307. {
  1308. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1309. return false;
  1310. }
  1311. if (!m_pwrapper->OnPostRestoreEnd(pIVssWriterComponents, true))
  1312. {
  1313. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  1314. return false;
  1315. }
  1316. return true;
  1317. } /* CVssIJetWriter::OnPostRestore () */
  1318. bool CVssIJetWriter::FCheckPathVolumeDependencies(const char * szPath) const
  1319. {
  1320. // use static variable in order to avoid alloc/free
  1321. WCHAR wszPath[MAX_PATH];
  1322. if (MultiByteToWideChar(CP_OEMCP, 0, szPath, -1, wszPath, MAX_PATH ) == 0 )
  1323. {
  1324. BS_ASSERT( ERROR_INSUFFICIENT_BUFFER != GetLastError() );
  1325. return false;
  1326. }
  1327. // use standart Writer call to check the affected path
  1328. return IsPathAffected(wszPath);
  1329. } /* CVssIJetWriter::FCheckPathVolumeDependencies () */
  1330. // all or nothing check: all path in instance are affected or none !
  1331. //
  1332. bool CVssIJetWriter::FCheckInstanceVolumeDependencies (const JET_INSTANCE_INFO * pInstanceInfo) const
  1333. {
  1334. BS_ASSERT(pInstanceInfo);
  1335. JET_ERR err = JET_errSuccess;
  1336. bool fAffected;
  1337. bool fAffected1;
  1338. char szPath[ MAX_PATH ];
  1339. // check first system and log path
  1340. err = JetGetSystemParameter( pInstanceInfo->hInstanceId, JET_sesidNil, JET_paramLogFilePath, NULL, szPath, sizeof( szPath ) );
  1341. if ( JET_errSuccess > err )
  1342. return false;
  1343. fAffected = FCheckPathVolumeDependencies( szPath );
  1344. err = JetGetSystemParameter
  1345. (
  1346. pInstanceInfo->hInstanceId,
  1347. JET_sesidNil,
  1348. JET_paramSystemPath,
  1349. NULL,
  1350. szPath,
  1351. sizeof(szPath)
  1352. );
  1353. if (JET_errSuccess > err)
  1354. return false;
  1355. fAffected1 = FCheckPathVolumeDependencies(szPath);
  1356. if ((fAffected && !fAffected1) || (!fAffected && fAffected1))
  1357. return false;
  1358. for (ULONG_PTR iDatabase = 0;
  1359. iDatabase < pInstanceInfo->cDatabases;
  1360. iDatabase++)
  1361. {
  1362. char * szFile = pInstanceInfo->szDatabaseFileName[iDatabase];
  1363. BS_ASSERT(szFile); // we always have a db file name
  1364. fAffected1 = FCheckPathVolumeDependencies(szFile);
  1365. if ((fAffected && !fAffected1) || (!fAffected && fAffected1))
  1366. return false;
  1367. szFile = pInstanceInfo->szDatabaseSLVFileName[iDatabase];
  1368. // if no SLV file, go to next database
  1369. if (!szFile)
  1370. continue;
  1371. fAffected1 = FCheckPathVolumeDependencies(szFile);
  1372. if ((fAffected && !fAffected1) || (!fAffected && fAffected1))
  1373. return false;
  1374. }
  1375. // all set !
  1376. return true;
  1377. } /* CVssIJetWriter::FCheckInstanceVolumeDependencies () */
  1378. bool CVssIJetWriter::FCheckVolumeDependencies
  1379. (
  1380. unsigned long cInstanceInfo,
  1381. JET_INSTANCE_INFO * aInstanceInfo
  1382. ) const
  1383. {
  1384. bool fResult = true;
  1385. // check each instance
  1386. while (cInstanceInfo && fResult)
  1387. {
  1388. cInstanceInfo--;
  1389. fResult = FCheckInstanceVolumeDependencies (aInstanceInfo + cInstanceInfo);
  1390. }
  1391. return fResult;
  1392. } /* CVssIJetWriter::FCheckVolumeDependencies () */
  1393. // internal method to assign basic members
  1394. HRESULT CVssIJetWriter::InternalInitialize (IN VSS_ID idWriter,
  1395. IN LPCWSTR wszWriterName,
  1396. IN bool bSystemService,
  1397. IN bool bBootableSystemState,
  1398. IN LPCWSTR wszFilesToInclude,
  1399. IN LPCWSTR wszFilesToExclude)
  1400. {
  1401. HRESULT hrStatus = NOERROR;
  1402. hrStatus = CVssWriter::Initialize (idWriter,
  1403. wszWriterName,
  1404. bBootableSystemState
  1405. ? VSS_UT_BOOTABLESYSTEMSTATE
  1406. : (bSystemService
  1407. ? VSS_UT_SYSTEMSERVICE
  1408. : VSS_UT_USERDATA),
  1409. VSS_ST_TRANSACTEDDB,
  1410. VSS_APP_BACK_END);
  1411. // hrStatus may be S_FALSE
  1412. if (hrStatus != S_OK)
  1413. return hrStatus;
  1414. m_idWriter = idWriter;
  1415. m_bSystemService = bSystemService;
  1416. m_bBootableSystemState = bBootableSystemState;
  1417. m_wszWriterName = _wcsdup(wszWriterName);
  1418. m_wszFilesToInclude = _wcsdup(wszFilesToInclude);
  1419. m_wszFilesToExclude = _wcsdup(wszFilesToExclude);
  1420. if ((NULL == m_wszWriterName) ||
  1421. (NULL == m_wszFilesToInclude) ||
  1422. (NULL == m_wszFilesToExclude))
  1423. {
  1424. delete m_wszWriterName;
  1425. delete m_wszFilesToInclude;
  1426. delete m_wszFilesToExclude;
  1427. m_wszWriterName = NULL;
  1428. m_wszFilesToInclude = NULL;
  1429. m_wszFilesToExclude = NULL;
  1430. hrStatus = E_OUTOFMEMORY;
  1431. }
  1432. return (hrStatus);
  1433. } /* CVssIJetWriter::InternalInitialize () */
  1434. // do initialization
  1435. HRESULT STDMETHODCALLTYPE CVssIJetWriter::Initialize (IN VSS_ID idWriter, // id of writer
  1436. IN LPCWSTR wszWriterName, // writer name
  1437. IN bool bSystemService, // is this a system service
  1438. IN bool bBootableSystemState, // is this writer part of bootable system state
  1439. IN LPCWSTR wszFilesToInclude, // additional files to include
  1440. IN LPCWSTR wszFilesToExclude, // additional files to exclude
  1441. IN CVssJetWriter *pWriter, // writer wrapper class
  1442. OUT void **ppInstance) // output instance
  1443. {
  1444. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::Initialize");
  1445. try
  1446. {
  1447. // check parameters
  1448. if (ppInstance == NULL)
  1449. {
  1450. ft.Throw (VSSDBG_GEN, E_INVALIDARG, L"NULL output parameter.");
  1451. }
  1452. // change null pointer to null strings for files to include
  1453. // and files to exclude
  1454. if (wszFilesToInclude == NULL)
  1455. wszFilesToInclude = L"";
  1456. if (wszFilesToExclude == NULL)
  1457. wszFilesToExclude = L"";
  1458. if (!ValidateIncludeExcludeList (wszFilesToInclude))
  1459. {
  1460. ft.Throw (VSSDBG_GEN, E_INVALIDARG, L"Bad FilesToInclude list.");
  1461. }
  1462. if (!ValidateIncludeExcludeList (wszFilesToExclude))
  1463. {
  1464. ft.Throw (VSSDBG_GEN, E_INVALIDARG, L"Bad FilesToExclude list.");
  1465. }
  1466. // null output parameter
  1467. *ppInstance = NULL;
  1468. // create instance
  1469. PVSSIJETWRITER pInstance = new CVssIJetWriter;
  1470. // create instance
  1471. ft.ThrowIf (NULL == pInstance,
  1472. VSSDBG_GEN,
  1473. E_OUTOFMEMORY,
  1474. L"FAILED creating CVssIJetWriter object due to allocation failure.");
  1475. // call internal initialization
  1476. ft.hr = pInstance->InternalInitialize (idWriter,
  1477. wszWriterName,
  1478. bSystemService,
  1479. bBootableSystemState,
  1480. wszFilesToInclude,
  1481. wszFilesToExclude);
  1482. ft.ThrowIf (ft.HrFailed(),
  1483. VSSDBG_GEN,
  1484. ft.hr,
  1485. L"FAILED during internal initialisation of CVssIJetWriter object");
  1486. // Subscribe the object.
  1487. ft.hr = pInstance->Subscribe();
  1488. ft.ThrowIf (ft.HrFailed(),
  1489. VSSDBG_GEN,
  1490. ft.hr,
  1491. L"FAILED during internal initialisation of CVssIJetWriter object");
  1492. ((CVssIJetWriter *) pInstance)->m_pwrapper = pWriter;
  1493. *ppInstance = (void *) pInstance;
  1494. } VSS_STANDARD_CATCH(ft)
  1495. return (ft.hr);
  1496. } /* CVssIJetWriter::Initialize () */
  1497. void STDMETHODCALLTYPE CVssIJetWriter::Uninitialize(IN PVSSIJETWRITER pInstance)
  1498. {
  1499. CVssFunctionTracer ft(VSSDBG_GEN, L"CVssIJetWriter::Uninitialize");
  1500. try
  1501. {
  1502. CVssIJetWriter *pWriter = (CVssIJetWriter *) pInstance;
  1503. // Unsubscribe the object.
  1504. BS_ASSERT(pWriter);
  1505. pWriter->Unsubscribe();
  1506. delete pWriter;
  1507. }
  1508. VSS_STANDARD_CATCH(ft)
  1509. } /* CVssIJetWriter::Uninitialize () */