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.

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