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.

13391 lines
428 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. metasub.cxx
  5. Abstract:
  6. IIS MetaBase subroutines to support exported routines
  7. Author:
  8. Michael W. Thomas 31-May-96
  9. Revision History:
  10. Notes:
  11. Most routines in this file assume that g_LockMasterResource is already taken
  12. for read or write as appropriate.
  13. --*/
  14. #include "precomp.hxx"
  15. #if DBG
  16. BOOL g_fShowMetaLocks = FALSE;
  17. #endif DBG
  18. #define _WIDEN(x) L ## x
  19. //
  20. // TODO: Since XML table also uses this cant we reduce to one definition?
  21. //
  22. static WCHAR * kByteToWchar[256] =
  23. {
  24. L"00", L"01", L"02", L"03", L"04", L"05", L"06", L"07", L"08", L"09", L"0a", L"0b", L"0c", L"0d", L"0e", L"0f",
  25. L"10", L"11", L"12", L"13", L"14", L"15", L"16", L"17", L"18", L"19", L"1a", L"1b", L"1c", L"1d", L"1e", L"1f",
  26. L"20", L"21", L"22", L"23", L"24", L"25", L"26", L"27", L"28", L"29", L"2a", L"2b", L"2c", L"2d", L"2e", L"2f",
  27. L"30", L"31", L"32", L"33", L"34", L"35", L"36", L"37", L"38", L"39", L"3a", L"3b", L"3c", L"3d", L"3e", L"3f",
  28. L"40", L"41", L"42", L"43", L"44", L"45", L"46", L"47", L"48", L"49", L"4a", L"4b", L"4c", L"4d", L"4e", L"4f",
  29. L"50", L"51", L"52", L"53", L"54", L"55", L"56", L"57", L"58", L"59", L"5a", L"5b", L"5c", L"5d", L"5e", L"5f",
  30. L"60", L"61", L"62", L"63", L"64", L"65", L"66", L"67", L"68", L"69", L"6a", L"6b", L"6c", L"6d", L"6e", L"6f",
  31. L"70", L"71", L"72", L"73", L"74", L"75", L"76", L"77", L"78", L"79", L"7a", L"7b", L"7c", L"7d", L"7e", L"7f",
  32. L"80", L"81", L"82", L"83", L"84", L"85", L"86", L"87", L"88", L"89", L"8a", L"8b", L"8c", L"8d", L"8e", L"8f",
  33. L"90", L"91", L"92", L"93", L"94", L"95", L"96", L"97", L"98", L"99", L"9a", L"9b", L"9c", L"9d", L"9e", L"9f",
  34. L"a0", L"a1", L"a2", L"a3", L"a4", L"a5", L"a6", L"a7", L"a8", L"a9", L"aa", L"ab", L"ac", L"ad", L"ae", L"af",
  35. L"b0", L"b1", L"b2", L"b3", L"b4", L"b5", L"b6", L"b7", L"b8", L"b9", L"ba", L"bb", L"bc", L"bd", L"be", L"bf",
  36. L"c0", L"c1", L"c2", L"c3", L"c4", L"c5", L"c6", L"c7", L"c8", L"c9", L"ca", L"cb", L"cc", L"cd", L"ce", L"cf",
  37. L"d0", L"d1", L"d2", L"d3", L"d4", L"d5", L"d6", L"d7", L"d8", L"d9", L"da", L"db", L"dc", L"dd", L"de", L"df",
  38. L"e0", L"e1", L"e2", L"e3", L"e4", L"e5", L"e6", L"e7", L"e8", L"e9", L"ea", L"eb", L"ec", L"ed", L"ee", L"ef",
  39. L"f0", L"f1", L"f2", L"f3", L"f4", L"f5", L"f6", L"f7", L"f8", L"f9", L"fa", L"fb", L"fc", L"fd", L"fe", L"ff"
  40. };
  41. static unsigned char kWcharToNibble[128] = //0xff is an illegal value, the illegal values should be weeded out by the parser
  42. { // 0 1 2 3 4 5 6 7 8 9 a b c d e f
  43. /*00*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  44. /*10*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  45. /*20*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  46. /*30*/ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  47. /*40*/ 0xff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  48. /*50*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  49. /*60*/ 0xff, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  50. /*70*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  51. };
  52. HRESULT
  53. ReadAllDataFromXML(LPSTR pszPasswd,
  54. LPSTR pszBackupLocation,
  55. LPSTR pszSchemaLocation,
  56. BOOL bHaveReadSaveSemaphore
  57. );
  58. HRESULT
  59. ReadAllDataFromBin(LPSTR pszPasswd,
  60. LPSTR pszBackupLocation,
  61. BOOL bHaveReadSaveSemaphore
  62. );
  63. HRESULT
  64. ReadMetaObject(IN CMDBaseObject*& cboRead,
  65. IN LPWSTR wszPath,
  66. IN FILETIME* pFileTime,
  67. IN BOOL bUnicode);
  68. HRESULT
  69. SaveMasterRoot(IN CWriter* pCWriter,
  70. IIS_CRYPTO_STORAGE* pCryptoStorage,
  71. PIIS_CRYPTO_BLOB pSessionKeyBlob);
  72. HRESULT
  73. SaveEntireTree(IN IIS_CRYPTO_STORAGE* pCryptoStorage,
  74. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  75. IN METADATA_HANDLE hHandle,
  76. IN LPWSTR pwszSchemaLocation,
  77. IN LPWSTR pwszSchemaFileName,
  78. IN PSECURITY_ATTRIBUTES psaStorage,
  79. IN HANDLE hTempFileHandle);
  80. void
  81. DetermineIfMetabaseCanBeRenamed(LPWSTR pwszBackupLocation,
  82. LPWSTR pwszRealFileName,
  83. BOOL bTerminating,
  84. BOOL* pbRenameMetabase);
  85. HRESULT
  86. SaveMetabaseFile(IN LPWSTR pwszSchemaFileName,
  87. IN DWORD ulHistoryMajorVersionNumber,
  88. IN DWORD dwEnableHistory,
  89. IN DWORD dwMaxHistoryFiles,
  90. IN DWORD dwTempLastSaveChangeNumber,
  91. IN BOOL bRenameMetabase,
  92. IN LPWSTR pwszTempFileName,
  93. IN LPWSTR pwszRealFileName,
  94. IN LPWSTR pwszBackupFileName,
  95. IN LPWSTR pwszBackupLocation,
  96. OUT BOOL* pbDeleteTemp);
  97. HRESULT
  98. SaveTree(IN CWriter* pCWriter,
  99. IN CMDBaseObject* pboRoot,
  100. IN BUFFER* pbufParentPath,
  101. IN IIS_CRYPTO_STORAGE* pCryptoStorage,
  102. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  103. IN BOOL bRecurse = TRUE,
  104. IN BOOL bSaveSchema = TRUE,
  105. IN BOOL bLocalMachine = FALSE);
  106. HRESULT
  107. SaveDataObject(CMDBaseData* pbdSave,
  108. CLocationWriter* pCLocationWriter,
  109. IIS_CRYPTO_STORAGE* pCryptoStorage,
  110. PIIS_CRYPTO_BLOB pSessionKeyBlob);
  111. BOOL
  112. DiscontinuousLocation(LPWSTR wszPreviousLocation,
  113. LPWSTR wszCurrentLocation);
  114. VOID
  115. SaveGlobalsFromLM(CMDBaseData* pbdSave);
  116. HRESULT
  117. InitializeGlobalsFromXML(ISimpleTableRead2* pISTProperty,
  118. LPWSTR wszDataFileName,
  119. LPWSTR wszSchemaFileName,
  120. IIS_CRYPTO_STORAGE** ppStorage,
  121. LPTSTR pszPasswd,
  122. BOOL bCalledFromRestore,
  123. FILETIME *pftLastWriteTimeDataFile);
  124. HRESULT
  125. InitializeIIS6GlobalsToDefaults(ULONG dwPrevSchemaChangeNumber,
  126. ULONG dwSchemaChangeNumber,
  127. LPSTR pszBackupLocation);
  128. HRESULT
  129. SaveGlobalsToXML(CWriter* pCWriter,
  130. PIIS_CRYPTO_BLOB pSessionKeyBlob,
  131. bool bSessionKeyOnly=false);
  132. HRESULT
  133. GetComputerValue(ISimpleTableRead2* pISTProperty,
  134. LPCWSTR wszName,
  135. ULONG* pcbSize,
  136. LPVOID* ppVoid);
  137. HRESULT
  138. GetValue(ISimpleTableRead2* pISTProperty,
  139. LPCWSTR wszPath,
  140. DWORD dwGroup,
  141. LPCWSTR wszName,
  142. ULONG* pcbSize,
  143. LPVOID* ppVoid);
  144. HRESULT
  145. GetUnicodeNameW(IN LPWSTR wszFileName,
  146. OUT LPWSTR* pwszFileName);
  147. HRESULT
  148. GetUnicodeNameA(IN LPSTR szFileName,
  149. OUT LPWSTR* pwszFileName);
  150. HRESULT
  151. InitEditWhileRunning(ISimpleTableRead2* pISTProperty);
  152. HRESULT
  153. InitChangeNumber(ISimpleTableRead2* pISTProperty);
  154. void
  155. ValidateMaxHistoryFiles();
  156. HRESULT
  157. CreateHistoryFile(LPWSTR i_wszFileName,
  158. LPWSTR i_wszHistroyFileDir,
  159. ULONG i_cchHistoryFileDir,
  160. LPWSTR i_wszFileNameWithoutPathWithoutExtension,
  161. ULONG i_cchFileNameWithoutPathWithoutExtension,
  162. LPWSTR i_wszFileNameExtension,
  163. ULONG i_cchFileNameExtension,
  164. ULONG i_ulHistoryMajorVersionNumber);
  165. HRESULT
  166. CreateHistoryFiles(LPWSTR wszDataFileName,
  167. LPWSTR wszSchemaFileName,
  168. ULONG ulHistoryMajorVersionNumber,
  169. DWORD dwMaxHistoryFiles);
  170. HRESULT
  171. CleanupObsoleteHistoryFiles(DWORD i_dwMaxHistoryFiles,
  172. ULONG i_ulHistoryMajorVersionNumber);
  173. HRESULT
  174. DeleteHistoryFile(LPWSTR i_wszHistroyFileDir,
  175. ULONG i_cchHistoryFileDir,
  176. LPWSTR i_wszFileNameWithoutPathWithoutExtension,
  177. ULONG i_cchFileNameWithoutPathWithoutExtension,
  178. LPWSTR i_wszFileNameExtension,
  179. ULONG i_cchFileNameExtension,
  180. ULONG i_ulMajorVersion,
  181. ULONG i_ulMinorVersion);
  182. HRESULT
  183. SaveSchemaIfNeeded(LPCWSTR i_wszTempFile,
  184. PSECURITY_ATTRIBUTES i_pSecurityAtrributes);
  185. HRESULT
  186. ReadSchema(IIS_CRYPTO_STORAGE* i_pStorage,
  187. FILETIME* pFileTime);
  188. BOOL
  189. SchemaTreeInTable(ISimpleTableRead2* i_pISTProperty);
  190. HRESULT
  191. CompileIfNeeded(LPWSTR i_wszDataFileName,
  192. LPWSTR i_wszSchemaFileName,
  193. BOOL* o_pbSchemaFileNotFound);
  194. HRESULT
  195. InitializeGlobalISTHelper(BOOL i_bFailIfBinFileAbsent);
  196. void
  197. ReleaseGlobalISTHelper();
  198. HRESULT
  199. MatchTimeStamp(LPWSTR i_wszDataFileName,
  200. LPWSTR i_wszSchemaXMLFileName,
  201. LPWSTR i_wszSchemaBINFileName,
  202. BOOL* o_bMatchTimeStamp);
  203. HRESULT
  204. ComputeNewHistoryVersionNumber();
  205. BOOL
  206. WstrToUl(
  207. LPCWSTR i_wszSrc,
  208. WCHAR i_wcTerminator,
  209. ULONG* o_pul);
  210. HRESULT
  211. UpdateTimeStamp(LPWSTR i_wszSchemaXMLFileName,
  212. LPWSTR i_wszSchemaBinFileName);
  213. HRESULT
  214. GetTimeStamp(LPWSTR i_wszFile,
  215. LPWSTR i_wszPropertyName,
  216. FILETIME* o_FileTime);
  217. HRESULT
  218. SetSecurityOnFile(LPWSTR i_wszFileSrc,
  219. LPWSTR i_wszFileDest);
  220. HRESULT
  221. LockMetabaseFile(LPWSTR pwszMetabaseFile,
  222. eMetabaseFile eMetabaseFileType,
  223. BOOL bHaveReadSaveSemaphore);
  224. HRESULT
  225. UnlockMetabaseFile(eMetabaseFile eMetabaseFileType,
  226. BOOL bHaveReadSaveSemaphore);
  227. //
  228. // Used by qsort in SaveTree and SaveMasterRoot. In pointers will never
  229. // be null because they are address of array elements.
  230. //
  231. int _cdecl MyComparePBaseObjectContainer(const void *a,
  232. const void *b)
  233. {
  234. MD_ASSERT(NULL != a);
  235. MD_ASSERT(NULL != b);
  236. PBASEOBJECT_CONTAINER pa = *((PBASEOBJECT_CONTAINER*)a);
  237. PBASEOBJECT_CONTAINER pb = *((PBASEOBJECT_CONTAINER*)b);
  238. MD_ASSERT(NULL != pa->pboMetaObject);
  239. MD_ASSERT(NULL != pb->pboMetaObject);
  240. int res = CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, (LPCWSTR)(pa->pboMetaObject->GetName(TRUE)), -1, (LPCWSTR)(pb->pboMetaObject->GetName(TRUE)), -1);
  241. return (res - 2);
  242. // #define CSTR_LESS_THAN 1 // string 1 less than string 2
  243. // #define CSTR_EQUAL 2 // string 1 equal to string 2
  244. // #define CSTR_GREATER_THAN 3 // string 1 greater than string 2
  245. }
  246. //
  247. // Added By Mohit
  248. //
  249. HRESULT
  250. SaveInheritedOnly(IN CWriter* i_pCWriter,
  251. IN CMDBaseObject* i_pboRoot,
  252. IN BUFFER* i_pbufParentPath,
  253. IN IIS_CRYPTO_STORAGE* i_pCryptoStorage,
  254. IN PIIS_CRYPTO_BLOB i_pSessionKeyBlob);
  255. #ifdef UNICODE
  256. #define GetUnicodeName GetUnicodeNameW
  257. #else
  258. #define GetUnicodeName GetUnicodeNameA
  259. #endif // !UNICODE
  260. HRESULT GetObjectFromPath(
  261. OUT CMDBaseObject *&rpboReturn,
  262. IN METADATA_HANDLE hHandle,
  263. IN DWORD dwPermissionNeeded,
  264. IN OUT LPTSTR &strPath,
  265. IN BOOL bUnicode)
  266. /*++
  267. Routine Description:
  268. Finds an object from a path. This function just calls GetHandleObject
  269. and calls the GetObjectFromPathWithHandle function.
  270. Arguments:
  271. Return - The object found.
  272. Handle - The Meta Data handle. METADATA_MASTER_ROOT_HANDLE or a handle
  273. returned by MDOpenMetaObject with read permission.
  274. PermissionNeeded - The read/write permissions needed. Compared with the
  275. permissions associated with Handle.
  276. Path - The path of the object requested, relative to Handle. If the path
  277. is not found, this is updated to point to the portion of the path
  278. not found.
  279. Return Value:
  280. DWORD - ERROR_SUCCESS
  281. ERROR_ACCESS_DENIED
  282. ERROR_PATH_NOT_FOUND
  283. Notes:
  284. --*/
  285. {
  286. CMDHandle *hHandleObject = GetHandleObject(hHandle);
  287. if (hHandleObject == NULL) {
  288. return E_HANDLE;
  289. }
  290. return GetObjectFromPathWithHandle(rpboReturn,
  291. hHandle,
  292. hHandleObject,
  293. dwPermissionNeeded,
  294. strPath,
  295. bUnicode);
  296. }
  297. HRESULT GetObjectFromPathWithHandle(
  298. OUT CMDBaseObject *&rpboReturn,
  299. IN METADATA_HANDLE ,
  300. IN CMDHandle *HandleObject,
  301. IN DWORD dwPermissionNeeded,
  302. IN OUT LPTSTR &strPath,
  303. IN BOOL bUnicode)
  304. /*++
  305. Routine Description:
  306. Finds an object from a path. Updates Path to point past the last
  307. object found if the whole path is not found. If the entire path
  308. is not found, the last object found is returned.
  309. Arguments:
  310. Return - The object found.
  311. Handle - The Meta Data handle. METADATA_MASTER_ROOT_HANDLE or a handle
  312. returned by MDOpenMetaObject with read permission.
  313. PermissionNeeded - The read/write permissions needed. Compared with the
  314. permissions associated with Handle.
  315. Path - The path of the object requested, relative to Handle. If the path
  316. is not found, this is updated to point to the portion of the path
  317. not found.
  318. Return Value:
  319. DWORD - ERROR_SUCCESS
  320. ERROR_ACCESS_DENIED
  321. ERROR_PATH_NOT_FOUND
  322. Notes:
  323. --*/
  324. {
  325. HRESULT hresReturn = ERROR_SUCCESS;
  326. CMDBaseObject *pboCurrent, *pboPrevious = NULL;
  327. LPTSTR strCurPath = strPath;
  328. rpboReturn = NULL;
  329. if ((((dwPermissionNeeded & METADATA_PERMISSION_WRITE) != 0) && (!HandleObject->IsWriteAllowed())) ||
  330. (((dwPermissionNeeded & METADATA_PERMISSION_READ) != 0) && (!HandleObject->IsReadAllowed()))) {
  331. hresReturn = E_ACCESSDENIED;
  332. }
  333. else {
  334. pboCurrent = HandleObject->GetObject();
  335. MD_ASSERT(pboCurrent != NULL);
  336. strCurPath = strPath;
  337. if (strCurPath != NULL) {
  338. SkipPathDelimeter(strCurPath, bUnicode);
  339. while ((pboCurrent != NULL) &&
  340. (!IsStringTerminator(strCurPath, bUnicode))) {
  341. pboPrevious = pboCurrent;
  342. //
  343. // GetChildObject increments strCurPath on success
  344. // and returns NULL if child not found
  345. //
  346. pboCurrent = pboCurrent->GetChildObject(strCurPath, &hresReturn, bUnicode);
  347. if (FAILED(hresReturn)) {
  348. break;
  349. }
  350. if (pboCurrent != NULL) {
  351. SkipPathDelimeter(strCurPath, bUnicode);
  352. }
  353. }
  354. }
  355. if (SUCCEEDED(hresReturn)) {
  356. if ((strCurPath == NULL) ||
  357. IsStringTerminator(strCurPath, bUnicode)) { // Found the whole path
  358. rpboReturn = pboCurrent;
  359. hresReturn = ERROR_SUCCESS;
  360. }
  361. else { //return last object found and an error code
  362. rpboReturn = pboPrevious;
  363. hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  364. strPath = strCurPath;
  365. }
  366. }
  367. }
  368. return (hresReturn);
  369. }
  370. HRESULT AddObjectToDataBase(
  371. IN METADATA_HANDLE hHandle,
  372. IN CMDHandle *hHandleObject,
  373. IN LPTSTR strPath,
  374. IN BOOL bUnicode)
  375. /*++
  376. Routine Description:
  377. Creates and adds one or more objects to the metabase. Finds the deepest object
  378. pointed to by Handle/Path and creates any subobject specified by path.
  379. Arguments:
  380. Handle - The Meta Data handle. METADATA_MASTER_ROOT_HANDLE or a handle
  381. returned by MDOpenMetaObject with read permission.
  382. Path - The path of the object(s) to be created.
  383. Return Value:
  384. DWORD - ERROR_SUCCESS
  385. ERROR_ACCESS_DENIED
  386. ERROR_NOT_ENOUGH_MEMORY
  387. ERROR_INVALID_NAME
  388. Notes:
  389. --*/
  390. {
  391. HRESULT hresReturn=ERROR_SUCCESS;
  392. CMDBaseObject *pboParent;
  393. CMDHandle *phCMDHandleObject;
  394. LPTSTR strTempPath = strPath;
  395. WCHAR strName[METADATA_MAX_NAME_LEN];
  396. HRESULT hresExtractRetCode = ERROR_SUCCESS;
  397. hresReturn = GetObjectFromPathWithHandle(pboParent,
  398. hHandle,
  399. hHandleObject,
  400. METADATA_PERMISSION_WRITE,
  401. strTempPath,
  402. bUnicode);
  403. //
  404. // This should return ERROR_PATH_NOT_FOUND and the parent object,
  405. // with strPath set to the remainder of the path,
  406. // which should be the child name, without a preceding delimeter.
  407. //
  408. if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND) &&
  409. pboParent) {
  410. MD_ASSERT(pboParent != NULL);
  411. for (hresExtractRetCode = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode);
  412. SUCCEEDED(hresExtractRetCode);
  413. hresExtractRetCode = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode)) {
  414. CMDBaseObject *pboNew;
  415. if (bUnicode) {
  416. pboNew = new CMDBaseObject((LPWSTR)strName, NULL);
  417. }
  418. else {
  419. pboNew = new CMDBaseObject((LPSTR)strName, NULL);
  420. }
  421. if (pboNew == NULL) {
  422. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  423. break;
  424. }
  425. else if (!pboNew->IsValid()) {
  426. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  427. delete (pboNew);
  428. break;
  429. }
  430. else {
  431. hresReturn = pboParent->InsertChildObject(pboNew);
  432. if (FAILED(hresReturn)) {
  433. delete (pboNew);
  434. break;
  435. }
  436. else {
  437. pboParent = pboNew;
  438. phCMDHandleObject = GetHandleObject( hHandle );
  439. if( !phCMDHandleObject )
  440. {
  441. return MD_ERROR_DATA_NOT_FOUND;
  442. }
  443. phCMDHandleObject->SetChangeData(pboNew, MD_CHANGE_TYPE_ADD_OBJECT, 0);
  444. }
  445. }
  446. }
  447. }
  448. else if (SUCCEEDED(hresReturn)) {
  449. hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
  450. }
  451. if (hresExtractRetCode == RETURNCODETOHRESULT(ERROR_INVALID_NAME)) {
  452. hresReturn = hresExtractRetCode;
  453. }
  454. return(hresReturn);
  455. }
  456. HRESULT RemoveObjectFromDataBase(
  457. IN METADATA_HANDLE hHandle,
  458. IN CMDHandle *hHandleObject,
  459. IN LPTSTR strPath,
  460. IN BOOL bUnicode)
  461. /*++
  462. Routine Description:
  463. Deletes a metaobject and all subobjects from the database.
  464. Arguments:
  465. Handle - The Meta Data handle. A handle returned by MDOpenMetaObject with write permission.
  466. Path - The path of the object(s) to be created.
  467. Return Value:
  468. DWORD - ERROR_SUCCESS
  469. ERROR_ACCESS_DENIED
  470. ERROR_PATH_NOT_FOUND
  471. ERROR_INVALID_PARAMETER
  472. Notes:
  473. --*/
  474. {
  475. HRESULT hresReturn;
  476. CMDBaseObject *pboDelete;
  477. LPTSTR strTempPath = strPath;
  478. WCHAR strName[METADATA_MAX_NAME_LEN];
  479. //
  480. // Make sure that a valid path was specified
  481. //
  482. SkipPathDelimeter(strTempPath, bUnicode);
  483. hresReturn = ExtractNameFromPath(strTempPath, (LPSTR)strName, bUnicode);
  484. if (FAILED(hresReturn)) {
  485. hresReturn = E_INVALIDARG;
  486. }
  487. else {
  488. strTempPath = strPath;
  489. hresReturn = GetObjectFromPathWithHandle(pboDelete,
  490. hHandle,
  491. hHandleObject,
  492. METADATA_PERMISSION_WRITE,
  493. strTempPath,
  494. bUnicode);
  495. if (SUCCEEDED(hresReturn)) {
  496. hresReturn = (pboDelete->GetParent())->RemoveChildObject(pboDelete);
  497. if (SUCCEEDED(hresReturn)) {
  498. MD_ASSERT(GetHandleObject(hHandle) != NULL);
  499. if (GetHandleObject(hHandle)->SetChangeData(pboDelete, MD_CHANGE_TYPE_DELETE_OBJECT, 0)
  500. != ERROR_SUCCESS) {
  501. delete(pboDelete);
  502. }
  503. }
  504. }
  505. }
  506. return(hresReturn);
  507. }
  508. CMDHandle *GetHandleObject(
  509. IN METADATA_HANDLE hHandle)
  510. /*++
  511. Routine Description:
  512. Gets the handle object associated with Handle.
  513. Arguments:
  514. Handle - The Meta Data handle to get. METADATA_MASTER_ROOT_HANDLE Or a handle
  515. returned by MDOpenMetaObject.
  516. Return Value:
  517. CMDHandle * - The handle object, or NULL if not found.
  518. Notes:
  519. --*/
  520. {
  521. CMDHandle *hoCurrent;
  522. for (hoCurrent = g_phHandleHead;
  523. (hoCurrent != NULL) && (hoCurrent->GetHandleIdentifier() != hHandle);
  524. hoCurrent = hoCurrent->GetNextPtr()) {
  525. }
  526. return (hoCurrent);
  527. }
  528. BOOL
  529. PermissionsAvailable(
  530. IN CMDBaseObject *pboTest,
  531. IN DWORD dwRequestedPermissions,
  532. IN DWORD dwReadThreshHold
  533. )
  534. /*++
  535. Routine Description:
  536. Checks if the requested handle permissions are available for a meta object.
  537. Arguments:
  538. Handle - The Meta Data handle to get. METADATA_MASTER_ROOT_HANDLE Or a handle
  539. returned by MDOpenMetaObject.
  540. RequestedPermissions - The permissions requested.
  541. ReadThreshHold - The number of reads allows on a write request. Normally 0.
  542. Return Value:
  543. BOOL - TRUE if the permissions are available.
  544. Notes:
  545. --*/
  546. {
  547. BOOL bResults = TRUE;
  548. CMDBaseObject *pboCurrent;
  549. MD_ASSERT(pboTest != NULL);
  550. if (dwRequestedPermissions & METADATA_PERMISSION_WRITE) {
  551. if ((pboTest->GetReadPathCounter() != 0) ||
  552. (pboTest->GetWritePathCounter() != 0)) {
  553. bResults = FALSE;
  554. }
  555. if ((pboTest->GetReadCounter() > dwReadThreshHold) || (pboTest->GetWriteCounter() != 0)) {
  556. bResults = FALSE;
  557. }
  558. for (pboCurrent = pboTest->GetParent();bResults && (pboCurrent!=NULL);pboCurrent=pboCurrent->GetParent()) {
  559. if ((pboCurrent->GetReadCounter() != 0) || (pboCurrent->GetWriteCounter() != 0)) {
  560. bResults = FALSE;
  561. }
  562. }
  563. }
  564. else if (dwRequestedPermissions & METADATA_PERMISSION_READ) {
  565. if (pboTest->GetWritePathCounter() != 0) {
  566. bResults = FALSE;
  567. }
  568. for (pboCurrent = pboTest;bResults && (pboCurrent!=NULL);pboCurrent=pboCurrent->GetParent()) {
  569. if (pboCurrent->GetWriteCounter() != 0) {
  570. bResults = FALSE;
  571. }
  572. }
  573. }
  574. else {
  575. MD_ASSERT(FALSE);
  576. }
  577. return (bResults);
  578. }
  579. VOID RemovePermissions(
  580. IN CMDBaseObject *pboAffected,
  581. IN DWORD dwRemovePermissions
  582. )
  583. /*++
  584. Routine Description:
  585. Removes the handle permissions from a meta object.
  586. Arguments:
  587. Affected - The object to remove permissions from.
  588. RemovePermissions - The permissions to remove.
  589. Return Value:
  590. Notes:
  591. --*/
  592. {
  593. MD_ASSERT(pboAffected != NULL);
  594. CMDBaseObject *pboCurrent;
  595. if ((dwRemovePermissions & METADATA_PERMISSION_WRITE) != 0) {
  596. pboAffected->DecrementWriteCounter();
  597. for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
  598. pboCurrent->DecrementWritePathCounter();
  599. }
  600. }
  601. if ((dwRemovePermissions & METADATA_PERMISSION_READ) != 0) {
  602. pboAffected->DecrementReadCounter();
  603. for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
  604. pboCurrent->DecrementReadPathCounter();
  605. }
  606. }
  607. #if DBG
  608. char szBuf[1024];
  609. unsigned long cchSz;
  610. BUFFER bufName;
  611. unsigned long cchBuf = 0;
  612. int wCount;
  613. if (g_fShowMetaLocks)
  614. {
  615. if ((dwRemovePermissions & (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ)) ==
  616. (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ))
  617. {
  618. strcpy(szBuf, "Read/Write");
  619. wCount = pboAffected->GetWriteCounter();
  620. }
  621. else if (dwRemovePermissions & (METADATA_PERMISSION_WRITE))
  622. {
  623. strcpy(szBuf, "Write");
  624. wCount = pboAffected->GetWriteCounter();
  625. }
  626. else if (dwRemovePermissions & (METADATA_PERMISSION_READ))
  627. {
  628. strcpy(szBuf, "Read");
  629. wCount = pboAffected->GetReadCounter();
  630. }
  631. else
  632. {
  633. strcpy(szBuf, "No");
  634. wCount = 0;
  635. }
  636. strcat(szBuf, " perms releasted (%d) on ");
  637. cchSz = (unsigned long)strlen(szBuf);
  638. GetObjectPath(pboAffected, &bufName, cchBuf, g_pboMasterRoot, FALSE);
  639. cchBuf = (cchBuf + cchSz + 2 > (unsigned long)sizeof(szBuf)) ? (unsigned long)sizeof(szBuf) - cchSz - 2 : cchBuf;
  640. memcpy(szBuf + cchSz, bufName.QueryPtr(), cchBuf);
  641. szBuf[cchSz + cchBuf] = '\n';
  642. szBuf[cchSz + cchBuf + 1] = '\0';
  643. DBGPRINTF((DBG_CONTEXT, szBuf, wCount));
  644. }
  645. #endif
  646. }
  647. VOID
  648. AddPermissions(
  649. IN CMDBaseObject *pboAffected,
  650. IN DWORD dwRequestedPermissions
  651. )
  652. /*++
  653. Routine Description:
  654. Adds handle permissions to a meta object.
  655. Arguments:
  656. Affected - The object to remove permissions from.
  657. ReqyestedPermissions - The permissions to add.
  658. Return Value:
  659. Notes:
  660. --*/
  661. {
  662. CMDBaseObject *pboCurrent;
  663. if (((dwRequestedPermissions & METADATA_PERMISSION_WRITE) != 0) &&
  664. ((dwRequestedPermissions & METADATA_PERMISSION_READ) != 0)) {
  665. pboAffected->IncrementWriteCounter();
  666. pboAffected->IncrementReadCounter();
  667. for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
  668. pboCurrent->IncrementWritePathCounter();
  669. pboCurrent->IncrementReadPathCounter();
  670. }
  671. }
  672. else if ((dwRequestedPermissions & METADATA_PERMISSION_WRITE) != 0) {
  673. pboAffected->IncrementWriteCounter();
  674. for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
  675. pboCurrent->IncrementWritePathCounter();
  676. }
  677. }
  678. else if ((dwRequestedPermissions & METADATA_PERMISSION_READ) != 0) {
  679. pboAffected->IncrementReadCounter();
  680. for (pboCurrent = pboAffected->GetParent(); pboCurrent != NULL; pboCurrent = pboCurrent->GetParent()) {
  681. pboCurrent->IncrementReadPathCounter();
  682. }
  683. }
  684. #if DBG
  685. char szBuf[1024];
  686. unsigned long cchSz;
  687. BUFFER bufName;
  688. unsigned long cchBuf = 0;
  689. int wCount;
  690. if (g_fShowMetaLocks)
  691. {
  692. if ((dwRequestedPermissions & (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ)) ==
  693. (METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ))
  694. {
  695. strcpy(szBuf, "Read/Write");
  696. wCount = pboAffected->GetWriteCounter();
  697. }
  698. else if (dwRequestedPermissions & (METADATA_PERMISSION_WRITE))
  699. {
  700. strcpy(szBuf, "Write");
  701. wCount = pboAffected->GetWriteCounter();
  702. }
  703. else if (dwRequestedPermissions & (METADATA_PERMISSION_READ))
  704. {
  705. strcpy(szBuf, "Read");
  706. wCount = pboAffected->GetReadCounter();
  707. }
  708. else
  709. {
  710. strcpy(szBuf, "No");
  711. wCount = 0;
  712. }
  713. strcat(szBuf, " perms obtained (%d) on ");
  714. cchSz = (unsigned long)strlen(szBuf);
  715. GetObjectPath(pboAffected, &bufName, cchBuf, g_pboMasterRoot, FALSE);
  716. cchBuf = (cchBuf + cchSz + 2 > (unsigned long)sizeof(szBuf)) ? (unsigned long)sizeof(szBuf) - cchSz - 2 : cchBuf;
  717. memcpy(szBuf + cchSz, bufName.QueryPtr(), cchBuf);
  718. szBuf[cchSz + cchBuf] = '\n';
  719. szBuf[cchSz + cchBuf + 1] = '\0';
  720. DBGPRINTF((DBG_CONTEXT, szBuf, wCount));
  721. }
  722. #endif
  723. }
  724. HRESULT
  725. AddHandle(
  726. IN CMDBaseObject *pboAssociated,
  727. IN DWORD dwRequestedPermissions,
  728. IN METADATA_HANDLE &rmhNew,
  729. IN BOOLEAN bSchemaKey
  730. )
  731. /*++
  732. Routine Description:
  733. Creates a handle object and adds it to the handle list.
  734. Arguments:
  735. Handle - The object the handle is associated with.
  736. RequestedPermissions - The permissions for the handle.
  737. New - The handle id.
  738. Return Value:
  739. DWORD - ERROR_SUCCESS
  740. ERROR_NOT_ENOUGH_MEMORY
  741. Notes:
  742. --*/
  743. {
  744. HRESULT hresReturn = ERROR_SUCCESS;
  745. CMDHandle *hoNew = new CMDHandle(pboAssociated,
  746. dwRequestedPermissions,
  747. g_dwSystemChangeNumber,
  748. g_mhHandleIdentifier++,
  749. bSchemaKey);
  750. if (hoNew == NULL) {
  751. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  752. }
  753. else {
  754. rmhNew = hoNew->GetHandleIdentifier();
  755. hoNew->SetNextPtr(g_phHandleHead);
  756. g_phHandleHead = hoNew;
  757. AddPermissions(pboAssociated, dwRequestedPermissions);
  758. }
  759. return(hresReturn);
  760. }
  761. CMDHandle *
  762. RemoveHandleObject(
  763. IN METADATA_HANDLE mhHandle
  764. )
  765. /*++
  766. Routine Description:
  767. Removes a handle object from the handle list.
  768. Arguments:
  769. Handle - The handle to be removed.
  770. Return Value:
  771. CMDHandle * - The Handle object removed.
  772. Notes:
  773. --*/
  774. {
  775. CMDHandle *hoCurrent;
  776. CMDHandle *hoReturn;
  777. if (g_phHandleHead->GetHandleIdentifier() == mhHandle) {
  778. hoReturn = g_phHandleHead;
  779. g_phHandleHead = g_phHandleHead->GetNextPtr();
  780. }
  781. else {
  782. for (hoCurrent = g_phHandleHead;(hoCurrent->GetNextPtr() != NULL) &&
  783. (hoCurrent->GetNextPtr()->GetHandleIdentifier() != mhHandle);
  784. hoCurrent = hoCurrent->GetNextPtr()) {
  785. }
  786. hoReturn = hoCurrent->GetNextPtr();
  787. if (hoCurrent->GetNextPtr() != NULL) {
  788. MD_ASSERT (hoCurrent->GetNextPtr()->GetHandleIdentifier() == mhHandle);
  789. hoCurrent->SetNextPtr(hoCurrent->GetNextPtr()->GetNextPtr());
  790. }
  791. }
  792. return (hoReturn);
  793. }
  794. HRESULT
  795. SaveDataObject(HANDLE hFileHandle,
  796. CMDBaseData *pbdSave,
  797. PBYTE pbLineBuf,
  798. DWORD dwWriteBufSize,
  799. PBYTE pbWriteBuf,
  800. PBYTE &pbrNextPtr,
  801. IIS_CRYPTO_STORAGE *pCryptoStorage
  802. )
  803. /*++
  804. Routine Description:
  805. Save a data object.
  806. Arguments:
  807. FileHandle - File handle for use by WriteLine.
  808. Save - The data object to save.
  809. LineBuf - The line buffer to write string to.
  810. WriteBufSize - Buffer size for use by WriteLine.
  811. WriteBuf - Buffer for use by WriteLine.
  812. NextPtr - Pointer into WriteBuf for use by WriteLine.
  813. CryptoStorage - Used to encrypt secure data.
  814. Return Value:
  815. DWORD - ERROR_SUCCESS
  816. Return codes from file system
  817. Notes:
  818. --*/
  819. {
  820. HRESULT hresReturn = ERROR_SUCCESS;
  821. DWORD dwTemp;
  822. if ((pbdSave->GetAttributes() & METADATA_VOLATILE) == 0) {
  823. *pbLineBuf = MD_ID_DATA;
  824. hresReturn = WriteLine(hFileHandle,
  825. dwWriteBufSize,
  826. pbWriteBuf,
  827. pbLineBuf,
  828. pbrNextPtr,
  829. 1,
  830. FALSE);
  831. if (SUCCEEDED(hresReturn)) {
  832. dwTemp = pbdSave->GetIdentifier();
  833. hresReturn = WriteLine(hFileHandle,
  834. dwWriteBufSize,
  835. pbWriteBuf,
  836. (PBYTE)&dwTemp,
  837. pbrNextPtr,
  838. sizeof(DWORD),
  839. FALSE);
  840. }
  841. if (SUCCEEDED(hresReturn)) {
  842. dwTemp = pbdSave->GetAttributes();
  843. hresReturn = WriteLine(hFileHandle,
  844. dwWriteBufSize,
  845. pbWriteBuf,
  846. (PBYTE)&dwTemp,
  847. pbrNextPtr,
  848. sizeof(DWORD),
  849. FALSE);
  850. }
  851. if (SUCCEEDED(hresReturn)) {
  852. dwTemp = pbdSave->GetUserType();
  853. hresReturn = WriteLine(hFileHandle,
  854. dwWriteBufSize,
  855. pbWriteBuf,
  856. (PBYTE)&dwTemp,
  857. pbrNextPtr,
  858. sizeof(DWORD),
  859. FALSE);
  860. }
  861. if (SUCCEEDED(hresReturn)) {
  862. dwTemp = pbdSave->GetDataType();
  863. hresReturn = WriteLine(hFileHandle,
  864. dwWriteBufSize,
  865. pbWriteBuf,
  866. (PBYTE)&dwTemp,
  867. pbrNextPtr,
  868. sizeof(DWORD),
  869. FALSE);
  870. }
  871. if (SUCCEEDED(hresReturn)) {
  872. if (pbdSave->GetData(TRUE) == NULL) {
  873. //
  874. // This is to make sure that unicode conversion doesn't cause an error.
  875. //
  876. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  877. }
  878. else {
  879. if (IsSecureMetadata(pbdSave->GetIdentifier(), pbdSave->GetAttributes())) {
  880. PIIS_CRYPTO_BLOB blob;
  881. //
  882. // This is a secure data object, so encrypt it before saving it
  883. // to the file.
  884. //
  885. MD_ASSERT(pCryptoStorage != NULL);
  886. hresReturn = pCryptoStorage->EncryptData( &blob,
  887. pbdSave->GetData(TRUE),
  888. pbdSave->GetDataLen(TRUE),
  889. 0);
  890. if (SUCCEEDED(hresReturn)) {
  891. hresReturn = WriteLine(hFileHandle,
  892. dwWriteBufSize,
  893. pbWriteBuf,
  894. (PBYTE)blob,
  895. pbrNextPtr,
  896. IISCryptoGetBlobLength(blob),
  897. TRUE);
  898. ::IISCryptoFreeBlob(blob);
  899. }
  900. } else {
  901. hresReturn = WriteLine(hFileHandle,
  902. dwWriteBufSize,
  903. pbWriteBuf,
  904. (PBYTE)pbdSave->GetData(TRUE),
  905. pbrNextPtr,
  906. pbdSave->GetDataLen(TRUE),
  907. TRUE);
  908. }
  909. }
  910. }
  911. }
  912. return (hresReturn);
  913. }
  914. HRESULT
  915. SaveMasterRoot(HANDLE hFileHandle,
  916. PBYTE pbLineBuf,
  917. DWORD dwWriteBufSize,
  918. PBYTE pbWriteBuf,
  919. PBYTE &pbrNextPtr,
  920. IIS_CRYPTO_STORAGE *pCryptoStorage
  921. )
  922. /*++
  923. Routine Description:
  924. Save the master root object, including its data objects.
  925. Arguments:
  926. FileHandle - File handle for use by WriteLine.
  927. LineBuf - The line buffer to write string to.
  928. WriteBufSize - Buffer size for use by WriteLine.
  929. WriteBuf - Buffer for use by WriteLine.
  930. NextPtr - Pointer into WriteBuf for use by WriteLine.
  931. CryptoStorage - Used to encrypt secure data.
  932. Return Value:
  933. DWORD - ERROR_SUCCESS
  934. Return codes from file system
  935. Notes:
  936. --*/
  937. {
  938. HRESULT hresReturn = ERROR_SUCCESS;
  939. CMDBaseData *dataAssociatedData;
  940. DWORD dwEnumObjectIndex;
  941. PFILETIME pftTime;
  942. pftTime = g_pboMasterRoot->GetLastChangeTime();
  943. *pbLineBuf = MD_ID_ROOT_OBJECT;
  944. hresReturn = WriteLine(hFileHandle,
  945. dwWriteBufSize,
  946. pbWriteBuf,
  947. pbLineBuf,
  948. pbrNextPtr,
  949. 1,
  950. FALSE);
  951. if (SUCCEEDED(hresReturn)) {
  952. hresReturn = WriteLine(hFileHandle,
  953. dwWriteBufSize,
  954. pbWriteBuf,
  955. (PBYTE)pftTime,
  956. pbrNextPtr,
  957. sizeof(FILETIME),
  958. TRUE);
  959. }
  960. for(dwEnumObjectIndex=0,dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
  961. (SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
  962. dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
  963. hresReturn = SaveDataObject(hFileHandle,
  964. dataAssociatedData,
  965. pbLineBuf,
  966. dwWriteBufSize,
  967. pbWriteBuf,
  968. pbrNextPtr,
  969. pCryptoStorage
  970. );
  971. }
  972. return(hresReturn);
  973. }
  974. HRESULT
  975. SaveTree(
  976. IN HANDLE hFileHandle,
  977. IN CMDBaseObject *pboRoot,
  978. IN PBYTE pbLineBuf,
  979. IN BUFFER *pbufParentPath,
  980. IN DWORD dwWriteBufSize,
  981. IN PBYTE pbWriteBuf,
  982. IN OUT PBYTE &pbrNextPtr,
  983. IN IIS_CRYPTO_STORAGE *pCryptoStorage
  984. )
  985. /*++
  986. Routine Description:
  987. Save a tree, recursively saving child objects. This works out as
  988. a depth first save.
  989. Arguments:
  990. FileHandle - File handle for use by WriteLine.
  991. Root - The root of the tree to save.
  992. LineBuf - The line buffer to write string to.
  993. WriteBufSize - Buffer size for use by WriteLine.
  994. WriteBuf - Buffer for use by WriteLine.
  995. NextPtr - Pointer into WriteBuf for use by WriteLine.
  996. CryptoStorage - Used to encrypt secure data.
  997. Return Value:
  998. DWORD - ERROR_SUCCESS
  999. Return codes from file system
  1000. Notes:
  1001. --*/
  1002. {
  1003. HRESULT hresReturn = ERROR_SUCCESS;
  1004. CMDBaseObject *objChildObject;
  1005. CMDBaseData *dataAssociatedData;
  1006. DWORD dwEnumObjectIndex;
  1007. DWORD dwParentPathLen, dwNewParentPathLen;
  1008. DWORD dwNameLen;
  1009. LPWSTR strParentPath;
  1010. PFILETIME pftTime;
  1011. dwParentPathLen = (DWORD)wcslen((LPWSTR)pbufParentPath->QueryPtr());
  1012. if (pboRoot->GetName(TRUE) == NULL) {
  1013. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1014. }
  1015. else {
  1016. dwNameLen = (DWORD)wcslen((LPWSTR)pboRoot->GetName(TRUE));
  1017. //
  1018. // include 1 for delimeter and 1 for \0
  1019. //
  1020. dwNewParentPathLen = dwParentPathLen + dwNameLen + 2;
  1021. if (!pbufParentPath->Resize((dwNewParentPathLen) * sizeof(WCHAR))) {
  1022. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1023. }
  1024. else {
  1025. strParentPath = (LPWSTR)pbufParentPath->QueryPtr();
  1026. wcscat(strParentPath, (LPWSTR)pboRoot->GetName(TRUE));
  1027. strParentPath[dwParentPathLen + dwNameLen] = MD_PATH_DELIMETERW;
  1028. strParentPath[dwNewParentPathLen - 1] = (WCHAR)L'\0';
  1029. pftTime = pboRoot->GetLastChangeTime();
  1030. *pbLineBuf = MD_ID_OBJECT;
  1031. hresReturn = WriteLine(hFileHandle,
  1032. dwWriteBufSize,
  1033. pbWriteBuf,
  1034. pbLineBuf,
  1035. pbrNextPtr,
  1036. 1,
  1037. FALSE);
  1038. if (SUCCEEDED(hresReturn)) {
  1039. hresReturn = WriteLine(hFileHandle,
  1040. dwWriteBufSize,
  1041. pbWriteBuf,
  1042. (PBYTE)pftTime,
  1043. pbrNextPtr,
  1044. sizeof(FILETIME),
  1045. FALSE);
  1046. }
  1047. if (SUCCEEDED(hresReturn)) {
  1048. hresReturn = WriteLine(hFileHandle,
  1049. dwWriteBufSize,
  1050. pbWriteBuf,
  1051. (PBYTE) strParentPath,
  1052. pbrNextPtr,
  1053. (dwNewParentPathLen) * sizeof(WCHAR),
  1054. TRUE);
  1055. }
  1056. if (SUCCEEDED(hresReturn)) {
  1057. for(dwEnumObjectIndex=0,dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
  1058. (SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
  1059. dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
  1060. hresReturn = SaveDataObject(hFileHandle,
  1061. dataAssociatedData,
  1062. pbLineBuf,
  1063. dwWriteBufSize,
  1064. pbWriteBuf,
  1065. pbrNextPtr,
  1066. pCryptoStorage
  1067. );
  1068. }
  1069. for(dwEnumObjectIndex=0,objChildObject=pboRoot->EnumChildObject(dwEnumObjectIndex++);
  1070. (SUCCEEDED(hresReturn)) && (objChildObject!=NULL);
  1071. objChildObject=pboRoot->EnumChildObject(dwEnumObjectIndex++)) {
  1072. hresReturn = SaveTree(hFileHandle,
  1073. objChildObject,
  1074. pbLineBuf,
  1075. pbufParentPath,
  1076. dwWriteBufSize,
  1077. pbWriteBuf,
  1078. pbrNextPtr,
  1079. pCryptoStorage
  1080. );
  1081. }
  1082. }
  1083. //
  1084. // Buffer may have changed, so don't use strParentPath
  1085. //
  1086. ((LPWSTR)pbufParentPath->QueryPtr())[dwParentPathLen] = (WCHAR)L'\0';
  1087. }
  1088. }
  1089. return(hresReturn);
  1090. }
  1091. HRESULT
  1092. ReadMetaObject(
  1093. IN CMDBaseObject *&cboRead,
  1094. IN BUFFER *pbufLine,
  1095. IN DWORD dwLineLen,
  1096. IN IIS_CRYPTO_STORAGE *,
  1097. IN BOOL bUnicode)
  1098. /*++
  1099. Routine Description:
  1100. Read a meta object. Given a string with the object info.,
  1101. create the object and add it to the database.
  1102. Arguments:
  1103. Read - Place to return the created object.
  1104. ObjectLine - The object info.
  1105. CryptoStorage - Used to decrypt secure data.
  1106. Return Value:
  1107. DWORD - ERROR_SUCCESS
  1108. ERROR_NOT_ENOUGH_MEMORY
  1109. ERROR_ALREADY_EXISTS
  1110. Notes:
  1111. --*/
  1112. {
  1113. HRESULT hresReturn;
  1114. CMDBaseObject *pboParent;
  1115. WCHAR strName[METADATA_MAX_NAME_LEN];
  1116. FILETIME ftTime;
  1117. PFILETIME pftParentTime;
  1118. FILETIME ftParentTime;
  1119. PBYTE pbLine = (PBYTE)pbufLine->QueryPtr();
  1120. LPTSTR strObjectName;
  1121. if ((dwLineLen <= BASEMETAOBJECTLENGTH) || (*(pbLine + dwLineLen - 1) != '\0')) {
  1122. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1123. }
  1124. else {
  1125. ftTime = *(UNALIGNED FILETIME *)(pbLine + 1);
  1126. //
  1127. // GetObjectFromPath checks permissions on the handle
  1128. // This only gets called from init so just tell it read.
  1129. //
  1130. strObjectName = (LPTSTR)(pbLine + BASEMETAOBJECTLENGTH);
  1131. if (bUnicode != FALSE) {
  1132. PCUWSTR strObjectNameUnaligned;
  1133. PCWSTR strObjectNameAligned;
  1134. //
  1135. // Generate an aligned copy of the string
  1136. //
  1137. strObjectNameUnaligned = (PCUWSTR)strObjectName;
  1138. #pragma warning(push, 3)
  1139. WSTR_ALIGNED_STACK_COPY(&strObjectNameAligned,
  1140. strObjectNameUnaligned);
  1141. #pragma warning(pop)
  1142. strObjectName = (LPTSTR)strObjectNameAligned;
  1143. }
  1144. hresReturn = GetObjectFromPath(pboParent,
  1145. METADATA_MASTER_ROOT_HANDLE,
  1146. METADATA_PERMISSION_READ,
  1147. strObjectName,
  1148. bUnicode);
  1149. //
  1150. // This should return ERROR_PATH_NOT_FOUND and the parent object,
  1151. // with strObjectLine set to the remainder of the path,
  1152. // which should be the child name, without a preceding delimeter.
  1153. //
  1154. if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
  1155. MD_ASSERT(pboParent != NULL);
  1156. if (bUnicode) {
  1157. hresReturn = ExtractNameFromPath((LPWSTR *)&strObjectName, (LPWSTR)strName);
  1158. }
  1159. else {
  1160. hresReturn = ExtractNameFromPath((LPSTR)strObjectName, (LPSTR)strName);
  1161. }
  1162. if (SUCCEEDED(hresReturn)) {
  1163. CMDBaseObject *pboNew;
  1164. if (bUnicode) {
  1165. pboNew = new CMDBaseObject((LPWSTR)strName, NULL);
  1166. }
  1167. else {
  1168. pboNew = new CMDBaseObject((LPSTR)strName, NULL);
  1169. }
  1170. if (pboNew == NULL) {
  1171. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1172. }
  1173. else if (!pboNew->IsValid()) {
  1174. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1175. delete (pboNew);
  1176. }
  1177. else {
  1178. //
  1179. // InsertChildObject sets the last change time to current time.
  1180. // This isn't really a change, so save and restore time.
  1181. //
  1182. pftParentTime = pboParent->GetLastChangeTime();
  1183. ftParentTime = *pftParentTime;
  1184. hresReturn = pboParent->InsertChildObject(pboNew);
  1185. if (SUCCEEDED(hresReturn)) {
  1186. pboParent->SetLastChangeTime(&ftParentTime);
  1187. pboNew->SetLastChangeTime(&ftTime);
  1188. cboRead = pboNew;
  1189. }
  1190. else {
  1191. delete (pboNew);
  1192. }
  1193. }
  1194. }
  1195. }
  1196. else if (SUCCEEDED(hresReturn)) {
  1197. hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
  1198. }
  1199. }
  1200. return (hresReturn);
  1201. }
  1202. HRESULT
  1203. ReadDataObject(
  1204. IN CMDBaseObject *cboAssociated,
  1205. IN BUFFER *pbufLine,
  1206. IN DWORD dwLineLen,
  1207. IN IIS_CRYPTO_STORAGE *pCryptoStorage,
  1208. IN BOOL bUnicode
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. Read a data object. Given a string with the object info.,
  1213. create the object and add it to the database.
  1214. Arguments:
  1215. Associated - The associated meta object.
  1216. DataLine - The data info.
  1217. BinaryBuf - Buffer to use in UUDecode.
  1218. CryptoStorage - Used to decrypt secure data.
  1219. Return Value:
  1220. DWORD - ERROR_SUCCESS
  1221. ERROR_NOT_ENOUGH_MEMORY
  1222. ERROR_ALREADY_EXISTS
  1223. ERROR_INVALID_DATA
  1224. Notes:
  1225. --*/
  1226. {
  1227. HRESULT hresReturn = ERROR_SUCCESS;
  1228. METADATA_RECORD mdrData;
  1229. PFILETIME pftTime;
  1230. FILETIME ftTime;
  1231. PBYTE pbDataLine = (PBYTE)pbufLine->QueryPtr();
  1232. PBYTE pbDataValue;
  1233. STACK_BUFFER( bufAlignedValue, 256 );
  1234. DWORD dwDataLength;
  1235. PIIS_CRYPTO_BLOB blob = NULL;
  1236. if (dwLineLen < DATAOBJECTBASESIZE) {
  1237. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1238. }
  1239. else {
  1240. MD_ASSERT(pbufLine->QuerySize() >= DATAOBJECTBASESIZE);
  1241. mdrData.dwMDIdentifier = *(UNALIGNED DWORD *)(pbDataLine + 1);
  1242. mdrData.dwMDAttributes = *(UNALIGNED DWORD *)(pbDataLine + 1 + sizeof(DWORD));
  1243. mdrData.dwMDUserType = *(UNALIGNED DWORD *)(pbDataLine + 1 + (2 * sizeof(DWORD)));
  1244. mdrData.dwMDDataType = *(UNALIGNED DWORD *)(pbDataLine + 1 + (3 * sizeof(DWORD)));
  1245. pbDataValue = pbDataLine + DATAOBJECTBASESIZE;
  1246. dwDataLength = dwLineLen - DATAOBJECTBASESIZE;
  1247. if (IsSecureMetadata(mdrData.dwMDIdentifier, mdrData.dwMDAttributes) &&
  1248. pCryptoStorage != NULL) {
  1249. //
  1250. // This is a secure data object, we we'll need to decrypt it
  1251. // before proceeding. Note that we must clone the blob before
  1252. // we can actually use it, as the blob data in the line buffer
  1253. // is not DWORD-aligned. (IISCryptoCloneBlobFromRawData() is
  1254. // the only IISCrypto function that can handle unaligned data.)
  1255. //
  1256. hresReturn = ::IISCryptoCloneBlobFromRawData(
  1257. &blob,
  1258. pbDataValue,
  1259. dwDataLength
  1260. );
  1261. if (SUCCEEDED(hresReturn)) {
  1262. DWORD dummyRegType;
  1263. MD_ASSERT(::IISCryptoIsValidBlob(blob));
  1264. hresReturn = pCryptoStorage->DecryptData(
  1265. (PVOID *)&pbDataValue,
  1266. &dwDataLength,
  1267. &dummyRegType,
  1268. blob
  1269. );
  1270. }
  1271. } else {
  1272. //
  1273. // The metadata was not secure, so decryption was not required.
  1274. // Nonetheless, it must be copied to an aligned buffer...
  1275. //
  1276. if( !bufAlignedValue.Resize( dwDataLength ) )
  1277. {
  1278. hresReturn = HRESULT_FROM_WIN32( GetLastError() );
  1279. }
  1280. else
  1281. {
  1282. memcpy( bufAlignedValue.QueryPtr(), pbDataValue, dwDataLength );
  1283. pbDataValue = ( PBYTE )bufAlignedValue.QueryPtr();
  1284. }
  1285. }
  1286. if (SUCCEEDED(hresReturn)) {
  1287. mdrData.pbMDData = pbDataValue;
  1288. switch (mdrData.dwMDDataType) {
  1289. case DWORD_METADATA: {
  1290. if (dwDataLength != sizeof(DWORD)) {
  1291. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1292. }
  1293. break;
  1294. }
  1295. case STRING_METADATA:
  1296. case EXPANDSZ_METADATA:
  1297. {
  1298. if ((LONG)dwDataLength < 1 ||
  1299. (!bUnicode && (pbDataValue[dwDataLength-1] != '\0')) ||
  1300. (bUnicode && *(((LPWSTR)pbDataValue) + ((dwDataLength / sizeof(WCHAR)) -1)) != (WCHAR)L'\0')) {
  1301. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1302. }
  1303. break;
  1304. }
  1305. case BINARY_METADATA:
  1306. {
  1307. mdrData.dwMDDataLen = dwDataLength;
  1308. break;
  1309. }
  1310. case MULTISZ_METADATA:
  1311. {
  1312. if (bUnicode) {
  1313. if (dwDataLength < (2 * sizeof(WCHAR)) ||
  1314. *((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-1)) != (WCHAR)L'\0' ||
  1315. *((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-2)) != (WCHAR)L'\0') {
  1316. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1317. }
  1318. }
  1319. else {
  1320. if (dwDataLength < 2 ||
  1321. pbDataValue[dwDataLength-1] != '\0' ||
  1322. pbDataValue[dwDataLength-2] != '\0') {
  1323. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1324. }
  1325. }
  1326. if (SUCCEEDED(hresReturn)) {
  1327. mdrData.dwMDDataLen = dwDataLength;
  1328. }
  1329. break;
  1330. }
  1331. default: {
  1332. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  1333. }
  1334. }
  1335. }
  1336. }
  1337. if (SUCCEEDED(hresReturn)) {
  1338. //
  1339. // SetDataObject sets the last change time to current time.
  1340. // This isn't really a change, so save and restore time.
  1341. //
  1342. pftTime = cboAssociated->GetLastChangeTime();
  1343. ftTime = *pftTime;
  1344. hresReturn = cboAssociated->SetDataObject(&mdrData, bUnicode);
  1345. cboAssociated->SetLastChangeTime(&ftTime);
  1346. }
  1347. if (blob != NULL) {
  1348. ::IISCryptoFreeBlob(blob);
  1349. }
  1350. return(hresReturn);
  1351. }
  1352. HRESULT
  1353. FlushWriteBuf(HANDLE hWriteFileHandle,
  1354. PBYTE pbWriteBuf,
  1355. PBYTE &pbrNextPtr)
  1356. /*++
  1357. Routine Description:
  1358. Flush the write buffer to the file.
  1359. Arguments:
  1360. FileHandle - File handle to write to.
  1361. WriteBuf - Buffer to write to file.
  1362. NextPtr - Pointer past end of buffer.
  1363. Return Value:
  1364. DWORD - ERROR_SUCCESS
  1365. Return codes from file system
  1366. Notes:
  1367. --*/
  1368. {
  1369. DWORD dwReturn = ERROR_SUCCESS;
  1370. DWORD dwBytesWritten;
  1371. if (pbrNextPtr > pbWriteBuf) {
  1372. if (!WriteFile(hWriteFileHandle,
  1373. pbWriteBuf,
  1374. (DWORD)DIFF((BYTE *)pbrNextPtr - (BYTE *)pbWriteBuf),
  1375. &dwBytesWritten,
  1376. NULL)) {
  1377. dwReturn = GetLastError();
  1378. }
  1379. }
  1380. return (RETURNCODETOHRESULT(dwReturn));
  1381. }
  1382. BOOL
  1383. CopyLineWithEscapes(PBYTE &pbrFileBuf,
  1384. DWORD &dwrFileBufLen,
  1385. PBYTE &pbrLineBuf,
  1386. DWORD &dwrLineBufLen,
  1387. BOOL &brMidEscape)
  1388. //
  1389. // CopyLineWithExcapes updates parameters.
  1390. // SUCCESS: pbrFileBuf, dwrFileBufLen, brMidEscape
  1391. // FAILURE: pbrLineBuf, dwrLineBufLen, brMidEscape
  1392. // On FAILURE, it fills to the end of the buffer
  1393. //
  1394. {
  1395. BOOL bReturn = TRUE;
  1396. PBYTE pbFileBufEnd = pbrFileBuf + dwrFileBufLen;
  1397. PBYTE pbLineBufEnd = pbrLineBuf + dwrLineBufLen;
  1398. PBYTE pbFileBufIndex = pbrFileBuf;
  1399. PBYTE pbLineBufIndex = pbrLineBuf;
  1400. brMidEscape = FALSE;
  1401. while ((pbLineBufIndex < pbLineBufEnd) && (pbFileBufIndex < (pbFileBufEnd - 1))) {
  1402. if (NEEDS_ESCAPE(*pbLineBufIndex)) {
  1403. *pbFileBufIndex++ = MD_ESCAPE_BYTE;
  1404. }
  1405. *pbFileBufIndex++ = *pbLineBufIndex++;
  1406. }
  1407. if ((pbLineBufIndex != pbLineBufEnd) && (pbFileBufIndex < pbFileBufEnd)) {
  1408. MD_ASSERT(pbFileBufIndex == (pbFileBufEnd - 1));
  1409. //
  1410. // file last byte in buffer
  1411. //
  1412. if (NEEDS_ESCAPE(*pbLineBufIndex)) {
  1413. *pbFileBufIndex++ = MD_ESCAPE_BYTE;
  1414. brMidEscape = TRUE;
  1415. }
  1416. else {
  1417. *pbFileBufIndex++ = *pbLineBufIndex++;
  1418. }
  1419. }
  1420. if (pbLineBufIndex != pbLineBufEnd) {
  1421. bReturn = FALSE;
  1422. pbrLineBuf = pbLineBufIndex;
  1423. dwrLineBufLen = (DWORD)DIFF(pbLineBufEnd - pbLineBufIndex);
  1424. }
  1425. else {
  1426. pbrFileBuf = pbFileBufIndex;
  1427. dwrFileBufLen = (DWORD)DIFF(pbFileBufEnd - pbFileBufIndex);
  1428. }
  1429. return bReturn;
  1430. }
  1431. HRESULT
  1432. WriteLine(HANDLE hWriteFileHandle,
  1433. DWORD dwWriteBufSize,
  1434. PBYTE pbWriteBuf,
  1435. PBYTE pbLineBuf,
  1436. PBYTE &pbNextPtr,
  1437. DWORD dwLineLen,
  1438. BOOL bTerminate)
  1439. /*++
  1440. Routine Description:
  1441. Write a line. Performs buffered writes to a file. Does not append \n.
  1442. The string does not need to be terminated with \0.
  1443. Arguments:
  1444. FileHandle - File to write to.
  1445. WriteBufSize - Buffer size.
  1446. WriteBuf - Buffer to store data in.
  1447. LineBuf - The line buffer with data to write.
  1448. NextPtr - Pointer to the next unused character in WriteBuf.
  1449. Len - The number of characters to write.
  1450. Return Value:
  1451. DWORD - ERROR_SUCCESS
  1452. Return codes from file system
  1453. Notes:
  1454. --*/
  1455. {
  1456. DWORD dwReturn = ERROR_SUCCESS;
  1457. PBYTE pbWriteBufEnd = pbWriteBuf + dwWriteBufSize;
  1458. DWORD dwBufferBytesLeft = (DWORD)DIFF(pbWriteBufEnd - pbNextPtr);
  1459. DWORD dwBytesWritten;
  1460. BOOL bMidEscape;
  1461. MD_ASSERT(pbLineBuf != NULL);
  1462. MD_ASSERT(pbWriteBuf != NULL);
  1463. MD_ASSERT((pbNextPtr >= pbWriteBuf) && (pbNextPtr <= pbWriteBufEnd));
  1464. //
  1465. // CopyLineWithExcapes updates parameters.
  1466. // SUCCESS: pbNextPtr, dwBufferBytesLeft
  1467. // FAILURE: pbLineBuf, dwLineLen, bMidEscape
  1468. // On FAILURE, it fills to the end of the buffer
  1469. //
  1470. while ((dwReturn == ERROR_SUCCESS) &&
  1471. (!CopyLineWithEscapes(pbNextPtr, dwBufferBytesLeft, pbLineBuf, dwLineLen, bMidEscape))) {
  1472. if (!WriteFile(hWriteFileHandle,
  1473. pbWriteBuf,
  1474. dwWriteBufSize,
  1475. &dwBytesWritten,
  1476. NULL)) {
  1477. dwReturn = GetLastError();
  1478. }
  1479. dwBufferBytesLeft = dwWriteBufSize;
  1480. pbNextPtr = pbWriteBuf;
  1481. if (bMidEscape) {
  1482. *pbNextPtr++ = *pbLineBuf++;
  1483. dwBufferBytesLeft--;
  1484. dwLineLen--;
  1485. }
  1486. }
  1487. if (bTerminate && (dwReturn == ERROR_SUCCESS)) {
  1488. if (dwBufferBytesLeft == 0) {
  1489. if (!WriteFile(hWriteFileHandle,
  1490. pbWriteBuf,
  1491. dwWriteBufSize,
  1492. &dwBytesWritten,
  1493. NULL)) {
  1494. dwReturn = GetLastError();
  1495. }
  1496. dwBufferBytesLeft = dwWriteBufSize;
  1497. pbNextPtr = pbWriteBuf;
  1498. }
  1499. *pbNextPtr++ = MD_ESCAPE_BYTE;
  1500. dwBufferBytesLeft--;
  1501. if (dwBufferBytesLeft == 0) {
  1502. if (!WriteFile(hWriteFileHandle,
  1503. pbWriteBuf,
  1504. dwWriteBufSize,
  1505. &dwBytesWritten,
  1506. NULL)) {
  1507. dwReturn = GetLastError();
  1508. }
  1509. dwBufferBytesLeft = dwWriteBufSize;
  1510. pbNextPtr = pbWriteBuf;
  1511. }
  1512. *pbNextPtr++ = MD_TERMINATE_BYTE;
  1513. }
  1514. return (RETURNCODETOHRESULT(dwReturn));
  1515. }
  1516. PBYTE
  1517. FindEndOfData(PBYTE pbNextPtr,
  1518. PBYTE pbEndReadData,
  1519. BOOL bEscapePending)
  1520. {
  1521. PBYTE pbIndex = pbNextPtr;
  1522. BOOL bEndFound = FALSE;
  1523. if ((pbEndReadData > pbIndex) && bEscapePending) {
  1524. if (*pbIndex == MD_TERMINATE_BYTE) {
  1525. bEndFound = TRUE;
  1526. }
  1527. pbIndex++;
  1528. }
  1529. while ((pbEndReadData -1 > pbIndex) && !bEndFound) {
  1530. if (*pbIndex == MD_ESCAPE_BYTE) {
  1531. pbIndex++;
  1532. if (*pbIndex == MD_TERMINATE_BYTE) {
  1533. bEndFound = TRUE;
  1534. }
  1535. }
  1536. pbIndex++;
  1537. }
  1538. if (!bEndFound) {
  1539. MD_ASSERT(pbIndex == pbEndReadData - 1);
  1540. pbIndex++;
  1541. }
  1542. return pbIndex;
  1543. }
  1544. DWORD
  1545. GetLineFromBuffer(PBYTE &pbrNextPtr,
  1546. PBYTE &pbrEndReadData,
  1547. BUFFER *pbufLine,
  1548. DWORD &dwrLineLen,
  1549. BOOL &brEscapePending)
  1550. //
  1551. // GetLineFromBuffer modifies variables!!!!
  1552. // SUCCESS: pbrNextPtr, pbufLine, dwrLineLen
  1553. // FAILURE: pbrNextPtr, pbufLine, dwrLineLen, bEscapePending
  1554. //
  1555. {
  1556. DWORD dwReturn = ERROR_HANDLE_EOF;
  1557. PBYTE pbLineIndex;
  1558. PBYTE pbEndReadLine;
  1559. PBYTE pbReadDataIndex = pbrNextPtr;
  1560. DBGINFO((DBG_CONTEXT,
  1561. "Entering GeLineFromBuffer, pbrNextPtr = %p, pbrEndReadData = %p\n",
  1562. pbrNextPtr,
  1563. pbrEndReadData));
  1564. if (pbrNextPtr != pbrEndReadData) {
  1565. //
  1566. // first find out how many bytes we need to read
  1567. //
  1568. pbEndReadLine = FindEndOfData(pbrNextPtr, pbrEndReadData, brEscapePending);
  1569. MD_ASSERT(pbEndReadLine > pbrNextPtr);
  1570. //
  1571. // Actual number of bytes needed may be less than the size of the data
  1572. // but never more, so just resize for the max we might need
  1573. //
  1574. if (!pbufLine->Resize(dwrLineLen + (ULONG)DIFF(pbEndReadLine - pbrNextPtr))) {
  1575. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1576. }
  1577. else {
  1578. pbLineIndex = (PBYTE)pbufLine->QueryPtr() + dwrLineLen;
  1579. if (brEscapePending) {
  1580. brEscapePending = FALSE;
  1581. if (*pbReadDataIndex == MD_ESCAPE_BYTE) {
  1582. *pbLineIndex++ = *pbReadDataIndex++;
  1583. }
  1584. else {
  1585. MD_ASSERT(*pbReadDataIndex == MD_TERMINATE_BYTE);
  1586. dwReturn = ERROR_SUCCESS;
  1587. pbReadDataIndex++;
  1588. }
  1589. }
  1590. while ((dwReturn != ERROR_SUCCESS) && (pbReadDataIndex < pbEndReadLine)) {
  1591. if (*pbReadDataIndex != MD_ESCAPE_BYTE) {
  1592. *pbLineIndex++ = *pbReadDataIndex++;
  1593. }
  1594. else {
  1595. pbReadDataIndex++;
  1596. if (pbReadDataIndex == pbEndReadLine) {
  1597. brEscapePending = TRUE;
  1598. }
  1599. else {
  1600. if (*pbReadDataIndex == MD_ESCAPE_BYTE) {
  1601. *pbLineIndex++ = *pbReadDataIndex++;
  1602. }
  1603. else {
  1604. MD_ASSERT(*pbReadDataIndex == MD_TERMINATE_BYTE);
  1605. pbReadDataIndex++;
  1606. dwReturn = ERROR_SUCCESS;
  1607. }
  1608. }
  1609. }
  1610. }
  1611. dwrLineLen = (DWORD)DIFF(pbLineIndex - (PBYTE)pbufLine->QueryPtr());
  1612. pbrNextPtr = pbReadDataIndex;
  1613. }
  1614. }
  1615. DBGINFO((DBG_CONTEXT,
  1616. "Leaving GeLineFromBuffer, pbrNextPter = %p, pbrEndReadData = %p\n",
  1617. pbrNextPtr,
  1618. pbrEndReadData));
  1619. return dwReturn;
  1620. }
  1621. HRESULT
  1622. GetNextLine(
  1623. IN HANDLE hReadFileHandle,
  1624. IN OUT PBYTE &pbrEndReadData,
  1625. IN BUFFER *pbufRead,
  1626. IN OUT BUFFER *pbufLine,
  1627. IN OUT DWORD &dwrLineLen,
  1628. IN OUT PBYTE &pbrNextPtr)
  1629. /*++
  1630. Routine Description:
  1631. Get the next line. Performs buffered reads from a file. Only pbrCurPtr may be modified between calls.
  1632. Other variables must be set up before the first call and not changed.
  1633. Arguments:
  1634. ReadFileHandle - File to write to.
  1635. EndReadDataPtr - Points past the end of the data in ReadBuf.
  1636. Read - Buffer for file data.
  1637. Line - A line buffer which the returned line is stored in.
  1638. LineLen - The length of the data in line
  1639. NextPtr - On entry, pointer to the next unread character in ReadBuf.
  1640. On exit, pointer to the new next unread character in ReadBuf.
  1641. Return Value:
  1642. DWORD - ERROR_SUCCESS
  1643. ERROR_INVALID_DATA
  1644. Return codes from file system
  1645. Notes:
  1646. On EOF, returns ERROR_SUCCESS, dwrLineLen = 0.
  1647. --*/
  1648. {
  1649. DWORD dwReturn = ERROR_SUCCESS;
  1650. DWORD dwBytesRead;
  1651. DWORD dwLineLen = 0;
  1652. BOOL bEscapePending = FALSE;
  1653. DWORD dwGetLineReturn = ERROR_HANDLE_EOF;
  1654. BOOL bEOF = FALSE;
  1655. DBGINFO((DBG_CONTEXT,
  1656. "Entering GetNextLine, pbrNextPtr = %p, pbrEndReadData = %p\n",
  1657. pbrNextPtr,
  1658. pbrEndReadData));
  1659. //
  1660. // GetLineFromBuffer modifies variables!!!!
  1661. // SUCCESS: pbrNextPtr, pbufLine, dwrLineLen
  1662. // FAILURE: pbrNextPtr, pbufLine, dwrLineLen, bEscapePending
  1663. //
  1664. while ((dwReturn == ERROR_SUCCESS) && (dwGetLineReturn == ERROR_HANDLE_EOF) && (!bEOF)) {
  1665. DBGINFO((DBG_CONTEXT,
  1666. "GetNextLine calling GetLineFromBuffer, pbrNextPtr = %p, pbrEndReadData = %p\n",
  1667. pbrNextPtr,
  1668. pbrEndReadData));
  1669. dwGetLineReturn = GetLineFromBuffer(pbrNextPtr,
  1670. pbrEndReadData,
  1671. pbufLine,
  1672. dwLineLen,
  1673. bEscapePending);
  1674. if (dwGetLineReturn == ERROR_HANDLE_EOF) {
  1675. DBGINFO((DBG_CONTEXT,
  1676. "GetNextLine calling ReadFile\n"));
  1677. if (!ReadFile(hReadFileHandle,
  1678. (LPVOID) pbufRead->QueryPtr(),
  1679. pbufRead->QuerySize(),
  1680. &dwBytesRead,
  1681. NULL)) {
  1682. dwReturn = GetLastError();
  1683. }
  1684. else {
  1685. pbrEndReadData = (BYTE *)pbufRead->QueryPtr() + dwBytesRead;
  1686. pbrNextPtr = (PBYTE)pbufRead->QueryPtr();
  1687. DBGINFO((DBG_CONTEXT,
  1688. "GetNextLine after call to ReadFile, pbrNextPter = %p, pbrEndReadData = %p\n",
  1689. pbrNextPtr,
  1690. pbrEndReadData));
  1691. if (dwBytesRead == 0) {
  1692. bEOF = TRUE;
  1693. }
  1694. }
  1695. }
  1696. }
  1697. if (bEOF) {
  1698. MD_ASSERT(dwGetLineReturn == ERROR_HANDLE_EOF);
  1699. dwLineLen = 0;
  1700. }
  1701. else if (dwGetLineReturn != ERROR_SUCCESS) {
  1702. dwReturn = dwGetLineReturn;
  1703. }
  1704. dwrLineLen = dwLineLen;
  1705. return RETURNCODETOHRESULT(dwReturn);
  1706. }
  1707. DWORD
  1708. GetLineID(
  1709. IN OUT LPTSTR &strCurPtr)
  1710. /*++
  1711. Routine Description:
  1712. Determines the ID of a line from the metadata file.
  1713. Arguments:
  1714. CurPtr - The line to ID. Updated on successful ID to point past
  1715. the id string.
  1716. Return Value:
  1717. DWORD - MD_ID_OBJECT
  1718. MD_ID_DATA
  1719. MD_ID_REFERENCE
  1720. MD_ID_ROOT_OBJECT
  1721. MD_ID_NONE
  1722. Notes:
  1723. --*/
  1724. {
  1725. DWORD dwLineID;
  1726. if (MD_STRNICMP(strCurPtr, MD_OBJECT_ID_STRING, ((sizeof(MD_OBJECT_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1727. dwLineID = MD_ID_OBJECT;
  1728. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_OBJECT_ID_STRING) - sizeof(TCHAR)));
  1729. }
  1730. else if (MD_STRNICMP(strCurPtr, MD_DATA_ID_STRING, ((sizeof(MD_DATA_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1731. dwLineID = MD_ID_DATA;
  1732. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_DATA_ID_STRING) - sizeof(TCHAR)));
  1733. }
  1734. else if (MD_STRNICMP(strCurPtr, MD_REFERENCE_ID_STRING, ((sizeof(MD_REFERENCE_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1735. dwLineID = MD_ID_REFERENCE;
  1736. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_REFERENCE_ID_STRING) - sizeof(TCHAR)));
  1737. }
  1738. else if (MD_STRNICMP(strCurPtr, MD_ROOT_OBJECT_ID_STRING, ((sizeof(MD_ROOT_OBJECT_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1739. dwLineID = MD_ID_ROOT_OBJECT;
  1740. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_ROOT_OBJECT_ID_STRING) - sizeof(TCHAR)));
  1741. }
  1742. else if (MD_STRNICMP(strCurPtr, MD_CHANGE_NUMBER_ID_STRING, ((sizeof(MD_CHANGE_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1743. dwLineID = MD_ID_CHANGE_NUMBER;
  1744. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_CHANGE_NUMBER_ID_STRING) - sizeof(TCHAR)));
  1745. }
  1746. else if (MD_STRNICMP(strCurPtr, MD_MAJOR_VERSION_NUMBER_ID_STRING, ((sizeof(MD_MAJOR_VERSION_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1747. dwLineID = MD_ID_MAJOR_VERSION_NUMBER;
  1748. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_MAJOR_VERSION_NUMBER_ID_STRING) - sizeof(TCHAR)));
  1749. }
  1750. else if (MD_STRNICMP(strCurPtr, MD_MINOR_VERSION_NUMBER_ID_STRING, ((sizeof(MD_MINOR_VERSION_NUMBER_ID_STRING)/sizeof(TCHAR)) - 1)) == 0) {
  1751. dwLineID = MD_ID_MINOR_VERSION_NUMBER;
  1752. strCurPtr = (LPTSTR)((BYTE *)strCurPtr + (sizeof(MD_MINOR_VERSION_NUMBER_ID_STRING) - sizeof(TCHAR)));
  1753. }
  1754. else {
  1755. dwLineID = MD_ID_NONE;
  1756. }
  1757. return(dwLineID);
  1758. }
  1759. HRESULT
  1760. GetWarning(
  1761. IN HRESULT hresWarningCode)
  1762. /*++
  1763. Routine Description:
  1764. Converts error to warnings.
  1765. Arguments:
  1766. WarnignCode - The error code to convert.
  1767. Return Value:
  1768. DWORD - MD_WARNING_PATH_NOT_FOUND
  1769. MD_WARNING_DUP_NAME
  1770. MD_WARNING_INVALID_DATA
  1771. Notes:
  1772. --*/
  1773. {
  1774. HRESULT hresReturn;
  1775. switch (hresWarningCode) {
  1776. case (RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)):
  1777. hresReturn = MD_WARNING_PATH_NOT_FOUND;
  1778. break;
  1779. case (RETURNCODETOHRESULT(ERROR_DUP_NAME)):
  1780. hresReturn = MD_WARNING_DUP_NAME;
  1781. break;
  1782. case (RETURNCODETOHRESULT(ERROR_INVALID_DATA)):
  1783. hresReturn = MD_WARNING_INVALID_DATA;
  1784. break;
  1785. case (RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS)):
  1786. hresReturn = MD_WARNING_DUP_NAME;
  1787. break;
  1788. default:
  1789. hresReturn = hresWarningCode;
  1790. }
  1791. return (hresReturn);
  1792. }
  1793. BOOL CheckDigits(LPTSTR pszString)
  1794. {
  1795. LPTSTR pszTemp;
  1796. BOOL bDigitFound = FALSE;
  1797. BOOL bReturn = FALSE;
  1798. DWORD dwNumber=0;
  1799. if (!pszString)
  1800. {
  1801. goto exit;
  1802. }
  1803. for (pszTemp = pszString; MD_ISDIGIT(*pszTemp)&&(dwNumber<=MD_BACKUP_MAX_VERSION); pszTemp++)
  1804. {
  1805. dwNumber*=10;
  1806. dwNumber+=*pszTemp-_T('0');
  1807. bDigitFound = TRUE;
  1808. }
  1809. if (bDigitFound && (dwNumber<=MD_BACKUP_MAX_VERSION) && (*pszTemp == _T('\0')))
  1810. {
  1811. bReturn = TRUE;
  1812. }
  1813. exit:
  1814. return bReturn;
  1815. }
  1816. HRESULT
  1817. InitStorageHelper(
  1818. PBYTE RawBlob,
  1819. DWORD RawBlobLength,
  1820. IIS_CRYPTO_STORAGE **NewStorage
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. Helper routine to create and initialize a new IIS_CRYPTO_STORAGE
  1825. object from an unaligned blob.
  1826. Arguments:
  1827. RawBlob - Pointer to the raw unaligned session key blob.
  1828. RawBlobLength - Length of the raw blob data.
  1829. NewStorage - Receives a pointer to the new IIS_CRYPTO_STORAGE object
  1830. if successful.
  1831. Return Value:
  1832. DWORD - 0 if successful, !0 otherwise.
  1833. --*/
  1834. {
  1835. PIIS_CRYPTO_BLOB alignedBlob;
  1836. IIS_CRYPTO_STORAGE *storage = NULL;
  1837. HRESULT hresReturn = NO_ERROR;
  1838. //
  1839. // Make a copy of the blob. This is necessary, as the incoming
  1840. // raw blob pointer is most likely not DWORD-aligned.
  1841. //
  1842. hresReturn = ::IISCryptoCloneBlobFromRawData(
  1843. &alignedBlob,
  1844. RawBlob,
  1845. RawBlobLength
  1846. );
  1847. if (SUCCEEDED(hresReturn)) {
  1848. //
  1849. // Create a new IIS_CRYPTO_STORAGE object and initialize it from
  1850. // the DWORD-aligned blob.
  1851. //
  1852. storage = new IIS_CRYPTO_STORAGE();
  1853. if (storage == NULL) {
  1854. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1855. } else {
  1856. HCRYPTPROV hProv;
  1857. hresReturn = GetCryptoProvider( &hProv );
  1858. if (SUCCEEDED(hresReturn)) {
  1859. hresReturn = storage->Initialize(
  1860. alignedBlob,
  1861. TRUE, // fUseMachineKeyset
  1862. hProv
  1863. );
  1864. if (FAILED(hresReturn))
  1865. {
  1866. DBGINFOW((DBG_CONTEXT,
  1867. L"[InitStorageHelper] IIS_CRYPTO_STORAGE::Initialize faile with hr = 0x%x.\n",hresReturn));
  1868. }
  1869. }
  1870. else
  1871. {
  1872. DBGINFOW((DBG_CONTEXT,
  1873. L"[InitStorageHelper] GetCryptoProvider failed with hr = 0x%x. (Crypto problem)\n",hresReturn));
  1874. }
  1875. if (FAILED(hresReturn)) {
  1876. delete storage;
  1877. storage = NULL;
  1878. }
  1879. }
  1880. ::IISCryptoFreeBlob(alignedBlob);
  1881. }
  1882. else
  1883. {
  1884. // something failed...
  1885. DBGINFOW((DBG_CONTEXT,
  1886. L"[InitStorageHelper] IISCryptoCloneBlobFromRawData failed with hr = 0x%x. (Crypto problem).\n",hresReturn));
  1887. }
  1888. *NewStorage = storage;
  1889. return hresReturn;
  1890. } // InitStorageHelper
  1891. HRESULT
  1892. InitStorageHelper2(
  1893. LPSTR pszPasswd,
  1894. PBYTE RawBlob,
  1895. DWORD RawBlobLength,
  1896. IIS_CRYPTO_STORAGE **NewStorage
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. Helper routine to create and initialize a new IIS_CRYPTO_STORAGE
  1901. object from an unaligned blob.
  1902. Arguments:
  1903. RawBlob - Pointer to the raw unaligned session key blob.
  1904. RawBlobLength - Length of the raw blob data.
  1905. NewStorage - Receives a pointer to the new IIS_CRYPTO_STORAGE object
  1906. if successful.
  1907. Return Value:
  1908. DWORD - 0 if successful, !0 otherwise.
  1909. --*/
  1910. {
  1911. PIIS_CRYPTO_BLOB alignedBlob;
  1912. IIS_CRYPTO_STORAGE2 *storage = NULL;
  1913. HRESULT hresReturn = NO_ERROR;
  1914. if( ( ( PIIS_CRYPTO_BLOB )RawBlob )->BlobSignature != SALT_BLOB_SIGNATURE )
  1915. {
  1916. return InitStorageHelper( RawBlob, RawBlobLength, NewStorage );
  1917. }
  1918. //
  1919. // Make a copy of the blob. This is necessary, as the incoming
  1920. // raw blob pointer is most likely not DWORD-aligned.
  1921. //
  1922. hresReturn = ::IISCryptoCloneBlobFromRawData2(
  1923. &alignedBlob,
  1924. RawBlob,
  1925. RawBlobLength
  1926. );
  1927. if (SUCCEEDED(hresReturn)) {
  1928. //
  1929. // Create a new IIS_CRYPTO_STORAGE object and initialize it from
  1930. // the DWORD-aligned blob.
  1931. //
  1932. storage = new IIS_CRYPTO_STORAGE2;
  1933. if (storage == NULL) {
  1934. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  1935. } else {
  1936. HCRYPTPROV hProv;
  1937. hresReturn = GetCryptoProvider2( &hProv );
  1938. if (SUCCEEDED(hresReturn)) {
  1939. hresReturn = storage->Initialize(
  1940. alignedBlob,
  1941. pszPasswd,
  1942. hProv
  1943. );
  1944. if (FAILED(hresReturn))
  1945. {
  1946. DBGINFOW((DBG_CONTEXT,
  1947. L"[InitStorageHelper2] IIS_CRYPTO_STORAGE::Initialize failed with hr = 0x%x.\n",hresReturn));
  1948. }
  1949. }
  1950. else
  1951. {
  1952. DBGINFOW((DBG_CONTEXT,
  1953. L"[InitStorageHelper] GetCryptoProvider failed with hr = 0x%x. (Crypto problem)\n",hresReturn));
  1954. }
  1955. if (FAILED(hresReturn)) {
  1956. delete storage;
  1957. storage = NULL;
  1958. }
  1959. }
  1960. ::IISCryptoFreeBlob2(alignedBlob);
  1961. }
  1962. else
  1963. {
  1964. // something failed...
  1965. DBGINFOW((DBG_CONTEXT,
  1966. L"[InitStorageHelper] IISCryptoCloneBlobFromRawData failed with hr = 0x%x. (Crypto problem).\n",hresReturn));
  1967. }
  1968. *NewStorage = ( IIS_CRYPTO_STORAGE * )storage;
  1969. return hresReturn;
  1970. } // InitStorageHelper2
  1971. HRESULT
  1972. ReadAllData(LPSTR pszPasswd,
  1973. LPSTR pszBackupLocation,
  1974. LPSTR pszSchemaLocation,
  1975. BOOL bHaveReadSaveSemaphore
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. Deletgates to correct Reads all meta data from metabase.bin
  1980. or metabase.xml
  1981. Arguments:
  1982. Return Value:
  1983. HRESULT - ERROR_SUCCESS
  1984. ERROR_NOT_ENOUGH_MEMORY
  1985. Return codes from file system
  1986. Return codes from config
  1987. Notes:
  1988. --*/
  1989. {
  1990. HRESULT hr = ERROR_SUCCESS;
  1991. hr = ReadAllDataFromXML(pszPasswd,
  1992. pszBackupLocation,
  1993. pszSchemaLocation,
  1994. bHaveReadSaveSemaphore
  1995. );
  1996. if(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1997. {
  1998. //
  1999. // Metabase.xml file was not found. Hence try to load from the
  2000. // metabase.bin file.
  2001. //
  2002. hr = ReadAllDataFromBin(pszPasswd,
  2003. pszBackupLocation,
  2004. bHaveReadSaveSemaphore
  2005. );
  2006. }
  2007. return hr;
  2008. }
  2009. HRESULT
  2010. ReadAllDataFromXML(LPSTR pszPasswd,
  2011. LPSTR pszBackupLocation,
  2012. LPSTR pszSchemaLocation,
  2013. BOOL bHaveReadSaveSemaphore
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. Reads all meta data from the XML file.
  2018. Arguments:
  2019. Return Value:
  2020. HRESULT - ERROR_SUCCESS
  2021. ERROR_NOT_ENOUGH_MEMORY
  2022. Return codes from file system
  2023. Return codes from the catalog
  2024. Notes:
  2025. --*/
  2026. {
  2027. HRESULT hr = ERROR_SUCCESS;
  2028. HRESULT hresWarningCode = ERROR_SUCCESS;
  2029. ISimpleTableDispenser2* pISTDisp = NULL;
  2030. ISimpleTableRead2* pISTProperty = NULL;
  2031. STQueryCell QueryCell[2];
  2032. ULONG cCell = sizeof(QueryCell)/sizeof(STQueryCell);
  2033. ULONG i = 0;
  2034. LPWSTR wszDataFileName = NULL;
  2035. LPWSTR wszSchemaFileName = NULL;
  2036. LPTSTR strReadFileName;
  2037. LPTSTR strSchemaFileName;
  2038. CMDBaseObject* pboRead = NULL;
  2039. IIS_CRYPTO_STORAGE* pStorage = NULL;
  2040. DWORD dwPreviousLocationID = (DWORD)-1;
  2041. LPWSTR wszPreviousContinuousLocation = L"/"; // Initialize to the root location
  2042. BOOL bLocationDiscontinuous = FALSE;
  2043. DWORD dwTempLastSaveChangeNumber = 0;
  2044. DWORD dwTempLastSaveMetabaseVersion = 0;
  2045. FILETIME fileTime;
  2046. BOOL bSchemaFileNotFound = FALSE;
  2047. BOOL bReadSchemaFromSchemaBin = TRUE;
  2048. BOOL bMRLock = false;
  2049. if( !pszPasswd && !pszBackupLocation )
  2050. {
  2051. strReadFileName = g_strRealFileName->QueryStr();
  2052. }
  2053. else
  2054. {
  2055. //
  2056. // Restore
  2057. //
  2058. strReadFileName = pszBackupLocation;
  2059. }
  2060. if(!pszPasswd && !pszSchemaLocation )
  2061. {
  2062. strSchemaFileName = g_strSchemaFileName->QueryStr();
  2063. }
  2064. else
  2065. {
  2066. //
  2067. // Restore
  2068. //
  2069. strSchemaFileName = pszSchemaLocation;
  2070. }
  2071. //
  2072. // Get full unicode file name for data file i.e. metabase.xml
  2073. //
  2074. hr = GetUnicodeName(strReadFileName, &wszDataFileName);
  2075. if(FAILED(hr))
  2076. {
  2077. DBGINFOW((DBG_CONTEXT,
  2078. L"[ReadAllDataFromXML] GetUnicodeName failed with hr = 0x%x.\n",hr));
  2079. goto exit;
  2080. }
  2081. //
  2082. // Get full file name for schema file i.e. mbschema.xml
  2083. //
  2084. hr = GetUnicodeName(strSchemaFileName, &wszSchemaFileName);
  2085. DBGINFOW((DBG_CONTEXT,
  2086. L"[ReadAllDataFromXML]\nDataFileName:%s\nSchemaFileName:%s\n",
  2087. wszDataFileName,
  2088. wszSchemaFileName));
  2089. if(FAILED(hr))
  2090. {
  2091. DBGINFOW((DBG_CONTEXT,
  2092. L"[ReadAllDataFromXML] GetUnicodeName failed with hr = 0x%x.\n",hr));
  2093. goto exit;
  2094. }
  2095. if (!bHaveReadSaveSemaphore)
  2096. {
  2097. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  2098. }
  2099. //
  2100. // Lock the metabase
  2101. //
  2102. g_LockMasterResource.WriteLock();
  2103. bMRLock = true;
  2104. //
  2105. // TODO:
  2106. // g_dwMajorVersionNumber = dwTemp;
  2107. // g_dwMinorVersionNumber = dwTemp;
  2108. // g_dwSystemChangeNumber = dwTemp;
  2109. //
  2110. //
  2111. // Set the global values to their defaults, so that even if they aren't
  2112. // present in the XML file, they are correctly initialized.
  2113. // Also initializes the dispenser and the bin file path.
  2114. //
  2115. hr = InitializeIIS6GlobalsToDefaults(1,1,pszBackupLocation);
  2116. //
  2117. // Compile the schema bin file if needed and initialize g_pGlobalISTHelper
  2118. //
  2119. hr = CompileIfNeeded(wszDataFileName, wszSchemaFileName, &bSchemaFileNotFound);
  2120. if(FAILED(hr))
  2121. {
  2122. goto exit;
  2123. }
  2124. if(bSchemaFileNotFound)
  2125. {
  2126. //
  2127. // If schema file is not found, set the schema change numbers to differ
  2128. // so that a compilation is forced. If schema file is not found and the
  2129. // schema tree is in the xml, we will read the schema tree from the xml
  2130. // hence we will need to force a compile during savealldata to merge
  2131. // the xml schema and the shippped schema..
  2132. //
  2133. g_dwLastSchemaChangeNumber = 0;
  2134. }
  2135. if(FAILED(hr))
  2136. {
  2137. goto exit;
  2138. }
  2139. //
  2140. // Get the property table.
  2141. //
  2142. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  2143. if(FAILED(hr))
  2144. {
  2145. DBGINFOW((DBG_CONTEXT,
  2146. L"[ReadAllDataFromXML] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
  2147. goto exit;
  2148. }
  2149. QueryCell[0].pData = (LPVOID)g_pGlobalISTHelper->m_wszBinFileForMeta;
  2150. QueryCell[0].eOperator = eST_OP_EQUAL;
  2151. QueryCell[0].iCell = iST_CELL_SCHEMAFILE;
  2152. QueryCell[0].dbType = DBTYPE_WSTR;
  2153. QueryCell[0].cbSize = 0;
  2154. QueryCell[1].pData = (LPVOID)wszDataFileName;
  2155. QueryCell[1].eOperator = eST_OP_EQUAL;
  2156. QueryCell[1].iCell = iST_CELL_FILE;
  2157. QueryCell[1].dbType = DBTYPE_WSTR;
  2158. QueryCell[1].cbSize = (lstrlenW(wszDataFileName)+1)*sizeof(WCHAR);
  2159. hr = pISTDisp->GetTable(wszDATABASE_METABASE,
  2160. wszTABLE_MBProperty,
  2161. (LPVOID)QueryCell,
  2162. (LPVOID)&cCell,
  2163. eST_QUERYFORMAT_CELLS,
  2164. 0,
  2165. (LPVOID *)&pISTProperty);
  2166. if(FAILED(hr))
  2167. {
  2168. DBGINFOW((DBG_CONTEXT,
  2169. L"[ReadAllDataFromXML] GetTable failed with hr = 0x%x.\n",hr));
  2170. goto exit;
  2171. }
  2172. hr = InitializeGlobalsFromXML(pISTProperty,
  2173. wszDataFileName,
  2174. wszSchemaFileName,
  2175. &pStorage,
  2176. pszPasswd,
  2177. pszBackupLocation ? TRUE : FALSE,
  2178. &fileTime);
  2179. if(FAILED(hr))
  2180. {
  2181. goto exit;
  2182. }
  2183. //
  2184. // Need to determine where to read the schema from.
  2185. // In upgrade scenarios from IIS5.0/5.1 to 6.0 ReadAllDataFromBin is called
  2186. // which reads the schema tree from the metabase.bin file.
  2187. // In upgrade scenarios from IIS6.0 Beta1 builds (where schema is stored in
  2188. // the metabase.xml file) to IIS6.0 Beta2 builds (where schema is stored in
  2189. // mbschema.XML files) a compile is done, but schema is still read from the
  2190. // metabase.XML file.
  2191. // Setup needs to force a save in these scenarios so that the schema that is
  2192. // read (from either metabase.bin or metabase.xml) can be merged with the
  2193. // shipped schema to generate a unified mbschema.bin and mbschema.xml file.
  2194. //
  2195. if(bSchemaFileNotFound && SchemaTreeInTable(pISTProperty))
  2196. {
  2197. DBGINFOW((DBG_CONTEXT,
  2198. L"[ReadAllDataFromXML] Should not be reading from schema bin.\n"));
  2199. bReadSchemaFromSchemaBin = FALSE;
  2200. }
  2201. if(bReadSchemaFromSchemaBin)
  2202. {
  2203. //
  2204. // Read the schema tree from the .bin
  2205. //
  2206. hr = ReadSchema(pStorage,
  2207. &fileTime);
  2208. if(FAILED(hr))
  2209. {
  2210. goto exit;
  2211. }
  2212. }
  2213. //
  2214. // All of the stuff is read into pISTProperty.
  2215. // Now loop through and populate in-memory cache
  2216. //
  2217. for(i=0; ;i++)
  2218. {
  2219. LPVOID a_pv[cMBProperty_NumberOfColumns];
  2220. ULONG a_Size[cMBProperty_NumberOfColumns];
  2221. ULONG a_iCol[] = {iMBProperty_Name,
  2222. iMBProperty_Location,
  2223. iMBProperty_ID,
  2224. iMBProperty_Attributes,
  2225. iMBProperty_UserType,
  2226. iMBProperty_Type,
  2227. iMBProperty_Value,
  2228. iMBProperty_LocationID};
  2229. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  2230. BOOL bLocationWithProperty = TRUE;
  2231. BOOL bNewLocation = FALSE;
  2232. BOOL bIsRoot = FALSE;
  2233. hr = pISTProperty->GetColumnValues(i,
  2234. cCol,
  2235. a_iCol,
  2236. a_Size,
  2237. a_pv);
  2238. if(E_ST_NOMOREROWS == hr)
  2239. {
  2240. hr = S_OK;
  2241. break;
  2242. }
  2243. else if(FAILED(hr))
  2244. {
  2245. DBGINFOW((DBG_CONTEXT,
  2246. L"[ReadAllDataFromXML] GetColumnValues failed with hr = 0x%x. Table:%s. Read row index:%d.\n", \
  2247. hr, wszTABLE_MBProperty, i));
  2248. goto exit;
  2249. }
  2250. else if((0 == wcscmp(MD_GLOBAL_LOCATIONW, (LPWSTR)a_pv[iMBProperty_Location])) ||
  2251. (bReadSchemaFromSchemaBin && (0 == _wcsnicmp((LPWSTR)a_pv[iMBProperty_Location], g_wszSlashSchema, g_cchSlashSchema)))
  2252. )
  2253. {
  2254. //
  2255. // Ignore globals.
  2256. //
  2257. //
  2258. // Ignore the schema tree if it has been read from bin,
  2259. //
  2260. continue;
  2261. }
  2262. if((*(DWORD*)a_pv[iMBProperty_ID] == MD_LOCATION) && (*(LPWSTR)a_pv[iMBProperty_Name] == MD_CH_LOC_NO_PROPERTYW))
  2263. {
  2264. bLocationWithProperty = FALSE;
  2265. }
  2266. if(dwPreviousLocationID != *(DWORD*)a_pv[iMBProperty_LocationID])
  2267. {
  2268. bNewLocation = TRUE;
  2269. dwPreviousLocationID = *(DWORD*)a_pv[iMBProperty_LocationID];
  2270. bLocationDiscontinuous = DiscontinuousLocation(wszPreviousContinuousLocation,
  2271. (LPWSTR)a_pv[iMBProperty_Location]);
  2272. if(!bLocationDiscontinuous)
  2273. {
  2274. wszPreviousContinuousLocation = (LPWSTR)a_pv[iMBProperty_Location];
  2275. }
  2276. else
  2277. {
  2278. DBGINFOW((DBG_CONTEXT,
  2279. L"[ReadAllDataFromXML] Encountered discontinuous location:%s. Ignoring this and all locations below it.\n", \
  2280. (LPWSTR)a_pv[iMBProperty_Location]));
  2281. LogEvent(g_pEventLog,
  2282. MD_WARNING_IGNORING_DISCONTINUOUS_NODE,
  2283. EVENTLOG_WARNING_TYPE,
  2284. ID_CAT_CAT,
  2285. ERROR_INVALID_DATA,
  2286. (LPWSTR)a_pv[iMBProperty_Location]);
  2287. }
  2288. }
  2289. if(bLocationDiscontinuous)
  2290. {
  2291. //
  2292. // Properties are sorted by location. If you have a discontinous location, the ignore it.
  2293. //
  2294. continue;
  2295. }
  2296. //
  2297. // TODO: Need to assert when bLocationWithProperty == FALSE, then bNewLocation must == TRUE
  2298. //
  2299. if(0 == wcscmp((LPWSTR)a_pv[iMBProperty_Location], L"/"))
  2300. {
  2301. bIsRoot = TRUE;
  2302. }
  2303. if(bNewLocation && (!bIsRoot)) // No need to read meta object for root - g_pboMasterRoot already present.
  2304. {
  2305. hr = ReadMetaObject(pboRead,
  2306. (LPWSTR)a_pv[iMBProperty_Location],
  2307. &fileTime,
  2308. TRUE);
  2309. if(FAILED(hr))
  2310. {
  2311. if (hr == RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY))
  2312. {
  2313. //
  2314. // Serious error, we're done.
  2315. //
  2316. goto exit;
  2317. }
  2318. else
  2319. {
  2320. //
  2321. // Just give a warning and go to the next object
  2322. //
  2323. hresWarningCode = hr;
  2324. continue;
  2325. }
  2326. }
  2327. }
  2328. if(bLocationWithProperty)
  2329. {
  2330. if(!bIsRoot)
  2331. {
  2332. hr = ReadDataObject(pboRead,
  2333. a_pv,
  2334. a_Size,
  2335. pStorage,
  2336. TRUE);
  2337. }
  2338. else
  2339. {
  2340. hr = ReadDataObject(g_pboMasterRoot,
  2341. a_pv,
  2342. a_Size,
  2343. pStorage,
  2344. TRUE);
  2345. }
  2346. if(FAILED(hr))
  2347. {
  2348. if (hr == RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY))
  2349. {
  2350. //
  2351. // Serious error, we're done.
  2352. //
  2353. goto exit;
  2354. }
  2355. else
  2356. {
  2357. //
  2358. // Just give a warning and go to the next object
  2359. //
  2360. hresWarningCode = hr;
  2361. continue;
  2362. }
  2363. }
  2364. }
  2365. }
  2366. exit:
  2367. //
  2368. // Must have MasterResource when accessing SystemChangeNumber
  2369. // so save it away here. Only update LastSaveChangeNumber on success.
  2370. //
  2371. dwTempLastSaveChangeNumber = g_dwSystemChangeNumber;
  2372. //
  2373. // Save the version number as well.
  2374. //
  2375. dwTempLastSaveMetabaseVersion = g_ulHistoryMajorVersionNumber;
  2376. if(bMRLock)
  2377. {
  2378. g_LockMasterResource.WriteUnlock();
  2379. bMRLock = false;
  2380. }
  2381. //
  2382. // If the file is not found we either read from the bin file
  2383. // (if it is present like in an upgrade scenario, or we fail.
  2384. //
  2385. if ((SUCCEEDED(hr)) && (hresWarningCode != ERROR_SUCCESS))
  2386. {
  2387. hr = GetWarning(hresWarningCode);
  2388. }
  2389. if (SUCCEEDED(hr))
  2390. {
  2391. g_dwLastSaveChangeNumber = dwTempLastSaveChangeNumber;
  2392. }
  2393. if(SUCCEEDED(hr) && (NULL == pszBackupLocation))
  2394. {
  2395. //
  2396. // Initialize last write timestamp. Do not initialize for the restore scenario.
  2397. //
  2398. WIN32_FILE_ATTRIBUTE_DATA CurrentMetabaseTempFileAttr;
  2399. FILETIME* pCurrentMetabaseLastWriteTimeStamp = NULL;
  2400. if(!GetFileAttributesExW(wszDataFileName,
  2401. GetFileExInfoStandard,
  2402. &CurrentMetabaseTempFileAttr)
  2403. )
  2404. {
  2405. //
  2406. // Could not fetch the current file attributes for the temporary metabase file.
  2407. // The file timestamp will remain initialized to zero - this will force a sav.
  2408. //
  2409. #if DBG
  2410. DWORD dwRes = GetLastError();
  2411. HRESULT hrSav = RETURNCODETOHRESULT(dwRes);
  2412. DBGINFOW((DBG_CONTEXT,
  2413. L"[ReadAllDataFromXML] Could not fetch the current file attributes for the temporary metabase file. GetFileAttributesEx on %s failed with hr = 0x%x.\n",
  2414. wszDataFileName,
  2415. hrSav));
  2416. #endif
  2417. }
  2418. else
  2419. {
  2420. pCurrentMetabaseLastWriteTimeStamp = &CurrentMetabaseTempFileAttr.ftLastWriteTime;
  2421. }
  2422. EnterCriticalSection(&g_csEditWhileRunning);
  2423. if(NULL != pCurrentMetabaseLastWriteTimeStamp)
  2424. {
  2425. g_MostRecentMetabaseFileLastWriteTimeStamp = CurrentMetabaseTempFileAttr.ftLastWriteTime;
  2426. }
  2427. else
  2428. {
  2429. memset((LPVOID)&g_MostRecentMetabaseFileLastWriteTimeStamp, 0, sizeof(FILETIME));
  2430. }
  2431. g_ulMostRecentMetabaseVersion = dwTempLastSaveMetabaseVersion;
  2432. LeaveCriticalSection(&g_csEditWhileRunning);
  2433. }
  2434. if((SUCCEEDED(hr)) &&
  2435. (NULL == pszBackupLocation)
  2436. )
  2437. {
  2438. //
  2439. // Note the global handle array is initialized in
  2440. // InitializeIIS6GlobalsToDefaults
  2441. //
  2442. if(!g_dwEnableEditWhileRunning)
  2443. {
  2444. // Write lock the file only if EWR is disabled and it is a
  2445. // ReadAllData that is called from service startup and not
  2446. // from Restore.
  2447. //
  2448. hr = LockMetabaseFile(wszDataFileName,
  2449. eMetabaseDataFile,
  2450. TRUE);
  2451. DBGINFOW((DBG_CONTEXT,
  2452. L"[ReadAllDataFromXML] Locking metabase file %s returned 0x%x.\n",
  2453. wszDataFileName,
  2454. hr));
  2455. if(SUCCEEDED(hr))
  2456. {
  2457. hr = LockMetabaseFile(wszSchemaFileName,
  2458. eMetabaseSchemaFile,
  2459. TRUE);
  2460. DBGINFOW((DBG_CONTEXT,
  2461. L"[ReadAllDataFromXML] Locking metabase file %s returned 0x%x.\n",
  2462. wszSchemaFileName,
  2463. hr));
  2464. }
  2465. }
  2466. }
  2467. //
  2468. // Cleanup
  2469. //
  2470. if (!bHaveReadSaveSemaphore)
  2471. {
  2472. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  2473. }
  2474. if(NULL != pISTProperty)
  2475. {
  2476. pISTProperty->Release();
  2477. pISTProperty = NULL;
  2478. }
  2479. if(NULL != pISTDisp)
  2480. {
  2481. pISTDisp->Release();
  2482. pISTDisp = NULL;
  2483. }
  2484. if(NULL != wszDataFileName)
  2485. {
  2486. delete [] wszDataFileName;
  2487. wszDataFileName = NULL;
  2488. }
  2489. if(NULL != wszSchemaFileName)
  2490. {
  2491. delete [] wszSchemaFileName;
  2492. wszSchemaFileName = NULL;
  2493. }
  2494. return hr;
  2495. }
  2496. HRESULT
  2497. ReadAllDataFromBin(LPSTR pszPasswd,
  2498. LPSTR pszBackupLocation,
  2499. BOOL bHaveReadSaveSemaphore
  2500. )
  2501. /*++
  2502. Routine Description:
  2503. Reads all meta data from the original bin file.
  2504. Arguments:
  2505. Return Value:
  2506. HRESULT - ERROR_SUCCESS
  2507. ERROR_NOT_ENOUGH_MEMORY
  2508. Return codes from file system
  2509. Notes:
  2510. --*/
  2511. {
  2512. HRESULT hresReturn = ERROR_SUCCESS;
  2513. HRESULT hresWarningCode = ERROR_SUCCESS;
  2514. PBYTE pbEndReadData;
  2515. PBYTE pbNextPtr;
  2516. DWORD dwLineLen;
  2517. LPTSTR strReadFileName;
  2518. HANDLE hReadFileHandle = INVALID_HANDLE_VALUE;
  2519. BYTE bLineId = MD_ID_NONE;
  2520. DWORD dwTemp;
  2521. DWORD dwError;
  2522. CMDBaseObject *pboRead;
  2523. FILETIME ftTime;
  2524. IIS_CRYPTO_STORAGE *pStorage = NULL;
  2525. BOOL bUnicode = TRUE;
  2526. DWORD dwTempLastSaveChangeNumber = 0;
  2527. STR* strRealBinFileName = NULL;
  2528. LPWSTR wszFileName = NULL;
  2529. BUFFER *pbufRead = new BUFFER(0);
  2530. if( !pbufRead )
  2531. {
  2532. return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2533. }
  2534. BUFFER *pbufLine = new BUFFER(0);
  2535. if( !pbufLine )
  2536. {
  2537. delete pbufRead;
  2538. pbufRead = NULL;
  2539. return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2540. }
  2541. if( !pszPasswd )
  2542. {
  2543. TCHAR* szBin = NULL;
  2544. TCHAR* szEnd = NULL;
  2545. TCHAR chDot = (TCHAR)'.';
  2546. TCHAR* szBinExtn = (TCHAR*)"bin";
  2547. szBin = new TCHAR[_tcslen(g_strRealFileName->QueryStr())+1];
  2548. if(NULL == szBin)
  2549. {
  2550. delete(pbufRead);
  2551. delete(pbufLine);
  2552. return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2553. }
  2554. else
  2555. {
  2556. _tcscpy(szBin, (g_strRealFileName->QueryStr()));
  2557. szEnd = _tcsrchr(szBin, chDot);
  2558. *(++szEnd) = (TCHAR)'\0';
  2559. _tcscat(szBin, szBinExtn);
  2560. strRealBinFileName = new STR(szBin);
  2561. delete [] szBin;
  2562. if(NULL == strRealBinFileName)
  2563. {
  2564. delete(pbufRead);
  2565. delete(pbufLine);
  2566. return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2567. }
  2568. else
  2569. strReadFileName = strRealBinFileName->QueryStr();
  2570. }
  2571. }
  2572. else
  2573. {
  2574. strReadFileName = pszBackupLocation;
  2575. }
  2576. hresReturn = GetUnicodeName(strReadFileName, &wszFileName);
  2577. if(FAILED(hresReturn))
  2578. {
  2579. DBGINFOW((DBG_CONTEXT,
  2580. L"[ReadAllDataFromBin] GetUnicodeName failed with hr = 0x%x.\n",hresReturn));
  2581. delete(pbufRead);
  2582. delete(pbufLine);
  2583. return RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  2584. }
  2585. hresReturn = InitializeIIS6GlobalsToDefaults(0,1,pszBackupLocation);
  2586. if(FAILED(hresReturn))
  2587. {
  2588. delete(pbufRead);
  2589. delete(pbufLine);
  2590. delete [] wszFileName;
  2591. DBGINFOW((DBG_CONTEXT,
  2592. L"[ReadAllDataFromBin] InitializeIIS6GlobalsToDefaults failed with hr = 0x%x.\n",hresReturn));
  2593. return hresReturn;
  2594. }
  2595. if (!bHaveReadSaveSemaphore) {
  2596. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  2597. }
  2598. //
  2599. // Open the file.
  2600. //
  2601. hReadFileHandle = CreateFile(strReadFileName,
  2602. GENERIC_READ,
  2603. 0,
  2604. NULL,
  2605. OPEN_EXISTING,
  2606. FILE_ATTRIBUTE_NORMAL,
  2607. 0);
  2608. if ((hReadFileHandle == INVALID_HANDLE_VALUE) || (hReadFileHandle == NULL)) {
  2609. dwError = GetLastError();
  2610. hresReturn = RETURNCODETOHRESULT(dwError);
  2611. }
  2612. else {
  2613. //
  2614. // Allocate Buffers
  2615. //
  2616. if (!pbufLine->Resize(MAX_RECORD_BUFFER) ||
  2617. !pbufRead->Resize(READWRITE_BUFFER_LENGTH)) {
  2618. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  2619. }
  2620. else {
  2621. pbEndReadData = (PBYTE)pbufRead->QueryPtr();
  2622. //
  2623. // GetNextLine makes sure that the next line is in the buffer and sets strCurPtr to point to it
  2624. // The line is NULL terminated, no new line. The variables passed in must not be modified outside
  2625. // of GetNextLine.
  2626. //
  2627. dwLineLen = 0;
  2628. pbNextPtr = pbEndReadData;
  2629. hresReturn = GetNextLine(hReadFileHandle,
  2630. pbEndReadData,
  2631. pbufRead,
  2632. pbufLine,
  2633. dwLineLen,
  2634. pbNextPtr);
  2635. if (SUCCEEDED(hresReturn)) {
  2636. //
  2637. // See if it's our file
  2638. //
  2639. if (dwLineLen == sizeof(MD_SIGNATURE_STRINGA) &&
  2640. (MD_CMP(MD_SIGNATURE_STRINGA, pbufLine->QueryPtr(), dwLineLen) == 0)) {
  2641. bUnicode = FALSE;
  2642. }
  2643. else if (dwLineLen == sizeof(MD_SIGNATURE_STRINGW) &&
  2644. (MD_CMP(MD_SIGNATURE_STRINGW, pbufLine->QueryPtr(), dwLineLen) == 0)) {
  2645. bUnicode = TRUE;
  2646. }
  2647. else {
  2648. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  2649. }
  2650. if (SUCCEEDED(hresReturn)) {
  2651. //
  2652. // The first GetNextLine filled the buffer
  2653. // so we may not need to do any file system stuff
  2654. // with g_LockMasterResource locked.
  2655. //
  2656. g_LockMasterResource.WriteLock();
  2657. while ((SUCCEEDED(hresReturn)) &&
  2658. (SUCCEEDED(hresReturn = GetNextLine(hReadFileHandle,
  2659. pbEndReadData,
  2660. pbufRead,
  2661. pbufLine,
  2662. dwLineLen,
  2663. pbNextPtr))) &&
  2664. (dwLineLen > 0) &&
  2665. (((bLineId = *(BYTE *)(pbufLine->QueryPtr())) == MD_ID_NONE) ||
  2666. (bLineId == MD_ID_MAJOR_VERSION_NUMBER) ||
  2667. (bLineId == MD_ID_MINOR_VERSION_NUMBER) ||
  2668. (bLineId == MD_ID_CHANGE_NUMBER) ||
  2669. (bLineId == MD_ID_SESSION_KEY))) {
  2670. if (bLineId != MD_ID_NONE) {
  2671. if (bLineId != MD_ID_SESSION_KEY &&
  2672. dwLineLen != (1 + sizeof(DWORD))) {
  2673. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  2674. }
  2675. else {
  2676. dwTemp = *(UNALIGNED DWORD *)FIRSTDATAPTR(pbufLine);
  2677. switch (bLineId) {
  2678. case MD_ID_MAJOR_VERSION_NUMBER:
  2679. g_dwMajorVersionNumber = dwTemp;
  2680. break;
  2681. case MD_ID_MINOR_VERSION_NUMBER:
  2682. g_dwMinorVersionNumber = dwTemp;
  2683. break;
  2684. case MD_ID_CHANGE_NUMBER:
  2685. g_dwSystemChangeNumber = dwTemp;
  2686. break;
  2687. case MD_ID_SESSION_KEY:
  2688. {
  2689. BOOL fSecuredRead = TRUE;
  2690. HKEY hkRegistryKey = NULL;
  2691. DWORD dwRegReturn, dwValue,dwType,dwSize = sizeof(DWORD);
  2692. dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
  2693. SETUP_REG_KEY,
  2694. &hkRegistryKey);
  2695. if (dwRegReturn == ERROR_SUCCESS)
  2696. {
  2697. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  2698. MD_UNSECUREDREAD_VALUE,
  2699. NULL,
  2700. &dwType,
  2701. (BYTE *)&dwValue,
  2702. &dwSize);
  2703. if ( dwRegReturn == ERROR_SUCCESS &&
  2704. dwType == REG_DWORD &&
  2705. dwValue == 1)
  2706. {
  2707. hresReturn = NO_ERROR;
  2708. pStorage = NULL;
  2709. fSecuredRead = FALSE;
  2710. DBGPRINTF(( DBG_CONTEXT,
  2711. "Temporary disabling decryption for metabase read\n"));
  2712. // special indicator for IIS setup that we passed this point
  2713. dwValue = 2;
  2714. dwRegReturn = RegSetValueEx(hkRegistryKey,
  2715. MD_UNSECUREDREAD_VALUE,
  2716. 0,
  2717. REG_DWORD,
  2718. (PBYTE)&dwValue,
  2719. sizeof(dwValue));
  2720. if (dwRegReturn == ERROR_SUCCESS)
  2721. {
  2722. DBGPRINTF(( DBG_CONTEXT,"Reanabling decryption after W9z upgrade\n"));
  2723. }
  2724. }
  2725. MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
  2726. }
  2727. if (fSecuredRead)
  2728. {
  2729. if (IISCryptoIsClearTextSignature((IIS_CRYPTO_BLOB UNALIGNED *) FIRSTDATAPTR(pbufLine)))
  2730. {
  2731. // call special function focibly tell that this machine has no
  2732. // encryption enabled even if it happens to be so
  2733. // that's a special handling for French case with US locale
  2734. IISCryptoInitializeOverride (FALSE);
  2735. }
  2736. if( !pszPasswd )
  2737. {
  2738. hresReturn = InitStorageHelper(
  2739. FIRSTDATAPTR(pbufLine),
  2740. dwLineLen-1,
  2741. &pStorage
  2742. );
  2743. }
  2744. else
  2745. {
  2746. hresReturn = InitStorageHelper2(
  2747. pszPasswd,
  2748. FIRSTDATAPTR(pbufLine),
  2749. dwLineLen-1,
  2750. &pStorage
  2751. );
  2752. }
  2753. }
  2754. }
  2755. break;
  2756. default:
  2757. MD_ASSERT(FALSE);
  2758. }
  2759. }
  2760. }
  2761. }
  2762. if (SUCCEEDED(hresReturn)) {
  2763. //
  2764. // This must be the global master object
  2765. //
  2766. if ((dwLineLen != 1 + sizeof(FILETIME)) || (bLineId != MD_ID_ROOT_OBJECT)) {
  2767. //
  2768. // This file is hosed
  2769. //
  2770. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  2771. }
  2772. else {
  2773. //
  2774. // Got the MasterRoot Object.
  2775. //
  2776. ftTime = *(UNALIGNED FILETIME *)FIRSTDATAPTR(pbufLine);
  2777. g_pboMasterRoot->SetLastChangeTime(&ftTime);
  2778. //
  2779. // Read in MasterRoot Data.
  2780. //
  2781. for (hresReturn = GetNextLine(hReadFileHandle,
  2782. pbEndReadData,
  2783. pbufRead,
  2784. pbufLine,
  2785. dwLineLen,
  2786. pbNextPtr);
  2787. ((SUCCEEDED(hresReturn)) && (dwLineLen != 0)
  2788. && ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
  2789. hresReturn = GetNextLine(hReadFileHandle,
  2790. pbEndReadData,
  2791. pbufRead,
  2792. pbufLine,
  2793. dwLineLen,
  2794. pbNextPtr)) {
  2795. if (bLineId == MD_ID_DATA) {
  2796. hresReturn = ReadDataObject( g_pboMasterRoot,
  2797. pbufLine,
  2798. dwLineLen,
  2799. pStorage,
  2800. bUnicode
  2801. );
  2802. }
  2803. }
  2804. }
  2805. }
  2806. //
  2807. // All of the required stuff is read in, and the next line is either
  2808. // NULL or the first normal object.
  2809. // Loop through all normal objects.
  2810. //
  2811. if (SUCCEEDED(hresReturn)) {
  2812. while ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)) {
  2813. MD_ASSERT(bLineId == MD_ID_OBJECT);
  2814. for (hresReturn = ReadMetaObject(pboRead,
  2815. pbufLine,
  2816. dwLineLen,
  2817. pStorage,
  2818. bUnicode);
  2819. (FAILED(hresReturn));
  2820. hresReturn = ReadMetaObject(pboRead,
  2821. pbufLine,
  2822. dwLineLen,
  2823. pStorage,
  2824. bUnicode)) {
  2825. //
  2826. // This for loop normally shouldn't be executed.
  2827. // The purpose of the loop is to ignore problems if
  2828. // the object is bad.
  2829. //
  2830. if (hresReturn == RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY)) {
  2831. //
  2832. // Serious error, we're done.
  2833. //
  2834. break;
  2835. }
  2836. else {
  2837. //
  2838. // Just give a warning and go to the next object
  2839. // Ignore everything until we get to the next object
  2840. //
  2841. hresWarningCode = hresReturn;
  2842. for (hresReturn = GetNextLine(hReadFileHandle,
  2843. pbEndReadData,
  2844. pbufRead,
  2845. pbufLine,
  2846. dwLineLen,
  2847. pbNextPtr);
  2848. ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)
  2849. && ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
  2850. hresReturn = GetNextLine(hReadFileHandle,
  2851. pbEndReadData,
  2852. pbufRead,
  2853. pbufLine,
  2854. dwLineLen,
  2855. pbNextPtr)) {
  2856. }
  2857. if (dwLineLen == 0) {
  2858. //
  2859. // EOF, we're done
  2860. //
  2861. break;
  2862. }
  2863. }
  2864. }
  2865. if ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)) {
  2866. //
  2867. // Got an object.
  2868. // Read in data.
  2869. //
  2870. for (hresReturn = GetNextLine(hReadFileHandle,
  2871. pbEndReadData,
  2872. pbufRead,
  2873. pbufLine,
  2874. dwLineLen,
  2875. pbNextPtr);
  2876. ((SUCCEEDED(hresReturn)) && (dwLineLen > 0)
  2877. //
  2878. // GetLineID increments strCurPtr if a match is found
  2879. //
  2880. && ((bLineId = *(PBYTE)pbufLine->QueryPtr()) != MD_ID_OBJECT));
  2881. hresReturn = GetNextLine(hReadFileHandle,
  2882. pbEndReadData,
  2883. pbufRead,
  2884. pbufLine,
  2885. dwLineLen,
  2886. pbNextPtr)) {
  2887. if (bLineId == MD_ID_DATA) {
  2888. hresReturn = ReadDataObject( pboRead,
  2889. pbufLine,
  2890. dwLineLen,
  2891. pStorage,
  2892. bUnicode
  2893. );
  2894. //
  2895. // dwReturn gets blown away by the for loop.
  2896. // Most errors we can just ignore anyway, but
  2897. // save a warning.
  2898. //
  2899. if (FAILED(hresReturn)) {
  2900. if (hresReturn != RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY)) {
  2901. hresWarningCode = hresReturn;
  2902. }
  2903. else {
  2904. break;
  2905. }
  2906. }
  2907. }
  2908. }
  2909. }
  2910. }
  2911. }
  2912. //
  2913. // Must have MasterResource when accessing SystemChangeNumber
  2914. // so save it away here. Only update LastSaveChangeNumber on success.
  2915. //
  2916. dwTempLastSaveChangeNumber = g_dwSystemChangeNumber;
  2917. g_LockMasterResource.WriteUnlock();
  2918. }
  2919. }
  2920. if (!CloseHandle(hReadFileHandle)) {
  2921. dwError = GetLastError();
  2922. hresReturn = RETURNCODETOHRESULT(dwError);
  2923. }
  2924. hReadFileHandle = INVALID_HANDLE_VALUE;
  2925. }
  2926. }
  2927. //
  2928. // File not found is ok
  2929. // Start with MasterRoot only
  2930. //
  2931. if (hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) {
  2932. hresReturn = ERROR_SUCCESS;
  2933. }
  2934. if ((SUCCEEDED(hresReturn)) && (hresWarningCode != ERROR_SUCCESS)) {
  2935. hresReturn = GetWarning(hresWarningCode);
  2936. }
  2937. if (SUCCEEDED(hresReturn)) {
  2938. g_dwLastSaveChangeNumber = dwTempLastSaveChangeNumber;
  2939. }
  2940. //
  2941. // Cleanup
  2942. //
  2943. if (!bHaveReadSaveSemaphore) {
  2944. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  2945. }
  2946. delete(pbufRead);
  2947. delete(pbufLine);
  2948. delete(pStorage);
  2949. if(NULL != wszFileName)
  2950. {
  2951. delete [] wszFileName;
  2952. }
  2953. if ((hReadFileHandle != INVALID_HANDLE_VALUE) && (hReadFileHandle != NULL))
  2954. {
  2955. CloseHandle(hReadFileHandle);
  2956. hReadFileHandle = INVALID_HANDLE_VALUE;
  2957. }
  2958. return hresReturn;
  2959. }
  2960. VOID
  2961. InitializeGlobalsToNull()
  2962. {
  2963. DWORD i;
  2964. g_pboMasterRoot = NULL;
  2965. g_phHandleHead = NULL;
  2966. for ( i = 0; i < EVENT_ARRAY_LENGTH; i++ )
  2967. {
  2968. g_phEventHandles[i] = NULL;
  2969. }
  2970. g_mhHandleIdentifier = METADATA_MASTER_ROOT_HANDLE;
  2971. g_ppbdDataHashTable = NULL;
  2972. g_dwSystemChangeNumber = 0;
  2973. g_strRealFileName = NULL;
  2974. g_strTempFileName = NULL;
  2975. g_strBackupFileName = NULL;
  2976. g_pstrBackupFilePath = NULL;
  2977. g_strSchemaFileName = NULL;
  2978. memset( &g_XMLSchemaFileTimeStamp, 0, sizeof(FILETIME) );
  2979. memset( &g_BINSchemaFileTimeStamp, 0, sizeof(FILETIME) );
  2980. EnterCriticalSection( &g_csEditWhileRunning );
  2981. memset( &g_MostRecentMetabaseFileLastWriteTimeStamp, 0, sizeof(FILETIME) );
  2982. memset( &g_EWRProcessedMetabaseTimeStamp, 0, sizeof(FILETIME) );
  2983. g_bSavingMetabaseFileToDisk = FALSE;
  2984. g_ulMostRecentMetabaseVersion = 0;
  2985. LeaveCriticalSection( &g_csEditWhileRunning );
  2986. InitializeUnicodeGlobalDataFileValues();
  2987. g_pGlobalISTHelper = NULL;
  2988. g_pListenerController = NULL;
  2989. g_pEventLog = NULL;
  2990. g_psidSystem = NULL;
  2991. g_psidAdmin = NULL;
  2992. g_paclDiscretionary = NULL;
  2993. g_psdStorage = NULL;
  2994. }
  2995. HRESULT
  2996. InitWorker(
  2997. IN BOOL bHaveReadSaveSemaphore,
  2998. IN LPSTR pszPasswd,
  2999. IN LPSTR pszBackupLocation,
  3000. IN LPSTR pszSchemaLocation)
  3001. {
  3002. HRESULT hr = S_OK;
  3003. ISimpleTableDispenser2 * pISTDisp = NULL;
  3004. IAdvancedTableDispenser * pISTAdvanced = NULL;
  3005. DWORD i;
  3006. DWORD dwOld;
  3007. DWORD dwNew;
  3008. bool fReadLocked = true; // This has to be bool, otherwise compiler gives a warning
  3009. DBGPRINTF(( DBG_CONTEXT,
  3010. "Enter InitWorker g_dwInitialized = %d\n",
  3011. g_dwInitialized ));
  3012. // TryWriteLock gives us 2 very important benefits:
  3013. // 1. If we can lock exclusive we can skip the smarts bellow.
  3014. // 2. If the caller already has acquired write lock we must recursively write lock.
  3015. if ( !g_LockMasterResource.TryWriteLock() )
  3016. {
  3017. g_LockMasterResource.ReadLock();
  3018. DBGPRINTF(( DBG_CONTEXT,
  3019. "InitWorker ReadLock\n" ));
  3020. dwOld = g_dwInitialized;
  3021. // If we are not about to add the 1st reference
  3022. while ( dwOld != 0 )
  3023. {
  3024. DBGPRINTF(( DBG_CONTEXT,
  3025. "InitWorker Old = %d\n",
  3026. dwOld ));
  3027. dwNew = (DWORD)InterlockedCompareExchange( (LONG*)&g_dwInitialized,
  3028. dwOld+1,
  3029. dwOld );
  3030. DBGPRINTF(( DBG_CONTEXT,
  3031. "InitWorker Old = %d New = %d\n",
  3032. dwOld,
  3033. dwNew ));
  3034. if ( dwOld == dwNew )
  3035. {
  3036. // We added a reference that was not the 1st one.
  3037. // We are done
  3038. hr = g_hresInitWarning;
  3039. DBGPRINTF(( DBG_CONTEXT,
  3040. "InitWorker Done hr = 0x%08x g_dwInitialized = %d\n",
  3041. hr,
  3042. g_dwInitialized ));
  3043. goto exit;
  3044. }
  3045. // Somebody else was faster than us. Retry.
  3046. dwOld = dwNew;
  3047. }
  3048. // We are about to add the 1st reference.
  3049. // It must happend under a write lock.
  3050. // Note that other reader/writers might do something with g_dwInitialized meanwhile
  3051. g_LockMasterResource.ConvertSharedToExclusive();
  3052. }
  3053. DBGPRINTF(( DBG_CONTEXT,
  3054. "InitWorker WriteLock\n" ));
  3055. // Either through success of TryWriteLock() or via ConvertSharedToExclusive()
  3056. // we have a write lock
  3057. fReadLocked = false;
  3058. dwNew = (DWORD)InterlockedIncrement( (LONG*)&g_dwInitialized );
  3059. if ( dwNew != 1 )
  3060. {
  3061. // We added a reference that was not the 1st one.
  3062. // We are done
  3063. hr = g_hresInitWarning;
  3064. DBGPRINTF(( DBG_CONTEXT,
  3065. "InitWorker Done hr = 0x%08x g_dwInitialized = %d\n",
  3066. hr,
  3067. g_dwInitialized ));
  3068. goto exit;
  3069. }
  3070. InitializeGlobalsToNull();
  3071. g_pboMasterRoot = new CMDBaseObject(MD_MASTER_ROOT_NAME);
  3072. if ( ( g_pboMasterRoot == NULL ) || ( !g_pboMasterRoot->IsValid() ) )
  3073. {
  3074. IIS_PRINTF(( buff, "Unable to allocate CMDBaseObject\n" ));
  3075. hr = E_OUTOFMEMORY;
  3076. goto cleanup;
  3077. }
  3078. g_pboMasterRoot->SetParent(NULL);
  3079. g_phHandleHead = new CMDHandle( g_pboMasterRoot,
  3080. METADATA_PERMISSION_READ,
  3081. g_dwSystemChangeNumber,
  3082. g_mhHandleIdentifier++,
  3083. FALSE );
  3084. if (g_phHandleHead == NULL)
  3085. {
  3086. IIS_PRINTF(( buff, "Unable to allocate CMDHandle\n" ));
  3087. hr = E_OUTOFMEMORY;
  3088. goto cleanup;
  3089. }
  3090. g_phHandleHead->SetNextPtr(NULL);
  3091. g_phEventHandles[EVENT_READ_INDEX] = IIS_CREATE_EVENT( "g_phEventHandles[EVENT_READ_INDEX]",
  3092. &g_phEventHandles[EVENT_READ_INDEX],
  3093. TRUE,
  3094. FALSE );
  3095. if ( g_phEventHandles[EVENT_READ_INDEX] == NULL )
  3096. {
  3097. hr = GetLastHResult();
  3098. IIS_PRINTF(( buff, "CreateEvent Failed with %x\n",hr ));
  3099. goto cleanup;
  3100. }
  3101. g_phEventHandles[EVENT_WRITE_INDEX] = IIS_CREATE_EVENT( "g_phEventHandles[EVENT_WRITE_INDEX]",
  3102. &g_phEventHandles[EVENT_WRITE_INDEX],
  3103. TRUE,
  3104. FALSE );
  3105. if( g_phEventHandles[EVENT_WRITE_INDEX] == NULL )
  3106. {
  3107. hr = GetLastHResult();
  3108. IIS_PRINTF(( buff, "CreateEvent Failed with %x\n", hr ));
  3109. goto cleanup;
  3110. }
  3111. g_ppbdDataHashTable = new CMDBaseData *[DATA_HASH_TABLE_LEN];
  3112. if ( g_ppbdDataHashTable == NULL)
  3113. {
  3114. IIS_PRINTF(( buff, "Unable to allocate CMDBaseData\n" ));
  3115. hr = E_OUTOFMEMORY;
  3116. goto cleanup;
  3117. }
  3118. for ( i=0; i < DATA_HASH_TABLE_LEN; i++ )
  3119. {
  3120. g_ppbdDataHashTable[i] = NULL;
  3121. }
  3122. hr = InitBufferPool();
  3123. if ( FAILED( hr ) )
  3124. {
  3125. goto cleanup;
  3126. }
  3127. // Code Work:
  3128. // There is a conceiveable deadlock if ReadAllData is called with g_LockMasterResource Locked,
  3129. // due to the semaphore used to control file access. Would like to release g_LockMasterResource,
  3130. // but that could cause duplicate inits.
  3131. hr = SetStorageSecurityDescriptor();
  3132. if ( FAILED( hr ) )
  3133. {
  3134. goto cleanup;
  3135. }
  3136. // Initialize logging object first
  3137. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  3138. if ( FAILED( hr ) )
  3139. {
  3140. goto cleanup;
  3141. }
  3142. hr = pISTDisp->QueryInterface( IID_IAdvancedTableDispenser,
  3143. (LPVOID*)&pISTAdvanced );
  3144. pISTDisp->Release();
  3145. pISTDisp = NULL;
  3146. if ( FAILED( hr ) )
  3147. {
  3148. goto cleanup;
  3149. }
  3150. hr = pISTAdvanced->GetCatalogErrorLogger( &g_pEventLog );
  3151. pISTAdvanced->Release();
  3152. pISTAdvanced = NULL;
  3153. if ( FAILED( hr ) )
  3154. {
  3155. goto cleanup;
  3156. }
  3157. hr = SetDataFile();
  3158. if ( FAILED( hr ) )
  3159. {
  3160. goto cleanup;
  3161. }
  3162. hr = ReadAllData( pszPasswd, pszBackupLocation, pszSchemaLocation, bHaveReadSaveSemaphore );
  3163. if ( FAILED( hr ) )
  3164. {
  3165. goto cleanup;
  3166. }
  3167. // Check if the Major/Minor version needs to get updated...
  3168. // if there is a specified version in the registry (set by iis setup during upgrade)
  3169. // then use that new version, if it's not a dword, then use the default for g_dwMajorVersionNumber.
  3170. CheckForNewMetabaseVersion();
  3171. if ( !CheckVersionNumber() )
  3172. {
  3173. IIS_PRINTF(( buff, "MD: Invalid version number\n" ));
  3174. hr = MD_ERROR_INVALID_VERSION;
  3175. goto cleanup;
  3176. }
  3177. // Initialize the listener controller and depending on whether Edit
  3178. // While running is enabled or disabled, start or stop it.
  3179. hr = InitializeListenerController();
  3180. if ( FAILED( hr ) )
  3181. {
  3182. goto cleanup;
  3183. }
  3184. if( g_dwEnableEditWhileRunning )
  3185. {
  3186. hr = g_pListenerController->Start();
  3187. }
  3188. else
  3189. {
  3190. hr = g_pListenerController->Stop( iSTATE_STOP_TEMPORARY,
  3191. NULL);
  3192. }
  3193. if ( FAILED( hr ) )
  3194. {
  3195. goto cleanup;
  3196. }
  3197. cleanup:
  3198. // Cleanup
  3199. if ( FAILED( hr ) )
  3200. {
  3201. DBGPRINTF(( DBG_CONTEXT,
  3202. "InitWorker Failed hr = 0x%08x!!!\n",
  3203. hr ));
  3204. InterlockedDecrement( (LONG*)&g_dwInitialized );
  3205. TerminateWorker();
  3206. }
  3207. // Save the return code.
  3208. // Secondary init's repeat warnings.
  3209. // If error, the next init will overwrite this.
  3210. // So don't worry about setting this to errors.
  3211. g_hresInitWarning = hr;
  3212. exit:
  3213. g_LockMasterResource.ReadOrWriteUnlock( fReadLocked );
  3214. DBGPRINTF(( DBG_CONTEXT,
  3215. "InitWorker %sUnlock\n",
  3216. fReadLocked ? "Read" : "Write" ));
  3217. DBGPRINTF(( DBG_CONTEXT,
  3218. "End InitWorker hr = 0x%08x g_dwInitialized = %d\n",
  3219. hr,
  3220. g_dwInitialized ));
  3221. return hr;
  3222. }
  3223. HRESULT
  3224. TerminateWorker1(
  3225. IN BOOL bHaveReadSaveSemaphore)
  3226. {
  3227. HRESULT hr = S_OK;
  3228. IIS_CRYPTO_STORAGE CryptoStorage;
  3229. PIIS_CRYPTO_BLOB pSessionKeyBlob = NULL;
  3230. HANDLE hEditWhileRunningThread = NULL;
  3231. DWORD dwOld;
  3232. DWORD dwNew;
  3233. bool fReadLocked = true; // This has to be bool, otherwise compiler gives a warning
  3234. DBGPRINTF(( DBG_CONTEXT,
  3235. "Enter TerminateWorker1 g_dwInitialized = %d\n",
  3236. g_dwInitialized ));
  3237. // TryWriteLock gives us 2 very important benefits:
  3238. // 1. If we can lock exclusive we can skip the smarts bellow.
  3239. // 2. If the caller already has acquired write lock we must recursively write lock.
  3240. if ( !g_LockMasterResource.TryWriteLock() )
  3241. {
  3242. g_LockMasterResource.ReadLock();
  3243. DBGPRINTF(( DBG_CONTEXT,
  3244. "TerminateWorker1 ReadLock\n" ));
  3245. dwOld = g_dwInitialized;
  3246. // If we are not about to release the last reference
  3247. while ( dwOld != 1 )
  3248. {
  3249. DBGPRINTF(( DBG_CONTEXT,
  3250. "TerminateWorker1 Old = %d\n",
  3251. dwOld ));
  3252. if ( dwOld == 0 )
  3253. {
  3254. hr = MD_ERROR_NOT_INITIALIZED;
  3255. DBGPRINTF(( DBG_CONTEXT,
  3256. "TerminateWorker1 Not Initialized hr = 0x%08x!!!\n",
  3257. hr ));
  3258. goto exit;
  3259. }
  3260. dwNew = (DWORD)InterlockedCompareExchange( (LONG*)&g_dwInitialized,
  3261. dwOld-1,
  3262. dwOld );
  3263. DBGPRINTF(( DBG_CONTEXT,
  3264. "TerminateWorker1 Old = %d New = %d\n",
  3265. dwOld,
  3266. dwNew ));
  3267. if ( dwOld == dwNew )
  3268. {
  3269. DBGPRINTF(( DBG_CONTEXT,
  3270. "TerminateWorker1 Done hr = 0x%08x g_dwInitialized = %d\n",
  3271. hr,
  3272. g_dwInitialized ));
  3273. // We released a reference that was not the last one.
  3274. // We are done
  3275. goto exit;
  3276. }
  3277. // Somebody else was faster than us. Retry.
  3278. dwOld = dwNew;
  3279. }
  3280. // We are about to release the last reference.
  3281. // It must happend under a write lock.
  3282. // Note that other readers/writers might do something with g_dwInitialized meanwhile
  3283. g_LockMasterResource.ConvertSharedToExclusive();
  3284. }
  3285. // Either through success of TryWriteLock() or via ConvertSharedToExclusive()
  3286. // we have a write lock
  3287. fReadLocked = false;
  3288. DBGPRINTF(( DBG_CONTEXT,
  3289. "TerminateWorker1 WriteLock\n" ));
  3290. if ( g_dwInitialized == 0 )
  3291. {
  3292. hr = MD_ERROR_NOT_INITIALIZED;
  3293. DBGPRINTF(( DBG_CONTEXT,
  3294. "TerminateWorker1 Not Initialized hr = 0x%08x!!!\n",
  3295. hr ));
  3296. goto exit;
  3297. }
  3298. if ( g_dwInitialized == 1 )
  3299. {
  3300. DBGPRINTF(( DBG_CONTEXT,
  3301. "TerminateWorker1 Stopping EWR\n" ));
  3302. if ( g_pListenerController != NULL )
  3303. {
  3304. hr = g_pListenerController->Stop( iSTATE_STOP_PERMANENT,
  3305. &hEditWhileRunningThread );
  3306. }
  3307. if ( FAILED( hr ) )
  3308. {
  3309. goto exit;
  3310. }
  3311. DBGPRINTF(( DBG_CONTEXT,
  3312. "TerminateWorker1 Getting key\n" ));
  3313. hr = InitStorageAndSessionKey( &CryptoStorage,
  3314. &pSessionKeyBlob );
  3315. if ( FAILED( hr ) )
  3316. {
  3317. // pretty serious.
  3318. DBGPRINTF(( DBG_CONTEXT, "TerminateWorker1.InitStorageAndSessionKey:Failed - error 0x%0x\n", hr ));
  3319. goto exit;
  3320. }
  3321. DBGPRINTF(( DBG_CONTEXT,
  3322. "TerminateWorker1 Saving data\n" ));
  3323. hr = SaveAllData( FALSE,
  3324. &CryptoStorage,
  3325. pSessionKeyBlob,
  3326. NULL,
  3327. NULL,
  3328. METADATA_MASTER_ROOT_HANDLE,
  3329. bHaveReadSaveSemaphore,
  3330. TRUE );
  3331. if ( FAILED( hr ) )
  3332. {
  3333. goto exit;
  3334. }
  3335. }
  3336. dwNew = (DWORD)InterlockedDecrement( (LONG*)&g_dwInitialized );
  3337. if ( dwNew == 0 )
  3338. {
  3339. DBGPRINTF(( DBG_CONTEXT,
  3340. "TerminateWorker1 Last Terminate\n" ));
  3341. TerminateWorker();
  3342. }
  3343. exit:
  3344. DBGPRINTF(( DBG_CONTEXT,
  3345. "TerminateWorker1 %sUnlock\n",
  3346. fReadLocked ? "Read" : "Write" ));
  3347. g_LockMasterResource.ReadOrWriteUnlock( fReadLocked );
  3348. if ( pSessionKeyBlob != NULL )
  3349. {
  3350. ::IISCryptoFreeBlob( pSessionKeyBlob );
  3351. pSessionKeyBlob = NULL;
  3352. }
  3353. // Wait for the Edit while running thread to die before terminating
  3354. // Note that we wait after the lock is released.
  3355. if ( hEditWhileRunningThread != NULL )
  3356. {
  3357. DBGPRINTF(( DBG_CONTEXT,
  3358. "TerminateWorker1 Waiting for EWR\n" ));
  3359. WaitForSingleObject( hEditWhileRunningThread, INFINITE );
  3360. CloseHandle( hEditWhileRunningThread );
  3361. hEditWhileRunningThread = NULL;
  3362. DBGPRINTF(( DBG_CONTEXT,
  3363. "TerminateWorker1 EWR stopped\n" ));
  3364. }
  3365. DBGPRINTF(( DBG_CONTEXT,
  3366. "End TerminateWorker1 hr = 0x%08x g_dwInitialized = %d\n",
  3367. hr,
  3368. g_dwInitialized ));
  3369. return hr;
  3370. }
  3371. VOID
  3372. TerminateWorker()
  3373. /*++
  3374. Routine Description:
  3375. Worker routine for termination.
  3376. Arguments:
  3377. Return Value:
  3378. VOID
  3379. Notes:
  3380. --*/
  3381. {
  3382. CMDHandle *CurHandle;
  3383. CMDHandle *NextHandle;
  3384. DWORD i;
  3385. for ( CurHandle = g_phHandleHead; CurHandle != NULL ; CurHandle = NextHandle )
  3386. {
  3387. NextHandle = CurHandle->GetNextPtr();
  3388. delete CurHandle;
  3389. }
  3390. for ( i = 0; i < EVENT_ARRAY_LENGTH; i++ )
  3391. {
  3392. if ( g_phEventHandles[i] != NULL )
  3393. {
  3394. CloseHandle( g_phEventHandles[i] );
  3395. }
  3396. }
  3397. if ( g_pboMasterRoot != NULL )
  3398. {
  3399. // Perf fix.
  3400. g_pboMasterRoot->CascadingDataCleanup();
  3401. delete g_pboMasterRoot;
  3402. }
  3403. // All data objects should be deleted by
  3404. // deleting the handles and masterroot
  3405. // but it's possible a client failed
  3406. // to release a data by reference so
  3407. // destroy all remaining data objects
  3408. DeleteAllRemainingDataObjects();
  3409. ReleaseStorageSecurityDescriptor();
  3410. if ( g_ppbdDataHashTable != NULL )
  3411. {
  3412. delete [] g_ppbdDataHashTable;
  3413. }
  3414. if ( g_strRealFileName != NULL )
  3415. {
  3416. delete g_strRealFileName;
  3417. }
  3418. if ( g_strRealFileName != NULL )
  3419. {
  3420. delete g_strTempFileName;
  3421. }
  3422. if ( g_strRealFileName != NULL )
  3423. {
  3424. delete g_strBackupFileName;
  3425. }
  3426. if ( g_strRealFileName != NULL )
  3427. {
  3428. delete g_pstrBackupFilePath;
  3429. }
  3430. if ( g_strRealFileName != NULL )
  3431. {
  3432. delete g_strSchemaFileName;
  3433. }
  3434. UnInitializeUnicodeGlobalDataFileValues();
  3435. if ( g_pGlobalISTHelper != NULL )
  3436. {
  3437. delete g_pGlobalISTHelper;
  3438. }
  3439. if ( g_pEventLog != NULL )
  3440. {
  3441. g_pEventLog->Release();
  3442. }
  3443. UnInitializeListenerController();
  3444. DeleteBufferPool();
  3445. InitializeGlobalsToNull();
  3446. }
  3447. HRESULT
  3448. SetStorageSecurityDescriptor()
  3449. {
  3450. HRESULT hresReturn = ERROR_SUCCESS;
  3451. BOOL status;
  3452. DWORD dwDaclSize;
  3453. SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
  3454. PLATFORM_TYPE platformType;
  3455. //
  3456. // Verify that globals were initialized correctly.
  3457. //
  3458. MD_ASSERT(g_psidSystem == NULL);
  3459. MD_ASSERT(g_psidAdmin == NULL);
  3460. MD_ASSERT(g_paclDiscretionary == NULL);
  3461. MD_ASSERT(g_psdStorage == NULL);
  3462. //
  3463. // Of course, we only need to do this under NT...
  3464. //
  3465. platformType = IISGetPlatformType();
  3466. if( (platformType == PtNtWorkstation) || (platformType == PtNtServer ) ) {
  3467. g_psdStorage = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
  3468. if (g_psdStorage == NULL) {
  3469. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3470. goto fatal;
  3471. }
  3472. //
  3473. // Initialize the security descriptor.
  3474. //
  3475. status = InitializeSecurityDescriptor(
  3476. g_psdStorage,
  3477. SECURITY_DESCRIPTOR_REVISION
  3478. );
  3479. if( !status ) {
  3480. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3481. goto fatal;
  3482. }
  3483. //
  3484. // Create the SIDs for the local system and admin group.
  3485. //
  3486. status = AllocateAndInitializeSid(
  3487. &ntAuthority,
  3488. 1,
  3489. SECURITY_LOCAL_SYSTEM_RID,
  3490. 0,
  3491. 0,
  3492. 0,
  3493. 0,
  3494. 0,
  3495. 0,
  3496. 0,
  3497. &g_psidSystem
  3498. );
  3499. if( !status ) {
  3500. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3501. goto fatal;
  3502. }
  3503. status= AllocateAndInitializeSid(
  3504. &ntAuthority,
  3505. 2,
  3506. SECURITY_BUILTIN_DOMAIN_RID,
  3507. DOMAIN_ALIAS_RID_ADMINS,
  3508. 0,
  3509. 0,
  3510. 0,
  3511. 0,
  3512. 0,
  3513. 0,
  3514. &g_psidAdmin
  3515. );
  3516. if( !status ) {
  3517. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3518. goto fatal;
  3519. }
  3520. //
  3521. // Create the DACL containing an access-allowed ACE
  3522. // for the local system and admin SIDs.
  3523. //
  3524. dwDaclSize = sizeof(ACL)
  3525. + sizeof(ACCESS_ALLOWED_ACE)
  3526. + GetLengthSid(g_psidAdmin)
  3527. + sizeof(ACCESS_ALLOWED_ACE)
  3528. + GetLengthSid(g_psidSystem)
  3529. - sizeof(DWORD);
  3530. g_paclDiscretionary = (PACL)LocalAlloc(LPTR, dwDaclSize );
  3531. if( g_paclDiscretionary == NULL ) {
  3532. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3533. goto fatal;
  3534. }
  3535. status = InitializeAcl(
  3536. g_paclDiscretionary,
  3537. dwDaclSize,
  3538. ACL_REVISION
  3539. );
  3540. if( !status ) {
  3541. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3542. goto fatal;
  3543. }
  3544. status = AddAccessAllowedAce(
  3545. g_paclDiscretionary,
  3546. ACL_REVISION,
  3547. FILE_ALL_ACCESS,
  3548. g_psidSystem
  3549. );
  3550. if( !status ) {
  3551. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3552. goto fatal;
  3553. }
  3554. status = AddAccessAllowedAce(
  3555. g_paclDiscretionary,
  3556. ACL_REVISION,
  3557. FILE_ALL_ACCESS,
  3558. g_psidAdmin
  3559. );
  3560. if( !status ) {
  3561. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3562. goto fatal;
  3563. }
  3564. //
  3565. // Set the DACL into the security descriptor.
  3566. //
  3567. status = SetSecurityDescriptorDacl(
  3568. g_psdStorage,
  3569. TRUE,
  3570. g_paclDiscretionary,
  3571. FALSE
  3572. );
  3573. if( !status ) {
  3574. hresReturn = RETURNCODETOHRESULT(GetLastError());
  3575. goto fatal;
  3576. }
  3577. }
  3578. fatal:
  3579. if (FAILED(hresReturn)) {
  3580. ReleaseStorageSecurityDescriptor();
  3581. }
  3582. return hresReturn;
  3583. }
  3584. VOID
  3585. ReleaseStorageSecurityDescriptor()
  3586. {
  3587. if( g_paclDiscretionary != NULL ) {
  3588. LocalFree( g_paclDiscretionary );
  3589. g_paclDiscretionary = NULL;
  3590. }
  3591. if( g_psidAdmin != NULL ) {
  3592. FreeSid( g_psidAdmin );
  3593. g_psidAdmin = NULL;
  3594. }
  3595. if( g_psidSystem != NULL ) {
  3596. FreeSid( g_psidSystem );
  3597. g_psidSystem = NULL;
  3598. }
  3599. if( g_psdStorage != NULL ) {
  3600. LocalFree( g_psdStorage );
  3601. g_psdStorage = NULL;
  3602. }
  3603. }
  3604. HRESULT
  3605. ExtractNameFromPath(
  3606. IN OUT LPSTR &strPath,
  3607. OUT LPSTR strNameBuffer,
  3608. IN BOOL bUnicode)
  3609. /*++
  3610. Routine Description:
  3611. Finds the next name in a path.
  3612. Arguments:
  3613. Path - The path. Updated on success to point past the name.
  3614. NameBuffer - The buffer to store the name.
  3615. Return Value:
  3616. DWORD - ERROR_SUCCESS
  3617. ERROR_PATH_NOT_FOUND
  3618. ERROR_INVALID_NAME
  3619. Notes:
  3620. --*/
  3621. {
  3622. LPSTR pszIndex;
  3623. HRESULT hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  3624. MD_ASSERT(strNameBuffer != NULL);
  3625. if (bUnicode) {
  3626. LPWSTR wstrPath = (LPWSTR)strPath;
  3627. hresReturn = ExtractNameFromPath(&wstrPath, (LPWSTR)strNameBuffer);
  3628. strPath = (LPSTR) wstrPath;
  3629. }
  3630. else {
  3631. if (strPath != NULL) {
  3632. for (pszIndex = strPath;
  3633. ((pszIndex - strPath) < METADATA_MAX_NAME_LEN) && (*pszIndex != (TCHAR)'\0') &&
  3634. (*pszIndex != MD_PATH_DELIMETER) && (*pszIndex != MD_ALT_PATH_DELIMETER);
  3635. pszIndex = CharNextExA(CP_ACP,
  3636. pszIndex,
  3637. 0)) {
  3638. }
  3639. DWORD dwStrBytes = (DWORD)DIFF(pszIndex - strPath);
  3640. if ((dwStrBytes) >= METADATA_MAX_NAME_LEN) {
  3641. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
  3642. }
  3643. else {
  3644. MD_COPY(strNameBuffer, strPath, dwStrBytes);
  3645. strNameBuffer[dwStrBytes] = (TCHAR)'\0';
  3646. strPath = pszIndex;
  3647. if (*strNameBuffer != (TCHAR)'\0') {
  3648. //
  3649. // if a non-null name
  3650. //
  3651. SKIP_PATH_DELIMETERA(strPath);
  3652. hresReturn = ERROR_SUCCESS;
  3653. }
  3654. }
  3655. }
  3656. }
  3657. return (hresReturn);
  3658. }
  3659. HRESULT
  3660. ExtractNameFromPath(
  3661. IN OUT LPWSTR *pstrPath,
  3662. OUT LPWSTR strNameBuffer)
  3663. /*++
  3664. Routine Description:
  3665. Finds the next name in a path.
  3666. Arguments:
  3667. Path - The path. Updated on success to point past the name.
  3668. NameBuffer - The buffer to store the name.
  3669. Return Value:
  3670. DWORD - ERROR_SUCCESS
  3671. ERROR_PATH_NOT_FOUND
  3672. ERROR_INVALID_NAME
  3673. Notes:
  3674. --*/
  3675. {
  3676. int i;
  3677. HRESULT hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  3678. MD_ASSERT(strNameBuffer != NULL);
  3679. if (*pstrPath != NULL) {
  3680. for (i = 0;
  3681. (i < METADATA_MAX_NAME_LEN) && ((*pstrPath)[i] != (WCHAR)L'\0') &&
  3682. ((*pstrPath)[i] != (WCHAR)MD_PATH_DELIMETER) && ((*pstrPath)[i] != (WCHAR)MD_ALT_PATH_DELIMETER);
  3683. i++) {
  3684. strNameBuffer[i] = (*pstrPath)[i];
  3685. }
  3686. if (i == METADATA_MAX_NAME_LEN) {
  3687. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
  3688. }
  3689. else {
  3690. strNameBuffer[i] = (WCHAR)L'\0';
  3691. *pstrPath += i;
  3692. if (*strNameBuffer != (WCHAR)L'\0') {
  3693. //
  3694. // if a non-null name
  3695. //
  3696. SKIP_PATH_DELIMETERW(*pstrPath);
  3697. hresReturn = ERROR_SUCCESS;
  3698. }
  3699. }
  3700. }
  3701. return (hresReturn);
  3702. }
  3703. BOOL DataMatch(IN CMDBaseData *pbdExisting,
  3704. IN PMETADATA_RECORD pmdrData,
  3705. OUT PBOOL pbError,
  3706. IN BOOL bUnicode)
  3707. {
  3708. /*++
  3709. Routine Description:
  3710. Determines if a set of data maches an existing object.
  3711. Arguments:
  3712. Existing - The existing data object.
  3713. Identifier - The Identifier of the data.
  3714. Attributes - The flags for the data.
  3715. METADATA_INHERIT
  3716. UserType - The User Type for the data. User Defined.
  3717. DataType - The Type of the data.
  3718. DWORD_METADATA
  3719. STRING_METADATA
  3720. BINARY_METADATA
  3721. DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
  3722. Binary data must not exceed METADATA_MAX_BINARY_LEN bytes.
  3723. String data must not exceed METADATA_MAX_STRING_LEN characters,
  3724. include the trailing '\0'.
  3725. Data - Pointer to the data.
  3726. Return Value:
  3727. BOOL - TRUE if the data matches
  3728. Notes:
  3729. --*/
  3730. BOOL bReturn = TRUE;
  3731. BOOL bError = FALSE;
  3732. if ((pmdrData->dwMDIdentifier != pbdExisting->GetIdentifier()) ||
  3733. (pmdrData->dwMDAttributes != pbdExisting->GetAttributes()) ||
  3734. (pmdrData->dwMDUserType != pbdExisting->GetUserType()) ||
  3735. (pmdrData->dwMDDataType != pbdExisting->GetDataType())) {
  3736. bReturn = FALSE;
  3737. }
  3738. else {
  3739. if (pbdExisting->GetData(bUnicode) == NULL) {
  3740. bError = TRUE;
  3741. }
  3742. else {
  3743. switch(pmdrData->dwMDDataType) {
  3744. case DWORD_METADATA: {
  3745. if (*(DWORD *)(pmdrData->pbMDData) != *(DWORD *)(pbdExisting->GetData())) {
  3746. bReturn = FALSE;
  3747. }
  3748. break;
  3749. }
  3750. case STRING_METADATA:
  3751. case EXPANDSZ_METADATA:
  3752. {
  3753. if (bUnicode) {
  3754. LPWSTR pszStringData = (LPWSTR)(pmdrData->pbMDData);
  3755. if (pszStringData == NULL) {
  3756. pszStringData = L"";
  3757. }
  3758. if (wcscmp(pszStringData, (LPWSTR)(pbdExisting->GetData(bUnicode))) != 0) {
  3759. bReturn = FALSE;
  3760. }
  3761. }
  3762. else {
  3763. LPSTR pszStringData = (LPSTR)(pmdrData->pbMDData);
  3764. if (pszStringData == NULL) {
  3765. pszStringData = "";
  3766. }
  3767. if (MD_STRCMP(pszStringData, (LPSTR)(pbdExisting->GetData(bUnicode))) != 0) {
  3768. bReturn = FALSE;
  3769. }
  3770. }
  3771. break;
  3772. }
  3773. case BINARY_METADATA:
  3774. case MULTISZ_METADATA:
  3775. {
  3776. if (pmdrData->dwMDDataLen != pbdExisting->GetDataLen(bUnicode)) {
  3777. bReturn = FALSE;
  3778. }
  3779. else {
  3780. if (MD_CMP(pmdrData->pbMDData, pbdExisting->GetData(bUnicode), pmdrData->dwMDDataLen) != 0) {
  3781. bReturn = FALSE;
  3782. }
  3783. }
  3784. break;
  3785. }
  3786. default: {
  3787. bReturn = FALSE;
  3788. }
  3789. }
  3790. }
  3791. }
  3792. *pbError = bError;
  3793. return (bReturn);
  3794. }
  3795. VOID
  3796. DeleteDataObject(
  3797. IN CMDBaseData *pbdDelete)
  3798. /*++
  3799. Routine Description:
  3800. Decrements the reference count of an object and deletes it if the reference count becomes 0.
  3801. Arguments:
  3802. Delete - The data object to delete.
  3803. Return Value:
  3804. Notes:
  3805. --*/
  3806. {
  3807. DWORD dwHash = DATA_HASH(pbdDelete->GetIdentifier());
  3808. CMDBaseData *pdataIndex;
  3809. MD_ASSERT(pbdDelete != NULL);
  3810. if (pbdDelete->DecrementReferenceCount() == 0) {
  3811. if (g_ppbdDataHashTable[dwHash] == pbdDelete) {
  3812. g_ppbdDataHashTable[dwHash] = pbdDelete->GetNextPtr();
  3813. }
  3814. else {
  3815. for (pdataIndex=g_ppbdDataHashTable[dwHash];
  3816. pdataIndex->GetNextPtr() != pbdDelete;
  3817. pdataIndex = pdataIndex->GetNextPtr()) {
  3818. }
  3819. pdataIndex->SetNextPtr(pbdDelete->GetNextPtr());
  3820. }
  3821. switch (pbdDelete->GetDataType()) {
  3822. case DWORD_METADATA: {
  3823. delete ((CMDDWData *) pbdDelete);
  3824. break;
  3825. }
  3826. case STRING_METADATA: {
  3827. delete ((CMDSTRData *) pbdDelete);
  3828. break;
  3829. }
  3830. case BINARY_METADATA: {
  3831. delete ((CMDBINData *) pbdDelete);
  3832. break;
  3833. }
  3834. case EXPANDSZ_METADATA: {
  3835. delete ((CMDEXSZData *) pbdDelete);
  3836. break;
  3837. }
  3838. case MULTISZ_METADATA: {
  3839. delete ((CMDMLSZData *) pbdDelete);
  3840. break;
  3841. }
  3842. default: {
  3843. MD_ASSERT(FALSE);
  3844. delete (pbdDelete);
  3845. }
  3846. }
  3847. }
  3848. }
  3849. VOID
  3850. DeleteAllRemainingDataObjects()
  3851. {
  3852. DWORD i;
  3853. CMDBaseData *pbdIndex;
  3854. CMDBaseData *pbdSave;
  3855. if ( g_ppbdDataHashTable == NULL )
  3856. {
  3857. return;
  3858. }
  3859. for (i = 0; i < DATA_HASH_TABLE_LEN; i++) {
  3860. for (pbdIndex=g_ppbdDataHashTable[i];
  3861. pbdIndex != NULL;
  3862. pbdIndex = pbdSave) {
  3863. pbdSave = pbdIndex->GetNextPtr();
  3864. switch (pbdIndex->GetDataType()) {
  3865. case DWORD_METADATA: {
  3866. delete ((CMDDWData *) pbdIndex);
  3867. break;
  3868. }
  3869. case STRING_METADATA: {
  3870. delete ((CMDSTRData *) pbdIndex);
  3871. break;
  3872. }
  3873. case BINARY_METADATA: {
  3874. delete ((CMDBINData *) pbdIndex);
  3875. break;
  3876. }
  3877. case EXPANDSZ_METADATA: {
  3878. delete ((CMDEXSZData *) pbdIndex);
  3879. break;
  3880. }
  3881. case MULTISZ_METADATA: {
  3882. delete ((CMDMLSZData *) pbdIndex);
  3883. break;
  3884. }
  3885. default: {
  3886. MD_ASSERT(FALSE);
  3887. delete (pbdIndex);
  3888. }
  3889. }
  3890. }
  3891. }
  3892. }
  3893. BOOL
  3894. ValidateData(IN PMETADATA_RECORD pmdrData,
  3895. IN BOOL bUnicode)
  3896. /*++
  3897. Routine Description:
  3898. Checks data values for new metadata.
  3899. Arguments:
  3900. Data - The data structure. All fields must be set.
  3901. Attributes - The flags for the data.
  3902. METADATA_INHERIT - If set on input, inherited data will be returned.
  3903. If not set on input, inherited data will not be returned.
  3904. METADATA_PARTIAL_PATH - If set on input, this routine will return ERROR_SUCCESS
  3905. and the inherited data even if the entire path is not present.
  3906. Only valid if METADATA_INHERIT is also set.
  3907. DataType - The Type of the data.
  3908. DWORD_METADATA
  3909. STRING_METADATA
  3910. BINARY_METADATA
  3911. Return Value:
  3912. BOOL - TRUE if the data values are valid.
  3913. Notes:
  3914. --*/
  3915. {
  3916. BOOL bReturn = TRUE;
  3917. LPCWSTR pwszData = NULL;
  3918. LPCSTR pszData = NULL;
  3919. DWORD dwDataLen = 0;
  3920. DWORD cch = 0;
  3921. ULONG i = 0;
  3922. // Must not have NULL DWORD data
  3923. if ( ( pmdrData->dwMDDataType == DWORD_METADATA ) &&
  3924. ( pmdrData->pbMDData == NULL ) )
  3925. {
  3926. bReturn = FALSE;
  3927. goto exit;
  3928. }
  3929. // Must not have NULL string (in all forms) or binary data
  3930. // with size >0
  3931. if ( ( ( pmdrData->dwMDDataType == BINARY_METADATA ) ||
  3932. ( pmdrData->dwMDDataType == MULTISZ_METADATA ) ||
  3933. ( pmdrData->dwMDDataType == EXPANDSZ_METADATA ) ||
  3934. ( pmdrData->dwMDDataType == STRING_METADATA ) ) &&
  3935. ( pmdrData->pbMDData == NULL ) &&
  3936. ( pmdrData->dwMDDataLen > 0 ) )
  3937. {
  3938. bReturn = FALSE;
  3939. goto exit;
  3940. }
  3941. // Must not have types outside the open interval (ALL_METADATA, INVALID_END_METADATA)
  3942. if ( ( pmdrData->dwMDDataType <= ALL_METADATA ) ||
  3943. ( pmdrData->dwMDDataType >= INVALID_END_METADATA ) )
  3944. {
  3945. bReturn = FALSE;
  3946. goto exit;
  3947. }
  3948. // Must not have unknown flags
  3949. if ( ( pmdrData->dwMDAttributes &
  3950. ~( METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE | METADATA_VOLATILE | METADATA_INSERT_PATH | METADATA_LOCAL_MACHINE_ONLY ) ) !=0 )
  3951. {
  3952. bReturn = FALSE;
  3953. goto exit;
  3954. }
  3955. // Must not have METADATA_INSERT_PATH together with METADATA_REFERENCE
  3956. if ( ( ( pmdrData->dwMDAttributes & METADATA_REFERENCE ) != 0 ) &&
  3957. ( ( pmdrData->dwMDAttributes & METADATA_INSERT_PATH ) != 0 ) )
  3958. {
  3959. bReturn = FALSE;
  3960. goto exit;
  3961. }
  3962. // Must not have METADATA_INSERT_PATH with DWORD or binary data
  3963. if ( ( ( pmdrData->dwMDDataType == DWORD_METADATA ) ||
  3964. ( pmdrData->dwMDDataType == BINARY_METADATA ) ) &&
  3965. ( ( pmdrData->dwMDAttributes & METADATA_INSERT_PATH ) != 0 ) )
  3966. {
  3967. bReturn = FALSE;
  3968. goto exit;
  3969. }
  3970. // Check multi strings
  3971. if ( pmdrData->dwMDDataType == MULTISZ_METADATA )
  3972. {
  3973. dwDataLen = pmdrData->dwMDDataLen;
  3974. // If the data size is 0 it is Ok
  3975. if ( dwDataLen == 0 )
  3976. {
  3977. goto exit;
  3978. }
  3979. if (bUnicode)
  3980. {
  3981. // The data size must be n*sizeof(WCHAR)
  3982. if ( dwDataLen % sizeof(WCHAR) )
  3983. {
  3984. bReturn = FALSE;
  3985. goto exit;
  3986. }
  3987. pwszData = (LPWSTR) pmdrData->pbMDData;
  3988. cch = dwDataLen / sizeof(WCHAR);
  3989. // The character count must be at least 2 (because the multi strings are double 0 terminated)
  3990. // and the multi string must be double 0 terminated at the end
  3991. if ( ( cch == 1 ) ||
  3992. ( pwszData[cch-1] != L'\0' ) ||
  3993. ( pwszData[cch-2] != L'\0' ) )
  3994. {
  3995. bReturn = FALSE;
  3996. goto exit;
  3997. }
  3998. // If this is an empty multi string it is Ok
  3999. if ( cch == 2 )
  4000. {
  4001. goto exit;
  4002. }
  4003. // Check for double 0 termination in the string excluding at the end, which is invalid
  4004. for ( i=0; i<cch-2; i++ )
  4005. {
  4006. if ( ( pwszData[i] == L'\0') &&
  4007. ( pwszData[i+1] == L'\0') )
  4008. {
  4009. // Encountered an embedded NULL string
  4010. bReturn = FALSE;
  4011. goto exit;
  4012. }
  4013. }
  4014. }
  4015. else
  4016. {
  4017. pszData = (LPSTR) pmdrData->pbMDData;
  4018. cch = dwDataLen;
  4019. // The character count must be at least 2 (because the multi strings are double 0 terminated)
  4020. // and the multi string must be double 0 terminated at the end
  4021. if ( ( cch == 1 ) ||
  4022. ( pszData[cch-1] != '\0' ) ||
  4023. ( pszData[cch-2] != '\0' ) )
  4024. {
  4025. bReturn = FALSE;
  4026. goto exit;
  4027. }
  4028. // If this is an empty multi string it is Ok
  4029. if ( cch == 2 )
  4030. {
  4031. goto exit;
  4032. }
  4033. // Check for double 0 termination in the string excluding at the end, which is invalid
  4034. for ( i=0; i<cch-2; i++)
  4035. {
  4036. if ( ( pszData[i] == (CHAR)'\0' ) &&
  4037. ( pszData[i+1] == (CHAR)'\0' ) )
  4038. {
  4039. // Encountered an embedded NULL string
  4040. bReturn = FALSE;
  4041. goto exit;
  4042. }
  4043. }
  4044. }
  4045. goto exit;
  4046. }
  4047. // Check strings and expand string, which must be at least well formed string
  4048. if ( ( pmdrData->dwMDDataType == STRING_METADATA ) ||
  4049. ( pmdrData->dwMDDataType == EXPANDSZ_METADATA ) )
  4050. {
  4051. dwDataLen = pmdrData->dwMDDataLen;
  4052. // If the data size is 0 it is Ok
  4053. if ( dwDataLen == 0 )
  4054. {
  4055. goto exit;
  4056. }
  4057. if (bUnicode)
  4058. {
  4059. // The data size must be n*sizeof(WCHAR)
  4060. if ( dwDataLen % sizeof(WCHAR) )
  4061. {
  4062. bReturn = FALSE;
  4063. goto exit;
  4064. }
  4065. pwszData = (LPWSTR) pmdrData->pbMDData;
  4066. cch = dwDataLen / sizeof(WCHAR);
  4067. // The string must be 0 terminated
  4068. if ( pwszData[cch-1] != L'\0' )
  4069. {
  4070. bReturn = FALSE;
  4071. goto exit;
  4072. }
  4073. // If this is an empty string it is Ok
  4074. if ( cch == 1 )
  4075. {
  4076. goto exit;
  4077. }
  4078. // Check for 0 termination in the string before the end, which is invalid
  4079. if ( wcslen( pwszData ) != cch-1 )
  4080. {
  4081. // Encountered an embedded NULL
  4082. bReturn = FALSE;
  4083. goto exit;
  4084. }
  4085. }
  4086. else
  4087. {
  4088. pszData = (LPSTR) pmdrData->pbMDData;
  4089. cch = dwDataLen;
  4090. // The string must be 0 terminated
  4091. if ( pszData[cch-1] != '\0' )
  4092. {
  4093. bReturn = FALSE;
  4094. goto exit;
  4095. }
  4096. // If this is an empty string it is Ok
  4097. if ( cch == 1 )
  4098. {
  4099. goto exit;
  4100. }
  4101. // Check for 0 termination in the string before the end, which is invalid
  4102. if ( strlen( pszData ) != cch-1 )
  4103. {
  4104. // Encountered an embedded NULL
  4105. bReturn = FALSE;
  4106. goto exit;
  4107. }
  4108. }
  4109. goto exit;
  4110. }
  4111. exit:
  4112. return ( bReturn );
  4113. }
  4114. CMDBaseData *
  4115. MakeDataObject(IN PMETADATA_RECORD pmdrData,
  4116. IN BOOL bUnicode)
  4117. {
  4118. /*++
  4119. Routine Description:
  4120. Looks for a data object matching the parameters.
  4121. If found, increments the reference count. If not found, it
  4122. creates it.
  4123. Arguments:
  4124. Data - The data for the new object.
  4125. Identifier - The Identifier of the data.
  4126. Attributes - The flags for the data.
  4127. METADATA_INHERIT
  4128. UserType - The User Type for the data. User Defined.
  4129. DataType - The Type of the data.
  4130. DWORD_METADATA
  4131. STRING_METADATA
  4132. BINARY_METADATA
  4133. DataLen - The length of the data. Only used if DataType == BINARY_METADATA.
  4134. Data - Pointer to the data.
  4135. Return Value:
  4136. BOOL - TRUE if the data matches
  4137. Notes:
  4138. --*/
  4139. // CMDBaseData *pbdIndex;
  4140. CMDBaseData *pbdReturn = NULL;
  4141. CMDBaseData *pbdNew = NULL;
  4142. DWORD dwHash = DATA_HASH(pmdrData->dwMDIdentifier);
  4143. // BOOL bDataMatchError = FALSE;
  4144. // for (pbdIndex = g_ppbdDataHashTable[dwHash];
  4145. // (pbdIndex != NULL) &&
  4146. // !DataMatch(pbdIndex, pmdrData, &bDataMatchError, bUnicode) &&
  4147. // !bDataMatchError;
  4148. // pbdIndex = pbdIndex->GetNextPtr()) {
  4149. // }
  4150. // if (!bDataMatchError) {
  4151. // if (pbdIndex != NULL) {
  4152. // pbdReturn = pbdIndex;
  4153. // pbdReturn->IncrementReferenceCount();
  4154. // }
  4155. // else {
  4156. switch(pmdrData->dwMDDataType) {
  4157. case DWORD_METADATA: {
  4158. pbdNew = new CMDDWData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
  4159. pmdrData->dwMDUserType, *(DWORD *)(pmdrData->pbMDData));
  4160. break;
  4161. }
  4162. case STRING_METADATA: {
  4163. pbdNew = new CMDSTRData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
  4164. pmdrData->dwMDUserType, (LPTSTR) (pmdrData->pbMDData), bUnicode);
  4165. break;
  4166. }
  4167. case BINARY_METADATA: {
  4168. pbdNew = new CMDBINData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
  4169. pmdrData->dwMDUserType, pmdrData->dwMDDataLen, pmdrData->pbMDData);
  4170. break;
  4171. }
  4172. case EXPANDSZ_METADATA: {
  4173. pbdNew = new CMDEXSZData(pmdrData->dwMDIdentifier, pmdrData->dwMDAttributes,
  4174. pmdrData->dwMDUserType, (LPTSTR) (pmdrData->pbMDData), bUnicode);
  4175. break;
  4176. }
  4177. case MULTISZ_METADATA: {
  4178. pbdNew = new CMDMLSZData(pmdrData->dwMDIdentifier,
  4179. pmdrData->dwMDAttributes,
  4180. pmdrData->dwMDUserType,
  4181. pmdrData->dwMDDataLen,
  4182. (LPSTR)pmdrData->pbMDData,
  4183. bUnicode);
  4184. break;
  4185. }
  4186. default: {
  4187. pbdNew = NULL;
  4188. }
  4189. }
  4190. if (pbdNew != NULL) {
  4191. if (!(pbdNew->IsValid())) {
  4192. delete (pbdNew);
  4193. }
  4194. else {
  4195. pbdNew->SetNextPtr(g_ppbdDataHashTable[dwHash]);
  4196. g_ppbdDataHashTable[dwHash] = pbdNew;
  4197. pbdReturn = pbdNew;
  4198. }
  4199. }
  4200. // }
  4201. // }
  4202. return (pbdReturn);
  4203. }
  4204. HRESULT
  4205. GetHighestVersion(IN OUT STRAU *pstrauBackupLocation,
  4206. OUT DWORD *pdwVersion)
  4207. {
  4208. long lHighestVersion = -1;
  4209. long lVersion;
  4210. HRESULT hresReturn = ERROR_SUCCESS;
  4211. DWORD dwPathBytes = g_pstrBackupFilePath->QueryCB() + 1;
  4212. DWORD dwNameBytes = pstrauBackupLocation->QueryCBA() - dwPathBytes;
  4213. if (!pstrauBackupLocation->Append("*")) {
  4214. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4215. }
  4216. else {
  4217. if (pstrauBackupLocation->QueryStrA() == NULL) {
  4218. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4219. }
  4220. else {
  4221. HANDLE hFile = INVALID_HANDLE_VALUE;
  4222. WIN32_FIND_DATA wfdFile;
  4223. hFile = FindFirstFile(pstrauBackupLocation->QueryStrA(),
  4224. &wfdFile);
  4225. if (hFile == INVALID_HANDLE_VALUE) {
  4226. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  4227. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4228. }
  4229. }
  4230. else {
  4231. //
  4232. // Process the first file
  4233. //
  4234. //
  4235. // dwNameBytes could be wrong for this assert in MBCS,
  4236. // so call MBCS strlen. Subtract 1 char for appended '*'
  4237. //
  4238. MD_ASSERT(MD_STRNICMP(pstrauBackupLocation->QueryStrA() + dwPathBytes,
  4239. wfdFile.cFileName,
  4240. MD_STRLEN(pstrauBackupLocation->QueryStrA() + dwPathBytes) - 1) == 0);
  4241. if (CheckDigits(wfdFile.cFileName + (dwNameBytes))) {
  4242. //
  4243. // One of our files
  4244. //
  4245. lVersion = atol(wfdFile.cFileName + dwNameBytes);
  4246. if ((lVersion <= MD_BACKUP_MAX_VERSION) &&
  4247. (lVersion > lHighestVersion)) {
  4248. lHighestVersion = lVersion;
  4249. }
  4250. }
  4251. //
  4252. // Process the remaining files
  4253. //
  4254. while (FindNextFile(hFile, &wfdFile)) {
  4255. MD_ASSERT(MD_STRNICMP(pstrauBackupLocation->QueryStrA() + dwPathBytes,
  4256. wfdFile.cFileName,
  4257. MD_STRLEN(pstrauBackupLocation->QueryStrA() + dwPathBytes) - 1) == 0);
  4258. if (CheckDigits(wfdFile.cFileName + dwNameBytes)) {
  4259. //
  4260. // One of our files
  4261. //
  4262. lVersion = atol(wfdFile.cFileName + dwNameBytes);
  4263. if ((lVersion <= MD_BACKUP_MAX_VERSION) &&
  4264. (lVersion > lHighestVersion)) {
  4265. lHighestVersion = lVersion;
  4266. }
  4267. }
  4268. }
  4269. FindClose(hFile);
  4270. }
  4271. if (SUCCEEDED(hresReturn)) {
  4272. if (lHighestVersion == -1) {
  4273. //
  4274. // May not be an error, but need to indicate that
  4275. // no backups were found.
  4276. //
  4277. hresReturn = RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND);
  4278. }
  4279. else if (lHighestVersion <= MD_BACKUP_MAX_VERSION) {
  4280. *pdwVersion = lHighestVersion;
  4281. }
  4282. else {
  4283. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
  4284. }
  4285. }
  4286. }
  4287. pstrauBackupLocation->SetLen(pstrauBackupLocation->QueryCCH() - 1);
  4288. }
  4289. return hresReturn;
  4290. }
  4291. BOOL
  4292. ValidateBackupLocation(LPSTR pszBackupLocation,
  4293. BOOL bUnicode)
  4294. {
  4295. //
  4296. // The main purpose of this routine is to make sure the user
  4297. // is not putting in any file system controls, like .., /, etc.
  4298. //
  4299. // Secondarily, try to eliminate any characters that cannot be
  4300. // used in database names
  4301. //
  4302. BOOL bReturn = TRUE;
  4303. DWORD dwStringLen;
  4304. MD_ASSERT(pszBackupLocation != NULL);
  4305. char *pszLocSave = setlocale(LC_CTYPE, NULL); // Save cur locale
  4306. if( pszLocSave )
  4307. {
  4308. pszLocSave = _strdup( pszLocSave );
  4309. }
  4310. if( !pszLocSave )
  4311. {
  4312. return FALSE;
  4313. }
  4314. setlocale(LC_CTYPE, ""); // Set sys locale
  4315. //
  4316. // strcspn doesn't have an error return, but will return
  4317. // the index of the terminating NULL if the chars are not found
  4318. //
  4319. if (bUnicode) {
  4320. dwStringLen = (DWORD)wcslen((LPWSTR)pszBackupLocation);
  4321. if ((dwStringLen >= MD_BACKUP_MAX_LEN) ||
  4322. (wcscspn((LPWSTR)pszBackupLocation, MD_BACKUP_INVALID_CHARS_W) !=
  4323. dwStringLen)) {
  4324. bReturn = FALSE;
  4325. }
  4326. else {
  4327. LPWSTR pszIndex;
  4328. for (pszIndex = (LPWSTR)pszBackupLocation;
  4329. (*pszIndex != (WCHAR)L'\0') &&
  4330. (iswprint(*pszIndex));
  4331. pszIndex++) {
  4332. }
  4333. if (*pszIndex != (WCHAR)L'\0') {
  4334. bReturn = FALSE;
  4335. }
  4336. }
  4337. }
  4338. else {
  4339. dwStringLen = (DWORD)_mbslen((PBYTE)pszBackupLocation);
  4340. if ((dwStringLen >= MD_BACKUP_MAX_LEN) ||
  4341. (_mbscspn((PBYTE)pszBackupLocation, (PBYTE)MD_BACKUP_INVALID_CHARS_A) !=
  4342. dwStringLen)) {
  4343. bReturn = FALSE;
  4344. }
  4345. else {
  4346. LPSTR pszIndex;
  4347. for (pszIndex = (LPSTR)pszBackupLocation;
  4348. (*pszIndex != (WCHAR)L'\0') &&
  4349. (_ismbcprint(*pszIndex));
  4350. pszIndex = CharNextExA(CP_ACP,
  4351. pszIndex,
  4352. 0)) {
  4353. }
  4354. if (*pszIndex != '\0') {
  4355. bReturn = FALSE;
  4356. }
  4357. }
  4358. }
  4359. setlocale(LC_CTYPE, pszLocSave);
  4360. free( pszLocSave );
  4361. return bReturn;
  4362. }
  4363. DWORD
  4364. GetBackupNameLen(LPSTR pszBackupName)
  4365. //
  4366. // Get Number of Bytes in name prior to suffix
  4367. //
  4368. {
  4369. LPSTR pszSubString = NULL;
  4370. LPSTR pszNextSubString;
  4371. MD_REQUIRE((pszNextSubString = (LPSTR)MD_STRCHR(pszBackupName, '.')) != NULL);
  4372. while (pszNextSubString != NULL) {
  4373. //
  4374. // In case the suffix happens to be part of the name
  4375. //
  4376. pszSubString = pszNextSubString;
  4377. pszNextSubString = (LPSTR)MD_STRCHR(pszSubString+1, '.');
  4378. }
  4379. if (pszSubString
  4380. && (pszSubString[1] != '\0')
  4381. && (pszSubString[2] != '\0')
  4382. && !IsDBCSLeadByte(pszSubString[1])
  4383. && (toupper(pszSubString[1]) == 'M')
  4384. && (toupper(pszSubString[2]) == 'D')) {
  4385. return (DWORD)DIFF(pszSubString - pszBackupName);
  4386. }
  4387. else {
  4388. return 0;
  4389. }
  4390. }
  4391. DWORD
  4392. GetBackupNameLen(LPWSTR pszBackupName)
  4393. //
  4394. // Get Number of WCHARs in name prior to version Number
  4395. //
  4396. {
  4397. LPWSTR pszSubString = NULL;
  4398. LPWSTR pszNextSubString;
  4399. MD_REQUIRE((pszNextSubString = wcschr(pszBackupName, L'.')) != NULL);
  4400. while (pszNextSubString != NULL) {
  4401. pszSubString = pszNextSubString;
  4402. pszNextSubString = wcschr(pszSubString+1, L'.');
  4403. }
  4404. if (pszSubString
  4405. && (pszSubString[1] != L'\0')
  4406. && (pszSubString[2] != L'\0')
  4407. && (towupper(pszSubString[1]) == L'M')
  4408. && (towupper(pszSubString[2]) == L'D')) {
  4409. return (DWORD)DIFF(pszSubString - pszBackupName);
  4410. }
  4411. else {
  4412. return 0;
  4413. }
  4414. }
  4415. HRESULT CreateBackupFileName(IN LPSTR pszMDBackupLocation,
  4416. IN DWORD dwMDVersion,
  4417. IN BOOL bUnicode,
  4418. IN OUT STRAU *pstrauBackupLocation,
  4419. IN OUT STRAU *pstrauSchemaLocation)
  4420. {
  4421. HRESULT hresReturn = ERROR_SUCCESS;
  4422. LPSTR pszBackupLocation = pszMDBackupLocation;
  4423. if (((dwMDVersion > MD_BACKUP_MAX_VERSION) &&
  4424. (dwMDVersion != MD_BACKUP_NEXT_VERSION) &&
  4425. (dwMDVersion != MD_BACKUP_HIGHEST_VERSION)) ||
  4426. ((pszBackupLocation != NULL) &&
  4427. !ValidateBackupLocation(pszBackupLocation, bUnicode))) {
  4428. hresReturn = E_INVALIDARG;
  4429. }
  4430. else {
  4431. if ((pszBackupLocation == NULL) ||
  4432. (bUnicode && ((*(LPWSTR)pszBackupLocation) == (WCHAR)L'\0')) ||
  4433. (!bUnicode && ((*(LPSTR)pszBackupLocation) == (CHAR)'\0'))) {
  4434. pszBackupLocation = MD_DEFAULT_BACKUP_LOCATION;
  4435. bUnicode = FALSE;
  4436. }
  4437. if (!pstrauBackupLocation->Copy(g_pstrBackupFilePath->QueryStr())) {
  4438. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4439. }
  4440. else if (!pstrauBackupLocation->Append("\\")) {
  4441. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4442. }
  4443. else {
  4444. if (bUnicode) {
  4445. if (!pstrauBackupLocation->Append((LPWSTR)pszBackupLocation)) {
  4446. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4447. }
  4448. }
  4449. else {
  4450. if (!pstrauBackupLocation->Append((LPSTR)pszBackupLocation)) {
  4451. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4452. }
  4453. }
  4454. }
  4455. if (SUCCEEDED(hresReturn)) {
  4456. if ( !pstrauSchemaLocation->Copy( (LPWSTR)pstrauBackupLocation->QueryStr(TRUE) ) |
  4457. !pstrauBackupLocation->Append( MD_BACKUP_SUFFIX ) |
  4458. !pstrauSchemaLocation->Append( MD_SCHEMA_SUFFIX )) {
  4459. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4460. }
  4461. else {
  4462. DWORD dwVersion = dwMDVersion;
  4463. if (dwVersion == MD_BACKUP_NEXT_VERSION) {
  4464. hresReturn = GetHighestVersion(pstrauBackupLocation, &dwVersion);
  4465. if (SUCCEEDED(hresReturn)) {
  4466. if (dwVersion < MD_BACKUP_MAX_VERSION) {
  4467. dwVersion++;
  4468. }
  4469. else {
  4470. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
  4471. }
  4472. }
  4473. else if (hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) {
  4474. //
  4475. // Database doesn't exist, so new version is 0
  4476. //
  4477. dwVersion = 0;
  4478. hresReturn = ERROR_SUCCESS;
  4479. }
  4480. }
  4481. else if (dwVersion == MD_BACKUP_HIGHEST_VERSION) {
  4482. hresReturn = GetHighestVersion(pstrauBackupLocation, &dwVersion);
  4483. }
  4484. if (SUCCEEDED(hresReturn)) {
  4485. CHAR pszBuffer[MD_MAX_DWORD_STRING];
  4486. _ultoa((int)dwVersion, pszBuffer, 10);
  4487. if (!pstrauBackupLocation->Append(pszBuffer) |
  4488. !pstrauSchemaLocation->Append(pszBuffer)) {
  4489. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4490. }
  4491. }
  4492. }
  4493. }
  4494. if (SUCCEEDED(hresReturn)) {
  4495. //
  4496. // Make sure the ANSI buffer is valid
  4497. //
  4498. if ( (pstrauBackupLocation->QueryStrA() == NULL) |
  4499. (pstrauSchemaLocation->QueryStrA() == NULL) ) {
  4500. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4501. }
  4502. }
  4503. }
  4504. return hresReturn;
  4505. }
  4506. HRESULT SetBackupPath(LPSTR pszBackupPath)
  4507. {
  4508. DWORD dwReturn = ERROR_DIRECTORY;
  4509. DWORD dwDirectoryAttributes;
  4510. dwDirectoryAttributes = GetFileAttributes(pszBackupPath);
  4511. if (dwDirectoryAttributes == 0xffffffff) {
  4512. //
  4513. // Can't get attributes
  4514. // Path probably doesn't exist
  4515. //
  4516. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  4517. dwReturn = GetLastError();
  4518. }
  4519. else if (!(CreateDirectory(pszBackupPath,
  4520. NULL))) {
  4521. dwReturn = GetLastError();
  4522. }
  4523. else {
  4524. dwReturn = ERROR_SUCCESS;
  4525. }
  4526. }
  4527. else if ((dwDirectoryAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
  4528. //
  4529. // If a directory
  4530. //
  4531. dwReturn = ERROR_SUCCESS;
  4532. }
  4533. if (dwReturn == ERROR_SUCCESS) {
  4534. //
  4535. // Got it! Now set global variable
  4536. //
  4537. MD_ASSERT(g_pstrBackupFilePath == NULL);
  4538. g_pstrBackupFilePath = new STR(pszBackupPath);
  4539. if (g_pstrBackupFilePath == NULL) {
  4540. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4541. }
  4542. else if (!(g_pstrBackupFilePath->IsValid())) {
  4543. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4544. delete g_pstrBackupFilePath;
  4545. g_pstrBackupFilePath = NULL;
  4546. }
  4547. else {
  4548. dwReturn = ERROR_SUCCESS;
  4549. }
  4550. }
  4551. return RETURNCODETOHRESULT(dwReturn);
  4552. }
  4553. HRESULT
  4554. SetGlobalDataFileValues(LPTSTR pszFileName)
  4555. {
  4556. HRESULT hresReturn = ERROR_SUCCESS;
  4557. HANDLE hFileHandle;
  4558. BOOL bMainFileFound = FALSE;
  4559. ResetFileAttributesIfNeeded(pszFileName,
  4560. FALSE);
  4561. hFileHandle = CreateFile(pszFileName,
  4562. GENERIC_READ | GENERIC_WRITE,
  4563. 0,
  4564. NULL,
  4565. OPEN_EXISTING,
  4566. FILE_ATTRIBUTE_NORMAL,
  4567. 0);
  4568. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4569. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  4570. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4571. }
  4572. else {
  4573. hFileHandle = CreateFile(pszFileName,
  4574. GENERIC_READ | GENERIC_WRITE,
  4575. 0,
  4576. NULL,
  4577. CREATE_NEW,
  4578. FILE_ATTRIBUTE_NORMAL,
  4579. 0);
  4580. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4581. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4582. }
  4583. else {
  4584. CloseHandle(hFileHandle);
  4585. DeleteFile(pszFileName);
  4586. }
  4587. }
  4588. }
  4589. else {
  4590. CloseHandle(hFileHandle);
  4591. bMainFileFound = TRUE;
  4592. }
  4593. if (SUCCEEDED(hresReturn)) {
  4594. g_strRealFileName = new STR(pszFileName);
  4595. g_strSchemaFileName = new STR(pszFileName);
  4596. g_strTempFileName = new STR(pszFileName);
  4597. g_strBackupFileName = new STR(pszFileName);
  4598. if( (NULL == g_strRealFileName) ||
  4599. (NULL == g_strSchemaFileName) ||
  4600. (NULL == g_strTempFileName) ||
  4601. (NULL == g_strBackupFileName)
  4602. )
  4603. {
  4604. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4605. }
  4606. else
  4607. {
  4608. if (g_strSchemaFileName->IsValid()) {
  4609. LPSTR szRealFileNameBegin = g_strRealFileName->QueryStr();
  4610. LPSTR szEnd = strrchr(szRealFileNameBegin, '\\');
  4611. if(NULL == szEnd) {
  4612. hresReturn = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  4613. }
  4614. else {
  4615. szEnd++;
  4616. g_strSchemaFileName->SetLen((DWORD)(szEnd-szRealFileNameBegin));
  4617. }
  4618. }
  4619. if(SUCCEEDED(hresReturn)) {
  4620. if(g_strSchemaFileName->IsValid()) {
  4621. g_strSchemaFileName->Append(MD_SCHEMA_FILE_NAME);
  4622. }
  4623. if (g_strTempFileName->IsValid()) {
  4624. g_strTempFileName->Append(MD_TEMP_DATA_FILE_EXT);
  4625. }
  4626. if (g_strBackupFileName->IsValid()) {
  4627. g_strBackupFileName->Append(MD_BACKUP_DATA_FILE_EXT);
  4628. }
  4629. if (!g_strSchemaFileName->IsValid() || !g_strTempFileName->IsValid() || !g_strBackupFileName->IsValid())
  4630. {
  4631. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4632. }
  4633. }
  4634. if(SUCCEEDED(hresReturn)) {
  4635. ResetFileAttributesIfNeeded( g_strTempFileName->QueryStrA(),
  4636. FALSE );
  4637. hFileHandle = CreateFile(g_strTempFileName->QueryStr(),
  4638. GENERIC_READ | GENERIC_WRITE,
  4639. 0,
  4640. NULL,
  4641. OPEN_EXISTING,
  4642. FILE_ATTRIBUTE_NORMAL,
  4643. 0);
  4644. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4645. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  4646. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4647. }
  4648. else {
  4649. hFileHandle = CreateFile(g_strTempFileName->QueryStr(),
  4650. GENERIC_READ | GENERIC_WRITE,
  4651. 0,
  4652. NULL,
  4653. CREATE_NEW,
  4654. FILE_ATTRIBUTE_NORMAL,
  4655. 0);
  4656. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4657. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4658. }
  4659. else {
  4660. CloseHandle(hFileHandle);
  4661. DeleteFile(g_strTempFileName->QueryStr());
  4662. }
  4663. }
  4664. }
  4665. else {
  4666. CloseHandle(hFileHandle);
  4667. DeleteFile( g_strTempFileName->QueryStrA() );
  4668. }
  4669. if (SUCCEEDED(hresReturn)) {
  4670. hFileHandle = CreateFile(g_strBackupFileName->QueryStr(),
  4671. GENERIC_READ | GENERIC_WRITE,
  4672. 0,
  4673. NULL,
  4674. OPEN_EXISTING,
  4675. FILE_ATTRIBUTE_NORMAL,
  4676. 0);
  4677. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4678. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  4679. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4680. }
  4681. else {
  4682. hFileHandle = CreateFile(g_strBackupFileName->QueryStr(),
  4683. GENERIC_READ | GENERIC_WRITE,
  4684. 0,
  4685. NULL,
  4686. CREATE_NEW,
  4687. FILE_ATTRIBUTE_NORMAL,
  4688. 0);
  4689. if (hFileHandle == INVALID_HANDLE_VALUE) {
  4690. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4691. }
  4692. else {
  4693. CloseHandle(hFileHandle);
  4694. DeleteFile(g_strBackupFileName->QueryStr());
  4695. if ( !bMainFileFound )
  4696. {
  4697. // We should fail the loading the metabase if there is no metabase.xml,
  4698. // with one very important exclusion: during the setup.
  4699. if ( CheckForSetup() != S_OK )
  4700. {
  4701. hresReturn = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  4702. }
  4703. }
  4704. }
  4705. }
  4706. }
  4707. else {
  4708. CloseHandle(hFileHandle);
  4709. if (!bMainFileFound) {
  4710. if (!MoveFile(g_strBackupFileName->QueryStr(), pszFileName)) {
  4711. hresReturn = RETURNCODETOHRESULT(GetLastError());
  4712. }
  4713. else
  4714. {
  4715. ResetFileAttributesIfNeeded( pszFileName,
  4716. FALSE );
  4717. }
  4718. }
  4719. }
  4720. }
  4721. }
  4722. }
  4723. if(SUCCEEDED(hresReturn))
  4724. {
  4725. hresReturn = SetUnicodeGlobalDataFileValues();
  4726. }
  4727. if (FAILED(hresReturn))
  4728. {
  4729. if( g_strRealFileName )
  4730. {
  4731. delete(g_strRealFileName);
  4732. g_strRealFileName = NULL;
  4733. }
  4734. if(g_strSchemaFileName)
  4735. {
  4736. delete(g_strSchemaFileName);
  4737. g_strSchemaFileName = NULL;
  4738. }
  4739. if( g_strTempFileName )
  4740. {
  4741. delete(g_strTempFileName);
  4742. g_strRealFileName = NULL;
  4743. }
  4744. if( g_strBackupFileName )
  4745. {
  4746. delete(g_strBackupFileName);
  4747. g_strRealFileName = NULL;
  4748. }
  4749. }
  4750. }
  4751. return hresReturn;
  4752. }
  4753. HRESULT
  4754. SetUnicodeGlobalDataFileValues()
  4755. //
  4756. // Create unicode versions of the realfilename, tempfilename, backupfilename
  4757. // metabasedir, historyfiledir, schemaextensions file for use by catalog
  4758. //
  4759. {
  4760. HRESULT hr = S_OK;
  4761. LPWSTR pwsz = NULL;
  4762. // Temp File name
  4763. hr = GetUnicodeName(g_strTempFileName->QueryStr(),
  4764. &g_wszTempFileName);
  4765. if(FAILED(hr))
  4766. {
  4767. goto exit;
  4768. }
  4769. g_cchTempFileName = (ULONG)wcslen(g_wszTempFileName);
  4770. // Real File name
  4771. hr = GetUnicodeName(g_strRealFileName->QueryStr(),
  4772. &g_wszRealFileName);
  4773. if(FAILED(hr))
  4774. {
  4775. goto exit;
  4776. }
  4777. g_cchRealFileName = (ULONG)wcslen(g_wszRealFileName);
  4778. // Backup File name
  4779. hr = GetUnicodeName(g_strBackupFileName->QueryStr(),
  4780. &g_wszBackupFileName);
  4781. if(FAILED(hr))
  4782. {
  4783. goto exit;
  4784. }
  4785. g_cchBackupFileName = (ULONG)wcslen(g_wszBackupFileName);
  4786. // Schema File name
  4787. hr = GetUnicodeName(g_strSchemaFileName->QueryStr(),
  4788. &g_wszSchemaFileName);
  4789. if(FAILED(hr))
  4790. {
  4791. goto exit;
  4792. }
  4793. g_cchSchemaFileName = (ULONG)wcslen(g_wszSchemaFileName);
  4794. // Position pwsz where real file name begins ie past last backslash.
  4795. pwsz = wcsrchr(g_wszRealFileName, L'\\');
  4796. if(NULL == pwsz)
  4797. {
  4798. hr = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  4799. goto exit;
  4800. }
  4801. pwsz++;
  4802. // Real File name without path
  4803. g_cchRealFileNameWithoutPath = (ULONG)wcslen(pwsz);
  4804. g_wszRealFileNameWithoutPath = new WCHAR[g_cchRealFileNameWithoutPath+1];
  4805. if(NULL == g_wszRealFileNameWithoutPath)
  4806. {
  4807. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4808. goto exit;
  4809. }
  4810. wcscpy(g_wszRealFileNameWithoutPath, pwsz);
  4811. // Create metabase directory, end with backslash
  4812. g_cchMetabaseDir = (ULONG)(pwsz-g_wszRealFileName);
  4813. g_wszMetabaseDir = new WCHAR[g_cchMetabaseDir+1];
  4814. if(NULL == g_wszMetabaseDir)
  4815. {
  4816. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4817. goto exit;
  4818. }
  4819. memcpy(g_wszMetabaseDir, g_wszRealFileName, g_cchMetabaseDir*sizeof(WCHAR));
  4820. g_wszMetabaseDir[g_cchMetabaseDir] = L'\0';
  4821. // Real File name without path & without extension
  4822. pwsz = wcsrchr(g_wszRealFileNameWithoutPath, MD_CH_EXTN_SEPERATORW);
  4823. g_cchRealFileNameWithoutPathWithoutExtension = g_cchRealFileNameWithoutPath;
  4824. g_wszRealFileNameWithoutPathWithoutExtension = new WCHAR[g_cchRealFileNameWithoutPathWithoutExtension +1];
  4825. if(NULL == g_wszRealFileNameWithoutPathWithoutExtension)
  4826. {
  4827. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4828. goto exit;
  4829. }
  4830. else if(NULL != pwsz)
  4831. {
  4832. g_cchRealFileNameWithoutPathWithoutExtension = (ULONG)(pwsz - g_wszRealFileNameWithoutPath);
  4833. memcpy(g_wszRealFileNameWithoutPathWithoutExtension, g_wszRealFileNameWithoutPath, g_cchRealFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4834. g_wszRealFileNameWithoutPathWithoutExtension[g_cchRealFileNameWithoutPathWithoutExtension] = L'\0';
  4835. // Real File name extension
  4836. g_cchRealFileNameExtension = (ULONG)wcslen(pwsz);
  4837. g_wszRealFileNameExtension = new WCHAR[g_cchRealFileNameExtension+1];
  4838. if(NULL == g_wszRealFileNameExtension)
  4839. {
  4840. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4841. goto exit;
  4842. }
  4843. memcpy(g_wszRealFileNameExtension, pwsz, g_cchRealFileNameExtension*sizeof(WCHAR));
  4844. g_wszRealFileNameExtension[g_cchRealFileNameExtension] = L'\0';
  4845. }
  4846. else
  4847. {
  4848. memcpy(g_wszRealFileNameWithoutPathWithoutExtension,g_wszRealFileNameWithoutPath,g_cchRealFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4849. g_wszRealFileNameWithoutPathWithoutExtension[g_cchRealFileNameExtension] = L'\0';
  4850. }
  4851. // Position pwsz where schema file name begins ie past last backslash.
  4852. pwsz = wcsrchr(g_wszSchemaFileName, L'\\');
  4853. if(NULL == pwsz)
  4854. {
  4855. hr = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
  4856. goto exit;
  4857. }
  4858. pwsz++;
  4859. // Schema File name without path
  4860. g_cchSchemaFileNameWithoutPath = (ULONG)wcslen(pwsz);
  4861. g_wszSchemaFileNameWithoutPath = new WCHAR[g_cchSchemaFileNameWithoutPath+1];
  4862. if(NULL == g_wszSchemaFileNameWithoutPath)
  4863. {
  4864. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4865. goto exit;
  4866. }
  4867. wcscpy(g_wszSchemaFileNameWithoutPath, pwsz);
  4868. // Schema File name without path & without extension
  4869. pwsz = wcsrchr(g_wszSchemaFileNameWithoutPath, MD_CH_EXTN_SEPERATORW);
  4870. g_cchSchemaFileNameWithoutPathWithoutExtension = g_cchSchemaFileNameWithoutPath;
  4871. g_wszSchemaFileNameWithoutPathWithoutExtension = new WCHAR[g_cchSchemaFileNameWithoutPathWithoutExtension +1];
  4872. if(NULL == g_wszSchemaFileNameWithoutPathWithoutExtension)
  4873. {
  4874. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4875. goto exit;
  4876. }
  4877. else if(NULL != pwsz)
  4878. {
  4879. g_cchSchemaFileNameWithoutPathWithoutExtension = (ULONG)(pwsz - g_wszSchemaFileNameWithoutPath);
  4880. memcpy(g_wszSchemaFileNameWithoutPathWithoutExtension, g_wszSchemaFileNameWithoutPath, g_cchSchemaFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4881. g_wszSchemaFileNameWithoutPathWithoutExtension[g_cchSchemaFileNameWithoutPathWithoutExtension] = L'\0';
  4882. // Schema File name extension
  4883. g_cchSchemaFileNameExtension = (ULONG)wcslen(pwsz);
  4884. g_wszSchemaFileNameExtension = new WCHAR[g_cchSchemaFileNameExtension+1];
  4885. if(NULL == g_wszSchemaFileNameExtension)
  4886. {
  4887. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4888. goto exit;
  4889. }
  4890. memcpy(g_wszSchemaFileNameExtension, pwsz, g_cchSchemaFileNameExtension*sizeof(WCHAR));
  4891. g_wszSchemaFileNameExtension[g_cchSchemaFileNameExtension] = L'\0';
  4892. }
  4893. else
  4894. {
  4895. memcpy(g_wszSchemaFileNameWithoutPathWithoutExtension,g_wszSchemaFileNameWithoutPath,g_cchSchemaFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4896. g_wszSchemaFileNameWithoutPathWithoutExtension[g_cchSchemaFileNameExtension] = L'\0';
  4897. }
  4898. // Create history file dir, end with backslash
  4899. g_cchHistoryFileDir = g_cchMetabaseDir + MD_CCH_HISTORY_FILE_SUBDIRW;
  4900. g_wszHistoryFileDir = new WCHAR[g_cchHistoryFileDir+1];
  4901. if(NULL == g_wszHistoryFileDir)
  4902. {
  4903. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4904. goto exit;
  4905. }
  4906. pwsz = g_wszHistoryFileDir;
  4907. memcpy(pwsz, g_wszMetabaseDir, g_cchMetabaseDir*sizeof(WCHAR));
  4908. pwsz = pwsz + g_cchMetabaseDir;
  4909. memcpy(pwsz, MD_HISTORY_FILE_SUBDIRW, MD_CCH_HISTORY_FILE_SUBDIRW*sizeof(WCHAR));
  4910. pwsz = pwsz + MD_CCH_HISTORY_FILE_SUBDIRW; // This contains the backslash
  4911. *pwsz = L'\0';
  4912. // Create history file seach string Eg: D:\WINNT\System32\inetsrv\History\Metabase_??????????_??????????.XML
  4913. g_cchHistoryFileSearchString = g_cchHistoryFileDir +
  4914. g_cchRealFileNameWithoutPathWithoutExtension +
  4915. MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW +
  4916. g_cchRealFileNameExtension;
  4917. if((g_cchHistoryFileSearchString + 1) > MAX_PATH)
  4918. {
  4919. g_cchHistoryFileSearchString += MD_CCH_LONG_STRING_PREFIXW;
  4920. }
  4921. g_wszHistoryFileSearchString = new WCHAR[g_cchHistoryFileSearchString + 1];
  4922. if(NULL == g_wszHistoryFileSearchString)
  4923. {
  4924. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4925. goto exit;
  4926. }
  4927. pwsz = g_wszHistoryFileSearchString;
  4928. if((g_cchHistoryFileSearchString + 1) > MAX_PATH)
  4929. {
  4930. memcpy(pwsz, MD_LONG_STRING_PREFIXW, MD_CCH_LONG_STRING_PREFIXW*sizeof(WCHAR));
  4931. pwsz = pwsz + (MD_CCH_LONG_STRING_PREFIXW);
  4932. }
  4933. memcpy(pwsz, g_wszHistoryFileDir, g_cchHistoryFileDir*sizeof(WCHAR));
  4934. pwsz = pwsz + g_cchHistoryFileDir;
  4935. memcpy(pwsz, g_wszRealFileNameWithoutPathWithoutExtension, g_cchRealFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4936. pwsz = pwsz + g_cchRealFileNameWithoutPathWithoutExtension;
  4937. memcpy(pwsz, MD_HISTORY_FILE_SEARCH_EXTENSIONW, MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW*sizeof(WCHAR));
  4938. pwsz = pwsz + MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW;
  4939. if(NULL != g_wszRealFileNameExtension)
  4940. {
  4941. memcpy(pwsz, g_wszRealFileNameExtension, g_cchRealFileNameExtension*sizeof(WCHAR));
  4942. pwsz = pwsz + g_cchRealFileNameExtension;
  4943. }
  4944. *pwsz = L'\0';
  4945. // Create error file search string Eg: D:\WINNT\System32\inetsrv\History\MetabaseError_??????????.XML
  4946. g_cchErrorFileSearchString = g_cchHistoryFileDir +
  4947. g_cchRealFileNameWithoutPathWithoutExtension +
  4948. MD_CCH_ERROR_FILE_NAME_EXTENSIONW +
  4949. MD_CCH_ERROR_FILE_SEARCH_EXTENSIONW +
  4950. g_cchRealFileNameExtension;
  4951. if((g_cchErrorFileSearchString + 1) > MAX_PATH)
  4952. {
  4953. g_cchErrorFileSearchString += MD_CCH_LONG_STRING_PREFIXW;
  4954. }
  4955. g_wszErrorFileSearchString = new WCHAR[g_cchErrorFileSearchString+1];
  4956. if(NULL == g_wszErrorFileSearchString)
  4957. {
  4958. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4959. goto exit;
  4960. }
  4961. pwsz = g_wszErrorFileSearchString;
  4962. if((g_cchErrorFileSearchString + 1) > MAX_PATH)
  4963. {
  4964. memcpy(pwsz,MD_LONG_STRING_PREFIXW, MD_CCH_LONG_STRING_PREFIXW*sizeof(WCHAR));
  4965. pwsz = pwsz + MD_CCH_LONG_STRING_PREFIXW;
  4966. }
  4967. memcpy(pwsz, g_wszHistoryFileDir, g_cchHistoryFileDir*sizeof(WCHAR));
  4968. pwsz = pwsz + g_cchHistoryFileDir;
  4969. memcpy(pwsz, g_wszRealFileNameWithoutPathWithoutExtension, g_cchRealFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  4970. pwsz = pwsz + g_cchRealFileNameWithoutPathWithoutExtension;
  4971. memcpy(pwsz, MD_ERROR_FILE_NAME_EXTENSIONW, MD_CCH_ERROR_FILE_NAME_EXTENSIONW*sizeof(WCHAR));
  4972. pwsz = pwsz + MD_CCH_ERROR_FILE_NAME_EXTENSIONW;
  4973. memcpy(pwsz, MD_ERROR_FILE_SEARCH_EXTENSIONW, MD_CCH_ERROR_FILE_SEARCH_EXTENSIONW*sizeof(WCHAR));
  4974. pwsz = pwsz + MD_CCH_ERROR_FILE_SEARCH_EXTENSIONW;
  4975. if(NULL != g_wszRealFileNameExtension)
  4976. {
  4977. memcpy(pwsz, g_wszRealFileNameExtension, g_cchRealFileNameExtension*sizeof(WCHAR));
  4978. pwsz = pwsz + g_cchRealFileNameExtension;
  4979. }
  4980. *pwsz = L'\0';
  4981. // Create schema extensions file. Eg: D:\WINNT\System32\inetsrv\MBSchExt.XML
  4982. g_cchSchemaExtensionFile = g_cchMetabaseDir +
  4983. MD_CCH_SCHEMA_EXTENSION_FILE_NAMEW;
  4984. g_wszSchemaExtensionFile = new WCHAR[g_cchSchemaExtensionFile+1];
  4985. if(NULL == g_wszSchemaExtensionFile)
  4986. {
  4987. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  4988. goto exit;
  4989. }
  4990. pwsz = g_wszSchemaExtensionFile;
  4991. memcpy(pwsz, g_wszMetabaseDir, g_cchMetabaseDir*sizeof(WCHAR));
  4992. pwsz = pwsz + g_cchMetabaseDir;
  4993. memcpy(pwsz, MD_SCHEMA_EXTENSION_FILE_NAMEW, MD_CCH_SCHEMA_EXTENSION_FILE_NAMEW*sizeof(WCHAR));
  4994. pwsz = pwsz + MD_CCH_SCHEMA_EXTENSION_FILE_NAMEW;
  4995. *pwsz = L'\0';
  4996. DBGINFOW((DBG_CONTEXT,
  4997. L"[SetUnicodeGlobalDataFileValues]\nTempFileName%s:%d\nRealFileName:%s::%d\nBackupFileName:%s::%d\nSchemaFileName:%s::%d\nRealFileNameWithoutPath:%s::%d\nRealFileNameWithoutPathWithoutExtension:%s::%d\nMetabaseDir:%s::%d\nSchemaFileNameWithoutPath:%s::%d\nSchemaFileNameWithoutPathWithoutExtension:%s::%d\nHistoryFileDir:%s::%d\nHistoryFileSearchString:%s::%d\nErrorFileSearchString:%s::%d\nSchemaExtensionFile:%s::%d\n",
  4998. g_wszTempFileName,
  4999. g_cchTempFileName,
  5000. g_wszRealFileName,
  5001. g_cchRealFileName,
  5002. g_wszBackupFileName,
  5003. g_cchBackupFileName,
  5004. g_wszSchemaFileName,
  5005. g_cchSchemaFileName,
  5006. g_wszRealFileNameWithoutPath,
  5007. g_cchRealFileNameWithoutPath,
  5008. g_wszRealFileNameWithoutPathWithoutExtension,
  5009. g_cchRealFileNameWithoutPathWithoutExtension,
  5010. g_wszMetabaseDir,
  5011. g_cchMetabaseDir,
  5012. g_wszSchemaFileNameWithoutPath,
  5013. g_cchSchemaFileNameWithoutPath,
  5014. g_wszSchemaFileNameWithoutPathWithoutExtension,
  5015. g_cchSchemaFileNameWithoutPathWithoutExtension,
  5016. g_wszHistoryFileDir,
  5017. g_cchHistoryFileDir,
  5018. g_wszHistoryFileSearchString,
  5019. g_cchHistoryFileSearchString,
  5020. g_wszErrorFileSearchString,
  5021. g_cchErrorFileSearchString,
  5022. g_wszSchemaExtensionFile,
  5023. g_cchSchemaExtensionFile));
  5024. if(NULL != g_wszRealFileNameExtension)
  5025. {
  5026. DBGINFOW((DBG_CONTEXT,
  5027. L"[SetUnicodeGlobalDataFileValues]\nRealFileNameExtension:%s::%d\n",
  5028. g_wszRealFileNameExtension,
  5029. g_cchRealFileNameExtension));
  5030. }
  5031. if(NULL != g_wszSchemaFileNameExtension)
  5032. {
  5033. DBGINFOW((DBG_CONTEXT,
  5034. L"[SetUnicodeGlobalDataFileValues]\nSchemaFileNameExtension:%s::%d\n",
  5035. g_wszSchemaFileNameExtension,
  5036. g_cchSchemaFileNameExtension));
  5037. }
  5038. exit:
  5039. if(FAILED(hr))
  5040. {
  5041. UnInitializeUnicodeGlobalDataFileValues();
  5042. }
  5043. else
  5044. {
  5045. hr = RETURNCODETOHRESULT(ERROR_SUCCESS);
  5046. }
  5047. return hr;
  5048. }
  5049. void
  5050. InitializeUnicodeGlobalDataFileValues()
  5051. {
  5052. g_wszTempFileName = NULL;
  5053. g_cchTempFileName = 0;
  5054. g_wszRealFileName = NULL;
  5055. g_cchRealFileName = 0;
  5056. g_wszBackupFileName = NULL;
  5057. g_cchBackupFileName = 0;
  5058. g_wszSchemaFileName = NULL;
  5059. g_cchSchemaFileName = 0;
  5060. g_wszRealFileNameWithoutPath = NULL;
  5061. g_cchRealFileNameWithoutPath = 0;
  5062. g_wszMetabaseDir = NULL;
  5063. g_cchMetabaseDir = 0;
  5064. g_wszRealFileNameWithoutPathWithoutExtension = NULL;
  5065. g_cchRealFileNameWithoutPathWithoutExtension = 0;
  5066. g_wszRealFileNameExtension = NULL;
  5067. g_cchRealFileNameExtension = 0;
  5068. g_wszSchemaFileNameWithoutPath = NULL;
  5069. g_cchSchemaFileNameWithoutPath = 0;
  5070. g_wszSchemaFileNameWithoutPathWithoutExtension = NULL;
  5071. g_cchSchemaFileNameWithoutPathWithoutExtension = 0;
  5072. g_wszSchemaFileNameExtension = NULL;
  5073. g_cchSchemaFileNameExtension = 0;
  5074. g_wszHistoryFileDir = NULL;
  5075. g_cchHistoryFileDir = 0;
  5076. g_wszHistoryFileSearchString = NULL;
  5077. g_cchHistoryFileSearchString = 0;
  5078. g_wszErrorFileSearchString = NULL;
  5079. g_cchErrorFileSearchString = 0;
  5080. g_wszSchemaExtensionFile = NULL;
  5081. g_cchSchemaExtensionFile = 0;
  5082. }
  5083. void
  5084. UnInitializeUnicodeGlobalDataFileValues()
  5085. {
  5086. if(NULL != g_wszTempFileName)
  5087. {
  5088. delete [] g_wszTempFileName;
  5089. g_wszTempFileName = NULL;
  5090. g_cchTempFileName = 0;
  5091. }
  5092. if(NULL != g_wszRealFileName)
  5093. {
  5094. delete [] g_wszRealFileName;
  5095. g_wszRealFileName = NULL;
  5096. g_cchRealFileName = 0;
  5097. }
  5098. if(NULL != g_wszBackupFileName)
  5099. {
  5100. delete [] g_wszBackupFileName;
  5101. g_wszBackupFileName = NULL;
  5102. g_cchBackupFileName = 0;
  5103. }
  5104. if(NULL != g_wszSchemaFileName)
  5105. {
  5106. delete [] g_wszSchemaFileName;
  5107. g_wszSchemaFileName = NULL;
  5108. g_cchSchemaFileName = 0;
  5109. }
  5110. if(NULL != g_wszRealFileNameWithoutPath)
  5111. {
  5112. delete [] g_wszRealFileNameWithoutPath;
  5113. g_wszRealFileNameWithoutPath = NULL;
  5114. g_cchRealFileNameWithoutPath = 0;
  5115. }
  5116. if(NULL != g_wszMetabaseDir)
  5117. {
  5118. delete [] g_wszMetabaseDir;
  5119. g_wszMetabaseDir = NULL;
  5120. g_cchMetabaseDir = 0;
  5121. }
  5122. if(NULL != g_wszRealFileNameWithoutPathWithoutExtension)
  5123. {
  5124. delete [] g_wszRealFileNameWithoutPathWithoutExtension;
  5125. g_wszRealFileNameWithoutPathWithoutExtension = NULL;
  5126. g_cchRealFileNameWithoutPathWithoutExtension = 0;
  5127. }
  5128. if(NULL != g_wszRealFileNameExtension)
  5129. {
  5130. delete [] g_wszRealFileNameExtension;
  5131. g_wszRealFileNameExtension = NULL;
  5132. g_cchRealFileNameExtension = 0;
  5133. }
  5134. if(NULL != g_wszSchemaFileNameWithoutPath)
  5135. {
  5136. delete [] g_wszSchemaFileNameWithoutPath;
  5137. g_wszSchemaFileNameWithoutPath = NULL;
  5138. g_cchSchemaFileNameWithoutPath = 0;
  5139. }
  5140. if(NULL != g_wszSchemaFileNameWithoutPathWithoutExtension)
  5141. {
  5142. delete [] g_wszSchemaFileNameWithoutPathWithoutExtension;
  5143. g_wszSchemaFileNameWithoutPathWithoutExtension = NULL;
  5144. g_cchSchemaFileNameWithoutPathWithoutExtension = 0;
  5145. }
  5146. if(NULL != g_wszSchemaFileNameExtension)
  5147. {
  5148. delete [] g_wszSchemaFileNameExtension;
  5149. g_wszSchemaFileNameExtension = NULL;
  5150. g_cchSchemaFileNameExtension = 0;
  5151. }
  5152. if(NULL != g_wszHistoryFileDir)
  5153. {
  5154. delete [] g_wszHistoryFileDir;
  5155. g_wszHistoryFileDir = NULL;
  5156. g_cchHistoryFileDir = 0;
  5157. }
  5158. if(NULL != g_wszHistoryFileSearchString)
  5159. {
  5160. delete [] g_wszHistoryFileSearchString;
  5161. g_wszHistoryFileSearchString = NULL;
  5162. g_cchHistoryFileSearchString = 0;
  5163. }
  5164. if(NULL != g_wszErrorFileSearchString)
  5165. {
  5166. delete [] g_wszErrorFileSearchString;
  5167. g_wszErrorFileSearchString = NULL;
  5168. g_cchErrorFileSearchString = 0;
  5169. }
  5170. if(NULL != g_wszSchemaExtensionFile)
  5171. {
  5172. delete [] g_wszSchemaExtensionFile;
  5173. g_wszSchemaExtensionFile = NULL;
  5174. g_cchSchemaExtensionFile = 0;
  5175. }
  5176. return;
  5177. }
  5178. HRESULT
  5179. SetDataFile()
  5180. {
  5181. HRESULT hr = S_OK;
  5182. CHAR szTemp[MAX_PATH+1]; // MAX_PATH+1 so we always have a zero terminated string
  5183. CHAR *pszLastSlash;
  5184. DWORD cch;
  5185. STRAU strMetabase;
  5186. STRAU strBackup;
  5187. // Zero out
  5188. memset( szTemp, 0 , sizeof(szTemp) );
  5189. // Get the full path name of the dll
  5190. cch = GetModuleFileNameA( GetModuleHandleA( MD_DEFAULT_DLL_FILE_NAME ), szTemp, MAX_PATH );
  5191. // Failed?
  5192. if ( cch == 0 )
  5193. {
  5194. hr = HRESULT_FROM_WIN32( GetLastError() );
  5195. goto exit;
  5196. }
  5197. // If the buffer is not big enough
  5198. if ( szTemp[MAX_PATH-1] != '\0' )
  5199. {
  5200. hr = E_FAIL;
  5201. goto exit;
  5202. }
  5203. // Find the last slash
  5204. pszLastSlash = strrchr( szTemp, '\\' );
  5205. if ( pszLastSlash == NULL )
  5206. {
  5207. hr = E_FAIL;
  5208. goto exit;
  5209. }
  5210. if ( _stricmp( pszLastSlash+1, MD_DEFAULT_DLL_FILE_NAME ) != 0 )
  5211. {
  5212. hr = E_FAIL;
  5213. goto exit;
  5214. }
  5215. // Terminate after the slash
  5216. pszLastSlash[1] = '\0';
  5217. if ( !strMetabase.Copy( szTemp ) )
  5218. {
  5219. hr = E_OUTOFMEMORY;
  5220. goto exit;
  5221. }
  5222. if ( !strMetabase.Append( MD_DEFAULT_DATA_FILE_NAME ) )
  5223. {
  5224. hr = E_OUTOFMEMORY;
  5225. goto exit;
  5226. }
  5227. if ( !strBackup.Copy( szTemp ) )
  5228. {
  5229. hr = E_OUTOFMEMORY;
  5230. goto exit;
  5231. }
  5232. if ( !strBackup.Append( MD_DEFAULT_BACKUP_PATH_NAME ) )
  5233. {
  5234. hr = E_OUTOFMEMORY;
  5235. goto exit;
  5236. }
  5237. hr = SetGlobalDataFileValues( strMetabase.QueryStrA() );
  5238. if ( FAILED( hr ) )
  5239. {
  5240. goto exit;
  5241. }
  5242. hr = SetBackupPath( strBackup.QueryStrA() );
  5243. if ( FAILED( hr ) )
  5244. {
  5245. goto exit;
  5246. }
  5247. exit:
  5248. return hr;
  5249. }
  5250. DWORD GetObjectPath(CMDBaseObject *pboObject,
  5251. BUFFER *pbufPath,
  5252. DWORD &rdwStringLen,
  5253. CMDBaseObject *pboTopObject,
  5254. IN BOOL bUnicode)
  5255. {
  5256. DWORD dwReturn = ERROR_SUCCESS;
  5257. DWORD dwOldStringLen;
  5258. MD_ASSERT(pboObject != NULL);
  5259. if (pboObject != pboTopObject) {
  5260. dwReturn = GetObjectPath(pboObject->GetParent(),
  5261. pbufPath,
  5262. rdwStringLen,
  5263. pboTopObject,
  5264. bUnicode);
  5265. dwOldStringLen = rdwStringLen;
  5266. if (pboObject->GetName(bUnicode) == NULL) {
  5267. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  5268. }
  5269. else {
  5270. if (bUnicode) {
  5271. rdwStringLen += (1 + (DWORD)wcslen((LPWSTR)pboObject->GetName(bUnicode)));
  5272. if (!pbufPath->Resize((rdwStringLen + 1) * sizeof(WCHAR))) {
  5273. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  5274. }
  5275. else {
  5276. LPWSTR lpzStringEnd = (LPWSTR)(pbufPath->QueryPtr()) + dwOldStringLen;
  5277. *lpzStringEnd = MD_PATH_DELIMETERW;
  5278. wcscpy(lpzStringEnd+1, (LPWSTR)(pboObject->GetName(bUnicode)));
  5279. }
  5280. }
  5281. else {
  5282. rdwStringLen += (1 + (DWORD)MD_STRBYTES(pboObject->GetName(bUnicode)));
  5283. if (!pbufPath->Resize((rdwStringLen + 1) * sizeof(TCHAR))) {
  5284. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  5285. }
  5286. else {
  5287. LPTSTR lpzStringEnd = (LPTSTR)(pbufPath->QueryPtr()) + dwOldStringLen;
  5288. *lpzStringEnd = MD_PATH_DELIMETERA;
  5289. MD_STRCPY(lpzStringEnd+1, pboObject->GetName(bUnicode));
  5290. }
  5291. }
  5292. }
  5293. }
  5294. return dwReturn;
  5295. }
  5296. HRESULT
  5297. MakeInsertPathData(STRAU *pstrauNewData,
  5298. LPTSTR pszPath,
  5299. LPTSTR pszOldData,
  5300. DWORD *pdwDataLen,
  5301. BOOL bUnicode)
  5302. {
  5303. HRESULT hresReturn = ERROR_SUCCESS;
  5304. if (bUnicode) {
  5305. LPWSTR pszDataIndex, pszNextDataIndex;
  5306. pstrauNewData->SetLen(0);
  5307. for (pszDataIndex = (LPWSTR)pszOldData;
  5308. SUCCEEDED(hresReturn) && ((pszNextDataIndex = wcsstr(pszDataIndex, MD_INSERT_PATH_STRINGW)) != NULL);
  5309. pszDataIndex = pszNextDataIndex + ((sizeof(MD_INSERT_PATH_STRINGW) / sizeof(WCHAR)) - 1)) {
  5310. // *pszNextDataIndex = (TCHAR)'\0';
  5311. if (!(pstrauNewData->Append(pszDataIndex, (DWORD)DIFF(pszNextDataIndex - pszDataIndex)))) {
  5312. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5313. }
  5314. if (!(pstrauNewData->Append((LPWSTR)pszPath))) {
  5315. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5316. }
  5317. }
  5318. if (!(pstrauNewData->Append(pszDataIndex))) {
  5319. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5320. }
  5321. *pdwDataLen = pstrauNewData->QueryCB(bUnicode) + sizeof(WCHAR);
  5322. }
  5323. else {
  5324. LPTSTR pszDataIndex, pszNextDataIndex;
  5325. pstrauNewData->SetLen(0);
  5326. for (pszDataIndex = pszOldData;
  5327. SUCCEEDED(hresReturn) && ((pszNextDataIndex = MD_STRSTR(pszDataIndex, MD_INSERT_PATH_STRINGA)) != NULL);
  5328. pszDataIndex = pszNextDataIndex + ((sizeof(MD_INSERT_PATH_STRINGA) - 1))) {
  5329. // *pszNextDataIndex = (TCHAR)'\0';
  5330. if (!(pstrauNewData->Append(pszDataIndex, (DWORD)DIFF(pszNextDataIndex - pszDataIndex)))) {
  5331. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5332. }
  5333. if (!(pstrauNewData->Append(pszPath))) {
  5334. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5335. }
  5336. }
  5337. if (!(pstrauNewData->Append(pszDataIndex))) {
  5338. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5339. }
  5340. *pdwDataLen = pstrauNewData->QueryCB(bUnicode) + sizeof(CHAR);
  5341. }
  5342. return hresReturn;
  5343. }
  5344. HRESULT
  5345. InsertPathIntoData(BUFFER *pbufNewData,
  5346. STRAU *pstrData,
  5347. PBYTE *ppbNewData,
  5348. DWORD *pdwNewDataLen,
  5349. CMDBaseData *pbdRetrieve,
  5350. METADATA_HANDLE hHandle,
  5351. CMDBaseObject *pboDataMetaObject,
  5352. IN BOOL bUnicode)
  5353. {
  5354. //
  5355. // Need to insert path
  5356. //
  5357. HRESULT hresReturn = ERROR_SUCCESS;
  5358. DWORD dwPathLen = 0;
  5359. BUFFER bufPath;
  5360. CMDHandle * pCMDHandle = GetHandleObject(hHandle);
  5361. if( !pCMDHandle )
  5362. {
  5363. return MD_ERROR_DATA_NOT_FOUND;
  5364. }
  5365. CMDBaseObject *pboHandleMetaObject = pCMDHandle->GetObject();
  5366. MD_ASSERT((pbdRetrieve->GetDataType() != DWORD_METADATA) &&
  5367. (pbdRetrieve->GetDataType() != BINARY_METADATA));
  5368. if (pboHandleMetaObject->GetObjectLevel() > pboDataMetaObject->GetObjectLevel()) {
  5369. hresReturn = MD_WARNING_PATH_NOT_INSERTED;
  5370. }
  5371. else {
  5372. DWORD dwReturn;
  5373. if ( (dwReturn = GetObjectPath(pboDataMetaObject,
  5374. &bufPath,
  5375. dwPathLen,
  5376. pboHandleMetaObject,
  5377. bUnicode)) != ERROR_SUCCESS) {
  5378. hresReturn = RETURNCODETOHRESULT(dwReturn);
  5379. }
  5380. else if (!bufPath.Resize((dwPathLen + 2) * ((bUnicode) ? sizeof(WCHAR) : sizeof(CHAR)))) {
  5381. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5382. }
  5383. else {
  5384. LPTSTR pszPath;
  5385. DWORD dwDataLen;
  5386. pszPath = (LPTSTR)(bufPath.QueryPtr());
  5387. if (bUnicode) {
  5388. ((LPWSTR)pszPath)[dwPathLen] = MD_PATH_DELIMETERW;
  5389. ((LPWSTR)pszPath)[dwPathLen + 1] = (WCHAR)L'\0';
  5390. }
  5391. else {
  5392. pszPath[dwPathLen] = MD_PATH_DELIMETERA;
  5393. pszPath[dwPathLen + 1] = (TCHAR)'\0';
  5394. }
  5395. //
  5396. // If there was an error in GetData, it would have been
  5397. // caught already.
  5398. //
  5399. MD_ASSERT(pbdRetrieve->GetData(bUnicode) != NULL);
  5400. switch (pbdRetrieve->GetDataType()) {
  5401. case STRING_METADATA:
  5402. case EXPANDSZ_METADATA:
  5403. {
  5404. hresReturn = MakeInsertPathData(pstrData,
  5405. (LPTSTR)bufPath.QueryPtr(),
  5406. (LPTSTR)pbdRetrieve->GetData(bUnicode),
  5407. &dwDataLen,
  5408. bUnicode);
  5409. if (SUCCEEDED(hresReturn)) {
  5410. //
  5411. // QueryStr should not fail in this instance
  5412. // since it was created with the same unicode flag
  5413. //
  5414. MD_ASSERT(pstrData->QueryStr(bUnicode) != NULL);
  5415. *ppbNewData = (PBYTE) pstrData->QueryStr(bUnicode);
  5416. *pdwNewDataLen = dwDataLen;
  5417. }
  5418. }
  5419. break;
  5420. case MULTISZ_METADATA:
  5421. {
  5422. if (bUnicode) {
  5423. LPWSTR pszDataIndex;
  5424. DWORD dwStringBytes;
  5425. dwDataLen = 0;
  5426. //
  5427. // Loop through all strings
  5428. //
  5429. for (pszDataIndex = (LPWSTR)pbdRetrieve->GetData(bUnicode);
  5430. SUCCEEDED(hresReturn) && (*pszDataIndex != (WCHAR)L'\0');
  5431. pszDataIndex += (wcslen(pszDataIndex) + 1)) {
  5432. hresReturn = MakeInsertPathData(pstrData,
  5433. (LPSTR)bufPath.QueryPtr(),
  5434. (LPSTR)pszDataIndex,
  5435. &dwStringBytes,
  5436. bUnicode);
  5437. if (SUCCEEDED(hresReturn)) {
  5438. if (!pbufNewData->Resize(dwDataLen + dwStringBytes)) {
  5439. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5440. }
  5441. else {
  5442. //
  5443. // QueryStr should not fail in this instance
  5444. // since it was created with the same unicode flag
  5445. //
  5446. MD_ASSERT(pstrData->QueryStr(bUnicode) != NULL);
  5447. MD_COPY((PBYTE)(pbufNewData->QueryPtr()) + dwDataLen,
  5448. pstrData->QueryStr(bUnicode),
  5449. dwStringBytes);
  5450. dwDataLen += dwStringBytes;
  5451. }
  5452. }
  5453. }
  5454. if (SUCCEEDED(hresReturn)) {
  5455. dwDataLen += sizeof(WCHAR);
  5456. if (!pbufNewData->Resize(dwDataLen)) {
  5457. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5458. }
  5459. else {
  5460. *ppbNewData = (PBYTE)(pbufNewData->QueryPtr());
  5461. *(((LPWSTR)(*ppbNewData)) + ((dwDataLen / sizeof(WCHAR)) - 1)) = (WCHAR)L'\0';
  5462. *pdwNewDataLen = dwDataLen;
  5463. }
  5464. }
  5465. }
  5466. else {
  5467. LPSTR pszDataIndex;
  5468. DWORD dwStringBytes;
  5469. dwDataLen = 0;
  5470. //
  5471. // Loop through all strings
  5472. //
  5473. for (pszDataIndex = (LPTSTR)pbdRetrieve->GetData(bUnicode);
  5474. SUCCEEDED(hresReturn) && (*pszDataIndex != (CHAR)'\0');
  5475. pszDataIndex += (MD_STRBYTES(pszDataIndex) + 1)) {
  5476. hresReturn = MakeInsertPathData(pstrData,
  5477. (LPTSTR)bufPath.QueryPtr(),
  5478. pszDataIndex,
  5479. &dwStringBytes);
  5480. if (SUCCEEDED(hresReturn)) {
  5481. if (!pbufNewData->Resize(dwDataLen + dwStringBytes)) {
  5482. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5483. }
  5484. else {
  5485. //
  5486. // QueryStr should not fail in this instance
  5487. // since it was created with the same unicode flag
  5488. //
  5489. MD_ASSERT(pstrData->QueryStrA() != NULL);
  5490. MD_COPY((PBYTE)(pbufNewData->QueryPtr()) + dwDataLen, pstrData->QueryStrA(), dwStringBytes);
  5491. dwDataLen += dwStringBytes;
  5492. }
  5493. }
  5494. }
  5495. if (SUCCEEDED(hresReturn)) {
  5496. dwDataLen += sizeof(TCHAR);
  5497. if (!pbufNewData->Resize(dwDataLen)) {
  5498. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5499. }
  5500. else {
  5501. *ppbNewData = (PBYTE)(pbufNewData->QueryPtr());
  5502. *(*ppbNewData + (dwDataLen-1)) = (CHAR)'\0';
  5503. *pdwNewDataLen = dwDataLen;
  5504. }
  5505. }
  5506. }
  5507. }
  5508. break;
  5509. default:
  5510. MD_ASSERT(FALSE);
  5511. }
  5512. }
  5513. }
  5514. return hresReturn;
  5515. }
  5516. HRESULT
  5517. MakeTreeCopyWithPath(CMDBaseObject *pboSource,
  5518. CMDBaseObject *&rpboNew,
  5519. LPSTR pszPath,
  5520. IN BOOL bUnicode)
  5521. {
  5522. WCHAR pszName[METADATA_MAX_NAME_LEN];
  5523. LPSTR pszTempPath = pszPath;
  5524. CMDBaseObject *pboNew = NULL;
  5525. CMDBaseObject *pboParent = NULL;
  5526. CMDBaseObject *pboTree = NULL;
  5527. HRESULT hresReturn = ERROR_SUCCESS;
  5528. HRESULT hresExtractReturn = S_OK;
  5529. while ((SUCCEEDED(hresReturn)) &&
  5530. (SUCCEEDED(hresExtractReturn = ExtractNameFromPath(pszTempPath, (LPSTR)pszName, bUnicode)))) {
  5531. if (bUnicode) {
  5532. pboNew = new CMDBaseObject((LPWSTR)pszName);
  5533. }
  5534. else {
  5535. pboNew = new CMDBaseObject((LPSTR)pszName);
  5536. }
  5537. if (pboNew == NULL) {
  5538. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5539. }
  5540. else if (!pboNew->IsValid()) {
  5541. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5542. delete (pboNew);
  5543. }
  5544. else {
  5545. if (pboParent != NULL) {
  5546. hresReturn = pboParent->InsertChildObject(pboNew);
  5547. if (FAILED(hresReturn)) {
  5548. delete pboNew;
  5549. pboNew = pboParent;
  5550. }
  5551. }
  5552. pboParent = pboNew;
  5553. }
  5554. }
  5555. if ((SUCCEEDED(hresReturn)) && (hresExtractReturn != (RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)))) {
  5556. hresReturn = hresExtractReturn;
  5557. }
  5558. if (SUCCEEDED(hresReturn)) {
  5559. //
  5560. // Don't really want the leaf object, as MakeTreeCopy will create it.
  5561. //
  5562. LPWSTR pszTreeName = NULL;
  5563. if (pboNew != NULL) {
  5564. pszTreeName = (LPWSTR)pboNew->GetName(TRUE);
  5565. pboParent = pboNew->GetParent();
  5566. if (pszTreeName == NULL) {
  5567. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5568. }
  5569. }
  5570. if (SUCCEEDED(hresReturn)) {
  5571. hresReturn = MakeTreeCopy(pboSource, pboTree, (LPSTR)pszTreeName, TRUE);
  5572. if (SUCCEEDED(hresReturn)) {
  5573. MD_ASSERT(pboTree != NULL);
  5574. if (pboParent != NULL) {
  5575. MD_REQUIRE(SUCCEEDED(pboParent->RemoveChildObject(pboNew)));
  5576. hresReturn = pboParent->InsertChildObject(pboTree);
  5577. if (FAILED(hresReturn)) {
  5578. delete(pboTree);
  5579. pboTree = NULL;
  5580. }
  5581. }
  5582. }
  5583. }
  5584. delete(pboNew);
  5585. pboNew = NULL;
  5586. }
  5587. if (FAILED(hresReturn)) {
  5588. if (pboParent != NULL) {
  5589. CMDBaseObject *pboTemp;
  5590. MD_ASSERT(pboNew != NULL);
  5591. for (pboTemp = pboParent; pboTemp->GetParent() != NULL; pboTemp = pboTemp->GetParent()) {
  5592. }
  5593. //
  5594. // destructor recurses through child objects
  5595. //
  5596. delete pboTemp;
  5597. }
  5598. }
  5599. else {
  5600. MD_ASSERT(pboTree != NULL);
  5601. CMDBaseObject *pboTemp;
  5602. for (pboTemp = pboTree; pboTemp->GetParent() != NULL; pboTemp = pboTemp->GetParent()) {
  5603. }
  5604. rpboNew = pboTemp;
  5605. }
  5606. return hresReturn;
  5607. }
  5608. HRESULT
  5609. MakeTreeCopy(CMDBaseObject *pboSource,
  5610. CMDBaseObject *&rpboNew,
  5611. LPSTR pszName,
  5612. IN BOOL bUnicode)
  5613. {
  5614. CMDBaseObject *pboTemp = NULL;
  5615. CMDBaseObject *pboOldChild, *pboNewChild;
  5616. DWORD i, dwNumDataObjects;
  5617. PVOID *ppvMainDataBuf;
  5618. CMDBaseData *pbdCurrent;
  5619. HRESULT hresReturn = ERROR_SUCCESS;
  5620. if (pszName == NULL) {
  5621. if ((pboSource->GetName(TRUE)) != NULL) {
  5622. pboTemp = new CMDBaseObject((LPWSTR)(pboSource->GetName(TRUE)), NULL);
  5623. }
  5624. }
  5625. else {
  5626. if (bUnicode) {
  5627. pboTemp = new CMDBaseObject((LPWSTR)pszName, NULL);
  5628. }
  5629. else {
  5630. pboTemp = new CMDBaseObject((LPSTR)pszName, NULL);
  5631. }
  5632. }
  5633. if (pboTemp == NULL) {
  5634. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5635. }
  5636. else if (!pboTemp->IsValid()) {
  5637. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5638. delete (pboTemp);
  5639. }
  5640. else {
  5641. ppvMainDataBuf = GetMainDataBuffer();
  5642. MD_ASSERT (ppvMainDataBuf != NULL);
  5643. if ( ppvMainDataBuf == NULL )
  5644. {
  5645. hresReturn = E_FAIL;
  5646. }
  5647. else
  5648. {
  5649. dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf, 0, ALL_METADATA, ALL_METADATA, FALSE, FALSE);
  5650. for (i = 0; (i < dwNumDataObjects) && (SUCCEEDED(hresReturn)) ; i++) {
  5651. pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
  5652. MD_ASSERT(pbdCurrent != NULL);
  5653. hresReturn = pboTemp->SetDataObject(pbdCurrent);
  5654. }
  5655. FreeMainDataBuffer(ppvMainDataBuf);
  5656. }
  5657. }
  5658. if (SUCCEEDED(hresReturn)) {
  5659. i = 0;
  5660. pboOldChild = pboSource->EnumChildObject(i);
  5661. while ((SUCCEEDED(hresReturn)) && (pboOldChild != NULL)) {
  5662. hresReturn = MakeTreeCopy(pboOldChild, pboNewChild, NULL, bUnicode);
  5663. if (SUCCEEDED(hresReturn)) {
  5664. MD_ASSERT (pboNewChild != NULL);
  5665. hresReturn = pboTemp->InsertChildObject(pboNewChild);
  5666. }
  5667. i++;
  5668. pboOldChild = pboSource->EnumChildObject(i);
  5669. }
  5670. }
  5671. if (SUCCEEDED(hresReturn)) {
  5672. rpboNew = pboTemp;
  5673. }
  5674. else {
  5675. rpboNew = NULL;
  5676. delete(pboTemp);
  5677. }
  5678. return (hresReturn);
  5679. }
  5680. void
  5681. AddNewChangeData(CMDHandle *phoDestHandle,
  5682. CMDBaseObject *pboNew)
  5683. {
  5684. DWORD i;
  5685. CMDBaseObject *pboChild;
  5686. CMDBaseData *pbdCurrent;
  5687. MD_ASSERT(pboNew != NULL);
  5688. phoDestHandle->SetChangeData(pboNew, MD_CHANGE_TYPE_ADD_OBJECT, 0);
  5689. if ((pbdCurrent = pboNew->EnumDataObject(0, 0, ALL_METADATA, ALL_METADATA)) != NULL) {
  5690. phoDestHandle->SetChangeData(pboNew, MD_CHANGE_TYPE_SET_DATA, pbdCurrent->GetIdentifier());
  5691. }
  5692. i = 0;
  5693. pboChild = pboNew->EnumChildObject(i);
  5694. while (pboChild != NULL) {
  5695. AddNewChangeData(phoDestHandle, pboChild);
  5696. i++;
  5697. pboChild = pboNew->EnumChildObject(i);
  5698. }
  5699. }
  5700. HRESULT
  5701. CopyTree(CMDHandle *phoDestParentHandle,
  5702. CMDBaseObject *pboDest,
  5703. CMDBaseObject *pboSource,
  5704. BOOL &rbChanged)
  5705. {
  5706. CMDBaseObject *pboOldChild, *pboNewChild;
  5707. DWORD i, dwNumDataObjects;
  5708. PVOID *ppvMainDataBuf;
  5709. CMDBaseData *pbdCurrent;
  5710. LPSTR pszTempName;
  5711. HRESULT hresReturn = ERROR_SUCCESS;
  5712. MD_ASSERT(pboDest != NULL);
  5713. MD_ASSERT(pboSource != NULL);
  5714. ppvMainDataBuf = GetMainDataBuffer();
  5715. MD_ASSERT (ppvMainDataBuf != NULL);
  5716. if ( ppvMainDataBuf == NULL )
  5717. {
  5718. hresReturn = E_FAIL;
  5719. }
  5720. else
  5721. {
  5722. dwNumDataObjects = pboSource->GetAllDataObjects(ppvMainDataBuf, 0, ALL_METADATA, ALL_METADATA, FALSE, FALSE);
  5723. for (i = 0; (i < dwNumDataObjects) && (SUCCEEDED(hresReturn)) ; i++) {
  5724. pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
  5725. MD_ASSERT(pbdCurrent != NULL);
  5726. PREFIX_ASSUME(pbdCurrent != NULL, "pbdCurrent is guaranteed not to NULL here");
  5727. hresReturn = pboDest->SetDataObject(pbdCurrent);
  5728. if (SUCCEEDED(hresReturn)) {
  5729. rbChanged = TRUE;
  5730. phoDestParentHandle->SetChangeData(pboDest, MD_CHANGE_TYPE_SET_DATA, pbdCurrent->GetIdentifier());
  5731. }
  5732. }
  5733. if (SUCCEEDED(hresReturn)) {
  5734. i = 0;
  5735. pboOldChild = pboSource->EnumChildObject(i);
  5736. while ((SUCCEEDED(hresReturn)) && (pboOldChild != NULL)) {
  5737. pszTempName = (pboOldChild->GetName(TRUE));
  5738. if (pszTempName == NULL) {
  5739. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  5740. }
  5741. else {
  5742. pboNewChild = pboDest->GetChildObject(pszTempName, &hresReturn, TRUE);
  5743. if (SUCCEEDED(hresReturn)) {
  5744. if (pboNewChild != NULL) {
  5745. hresReturn = CopyTree(phoDestParentHandle, pboNewChild, pboOldChild, rbChanged);
  5746. }
  5747. else {
  5748. hresReturn = MakeTreeCopy(pboOldChild, pboNewChild);
  5749. if (SUCCEEDED(hresReturn)) {
  5750. MD_ASSERT (pboNewChild != NULL);
  5751. hresReturn = pboDest->InsertChildObject(pboNewChild);
  5752. if (SUCCEEDED(hresReturn)) {
  5753. rbChanged = TRUE;
  5754. AddNewChangeData(phoDestParentHandle, pboNewChild);
  5755. }
  5756. else {
  5757. delete(pboNewChild);
  5758. }
  5759. }
  5760. }
  5761. i++;
  5762. pboOldChild = pboSource->EnumChildObject(i);
  5763. }
  5764. }
  5765. }
  5766. }
  5767. FreeMainDataBuffer(ppvMainDataBuf);
  5768. }
  5769. return (hresReturn);
  5770. }
  5771. HRESULT
  5772. CheckForSetup()
  5773. /*++
  5774. Routine Description:
  5775. Checks whether the IIS setup is currently running.
  5776. Arguments:
  5777. Return Value:
  5778. HRESULT - S_OK: Yes, we are in setup
  5779. - S_FALSE: No, we are not in setup
  5780. - E_*: Failure
  5781. Notes:
  5782. --*/
  5783. {
  5784. HRESULT hr = S_OK;
  5785. HKEY hkeySetup = NULL;
  5786. DWORD dwErr;
  5787. DWORD dwValue = 0;
  5788. DWORD dwType = REG_NONE;
  5789. DWORD dwSize = sizeof(DWORD);
  5790. // Open HKLM\SOFTWARE\Microsoft\InetStp
  5791. dwErr = RegOpenKey( HKEY_LOCAL_MACHINE,
  5792. SETUP_REG_KEY,
  5793. &hkeySetup );
  5794. if ( dwErr != ERROR_SUCCESS )
  5795. {
  5796. hr = HRESULT_FROM_WIN32( dwErr );
  5797. goto exit;
  5798. }
  5799. // Get CurrentInstallState
  5800. dwErr = RegQueryValueEx( hkeySetup,
  5801. MD_CURRENT_INSTALL_STATE,
  5802. NULL,
  5803. &dwType,
  5804. (BYTE*)&dwValue,
  5805. &dwSize );
  5806. if ( dwErr != ERROR_SUCCESS )
  5807. {
  5808. hr = HRESULT_FROM_WIN32( dwErr );
  5809. goto exit;
  5810. }
  5811. // If it isn't a DWORD
  5812. if ( ( dwType != REG_DWORD ) ||
  5813. ( dwSize != sizeof(DWORD) ) )
  5814. {
  5815. // The value is bad
  5816. hr = E_FAIL;
  5817. goto exit;
  5818. }
  5819. // If during setup
  5820. if ( ( dwValue & MD_INSTALL_STATE_INSTALLING ) == MD_INSTALL_STATE_INSTALLING )
  5821. {
  5822. // Yes, we are in setup
  5823. hr = S_OK;
  5824. }
  5825. else
  5826. {
  5827. // No, we are not in setup
  5828. hr = S_FALSE;
  5829. }
  5830. exit:
  5831. if ( hkeySetup != NULL )
  5832. {
  5833. RegCloseKey( hkeySetup );
  5834. hkeySetup = NULL;
  5835. }
  5836. // Done
  5837. return hr;
  5838. }
  5839. void CheckForNewMetabaseVersion()
  5840. {
  5841. BOOL bValueWasWrongType = FALSE;
  5842. BOOL bSomethingChanged = FALSE;
  5843. HKEY hkRegistryKey = NULL;
  5844. DWORD dwRegReturn,dwValue,dwType,dwSize = sizeof(DWORD);
  5845. dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
  5846. SETUP_REG_KEY,
  5847. &hkRegistryKey);
  5848. if (dwRegReturn == ERROR_SUCCESS)
  5849. {
  5850. // Check for update to major version
  5851. // get the Type of data only first
  5852. // since a string won't fit in &dwValue
  5853. dwValue = 0;
  5854. dwSize = sizeof(DWORD);
  5855. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  5856. MD_SETMAJORVERSION_VALUE,
  5857. NULL,
  5858. &dwType,
  5859. NULL,
  5860. &dwSize);
  5861. if ( dwRegReturn == ERROR_SUCCESS)
  5862. {
  5863. if (dwType == REG_DWORD)
  5864. {
  5865. dwSize = sizeof(DWORD);
  5866. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  5867. MD_SETMAJORVERSION_VALUE,
  5868. NULL,
  5869. &dwType,
  5870. (BYTE *)&dwValue,
  5871. &dwSize);
  5872. if ( dwRegReturn == ERROR_SUCCESS)
  5873. {
  5874. // default the value with the version that this binary was compiled with
  5875. if (dwType == REG_DWORD)
  5876. {
  5877. if (g_dwMajorVersionNumber != dwValue && dwValue >= 1)
  5878. {
  5879. g_dwMajorVersionNumber = dwValue;
  5880. bSomethingChanged = TRUE;
  5881. }
  5882. }
  5883. else
  5884. {
  5885. bValueWasWrongType = TRUE;
  5886. }
  5887. }
  5888. }
  5889. else
  5890. {
  5891. bValueWasWrongType = TRUE;
  5892. }
  5893. }
  5894. if (FALSE == bValueWasWrongType)
  5895. {
  5896. // Check for update to minor version
  5897. // get the Type of data only first
  5898. // since a string won't fit in &dwValue
  5899. dwValue = 0;
  5900. dwSize = sizeof(DWORD);
  5901. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  5902. MD_SETMINORVERSION_VALUE,
  5903. NULL,
  5904. &dwType,
  5905. NULL,
  5906. &dwSize);
  5907. if ( dwRegReturn == ERROR_SUCCESS)
  5908. {
  5909. if (dwType == REG_DWORD)
  5910. {
  5911. dwSize = sizeof(DWORD);
  5912. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  5913. MD_SETMINORVERSION_VALUE,
  5914. NULL,
  5915. &dwType,
  5916. (BYTE *)&dwValue,
  5917. &dwSize);
  5918. if ( dwRegReturn == ERROR_SUCCESS)
  5919. {
  5920. if (dwType == REG_DWORD)
  5921. {
  5922. if (g_dwMinorVersionNumber != dwValue)
  5923. {
  5924. g_dwMinorVersionNumber = dwValue;
  5925. bSomethingChanged = TRUE;
  5926. }
  5927. }
  5928. else
  5929. {
  5930. bValueWasWrongType = TRUE;
  5931. }
  5932. }
  5933. }
  5934. else
  5935. {
  5936. bValueWasWrongType = TRUE;
  5937. }
  5938. }
  5939. }
  5940. MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
  5941. }
  5942. if (TRUE == bValueWasWrongType)
  5943. {
  5944. // default the value with the version that this binary was compiled with
  5945. if (g_dwMajorVersionNumber != MD_MAJOR_VERSION_NUMBER)
  5946. {
  5947. g_dwMajorVersionNumber = MD_MAJOR_VERSION_NUMBER;
  5948. bSomethingChanged = TRUE;
  5949. }
  5950. if (g_dwMinorVersionNumber != MD_MINOR_VERSION_NUMBER)
  5951. {
  5952. g_dwMinorVersionNumber = MD_MINOR_VERSION_NUMBER;
  5953. bSomethingChanged = TRUE;
  5954. }
  5955. }
  5956. if (TRUE == bSomethingChanged)
  5957. {
  5958. // make sure that we tell the metabase that there was a change made..
  5959. g_dwSystemChangeNumber++;
  5960. IIS_PRINTF((buff,"MD:New Metabase Version:%d.%d\n",g_dwMajorVersionNumber,g_dwMinorVersionNumber));
  5961. }
  5962. return;
  5963. }
  5964. BOOL
  5965. CheckVersionNumber()
  5966. {
  5967. BOOL bReturn = FALSE;
  5968. if (g_dwMajorVersionNumber >= 1) {
  5969. // 1 = IIS4
  5970. // we need to be able to open IIS4 in IIS5 during setup upgrade
  5971. // 2 = IIS5
  5972. bReturn = TRUE;
  5973. }
  5974. // g_dwMinorVersionNumber -- maybe use this for Major service pack releases or something in which
  5975. // Metabase has been changed and we need to know the difference?
  5976. return bReturn;
  5977. }
  5978. HRESULT
  5979. InitStorageAndSessionKey(
  5980. IN IIS_CRYPTO_STORAGE *pCryptoStorage,
  5981. OUT PIIS_CRYPTO_BLOB *ppSessionKeyBlob
  5982. )
  5983. {
  5984. HRESULT hresReturn;
  5985. HCRYPTPROV hProv;
  5986. //
  5987. // Get a handle to the crypto provider, init the storage object,
  5988. // then export the session key blob.
  5989. //
  5990. hresReturn = GetCryptoProvider( &hProv );
  5991. if( SUCCEEDED(hresReturn) )
  5992. {
  5993. hresReturn = pCryptoStorage->Initialize(
  5994. TRUE, // fUseMachineKeyset
  5995. hProv
  5996. );
  5997. if (FAILED(hresReturn))
  5998. {
  5999. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->Initialize Failed - error 0x%0x\n", hresReturn));
  6000. }
  6001. }
  6002. else
  6003. {
  6004. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: GetCryptoProvider Failed - error 0x%0x\n", hresReturn));
  6005. }
  6006. if( SUCCEEDED(hresReturn) )
  6007. {
  6008. hresReturn = pCryptoStorage->GetSessionKeyBlob( ppSessionKeyBlob );
  6009. if (FAILED(hresReturn))
  6010. {
  6011. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->GetSessionKeyBlob Failed - error 0x%0x\n", hresReturn));
  6012. }
  6013. }
  6014. return hresReturn;
  6015. } // InitStorageAndSessionKey
  6016. HRESULT
  6017. InitStorageAndSessionKey2(
  6018. IN LPSTR pszPasswd,
  6019. IN IIS_CRYPTO_STORAGE *pCryptoStorage,
  6020. OUT PIIS_CRYPTO_BLOB *ppSessionKeyBlob
  6021. )
  6022. {
  6023. HRESULT hresReturn;
  6024. HCRYPTPROV hProv;
  6025. //
  6026. // Get a handle to the crypto provider, init the storage object,
  6027. // then export the session key blob.
  6028. //
  6029. hresReturn = GetCryptoProvider2( &hProv );
  6030. if( SUCCEEDED(hresReturn) )
  6031. {
  6032. hresReturn = ((IIS_CRYPTO_STORAGE2*)pCryptoStorage)->Initialize(
  6033. hProv
  6034. );
  6035. if (FAILED(hresReturn))
  6036. {
  6037. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->Initialize Failed - error 0x%0x\n", hresReturn));
  6038. }
  6039. }
  6040. else
  6041. {
  6042. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: GetCryptoProvider2 Failed - error 0x%0x\n", hresReturn));
  6043. }
  6044. if( SUCCEEDED(hresReturn) )
  6045. {
  6046. hresReturn = ((IIS_CRYPTO_STORAGE2*)pCryptoStorage)->GetSessionKeyBlob( pszPasswd, ppSessionKeyBlob );
  6047. if (FAILED(hresReturn))
  6048. {
  6049. DBGPRINTF(( DBG_CONTEXT, "InitStorageAndSessionKey: pCryptoStorage->GetSessionKeyBlob Failed - error 0x%0x\n", hresReturn));
  6050. }
  6051. }
  6052. return hresReturn;
  6053. } // InitStorageAndSessionKey2
  6054. VOID
  6055. SkipPathDelimeter(IN OUT LPSTR &rpszPath,
  6056. IN BOOL bUnicode)
  6057. {
  6058. if (bUnicode) {
  6059. LPWSTR pszPath = (LPWSTR)rpszPath;
  6060. SKIP_PATH_DELIMETERW(pszPath);
  6061. rpszPath = (LPSTR)pszPath;
  6062. }
  6063. else {
  6064. SKIP_PATH_DELIMETERA(rpszPath);
  6065. }
  6066. }
  6067. BOOL
  6068. IsStringTerminator(IN LPTSTR pszString,
  6069. IN BOOL bUnicode)
  6070. {
  6071. if (bUnicode) {
  6072. if (*(LPWSTR)pszString == (WCHAR)L'\0') {
  6073. return TRUE;
  6074. }
  6075. }
  6076. else {
  6077. if (*(LPSTR)pszString == (CHAR)'\0') {
  6078. return TRUE;
  6079. }
  6080. }
  6081. return FALSE;
  6082. }
  6083. HRESULT
  6084. GetLastHResult() {
  6085. DWORD tmp = GetLastError();
  6086. return RETURNCODETOHRESULT(tmp);
  6087. }
  6088. HRESULT STDMETHODCALLTYPE BackupCertificates (LPCWSTR backupName,PCHAR lpszToPath,PCHAR lpszFromPath)
  6089. {
  6090. HRESULT hresReturn = ERROR_SUCCESS;
  6091. CHAR *p1,*p2;
  6092. LPSTR searchMask = "*.mp";
  6093. LPSTR backupNameSeparator = ".";
  6094. CHAR strSourcePath[MAX_PATH];
  6095. CHAR strSearchPattern[MAX_PATH];
  6096. CHAR strDestPath[MAX_PATH];
  6097. DWORD dwLenOfBackupName, n1;
  6098. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  6099. WIN32_FIND_DATA FileInfo;
  6100. BOOL fFoundFile = TRUE, fValid;
  6101. STRAU strSrcFileName, strDestFileName;
  6102. dwLenOfBackupName = (DWORD)(wcslen (backupName) * sizeof (WCHAR));
  6103. p1 = strrchr (lpszFromPath,'\\');
  6104. p2 = strrchr (lpszToPath,'\\');
  6105. if (p1 &&p2)
  6106. {
  6107. n1 = min (MAX_PATH-1, (DWORD)DIFF(p1 - lpszFromPath)+1);
  6108. strncpy (strSourcePath,lpszFromPath,n1);
  6109. strSourcePath[n1] = 0;
  6110. strcpy (strSearchPattern,strSourcePath);
  6111. n1 = min (MAX_PATH-1, (DWORD)DIFF(p2 - lpszToPath)+1);
  6112. strncpy (strDestPath,lpszToPath,n1);
  6113. strDestPath[n1] = 0;
  6114. if (strlen (strSourcePath) + strlen(searchMask) < MAX_PATH)
  6115. {
  6116. strcat (strSearchPattern,searchMask);
  6117. hFindFile = FindFirstFile( strSearchPattern, &FileInfo);
  6118. if (hFindFile == INVALID_HANDLE_VALUE)
  6119. {
  6120. // no certificate file found
  6121. return ERROR_SUCCESS;
  6122. }
  6123. while (fFoundFile)
  6124. {
  6125. if ( strlen (FileInfo.cFileName) + strlen (strDestPath) + dwLenOfBackupName + 1 < MAX_PATH)
  6126. {
  6127. fValid = strSrcFileName.Copy (strSourcePath);
  6128. fValid = fValid && strSrcFileName.Append (FileInfo.cFileName);
  6129. fValid = fValid && strDestFileName.Copy (strDestPath);
  6130. fValid = fValid && strDestFileName.Append ((LPWSTR)backupName);
  6131. fValid = fValid && strDestFileName.Append (backupNameSeparator);
  6132. fValid = fValid && strDestFileName.Append (FileInfo.cFileName);
  6133. if (fValid)
  6134. {
  6135. if (!CopyFileW (strSrcFileName.QueryStrW(),strDestFileName.QueryStrW(),FALSE))
  6136. {
  6137. IIS_PRINTF((buff,"CertificateBackup: CopyFileW error 0x%0X \n",GetLastError()));
  6138. }
  6139. }
  6140. else
  6141. {
  6142. IIS_PRINTF((buff,"CertificateBackup: Failure in STRAU manipulation \n"));
  6143. }
  6144. }
  6145. fFoundFile = FindNextFile(hFindFile,&FileInfo);
  6146. }
  6147. fFoundFile = FindClose (hFindFile);
  6148. MD_ASSERT (fFoundFile);
  6149. }
  6150. else
  6151. {
  6152. IIS_PRINTF((buff,"CertificateBackup: strSourcePath filename was too long\n"));
  6153. }
  6154. }
  6155. else
  6156. {
  6157. IIS_PRINTF((buff,"CertificateBackup: can't find last back slash in one of these strings %s %s\n",lpszToPath,lpszFromPath));
  6158. }
  6159. return hresReturn;
  6160. }
  6161. HRESULT STDMETHODCALLTYPE RestoreCertificates (LPCWSTR backupName,PCHAR lpszFromPath,PCHAR lpszToPath)
  6162. {
  6163. HRESULT hresReturn = ERROR_SUCCESS;
  6164. DWORD n1;
  6165. CHAR strDestinationPath[MAX_PATH];
  6166. CHAR strSourcePath[MAX_PATH];
  6167. CHAR *p1,*p2;
  6168. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  6169. BOOL fFoundFile = TRUE, fValid;
  6170. STRAU strSearchPatttern, strDestFileName, strSrcFileName;
  6171. WIN32_FIND_DATAW FileInfo;
  6172. LPWSTR pszSearchPattern = NULL;
  6173. p1 = strrchr (lpszToPath,'\\');
  6174. p2 = strrchr (lpszFromPath,'\\');
  6175. if (p1 &&p2)
  6176. {
  6177. n1 = min (MAX_PATH-1, (DWORD)DIFF(p1 - lpszToPath)+1);
  6178. strncpy (strDestinationPath,lpszToPath,n1);
  6179. strDestinationPath[n1] = 0;
  6180. n1 = min (MAX_PATH-1, (DWORD)DIFF(p2 - lpszFromPath)+1);
  6181. strncpy (strSourcePath,lpszFromPath,n1);
  6182. strSourcePath[n1] = 0;
  6183. strSearchPatttern.Copy (strSourcePath);
  6184. strSearchPatttern.Append ((LPWSTR)backupName);
  6185. strSearchPatttern.Append ((LPWSTR)L".*.mp");
  6186. pszSearchPattern = strSearchPatttern.QueryStrW();
  6187. if( !( pszSearchPattern ) )
  6188. {
  6189. return ERROR_SUCCESS;
  6190. }
  6191. hFindFile = FindFirstFileW( pszSearchPattern, &FileInfo);
  6192. if (hFindFile == INVALID_HANDLE_VALUE)
  6193. {
  6194. // no certificate file found
  6195. return ERROR_SUCCESS;
  6196. }
  6197. while (fFoundFile)
  6198. {
  6199. fValid = strDestFileName.Copy (strDestinationPath);
  6200. fValid = fValid && strDestFileName.Append ((LPWSTR)(FileInfo.cFileName + wcslen (backupName) +1));
  6201. fValid = fValid && strSrcFileName.Copy (strSourcePath);
  6202. fValid = fValid && strSrcFileName.Append ((LPWSTR)FileInfo.cFileName);
  6203. if (fValid)
  6204. {
  6205. if (!CopyFileW (strSrcFileName.QueryStrW(),strDestFileName.QueryStrW(),FALSE))
  6206. {
  6207. IIS_PRINTF((buff,"CertificateBackup: CopyFileW error 0x%0X \n",GetLastError()));
  6208. }
  6209. }
  6210. else
  6211. {
  6212. IIS_PRINTF((buff,"CertificateBackup: Failure in STRAU manipulation \n"));
  6213. }
  6214. fFoundFile = FindNextFileW(hFindFile,&FileInfo);
  6215. }
  6216. fFoundFile = FindClose (hFindFile);
  6217. MD_ASSERT (fFoundFile);
  6218. }
  6219. else
  6220. {
  6221. IIS_PRINTF((buff,"CertificateRestore: can't find last back slash in one of these strings %s %s\n",lpszToPath,lpszFromPath));
  6222. }
  6223. return hresReturn;
  6224. }
  6225. HRESULT
  6226. ReadMetaObject(IN CMDBaseObject*& cboRead,
  6227. IN LPWSTR wszPath,
  6228. IN FILETIME* pFileTime,
  6229. IN BOOL bUnicode)
  6230. /*++
  6231. Routine Description:
  6232. Read a meta object. Given a string with the object info.,
  6233. create the object and add it to the database.
  6234. Arguments:
  6235. Read - Place to return the created object.
  6236. Path - Object path
  6237. Return Value:
  6238. DWORD - ERROR_SUCCESS
  6239. ERROR_NOT_ENOUGH_MEMORY
  6240. ERROR_ALREADY_EXISTS
  6241. Notes:
  6242. --*/
  6243. {
  6244. HRESULT hresReturn;
  6245. CMDBaseObject* pboParent;
  6246. WCHAR strName[METADATA_MAX_NAME_LEN];
  6247. FILETIME ftTime;
  6248. PFILETIME pftParentTime;
  6249. FILETIME ftParentTime;
  6250. LPTSTR strObjectName;
  6251. //
  6252. // This should never be called for the root object.
  6253. // If it is return without doing anything.
  6254. //
  6255. if(0 == wcscmp(wszPath, L"/"))
  6256. return S_OK;
  6257. //
  6258. // TODO: What to do about file time?
  6259. //
  6260. ftTime = *(UNALIGNED FILETIME *)(pFileTime);
  6261. strObjectName = (LPTSTR)wszPath; //
  6262. // It is OK to cast because we are always passing unicode
  6263. // and bUnicode is always set to TRUE when this function
  6264. // is called.
  6265. //
  6266. hresReturn = GetObjectFromPath(pboParent,
  6267. METADATA_MASTER_ROOT_HANDLE,
  6268. METADATA_PERMISSION_READ,
  6269. strObjectName,
  6270. bUnicode);
  6271. //
  6272. // This should return ERROR_PATH_NOT_FOUND and the parent object,
  6273. // with strObjectLine set to the remainder of the path,
  6274. // which should be the child name, without a preceding delimeter.
  6275. //
  6276. if (hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) {
  6277. MD_ASSERT(pboParent != NULL);
  6278. if (bUnicode) {
  6279. hresReturn = ExtractNameFromPath((LPWSTR *)&strObjectName, (LPWSTR)strName);
  6280. }
  6281. else {
  6282. hresReturn = ExtractNameFromPath((LPSTR)strObjectName, (LPSTR)strName);
  6283. }
  6284. if (SUCCEEDED(hresReturn)) {
  6285. CMDBaseObject *pboNew;
  6286. if (bUnicode) {
  6287. pboNew = new CMDBaseObject((LPWSTR)strName, NULL);
  6288. }
  6289. else {
  6290. pboNew = new CMDBaseObject((LPSTR)strName, NULL);
  6291. }
  6292. if (pboNew == NULL) {
  6293. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  6294. }
  6295. else if (!pboNew->IsValid()) {
  6296. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  6297. delete (pboNew);
  6298. }
  6299. else {
  6300. //
  6301. // InsertChildObject sets the last change time to current time.
  6302. // This isn't really a change, so save and restore time.
  6303. //
  6304. pftParentTime = pboParent->GetLastChangeTime();
  6305. ftParentTime = *pftParentTime;
  6306. hresReturn = pboParent->InsertChildObject(pboNew);
  6307. if (SUCCEEDED(hresReturn)) {
  6308. pboParent->SetLastChangeTime(&ftParentTime);
  6309. pboNew->SetLastChangeTime(&ftTime);
  6310. cboRead = pboNew;
  6311. }
  6312. else {
  6313. delete (pboNew);
  6314. }
  6315. }
  6316. }
  6317. }
  6318. else if (SUCCEEDED(hresReturn)) {
  6319. hresReturn = RETURNCODETOHRESULT(ERROR_ALREADY_EXISTS);
  6320. }
  6321. return (hresReturn);
  6322. }
  6323. HRESULT
  6324. ReadDataObject(
  6325. IN CMDBaseObject* cboAssociated,
  6326. LPVOID* a_pv,
  6327. ULONG* a_Size,
  6328. IN IIS_CRYPTO_STORAGE* pCryptoStorage,
  6329. IN BOOL bUnicode)
  6330. /*++
  6331. Routine Description:
  6332. Read a data object. Given a string with the object info.,
  6333. create the object and add it to the database.
  6334. Arguments:
  6335. Associated - The associated meta object.
  6336. Buffer - DataBuffer from config containing data.
  6337. Size buffer - Size buffer for data.
  6338. CryptoStorage - Used to decrypt secure data.
  6339. Return Value:
  6340. DWORD - ERROR_SUCCESS
  6341. ERROR_NOT_ENOUGH_MEMORY
  6342. ERROR_ALREADY_EXISTS
  6343. ERROR_INVALID_DATA
  6344. Notes:
  6345. --*/
  6346. {
  6347. HRESULT hresReturn = ERROR_SUCCESS;
  6348. METADATA_RECORD mdrData;
  6349. PFILETIME pftTime;
  6350. FILETIME ftTime;
  6351. PBYTE pbDataValue;
  6352. STACK_BUFFER( bufAlignedValue, 256 );
  6353. DWORD dwDataLength;
  6354. PIIS_CRYPTO_BLOB blob = NULL;
  6355. // Assert that these pointers are always valid.
  6356. MD_ASSERT(a_pv[iMBProperty_ID] != NULL);
  6357. MD_ASSERT(a_pv[iMBProperty_Attributes] != NULL);
  6358. MD_ASSERT(a_pv[iMBProperty_UserType] != NULL);
  6359. MD_ASSERT(a_pv[iMBProperty_Type] != NULL);
  6360. mdrData.dwMDIdentifier = *(DWORD *)(a_pv[iMBProperty_ID]);
  6361. mdrData.dwMDAttributes = *(DWORD *)(a_pv[iMBProperty_Attributes]);
  6362. mdrData.dwMDUserType = *(DWORD *)(a_pv[iMBProperty_UserType]);
  6363. mdrData.dwMDDataType = *(DWORD *)(a_pv[iMBProperty_Type]);
  6364. // Assert that catalog returns a valid type.
  6365. MD_ASSERT(mdrData.dwMDDataType < INVALID_END_METADATA );
  6366. pbDataValue = (PBYTE)a_pv[iMBProperty_Value];
  6367. dwDataLength = a_Size[iMBProperty_Value];
  6368. if (IsSecureMetadata(mdrData.dwMDIdentifier, mdrData.dwMDAttributes) &&
  6369. pCryptoStorage != NULL) {
  6370. //
  6371. // This is a secure data object, we we'll need to decrypt it
  6372. // before proceeding. Note that we must clone the blob before
  6373. // we can actually use it, as the blob data in the line buffer
  6374. // is not DWORD-aligned. (IISCryptoCloneBlobFromRawData() is
  6375. // the only IISCrypto function that can handle unaligned data.)
  6376. //
  6377. if(0 != dwDataLength)
  6378. {
  6379. // ::IISCryptoCloneBlobFromRawData cannot handle 0 length
  6380. // Hence this work around.
  6381. hresReturn = ::IISCryptoCloneBlobFromRawData(
  6382. &blob,
  6383. pbDataValue,
  6384. dwDataLength
  6385. );
  6386. if (SUCCEEDED(hresReturn)) {
  6387. DWORD dummyRegType;
  6388. MD_ASSERT(::IISCryptoIsValidBlob(blob));
  6389. hresReturn = pCryptoStorage->DecryptData(
  6390. (PVOID *)&pbDataValue,
  6391. &dwDataLength,
  6392. &dummyRegType,
  6393. blob
  6394. );
  6395. }
  6396. }
  6397. else
  6398. {
  6399. hresReturn = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  6400. }
  6401. if(FAILED(hresReturn))
  6402. {
  6403. LogEvent(g_pEventLog,
  6404. MD_WARNING_UNABLE_TO_DECRYPT,
  6405. EVENTLOG_WARNING_TYPE,
  6406. ID_CAT_CAT,
  6407. hresReturn,
  6408. (LPWSTR)(a_pv[iMBProperty_Location]),
  6409. (LPWSTR)(a_pv[iMBProperty_Name]));
  6410. }
  6411. } else {
  6412. //
  6413. // The metadata was not secure, so decryption was not required.
  6414. // Nonetheless, it must be copied to an aligned buffer...
  6415. //
  6416. if( !bufAlignedValue.Resize( dwDataLength ) )
  6417. {
  6418. hresReturn = HRESULT_FROM_WIN32( GetLastError() );
  6419. }
  6420. else
  6421. {
  6422. memcpy( bufAlignedValue.QueryPtr(), pbDataValue, dwDataLength );
  6423. pbDataValue = ( PBYTE )bufAlignedValue.QueryPtr();
  6424. }
  6425. }
  6426. if (SUCCEEDED(hresReturn)) {
  6427. mdrData.pbMDData = pbDataValue;
  6428. switch (mdrData.dwMDDataType) {
  6429. case DWORD_METADATA: {
  6430. if (dwDataLength != sizeof(DWORD)) {
  6431. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  6432. DBGINFOW((DBG_CONTEXT,
  6433. L"Error: Invalid dword length. Length %d. Property id: %d. location: %s. hr = 0x%x.\n",
  6434. dwDataLength,
  6435. mdrData.dwMDIdentifier,
  6436. (LPWSTR)a_pv[iMBProperty_Location],
  6437. hresReturn));
  6438. }
  6439. break;
  6440. }
  6441. case STRING_METADATA:
  6442. case EXPANDSZ_METADATA:
  6443. {
  6444. if ((LONG)dwDataLength < 1 ||
  6445. (!bUnicode && (pbDataValue[dwDataLength-1] != '\0')) ||
  6446. (bUnicode && *(((LPWSTR)pbDataValue) + ((dwDataLength / sizeof(WCHAR)) -1)) != (WCHAR)L'\0')) {
  6447. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  6448. DBGINFOW((DBG_CONTEXT,
  6449. L"Error: Invalid string. Length %d. Property id: %d. location: %s. hr = 0x%x.\n",
  6450. dwDataLength,
  6451. mdrData.dwMDIdentifier,
  6452. (LPWSTR)a_pv[iMBProperty_Location],
  6453. hresReturn));
  6454. }
  6455. break;
  6456. }
  6457. case BINARY_METADATA:
  6458. {
  6459. mdrData.dwMDDataLen = dwDataLength;
  6460. break;
  6461. }
  6462. case MULTISZ_METADATA:
  6463. {
  6464. if (bUnicode) {
  6465. if (dwDataLength < (2 * sizeof(WCHAR)) ||
  6466. *((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-1)) != (WCHAR)L'\0' ||
  6467. *((LPWSTR)pbDataValue + ((dwDataLength / sizeof(WCHAR))-2)) != (WCHAR)L'\0') {
  6468. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  6469. DBGINFOW((DBG_CONTEXT,
  6470. L"[ReadDataObject] Error: Invalid multisz. Length %d. Property id: %d. location: %s. hr = 0x%x.\n",
  6471. dwDataLength,
  6472. mdrData.dwMDIdentifier,
  6473. (LPWSTR)a_pv[iMBProperty_Location],
  6474. hresReturn));
  6475. }
  6476. }
  6477. else {
  6478. if (dwDataLength < 2 ||
  6479. pbDataValue[dwDataLength-1] != '\0' ||
  6480. pbDataValue[dwDataLength-2] != '\0') {
  6481. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  6482. }
  6483. }
  6484. if (SUCCEEDED(hresReturn)) {
  6485. mdrData.dwMDDataLen = dwDataLength;
  6486. }
  6487. break;
  6488. }
  6489. default: {
  6490. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_DATA);
  6491. }
  6492. }
  6493. }
  6494. if (SUCCEEDED(hresReturn)) {
  6495. //
  6496. // SetDataObject sets the last change time to current time.
  6497. // This isn't really a change, so save and restore time.
  6498. //
  6499. pftTime = cboAssociated->GetLastChangeTime();
  6500. ftTime = *pftTime;
  6501. hresReturn = cboAssociated->SetDataObject(&mdrData, bUnicode);
  6502. cboAssociated->SetLastChangeTime(&ftTime);
  6503. }
  6504. if (blob != NULL) {
  6505. ::IISCryptoFreeBlob(blob);
  6506. }
  6507. return(hresReturn);
  6508. }
  6509. HRESULT
  6510. SaveAllData(
  6511. IN BOOL bSetSaveDisallowed,
  6512. IN IIS_CRYPTO_STORAGE *pCryptoStorage,
  6513. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  6514. IN LPWSTR pwszBackupLocation,
  6515. IN LPWSTR pwszSchemaLocation,
  6516. IN METADATA_HANDLE hHandle,
  6517. IN BOOL bHaveReadSaveSemaphore,
  6518. IN BOOL bTerminating
  6519. )
  6520. /*
  6521. ++
  6522. Routine Description:
  6523. Saves all meta data.
  6524. Arguments:
  6525. Return Value:
  6526. HRESULT - ERROR_SUCCESS
  6527. ERROR_NOT_ENOUGH_MEMORY
  6528. Return codes from file system
  6529. Notes:
  6530. --*/
  6531. {
  6532. HRESULT hresReturn = ERROR_SUCCESS;
  6533. HRESULT hresReturnSav = ERROR_SUCCESS;
  6534. HANDLE hTempFileHandle = INVALID_HANDLE_VALUE;
  6535. BOOL bDeleteTemp = TRUE;
  6536. DWORD dwTempLastSaveChangeNumber = 0;
  6537. BOOL bSaveNeeded = FALSE;
  6538. DWORD ulHistoryMajorVersionNumber = 0;
  6539. DWORD dwEnableHistory = 0;
  6540. DWORD dwMaxHistoryFiles = 0;
  6541. LPWSTR pwszRealFileName = NULL;
  6542. LPWSTR pwszSchemaFileName = NULL;
  6543. LPWSTR pwszTempFileName = g_wszTempFileName;
  6544. LPWSTR pwszBackupFileName = g_wszBackupFileName;
  6545. SECURITY_ATTRIBUTES saStorage;
  6546. BOOL bRenameMetabase = TRUE;
  6547. FILETIME MostRecentMetabaseFileLastWriteTimeStamp = g_MostRecentMetabaseFileLastWriteTimeStamp;
  6548. ULONG ulMostRecentMetabaseVersion = 0;
  6549. BOOL bMRLock = false;
  6550. bool bMRReadLock = false;
  6551. DWORD dwError;
  6552. //
  6553. // Figure out the schema and data file names. Note that pwszBackupLocation
  6554. // and pwszSchemaLocation are passed in during backup restore only.
  6555. //
  6556. if( !pwszBackupLocation )
  6557. {
  6558. pwszRealFileName = g_wszRealFileName;
  6559. }
  6560. else
  6561. {
  6562. pwszRealFileName = pwszBackupLocation;
  6563. }
  6564. if( !pwszSchemaLocation )
  6565. {
  6566. pwszSchemaFileName = g_wszSchemaFileName;
  6567. }
  6568. else
  6569. {
  6570. pwszSchemaFileName = pwszSchemaLocation;
  6571. }
  6572. //
  6573. // If ReadSaveSemaphore hasnt been already taken, then take it.
  6574. //
  6575. if (!bHaveReadSaveSemaphore)
  6576. {
  6577. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  6578. }
  6579. if(g_bSaveDisallowed)
  6580. {
  6581. goto exit;
  6582. }
  6583. g_bSaveDisallowed = bSetSaveDisallowed;
  6584. //
  6585. // Write to a temp file first in case there are errors.
  6586. // Create the temp file
  6587. //
  6588. if (g_psdStorage != NULL)
  6589. {
  6590. saStorage.nLength = sizeof(SECURITY_ATTRIBUTES);
  6591. saStorage.lpSecurityDescriptor = g_psdStorage;
  6592. saStorage.bInheritHandle = FALSE;
  6593. }
  6594. hTempFileHandle = CreateFileW(pwszTempFileName,
  6595. GENERIC_READ | GENERIC_WRITE,
  6596. 0,
  6597. &saStorage,
  6598. OPEN_ALWAYS,
  6599. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  6600. 0);
  6601. if (hTempFileHandle == INVALID_HANDLE_VALUE)
  6602. {
  6603. dwError = GetLastError();
  6604. hresReturn = RETURNCODETOHRESULT(dwError);
  6605. goto exit;
  6606. }
  6607. //
  6608. // Lock the in-memory metabase (master resource) to prevent writes.
  6609. //
  6610. bMRReadLock = g_LockMasterResource.ReadOrWriteLock();
  6611. bMRLock = true;
  6612. if ((pwszBackupLocation) ||
  6613. (g_dwLastSaveChangeNumber != g_dwSystemChangeNumber))
  6614. {
  6615. //
  6616. // Only Save if changes have been made since the last save.
  6617. //
  6618. bSaveNeeded = TRUE;
  6619. hresReturn = SaveEntireTree(pCryptoStorage,
  6620. pSessionKeyBlob,
  6621. hHandle,
  6622. pwszSchemaLocation,
  6623. pwszSchemaFileName,
  6624. &saStorage,
  6625. hTempFileHandle);
  6626. //
  6627. // Must have MasterResource when accessing SystemChangeNumber
  6628. // so save it away here. Only update LastSaveChangeNumber on success.
  6629. //
  6630. dwTempLastSaveChangeNumber = g_dwSystemChangeNumber;
  6631. ulHistoryMajorVersionNumber = g_ulHistoryMajorVersionNumber;
  6632. dwEnableHistory = g_dwEnableHistory;
  6633. ValidateMaxHistoryFiles();
  6634. dwMaxHistoryFiles = g_dwMaxHistoryFiles;
  6635. DetermineIfMetabaseCanBeRenamed(pwszBackupLocation,
  6636. pwszRealFileName,
  6637. bTerminating,
  6638. &bRenameMetabase);
  6639. }
  6640. if(NULL != g_pListenerController)
  6641. {
  6642. if(g_dwEnableEditWhileRunning)
  6643. {
  6644. hresReturnSav = g_pListenerController->Start();
  6645. }
  6646. else
  6647. {
  6648. hresReturnSav = g_pListenerController->Stop(iSTATE_STOP_TEMPORARY,
  6649. NULL);
  6650. }
  6651. if(SUCCEEDED(hresReturn))
  6652. {
  6653. hresReturn = hresReturnSav;
  6654. }
  6655. }
  6656. //
  6657. // Unlock the in-memory metabase once it has been saved to the temp file.
  6658. // Unlock the metabase file once the temp file has been created.
  6659. //
  6660. if(bMRLock)
  6661. {
  6662. g_LockMasterResource.ReadOrWriteUnlock(bMRReadLock);
  6663. bMRLock = false;
  6664. }
  6665. if (!CloseHandle(hTempFileHandle))
  6666. {
  6667. if(SUCCEEDED(hresReturn))
  6668. {
  6669. dwError = GetLastError();
  6670. hresReturn = RETURNCODETOHRESULT(dwError);
  6671. }
  6672. }
  6673. if(FAILED(hresReturn) || (!bSaveNeeded))
  6674. {
  6675. goto exit;
  6676. }
  6677. if(bRenameMetabase)
  6678. {
  6679. //
  6680. // Update the g_MostRecentMetabaseSaveTimeStamp value
  6681. // to the current time stamp, just before the move and rename.
  6682. // Note that if the rename is not happening, then we needn't
  6683. // update the values because a notification will not be sent.
  6684. // Also, update the g_MostRecentMetabaseFileLastWriteTimeStamp
  6685. // even if EWR is not enabled, because if EWR is disabled and
  6686. // while the server is running, you enable it, then you will
  6687. // want the last saved time stamp to determine the rename.
  6688. //
  6689. WIN32_FILE_ATTRIBUTE_DATA CurrentMetabaseTempFileAttr;
  6690. BOOL bFetchedCurrentMetabaseAttr = TRUE;
  6691. if(!GetFileAttributesExW(pwszTempFileName,
  6692. GetFileExInfoStandard,
  6693. &CurrentMetabaseTempFileAttr)
  6694. )
  6695. {
  6696. //
  6697. // Could not fetch the current file attributes for the temporary metabase file.
  6698. //
  6699. DWORD dwRes = GetLastError();
  6700. hresReturn = RETURNCODETOHRESULT(dwRes);
  6701. DBGINFOW((DBG_CONTEXT,
  6702. L"[SaveAllData] Could not fetch the current file attributes for the temporary metabase file. GetFileAttributesEx on %s failed with hr = 0x%x.\n",
  6703. pwszTempFileName,
  6704. hresReturn));
  6705. bFetchedCurrentMetabaseAttr = FALSE;
  6706. }
  6707. EnterCriticalSection(&g_csEditWhileRunning);
  6708. MostRecentMetabaseFileLastWriteTimeStamp = g_MostRecentMetabaseFileLastWriteTimeStamp;
  6709. ulMostRecentMetabaseVersion = g_ulMostRecentMetabaseVersion;
  6710. g_ulMostRecentMetabaseVersion = ulHistoryMajorVersionNumber;
  6711. g_bSavingMetabaseFileToDisk = TRUE;
  6712. if(bFetchedCurrentMetabaseAttr)
  6713. {
  6714. g_MostRecentMetabaseFileLastWriteTimeStamp = CurrentMetabaseTempFileAttr.ftLastWriteTime;
  6715. }
  6716. else
  6717. {
  6718. // Unable to fetch the time stamp - hence reset g_MostRecentMetabaseFileLastWriteTimeStamp
  6719. // to zeroes. This will force the next SaveAllData to rename - else we may land up in a
  6720. // condition where we never rename, because the comparisons will always fail (because
  6721. // the timestamp on the file would have changed and the
  6722. // g_MostRecentMetabaseFileLastWriteTimeStamp will have a stale value)
  6723. //
  6724. memset((LPVOID)&g_MostRecentMetabaseFileLastWriteTimeStamp, 0, sizeof(FILETIME));
  6725. }
  6726. LeaveCriticalSection(&g_csEditWhileRunning);
  6727. }
  6728. hresReturn = SaveMetabaseFile(pwszSchemaFileName,
  6729. ulHistoryMajorVersionNumber,
  6730. dwEnableHistory,
  6731. dwMaxHistoryFiles,
  6732. dwTempLastSaveChangeNumber,
  6733. bRenameMetabase,
  6734. pwszTempFileName,
  6735. pwszRealFileName,
  6736. pwszBackupFileName,
  6737. pwszBackupLocation,
  6738. &bDeleteTemp);
  6739. if (FAILED(hresReturn))
  6740. {
  6741. if(bRenameMetabase)
  6742. {
  6743. //
  6744. // The previous time stamp would have been updated to
  6745. // the current tempfile timestamp just before the move
  6746. // is attempted. If the move of the temp file to the
  6747. // real file fails, then we must reset this time stamp.
  6748. //
  6749. EnterCriticalSection(&g_csEditWhileRunning);
  6750. g_MostRecentMetabaseFileLastWriteTimeStamp = MostRecentMetabaseFileLastWriteTimeStamp;
  6751. g_ulMostRecentMetabaseVersion = ulMostRecentMetabaseVersion;
  6752. LeaveCriticalSection(&g_csEditWhileRunning);
  6753. }
  6754. goto exit;
  6755. }
  6756. else
  6757. {
  6758. //
  6759. // Update Change Number
  6760. // Must have ReadSaveSemaphore when accessing this.
  6761. // Note that we are updating the change number only if
  6762. // we have renamed the metabase. If we have not renamed the
  6763. // metabase, then we not not update the last save change number.
  6764. // This will force another save attempt when the next SaveAllData
  6765. // is called, therby ensuring that at some point the metabase
  6766. // file will get updated.
  6767. //
  6768. if(bRenameMetabase)
  6769. {
  6770. g_dwLastSaveChangeNumber = dwTempLastSaveChangeNumber;
  6771. }
  6772. }
  6773. exit:
  6774. if(bMRLock)
  6775. {
  6776. g_LockMasterResource.ReadOrWriteUnlock(bMRReadLock);
  6777. bMRLock = false;
  6778. }
  6779. if(bTerminating)
  6780. {
  6781. //
  6782. // Unlock the metabase if terminating - irrespective of failure.
  6783. //
  6784. hresReturnSav = S_OK;
  6785. hresReturnSav = UnlockMetabaseFile(eMetabaseDataFile,
  6786. TRUE);
  6787. DBGINFOW((DBG_CONTEXT,
  6788. L"[SaveAllData] Unlocking metabase file %s returned 0x%x.\n",
  6789. pwszRealFileName,
  6790. hresReturnSav));
  6791. if(SUCCEEDED(hresReturnSav))
  6792. {
  6793. hresReturnSav = UnlockMetabaseFile(eMetabaseSchemaFile,
  6794. TRUE);
  6795. DBGINFOW((DBG_CONTEXT,
  6796. L"[SaveAllData] Unlocking metabase file %s returned 0x%x.\n",
  6797. pwszSchemaFileName,
  6798. hresReturnSav));
  6799. }
  6800. if(SUCCEEDED(hresReturn))
  6801. {
  6802. hresReturn = hresReturnSav;
  6803. }
  6804. }
  6805. if (bDeleteTemp && (hTempFileHandle != INVALID_HANDLE_VALUE))
  6806. {
  6807. DeleteFileW(pwszTempFileName);
  6808. hTempFileHandle = INVALID_HANDLE_VALUE;
  6809. }
  6810. if (!bHaveReadSaveSemaphore)
  6811. {
  6812. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  6813. }
  6814. if ( FAILED( hresReturn ))
  6815. {
  6816. LogEvent(g_pEventLog,
  6817. MD_ERROR_UNABLE_TOSAVE_METABASE,
  6818. EVENTLOG_ERROR_TYPE,
  6819. ID_CAT_CAT,
  6820. hresReturn);
  6821. DBGPRINTF(( DBG_CONTEXT, "Failed to flush metabase - error 0x%08lx\n", hresReturn));
  6822. }
  6823. return hresReturn;
  6824. } // SaveAllData
  6825. HRESULT
  6826. SaveEntireTree(IN IIS_CRYPTO_STORAGE* pCryptoStorage,
  6827. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  6828. IN METADATA_HANDLE hHandle,
  6829. IN LPWSTR pwszSchemaLocation,
  6830. IN LPWSTR pwszSchemaFileName,
  6831. IN PSECURITY_ATTRIBUTES psaStorage,
  6832. IN HANDLE hTempFileHandle)
  6833. /*
  6834. ++
  6835. Routine Description:
  6836. Saves the metabase tree to disk.
  6837. Arguments:
  6838. [in] Crypto object for encryption/decryption.
  6839. [in] Session key blob.
  6840. [in] Handle to in-memory metabase.
  6841. [in] Schema location (used only for backup/restore)
  6842. [in] Schema file name.
  6843. [in] Security Attributes to set on the file.
  6844. [in] File handle of the temp file.
  6845. Return Value:
  6846. HRESULT - ERROR_SUCCESS
  6847. ERROR_NOT_ENOUGH_MEMORY
  6848. Return codes from file system
  6849. Notes:
  6850. --*/
  6851. {
  6852. HRESULT hresReturn = S_OK;
  6853. HRESULT hresReturnSav = S_OK;
  6854. BUFFER* pbufParentPath = NULL;
  6855. PBASEOBJECT_CONTAINER objChildObjectContainer = NULL;
  6856. CWriter* pCWriter = NULL;
  6857. ULONG cChildObjects = 0;
  6858. ULONG iChildObjects = 0;
  6859. PBASEOBJECT_CONTAINER arrFixedChildObjects[MD_MAX_CHILD_OBJECTS];
  6860. PBASEOBJECT_CONTAINER* arrChildObject = arrFixedChildObjects;
  6861. if (hHandle != METADATA_MASTER_ROOT_HANDLE)
  6862. {
  6863. CMDHandle *phoHandle;
  6864. phoHandle = GetHandleObject(hHandle);
  6865. if ((phoHandle == NULL) ||
  6866. (phoHandle->GetObject() != g_pboMasterRoot))
  6867. {
  6868. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
  6869. }
  6870. else if ((!phoHandle->IsReadAllowed()) &&
  6871. (!phoHandle->IsWriteAllowed()))
  6872. {
  6873. hresReturn = RETURNCODETOHRESULT(ERROR_ACCESS_DENIED);
  6874. }
  6875. }
  6876. if(FAILED(hresReturn))
  6877. {
  6878. goto exit;
  6879. }
  6880. pbufParentPath = new BUFFER(4);
  6881. if( pbufParentPath == NULL )
  6882. {
  6883. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  6884. goto exit;
  6885. }
  6886. *(LPWSTR)pbufParentPath->QueryPtr() = MD_PATH_DELIMETERW;
  6887. ((LPWSTR)pbufParentPath->QueryPtr())[1] = (WCHAR)L'\0';
  6888. //
  6889. // TODO: Need to add the following:
  6890. // MD_ID_MAJOR_VERSION_NUMBER
  6891. // MD_ID_MINOR_VERSION_NUMBER
  6892. //
  6893. if( pwszSchemaLocation )
  6894. {
  6895. //
  6896. // Bump up g_dwSchemaChangeNumber to force save MBSchema.XML
  6897. // This (pszSchemaLocation being non-null) is in
  6898. // the case of Restore.
  6899. //
  6900. g_dwSchemaChangeNumber++;
  6901. }
  6902. //
  6903. // Unlock the schema file before compile
  6904. //
  6905. if(NULL == pwszSchemaLocation)
  6906. {
  6907. hresReturn = UnlockMetabaseFile(eMetabaseSchemaFile,
  6908. TRUE);
  6909. DBGINFOW((DBG_CONTEXT,
  6910. L"[SaveAllData] Unlocking metabase file %s returned 0x%x.\n",
  6911. pwszSchemaFileName,
  6912. hresReturn));
  6913. if(FAILED(hresReturn))
  6914. {
  6915. goto exit;
  6916. }
  6917. }
  6918. hresReturn = SaveSchemaIfNeeded(pwszSchemaFileName,
  6919. psaStorage);
  6920. //
  6921. // Lock the metabase file even if compile has failed or even if EWR is
  6922. // enabled - we do not allow users to edit the schema file.
  6923. //
  6924. if(NULL == pwszSchemaLocation)
  6925. {
  6926. hresReturnSav = LockMetabaseFile(pwszSchemaFileName,
  6927. eMetabaseSchemaFile,
  6928. TRUE);
  6929. DBGINFOW((DBG_CONTEXT,
  6930. L"[SaveAllData] Locking metabase file %s returned 0x%x.\n",
  6931. pwszSchemaFileName,
  6932. hresReturnSav));
  6933. if(FAILED(hresReturnSav) && SUCCEEDED(hresReturn))
  6934. {
  6935. hresReturn = hresReturnSav;
  6936. }
  6937. }
  6938. if(FAILED(hresReturn))
  6939. {
  6940. goto exit;
  6941. }
  6942. // Assert g_pGlobalISTHelper is valid.
  6943. MD_ASSERT( g_pGlobalISTHelper != NULL);
  6944. DBGINFOW((DBG_CONTEXT,
  6945. L"[SaveAllData] Initializing writer with write file: %s bin file: %s.\n",
  6946. g_wszTempFileName,
  6947. g_pGlobalISTHelper->m_wszBinFileForMeta));
  6948. pCWriter = new CWriter();
  6949. if(NULL == pCWriter)
  6950. {
  6951. hresReturn = E_OUTOFMEMORY;
  6952. goto exit;
  6953. }
  6954. hresReturn = pCWriter->Initialize(g_wszTempFileName,
  6955. g_pGlobalISTHelper,
  6956. hTempFileHandle);
  6957. if(FAILED(hresReturn))
  6958. {
  6959. goto exit;
  6960. }
  6961. hresReturn = pCWriter->BeginWrite(eWriter_Metabase);
  6962. if(FAILED(hresReturn))
  6963. {
  6964. goto exit;
  6965. }
  6966. //
  6967. // Save the global location first
  6968. //
  6969. hresReturn = SaveGlobalsToXML(pCWriter,
  6970. pSessionKeyBlob);
  6971. if(FAILED(hresReturn))
  6972. {
  6973. goto exit;
  6974. }
  6975. //
  6976. // Save the master root.
  6977. //
  6978. hresReturn = SaveMasterRoot(pCWriter,
  6979. pCryptoStorage,
  6980. pSessionKeyBlob);
  6981. if(FAILED(hresReturn))
  6982. {
  6983. goto exit;
  6984. }
  6985. //
  6986. // Enumerate all the subnodes and write all the sub-nodes, in a sorted manner.
  6987. //
  6988. //
  6989. // First pass, count the number of child objects
  6990. //
  6991. for(objChildObjectContainer=g_pboMasterRoot->NextChildObject(NULL);
  6992. (SUCCEEDED(hresReturn)) && (objChildObjectContainer!=NULL);
  6993. objChildObjectContainer=g_pboMasterRoot->NextChildObject(objChildObjectContainer)) {
  6994. cChildObjects++;
  6995. }
  6996. if(FAILED(hresReturn))
  6997. {
  6998. goto exit;
  6999. }
  7000. //
  7001. // Allocate memory if greater than whats allocated on the stack.
  7002. //
  7003. if(cChildObjects > MD_MAX_CHILD_OBJECTS)
  7004. {
  7005. arrChildObject = new PBASEOBJECT_CONTAINER[cChildObjects];
  7006. if(NULL == arrChildObject)
  7007. {
  7008. hresReturn = E_OUTOFMEMORY;
  7009. goto exit;
  7010. }
  7011. }
  7012. //
  7013. // Make another pass and populate the array
  7014. //
  7015. for(objChildObjectContainer=g_pboMasterRoot->NextChildObject(NULL),iChildObjects=0;
  7016. (SUCCEEDED(hresReturn)) && (objChildObjectContainer!=NULL);
  7017. objChildObjectContainer=g_pboMasterRoot->NextChildObject(objChildObjectContainer),iChildObjects++) {
  7018. arrChildObject[iChildObjects] = objChildObjectContainer;
  7019. }
  7020. if(FAILED(hresReturn))
  7021. {
  7022. goto exit;
  7023. }
  7024. //
  7025. // Sort the array
  7026. //
  7027. qsort((void*)arrChildObject, cChildObjects, sizeof(PBASEOBJECT_CONTAINER), MyComparePBaseObjectContainer);
  7028. //
  7029. // Enumerate the sorted array of child objects and call SaveTree on each of them
  7030. //
  7031. for(iChildObjects=0;
  7032. (SUCCEEDED(hresReturn)) && (iChildObjects<cChildObjects);
  7033. iChildObjects++) {
  7034. BOOL bLocalMachine = FALSE;
  7035. if(0 == _wcsnicmp((LPWSTR)((arrChildObject[iChildObjects])->pboMetaObject->GetName(TRUE)), g_wszSchema, g_cchSchema))
  7036. {
  7037. //
  7038. // No need to save the schema tree in data file.
  7039. //
  7040. #ifndef _SAVE_SCHEMA_TREE_IN_DATA_FILE_
  7041. continue;
  7042. #endif _SAVE_SCHEMA_TREE_IN_DATA_FILE_
  7043. }
  7044. else if(0 == _wcsnicmp((LPWSTR)((arrChildObject[iChildObjects])->pboMetaObject->GetName(TRUE)), g_wszLM, g_cchLM))
  7045. {
  7046. bLocalMachine = TRUE;
  7047. }
  7048. hresReturn = SaveTree(pCWriter,
  7049. (arrChildObject[iChildObjects])->pboMetaObject,
  7050. pbufParentPath,
  7051. pCryptoStorage,
  7052. pSessionKeyBlob,
  7053. TRUE,
  7054. TRUE,
  7055. bLocalMachine);
  7056. }
  7057. if(FAILED(hresReturn))
  7058. {
  7059. goto exit;
  7060. }
  7061. hresReturn = pCWriter->EndWrite(eWriter_Metabase);
  7062. if(FAILED(hresReturn))
  7063. {
  7064. goto exit;
  7065. }
  7066. exit:
  7067. if(NULL != pCWriter)
  7068. {
  7069. delete pCWriter;
  7070. pCWriter = NULL;
  7071. }
  7072. if ( pbufParentPath != NULL )
  7073. {
  7074. pbufParentPath->FreeMemory();
  7075. delete(pbufParentPath);
  7076. }
  7077. if((NULL != arrChildObject) && (arrChildObject != arrFixedChildObjects) )
  7078. {
  7079. delete [] arrChildObject;
  7080. arrChildObject = NULL;
  7081. }
  7082. return hresReturn;
  7083. } // SaveEntireTree
  7084. HRESULT
  7085. SaveMetabaseFile(IN LPWSTR pwszSchemaFileName,
  7086. IN ULONG ulHistoryMajorVersionNumber,
  7087. IN DWORD dwEnableHistory,
  7088. IN DWORD dwMaxHistoryFiles,
  7089. IN DWORD ,
  7090. IN BOOL bRenameMetabase,
  7091. IN LPWSTR pwszTempFileName,
  7092. IN LPWSTR pwszRealFileName,
  7093. IN LPWSTR pwszBackupFileName,
  7094. IN LPWSTR pwszBackupLocation,
  7095. OUT BOOL* pbDeleteTemp)
  7096. /*
  7097. ++
  7098. Routine Description:
  7099. Creates the history file and moves the temp file to the
  7100. real xml file.
  7101. Arguments:
  7102. [in] Schema file name.
  7103. [in] History major version number.
  7104. [in] Enable history.
  7105. [in] Max history files.
  7106. [in] Last save change number.
  7107. [in] Bool to indicate rename temp file to xml file or not.
  7108. [in] Temp file name.
  7109. [in] Real file name.
  7110. [in] Schema file name.
  7111. [in] Backup file name.
  7112. [in] Backup location.
  7113. [out] Bool to indicate delete temp or not.
  7114. Return Value:
  7115. HRESULT - ERROR_SUCCESS
  7116. ERROR_NOT_ENOUGH_MEMORY
  7117. Return codes from file system
  7118. Notes:
  7119. --*/
  7120. {
  7121. HRESULT hresReturn = S_OK;
  7122. DWORD dwTemp = 0;
  7123. BOOL bUnlocked = FALSE;
  7124. //
  7125. // Save the temp file in the history directory.
  7126. // If we are unable to create a history, then we
  7127. // will not be able to diff if someone makes changes.
  7128. // Hence we will have to error at the time of diffing.
  7129. //
  7130. DBGINFOW((DBG_CONTEXT,
  7131. L"[SaveAllData] HistoryMajorVersionNumber: %d.\n", g_ulHistoryMajorVersionNumber));
  7132. DBGINFOW((DBG_CONTEXT,
  7133. L"[SaveAllData] HistoryMajorVersionNumber: %d.\n", ulHistoryMajorVersionNumber));
  7134. //
  7135. // We want to create history files only if we are saving to the actual
  7136. // metabase.xml (and not to a backup file)
  7137. //
  7138. if(dwEnableHistory && NULL == pwszBackupLocation)
  7139. {
  7140. CreateHistoryFiles(g_wszTempFileName,
  7141. pwszSchemaFileName,
  7142. ulHistoryMajorVersionNumber,
  7143. dwMaxHistoryFiles);
  7144. }
  7145. //
  7146. // New data file created successfully
  7147. // Backup real file and copy temp
  7148. // to real
  7149. //
  7150. if(g_dwEnableEditWhileRunning && (!bRenameMetabase))
  7151. {
  7152. DBGINFOW((DBG_CONTEXT,
  7153. L"[SaveAllData] Edit while running is enabled and a user has edited the file and the edit hasn't been processed. Meanwhile SaveAllData has been called. Hence SaveAllData is not renaming the file, so that the user edits are not overwrittem.\n"));
  7154. goto exit;
  7155. }
  7156. //
  7157. // Unlock the metabase file just before the rename and if is not called from
  7158. // backup.
  7159. //
  7160. if(NULL == pwszBackupLocation)
  7161. {
  7162. hresReturn = UnlockMetabaseFile(eMetabaseDataFile,
  7163. TRUE);
  7164. DBGINFOW((DBG_CONTEXT,
  7165. L"[SaveMetabaseFile] Unlocking metabase file %s returned 0x%x.\n",
  7166. pwszRealFileName,
  7167. hresReturn));
  7168. if(FAILED(hresReturn))
  7169. {
  7170. goto exit;
  7171. }
  7172. bUnlocked = TRUE;
  7173. }
  7174. //
  7175. // Rename the temp file to the real file
  7176. //
  7177. if (!MoveFileW(pwszTempFileName, pwszRealFileName))
  7178. {
  7179. if (GetLastError() != ERROR_ALREADY_EXISTS)
  7180. {
  7181. dwTemp = GetLastError();
  7182. hresReturn = RETURNCODETOHRESULT(dwTemp);
  7183. goto exit;
  7184. }
  7185. //
  7186. // Real File exists, so back it up
  7187. //
  7188. //
  7189. // Bug #260590 If someone had attrib-ed the real file to
  7190. // be read-only then we could land up in a state where the
  7191. // backup file is read-only. Hence attrib the real file to
  7192. // be read-write and then move it to the backup file.
  7193. //
  7194. ResetFileAttributesIfNeeded((LPTSTR)pwszRealFileName,
  7195. TRUE);
  7196. if (!MoveFileW(pwszRealFileName, pwszBackupFileName))
  7197. {
  7198. //
  7199. // backup failed, check for old backup file
  7200. //
  7201. if (GetLastError() != ERROR_ALREADY_EXISTS)
  7202. {
  7203. dwTemp = GetLastError();
  7204. hresReturn = RETURNCODETOHRESULT(dwTemp);
  7205. goto exit;
  7206. }
  7207. else if (!DeleteFileW(pwszBackupFileName))
  7208. {
  7209. dwTemp = GetLastError();
  7210. hresReturn = RETURNCODETOHRESULT(dwTemp);
  7211. goto exit;
  7212. }
  7213. else if (!MoveFileW(pwszRealFileName, pwszBackupFileName))
  7214. {
  7215. dwTemp = GetLastError();
  7216. hresReturn = RETURNCODETOHRESULT(dwTemp);
  7217. goto exit;
  7218. }
  7219. }
  7220. //
  7221. // Real file is backed up
  7222. // so move in new file
  7223. //
  7224. if (!MoveFileW(pwszTempFileName, pwszRealFileName))
  7225. {
  7226. dwTemp = GetLastError();
  7227. hresReturn = RETURNCODETOHRESULT(dwTemp);
  7228. //
  7229. // Moved real to backup but
  7230. // failed to move temp to real
  7231. // so restore from backup
  7232. //
  7233. if (!MoveFileW(pwszBackupFileName, pwszRealFileName))
  7234. {
  7235. //
  7236. // Unable to write new file
  7237. // or restore original file so don't delete backup
  7238. //
  7239. goto exit;
  7240. }
  7241. }
  7242. DeleteFileW(pwszBackupFileName);
  7243. }
  7244. exit:
  7245. //
  7246. // Lock the metabase file if edit while running is disabled and if it is
  7247. // not called from backup and if it was unlocked above.
  7248. //
  7249. if((NULL == pwszBackupLocation) && (!g_dwEnableEditWhileRunning) && (bUnlocked))
  7250. {
  7251. HRESULT hresReturnSav = S_OK;
  7252. hresReturnSav = LockMetabaseFile(pwszRealFileName,
  7253. eMetabaseDataFile,
  7254. TRUE);
  7255. DBGINFOW((DBG_CONTEXT,
  7256. L"[SaveMetabaseFile] Locking metabase file %s returned 0x%x.\n",
  7257. pwszRealFileName,
  7258. hresReturn));
  7259. if(SUCCEEDED(hresReturn))
  7260. {
  7261. hresReturn = hresReturnSav;
  7262. }
  7263. }
  7264. if (FAILED(hresReturn))
  7265. {
  7266. //
  7267. // temp file was created ok but a problem
  7268. // occurred while moving it to real
  7269. // so don't delete it
  7270. //
  7271. *pbDeleteTemp = FALSE;
  7272. }
  7273. return hresReturn;
  7274. }
  7275. void
  7276. DetermineIfMetabaseCanBeRenamed(LPWSTR pwszBackupLocation,
  7277. LPWSTR pwszRealFileName,
  7278. BOOL bTerminating,
  7279. BOOL* pbRenameMetabase)
  7280. /*
  7281. ++
  7282. Routine Description:
  7283. Helper function to determine if the metabase can be renamed.
  7284. It compares the current filetime with that of the last save
  7285. and if not equal it tries to match it with the last processed
  7286. edit while running timestamp.
  7287. Arguments:
  7288. [in] Real file name.
  7289. [in] Metabase file.
  7290. [in] Bool to indicate terminating or not.
  7291. [out] Bool to indicate rename or not.
  7292. Return Value:
  7293. HRESULT
  7294. Notes:
  7295. --*/
  7296. {
  7297. //
  7298. // This function assumes that the g_masterResourceLock has been taken
  7299. //
  7300. HRESULT hr = S_OK;
  7301. WIN32_FILE_ATTRIBUTE_DATA CurrentAttr;
  7302. static FILETIME ZeroedTimeStamp;
  7303. FILETIME MostRecentMetabaseFileLastWriteTimeStamp;
  7304. FILETIME EWRProcessedMetabaseTimeStamp;
  7305. memset((LPVOID)&ZeroedTimeStamp, 0, sizeof(FILETIME));
  7306. EnterCriticalSection(&g_csEditWhileRunning);
  7307. MostRecentMetabaseFileLastWriteTimeStamp = g_MostRecentMetabaseFileLastWriteTimeStamp;
  7308. EWRProcessedMetabaseTimeStamp = g_EWRProcessedMetabaseTimeStamp;
  7309. LeaveCriticalSection(&g_csEditWhileRunning);
  7310. if(!g_dwEnableEditWhileRunning)
  7311. {
  7312. *pbRenameMetabase = TRUE;
  7313. return;
  7314. }
  7315. else if(NULL != pwszBackupLocation)
  7316. {
  7317. // Always rename for backup
  7318. *pbRenameMetabase = TRUE;
  7319. return;
  7320. }
  7321. else if(0 == memcmp(&MostRecentMetabaseFileLastWriteTimeStamp, &ZeroedTimeStamp, sizeof(FILETIME)))
  7322. {
  7323. //
  7324. // This means that we were unable to initialize g_MostRecentMetabaseFileLastWriteTimeStamp
  7325. // (this can happen when the metabase file is missing on startup, or, when we are unable to
  7326. // fetch the last write timestamp)
  7327. //
  7328. *pbRenameMetabase = TRUE;
  7329. return;
  7330. }
  7331. else
  7332. {
  7333. *pbRenameMetabase = FALSE;
  7334. if(!GetFileAttributesExW(pwszRealFileName,
  7335. GetFileExInfoStandard,
  7336. &CurrentAttr)
  7337. )
  7338. {
  7339. //
  7340. // Could not fetch the current file attributes for the metabase file.
  7341. // Assume that it cannot be renamed.
  7342. //
  7343. DWORD dwRes = GetLastError();
  7344. hr = RETURNCODETOHRESULT(dwRes);
  7345. DBGINFOW((DBG_CONTEXT,
  7346. L"[DetermineIfMetabaseCanBeRenamed] Coud not fetch file attributes of the metabase file. GetFileAttributesEx on %s failed with hr = 0x%x.\n",
  7347. pwszRealFileName,
  7348. hr));
  7349. if( (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) ||
  7350. (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
  7351. )
  7352. {
  7353. //
  7354. // Perhaps someone deleted the file - ok to rename.
  7355. //
  7356. *pbRenameMetabase = TRUE;
  7357. }
  7358. else
  7359. {
  7360. //
  7361. // Do not rename for this SaveAllData
  7362. // Reset g_MostRecentMetabaseFileLastWriteTimeStamp so that the next SaveAllData will
  7363. // rename - else we may land up in a condition where we never rename.
  7364. //
  7365. EnterCriticalSection(&g_csEditWhileRunning);
  7366. memset((LPVOID)&g_MostRecentMetabaseFileLastWriteTimeStamp, 0, sizeof(FILETIME));
  7367. LeaveCriticalSection(&g_csEditWhileRunning);
  7368. }
  7369. return;
  7370. }
  7371. DBGINFO((DBG_CONTEXT,
  7372. "[DetermineIfMetabaseCanBeRenamed] CURRENT TIMESTAMPS:\nMetabaseFileLastWrite low: %d\nMetabaseFileLastWrite high: %d\n",
  7373. CurrentAttr.ftLastWriteTime.dwLowDateTime,
  7374. CurrentAttr.ftLastWriteTime.dwHighDateTime));
  7375. DBGINFO((DBG_CONTEXT,
  7376. "[DetermineIfMetabaseCanBeRenamed] LAST SAVE TIMESTAMPS:\nMetabaseFileLastWrite low: %d\nMetabaseFileLastWrite high: %d\n",
  7377. MostRecentMetabaseFileLastWriteTimeStamp.dwLowDateTime,
  7378. MostRecentMetabaseFileLastWriteTimeStamp.dwHighDateTime));
  7379. DBGINFO((DBG_CONTEXT,
  7380. "[DetermineIfMetabaseCanBeRenamed] LAST EWR PROCESSED TIMESTAMPS:\nMetabaseFileLastWrite low: %d\nMetabaseFileLastWrite high: %d\n",
  7381. EWRProcessedMetabaseTimeStamp.dwLowDateTime,
  7382. EWRProcessedMetabaseTimeStamp.dwHighDateTime));
  7383. if(0 == CompareFileTime(&(CurrentAttr.ftLastWriteTime), &MostRecentMetabaseFileLastWriteTimeStamp))
  7384. {
  7385. *pbRenameMetabase = TRUE;
  7386. return;
  7387. }
  7388. else if(0 == CompareFileTime(&(CurrentAttr.ftLastWriteTime), &EWRProcessedMetabaseTimeStamp))
  7389. {
  7390. *pbRenameMetabase = TRUE;
  7391. return;
  7392. }
  7393. else if(0 == memcmp(&EWRProcessedMetabaseTimeStamp, &ZeroedTimeStamp, sizeof(FILETIME)))
  7394. {
  7395. //
  7396. // This means that we were unable to initialize g_EWRProcessedMetabaseTimeStamp
  7397. // (this can happen when the EWR thread fails to get the file attribute or when it
  7398. // shutsdown.
  7399. //
  7400. *pbRenameMetabase = TRUE;
  7401. return;
  7402. }
  7403. else if(bTerminating)
  7404. {
  7405. //
  7406. // We always want to rename while terminating so that the metabase file reflects what was in memory.
  7407. //
  7408. DBGINFO((DBG_CONTEXT,
  7409. "[DetermineIfMetabaseCanBeRenamed] Metabase timestamp did not match last saved or last EWR processed timestamp. Renaming anyway.\n"));
  7410. *pbRenameMetabase = TRUE;
  7411. return;
  7412. }
  7413. else
  7414. {
  7415. //
  7416. // This means that the metabase timestamp was different from the last metabase save
  7417. // and the last edit while running processed timestamp. We will not do the rename
  7418. // this time around, but however we will reset the g_EWRProcessedMetabaseTimeStamp
  7419. // so that the next time around, we will be forced to rename. This is because we do not always
  7420. // want to always rely on filetimestamp comparison (which is known to return cached values).
  7421. //
  7422. EnterCriticalSection(&g_csEditWhileRunning);
  7423. memset((LPVOID)&g_EWRProcessedMetabaseTimeStamp, 0, sizeof(FILETIME));
  7424. LeaveCriticalSection(&g_csEditWhileRunning);
  7425. }
  7426. }
  7427. return;
  7428. } // DetermineIfMetabaseCanBeRenamed
  7429. HRESULT
  7430. SaveMasterRoot(CWriter* pCWriter,
  7431. IIS_CRYPTO_STORAGE* pCryptoStorage,
  7432. PIIS_CRYPTO_BLOB pSessionKeyBlob
  7433. )
  7434. /*++
  7435. Routine Description:
  7436. Save the master root object, including its data objects.
  7437. Arguments:
  7438. CryptoStorage - Used to encrypt secure data.
  7439. Return Value:
  7440. DWORD - ERROR_SUCCESS
  7441. Return codes from file system
  7442. Notes:
  7443. --*/
  7444. {
  7445. HRESULT hresReturn = ERROR_SUCCESS;
  7446. CMDBaseData* dataAssociatedData = NULL;
  7447. DWORD dwEnumObjectIndex;
  7448. PFILETIME pftTime;
  7449. LPWSTR wszKeyType = NULL;
  7450. CLocationWriter* pCLocationWriter = NULL;
  7451. LPWSTR wszRootLocation = L"/";
  7452. DWORD dwAttributes = 0;
  7453. DWORD dwUserType = 0;
  7454. DWORD dwDataType = 0;
  7455. ULONG cbData = 0;
  7456. //
  7457. // TODO: What to do about change time at node level?
  7458. //
  7459. pftTime = g_pboMasterRoot->GetLastChangeTime();
  7460. //
  7461. // Fetch the Location writer.
  7462. //
  7463. hresReturn = pCWriter->GetLocationWriter(&pCLocationWriter,
  7464. wszRootLocation);
  7465. if(FAILED(hresReturn))
  7466. {
  7467. goto exit;
  7468. }
  7469. //
  7470. // Figure out the KeyType of this node.
  7471. //
  7472. for(dwEnumObjectIndex=0,dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
  7473. (SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
  7474. dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
  7475. if(MD_KEY_TYPE == dataAssociatedData->GetIdentifier())
  7476. {
  7477. wszKeyType = (LPWSTR)dataAssociatedData->GetData(TRUE);
  7478. dwAttributes = dataAssociatedData->GetAttributes();
  7479. dwUserType = dataAssociatedData->GetUserType();
  7480. dwDataType = dataAssociatedData->GetDataType();
  7481. cbData = dataAssociatedData->GetDataLen(TRUE);
  7482. break;
  7483. }
  7484. }
  7485. //
  7486. // Initialize the keytype at this node
  7487. //
  7488. hresReturn = pCLocationWriter->InitializeKeyType(MD_KEY_TYPE,
  7489. dwAttributes,
  7490. dwUserType,
  7491. dwDataType,
  7492. (PBYTE)wszKeyType,
  7493. cbData);
  7494. if(FAILED(hresReturn))
  7495. {
  7496. goto exit;
  7497. }
  7498. //
  7499. // Save all the properties at this node
  7500. //
  7501. for(dwEnumObjectIndex=0,dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
  7502. (SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
  7503. dataAssociatedData=g_pboMasterRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
  7504. hresReturn = SaveDataObject(dataAssociatedData,
  7505. pCLocationWriter,
  7506. pCryptoStorage,
  7507. pSessionKeyBlob);
  7508. }
  7509. if(FAILED(hresReturn))
  7510. {
  7511. goto exit;
  7512. }
  7513. //
  7514. // Write the node.
  7515. //
  7516. hresReturn = pCLocationWriter->WriteLocation(TRUE);
  7517. if(FAILED(hresReturn))
  7518. {
  7519. goto exit;
  7520. }
  7521. exit:
  7522. if(NULL != pCLocationWriter)
  7523. {
  7524. delete pCLocationWriter;
  7525. pCLocationWriter = NULL;
  7526. }
  7527. return(hresReturn);
  7528. }
  7529. void SaveGlobalsFromLM(CMDBaseData* pbSave)
  7530. {
  7531. if(pbSave->GetDataType() == DWORD_METADATA)
  7532. {
  7533. switch(pbSave->GetIdentifier())
  7534. {
  7535. case MD_ROOT_ENABLE_HISTORY:
  7536. g_dwEnableHistory = *(DWORD*)pbSave->GetData(TRUE);
  7537. break;
  7538. case MD_ROOT_MAX_HISTORY_FILES:
  7539. g_dwMaxHistoryFiles = *(DWORD*)pbSave->GetData(TRUE);
  7540. break;
  7541. case MD_ROOT_ENABLE_EDIT_WHILE_RUNNING:
  7542. g_dwEnableEditWhileRunning = *(DWORD*)pbSave->GetData(TRUE);
  7543. break;
  7544. case MD_MAX_ERROR_FILES:
  7545. g_dwMaxErrorFiles = *(DWORD*)pbSave->GetData(TRUE);
  7546. break;
  7547. }
  7548. }
  7549. return;
  7550. }
  7551. HRESULT
  7552. SaveTree(IN CWriter* pCWriter,
  7553. IN CMDBaseObject* pboRoot,
  7554. IN BUFFER* pbufParentPath,
  7555. IN IIS_CRYPTO_STORAGE* pCryptoStorage,
  7556. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  7557. IN BOOL bRecurse, /* default = TRUE */
  7558. IN BOOL bSaveSchema, /* default = TRUE */
  7559. IN BOOL bLocalMachine /* default = FALSE */)
  7560. /*++
  7561. Routine Description:
  7562. Save a tree, recursively saving child objects. This works out as
  7563. a depth first save.
  7564. Arguments:
  7565. Root - The root of the tree to save.
  7566. CryptoStorage - Used to encrypt secure data.
  7567. bRecurse - Save Children as well.
  7568. bSaveSchema - If we end up at /schema node, call SaveTree on /schema.
  7569. bLocalMachine - True if it is the /LM node.
  7570. Return Value:
  7571. DWORD - ERROR_SUCCESS
  7572. Return codes from file system
  7573. Notes:
  7574. --*/
  7575. {
  7576. HRESULT hresReturn = ERROR_SUCCESS;
  7577. PBASEOBJECT_CONTAINER objChildObjectContainer = NULL;
  7578. CMDBaseData *dataAssociatedData;
  7579. DWORD dwEnumObjectIndex;
  7580. DWORD dwParentPathLen, dwNewParentPathLen;
  7581. DWORD dwNameLen;
  7582. LPWSTR strParentPath;
  7583. PFILETIME pftTime;
  7584. CLocationWriter* pCLocationWriter = NULL;
  7585. LPWSTR wszKeyType = NULL;
  7586. DWORD dwAttributes = 0;
  7587. DWORD dwUserType = 0;
  7588. DWORD dwDataType = 0;
  7589. DWORD cbData = 0;
  7590. PBASEOBJECT_CONTAINER arrFixedChildObjects[MD_MAX_CHILD_OBJECTS];
  7591. PBASEOBJECT_CONTAINER* arrChildObject = arrFixedChildObjects;
  7592. dwParentPathLen = (DWORD)wcslen((LPWSTR)pbufParentPath->QueryPtr());
  7593. if (pboRoot->GetName(TRUE) == NULL) {
  7594. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  7595. }
  7596. else {
  7597. dwNameLen = (DWORD)wcslen((LPWSTR)pboRoot->GetName(TRUE));
  7598. //
  7599. // include 1 for delimeter and 1 for \0
  7600. //
  7601. dwNewParentPathLen = dwParentPathLen + dwNameLen + 2;
  7602. if (!pbufParentPath->Resize((dwNewParentPathLen) * sizeof(WCHAR))) {
  7603. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  7604. }
  7605. else {
  7606. strParentPath = (LPWSTR)pbufParentPath->QueryPtr();
  7607. if(pboRoot != g_pboMasterRoot) {
  7608. wcscat(strParentPath, (LPWSTR)pboRoot->GetName(TRUE));
  7609. strParentPath[dwParentPathLen + dwNameLen] = MD_PATH_DELIMETERW;
  7610. strParentPath[dwNewParentPathLen - 1] = (WCHAR)L'\0';
  7611. }
  7612. pftTime = pboRoot->GetLastChangeTime();
  7613. // TODO: MD_ID_OBJECT
  7614. // pftFileTIme?
  7615. //
  7616. // Fetch the Location writer.
  7617. //
  7618. hresReturn = pCWriter->GetLocationWriter(&pCLocationWriter,
  7619. strParentPath);
  7620. //
  7621. // Figure out the KeyType of this node.
  7622. //
  7623. for(dwEnumObjectIndex=0,dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA);
  7624. (SUCCEEDED(hresReturn)) && (dataAssociatedData!=NULL);
  7625. dataAssociatedData=pboRoot->EnumDataObject(dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA)) {
  7626. if(MD_KEY_TYPE == dataAssociatedData->GetIdentifier())
  7627. {
  7628. wszKeyType = (LPWSTR)dataAssociatedData->GetData(TRUE);
  7629. dwAttributes = dataAssociatedData->GetAttributes();
  7630. dwUserType = dataAssociatedData->GetUserType();
  7631. dwDataType = dataAssociatedData->GetDataType();
  7632. cbData = dataAssociatedData->GetDataLen(TRUE);
  7633. break;
  7634. }
  7635. }
  7636. //
  7637. // Initialize the writer with the keytype
  7638. //
  7639. if(SUCCEEDED(hresReturn))
  7640. {
  7641. hresReturn = pCLocationWriter->InitializeKeyType(MD_KEY_TYPE,
  7642. dwAttributes,
  7643. dwUserType,
  7644. dwDataType,
  7645. (PBYTE)wszKeyType,
  7646. cbData);
  7647. }
  7648. //
  7649. // Save all the properties at this node
  7650. //
  7651. for ( dwEnumObjectIndex = 0, dataAssociatedData = pboRoot->EnumDataObject( dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA );
  7652. SUCCEEDED( hresReturn ) && ( dataAssociatedData != NULL );
  7653. dataAssociatedData = pboRoot->EnumDataObject( dwEnumObjectIndex++, 0, ALL_METADATA, ALL_METADATA ) )
  7654. {
  7655. hresReturn = SaveDataObject( dataAssociatedData,
  7656. pCLocationWriter,
  7657. pCryptoStorage,
  7658. pSessionKeyBlob );
  7659. if ( bLocalMachine )
  7660. {
  7661. SaveGlobalsFromLM( dataAssociatedData );
  7662. }
  7663. }
  7664. if ( bLocalMachine )
  7665. {
  7666. if ( g_dwEnableEditWhileRunning && !g_dwEnableHistory )
  7667. {
  7668. DBGINFOW(( DBG_CONTEXT,
  7669. L"[SaveTree] Warning! Edit while running is enabled, while Enable history is disabled. Forcibly enabling history.\n" ));
  7670. g_dwEnableHistory = TRUE;
  7671. }
  7672. }
  7673. //
  7674. // Write out the node
  7675. //
  7676. if(SUCCEEDED(hresReturn))
  7677. {
  7678. hresReturn = pCLocationWriter->WriteLocation(TRUE);
  7679. }
  7680. //
  7681. // If recurse, the enumerate and write all the sub-nodes, in a sorted manner.
  7682. //
  7683. if((SUCCEEDED(hresReturn)) && (bRecurse)) {
  7684. //
  7685. // First pass, count the number of child objects
  7686. //
  7687. ULONG cChildObjects = 0;
  7688. ULONG iChildObjects = 0;
  7689. for(objChildObjectContainer=pboRoot->NextChildObject(NULL);
  7690. (SUCCEEDED(hresReturn)) && (objChildObjectContainer!=NULL);
  7691. objChildObjectContainer=pboRoot->NextChildObject(objChildObjectContainer)) {
  7692. cChildObjects++;
  7693. }
  7694. //
  7695. // Allocate memory if greater than whats allocated on the stack.
  7696. //
  7697. if(SUCCEEDED(hresReturn) && (cChildObjects > MD_MAX_CHILD_OBJECTS))
  7698. {
  7699. arrChildObject = new PBASEOBJECT_CONTAINER[cChildObjects];
  7700. if(NULL == arrChildObject)
  7701. {
  7702. hresReturn = E_OUTOFMEMORY;
  7703. }
  7704. }
  7705. //
  7706. // Make another pass and populate the array
  7707. //
  7708. for(objChildObjectContainer=pboRoot->NextChildObject(NULL),iChildObjects=0;
  7709. (SUCCEEDED(hresReturn)) && (objChildObjectContainer!=NULL);
  7710. objChildObjectContainer=pboRoot->NextChildObject(objChildObjectContainer),iChildObjects++) {
  7711. arrChildObject[iChildObjects] = objChildObjectContainer;
  7712. }
  7713. //
  7714. // Sort the array
  7715. //
  7716. if(SUCCEEDED(hresReturn))
  7717. {
  7718. qsort((void*)arrChildObject, cChildObjects, sizeof(PBASEOBJECT_CONTAINER), MyComparePBaseObjectContainer);
  7719. }
  7720. //
  7721. // Enumerate the sorted array of child objects and call SaveTree on each of them
  7722. //
  7723. for(iChildObjects=0;
  7724. (SUCCEEDED(hresReturn)) && (iChildObjects<cChildObjects);
  7725. iChildObjects++) {
  7726. if(bSaveSchema ||
  7727. !(pboRoot == g_pboMasterRoot &&
  7728. _wcsicmp((LPWSTR)((arrChildObject[iChildObjects])->pboMetaObject->GetName(TRUE)), g_wszSchema) == 0
  7729. )
  7730. )
  7731. {
  7732. hresReturn = SaveTree(pCWriter,
  7733. (arrChildObject[iChildObjects])->pboMetaObject,
  7734. pbufParentPath,
  7735. pCryptoStorage,
  7736. pSessionKeyBlob,
  7737. bRecurse,
  7738. true);
  7739. }
  7740. }
  7741. }
  7742. //
  7743. // Buffer may have changed, so don't use strParentPath
  7744. //
  7745. ((LPWSTR)pbufParentPath->QueryPtr())[dwParentPathLen] = (WCHAR)L'\0';
  7746. }
  7747. }
  7748. if(NULL != pCLocationWriter)
  7749. {
  7750. delete pCLocationWriter;
  7751. pCLocationWriter = NULL;
  7752. }
  7753. if((NULL != arrChildObject) && (arrChildObject != arrFixedChildObjects) )
  7754. {
  7755. delete [] arrChildObject;
  7756. arrChildObject = NULL;
  7757. }
  7758. return(hresReturn);
  7759. }
  7760. HRESULT
  7761. SaveDataObject(CMDBaseData* pbdSave,
  7762. CLocationWriter* pCLocationWriter,
  7763. IIS_CRYPTO_STORAGE* pCryptoStorage,
  7764. PIIS_CRYPTO_BLOB )
  7765. /*++
  7766. Routine Description:
  7767. Save a data object.
  7768. Arguments:
  7769. Save - The data object to save.
  7770. CryptoStorage - Used to encrypt secure data.
  7771. Return Value:
  7772. DWORD - ERROR_SUCCESS
  7773. Return codes from file system
  7774. Notes:
  7775. --*/
  7776. {
  7777. HRESULT hresReturn = ERROR_SUCCESS;
  7778. if ((pbdSave->GetAttributes() & METADATA_VOLATILE) == 0) {
  7779. if (SUCCEEDED(hresReturn)) {
  7780. if (pbdSave->GetData(TRUE) == NULL) {
  7781. //
  7782. // This is to make sure that unicode conversion doesn't cause an error.
  7783. //
  7784. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  7785. }
  7786. else {
  7787. PIIS_CRYPTO_BLOB blob = NULL;
  7788. PBYTE pbData = NULL;
  7789. DWORD cbData = 0;
  7790. pbData = (PBYTE)pbdSave->GetData(TRUE);
  7791. cbData = pbdSave->GetDataLen(TRUE);
  7792. if (IsSecureMetadata(pbdSave->GetIdentifier(), pbdSave->GetAttributes())) {
  7793. //
  7794. // This is a secure data object, so encrypt it before saving it
  7795. // to the file.
  7796. //
  7797. MD_ASSERT(pCryptoStorage != NULL);
  7798. hresReturn = pCryptoStorage->EncryptData(&blob,
  7799. pbData,
  7800. cbData,
  7801. 0);
  7802. if (SUCCEEDED(hresReturn)) {
  7803. pbData = (PBYTE)blob;
  7804. cbData = IISCryptoGetBlobLength(blob);
  7805. }
  7806. else
  7807. {
  7808. DBGINFOW((DBG_CONTEXT,
  7809. L"[SaveDataObject] Unable to encrypt data. Failed with hr = 0x%x. Property id: %d Location %s.\n",
  7810. hresReturn,
  7811. pbdSave->GetIdentifier(),
  7812. pCLocationWriter->m_wszLocation));
  7813. }
  7814. }
  7815. if (SUCCEEDED(hresReturn)) {
  7816. hresReturn = pCLocationWriter->AddProperty(pbdSave->GetIdentifier(),
  7817. pbdSave->GetAttributes(),
  7818. pbdSave->GetUserType(),
  7819. pbdSave->GetDataType(),
  7820. (PBYTE)pbData,
  7821. cbData);
  7822. if(NULL != blob) {
  7823. ::IISCryptoFreeBlob(blob);
  7824. }
  7825. }
  7826. }
  7827. }
  7828. }
  7829. return (hresReturn);
  7830. }
  7831. BOOL
  7832. DiscontinuousLocation(LPWSTR wszPreviousLocation,
  7833. LPWSTR wszCurrentLocation)
  7834. {
  7835. LPWSTR wszEndCurrent = NULL;
  7836. BOOL bNeedRestore = FALSE;
  7837. ULONG cchCurrentLocation = 0;
  7838. BOOL bReturn;
  7839. ULONG cchCompare = 0;
  7840. if(NULL == wszPreviousLocation || 0 == *wszPreviousLocation ||
  7841. NULL == wszCurrentLocation || 0 == *wszCurrentLocation)
  7842. {
  7843. bReturn = TRUE;
  7844. }
  7845. else
  7846. {
  7847. cchCurrentLocation = (ULONG)wcslen(wszCurrentLocation);
  7848. if((wszCurrentLocation[cchCurrentLocation-1] == L'/') &&
  7849. (1 != cchCurrentLocation)
  7850. )
  7851. {
  7852. //
  7853. // If the location ends in a "/" and is not the root location,
  7854. // then null it out for the purpose of comparison.
  7855. //
  7856. wszCurrentLocation[cchCurrentLocation-1] = 0;
  7857. bNeedRestore = TRUE;
  7858. }
  7859. wszEndCurrent = wcsrchr(wszCurrentLocation, L'/');
  7860. if(wszEndCurrent == wszCurrentLocation)
  7861. {
  7862. //
  7863. // This is the root location
  7864. //
  7865. cchCompare = 1;
  7866. }
  7867. else
  7868. {
  7869. cchCompare = (ULONG)(wszEndCurrent-wszCurrentLocation);
  7870. }
  7871. if(0 == _wcsnicmp(wszPreviousLocation, wszCurrentLocation, cchCompare))
  7872. {
  7873. bReturn = FALSE;
  7874. }
  7875. else
  7876. {
  7877. bReturn = TRUE;
  7878. }
  7879. if(bNeedRestore)
  7880. {
  7881. wszCurrentLocation[cchCurrentLocation-1] = L'/';
  7882. }
  7883. }
  7884. return bReturn;
  7885. }
  7886. HRESULT
  7887. InitSessionKey(ISimpleTableRead2* pISTProperty,
  7888. IIS_CRYPTO_STORAGE** ppStorage,
  7889. LPSTR pszPasswd)
  7890. {
  7891. HRESULT hresReturn = 0;
  7892. BOOL fSecuredRead = TRUE;
  7893. HKEY hkRegistryKey = NULL;
  7894. DWORD dwRegReturn, dwValue,dwType,dwSize = sizeof(DWORD);
  7895. dwRegReturn = RegOpenKey(HKEY_LOCAL_MACHINE,
  7896. SETUP_REG_KEY,
  7897. &hkRegistryKey);
  7898. if (dwRegReturn == ERROR_SUCCESS)
  7899. {
  7900. dwSize = sizeof(DWORD);
  7901. dwRegReturn = RegQueryValueEx(hkRegistryKey,
  7902. MD_UNSECUREDREAD_VALUE,
  7903. NULL,
  7904. &dwType,
  7905. (BYTE *)&dwValue,
  7906. &dwSize);
  7907. if ( dwRegReturn == ERROR_SUCCESS &&
  7908. dwType == REG_DWORD &&
  7909. dwValue == 1)
  7910. {
  7911. hresReturn = NO_ERROR;
  7912. *ppStorage = NULL;
  7913. fSecuredRead = FALSE;
  7914. DBGPRINTF(( DBG_CONTEXT,
  7915. "Temporary disabling decryption for metabase read\n"));
  7916. // special indicator for IIS setup that we passed this point
  7917. dwValue = 2;
  7918. dwRegReturn = RegSetValueEx(hkRegistryKey,
  7919. MD_UNSECUREDREAD_VALUE,
  7920. 0,
  7921. REG_DWORD,
  7922. (PBYTE)&dwValue,
  7923. sizeof(dwValue));
  7924. if (dwRegReturn == ERROR_SUCCESS)
  7925. {
  7926. DBGPRINTF(( DBG_CONTEXT,"Reanabling decryption after W9z upgrade\n"));
  7927. }
  7928. }
  7929. MD_REQUIRE( RegCloseKey( hkRegistryKey ) == NO_ERROR );
  7930. }
  7931. if (fSecuredRead)
  7932. {
  7933. ULONG cbSessionKey = 0;
  7934. BYTE* pbSessionKey = NULL;
  7935. hresReturn = GetGlobalValue(pISTProperty,
  7936. MD_SESSION_KEYW,
  7937. &cbSessionKey,
  7938. (LPVOID*)&pbSessionKey);
  7939. if(FAILED(hresReturn))
  7940. {
  7941. DBGINFOW((DBG_CONTEXT,
  7942. L"[InitSessionKey] Error: Session key could not be fetched. GetGlobalValue failed with hr = 0x%x.\n",
  7943. hresReturn));
  7944. return MD_ERROR_NO_SESSION_KEY;
  7945. }
  7946. if (IISCryptoIsClearTextSignature((IIS_CRYPTO_BLOB UNALIGNED *) pbSessionKey))
  7947. {
  7948. // call special function focibly tell that this machine has no
  7949. // encryption enabled even if it happens to be so
  7950. // that's a special handling for French case with US locale
  7951. IISCryptoInitializeOverride (FALSE);
  7952. }
  7953. if( !pszPasswd )
  7954. {
  7955. hresReturn = InitStorageHelper(pbSessionKey,
  7956. cbSessionKey, // dwLineLen-1
  7957. ppStorage);
  7958. }
  7959. else
  7960. {
  7961. hresReturn = InitStorageHelper2(pszPasswd,
  7962. pbSessionKey,
  7963. cbSessionKey, // dwLineLen-1
  7964. ppStorage);
  7965. }
  7966. if(FAILED(hresReturn))
  7967. {
  7968. DBGINFOW((DBG_CONTEXT,
  7969. L"[InitSessionKey] InitStorageHelper? failed with hr = 0x%x.\n",hresReturn));
  7970. }
  7971. }
  7972. return hresReturn;
  7973. }
  7974. HRESULT
  7975. GetUnicodeNameW(IN LPWSTR wszFileName,
  7976. OUT LPWSTR* pwszFileName)
  7977. {
  7978. *pwszFileName = new WCHAR[wcslen(wszFileName)+1];
  7979. if(NULL == *pwszFileName)
  7980. return E_OUTOFMEMORY;
  7981. wcscpy(*pwszFileName, wszFileName);
  7982. return S_OK;
  7983. }
  7984. HRESULT
  7985. GetUnicodeNameA(IN LPSTR szFileName,
  7986. OUT LPWSTR* pwszFileName)
  7987. {
  7988. ULONG cchOut = 0;
  7989. cchOut = MultiByteToWideChar(CP_ACP, // XXX Consider: make any cp?
  7990. 0,
  7991. szFileName,
  7992. (int)((strlen(szFileName) + 1)*sizeof(char)),
  7993. NULL,
  7994. 0);
  7995. if(!cchOut)
  7996. return HRESULT_FROM_WIN32(GetLastError());
  7997. *pwszFileName = new WCHAR[cchOut+1];
  7998. if(NULL == *pwszFileName)
  7999. return E_OUTOFMEMORY;
  8000. cchOut = MultiByteToWideChar(CP_ACP, // XXX Consider: make any cp?
  8001. 0,
  8002. szFileName,
  8003. (int)((strlen(szFileName) + 1)*sizeof(char)),
  8004. *pwszFileName,
  8005. cchOut);
  8006. if(!cchOut)
  8007. {
  8008. delete *pwszFileName;
  8009. return HRESULT_FROM_WIN32(GetLastError());
  8010. }
  8011. return S_OK;
  8012. }
  8013. HRESULT
  8014. InitEditWhileRunning(ISimpleTableRead2* pISTProperty)
  8015. {
  8016. HRESULT hresReturn = S_OK;
  8017. DWORD dwDisable = 0;
  8018. DWORD* pdwEnable = &dwDisable;
  8019. ULONG* pulVersionMajor = NULL;
  8020. ULONG* pulMaxErrorFiles = NULL;
  8021. hresReturn = GetComputerValue(pISTProperty,
  8022. MD_ENABLE_EDIT_WHILE_RUNNINGW,
  8023. NULL,
  8024. (LPVOID*)&pdwEnable);
  8025. if(FAILED(hresReturn))
  8026. {
  8027. DBGINFOW((DBG_CONTEXT,
  8028. L"[InitEditWhileRunning] Could not determine if edit while running was enabled. Defaulting to %d. GetComputerValue failed with hr = 0x%x.\n",
  8029. g_dwEnableEditWhileRunning, hresReturn));
  8030. }
  8031. else
  8032. {
  8033. g_dwEnableEditWhileRunning = *pdwEnable;
  8034. }
  8035. //
  8036. // Init Edit while running version number irrespective of whether edit
  8037. // while running is enabled, because they are used to create history files.
  8038. //
  8039. hresReturn = GetGlobalValue(pISTProperty,
  8040. MD_EDIT_WHILE_RUNNING_MAJOR_VERSION_NUMBERW,
  8041. NULL,
  8042. (LPVOID*)&pulVersionMajor);
  8043. if(E_ST_NOMOREROWS == hresReturn)
  8044. {
  8045. //
  8046. // Currently, if we are unable to fetch the major version number, we
  8047. // initialize it to 0. The next time metabase.xml gets saved (in
  8048. // SaveAllData, we will search through history dir and compute the
  8049. // next available version number and assign it to
  8050. // g_ulHistoryMajorVersionNumber.
  8051. //
  8052. DBGINFOW((DBG_CONTEXT,
  8053. L"[InitEditWhileRunning] Could not fetch history major version number. Defaulting to 0x%x. GetGlobalValue failed with hr = 0x%x.\n",
  8054. g_ulHistoryMajorVersionNumber, hresReturn));
  8055. hresReturn = S_OK;
  8056. }
  8057. else if(FAILED(hresReturn))
  8058. {
  8059. DBGINFOW((DBG_CONTEXT,
  8060. L"[InitEditWhileRunning] Could not fetch history major version number. Defaulting to 0x%x. GetGlobalValue failed with hr = 0x%x.\n",
  8061. g_ulHistoryMajorVersionNumber, hresReturn));
  8062. hresReturn = S_OK;
  8063. }
  8064. else
  8065. {
  8066. g_ulHistoryMajorVersionNumber = (*(ULONG*)pulVersionMajor);
  8067. DBGINFOW((DBG_CONTEXT,
  8068. L"[InitEditWhileRunning] Read history major version number as 0x%x.\n",
  8069. g_ulHistoryMajorVersionNumber));
  8070. }
  8071. //
  8072. // Get the MaxErrorFiles property.
  8073. //
  8074. hresReturn = GetComputerValue(pISTProperty,
  8075. MD_MAX_ERROR_FILESW,
  8076. NULL,
  8077. (LPVOID*)&pulMaxErrorFiles);
  8078. if(FAILED(hresReturn))
  8079. {
  8080. DBGINFOW((DBG_CONTEXT,
  8081. L"[InitEditWhileRunning] Could not determine if edit while running was enabled. Defaulting to %d. GetComputerValue failed with hr = 0x%x.\n",
  8082. g_dwEnableEditWhileRunning, hresReturn));
  8083. }
  8084. else
  8085. {
  8086. g_dwMaxErrorFiles = *pulMaxErrorFiles;
  8087. }
  8088. return hresReturn;
  8089. }
  8090. HRESULT InitEnableHistory(ISimpleTableRead2* pISTProperty,
  8091. LPWSTR wszDataFileName,
  8092. LPWSTR wszSchemaFileName,
  8093. BOOL bCalledFromRestore)
  8094. {
  8095. HRESULT hresReturn = S_OK;
  8096. DWORD dwEnableHistory = FALSE;
  8097. DWORD* pdwEnableHistory = &dwEnableHistory;
  8098. DWORD dwMaxHistoryFiles = 0;
  8099. DWORD* pdwMaxHistoryFiles = &dwMaxHistoryFiles;
  8100. hresReturn = GetComputerValue(pISTProperty,
  8101. MD_ENABLE_HISTORYW,
  8102. NULL,
  8103. (LPVOID*)&pdwEnableHistory);
  8104. if(E_ST_NOMOREROWS == hresReturn)
  8105. {
  8106. DBGINFOW((DBG_CONTEXT,
  8107. L"[InitEnableHistory] Could not fetch enable history. Defaulting to %d. GetComputerValue failed with hr = 0x%x.\n",
  8108. g_dwEnableHistory, hresReturn));
  8109. hresReturn = S_OK;
  8110. }
  8111. else if(FAILED(hresReturn))
  8112. {
  8113. DBGINFOW((DBG_CONTEXT,
  8114. L"[InitEnableHistory] Could not fetch enable history. GetGlobalValue failed with hr = 0x%x.\n",
  8115. hresReturn));
  8116. return hresReturn;
  8117. }
  8118. else
  8119. {
  8120. g_dwEnableHistory = *pdwEnableHistory;
  8121. }
  8122. if((g_dwEnableEditWhileRunning) && (0 == g_dwEnableHistory))
  8123. {
  8124. DBGINFOW((DBG_CONTEXT,
  8125. L"[InitEnableHistory] Warning! Edit while running is enabled, while Enable history is disabled. Forcibly enabling history.\n"));
  8126. g_dwEnableHistory = 1;
  8127. }
  8128. hresReturn = GetComputerValue(pISTProperty,
  8129. MD_MAX_HISTORY_FILESW,
  8130. NULL,
  8131. (LPVOID*)&pdwMaxHistoryFiles);
  8132. if(E_ST_NOMOREROWS == hresReturn)
  8133. {
  8134. DBGINFOW((DBG_CONTEXT,
  8135. L"[InitEnableHistory] Could not fetch max history files. Defaulting to %d. GetComputerValue failed with hr = 0x%x.\n",
  8136. g_dwMaxHistoryFiles, hresReturn));
  8137. hresReturn = S_OK;
  8138. }
  8139. else if(FAILED(hresReturn))
  8140. {
  8141. DBGINFOW((DBG_CONTEXT,
  8142. L"[InitEnableHistory] Could not fetch max history files. GetComputerValue with hr = 0x%x.\n",
  8143. hresReturn));
  8144. return hresReturn;
  8145. }
  8146. else
  8147. {
  8148. g_dwMaxHistoryFiles = *pdwMaxHistoryFiles;
  8149. }
  8150. ValidateMaxHistoryFiles();
  8151. if(g_dwEnableHistory && !bCalledFromRestore)
  8152. {
  8153. hresReturn = CreateHistoryFiles(wszDataFileName,
  8154. wszSchemaFileName,
  8155. g_ulHistoryMajorVersionNumber,
  8156. g_dwMaxHistoryFiles);
  8157. }
  8158. return hresReturn;
  8159. }
  8160. void
  8161. ValidateMaxHistoryFiles()
  8162. {
  8163. if((0 == g_dwMaxHistoryFiles) && (g_dwEnableEditWhileRunning))
  8164. {
  8165. g_dwMaxHistoryFiles = MD_COUNT_MAX_HISTORY_FILES;
  8166. DBGINFOW((DBG_CONTEXT,
  8167. L"[ValidateMaxHistoryFiles] Warning! Edit while running is enable, while max history files is zero. Defaulting to %d.\n",
  8168. g_dwMaxHistoryFiles, HRESULT_FROM_WIN32(ERROR_INVALID_DATA)));
  8169. LogEvent(g_pEventLog,
  8170. MD_ERROR_DAFAULTING_MAX_HISTORY_FILES,
  8171. EVENTLOG_ERROR_TYPE,
  8172. ID_CAT_CAT,
  8173. S_OK);
  8174. }
  8175. else if((0 == g_dwMaxHistoryFiles) && (g_dwEnableHistory))
  8176. {
  8177. g_dwMaxHistoryFiles = MD_COUNT_MAX_HISTORY_FILES;
  8178. DBGINFOW((DBG_CONTEXT,
  8179. L"[ValidateMaxHistoryFiles] Warning! History is enabled, while max history files is zero. Defaulting to %d.\n",
  8180. g_dwMaxHistoryFiles, HRESULT_FROM_WIN32(ERROR_INVALID_DATA)));
  8181. LogEvent(g_pEventLog,
  8182. MD_ERROR_DAFAULTING_MAX_HISTORY_FILES,
  8183. EVENTLOG_ERROR_TYPE,
  8184. ID_CAT_CAT,
  8185. (DWORD)HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  8186. }
  8187. return;
  8188. }
  8189. HRESULT
  8190. InitChangeNumber(ISimpleTableRead2* pISTProperty)
  8191. {
  8192. HRESULT hresReturn = S_OK;
  8193. DWORD* pdwChangeNumber = NULL;
  8194. hresReturn = GetGlobalValue(pISTProperty,
  8195. MD_CHANGE_NUMBERW,
  8196. NULL,
  8197. (LPVOID*)&pdwChangeNumber);
  8198. if(FAILED(hresReturn))
  8199. {
  8200. //
  8201. // If unable to read change number, initialize to 0.
  8202. //
  8203. g_dwSystemChangeNumber = 0;
  8204. DBGINFOW((DBG_CONTEXT,
  8205. L"[InitChangeNumber] Could not fetch change number. Defaulting to %d. GetGlobalValue failed with hr = 0x%x.\n",
  8206. g_dwSystemChangeNumber, hresReturn));
  8207. }
  8208. else
  8209. {
  8210. g_dwSystemChangeNumber = *pdwChangeNumber;
  8211. }
  8212. return S_OK;
  8213. }
  8214. HRESULT
  8215. CreateHistoryFiles(LPWSTR i_wszDataFileName,
  8216. LPWSTR i_wszSchemaFileName,
  8217. ULONG i_ulHistoryMajorVersionNumber,
  8218. DWORD i_dwMaxHistoryFiles)
  8219. {
  8220. HRESULT hr = S_OK;
  8221. //
  8222. // Create the history directory, if it is not present.
  8223. //
  8224. if(-1 == GetFileAttributesW(g_wszHistoryFileDir))
  8225. {
  8226. hr = HRESULT_FROM_WIN32(GetLastError());
  8227. if((hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))||
  8228. (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  8229. )
  8230. {
  8231. SECURITY_ATTRIBUTES saStorage;
  8232. PSECURITY_ATTRIBUTES psaStorage = NULL;
  8233. //
  8234. // Initialize the security attributes & create the file
  8235. //
  8236. if (g_psdStorage != NULL) {
  8237. saStorage.nLength = sizeof(SECURITY_ATTRIBUTES);
  8238. saStorage.lpSecurityDescriptor = g_psdStorage;
  8239. saStorage.bInheritHandle = FALSE;
  8240. psaStorage = &saStorage;
  8241. }
  8242. if(!CreateDirectoryW(g_wszHistoryFileDir, psaStorage))
  8243. {
  8244. hr = HRESULT_FROM_WIN32(GetLastError());
  8245. DBGINFOW((DBG_CONTEXT,
  8246. L"[CreateHistoryFile] Unable to create history directory. CreateDirectoryW failed with hr = 0x%x. \n",
  8247. hr));
  8248. return hr;
  8249. }
  8250. else
  8251. {
  8252. hr = S_OK;
  8253. }
  8254. }
  8255. else
  8256. {
  8257. return hr;
  8258. }
  8259. }
  8260. //
  8261. // Create the data file before the schema file. Under stress data files
  8262. // can grow and if the creation of data files fail, then you do not want
  8263. // to create the schema file.
  8264. //
  8265. //
  8266. // Create the data history file first
  8267. //
  8268. hr = CreateHistoryFile(i_wszDataFileName,
  8269. g_wszHistoryFileDir,
  8270. g_cchHistoryFileDir,
  8271. g_wszRealFileNameWithoutPathWithoutExtension,
  8272. g_cchRealFileNameWithoutPathWithoutExtension,
  8273. g_wszRealFileNameExtension,
  8274. g_cchRealFileNameExtension,
  8275. i_ulHistoryMajorVersionNumber);
  8276. if(SUCCEEDED(hr))
  8277. {
  8278. //
  8279. // Create the schema history file next
  8280. //
  8281. hr = CreateHistoryFile(i_wszSchemaFileName,
  8282. g_wszHistoryFileDir,
  8283. g_cchHistoryFileDir,
  8284. g_wszSchemaFileNameWithoutPathWithoutExtension,
  8285. g_cchSchemaFileNameWithoutPathWithoutExtension,
  8286. g_wszSchemaFileNameExtension,
  8287. g_cchSchemaFileNameExtension,
  8288. i_ulHistoryMajorVersionNumber);
  8289. }
  8290. //
  8291. // Cleanup the obsolete history files.
  8292. //
  8293. hr = CleanupObsoleteHistoryFiles(i_dwMaxHistoryFiles,
  8294. i_ulHistoryMajorVersionNumber);
  8295. return hr;
  8296. }
  8297. HRESULT
  8298. CreateHistoryFile(LPWSTR i_wszFileName,
  8299. LPWSTR i_wszHistroyFileDir,
  8300. ULONG i_cchHistoryFileDir,
  8301. LPWSTR i_wszFileNameWithoutPathWithoutExtension,
  8302. ULONG i_cchFileNameWithoutPathWithoutExtension,
  8303. LPWSTR i_wszFileNameExtension,
  8304. ULONG i_cchFileNameExtension,
  8305. DWORD i_ulHistoryMajorVersionNumber)
  8306. {
  8307. WCHAR* wszHistoryFileName = NULL;
  8308. HRESULT hr = S_OK;
  8309. DWORD dwMinorVersion = 0;
  8310. //
  8311. // Construct the history data file name
  8312. //
  8313. hr = ConstructHistoryFileName(&wszHistoryFileName,
  8314. i_wszHistroyFileDir,
  8315. i_cchHistoryFileDir,
  8316. i_wszFileNameWithoutPathWithoutExtension,
  8317. i_cchFileNameWithoutPathWithoutExtension,
  8318. i_wszFileNameExtension,
  8319. i_cchFileNameExtension,
  8320. i_ulHistoryMajorVersionNumber,
  8321. dwMinorVersion);
  8322. if(FAILED(hr))
  8323. {
  8324. DBGINFOW((DBG_CONTEXT,
  8325. L"[CreateHistoryFile] Unable to construct history file name. ConstructHistoryFileName failed with hr = 0x%x\n.",
  8326. hr));
  8327. goto exit;
  8328. }
  8329. //
  8330. // Create the history file.
  8331. //
  8332. DBGINFOW((DBG_CONTEXT,
  8333. L"[CreateHistoryFile] Copying history file from %s to %s.\n",
  8334. i_wszFileName,
  8335. wszHistoryFileName));
  8336. //
  8337. // Compare the names of the source and dest. Do not copy if they are the same.
  8338. // This can happen when restoring from history directory, and ReadAllData=>
  8339. // InitEnableHistory=>CreateHistoryFiles is called.
  8340. //
  8341. if(0 == _wcsicmp(i_wszFileName, wszHistoryFileName))
  8342. {
  8343. goto exit;
  8344. }
  8345. if(!CopyFileW(i_wszFileName,
  8346. wszHistoryFileName,
  8347. FALSE) // Overwrite if it exists.
  8348. )
  8349. {
  8350. hr = HRESULT_FROM_WIN32(GetLastError());
  8351. DBGINFOW((DBG_CONTEXT,
  8352. L"[CreateHistoryFile] Unable to create history file. CopyFileW from %s to %s failed with hr = 0x%x\n.",
  8353. i_wszFileName,
  8354. wszHistoryFileName,
  8355. hr));
  8356. goto exit;
  8357. }
  8358. else
  8359. {
  8360. SetSecurityOnFile(i_wszFileName,
  8361. wszHistoryFileName);
  8362. }
  8363. exit:
  8364. if(NULL != wszHistoryFileName)
  8365. {
  8366. delete [] wszHistoryFileName;
  8367. wszHistoryFileName = NULL;
  8368. }
  8369. return hr;
  8370. }
  8371. int _cdecl MyCompareFileData(const void *a,
  8372. const void *b)
  8373. {
  8374. return CompareFileTime(&(((METABASE_FILE_DATA*)a)->ftLastWriteTime), &(((METABASE_FILE_DATA*)b)->ftLastWriteTime));
  8375. }
  8376. HRESULT ConstructHistoryFileName(LPWSTR* o_wszHistoryFile,
  8377. LPWSTR i_wszHistroyFileDir,
  8378. ULONG i_cchHistoryFileDir,
  8379. LPWSTR i_wszFileNameWithoutPathWithoutExtension,
  8380. ULONG i_cchFileNameWithoutPathWithoutExtension,
  8381. LPWSTR i_wszFileNameExtension,
  8382. ULONG i_cchFileNameExtension,
  8383. ULONG i_ulMajorVersion,
  8384. ULONG i_ulMinorVersion)
  8385. {
  8386. ULONG cch = 0;
  8387. LPWSTR pEnd = NULL;
  8388. int res = 0;
  8389. HRESULT hr = S_OK;
  8390. WCHAR wszVersion[MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW+1];
  8391. *o_wszHistoryFile = NULL;
  8392. res = _snwprintf(wszVersion,
  8393. MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW+1,
  8394. L"_%010lu_%010lu",
  8395. i_ulMajorVersion,
  8396. i_ulMinorVersion);
  8397. if(res < 0)
  8398. {
  8399. DBGINFOW((DBG_CONTEXT,
  8400. L"[ConstructHistoryFileName] _snwprintf returned a negative value. This should never happen.\n"));
  8401. MD_ASSERT(0);
  8402. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  8403. goto exit;
  8404. }
  8405. cch = i_cchHistoryFileDir +
  8406. 1 + // For backslash if it doesn't end in one
  8407. i_cchFileNameWithoutPathWithoutExtension +
  8408. MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW +
  8409. i_cchFileNameExtension;
  8410. *o_wszHistoryFile= new WCHAR[cch+1];
  8411. if(NULL == *o_wszHistoryFile)
  8412. {
  8413. hr = E_OUTOFMEMORY;
  8414. goto exit;
  8415. }
  8416. pEnd = *o_wszHistoryFile;
  8417. memcpy(pEnd, i_wszHistroyFileDir, i_cchHistoryFileDir*sizeof(WCHAR));
  8418. pEnd = pEnd + i_cchHistoryFileDir;
  8419. if(i_wszHistroyFileDir[i_cchHistoryFileDir-1] != L'\\')
  8420. {
  8421. *pEnd = L'\\';
  8422. pEnd++;
  8423. }
  8424. memcpy(pEnd, i_wszFileNameWithoutPathWithoutExtension, i_cchFileNameWithoutPathWithoutExtension*sizeof(WCHAR));
  8425. pEnd = pEnd + i_cchFileNameWithoutPathWithoutExtension;
  8426. memcpy(pEnd, wszVersion, MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW*sizeof(WCHAR));
  8427. pEnd = pEnd + MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW;
  8428. if(0 != i_cchFileNameExtension)
  8429. {
  8430. memcpy(pEnd, i_wszFileNameExtension, i_cchFileNameExtension*sizeof(WCHAR));
  8431. pEnd = pEnd + i_cchFileNameExtension;
  8432. }
  8433. *(pEnd) = L'\0';
  8434. exit:
  8435. return hr;
  8436. }
  8437. HRESULT ConstructHistoryFileNameWithoutMinorVersion(LPWSTR* o_wszHistoryFileNameWithoutMinorVersion,
  8438. ULONG* o_iStartMinorVersion,
  8439. LPWSTR i_wszHistroyFileSearchString,
  8440. ULONG i_cchHistoryFileSearchString,
  8441. LPWSTR ,
  8442. ULONG i_cchFileNameExtension,
  8443. ULONG i_ulMajorVersion)
  8444. /*
  8445. ++
  8446. Routine Description:
  8447. Constructs the history file search string, given the following:
  8448. History file search string
  8449. (This would look like:
  8450. D:\Winnt\system32\inetsrv\History\Metabase_??????????_??????????.XML
  8451. or if the path is long (greater that MAX_PATH):
  8452. \\?\D:\Winnt\system32\inetsrv\History\Metabase_??????????_??????????.XML
  8453. )
  8454. Major history version number
  8455. The resulting string would look something like:
  8456. D:\Winnt\system32\inetsrv\History\Metabase_0000000001_??????????.XML
  8457. or if the path is long (greater that MAX_PATH):
  8458. \\?\D:\Winnt\system32\inetsrv\History\Metabase_0000000001_??????????.XML
  8459. Arguments:
  8460. Return - The full path of the history file search string.
  8461. Return - The start index of where the minor version would begin.
  8462. History file search string
  8463. History file search string count of characters
  8464. History file extension, if any (Eg: ".XML")
  8465. History file extension character count
  8466. Major history version number
  8467. Return Value:
  8468. HRESULT - S_OK
  8469. HRESULT_FROM_WIN32(ERROR_INVALID_DATA)
  8470. E_OUTOFMEMORY
  8471. Notes:
  8472. --*/
  8473. {
  8474. LPWSTR pEnd = NULL;
  8475. int res = 0;
  8476. HRESULT hr = S_OK;
  8477. WCHAR wszVersionNumber[MD_CCH_MAX_ULONG+1];
  8478. res = _snwprintf(wszVersionNumber,
  8479. MD_CCH_MAX_ULONG,
  8480. L"%010lu",
  8481. i_ulMajorVersion);
  8482. wszVersionNumber[MD_CCH_MAX_ULONG]=L'\0';
  8483. if(res < 0)
  8484. {
  8485. DBGINFOW((DBG_CONTEXT,
  8486. L"[ConstructHistoryFileNameWithoutMinorVersion] _snwprintf returned a negative value. This should never happen.\n"));
  8487. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  8488. goto exit;
  8489. }
  8490. *o_wszHistoryFileNameWithoutMinorVersion = new WCHAR[i_cchHistoryFileSearchString+1];
  8491. if(NULL == *o_wszHistoryFileNameWithoutMinorVersion)
  8492. {
  8493. hr = E_OUTOFMEMORY;
  8494. goto exit;
  8495. }
  8496. pEnd = *o_wszHistoryFileNameWithoutMinorVersion;
  8497. memcpy(pEnd, i_wszHistroyFileSearchString, i_cchHistoryFileSearchString*sizeof(WCHAR));
  8498. pEnd = pEnd + i_cchHistoryFileSearchString;
  8499. *pEnd = 0;
  8500. pEnd = ((*o_wszHistoryFileNameWithoutMinorVersion) + i_cchHistoryFileSearchString) -
  8501. i_cchFileNameExtension -
  8502. MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW +
  8503. MD_CCH_UNDERSCOREW;
  8504. memcpy(pEnd, wszVersionNumber, MD_CCH_MAX_ULONG*sizeof(WCHAR));
  8505. if(NULL != o_iStartMinorVersion)
  8506. {
  8507. *o_iStartMinorVersion = i_cchHistoryFileSearchString -
  8508. i_cchFileNameExtension -
  8509. MD_CCH_HISTORY_FILE_SEARCH_EXTENSIONW +
  8510. MD_CCH_UNDERSCOREW +
  8511. MD_CCH_MAX_ULONG +
  8512. MD_CCH_UNDERSCOREW;
  8513. }
  8514. exit:
  8515. return hr;
  8516. } // ConstructHistoryFileNameWithoutMinorVersion
  8517. HRESULT ReAllocateFileData(ULONG i_iFileData,
  8518. METABASE_FILE_DATA** io_aFileData,
  8519. ULONG* io_pcFileData,
  8520. BOOL* io_pbReAlloced)
  8521. {
  8522. METABASE_FILE_DATA* aTemp = NULL;
  8523. HRESULT hr = S_OK;
  8524. aTemp = new METABASE_FILE_DATA[*io_pcFileData + MD_MAX_HISTORY_FILES_ALLOC_SIZE];
  8525. if(NULL == aTemp)
  8526. {
  8527. hr = E_OUTOFMEMORY;
  8528. return hr;
  8529. }
  8530. *io_pcFileData = *io_pcFileData + MD_MAX_HISTORY_FILES_ALLOC_SIZE;
  8531. memset(aTemp, 0, (*io_pcFileData)*sizeof(METABASE_FILE_DATA));
  8532. if((NULL != *io_aFileData))
  8533. {
  8534. memcpy(aTemp, *io_aFileData, i_iFileData*sizeof(METABASE_FILE_DATA));
  8535. if(*io_pbReAlloced)
  8536. {
  8537. delete [] *io_aFileData;
  8538. *io_aFileData = NULL;
  8539. }
  8540. }
  8541. *io_pbReAlloced = TRUE;
  8542. *io_aFileData = aTemp;
  8543. return hr;
  8544. }
  8545. HRESULT CleanupObsoleteHistoryFiles(DWORD i_dwMaxHistoryFiles,
  8546. ULONG i_ulHistoryMajorVersionNumber)
  8547. {
  8548. HANDLE hFind = INVALID_HANDLE_VALUE;
  8549. WIN32_FIND_DATAW FileData;
  8550. FILETIME ftLastWriteTime;
  8551. HRESULT hr = S_OK;
  8552. ULONG iVersion = 0;
  8553. METABASE_FILE_DATA aOldVersionsFixed[MD_MAX_HISTORY_FILES_ALLOC_SIZE];
  8554. METABASE_FILE_DATA* aOldVersions = (METABASE_FILE_DATA*)&(aOldVersionsFixed[0]);
  8555. BOOL bReAlloced = FALSE;
  8556. ULONG cVersions = MD_MAX_HISTORY_FILES_ALLOC_SIZE;
  8557. ULONG ulVersionMajor;
  8558. ULONG ulVersionMinor;
  8559. //
  8560. // We also cleanup the stale (non-zero) backedup minor versions, that
  8561. // correspond to the major version we just created.This can happen if
  8562. // someone is restoring to an old version, & restarting IIS.
  8563. //
  8564. // Delete old history files based on timestamp rather than version number.
  8565. // Because if you start by restoring an old version, you dont
  8566. // want to delete it. Save as soon as you load the old version so
  8567. // that it is re-backed up.
  8568. //
  8569. // We search for all the data history files only, then we sort them
  8570. // in ascending order, then we delete the old ones along with their
  8571. // schema files.
  8572. //
  8573. //
  8574. // Search for all the data history files.
  8575. //
  8576. hFind = FindFirstFileW(g_wszHistoryFileSearchString, &FileData);
  8577. if (hFind == INVALID_HANDLE_VALUE)
  8578. {
  8579. hr = HRESULT_FROM_WIN32(GetLastError());
  8580. DBGINFOW((DBG_CONTEXT,
  8581. L"[CleanupObsoleteHistoryFiles] Unable find any old history files. FindFirstFileW on %s failed with hr = 0x%x.\n",
  8582. g_wszHistoryFileSearchString, hr));
  8583. goto exit;
  8584. }
  8585. do
  8586. {
  8587. //
  8588. // Extract the version number from the file name.
  8589. //
  8590. hr = ParseVersionNumber(FileData.cFileName,
  8591. g_cchRealFileNameWithoutPathWithoutExtension,
  8592. &ulVersionMinor,
  8593. &ulVersionMajor);
  8594. if(FAILED(hr))
  8595. {
  8596. //
  8597. // Assume invalid file and continue
  8598. //
  8599. DBGINFOW((DBG_CONTEXT,
  8600. L"[CleanupObsoleteHistoryFiles] Unable to parse version number from file name %s. This file will not be cleaned up.\n",
  8601. FileData.cFileName));
  8602. hr = S_OK;
  8603. continue;
  8604. }
  8605. //
  8606. // Save the last write timestamp.
  8607. //
  8608. ftLastWriteTime = FileData.ftLastWriteTime;
  8609. //
  8610. // Save the version number.
  8611. //
  8612. if(iVersion >= cVersions)
  8613. {
  8614. hr = ReAllocateFileData(iVersion,
  8615. &aOldVersions,
  8616. &cVersions,
  8617. &bReAlloced);
  8618. if(FAILED(hr))
  8619. {
  8620. goto exit;
  8621. }
  8622. }
  8623. aOldVersions[iVersion].ulVersionMinor = ulVersionMinor;
  8624. aOldVersions[iVersion].ulVersionMajor = ulVersionMajor;
  8625. aOldVersions[iVersion].ftLastWriteTime = ftLastWriteTime;
  8626. iVersion++;
  8627. }while (FindNextFileW(hFind, &FileData));
  8628. if (hFind != INVALID_HANDLE_VALUE)
  8629. {
  8630. FindClose(hFind);
  8631. hFind = INVALID_HANDLE_VALUE;
  8632. }
  8633. //
  8634. // Check to see if there are any history files with the same major version and a
  8635. // non-zero minor version, if so delete the non-zero minor versions. This
  8636. // can happen when someone restores from an old history file. Make sure
  8637. // this cleanup happens first so that we are in a state where timestamps
  8638. // of all non-zero minor versions are greater that the zero minor versions.
  8639. //
  8640. for (ULONG i=0; i< iVersion; i++ )
  8641. {
  8642. if((aOldVersions[i].ulVersionMajor == i_ulHistoryMajorVersionNumber) &&
  8643. (aOldVersions[i].ulVersionMinor != 0)
  8644. )
  8645. {
  8646. //
  8647. // Delete data history file first. We create a data file with a
  8648. // non-zero minor number when a text edit takes place and we
  8649. // have successfully applied the text edit to memory.
  8650. //
  8651. hr = DeleteHistoryFile(g_wszHistoryFileDir,
  8652. g_cchHistoryFileDir,
  8653. g_wszRealFileNameWithoutPathWithoutExtension,
  8654. g_cchRealFileNameWithoutPathWithoutExtension,
  8655. g_wszRealFileNameExtension,
  8656. g_cchRealFileNameExtension,
  8657. aOldVersions[i].ulVersionMajor,
  8658. aOldVersions[i].ulVersionMinor);
  8659. if(SUCCEEDED(hr))
  8660. {
  8661. //
  8662. // Delete schema file next
  8663. //
  8664. hr = DeleteHistoryFile(g_wszHistoryFileDir,
  8665. g_cchHistoryFileDir,
  8666. g_wszSchemaFileNameWithoutPathWithoutExtension,
  8667. g_cchSchemaFileNameWithoutPathWithoutExtension,
  8668. g_wszSchemaFileNameExtension,
  8669. g_cchSchemaFileNameExtension,
  8670. aOldVersions[i].ulVersionMajor,
  8671. aOldVersions[i].ulVersionMinor);
  8672. }
  8673. }
  8674. }
  8675. if ( iVersion > i_dwMaxHistoryFiles )
  8676. {
  8677. ULONG cDeleted = 0;
  8678. ULONG cNeedDeleted = iVersion-i_dwMaxHistoryFiles;
  8679. //
  8680. // Exceeded max history files -
  8681. // Delete old history files i.e. the first dwMaxHistoryFiles - cFile
  8682. //
  8683. qsort((void*)aOldVersions, iVersion, sizeof(METABASE_FILE_DATA), MyCompareFileData);
  8684. for (ULONG i=0; cDeleted<cNeedDeleted && i<iVersion ; i++ )
  8685. {
  8686. if(aOldVersions[i].ulVersionMajor == i_ulHistoryMajorVersionNumber)
  8687. {
  8688. //
  8689. // Do not cleanup the file you just created.
  8690. //
  8691. continue;
  8692. }
  8693. else
  8694. {
  8695. //
  8696. // Delete data history file first
  8697. //
  8698. hr = DeleteHistoryFile(g_wszHistoryFileDir,
  8699. g_cchHistoryFileDir,
  8700. g_wszRealFileNameWithoutPathWithoutExtension,
  8701. g_cchRealFileNameWithoutPathWithoutExtension,
  8702. g_wszRealFileNameExtension,
  8703. g_cchRealFileNameExtension,
  8704. aOldVersions[i].ulVersionMajor,
  8705. aOldVersions[i].ulVersionMinor);
  8706. if(SUCCEEDED(hr))
  8707. {
  8708. //
  8709. // Delete schema file next
  8710. //
  8711. cDeleted++;
  8712. hr = DeleteHistoryFile(g_wszHistoryFileDir,
  8713. g_cchHistoryFileDir,
  8714. g_wszSchemaFileNameWithoutPathWithoutExtension,
  8715. g_cchSchemaFileNameWithoutPathWithoutExtension,
  8716. g_wszSchemaFileNameExtension,
  8717. g_cchSchemaFileNameExtension,
  8718. aOldVersions[i].ulVersionMajor,
  8719. aOldVersions[i].ulVersionMinor);
  8720. }
  8721. }
  8722. } // End loop for all history files, delete the oldest (see rules in comment)
  8723. } // End if the number of histor files exceeds the max history file count.
  8724. exit:
  8725. if((aOldVersionsFixed != aOldVersions) && (NULL != aOldVersions))
  8726. {
  8727. delete [] aOldVersions;
  8728. aOldVersions = NULL;
  8729. cVersions = 0;
  8730. }
  8731. if (hFind != INVALID_HANDLE_VALUE)
  8732. {
  8733. FindClose(hFind);
  8734. hFind = INVALID_HANDLE_VALUE;
  8735. }
  8736. return hr;
  8737. } // CleanupObsoleteHistoryFiles
  8738. HRESULT ParseVersionNumber(LPWSTR i_wszFileName,
  8739. ULONG i_cchFileNameUntilFirstUnderscore,
  8740. ULONG* o_ulVersionMinor,
  8741. ULONG* o_ulVersionMajor)
  8742. /*
  8743. ++
  8744. Routine Description:
  8745. Parses the major and minor history version numbers from the file name.
  8746. The file name can be the full path to the hisory file or the file name
  8747. only.
  8748. Eg:
  8749. D:\Winnt\system32\inetsrv\History\Metabase_0000000001_0000000001.XML
  8750. Metabase_0000000001_0000000001.XML
  8751. Arguments:
  8752. History file name (full path to file name or just file name). The file
  8753. name cannot contain wild chars ?????????? for version numbers.
  8754. Count of chars in the history file name upto the fist underscore.
  8755. Return - Major history version number
  8756. Return - Minor history version number
  8757. Return Value:
  8758. HRESULT - S_OK
  8759. HRESULT_FROM_WIN32(ERROR_INVALID_NAME)
  8760. Notes:
  8761. --*/
  8762. {
  8763. HRESULT hr = S_OK;
  8764. ULONG ulVersionMinor = 0;
  8765. ULONG ulVersionMajor = 0;
  8766. //
  8767. // Look for the first underscore
  8768. //
  8769. if(i_wszFileName[i_cchFileNameUntilFirstUnderscore] != MD_CH_UNDERSCOREW)
  8770. {
  8771. hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  8772. goto exit;
  8773. }
  8774. LPWSTR pCur = &(i_wszFileName[i_cchFileNameUntilFirstUnderscore]);
  8775. for(ULONG i = 0; i < 2; i++)
  8776. {
  8777. pCur = wcschr(pCur, L'_');
  8778. if(pCur == NULL)
  8779. {
  8780. hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  8781. goto exit;
  8782. }
  8783. pCur++;
  8784. if( !WstrToUl(
  8785. pCur,
  8786. (i == 0) ? L'_' : L'.',
  8787. (i == 0) ? &ulVersionMajor : &ulVersionMinor) )
  8788. {
  8789. hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  8790. goto exit;
  8791. }
  8792. }
  8793. if(NULL != o_ulVersionMinor)
  8794. {
  8795. *o_ulVersionMinor = ulVersionMinor;
  8796. }
  8797. if(NULL != o_ulVersionMajor)
  8798. {
  8799. *o_ulVersionMajor = ulVersionMajor;
  8800. }
  8801. exit:
  8802. if(FAILED(hr))
  8803. {
  8804. DBGINFOW((DBG_CONTEXT,
  8805. L"[ParseVersionNumber] Invalid file name %s.\n",
  8806. i_wszFileName));
  8807. }
  8808. return hr;
  8809. }
  8810. HRESULT
  8811. ParseVersionNumber(IN LPWSTR i_wszFileName,
  8812. IN OUT DWORD* io_pdwMinor,
  8813. IN OUT DWORD* io_pdwMajor)
  8814. /*++
  8815. Synopsis:
  8816. Overloaded version of ParseVersionNumber that will figure out
  8817. i_cchFileNameUntilFirstUnderscore,
  8818. Arguments: [i_wszFileName] - filename formatted as blah_major_minor.xml
  8819. [io_pdwMinor] -
  8820. [io_pdwMajor] -
  8821. Return Value:
  8822. --*/
  8823. {
  8824. MD_ASSERT(i_wszFileName);
  8825. MD_ASSERT(io_pdwMinor);
  8826. MD_ASSERT(io_pdwMajor);
  8827. ULONG iNrUnderscoresSeen = 0;
  8828. LPWSTR pEnd = i_wszFileName + wcslen(i_wszFileName);
  8829. for(; pEnd >= i_wszFileName; pEnd--)
  8830. {
  8831. if(*pEnd == L'_')
  8832. {
  8833. iNrUnderscoresSeen++;
  8834. }
  8835. if(iNrUnderscoresSeen == 2)
  8836. {
  8837. break;
  8838. }
  8839. }
  8840. if(iNrUnderscoresSeen != 2)
  8841. {
  8842. return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  8843. }
  8844. return ParseVersionNumber(
  8845. i_wszFileName,
  8846. (ULONG)(pEnd - i_wszFileName),
  8847. io_pdwMinor,
  8848. io_pdwMajor);
  8849. }
  8850. HRESULT DeleteHistoryFile(LPWSTR i_wszHistroyFileDir,
  8851. ULONG i_cchHistoryFileDir,
  8852. LPWSTR i_wszFileNameWithoutPathWithoutExtension,
  8853. ULONG i_cchFileNameWithoutPathWithoutExtension,
  8854. LPWSTR i_wszFileNameExtension,
  8855. ULONG i_cchFileNameExtension,
  8856. ULONG i_ulVersionMajor,
  8857. ULONG i_ulVersionMinor)
  8858. {
  8859. LPWSTR wszDeleteFileName = NULL;
  8860. HRESULT hr = S_OK;
  8861. hr = ConstructHistoryFileName(&wszDeleteFileName,
  8862. i_wszHistroyFileDir,
  8863. i_cchHistoryFileDir,
  8864. i_wszFileNameWithoutPathWithoutExtension,
  8865. i_cchFileNameWithoutPathWithoutExtension,
  8866. i_wszFileNameExtension,
  8867. i_cchFileNameExtension,
  8868. i_ulVersionMajor,
  8869. i_ulVersionMinor);
  8870. if(FAILED(hr))
  8871. {
  8872. DBGINFOW((DBG_CONTEXT,
  8873. L"[DeleteHistoryFile] Unable to cleanup history files. ConstructHistoryFileName failed with hr = 0x%x.\n",
  8874. hr));
  8875. return hr;
  8876. }
  8877. if(!DeleteFileW(wszDeleteFileName))
  8878. {
  8879. hr = HRESULT_FROM_WIN32(GetLastError());
  8880. DBGINFOW((DBG_CONTEXT,
  8881. L"[DeleteHistoryFile] Unable to cleanup history file: %s. DeleteFileW failed with hr = 0x%x.\n",
  8882. wszDeleteFileName, hr));
  8883. }
  8884. delete [] wszDeleteFileName;
  8885. wszDeleteFileName = NULL;
  8886. return hr;
  8887. }
  8888. HRESULT
  8889. GetGlobalValue(ISimpleTableRead2* pISTProperty,
  8890. LPCWSTR wszName,
  8891. ULONG* pcbSize,
  8892. LPVOID* ppVoid)
  8893. {
  8894. LPWSTR wszPath = L".";
  8895. DWORD dwGroup = eMBProperty_IIS_Global;
  8896. return GetValue(pISTProperty,
  8897. wszPath,
  8898. dwGroup,
  8899. wszName,
  8900. pcbSize,
  8901. ppVoid);
  8902. }
  8903. HRESULT
  8904. GetComputerValue(ISimpleTableRead2* pISTProperty,
  8905. LPCWSTR wszName,
  8906. ULONG* pcbSize,
  8907. LPVOID* ppVoid)
  8908. {
  8909. LPWSTR wszPath = L"/LM";
  8910. DWORD dwGroup = eMBProperty_IIsComputer;
  8911. return GetValue(pISTProperty,
  8912. wszPath,
  8913. dwGroup,
  8914. wszName,
  8915. pcbSize,
  8916. ppVoid);
  8917. }
  8918. HRESULT
  8919. GetValue(ISimpleTableRead2* pISTProperty,
  8920. LPCWSTR wszPath,
  8921. DWORD dwGroup,
  8922. LPCWSTR wszName,
  8923. ULONG* pcbSize,
  8924. LPVOID* ppVoid)
  8925. {
  8926. HRESULT hr = S_OK;
  8927. ULONG iRow = 0;
  8928. ULONG iColumn = iMBProperty_Value;
  8929. LPVOID aIdentity[] = {(LPVOID)(LPWSTR)wszName,
  8930. (LPVOID)(LPWSTR)wszPath,
  8931. &dwGroup};
  8932. *ppVoid = NULL;
  8933. hr = pISTProperty->GetRowIndexByIdentity(NULL,
  8934. aIdentity,
  8935. &iRow);
  8936. if(E_ST_NOMOREROWS == hr)
  8937. {
  8938. //
  8939. // Perhaps key type was not present and hence it may be custom
  8940. //
  8941. dwGroup = eMBProperty_Custom;
  8942. hr = pISTProperty->GetRowIndexByIdentity(NULL,
  8943. aIdentity,
  8944. &iRow);
  8945. if(E_ST_NOMOREROWS == hr)
  8946. {
  8947. dwGroup = eMBProperty_IIsConfigObject;
  8948. hr = pISTProperty->GetRowIndexByIdentity(NULL,
  8949. aIdentity,
  8950. &iRow);
  8951. }
  8952. }
  8953. if(FAILED(hr))
  8954. {
  8955. return hr;
  8956. }
  8957. hr = pISTProperty->GetColumnValues(iRow,
  8958. 1,
  8959. &iColumn,
  8960. pcbSize,
  8961. (LPVOID*)ppVoid);
  8962. return hr;
  8963. }
  8964. HRESULT
  8965. InitializeIIS6GlobalsToDefaults(ULONG dwPrevSchemaChangeNumber,
  8966. ULONG dwSchemaChangeNumber,
  8967. LPSTR pszBackupLocation)
  8968. {
  8969. ISimpleTableDispenser2* pISTDisp = NULL;
  8970. IMetabaseSchemaCompiler* pCompiler = NULL;
  8971. HRESULT hr = S_OK;
  8972. //
  8973. // This is used to initialize the following global properties to their
  8974. // defaults. Note that these are global properties that were introduced
  8975. // in IIS60. Hence this function needs to be called from ReadAllDataFromBin
  8976. // else these properties will not be initialized during an upgrade scenario
  8977. // ie. from IIS50/51 to IIS60 when you read from a bin file, in the absence
  8978. // of the XML file. It ned to be called from ReadAllDataFromXML as well so
  8979. // that they can be initialized correctly.
  8980. //
  8981. g_dwEnableEditWhileRunning = 0;
  8982. g_ulHistoryMajorVersionNumber = 0;
  8983. g_dwEnableHistory = TRUE;
  8984. g_dwMaxHistoryFiles = MD_COUNT_MAX_HISTORY_FILES;
  8985. g_dwMaxErrorFiles = MD_COUNT_MAX_ERROR_FILES;
  8986. g_dwSchemaChangeNumber = dwSchemaChangeNumber;
  8987. g_dwLastSchemaChangeNumber = dwPrevSchemaChangeNumber;
  8988. if(NULL == pszBackupLocation)
  8989. {
  8990. //
  8991. // Initialize the global array containing file handles. The
  8992. // initialization is done here (one time only) because this if
  8993. // condition will evaluate one time only during service startup.
  8994. // Other times when this function is invoked is during restore
  8995. // - you can tell when restore is calling by checking
  8996. // pszBackupLocation which will be non null.
  8997. //
  8998. DBGINFOW((DBG_CONTEXT,
  8999. L"[InitializeIIS6GlobalsToDefaults] Initializing global file handle array.\n"));
  9000. for(ULONG i=0; i<cMetabaseFileTypes; i++)
  9001. {
  9002. g_ahMetabaseFile[i] = INVALID_HANDLE_VALUE;
  9003. }
  9004. }
  9005. //
  9006. // No need to initilize dispenser (InitializeSimpleTableDispenser()),
  9007. // because we now specify USE_CRT=1 in sources, which means that
  9008. // globals will be initialized.
  9009. //
  9010. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  9011. if(FAILED(hr))
  9012. {
  9013. DBGINFOW((DBG_CONTEXT,
  9014. L"[InitializeIIS6GlobalsToDefaults] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
  9015. goto exit;
  9016. }
  9017. //
  9018. // Always set the Bin path to point to the metabase directory.
  9019. // Even if ReadAllData* gets called with a different filename during restore,
  9020. // SetBinPath should always be set to the metabase directory
  9021. //
  9022. hr = pISTDisp->QueryInterface(IID_IMetabaseSchemaCompiler,
  9023. (LPVOID*)&pCompiler);
  9024. if(FAILED(hr))
  9025. {
  9026. DBGINFOW((DBG_CONTEXT,
  9027. L"[InitializeIIS6GlobalsToDefaults] QueryInterface on compiler failed with hr = 0x%x.\n",hr));
  9028. goto exit;
  9029. }
  9030. hr = pCompiler->SetBinPath(g_wszMetabaseDir);
  9031. if(FAILED(hr))
  9032. {
  9033. DBGINFOW((DBG_CONTEXT,
  9034. L"[InitializeIIS6GlobalsToDefaults] SetBinPath failed with hr = 0x%x.\n",hr));
  9035. goto exit;
  9036. }
  9037. exit:
  9038. if(NULL != pCompiler)
  9039. {
  9040. pCompiler->Release();
  9041. }
  9042. if(NULL != pISTDisp)
  9043. {
  9044. pISTDisp->Release();
  9045. }
  9046. return hr;
  9047. }
  9048. HRESULT
  9049. InitializeGlobalsFromXML(ISimpleTableRead2* pISTProperty,
  9050. LPWSTR wszDataFileName,
  9051. LPWSTR wszSchemaFileName,
  9052. IIS_CRYPTO_STORAGE** ppStorage,
  9053. LPTSTR pszPasswd,
  9054. BOOL bCalledFromRestore,
  9055. FILETIME *pftLastWriteTimeDataFile)
  9056. {
  9057. HRESULT hr = S_OK;
  9058. WIN32_FILE_ATTRIBUTE_DATA MBFileAttr;
  9059. //
  9060. // Currently, we are setting the Master root last change time to the
  9061. // timestamp on the metabase.xml file.
  9062. // TODO: Should this information be persisted as an attribute in
  9063. // the metabase.xml file, and should we read from it?
  9064. //
  9065. if(!GetFileAttributesExW(wszDataFileName,
  9066. GetFileExInfoStandard,
  9067. &MBFileAttr))
  9068. {
  9069. hr = HRESULT_FROM_WIN32(GetLastError());
  9070. DBGINFOW((DBG_CONTEXT,
  9071. L"[InitializeGlobalsFromXML] GetFileAttributesExW failed with hr = 0x%x.\n",
  9072. hr));
  9073. return hr;
  9074. }
  9075. else
  9076. {
  9077. if ( pftLastWriteTimeDataFile )
  9078. {
  9079. *pftLastWriteTimeDataFile = MBFileAttr.ftLastWriteTime;
  9080. }
  9081. //
  9082. // TODO: Is it sufficient if we only set the root filetime?
  9083. // IVANPASH: Fixing BUG 751131, it looks like setting only the root,
  9084. // could be sufficient if ReadSchema was not explicitely setting the LastChangeTime on every node.
  9085. // Now I return the ftLastWriteTime to the caller in pftLastWriteTimeDataFile.
  9086. //
  9087. g_pboMasterRoot->SetLastChangeTime( &MBFileAttr.ftLastWriteTime );
  9088. }
  9089. //
  9090. // Initialize session key before you read stuff in.
  9091. //
  9092. hr = InitSessionKey(pISTProperty,
  9093. ppStorage,
  9094. pszPasswd);
  9095. if(FAILED(hr))
  9096. {
  9097. return hr;
  9098. }
  9099. //
  9100. // Initialize enable edit while running before you read stuff in.
  9101. //
  9102. InitEditWhileRunning(pISTProperty);
  9103. //
  9104. // Initialize change number before you read stuff in.
  9105. // TODO: Should we migrate the change number when we migrate from .bin to .xml?
  9106. //
  9107. InitChangeNumber(pISTProperty);
  9108. //
  9109. // Initialize enable history - Should be called after InitEditWhileRunning
  9110. //
  9111. InitEnableHistory(pISTProperty,
  9112. wszDataFileName,
  9113. wszSchemaFileName,
  9114. bCalledFromRestore);
  9115. return hr; // Return failure code only if you want to exit.
  9116. }
  9117. HRESULT
  9118. SaveGlobalsToXML(CWriter* pCWriter,
  9119. PIIS_CRYPTO_BLOB pSessionKeyBlob,
  9120. bool bSessionKeyOnly)
  9121. {
  9122. HRESULT hr = S_OK;
  9123. CLocationWriter* pCLocationWriter = NULL;
  9124. LPWSTR wszGlobalLocation = L".";
  9125. LPWSTR wszKeyType = L"IIS_Global";
  9126. DWORD dwIdentifier;
  9127. DWORD dwDataType;
  9128. DWORD dwAttributes;
  9129. DWORD dwNumber;
  9130. DWORD dwUserType = IIS_MD_UT_SERVER;
  9131. hr = pCWriter->GetLocationWriter(&pCLocationWriter,
  9132. wszGlobalLocation);
  9133. if(FAILED(hr))
  9134. {
  9135. DBGINFOW((DBG_CONTEXT,
  9136. L"[SaveGlobalsToXML] GetLocationWriter failed with hr = 0x%x.\n",
  9137. hr));
  9138. goto exit;
  9139. }
  9140. hr = pCLocationWriter->InitializeKeyType(MD_KEY_TYPE,
  9141. METADATA_NO_ATTRIBUTES,
  9142. IIS_MD_UT_SERVER,
  9143. STRING_METADATA,
  9144. (PBYTE)wszKeyType,
  9145. (DWORD)((wcslen(wszKeyType)+1)*sizeof(WCHAR))
  9146. );
  9147. if(FAILED(hr))
  9148. {
  9149. DBGINFOW((DBG_CONTEXT,
  9150. L"[SaveGlobalsToXML] InitializeKeyType failed with hr = 0x%x.\n",
  9151. hr));
  9152. goto exit;
  9153. }
  9154. if(!bSessionKeyOnly)
  9155. {
  9156. //
  9157. // Change Number
  9158. //
  9159. dwIdentifier = MD_GLOBAL_CHANGE_NUMBER;
  9160. dwDataType = DWORD_METADATA;
  9161. dwAttributes = METADATA_NO_ATTRIBUTES;
  9162. hr = pCLocationWriter->AddProperty(dwIdentifier,
  9163. dwAttributes,
  9164. dwUserType,
  9165. dwDataType,
  9166. (PBYTE)&g_dwSystemChangeNumber,
  9167. sizeof(DWORD));
  9168. if(FAILED(hr))
  9169. {
  9170. DBGINFOW((DBG_CONTEXT,
  9171. L"[SaveGlobalsToXML] AddProperty for ID: %d failed with hr = 0x%x.\n",
  9172. dwIdentifier, hr));
  9173. goto exit;
  9174. }
  9175. //
  9176. // HistoryMajorVersionNumber
  9177. //
  9178. ComputeNewHistoryVersionNumber();
  9179. dwIdentifier = MD_GLOBAL_EDIT_WHILE_RUNNING_MAJOR_VERSION_NUMBER;
  9180. dwDataType = DWORD_METADATA;
  9181. dwAttributes = METADATA_NO_ATTRIBUTES;
  9182. dwNumber = g_ulHistoryMajorVersionNumber;
  9183. hr = pCLocationWriter->AddProperty(dwIdentifier,
  9184. dwAttributes,
  9185. dwUserType,
  9186. dwDataType,
  9187. (PBYTE)&dwNumber,
  9188. sizeof(DWORD));
  9189. if(FAILED(hr))
  9190. {
  9191. DBGINFOW((DBG_CONTEXT,
  9192. L"[SaveGlobalsToXML] AddProperty for ID: %d failed with hr = 0x%x.\n",
  9193. dwIdentifier, hr));
  9194. goto exit;
  9195. }
  9196. }
  9197. //
  9198. // Add SessionKey
  9199. //
  9200. dwIdentifier = MD_GLOBAL_SESSIONKEY;
  9201. dwDataType = BINARY_METADATA;
  9202. dwAttributes = METADATA_NO_ATTRIBUTES;
  9203. hr = pCLocationWriter->AddProperty(dwIdentifier,
  9204. dwAttributes,
  9205. dwUserType,
  9206. dwDataType,
  9207. (PBYTE)pSessionKeyBlob,
  9208. IISCryptoGetBlobLength(pSessionKeyBlob));
  9209. if(FAILED(hr))
  9210. {
  9211. DBGINFOW((DBG_CONTEXT,
  9212. L"[SaveGlobalsToXML] AddProperty for ID: %d failed with hr = 0x%x.\n",
  9213. dwIdentifier, hr));
  9214. goto exit;
  9215. }
  9216. if(!bSessionKeyOnly)
  9217. {
  9218. //
  9219. // Add XML Schema timestamp
  9220. //
  9221. dwIdentifier = MD_GLOBAL_XMLSCHEMATIMESTAMP;
  9222. dwDataType = BINARY_METADATA;
  9223. dwAttributes = METADATA_NO_ATTRIBUTES;
  9224. hr = pCLocationWriter->AddProperty(dwIdentifier,
  9225. dwAttributes,
  9226. dwUserType,
  9227. dwDataType,
  9228. (PBYTE)&g_XMLSchemaFileTimeStamp,
  9229. sizeof(FILETIME));
  9230. if(FAILED(hr))
  9231. {
  9232. DBGINFOW((DBG_CONTEXT,
  9233. L"[SaveGlobalsToXML] AddProperty for ID: %d failed with hr = 0x%x.\n",
  9234. dwIdentifier, hr));
  9235. goto exit;
  9236. }
  9237. //
  9238. // Add XML Schema timestamp
  9239. //
  9240. dwIdentifier = MD_GLOBAL_BINSCHEMATIMESTAMP;
  9241. dwDataType = BINARY_METADATA;
  9242. dwAttributes = METADATA_NO_ATTRIBUTES;
  9243. hr = pCLocationWriter->AddProperty(dwIdentifier,
  9244. dwAttributes,
  9245. dwUserType,
  9246. dwDataType,
  9247. (PBYTE)&g_BINSchemaFileTimeStamp,
  9248. sizeof(FILETIME));
  9249. if(FAILED(hr))
  9250. {
  9251. DBGINFOW((DBG_CONTEXT,
  9252. L"[SaveGlobalsToXML] AddProperty for ID: %d failed with hr = 0x%x.\n",
  9253. dwIdentifier, hr));
  9254. goto exit;
  9255. }
  9256. }
  9257. hr = pCLocationWriter->WriteLocation(TRUE);
  9258. if(FAILED(hr))
  9259. {
  9260. DBGINFOW((DBG_CONTEXT,
  9261. L"[SaveGlobalsToXML] WriteLocation failed with hr = 0x%x.\n",
  9262. hr));
  9263. goto exit;
  9264. }
  9265. exit:
  9266. if(NULL != pCLocationWriter)
  9267. {
  9268. delete pCLocationWriter;
  9269. pCLocationWriter = NULL;
  9270. }
  9271. return hr;
  9272. }
  9273. //
  9274. // Added by Mohit (10/00)
  9275. //
  9276. //********** Utilities **********//
  9277. HRESULT
  9278. RemoveLastPartOfPath(
  9279. IN OUT LPWSTR io_wszPath,
  9280. IN int i_iLen)
  9281. /*++
  9282. Routine Description:
  9283. Removes last part of absolute path.
  9284. Ex: "/LM/w3svc/" -> "/LM/"
  9285. "/LM/w3svc" -> "/LM/"
  9286. "/LM" -> "/"
  9287. "/" -> "/"
  9288. Arguments:
  9289. wszPath - The absolute path (null terminated).
  9290. iLen - The length of the string in chars
  9291. (not including null termination)
  9292. Return Value:
  9293. HRESULT - ERROR_SUCCESS
  9294. ERROR_INVALID_NAME
  9295. Notes:
  9296. --*/
  9297. {
  9298. MD_ASSERT(io_wszPath != NULL);
  9299. bool bCharSeen = false;
  9300. HRESULT hr = RETURNCODETOHRESULT(ERROR_INVALID_NAME);
  9301. for(int i = i_iLen-1; i>=0; i--)
  9302. {
  9303. if(io_wszPath[i] == MD_PATH_DELIMETERW)
  9304. {
  9305. hr = RETURNCODETOHRESULT(ERROR_SUCCESS);
  9306. if(bCharSeen)
  9307. break;
  9308. }
  9309. else
  9310. {
  9311. bCharSeen = true;
  9312. }
  9313. io_wszPath[i] = L'\0';
  9314. }
  9315. if(io_wszPath[0] == L'\0' && i_iLen > 0)
  9316. {
  9317. io_wszPath[0] = MD_PATH_DELIMETERW;
  9318. io_wszPath[1] = L'\0';
  9319. }
  9320. return hr;
  9321. }
  9322. HRESULT
  9323. GetMostRecentHistoryFile(
  9324. LPCWSTR i_wszPattern,
  9325. DWORD* io_pdwMajor,
  9326. DWORD* io_pdwMinor)
  9327. {
  9328. MD_ASSERT(i_wszPattern != NULL);
  9329. MD_ASSERT(io_pdwMajor != NULL);
  9330. MD_ASSERT(io_pdwMinor != NULL);
  9331. HRESULT hr = S_OK;
  9332. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  9333. WIN32_FIND_DATAW fdCur;
  9334. WIN32_FIND_DATAW fdMostRecent;
  9335. DWORD dwMajor = 0;
  9336. DWORD dwMinor = 0;
  9337. DWORD dwError;
  9338. bool bMatch = false;
  9339. hFindFile = FindFirstFileW(i_wszPattern, &fdCur);
  9340. if(hFindFile == INVALID_HANDLE_VALUE)
  9341. {
  9342. dwError = GetLastError();
  9343. hr = RETURNCODETOHRESULT(dwError);
  9344. // printf("[%s: Line %d] hr=0x%x\n", __FILE__, __LINE__, hr);
  9345. goto exit;
  9346. }
  9347. do
  9348. {
  9349. if( !bMatch ||
  9350. (bMatch && CompareFileTime(&fdCur.ftLastWriteTime, &fdMostRecent.ftLastWriteTime) > 0) )
  9351. {
  9352. hr = ParseVersionNumber(
  9353. fdCur.cFileName,
  9354. &dwMinor,
  9355. &dwMajor);
  9356. if(SUCCEEDED(hr))
  9357. {
  9358. bMatch = true;
  9359. memcpy(&fdMostRecent, &fdCur, sizeof(WIN32_FIND_DATA));
  9360. }
  9361. hr = S_OK;
  9362. }
  9363. }
  9364. while(FindNextFileW(hFindFile, &fdCur));
  9365. if(!bMatch)
  9366. {
  9367. hr = RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND);
  9368. goto exit;
  9369. }
  9370. hr = ParseVersionNumber(
  9371. fdMostRecent.cFileName,
  9372. &dwMinor,
  9373. &dwMajor);
  9374. if(FAILED(hr))
  9375. {
  9376. goto exit;
  9377. }
  9378. *io_pdwMajor = dwMajor;
  9379. *io_pdwMinor = dwMinor;
  9380. exit:
  9381. if(hFindFile != INVALID_HANDLE_VALUE)
  9382. {
  9383. FindClose(hFindFile);
  9384. }
  9385. return hr;
  9386. }
  9387. //******** Meat *********//
  9388. HRESULT
  9389. SaveInheritedOnly(IN CWriter* i_pCWriter,
  9390. IN CMDBaseObject* i_pboRoot,
  9391. IN BUFFER* i_pbufParentPath,
  9392. IN IIS_CRYPTO_STORAGE* i_pCryptoStorage,
  9393. IN PIIS_CRYPTO_BLOB i_pSessionKeyBlob)
  9394. /*++
  9395. Routine Description:
  9396. Save a node, either with or w/o inherited properties.
  9397. Arguments:
  9398. Root - The root of the tree to save.
  9399. CryptoStorage - Used to encrypt secure data.
  9400. Return Value:
  9401. DWORD - ERROR_SUCCESS
  9402. Return codes from file system
  9403. Notes:
  9404. --*/
  9405. {
  9406. MD_ASSERT(i_pbufParentPath->QueryPtr() != NULL);
  9407. HRESULT hresReturn = S_OK;
  9408. DWORD cchParentPath = (DWORD)wcslen((LPCWSTR)i_pbufParentPath->QueryPtr());
  9409. DWORD cchName = 0;
  9410. DWORD cchNewParentPath = 0; // consists of parent and name
  9411. LPWSTR wszNewParentPath = NULL;
  9412. LPWSTR pCur = NULL;
  9413. FILETIME* pftTime = NULL;
  9414. CLocationWriter* pCLocationWriter = NULL;
  9415. CMDBaseData* dataAssociatedData = NULL;
  9416. DWORD dwEnumObjectIndex = 0;
  9417. //
  9418. // Construct the location (i.e. inherited:/LM/w3svc/1)
  9419. //
  9420. if(i_pboRoot->GetName(TRUE) == NULL)
  9421. {
  9422. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  9423. DBGERROR((DBG_CONTEXT, "Out of memory\n"));
  9424. goto exit;
  9425. }
  9426. cchName = (DWORD)wcslen((LPWSTR)i_pboRoot->GetName(TRUE));
  9427. cchNewParentPath =
  9428. CImporter::sm_cchInheritedPropertiesLocationPrefix +
  9429. cchParentPath +
  9430. cchName +
  9431. 2; // terminating slash + null terminator
  9432. wszNewParentPath = new WCHAR[cchNewParentPath];
  9433. if(wszNewParentPath == NULL)
  9434. {
  9435. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  9436. DBGERROR((DBG_CONTEXT, "Out of memory\n"));
  9437. goto exit;
  9438. }
  9439. pCur = wszNewParentPath;
  9440. memcpy(
  9441. pCur,
  9442. CImporter::sm_wszInheritedPropertiesLocationPrefix,
  9443. sizeof(WCHAR) * CImporter::sm_cchInheritedPropertiesLocationPrefix);
  9444. pCur += CImporter::sm_cchInheritedPropertiesLocationPrefix;
  9445. memcpy(pCur, i_pbufParentPath->QueryPtr(), sizeof(WCHAR) * cchParentPath);
  9446. pCur += cchParentPath;
  9447. if(i_pboRoot != g_pboMasterRoot)
  9448. {
  9449. memcpy(pCur, i_pboRoot->GetName(TRUE), sizeof(WCHAR) * cchName);
  9450. pCur += cchName;
  9451. *pCur = MD_PATH_DELIMETERW;
  9452. pCur += 1;
  9453. *pCur = L'\0';
  9454. }
  9455. pftTime = i_pboRoot->GetLastChangeTime();
  9456. //
  9457. // Fetch the location writer
  9458. //
  9459. hresReturn = i_pCWriter->GetLocationWriter(&pCLocationWriter, wszNewParentPath);
  9460. if(FAILED(hresReturn))
  9461. {
  9462. DBGERROR((DBG_CONTEXT, "GetLocationWriter failed [0x%x]\n", hresReturn));
  9463. goto exit;
  9464. }
  9465. hresReturn = pCLocationWriter->InitializeKeyTypeAsInherited();
  9466. if(FAILED(hresReturn))
  9467. {
  9468. DBGERROR((DBG_CONTEXT, "InitializeKeyTypeAsInherited failed [0x%x]\n", hresReturn));
  9469. goto exit;
  9470. }
  9471. for(dwEnumObjectIndex=0; ; dwEnumObjectIndex++)
  9472. {
  9473. DWORD dwTemp = dwEnumObjectIndex;
  9474. CMDBaseObject* pboTemp = NULL;
  9475. dataAssociatedData = i_pboRoot->EnumInheritableDataObject(
  9476. /*ref*/ dwTemp,
  9477. ALL_METADATA,
  9478. ALL_METADATA,
  9479. &pboTemp);
  9480. //
  9481. // No more data
  9482. //
  9483. if(dataAssociatedData == NULL)
  9484. {
  9485. break;
  9486. }
  9487. //
  9488. // Only save property if it's inherited
  9489. //
  9490. if(pboTemp != i_pboRoot)
  9491. {
  9492. hresReturn = SaveDataObject(
  9493. dataAssociatedData,
  9494. pCLocationWriter,
  9495. i_pCryptoStorage,
  9496. i_pSessionKeyBlob);
  9497. if(FAILED(hresReturn))
  9498. {
  9499. DBGERROR((DBG_CONTEXT, "SaveDataObject failed [0x%x]\n", hresReturn));
  9500. goto exit;
  9501. }
  9502. }
  9503. }
  9504. hresReturn = pCLocationWriter->WriteLocation(TRUE);
  9505. if(FAILED(hresReturn))
  9506. {
  9507. DBGERROR((DBG_CONTEXT, "WriteLocation failed [0x%x]\n", hresReturn));
  9508. goto exit;
  9509. }
  9510. exit:
  9511. delete pCLocationWriter;
  9512. pCLocationWriter = NULL;
  9513. delete [] wszNewParentPath;
  9514. wszNewParentPath = NULL;
  9515. return hresReturn;
  9516. }
  9517. HRESULT
  9518. SaveSomeData(
  9519. IN BOOL i_bSaveInherited,
  9520. IN BOOL i_bSaveNodeOnly,
  9521. IN BOOL i_bOverwriteFile,
  9522. IN IIS_CRYPTO_STORAGE* i_pCryptoStorage,
  9523. IN PIIS_CRYPTO_BLOB i_pSessionKeyBlob,
  9524. IN LPCWSTR i_wszBackupLocation,
  9525. IN METADATA_HANDLE i_hHandle,
  9526. IN LPCWSTR i_wszSourcePath,
  9527. IN BOOL i_bHaveReadSaveSemaphore
  9528. )
  9529. /*++
  9530. Routine Description:
  9531. Saves some meta data (used by export).
  9532. Arguments:
  9533. i_wszSourcePath - This is absolute (not relative to handle). We need
  9534. it for SaveTree()
  9535. Return Value:
  9536. HRESULT - ERROR_SUCCESS
  9537. ERROR_NOT_ENOUGH_MEMORY
  9538. Return codes from file system
  9539. Notes:
  9540. --*/
  9541. {
  9542. MD_ASSERT(i_wszBackupLocation != NULL);
  9543. if(!i_bOverwriteFile)
  9544. {
  9545. return RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
  9546. }
  9547. HRESULT hresReturn = ERROR_SUCCESS;
  9548. //
  9549. // Stores i_wszSourcePath as unicode (i.e. /LM/w3svc/1)
  9550. // Passed to SaveTree
  9551. //
  9552. BUFFER bufParentPath;
  9553. //
  9554. // Handle of the source path
  9555. //
  9556. CMDHandle* phoHandle = NULL;
  9557. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  9558. LPWSTR wszTempFile = NULL;
  9559. BOOL bTempFileOpen = false;
  9560. BOOL bMRLock = false;
  9561. DWORD dwError;
  9562. if(!i_bHaveReadSaveSemaphore)
  9563. {
  9564. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  9565. }
  9566. if(wcschr(i_wszBackupLocation, L'\\') == NULL)
  9567. {
  9568. hresReturn = RETURNCODETOHRESULT(ERROR_FILE_INVALID);
  9569. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9570. goto exit;
  9571. }
  9572. g_LockMasterResource.ReadLock();
  9573. bMRLock = true;
  9574. hresReturn = GetUnicodeName(g_strTempFileName->QueryStr(), &wszTempFile);
  9575. if(FAILED(hresReturn))
  9576. {
  9577. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9578. goto exit;
  9579. }
  9580. //
  9581. // TODO: Investigate if I actually need to check this.
  9582. //
  9583. if(g_bSaveDisallowed)
  9584. {
  9585. hresReturn = RETURNCODETOHRESULT(ERROR_SHUTDOWN_IN_PROGRESS);
  9586. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9587. goto exit;
  9588. }
  9589. //
  9590. // Write to a temp file first in case there are errors.
  9591. //
  9592. SECURITY_ATTRIBUTES saStorage;
  9593. if (g_psdStorage != NULL)
  9594. {
  9595. saStorage.nLength = sizeof(SECURITY_ATTRIBUTES);
  9596. saStorage.lpSecurityDescriptor = g_psdStorage;
  9597. saStorage.bInheritHandle = FALSE;
  9598. }
  9599. hTempFile = CreateFileW(
  9600. wszTempFile,
  9601. GENERIC_READ | GENERIC_WRITE,
  9602. 0,
  9603. &saStorage,
  9604. OPEN_ALWAYS,
  9605. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  9606. 0);
  9607. if (hTempFile == INVALID_HANDLE_VALUE)
  9608. {
  9609. dwError = GetLastError();
  9610. hresReturn = RETURNCODETOHRESULT(dwError);
  9611. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9612. goto exit;
  9613. }
  9614. bTempFileOpen = true;
  9615. //
  9616. // Validate source handle
  9617. //
  9618. phoHandle = GetHandleObject(i_hHandle);
  9619. if(phoHandle == NULL)
  9620. {
  9621. hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE);
  9622. }
  9623. else if(!phoHandle->IsReadAllowed() && !phoHandle->IsWriteAllowed())
  9624. {
  9625. hresReturn = RETURNCODETOHRESULT(ERROR_ACCESS_DENIED);
  9626. }
  9627. else if(phoHandle->IsSchemaHandle())
  9628. {
  9629. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_SUPPORTED);
  9630. }
  9631. if(FAILED(hresReturn))
  9632. {
  9633. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9634. goto exit;
  9635. }
  9636. //
  9637. // Doctor up i_wszSourcePath and put it in pbufParentPath
  9638. //
  9639. int cchSourcePath = (int)wcslen(i_wszSourcePath);
  9640. if( !bufParentPath.Resize( sizeof(WCHAR)*(cchSourcePath+2)) )
  9641. {
  9642. dwError = GetLastError();
  9643. hresReturn = RETURNCODETOHRESULT(dwError);
  9644. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9645. goto exit;
  9646. }
  9647. LPWSTR wszPathNew = (LPWSTR)bufParentPath.QueryPtr();
  9648. if(i_wszSourcePath[0] == L'\0')
  9649. {
  9650. wszPathNew[0] = MD_PATH_DELIMETERW;
  9651. wszPathNew[1] = L'\0';
  9652. }
  9653. else
  9654. {
  9655. for(int i = 0; i < cchSourcePath; i++)
  9656. {
  9657. wszPathNew[i] = (i_wszSourcePath[i] == MD_ALT_PATH_DELIMETERW) ?
  9658. MD_PATH_DELIMETERW : i_wszSourcePath[i];
  9659. }
  9660. wszPathNew[i] = L'\0';
  9661. hresReturn = RemoveLastPartOfPath((LPWSTR)bufParentPath.QueryPtr(), cchSourcePath);
  9662. if(FAILED(hresReturn))
  9663. {
  9664. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9665. goto exit;
  9666. }
  9667. }
  9668. //
  9669. // Walk thru metabase and actually do the writing
  9670. //
  9671. DBGINFOW((DBG_CONTEXT,
  9672. L"[SaveSchema] Initializing writer with write file: %s bin file: %s.\n",
  9673. g_wszTempFileName,
  9674. g_pGlobalISTHelper->m_wszBinFileForMeta));
  9675. {
  9676. //
  9677. // Inside {} because we need to call CWriter's destructor to flush the file.
  9678. //
  9679. CWriter writer;
  9680. hresReturn = writer.Initialize(
  9681. wszTempFile,
  9682. g_pGlobalISTHelper,
  9683. hTempFile);
  9684. if(FAILED(hresReturn))
  9685. {
  9686. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9687. goto exit;
  9688. }
  9689. hresReturn = writer.BeginWrite(eWriter_Metabase);
  9690. if(FAILED(hresReturn))
  9691. {
  9692. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9693. goto exit;
  9694. }
  9695. hresReturn = SaveGlobalsToXML(
  9696. &writer,
  9697. i_pSessionKeyBlob,
  9698. true); // session key only
  9699. if(FAILED(hresReturn))
  9700. {
  9701. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9702. goto exit;
  9703. }
  9704. hresReturn = SaveTree(&writer,
  9705. phoHandle->GetObject(),
  9706. &bufParentPath,
  9707. i_pCryptoStorage,
  9708. i_pSessionKeyBlob,
  9709. !i_bSaveNodeOnly,
  9710. false /* do not save schema node */);
  9711. if(FAILED(hresReturn))
  9712. {
  9713. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9714. goto exit;
  9715. }
  9716. if(i_bSaveInherited)
  9717. {
  9718. hresReturn = SaveInheritedOnly(&writer,
  9719. phoHandle->GetObject(),
  9720. &bufParentPath,
  9721. i_pCryptoStorage,
  9722. i_pSessionKeyBlob);
  9723. }
  9724. if(FAILED(hresReturn))
  9725. {
  9726. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9727. goto exit;
  9728. }
  9729. hresReturn = writer.EndWrite(eWriter_Metabase);
  9730. if(FAILED(hresReturn))
  9731. {
  9732. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9733. goto exit;
  9734. }
  9735. }
  9736. g_LockMasterResource.ReadUnlock();
  9737. bMRLock = false;
  9738. if(!CloseHandle(hTempFile))
  9739. {
  9740. dwError = GetLastError();
  9741. hresReturn = RETURNCODETOHRESULT(dwError);
  9742. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9743. goto exit;
  9744. }
  9745. bTempFileOpen = false;
  9746. //
  9747. // Temp file created successfully. Finally, move temp to real
  9748. // Real may be on another machine, so we need to impersonate.
  9749. //
  9750. hresReturn = CoImpersonateClient();
  9751. if(FAILED(hresReturn))
  9752. {
  9753. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9754. goto exit;
  9755. }
  9756. if(!MoveFileExW(wszTempFile, i_wszBackupLocation,
  9757. MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
  9758. {
  9759. dwError = GetLastError();
  9760. hresReturn = RETURNCODETOHRESULT(dwError);
  9761. }
  9762. CoRevertToSelf();
  9763. if(FAILED(hresReturn))
  9764. {
  9765. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hresReturn));
  9766. goto exit;
  9767. }
  9768. exit:
  9769. if(bMRLock)
  9770. {
  9771. g_LockMasterResource.ReadUnlock();
  9772. bMRLock = false;
  9773. }
  9774. if(bTempFileOpen)
  9775. {
  9776. MD_ASSERT(hTempFile != INVALID_HANDLE_VALUE);
  9777. CloseHandle(hTempFile);
  9778. //
  9779. // Only set failure code if we don't already have another failure.
  9780. //
  9781. if(SUCCEEDED(hresReturn))
  9782. {
  9783. dwError = GetLastError();
  9784. hresReturn = RETURNCODETOHRESULT(dwError);
  9785. }
  9786. }
  9787. if(hTempFile != INVALID_HANDLE_VALUE)
  9788. {
  9789. DeleteFileW(wszTempFile);
  9790. }
  9791. if(!i_bHaveReadSaveSemaphore)
  9792. {
  9793. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  9794. }
  9795. bufParentPath.FreeMemory();
  9796. delete [] wszTempFile;
  9797. wszTempFile = NULL;
  9798. return hresReturn;
  9799. }
  9800. HRESULT
  9801. ReadSomeDataFromXML(
  9802. IN LPSTR i_pszPasswd,
  9803. IN LPWSTR i_wszFileName,
  9804. IN LPWSTR i_wszSourcePath,
  9805. IN LPCWSTR i_wszKeyType,
  9806. IN DWORD i_dwMDFlags,
  9807. IN BOOL i_bHaveReadSaveSemaphore,
  9808. OUT CMDBaseObject** o_ppboNew)
  9809. /*++
  9810. Routine Description:
  9811. Used by import.
  9812. Arguments:
  9813. Return Value:
  9814. HRESULT - ERROR_SUCCESS
  9815. ERROR_NOT_ENOUGH_MEMORY
  9816. Return codes from file system
  9817. Return codes from config.
  9818. Notes:
  9819. --*/
  9820. {
  9821. MD_ASSERT(i_wszKeyType != NULL);
  9822. MD_ASSERT(o_ppboNew != NULL);
  9823. HRESULT hr = S_OK;
  9824. bool bImpersonatingClient = false;
  9825. CImporter Importer(i_wszFileName, i_pszPasswd);
  9826. //
  9827. // TODO: Determine if we need this
  9828. //
  9829. if (!i_bHaveReadSaveSemaphore)
  9830. {
  9831. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  9832. }
  9833. hr = CoImpersonateClient();
  9834. if(FAILED(hr))
  9835. {
  9836. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hr));
  9837. goto exit;
  9838. }
  9839. bImpersonatingClient = true;
  9840. hr = Importer.Init();
  9841. if(FAILED(hr))
  9842. {
  9843. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hr));
  9844. goto exit;
  9845. }
  9846. hr = Importer.DoIt(i_wszSourcePath, i_wszKeyType, i_dwMDFlags, o_ppboNew);
  9847. if(FAILED(hr))
  9848. {
  9849. DBGERROR((DBG_CONTEXT, "hr=0x%x\n", hr));
  9850. goto exit;
  9851. }
  9852. exit:
  9853. if (!i_bHaveReadSaveSemaphore)
  9854. {
  9855. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  9856. }
  9857. if (bImpersonatingClient)
  9858. {
  9859. CoRevertToSelf();
  9860. bImpersonatingClient = false;
  9861. }
  9862. return hr;
  9863. }
  9864. HRESULT
  9865. EnumFiles(IN LPWSTR i_wszPattern,
  9866. IN DWORD i_dwMDEnumIndex,
  9867. OUT DWORD *o_pdwMajor,
  9868. OUT DWORD *o_pdwMinor,
  9869. OUT PFILETIME o_pftMDBackupTime)
  9870. /*++
  9871. Routine Description:
  9872. Given a pattern, will enum the corresponding files, filling in the
  9873. out params. Used as a helper routine for EnumHistory.
  9874. TODO: Have EnumBackups use this as well to eliminate duplicate code.
  9875. Arguments:
  9876. Return Value:
  9877. Notes:
  9878. Out parameters may be set even though the function fails. Caller should
  9879. deal with this.
  9880. --*/
  9881. {
  9882. HRESULT hresReturn = ERROR_SUCCESS;
  9883. //
  9884. // TODO: Assert that params are not null.
  9885. // (This is checked by caller)
  9886. //
  9887. if(i_wszPattern == NULL) {
  9888. hresReturn = E_INVALIDARG;
  9889. return hresReturn;
  9890. }
  9891. if (SUCCEEDED(hresReturn)) {
  9892. //
  9893. // Enumerate files
  9894. //
  9895. HANDLE hFile = INVALID_HANDLE_VALUE;
  9896. WIN32_FIND_DATAW wfdFile;
  9897. DWORD dwEnumIndex = (DWORD) -1;
  9898. hFile = FindFirstFileW(i_wszPattern,
  9899. &wfdFile);
  9900. if (hFile == INVALID_HANDLE_VALUE) {
  9901. hresReturn = RETURNCODETOHRESULT(GetLastError());
  9902. }
  9903. else {
  9904. /*if (CheckDigits(wfdFile.cFileName +
  9905. GetBackupNameLen(wfdFile.cFileName) +
  9906. (sizeof(MD_BACKUP_SUFFIX) - 1))) {
  9907. dwEnumIndex++;
  9908. }*/
  9909. hresReturn = ParseVersionNumber(wfdFile.cFileName, o_pdwMinor, o_pdwMajor);
  9910. if (SUCCEEDED(hresReturn))
  9911. {
  9912. dwEnumIndex++;
  9913. }
  9914. else
  9915. {
  9916. hresReturn = S_OK;
  9917. }
  9918. while (SUCCEEDED(hresReturn) && (dwEnumIndex != i_dwMDEnumIndex)) {
  9919. //
  9920. // Process the remaining files
  9921. //
  9922. if (FindNextFileW(hFile, &wfdFile)) {
  9923. /*if (CheckDigits(wfdFile.cFileName +
  9924. GetBackupNameLen(wfdFile.cFileName) +
  9925. (sizeof(MD_BACKUP_SUFFIX) - 1))) {
  9926. //
  9927. // One of our files
  9928. //
  9929. dwEnumIndex++;
  9930. }*/
  9931. if (SUCCEEDED(ParseVersionNumber(wfdFile.cFileName, o_pdwMinor, o_pdwMajor))) {
  9932. dwEnumIndex++;
  9933. }
  9934. }
  9935. else {
  9936. hresReturn = GetLastHResult();
  9937. }
  9938. }
  9939. FindClose(hFile);
  9940. }
  9941. if (SUCCEEDED(hresReturn)) {
  9942. //
  9943. // Found the file
  9944. //
  9945. int iLen = (int)wcslen(wfdFile.cFileName);
  9946. if(iLen > MD_BACKUP_MAX_LEN-1) {
  9947. hresReturn = E_INVALIDARG;
  9948. }
  9949. else {
  9950. MD_COPY(o_pftMDBackupTime,
  9951. &(wfdFile.ftLastWriteTime),
  9952. sizeof(FILETIME));
  9953. }
  9954. }
  9955. else {
  9956. if ((hresReturn == RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND)) ||
  9957. (hresReturn == RETURNCODETOHRESULT(ERROR_NO_MORE_FILES))) {
  9958. hresReturn = RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS);
  9959. }
  9960. }
  9961. }
  9962. return hresReturn;
  9963. }
  9964. HRESULT
  9965. ReplaceMasterRoot(
  9966. CMDBaseObject* i_pboNew,
  9967. CMDHandle* i_phoRootHandle)
  9968. /*++
  9969. Synopsis:
  9970. Replaces g_pboMasterRoot with a copy of i_pboNew. The exception is that the
  9971. schema node from g_pboMasterRoot is maintained.
  9972. Caller must have g_rMasterResourceLock(TSRES_LOCK_WRITE)
  9973. Arguments: [i_pboNew] - The pbo to become the new root. Does NOT contain schema
  9974. schema node.
  9975. [i_phoRootHandle] - An open write handle to the existing root.
  9976. Return Value:
  9977. --*/
  9978. {
  9979. MD_ASSERT(i_pboNew != NULL);
  9980. MD_ASSERT(i_phoRootHandle != NULL);
  9981. HRESULT hr = S_OK;
  9982. BOOL bChanged = false;
  9983. //
  9984. // For child nodes
  9985. //
  9986. CMDBaseObject* pboChild = NULL;
  9987. CMDBaseObject* pboSchema = NULL;
  9988. //
  9989. // For data
  9990. //
  9991. PVOID* ppvMainDataBuf = NULL;
  9992. CMDBaseData* pbdCurrent = NULL;
  9993. DWORD dwNumDataObjects = 0;
  9994. DWORD dwCurrentDataID = 0;
  9995. //
  9996. // Remove all the data from g_pboMastRoot
  9997. //
  9998. ppvMainDataBuf = GetMainDataBuffer();
  9999. MD_ASSERT (ppvMainDataBuf != NULL);
  10000. if ( ppvMainDataBuf == NULL )
  10001. {
  10002. hr = E_FAIL;
  10003. goto exit;
  10004. }
  10005. dwNumDataObjects = g_pboMasterRoot->GetAllDataObjects(
  10006. ppvMainDataBuf,
  10007. 0,
  10008. ALL_METADATA,
  10009. ALL_METADATA,
  10010. FALSE,
  10011. FALSE);
  10012. for (ULONG i = 0; i < dwNumDataObjects ; i++)
  10013. {
  10014. pbdCurrent=(CMDBaseData *)GetItemFromDataBuffer(ppvMainDataBuf, i);
  10015. MD_ASSERT(pbdCurrent != NULL);
  10016. dwCurrentDataID = pbdCurrent->GetIdentifier();
  10017. MD_REQUIRE(g_pboMasterRoot->RemoveDataObject(pbdCurrent, TRUE) == S_OK);
  10018. i_phoRootHandle->SetChangeData(g_pboMasterRoot, MD_CHANGE_TYPE_DELETE_DATA, dwCurrentDataID);
  10019. }
  10020. if (dwNumDataObjects > 0)
  10021. {
  10022. bChanged = true;
  10023. }
  10024. FreeMainDataBuffer(ppvMainDataBuf);
  10025. //
  10026. // Remove all the child data nodes except schema node.
  10027. //
  10028. ULONG idxFirstNonSchema = 0;
  10029. while((pboChild = g_pboMasterRoot->EnumChildObject(idxFirstNonSchema)) != NULL)
  10030. {
  10031. if(_wcsicmp(WSZSCHEMA_KEY_NAME1, (LPWSTR)pboChild->GetName(true)) == 0)
  10032. {
  10033. MD_ASSERT(idxFirstNonSchema == 0);
  10034. idxFirstNonSchema++;
  10035. pboSchema = pboChild;
  10036. }
  10037. else
  10038. {
  10039. bChanged = true;
  10040. MD_REQUIRE(g_pboMasterRoot->RemoveChildObject(pboChild) == S_OK);
  10041. if(i_phoRootHandle->SetChangeData(pboChild, MD_CHANGE_TYPE_DELETE_OBJECT, 0) != S_OK)
  10042. {
  10043. delete(pboChild);
  10044. }
  10045. }
  10046. }
  10047. MD_ASSERT(idxFirstNonSchema <= 1);
  10048. //
  10049. // Do the copying of data and child nodes
  10050. //
  10051. hr = CopyTree(
  10052. i_phoRootHandle,
  10053. g_pboMasterRoot,
  10054. i_pboNew,
  10055. bChanged);
  10056. if(FAILED(hr))
  10057. {
  10058. goto exit;
  10059. }
  10060. exit:
  10061. if(bChanged)
  10062. {
  10063. g_dwSystemChangeNumber++;
  10064. }
  10065. return hr;
  10066. }
  10067. HRESULT
  10068. CopyMetaObject(
  10069. /* [in] */ METADATA_HANDLE hMDSourceHandle,
  10070. /* [string][in][unique] */ unsigned char __RPC_FAR *pszMDSourcePath,
  10071. BOOL bUseSourceHandle,
  10072. CMDBaseObject* pboSourceIn,
  10073. /* [in] */ METADATA_HANDLE hMDDestHandle,
  10074. /* [string][in][unique] */ unsigned char __RPC_FAR *pszMDDestPath,
  10075. /* [in] */ BOOL bMDOverwriteFlag,
  10076. /* [in] */ BOOL bMDCopyFlag,
  10077. IN BOOL bUnicode)
  10078. /*++
  10079. Routine Description:
  10080. Copies or moves Source meta object and it's data and descendants to Dest. The
  10081. copied object is a child of Dest.
  10082. Arguments:
  10083. SourceHandle - The handle or the object to be copied. If copyflag is specified, read permission
  10084. is requried. If not, read/write permission is required.
  10085. SourcePath - Path of the object to be copied, relative to the path of SourceHandle.
  10086. eg. "Root Object/Child/GrandChild"
  10087. DestHandle - The handle of the new location for the object. Write permission is required.
  10088. DestPath - The path of the new location for the object, relative to the path of
  10089. DestHandle. The new object will be a child of the object specified by
  10090. DestHandle/DestPath. Must not be a descendant of SourceHandle/SourePath.
  10091. eg. "Root Object/Child2"
  10092. OverwriteFlag - Determines the behavior if the a meta object with the same name as Source is
  10093. already a child of Dest.
  10094. If TRUE, the existing object and all of its data and
  10095. descandants are deleted prior to copying/moving Source.
  10096. If FALSE, the existing object, data, and descendants remain, and Source is merged
  10097. in. In cases of data conflicts, the Source data overwrites the Dest data.
  10098. CopyFlag - Determines whether Source is deleted from its original location.
  10099. If TRUE, a copy is performed. Source is not deleted from its original location.
  10100. If FALSE, a move is performed. Source is deleted from its original location.
  10101. Return Value:
  10102. DWORD - Return Code
  10103. ERROR_SUCCESS
  10104. MD_ERROR_NOT_INITIALIZED
  10105. ERROR_INVALID_PARAMETER
  10106. ERROR_ACCESS_DENIED
  10107. ERROR_NOT_ENOUGH_MEMORY
  10108. ERROR_PATH_NOT_FOUND
  10109. ERROR_DUP_NAME
  10110. Notes:
  10111. --*/
  10112. {
  10113. HRESULT hresReturn = ERROR_SUCCESS;
  10114. LPSTR pszSourcePath = (LPSTR)pszMDSourcePath;
  10115. LPSTR pszDestPath = (LPSTR)pszMDDestPath;
  10116. CMDHandle *phoDestHandle, *phoSourceHandle;
  10117. CMDBaseObject *pboSource = NULL, *pboDest = NULL, *pboIndex = NULL, *pboNew = NULL, *pboDestParent = NULL;
  10118. LPSTR pszTempPath;
  10119. LPSTR pszRemainingDestPath;
  10120. BOOL bChanged = FALSE;
  10121. WCHAR strName[METADATA_MAX_NAME_LEN];
  10122. if(!bUseSourceHandle)
  10123. {
  10124. MD_ASSERT(pboSourceIn != NULL);
  10125. }
  10126. if (g_dwInitialized == 0) {
  10127. hresReturn = MD_ERROR_NOT_INITIALIZED;
  10128. }
  10129. else {
  10130. //
  10131. // check if pszDestPath is a valid parameter (non-NULL)
  10132. //
  10133. if (pszDestPath == NULL) {
  10134. hresReturn = E_INVALIDARG;
  10135. }
  10136. else {
  10137. //
  10138. // Must have access to Dest parent to add it.
  10139. // Make sure that a valid path was specified, ie. handle
  10140. // points to ancestor.
  10141. //
  10142. pszTempPath = pszDestPath;
  10143. SkipPathDelimeter(pszTempPath, bUnicode);
  10144. if(bUseSourceHandle)
  10145. {
  10146. hresReturn = ExtractNameFromPath(pszTempPath, (LPSTR)strName, bUnicode);
  10147. }
  10148. if (FAILED(hresReturn)) {
  10149. hresReturn = E_INVALIDARG;
  10150. }
  10151. if (!bMDCopyFlag) {
  10152. //
  10153. // Must have access to source parent to remove it.
  10154. // Make sure that a valid path was specified, ie. handle
  10155. // points to ancestor.
  10156. //
  10157. pszTempPath = pszSourcePath;
  10158. SkipPathDelimeter(pszTempPath, bUnicode);
  10159. hresReturn = ExtractNameFromPath(pszTempPath, (LPSTR)strName, bUnicode);
  10160. if (FAILED(hresReturn)) {
  10161. hresReturn = E_INVALIDARG;
  10162. }
  10163. }
  10164. }
  10165. }
  10166. if (SUCCEEDED(hresReturn)) {
  10167. g_LockMasterResource.WriteLock();
  10168. if(bUseSourceHandle)
  10169. {
  10170. hresReturn = GetObjectFromPath(pboSource, hMDSourceHandle,
  10171. (bMDCopyFlag) ? METADATA_PERMISSION_READ : METADATA_PERMISSION_WRITE,
  10172. (LPSTR)pszSourcePath, bUnicode);
  10173. }
  10174. else
  10175. {
  10176. pboSource = pboSourceIn;
  10177. }
  10178. if (SUCCEEDED(hresReturn)) {
  10179. //
  10180. // GetObjectFromPath updates path, need both original and remainder
  10181. //
  10182. pszRemainingDestPath = pszDestPath;
  10183. phoDestHandle = GetHandleObject(hMDDestHandle);
  10184. if(phoDestHandle != NULL)
  10185. {
  10186. hresReturn = GetObjectFromPathWithHandle(pboDest,
  10187. hMDDestHandle,
  10188. phoDestHandle,
  10189. METADATA_PERMISSION_WRITE,
  10190. (LPSTR)pszRemainingDestPath,
  10191. bUnicode);
  10192. }
  10193. else
  10194. {
  10195. hresReturn = E_HANDLE;
  10196. }
  10197. if ((SUCCEEDED(hresReturn)) ||
  10198. ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboDest != NULL))) {
  10199. //
  10200. // Make sure dest is not descendant of source
  10201. //
  10202. for (pboIndex = pboDest; pboIndex != NULL; pboIndex = pboIndex->GetParent()) {
  10203. if (pboIndex == pboSource) {
  10204. hresReturn = E_INVALIDARG;
  10205. break;
  10206. }
  10207. }
  10208. }
  10209. //
  10210. // I don't think we need this call, since we have already called
  10211. // GetHandleObject Above.
  10212. //
  10213. // phoDestHandle = GetHandleObject(hMDDestHandle);
  10214. if (SUCCEEDED(hresReturn)) {
  10215. //
  10216. // Object already exists
  10217. //
  10218. if (pboDest == pboSource) {
  10219. //
  10220. // Copy to self
  10221. //
  10222. }
  10223. else {
  10224. MD_ASSERT (phoDestHandle != NULL);
  10225. if (bMDOverwriteFlag) {
  10226. if (pboDest->GetName(bUnicode) == NULL) {
  10227. hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  10228. }
  10229. else if(pboDest == g_pboMasterRoot) {
  10230. hresReturn = ReplaceMasterRoot(pboSource, phoDestHandle);
  10231. }
  10232. else {
  10233. pboDestParent = pboDest->GetParent();
  10234. hresReturn = MakeTreeCopy(pboSource, pboNew, pboDest->GetName(bUnicode), bUnicode);
  10235. if (SUCCEEDED(hresReturn)) {
  10236. MD_REQUIRE(SUCCEEDED(pboDestParent->RemoveChildObject(pboDest->GetName(bUnicode), bUnicode)));
  10237. hresReturn = pboDestParent->InsertChildObject(pboNew);
  10238. if (SUCCEEDED(hresReturn)) {
  10239. g_dwSystemChangeNumber++;
  10240. INCREMENT_SCHEMA_CHANGE_NUMBER(hMDDestHandle,
  10241. phoDestHandle,
  10242. pszDestPath,
  10243. bUnicode);
  10244. if (phoDestHandle->SetChangeData(
  10245. pboDest, MD_CHANGE_TYPE_DELETE_OBJECT, 0) != ERROR_SUCCESS) {
  10246. delete(pboDest);
  10247. }
  10248. AddNewChangeData(phoDestHandle, pboNew);
  10249. }
  10250. else {
  10251. delete (pboNew);
  10252. pboDestParent->InsertChildObject(pboDest);
  10253. }
  10254. }
  10255. }
  10256. }
  10257. else {
  10258. //
  10259. // Object exists at destination and not overwrite.
  10260. // Add in missing objects and data.
  10261. //
  10262. hresReturn = CopyTree(phoDestHandle, pboDest, pboSource, bChanged);
  10263. if (bChanged) {
  10264. g_dwSystemChangeNumber++;
  10265. INCREMENT_SCHEMA_CHANGE_NUMBER(hMDDestHandle,
  10266. phoDestHandle,
  10267. pszDestPath,
  10268. bUnicode);
  10269. }
  10270. }
  10271. }
  10272. }
  10273. else if ((hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) && (pboDest != NULL)) {
  10274. //
  10275. // Full destination path doesn't exist, so create it
  10276. //
  10277. hresReturn = MakeTreeCopyWithPath(pboSource,
  10278. pboNew,
  10279. pszRemainingDestPath,
  10280. bUnicode);
  10281. if (SUCCEEDED(hresReturn)) {
  10282. MD_ASSERT(pboDest != NULL);
  10283. hresReturn = pboDest->InsertChildObject(pboNew);
  10284. if (SUCCEEDED(hresReturn)) {
  10285. g_dwSystemChangeNumber++;
  10286. INCREMENT_SCHEMA_CHANGE_NUMBER(hMDDestHandle,
  10287. phoDestHandle,
  10288. pszDestPath,
  10289. bUnicode);
  10290. AddNewChangeData(phoDestHandle, pboNew);
  10291. }
  10292. else {
  10293. delete (pboNew);
  10294. }
  10295. }
  10296. }
  10297. if ((SUCCEEDED(hresReturn)) && (!bMDCopyFlag)) {
  10298. MD_REQUIRE(SUCCEEDED(pboSource->GetParent()->RemoveChildObject(pboSource)));
  10299. phoSourceHandle = GetHandleObject(hMDSourceHandle);
  10300. MD_ASSERT (phoSourceHandle != NULL);
  10301. if (phoSourceHandle->SetChangeData(pboSource, MD_CHANGE_TYPE_DELETE_OBJECT, 0)
  10302. != ERROR_SUCCESS) {
  10303. delete(pboSource);
  10304. }
  10305. }
  10306. }
  10307. g_LockMasterResource.WriteUnlock();
  10308. }
  10309. return hresReturn;
  10310. }
  10311. BOOL WstrToUl(
  10312. LPCWSTR i_wszSrc,
  10313. WCHAR i_wcTerminator,
  10314. ULONG* o_pul)
  10315. /*++
  10316. Synopsis:
  10317. Converts a WstrToUl.
  10318. We need this because neither swscanf nor atoi indicate error cases correctly.
  10319. Arguments: [i_wszSrc] - The str to be converted
  10320. [i_wcTerminator] - At what char we should stop searching
  10321. [o_pul] - The result, only set on success.
  10322. Return Value:
  10323. BOOL - true if succeeded, false otherwise
  10324. --*/
  10325. {
  10326. MD_ASSERT(o_pul);
  10327. MD_ASSERT(i_wszSrc);
  10328. static const ULONG ulMax = 0xFFFFFFFF;
  10329. ULONG ulCur = 0;
  10330. _int64 i64Out = 0;
  10331. for(LPCWSTR pCur = i_wszSrc; *pCur != L'\0' && *pCur != i_wcTerminator; pCur++)
  10332. {
  10333. ulCur = *pCur - L'0';
  10334. if(ulCur > 9)
  10335. {
  10336. DBGINFO((DBG_CONTEXT, "[WstrToUl] Invalid char encountered\n"));
  10337. return false;
  10338. }
  10339. i64Out = i64Out*10 + ulCur;
  10340. if(i64Out > ulMax)
  10341. {
  10342. DBGINFO((DBG_CONTEXT, "[WstrToUl] Number is too big\n"));
  10343. return false;
  10344. }
  10345. }
  10346. MD_ASSERT(i64Out <= ulMax);
  10347. *o_pul = (ULONG)i64Out;
  10348. return true;
  10349. }
  10350. BOOL SchemaTreeInTable(ISimpleTableRead2* i_pISTProperty)
  10351. {
  10352. HRESULT hr = S_OK;
  10353. DWORD dwGroup = eMBProperty_Custom;
  10354. LPWSTR wszName = L"AdminACL";
  10355. LPWSTR wszLocation = L"/Schema";
  10356. LPVOID a_Identity[] = {(LPVOID)wszName,
  10357. (LPVOID)wszLocation,
  10358. (LPVOID)&dwGroup
  10359. };
  10360. ULONG iRow = 0;
  10361. //
  10362. // Assumption here is that AdminACL is always present at /Schema
  10363. // If we find it, we assume that the schema tree is in the table.
  10364. //
  10365. hr = i_pISTProperty->GetRowIndexByIdentity(NULL,
  10366. a_Identity,
  10367. &iRow);
  10368. DBGINFOW((DBG_CONTEXT,
  10369. L"[SchemaTreeInTable] GetRowIndexByIdentity returned hr=0x%x\n",hr));
  10370. if(FAILED(hr))
  10371. {
  10372. dwGroup = eMBProperty_IIsConfigObject;
  10373. hr = i_pISTProperty->GetRowIndexByIdentity(NULL,
  10374. a_Identity,
  10375. &iRow);
  10376. if(FAILED(hr))
  10377. {
  10378. return FALSE;
  10379. }
  10380. }
  10381. return TRUE;
  10382. }
  10383. HRESULT CompileIfNeeded(LPWSTR i_wszDataFileName,
  10384. LPWSTR i_wszSchemaFileName,
  10385. BOOL* o_pbSchemaFileNotFound)
  10386. {
  10387. HRESULT hr = S_OK;
  10388. ISimpleTableDispenser2* pISTDisp = NULL;
  10389. IMetabaseSchemaCompiler* pCompiler = NULL;
  10390. //
  10391. // Get a pointer to the compiler to get the bin file name.
  10392. //
  10393. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  10394. if(FAILED(hr))
  10395. {
  10396. DBGINFOW((DBG_CONTEXT,
  10397. L"[CompileIfNeeded] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
  10398. goto exit;
  10399. }
  10400. hr = pISTDisp->QueryInterface(IID_IMetabaseSchemaCompiler,
  10401. (LPVOID*)&pCompiler);
  10402. if(FAILED(hr))
  10403. {
  10404. DBGINFOW((DBG_CONTEXT,
  10405. L"[CompileIfNeeded] QueryInterface on compiler failed with hr = 0x%x.\n",hr));
  10406. goto exit;
  10407. }
  10408. if(-1 != GetFileAttributesW(i_wszSchemaFileName))
  10409. {
  10410. BOOL bMatchTimeStamp = FALSE;
  10411. //
  10412. // Schema file present. Check if it has a corresponding valid bin file.
  10413. //
  10414. *o_pbSchemaFileNotFound = FALSE;
  10415. if(NULL == g_pGlobalISTHelper)
  10416. {
  10417. BOOL bFailIfBinFileAbsent = TRUE;
  10418. hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
  10419. if(SUCCEEDED(hr))
  10420. {
  10421. hr = MatchTimeStamp(i_wszDataFileName,
  10422. i_wszSchemaFileName,
  10423. g_pGlobalISTHelper->m_wszBinFileForMeta,
  10424. &bMatchTimeStamp);
  10425. if(FAILED(hr))
  10426. {
  10427. goto exit;
  10428. }
  10429. if(bMatchTimeStamp)
  10430. {
  10431. //
  10432. // Bin file found and time stamp matched, no need to compile
  10433. //
  10434. DBGINFOW((DBG_CONTEXT,
  10435. L"[CompileIfNeeded] Schema file: %s found. Schema bin file: %s is valid, and its timestamp matches what is stored in data file %s. No compilation reqired.\n",
  10436. i_wszSchemaFileName,
  10437. g_pGlobalISTHelper->m_wszBinFileForMeta,
  10438. i_wszDataFileName));
  10439. goto exit;
  10440. }
  10441. }
  10442. else
  10443. {
  10444. DBGINFOW((DBG_CONTEXT,
  10445. L"[CompileIfNeeded] Unable to get the the bin file name. (Assuming file is missing or invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
  10446. }
  10447. }
  10448. else
  10449. {
  10450. hr = MatchTimeStamp(i_wszDataFileName,
  10451. i_wszSchemaFileName,
  10452. g_pGlobalISTHelper->m_wszBinFileForMeta,
  10453. &bMatchTimeStamp);
  10454. if(FAILED(hr))
  10455. {
  10456. goto exit;
  10457. }
  10458. if(bMatchTimeStamp)
  10459. {
  10460. //
  10461. // Bin file found and time stamp matched, no need to compile
  10462. //
  10463. DBGINFOW((DBG_CONTEXT,
  10464. L"[CompileIfNeeded] Schema file: %s found. Schema bin file: %s is valid, and its timestamp matches what is stored in data file %s. No compilation reqired.\n",
  10465. i_wszSchemaFileName,
  10466. g_pGlobalISTHelper->m_wszBinFileForMeta,
  10467. i_wszDataFileName));
  10468. goto exit;
  10469. }
  10470. }
  10471. //
  10472. // If you reach here it means that the schema file was found and either
  10473. // a. the bin file was invalid
  10474. // b. the bin file was missing
  10475. // c. the bin file had a timestamp mistmatch
  10476. // Hence try compiling from the schema file.
  10477. //
  10478. DBGINFOW((DBG_CONTEXT,
  10479. L"[CompileIfNeeded] Compiling from schema file %s\n", i_wszSchemaFileName));
  10480. hr = CompileIntoBinFromSchemaFile(pCompiler,
  10481. i_wszSchemaFileName);
  10482. if(SUCCEEDED(hr))
  10483. {
  10484. goto exit;
  10485. }
  10486. }
  10487. else
  10488. {
  10489. *o_pbSchemaFileNotFound = TRUE;
  10490. }
  10491. //
  10492. // Recreate from shipped schema
  10493. //
  10494. DBGINFOW((DBG_CONTEXT,
  10495. L"[CompileIfNeeded] Schema file not found or compile from it failed. Compiling from shipped schema\n"));
  10496. hr = CompileIntoBin(pCompiler,
  10497. NULL,
  10498. i_wszSchemaFileName);
  10499. exit:
  10500. if(SUCCEEDED(hr))
  10501. {
  10502. if(NULL == g_pGlobalISTHelper)
  10503. {
  10504. BOOL bFailIfBinFileAbsent = TRUE;
  10505. hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
  10506. if(FAILED(hr))
  10507. {
  10508. DBGINFOW((DBG_CONTEXT,
  10509. L"[CompileIfNeeded] Unable to get the the bin file name. (Assuming file is invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
  10510. }
  10511. }
  10512. if(SUCCEEDED(hr))
  10513. {
  10514. hr = UpdateTimeStamp((LPWSTR)i_wszSchemaFileName,
  10515. g_pGlobalISTHelper->m_wszBinFileForMeta);
  10516. if(FAILED(hr))
  10517. {
  10518. DBGINFOW((DBG_CONTEXT,
  10519. L"[CompileIfNeeded] UpdateTimeStamp failed with hr = 0x%x.\n",hr));
  10520. }
  10521. }
  10522. }
  10523. if(NULL != pCompiler)
  10524. {
  10525. pCompiler->Release();
  10526. }
  10527. if(NULL != pISTDisp)
  10528. {
  10529. pISTDisp->Release();
  10530. }
  10531. return hr;
  10532. }
  10533. /***************************************************************************++
  10534. Routine Description:
  10535. Utility function that takes the schema file and copies it as an extension
  10536. file and then invokes compile. This is called in cases where the bin file
  10537. is out of sync with the schema file, and since the schema file is the
  10538. master, you want to regenerate the bin file from the existing schema file.
  10539. This function touches global variable g_wszSchemaExtensions file, and hence
  10540. needs the appropriate lock to be taken before calling.
  10541. Arguments:
  10542. [in] compiler
  10543. [in] name of the schema file that needs to be compiled
  10544. Return Value:
  10545. HRESULT
  10546. --***************************************************************************/
  10547. HRESULT CompileIntoBinFromSchemaFile(IMetabaseSchemaCompiler* i_pCompiler,
  10548. LPCWSTR i_wszSchemaFileName)
  10549. {
  10550. HRESULT hr = S_OK;
  10551. MD_ASSERT(NULL != i_pCompiler);
  10552. MD_ASSERT(NULL != i_wszSchemaFileName);
  10553. //
  10554. // Bug #512868 If someone had attrib-ed an existing extenstion file
  10555. // be read-only then we could land up in a state where we will not be
  10556. // able to recreate the extensions file. Hence attrib the extensions
  10557. // file to be read-write if it exists. An extensions file can be
  10558. // around only if a previous compile has failed.
  10559. //
  10560. // Also, in this case reset the attrib on the extensions file after you
  10561. // have created it via copy. Else, if the schema file is read-only you
  10562. // will land up with a read-only extensions file. We cannot reset the
  10563. // schema file before the copy because it may be on a CD-ROM.
  10564. //
  10565. ResetFileAttributesIfNeeded((LPTSTR)g_wszSchemaExtensionFile,
  10566. TRUE);
  10567. if(CopyFileW(i_wszSchemaFileName,
  10568. g_wszSchemaExtensionFile,
  10569. FALSE))
  10570. {
  10571. ResetFileAttributesIfNeeded((LPTSTR)g_wszSchemaExtensionFile,
  10572. TRUE);
  10573. hr = CompileIntoBin(i_pCompiler,
  10574. g_wszSchemaExtensionFile,
  10575. i_wszSchemaFileName);
  10576. if(SUCCEEDED(hr))
  10577. {
  10578. if(!DeleteFileW(g_wszSchemaExtensionFile))
  10579. {
  10580. hr = HRESULT_FROM_WIN32(GetLastError());
  10581. DBGINFOW((DBG_CONTEXT,
  10582. L"[CompileIntoBinFromSchemaFile] Compile from schema file: %s succeeded, but cannot delete the extsions file: %s into which it was copied. Delete file failed with hr = 0x%x.\n",
  10583. i_wszSchemaFileName,
  10584. g_wszSchemaExtensionFile,
  10585. hr));
  10586. hr = S_OK;
  10587. }
  10588. }
  10589. else
  10590. {
  10591. DBGINFOW((DBG_CONTEXT,
  10592. L"[CompileIntoBinFromSchemaFile] Compile from schema file failed with hr = 0x%x.\n",
  10593. hr));
  10594. }
  10595. }
  10596. else
  10597. {
  10598. hr = HRESULT_FROM_WIN32(GetLastError());
  10599. DBGINFOW((DBG_CONTEXT,
  10600. L"[CompileIntoBinFromSchemaFile] Unable to copy %s to %s. CopyFile failed with hr = 0x%x.\n",
  10601. i_wszSchemaFileName,
  10602. g_wszSchemaExtensionFile,
  10603. hr));
  10604. }
  10605. return hr;
  10606. } // CompileIntoBinFromSchemaFile
  10607. /***************************************************************************++
  10608. Routine Description:
  10609. Utility function that takes the extension file and compiles it into the
  10610. schema file
  10611. Arguments:
  10612. [in] compiler
  10613. [in] Extension file to be compiled
  10614. [in] Name of the output schema file
  10615. Return Value:
  10616. HRESULT
  10617. --***************************************************************************/
  10618. HRESULT CompileIntoBin(IMetabaseSchemaCompiler* i_pCompiler,
  10619. LPCWSTR i_wszSchemaExtensionFileName,
  10620. LPCWSTR i_wszSchemaFileName)
  10621. {
  10622. HRESULT hr = S_OK;
  10623. MD_ASSERT(NULL != i_pCompiler);
  10624. MD_ASSERT(NULL != i_wszSchemaFileName);
  10625. //
  10626. // Always release the bin file that you've been using so far before a
  10627. // compile.
  10628. //
  10629. ReleaseGlobalISTHelper();
  10630. //
  10631. // Bug #513962 If someone had attrib-ed an existing schema file
  10632. // be read-only then we could land up in a state where we will not be
  10633. // able to recreate the schema file. Hence attrib the schema
  10634. // file to be read-write if it exists.
  10635. //
  10636. ResetFileAttributesIfNeeded((LPTSTR)i_wszSchemaFileName,
  10637. TRUE);
  10638. hr = i_pCompiler->Compile(i_wszSchemaExtensionFileName,
  10639. i_wszSchemaFileName);
  10640. return hr;
  10641. } // CompileIntoBin
  10642. HRESULT MatchTimeStamp(LPWSTR i_wszDataFileName,
  10643. LPWSTR i_wszSchemaXMLFileName,
  10644. LPWSTR i_wszSchemaBINFileName,
  10645. BOOL* o_bMatchTimeStamp)
  10646. {
  10647. HRESULT hr = S_OK;
  10648. LPWSTR wszSchemaXMLTimeStamp = MD_XML_SCHEMA_TIMESTAMPW;
  10649. LPWSTR wszSchemaBINTimeStamp = MD_BIN_SCHEMA_TIMESTAMPW;
  10650. FILETIME XMLSchemaTimeStamp;
  10651. FILETIME BINSchemaTimeStamp;
  10652. WIN32_FILE_ATTRIBUTE_DATA XMLSchema;
  10653. WIN32_FILE_ATTRIBUTE_DATA BINSchema;
  10654. *o_bMatchTimeStamp = FALSE;
  10655. hr = GetTimeStamp(i_wszDataFileName,
  10656. wszSchemaXMLTimeStamp,
  10657. &XMLSchemaTimeStamp);
  10658. if(FAILED(hr))
  10659. {
  10660. if(E_ST_INVALIDTABLE == hr)
  10661. {
  10662. return hr;
  10663. }
  10664. else
  10665. {
  10666. return S_OK;
  10667. }
  10668. }
  10669. if(!GetFileAttributesExW(i_wszSchemaXMLFileName,
  10670. GetFileExInfoStandard,
  10671. (LPVOID)&XMLSchema))
  10672. {
  10673. return S_OK;
  10674. }
  10675. if(0 != CompareFileTime(&XMLSchemaTimeStamp,
  10676. &XMLSchema.ftLastWriteTime))
  10677. {
  10678. return S_OK;
  10679. }
  10680. hr = GetTimeStamp(i_wszDataFileName,
  10681. wszSchemaBINTimeStamp,
  10682. &BINSchemaTimeStamp);
  10683. if(FAILED(hr))
  10684. {
  10685. if(E_ST_INVALIDTABLE == hr)
  10686. {
  10687. return hr;
  10688. }
  10689. else
  10690. {
  10691. return S_OK;
  10692. }
  10693. }
  10694. if(!GetFileAttributesExW(i_wszSchemaBINFileName,
  10695. GetFileExInfoStandard,
  10696. (LPVOID)&BINSchema))
  10697. {
  10698. return S_OK;
  10699. }
  10700. if(0 != CompareFileTime(&BINSchemaTimeStamp,
  10701. &BINSchema.ftLastWriteTime))
  10702. {
  10703. return S_OK;
  10704. }
  10705. *o_bMatchTimeStamp = TRUE;
  10706. return S_OK;
  10707. }
  10708. HRESULT UpdateTimeStamp(LPWSTR i_wszSchemaXMLFileName,
  10709. LPWSTR i_wszSchemaBinFileName)
  10710. {
  10711. WIN32_FILE_ATTRIBUTE_DATA XMLSchema;
  10712. WIN32_FILE_ATTRIBUTE_DATA BINSchema;
  10713. if(!GetFileAttributesExW(i_wszSchemaXMLFileName,
  10714. GetFileExInfoStandard,
  10715. (LPVOID)&XMLSchema))
  10716. {
  10717. return HRESULT_FROM_WIN32(GetLastError());
  10718. }
  10719. memcpy(&g_XMLSchemaFileTimeStamp, &(XMLSchema.ftLastWriteTime), sizeof(FILETIME));
  10720. if(!GetFileAttributesExW(i_wszSchemaBinFileName,
  10721. GetFileExInfoStandard,
  10722. (LPVOID)&BINSchema))
  10723. {
  10724. return HRESULT_FROM_WIN32(GetLastError());
  10725. }
  10726. memcpy(&g_BINSchemaFileTimeStamp, &(BINSchema.ftLastWriteTime), sizeof(FILETIME));
  10727. return S_OK;
  10728. }
  10729. HRESULT ComputeNewHistoryVersionNumber()
  10730. {
  10731. ULONG ulCurrentVersionNumber = g_ulHistoryMajorVersionNumber;
  10732. ULONG ulNextVersionNumber = 0;
  10733. WIN32_FIND_DATAW FileData;
  10734. HRESULT hr = S_OK;
  10735. HANDLE hFind = INVALID_HANDLE_VALUE;
  10736. LPWSTR wszSearchString = NULL;
  10737. ULONG i = 0;
  10738. //
  10739. // Compute a new version number and make sure that no history files
  10740. // exist with that major version number.
  10741. //
  10742. do
  10743. {
  10744. if(ulCurrentVersionNumber != 0xFFFFFFFF)
  10745. {
  10746. ulNextVersionNumber = ulCurrentVersionNumber + 1;
  10747. }
  10748. else
  10749. {
  10750. ulNextVersionNumber = 0;
  10751. }
  10752. if((hFind != INVALID_HANDLE_VALUE) && (hFind != NULL))
  10753. {
  10754. FindClose(hFind);
  10755. hFind = INVALID_HANDLE_VALUE;
  10756. }
  10757. hr = ConstructHistoryFileNameWithoutMinorVersion(&wszSearchString,
  10758. NULL,
  10759. g_wszHistoryFileSearchString,
  10760. g_cchHistoryFileSearchString,
  10761. g_wszRealFileNameExtension,
  10762. g_cchRealFileNameExtension,
  10763. ulNextVersionNumber);
  10764. if(FAILED(hr))
  10765. {
  10766. goto exit;
  10767. }
  10768. hFind = FindFirstFileW(wszSearchString, &FileData);
  10769. if(NULL != wszSearchString)
  10770. {
  10771. delete [] wszSearchString;
  10772. wszSearchString = NULL;
  10773. }
  10774. ulCurrentVersionNumber = ulNextVersionNumber;
  10775. }
  10776. while((hFind != INVALID_HANDLE_VALUE) && (hFind != NULL) && (++i < 0xFFFFFFFF));
  10777. g_ulHistoryMajorVersionNumber = ulNextVersionNumber;
  10778. exit:
  10779. if((hFind != INVALID_HANDLE_VALUE) && (hFind != NULL))
  10780. {
  10781. FindClose(hFind);
  10782. hFind = INVALID_HANDLE_VALUE;
  10783. }
  10784. return hr;
  10785. } // ComputeNewHistoryVersionNumber
  10786. /***************************************************************************++
  10787. Routine Description:
  10788. Utility function to fetch the timestamp of the file. It maps a view of
  10789. the file and looks for the timestamp
  10790. Arguments:
  10791. [in] File name
  10792. [out] Count of bytes for version number
  10793. [out] Version number
  10794. Return Value:
  10795. HRESULT
  10796. --***************************************************************************/
  10797. HRESULT
  10798. GetTimeStamp(LPWSTR i_wszFile,
  10799. LPWSTR i_wszPropertyName,
  10800. FILETIME* o_FileTime)
  10801. {
  10802. HRESULT hr = S_OK;
  10803. ISimpleTableDispenser2* pISTDisp = NULL;
  10804. ISimpleTableRead2* pISTProperty = NULL;
  10805. STQueryCell QueryCell[2];
  10806. ULONG cCell = sizeof(QueryCell)/sizeof(STQueryCell);
  10807. LPWSTR wszGlobalLocation = MD_GLOBAL_LOCATIONW;
  10808. ULONG cbFileTime = sizeof(FILETIME);
  10809. DWORD cb = 0;
  10810. FILETIME* pFileTime = NULL;
  10811. //
  10812. // Get only the root location - that where the timestamps are stored.
  10813. //
  10814. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  10815. if(FAILED(hr))
  10816. {
  10817. DBGINFOW((DBG_CONTEXT,
  10818. L"[GetTimeStamp] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
  10819. goto exit;
  10820. }
  10821. //
  10822. // No need to specify the schema file because we are getting a shipped
  10823. // property from a global location.
  10824. //
  10825. QueryCell[0].pData = (LPVOID)i_wszFile;
  10826. QueryCell[0].eOperator = eST_OP_EQUAL;
  10827. QueryCell[0].iCell = iST_CELL_FILE;
  10828. QueryCell[0].dbType = DBTYPE_WSTR;
  10829. QueryCell[0].cbSize = (lstrlenW(i_wszFile)+1)*sizeof(WCHAR);
  10830. QueryCell[1].pData = (LPVOID)wszGlobalLocation;
  10831. QueryCell[1].eOperator = eST_OP_EQUAL;
  10832. QueryCell[1].iCell = iMBProperty_Location;
  10833. QueryCell[1].dbType = DBTYPE_WSTR;
  10834. QueryCell[1].cbSize = (lstrlenW(wszGlobalLocation)+1)*sizeof(WCHAR);
  10835. hr = pISTDisp->GetTable(wszDATABASE_METABASE,
  10836. wszTABLE_MBProperty,
  10837. (LPVOID)QueryCell,
  10838. (LPVOID)&cCell,
  10839. eST_QUERYFORMAT_CELLS,
  10840. 0,
  10841. (LPVOID *)&pISTProperty);
  10842. if(FAILED(hr))
  10843. {
  10844. DBGINFOW((DBG_CONTEXT,
  10845. L"[GetTimeStamp] GetTable on %s failed with hr = 0x%x.\n",
  10846. wszTABLE_MBProperty,
  10847. hr));
  10848. goto exit;
  10849. }
  10850. //
  10851. // Get the timestamps.
  10852. //
  10853. hr = GetGlobalValue(pISTProperty,
  10854. i_wszPropertyName,
  10855. &cb,
  10856. (LPVOID*)&pFileTime);
  10857. if(FAILED(hr))
  10858. {
  10859. DBGINFOW((DBG_CONTEXT,
  10860. L"[GetTimeStamp] Unable to read %s. GetGlobalValue failed with hr = 0x%x.\n",
  10861. i_wszPropertyName,
  10862. hr));
  10863. goto exit;
  10864. }
  10865. else if(cbFileTime != cb)
  10866. {
  10867. DBGINFOW((DBG_CONTEXT,
  10868. L"[GetTimeStamp] GetGlobalValue returns incorrect count of bytes %d for %s. Expected %d.\n",
  10869. cb,
  10870. i_wszPropertyName,
  10871. cbFileTime));
  10872. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  10873. goto exit;
  10874. }
  10875. *o_FileTime = *(FILETIME*)pFileTime;
  10876. exit:
  10877. if(NULL != pISTProperty)
  10878. {
  10879. pISTProperty->Release();
  10880. pISTProperty = NULL;
  10881. }
  10882. if(NULL != pISTDisp)
  10883. {
  10884. pISTDisp->Release();
  10885. pISTDisp = NULL;
  10886. }
  10887. return hr;
  10888. }
  10889. /***************************************************************************++
  10890. Routine Description:
  10891. Sets the security on the the given file to system and administrators.
  10892. Arguments:
  10893. [in] File name
  10894. Return Value:
  10895. HRESULT
  10896. --***************************************************************************/
  10897. HRESULT SetSecurityOnFile(LPWSTR i_wszFileSrc,
  10898. LPWSTR i_wszFileDest)
  10899. {
  10900. DWORD dwRes;
  10901. PACL pDACL = NULL;
  10902. PSECURITY_DESCRIPTOR pSD = NULL;
  10903. HRESULT hr = S_OK;
  10904. //
  10905. // Get the DACL of the original file.
  10906. //
  10907. dwRes = GetNamedSecurityInfoW(i_wszFileSrc,
  10908. SE_FILE_OBJECT,
  10909. DACL_SECURITY_INFORMATION,
  10910. NULL,
  10911. NULL,
  10912. &pDACL,
  10913. NULL,
  10914. &pSD);
  10915. if (dwRes != ERROR_SUCCESS)
  10916. {
  10917. hr = HRESULT_FROM_WIN32(dwRes);
  10918. DBGINFOW((DBG_CONTEXT,
  10919. L"[SetSecurityOnFile] Unable to set security on %s. GetNamedSecurityInfo on %s failed with hr = 0x%x\n.",
  10920. i_wszFileDest,
  10921. i_wszFileSrc,
  10922. hr));
  10923. hr = S_OK;
  10924. }
  10925. else
  10926. {
  10927. //
  10928. // Set the DACL of the original file to the copy.
  10929. //
  10930. dwRes = SetNamedSecurityInfoW(i_wszFileDest,
  10931. SE_FILE_OBJECT,
  10932. DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
  10933. NULL,
  10934. NULL,
  10935. pDACL,
  10936. NULL);
  10937. if (dwRes != ERROR_SUCCESS)
  10938. {
  10939. hr = HRESULT_FROM_WIN32(dwRes);
  10940. DBGINFOW((DBG_CONTEXT,
  10941. L"[SetSecurityOnFile] Unable to set security on %s. SetNamedSecurityInfo failed with hr = 0x%x\n.",
  10942. i_wszFileDest,
  10943. hr));
  10944. hr = S_OK;
  10945. }
  10946. }
  10947. //
  10948. // Cleanup the security descriptor.
  10949. //
  10950. if (NULL != pSD)
  10951. {
  10952. LocalFree(pSD);
  10953. }
  10954. return hr;
  10955. } // SetSecurityOnFile
  10956. void ResetFileAttributesIfNeeded(LPTSTR pszFile,
  10957. BOOL bUnicode)
  10958. {
  10959. DWORD dwRealFileAttributes;
  10960. if(bUnicode)
  10961. {
  10962. dwRealFileAttributes = GetFileAttributesW((LPWSTR)pszFile);
  10963. }
  10964. else
  10965. {
  10966. dwRealFileAttributes = GetFileAttributes(pszFile);
  10967. }
  10968. if((-1 != dwRealFileAttributes) &&
  10969. (FILE_ATTRIBUTE_READONLY == (dwRealFileAttributes & FILE_ATTRIBUTE_READONLY)))
  10970. {
  10971. DWORD dwRes = 0;
  10972. if(bUnicode)
  10973. {
  10974. dwRes = SetFileAttributesW((LPWSTR)pszFile,
  10975. FILE_ATTRIBUTE_NORMAL);
  10976. }
  10977. else
  10978. {
  10979. dwRes = SetFileAttributes(pszFile,
  10980. FILE_ATTRIBUTE_NORMAL);
  10981. }
  10982. if(dwRes)
  10983. {
  10984. LogEvent(g_pEventLog,
  10985. MD_WARNING_RESETTING_READ_ONLY_ATTRIB,
  10986. EVENTLOG_WARNING_TYPE,
  10987. ID_CAT_CAT,
  10988. S_OK);
  10989. }
  10990. else
  10991. {
  10992. HRESULT hr;
  10993. DWORD dwError;
  10994. dwError = GetLastError();
  10995. hr = RETURNCODETOHRESULT(dwError);
  10996. DBGINFOW((DBG_CONTEXT,
  10997. L"[ResetFileAttributesIfNeeded] Unable to reset metabase file attributes. SetFileAttributes failed with hr=0x%x", hr));
  10998. }
  10999. }
  11000. } // ResetFileAttributesIfNeeded
  11001. //
  11002. // The following two functions LockMetabaseFiles and UnlockMetabaseFiles are used to
  11003. // write lock the metabase files when edit while running is disabled and unlock it
  11004. // when edit while running is enabled. This change was necessary for full volume
  11005. // restore to work. Backup vendors have been told that they need not change their
  11006. // scripts for the whistler release. Eg: When they do a full volume restore,
  11007. // they will overwrite metabase.xml and a competing save can overwrite the
  11008. // metabase.xml that has just been restored, thus invalidating the restore.
  11009. // Vendors have been told that if a file is in use, they must use MoveFileEx with
  11010. // the delay until reboot option. Hence by write locking the file, their copy will
  11011. // fail and they will be forced to use MoveFileEx with the delay until reboot option
  11012. // for the metabase files. Once that happens we're safe because on a reboot we will
  11013. // read from their new files.
  11014. //
  11015. // Note1: We are going to document that full volume restore is not going to work when
  11016. // edit while running is enabled. This is because we do not lock the file. Also note
  11017. // that when they transition from edit while running enabled/disable state and vice
  11018. // versa, they must always force a flush (SaveAllData) for any of these changes,
  11019. // because we look at the enabled/disable value only in SaveAllData
  11020. //
  11021. // Note2: There is a window where the file will not be write locked. For Eg: When
  11022. // we rename metabase.xml.tmp to metabase.xml, we have to unlock the metabase.xml,
  11023. // rename it to metabase.xml and relock metabase,xml. Similarly when invoking compile,
  11024. // we will have to unlock mbschema.xml invoke compile (that will regenerate mbschema.xml)
  11025. // and relock mbschema.xml. But these windows are very small.
  11026. //
  11027. // Note3: The g_ahMetabaseFile is protected by the read/sve semaphore.
  11028. //
  11029. HRESULT LockMetabaseFile(LPWSTR pwszMetabaseFile,
  11030. eMetabaseFile eMetabaseFileType,
  11031. BOOL bHaveReadSaveSemaphore)
  11032. {
  11033. HRESULT hr = S_OK;
  11034. if (!bHaveReadSaveSemaphore)
  11035. {
  11036. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  11037. }
  11038. MD_ASSERT(INVALID_HANDLE_VALUE == g_ahMetabaseFile[eMetabaseFileType]);
  11039. g_ahMetabaseFile[eMetabaseFileType] = CreateFileW(pwszMetabaseFile,
  11040. GENERIC_READ,
  11041. FILE_SHARE_READ,
  11042. NULL,
  11043. OPEN_EXISTING,
  11044. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  11045. NULL);
  11046. if(INVALID_HANDLE_VALUE == g_ahMetabaseFile[eMetabaseFileType])
  11047. {
  11048. hr = GetLastError();
  11049. hr = HRESULT_FROM_WIN32(hr);
  11050. }
  11051. if (!bHaveReadSaveSemaphore)
  11052. {
  11053. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  11054. }
  11055. return hr;
  11056. }
  11057. HRESULT UnlockMetabaseFile(eMetabaseFile eMetabaseFileType,
  11058. BOOL bHaveReadSaveSemaphore)
  11059. {
  11060. HRESULT hr = S_OK;
  11061. if(INVALID_HANDLE_VALUE != g_ahMetabaseFile[eMetabaseFileType])
  11062. {
  11063. if (!bHaveReadSaveSemaphore)
  11064. {
  11065. MD_REQUIRE(WaitForSingleObject(g_hReadSaveSemaphore, INFINITE) != WAIT_TIMEOUT);
  11066. }
  11067. if(!CloseHandle(g_ahMetabaseFile[eMetabaseFileType]))
  11068. {
  11069. hr = GetLastError();
  11070. hr = HRESULT_FROM_WIN32(hr);
  11071. }
  11072. g_ahMetabaseFile[eMetabaseFileType] = INVALID_HANDLE_VALUE;
  11073. if (!bHaveReadSaveSemaphore)
  11074. {
  11075. MD_REQUIRE(ReleaseSemaphore(g_hReadSaveSemaphore, 1, NULL));
  11076. }
  11077. }
  11078. return hr;
  11079. }
  11080. /*
  11081. This is a wrapper function that logs the appropriate event
  11082. //-----------------Columns as Struct---------------
  11083. struct tDETAILEDERRORSRow {
  11084. ULONG * pErrorID;
  11085. WCHAR * pDescription;
  11086. WCHAR * pDate;
  11087. WCHAR * pTime;
  11088. WCHAR * pSourceModuleName;
  11089. WCHAR * pMessageString;
  11090. WCHAR * pCategoryString;
  11091. WCHAR * pSource;
  11092. ULONG * pType;
  11093. ULONG * pCategory;
  11094. WCHAR * pUser;
  11095. WCHAR * pComputer;
  11096. unsigned char * pData;
  11097. ULONG * pEvent;
  11098. WCHAR * pString1;
  11099. WCHAR * pString2;
  11100. WCHAR * pString3;
  11101. WCHAR * pString4;
  11102. WCHAR * pString5;
  11103. ULONG * pErrorCode;
  11104. ULONG * pInterceptor;
  11105. WCHAR * pInterceptorSource;
  11106. ULONG * pOperationType;
  11107. WCHAR * pTable;
  11108. WCHAR * pConfigurationSource;
  11109. ULONG * pRow;
  11110. ULONG * pColumn;
  11111. ULONG * pMajorVersion;
  11112. ULONG * pMinorVersion;
  11113. };
  11114. */
  11115. HRESULT LogEvent(ICatalogErrorLogger2* pLogger,
  11116. DWORD dwError,
  11117. DWORD dwErrorType,
  11118. DWORD dwErrorCategory,
  11119. DWORD dwHr,
  11120. WCHAR* pString1, /* Default = NULL */
  11121. WCHAR* pString2, /* Default = NULL */
  11122. WCHAR* pString3, /* Default = NULL */
  11123. WCHAR* pString4, /* Default = NULL */
  11124. WCHAR* pString5) /* Default = NULL */
  11125. {
  11126. static LPCWSTR wszSource = L"IIS Config";
  11127. struct tDETAILEDERRORSRow sErr;
  11128. memset(&sErr, 0, sizeof(struct tDETAILEDERRORSRow ));
  11129. sErr.pSource = (WCHAR*)wszSource;
  11130. sErr.pType = &dwErrorType;
  11131. sErr.pCategory = &dwErrorCategory;
  11132. sErr.pEvent = &dwError;
  11133. sErr.pErrorCode = &dwHr;
  11134. sErr.pString1 = pString1;
  11135. sErr.pString2 = pString2;
  11136. sErr.pString3 = pString3;
  11137. sErr.pString4 = pString4;
  11138. sErr.pString5 = pString5;
  11139. return pLogger->ReportError(BaseVersion_DETAILEDERRORS,
  11140. ExtendedVersion_DETAILEDERRORS,
  11141. cDETAILEDERRORS_NumberOfColumns,
  11142. NULL,
  11143. (LPVOID*)&sErr);
  11144. }