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.

4430 lines
144 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. ///
  3. ///
  4. /// MPSMisc.C
  5. ///
  6. /// Microsoft Property Store - WAB Dll - miscellaneous helper functions
  7. ///
  8. /// binSearchStr
  9. /// binSearchEID
  10. /// LoadIndex
  11. /// SizeOfSinglePropData
  12. /// SizeOfMultiPropData
  13. /// UnlockFileAccess
  14. /// LockFileAccess
  15. /// LocalFreePropArray
  16. /// FreePcontentlist
  17. /// ReadRecordWithoutLocking
  18. /// GetWABBackupFileName
  19. /// CopySrcFileToDestFile
  20. /// bIsValidRecord
  21. /// TagWABFileError
  22. /// ReloadMPSWabFileInfo
  23. ///
  24. /// CreateMPSWabFile
  25. /// CompressFile
  26. /// HrDoQuickWABIntegrityCheck
  27. /// HrResetWABFileContents
  28. /// HrRestoreFromBackup
  29. /// HrDoDetailedWABIntegrityCheck
  30. /////////////////////////////////////////////////////////////////////////////////
  31. #include "_apipch.h"
  32. extern BOOL fTrace; // Set TRUE if you want debug traces
  33. extern BOOL fDebugTrap; // Set TRUE to get int3's
  34. extern TCHAR szDebugOutputFile[MAX_PATH]; // the name of the debug output file
  35. extern BOOL SubstringSearch(LPTSTR pszTarget, LPTSTR pszSearch);
  36. BOOL CopySrcFileToDestFile(HANDLE hSrc, ULONG ulSrcStartOffset,
  37. HANDLE hDest,ULONG ulDestStartOffset);
  38. //$$////////////////////////////////////////////////////////////////////////////
  39. //
  40. // Gets us a WAB specific temp file name to play with
  41. //
  42. //
  43. ////////////////////////////////////////////////////////////////////////////////
  44. void GetWABTempFileName(LPTSTR szFileName)
  45. {
  46. TCHAR szBuf[MAX_PATH];
  47. TCHAR szBufPath[MAX_PATH];
  48. szBufPath[0]='\0';
  49. GetTempPath(MAX_PATH,szBufPath);
  50. LoadString(hinstMapiX, IDS_WAB_TEMP_FILE_PREFIX, szBuf, CharSizeOf(szBuf));
  51. GetTempFileName(szBufPath, /* dir. for temp. files */
  52. szBuf, //"MPS", /* temp. filename prefix */
  53. 0, /* create unique name w/ sys. time */
  54. (LPTSTR) szFileName); /* buffer for name */
  55. return;
  56. }
  57. //$$//////////////////////////////////////////////////////////////////////////////////
  58. //
  59. // BOOL binSearchStr - binary search routine for scanning string indexes
  60. //
  61. // IN struct _tagIndexOffset * Index - Index Array to Search in
  62. // IN LPTSTR lpszValue - value to search for
  63. // IN ULONG nArraySize - number of elements in array
  64. // OUT ULONG lpulMatchIndex - array index of matched item
  65. //
  66. // Returns:
  67. // Nothing found: FALSE - lpulMatchIndex contains array position at which this entry
  68. // this entry would hypothetically exist, were it a part of the array
  69. // Match found: TRUE - lpulMatchIndex contains array position of matched entry
  70. //
  71. // Comments:
  72. // Algorithm from "Data Structures" by Reingold & Hansen, pg. 278.
  73. //
  74. ////////////////////////////////////////////////////////////////////////////////////
  75. BOOL BinSearchStr( IN struct _tagMPSWabIndexEntryDataString * lpIndexStr,
  76. IN LPTSTR lpszValue, //used for searching strings
  77. IN ULONG nArraySize,
  78. OUT ULONG * lpulMatchIndex)
  79. {
  80. LONG low = 0;
  81. LONG high = nArraySize - 1;
  82. LONG mid = (low + high) / 2;
  83. int comp = 0;
  84. BOOL bRet = FALSE;
  85. *lpulMatchIndex = 0;
  86. if (nArraySize == 0) return FALSE;
  87. while (low <= high && ! bRet) {
  88. mid = (low + high) / 2;
  89. comp = lstrcmpi(lpIndexStr[mid].szIndex, lpszValue);
  90. if (comp < 0) {
  91. low = mid + 1;
  92. } else if (comp > 0) {
  93. high = mid - 1;
  94. } else {
  95. bRet = TRUE;
  96. }
  97. }
  98. // Calculate found or insert position
  99. (ULONG)*lpulMatchIndex = bRet ? mid : low;
  100. // DebugTrace(TEXT("\tBinSearchSTR: Exit\n"));
  101. return bRet;
  102. }
  103. //$$//////////////////////////////////////////////////////////////////////////////////
  104. //
  105. // BOOL binSearchEID - binary search routine for scanning EntryID index
  106. //
  107. // IN lpIndexEID - Index Array to Search in
  108. // IN LPTSTR dwValue - value to search for
  109. // IN ULONG nArraySize - number of elements in array
  110. // OUT ULONG lpulMatchIndex - array index of matched item
  111. //
  112. // Returns:
  113. // Nothing found: FALSE - lpulMatchIndex contains array position at which this entry
  114. // this entry would hypothetically exist, were it a part of the array
  115. // Match found: TRUE - lpulMatchIndex contains array position of matched entry
  116. //
  117. ////////////////////////////////////////////////////////////////////////////////////
  118. BOOL BinSearchEID( IN struct _tagMPSWabIndexEntryDataEntryID * lpIndexEID,
  119. IN DWORD dwValue, //used for comparing DWORDs
  120. IN ULONG nArraySize,
  121. OUT ULONG * lpulMatchIndex)
  122. {
  123. LONG low = 0;
  124. LONG high = nArraySize - 1;
  125. LONG mid = (low + high) / 2;
  126. BOOL bRet = FALSE;
  127. *lpulMatchIndex = 0;
  128. // The special cases for this algorithm are
  129. // nArraySize == 0
  130. if (nArraySize == 0) return FALSE;
  131. while (low <= high && ! bRet) {
  132. mid = (low + high) / 2;
  133. if (lpIndexEID[mid].dwEntryID < dwValue)
  134. low = mid+1;
  135. else if (lpIndexEID[mid].dwEntryID > dwValue)
  136. high = mid - 1;
  137. else //equal
  138. bRet = TRUE;
  139. }
  140. // Calculate found or insert position
  141. (ULONG)*lpulMatchIndex = bRet ? mid : low;
  142. return bRet;
  143. }
  144. //$$//////////////////////////////////////////////////////////////////////////////////
  145. //
  146. // CreateMPSWabFile
  147. //
  148. // Internal function for creating the MPS Wab File - called from several places
  149. //
  150. // IN ulcMaxEntries - this number determines how much space we put aside for
  151. // the indexes when we create the file. From time to time
  152. // we will need to grow the file so we can call this CreateFile
  153. // function to create the new file with the new size...
  154. //
  155. ////////////////////////////////////////////////////////////////////////////////////
  156. BOOL CreateMPSWabFile(IN struct _tagMPSWabFileHeader * lpMPSWabFileHeader,
  157. IN LPTSTR lpszFileName,
  158. IN ULONG ulcMaxEntries,
  159. IN ULONG ulNamedPropSize)
  160. {
  161. HRESULT hr = E_FAIL;
  162. HANDLE hMPSWabFile = NULL;
  163. DWORD dwNumofBytesWritten;
  164. LPVOID lpszBuffer = NULL;
  165. int i = 0;
  166. DebugTrace(TEXT("\tCreateMPSWabFile: Entry\n"));
  167. //
  168. // Create the file - its assumed that calling function has worked out all the
  169. // logic for whether or not old file should be left alone or not.
  170. //
  171. hMPSWabFile = CreateFile( lpszFileName,
  172. GENERIC_WRITE,
  173. 0,
  174. (LPSECURITY_ATTRIBUTES) NULL,
  175. CREATE_ALWAYS,
  176. FILE_ATTRIBUTE_NORMAL,
  177. (HANDLE) NULL);
  178. if (hMPSWabFile == INVALID_HANDLE_VALUE)
  179. {
  180. DebugPrintError(( TEXT("Could not create file.\nExiting ...\n")));
  181. goto out;
  182. }
  183. lpMPSWabFileHeader->ulModificationCount = 0;
  184. lpMPSWabFileHeader->MPSWabGuid = MPSWab_GUID;
  185. lpMPSWabFileHeader->ulcNumEntries = 0;
  186. lpMPSWabFileHeader->ulcMaxNumEntries = ulcMaxEntries;
  187. lpMPSWabFileHeader->ulFlags = WAB_CLEAR;
  188. lpMPSWabFileHeader->ulReserved1 = 0;
  189. lpMPSWabFileHeader->ulReserved2 = 0;
  190. lpMPSWabFileHeader->ulReserved3 = 0;
  191. lpMPSWabFileHeader->ulReserved4 = 0;
  192. lpMPSWabFileHeader->dwNextEntryID = 1;
  193. // We will squeeze in the space to save the named property data betweeen th
  194. // File header and the First Index
  195. lpMPSWabFileHeader->NamedPropData.ulOffset = sizeof(MPSWab_FILE_HEADER);
  196. lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize = 0;
  197. lpMPSWabFileHeader->NamedPropData.ulcNumEntries = 0;
  198. lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize = ulNamedPropSize;
  199. // its important that this order matches TEXT("enum _IndexType") in mpswab.h
  200. // or we'll have major read-write problems
  201. for(i=0;i<indexMax;i++)
  202. {
  203. lpMPSWabFileHeader->IndexData[i].UtilizedBlockSize = 0;
  204. lpMPSWabFileHeader->IndexData[i].ulcNumEntries = 0;
  205. if(i==indexEntryID)
  206. {
  207. lpMPSWabFileHeader->IndexData[i].ulOffset = lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize + lpMPSWabFileHeader->NamedPropData.ulOffset;
  208. lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize = ulcMaxEntries * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
  209. }
  210. else
  211. {
  212. lpMPSWabFileHeader->IndexData[i].ulOffset = lpMPSWabFileHeader->IndexData[i-1].ulOffset + lpMPSWabFileHeader->IndexData[i-1].AllocatedBlockSize;
  213. lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize = ulcMaxEntries * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
  214. }
  215. }
  216. //Now we write this dummy structure to the file
  217. if(!WriteFile( hMPSWabFile,
  218. (LPCVOID) lpMPSWabFileHeader,
  219. (DWORD) sizeof(MPSWab_FILE_HEADER),
  220. &dwNumofBytesWritten,
  221. NULL))
  222. {
  223. DebugPrintError(( TEXT("Writing FileHeader failed.\n")));
  224. goto out;
  225. }
  226. //Assuming that the entryid index is always smaller than the display name index
  227. // allocate enough empty space for a display name index and
  228. lpszBuffer = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileHeader->IndexData[indexDisplayName].AllocatedBlockSize);
  229. if(!lpszBuffer)
  230. {
  231. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  232. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  233. goto out;
  234. }
  235. // Write the dummy blank Named Prop data into the file
  236. // (this ensures that there are all zeros in the blank space)
  237. // Assumes that the NamedPropData will be less than the index space
  238. if(!WriteFile( hMPSWabFile,
  239. (LPCVOID) lpszBuffer,
  240. (DWORD) lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize,
  241. &dwNumofBytesWritten,
  242. NULL))
  243. {
  244. DebugPrintError(( TEXT("Writing Index No. %d failed.\n"),i));
  245. goto out;
  246. }
  247. for (i=0;i<indexMax;i++)
  248. {
  249. if(!WriteFile( hMPSWabFile,
  250. (LPCVOID) lpszBuffer,
  251. (DWORD) lpMPSWabFileHeader->IndexData[i].AllocatedBlockSize,
  252. &dwNumofBytesWritten,
  253. NULL))
  254. {
  255. DebugPrintError(( TEXT("Writing Index No. %d failed.\n"),i));
  256. goto out;
  257. }
  258. }
  259. LocalFreeAndNull(&lpszBuffer);
  260. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  261. hMPSWabFile = NULL;
  262. hr = S_OK;
  263. out:
  264. LocalFreeAndNull(&lpszBuffer);
  265. DebugTrace(TEXT("\tCreateMPSWabFile: Exit\n"));
  266. return( (FAILED(hr)) ? FALSE : TRUE);
  267. }
  268. //$$//////////////////////////////////////////////////////////////////////////////////
  269. //
  270. // LoadIndex - Only one of the string indexes is loaded at any given time
  271. // If we need some other index in memory, we have to reload it from the file ...
  272. //
  273. // This assumes that the ulcNumEntries and UtilizedBlockData for each index in the file header is up to date
  274. // because that value is used to allocate memory for the index
  275. //
  276. // We use this function as a generic load index function too
  277. //
  278. //
  279. ////////////////////////////////////////////////////////////////////////////////////
  280. BOOL LoadIndex( IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo,
  281. IN ULONG nIndexType,
  282. IN HANDLE hMPSWabFile)
  283. {
  284. BOOL bRet = FALSE;
  285. DWORD dwNumofBytes = 0;
  286. // DebugTrace(TEXT("\tLoadIndex: Entry\n"));
  287. if (!lpMPSWabFileInfo) goto out;
  288. if (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries==0) //assumes this is an accurate value
  289. {
  290. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
  291. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
  292. bRet = TRUE;
  293. goto out;
  294. }
  295. //otherwise we have to reload the index from file
  296. //
  297. //First free the existing index
  298. //
  299. if (nIndexType == indexEntryID)
  300. {
  301. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
  302. }
  303. else
  304. {
  305. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
  306. }
  307. //Load the index into memory
  308. if(0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  309. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].ulOffset,
  310. NULL,
  311. FILE_BEGIN))
  312. {
  313. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  314. goto out;
  315. }
  316. if (nIndexType == indexEntryID)
  317. {
  318. lpMPSWabFileInfo->lpMPSWabIndexEID = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize);
  319. if(!(lpMPSWabFileInfo->lpMPSWabIndexEID))
  320. {
  321. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  322. goto out;
  323. }
  324. if(!ReadFile( hMPSWabFile,
  325. (LPVOID) lpMPSWabFileInfo->lpMPSWabIndexEID,
  326. (DWORD) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize,
  327. &dwNumofBytes,
  328. NULL))
  329. {
  330. DebugPrintError(( TEXT("Reading Index failed.\n")));
  331. goto out;
  332. }
  333. }
  334. else
  335. {
  336. lpMPSWabFileInfo->lpMPSWabIndexStr = LocalAlloc(LMEM_ZEROINIT, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize);
  337. if(!(lpMPSWabFileInfo->lpMPSWabIndexStr))
  338. {
  339. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  340. goto out;
  341. }
  342. if(!ReadFile( hMPSWabFile,
  343. (LPVOID) lpMPSWabFileInfo->lpMPSWabIndexStr,
  344. (DWORD) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[nIndexType].UtilizedBlockSize,
  345. &dwNumofBytes,
  346. NULL))
  347. {
  348. DebugPrintError(( TEXT("Reading Index failed.\n")));
  349. goto out;
  350. }
  351. }
  352. if (nIndexType != indexEntryID)
  353. lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType = nIndexType;
  354. bRet = TRUE;
  355. out:
  356. // DebugTrace(TEXT( TEXT("\tLoadIndex: Exit\n")));
  357. return bRet;
  358. }
  359. //$$//////////////////////////////////////////////////////////////////////////////////
  360. //
  361. // SizeOfSinglePropData - returns the number of bytes of data in a given SPropValue ...
  362. //
  363. //
  364. ////////////////////////////////////////////////////////////////////////////////////
  365. ULONG SizeOfSinglePropData(SPropValue Prop)
  366. {
  367. ULONG i = 0;
  368. ULONG ulDataSize = 0;
  369. switch(PROP_TYPE(Prop.ulPropTag))
  370. {
  371. case PT_I2:
  372. ulDataSize = sizeof(short int);
  373. break;
  374. case PT_LONG:
  375. ulDataSize = sizeof(LONG);
  376. break;
  377. case PT_R4:
  378. ulDataSize = sizeof(float);
  379. break;
  380. case PT_DOUBLE:
  381. ulDataSize = sizeof(double);
  382. break;
  383. case PT_BOOLEAN:
  384. ulDataSize = sizeof(unsigned short int);
  385. break;
  386. case PT_CURRENCY:
  387. ulDataSize = sizeof(CURRENCY);
  388. break;
  389. case PT_APPTIME:
  390. ulDataSize = sizeof(double);
  391. break;
  392. case PT_SYSTIME:
  393. ulDataSize = sizeof(FILETIME);
  394. break;
  395. case PT_STRING8:
  396. ulDataSize = lstrlenA(Prop.Value.lpszA)+1;
  397. break;
  398. case PT_UNICODE:
  399. ulDataSize = sizeof(TCHAR)*(lstrlenW(Prop.Value.lpszW)+1);
  400. break;
  401. case PT_BINARY:
  402. ulDataSize = Prop.Value.bin.cb;
  403. break;
  404. case PT_CLSID:
  405. ulDataSize = sizeof(GUID);
  406. break;
  407. case PT_I8:
  408. ulDataSize = sizeof(LARGE_INTEGER);
  409. break;
  410. case PT_ERROR:
  411. ulDataSize = sizeof(SCODE);
  412. break;
  413. case PT_NULL:
  414. ulDataSize = sizeof(LONG);
  415. break;
  416. }
  417. return ulDataSize;
  418. }
  419. //$$//////////////////////////////////////////////////////////////////////////////////
  420. //
  421. // SizeOfMultiPropData - returns the number of bytes of data in a given SPropValue ...
  422. //
  423. //
  424. ////////////////////////////////////////////////////////////////////////////////////
  425. ULONG SizeOfMultiPropData(SPropValue Prop)
  426. {
  427. ULONG i = 0;
  428. ULONG ulDataSize = 0;
  429. switch(PROP_TYPE(Prop.ulPropTag))
  430. {
  431. case PT_MV_I2:
  432. ulDataSize = sizeof(short int) * Prop.Value.MVi.cValues;
  433. break;
  434. case PT_MV_LONG:
  435. ulDataSize = sizeof(LONG) * Prop.Value.MVl.cValues;
  436. break;
  437. case PT_MV_R4:
  438. ulDataSize = sizeof(float) * Prop.Value.MVflt.cValues;
  439. break;
  440. case PT_MV_DOUBLE:
  441. ulDataSize = sizeof(double) * Prop.Value.MVdbl.cValues;
  442. break;
  443. case PT_MV_CURRENCY:
  444. ulDataSize = sizeof(CURRENCY) * Prop.Value.MVcur.cValues;
  445. break;
  446. case PT_MV_APPTIME:
  447. ulDataSize = sizeof(double) * Prop.Value.MVat.cValues;
  448. break;
  449. case PT_MV_SYSTIME:
  450. ulDataSize = sizeof(FILETIME) * Prop.Value.MVft.cValues;
  451. break;
  452. case PT_MV_BINARY:
  453. ulDataSize = 0;
  454. // Note this data size includes, for each array entry, the sizeof(ULONG) that
  455. // contains the actual datasize (i.e cb)
  456. for(i=0;i<Prop.Value.MVbin.cValues;i++)
  457. {
  458. ulDataSize += sizeof(ULONG) + Prop.Value.MVbin.lpbin[i].cb;
  459. }
  460. break;
  461. case PT_MV_STRING8:
  462. ulDataSize = 0;
  463. DebugTrace(TEXT("where the heck are we getting ANSI data from\n"));
  464. // Note this data size includes, for each array entry, the sizeof(ULONG) that
  465. // contains the actual datasize (i.e cb)
  466. for(i=0;i<Prop.Value.MVszA.cValues;i++)
  467. {
  468. // Note the strlen is incremented by '+1' to include the terminating NULL for
  469. // each string
  470. ulDataSize += sizeof(ULONG) + lstrlenA(Prop.Value.MVszA.lppszA[i])+1;
  471. }
  472. break;
  473. case PT_MV_UNICODE:
  474. ulDataSize = 0;
  475. // Note this data size includes, for each array entry, the sizeof(ULONG) that
  476. // contains the actual datasize (i.e cb)
  477. for(i=0;i<Prop.Value.MVszW.cValues;i++)
  478. {
  479. // Note the strlen is incremented by '+1' to include the terminating NULL for
  480. // each string
  481. ulDataSize += sizeof(ULONG) + sizeof(TCHAR)*(lstrlenW(Prop.Value.MVszW.lppszW[i])+1);
  482. }
  483. break;
  484. case PT_MV_CLSID:
  485. ulDataSize = sizeof(GUID) * Prop.Value.MVguid.cValues;
  486. break;
  487. case PT_MV_I8:
  488. ulDataSize = sizeof(LARGE_INTEGER) * Prop.Value.MVli.cValues;
  489. break;
  490. }
  491. return ulDataSize;
  492. }
  493. //$$//////////////////////////////////////////////////////////////////////////////////
  494. //
  495. // ReloadMPSWabFileInfo - Reloads the MPSWabFileHeader and reloads the
  496. // memory indexes. This is a performance hit but cant be helped since it
  497. // is the most reliable way to ensure we are working with the latest
  498. // valid information
  499. //
  500. // Thus a write by one program cannot mess up the read by another program
  501. //
  502. ////////////////////////////////////////////////////////////////////////////////////
  503. BOOL ReloadMPSWabFileInfo(
  504. IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo,
  505. IN HANDLE hMPSWabFile)
  506. {
  507. BOOL bRet = TRUE;
  508. ULONG i = 0;
  509. DWORD dwNumofBytes = 0;
  510. if(!ReadDataFromWABFile(hMPSWabFile,
  511. 0,
  512. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  513. sizeof(MPSWab_FILE_HEADER)))
  514. goto out;
  515. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  516. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  517. for(i=indexDisplayName;i<indexMax;i++)
  518. {
  519. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  520. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  521. }
  522. if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED)
  523. {
  524. if(!WriteFile( hMPSWabFile,
  525. (LPCVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  526. (DWORD) sizeof(MPSWab_FILE_HEADER),
  527. &dwNumofBytes,
  528. NULL))
  529. {
  530. DebugPrintError(( TEXT("Writing FileHeader failed.\n")));
  531. goto out;
  532. }
  533. }
  534. //
  535. // Get the Entry iD index
  536. //
  537. if (!LoadIndex( IN lpMPSWabFileInfo,
  538. IN indexEntryID,
  539. IN hMPSWabFile) )
  540. {
  541. DebugPrintError(( TEXT("Error Loading EntryID Index!\n")));
  542. goto out;
  543. }
  544. //
  545. // Get the current string index
  546. //
  547. if (!LoadIndex( IN lpMPSWabFileInfo,
  548. IN lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType,
  549. IN hMPSWabFile) )
  550. {
  551. DebugPrintError(( TEXT("Error Loading String Index!\n")));
  552. goto out;
  553. }
  554. bRet = TRUE;
  555. out:
  556. return bRet;
  557. }
  558. //$$//////////////////////////////////////////////////////////////////////////////////
  559. //
  560. // UnlockFileAccess - UnLocks Exclusive Access to the property store
  561. //
  562. ////////////////////////////////////////////////////////////////////////////////////
  563. BOOL UnLockFileAccess(LPMPSWab_FILE_INFO lpMPSWabFileInfo)
  564. {
  565. BOOL bRet = FALSE;
  566. //DebugTrace(TEXT( TEXT("\t\tUnlockFileAccess\n")));
  567. if(lpMPSWabFileInfo)
  568. {
  569. bRet = ReleaseMutex(lpMPSWabFileInfo->hDataAccessMutex);
  570. }
  571. return bRet;
  572. }
  573. //$$//////////////////////////////////////////////////////////////////////////////////
  574. //
  575. // LockFileAccess - Gives exclusive access to the Property Store
  576. //
  577. ////////////////////////////////////////////////////////////////////////////////////
  578. BOOL LockFileAccess(LPMPSWab_FILE_INFO lpMPSWabFileInfo)
  579. {
  580. BOOL bRet = FALSE;
  581. DWORD dwWait = 0;
  582. //DebugTrace(TEXT( TEXT("\t\tLockFileAccess\n")));
  583. if(lpMPSWabFileInfo)
  584. {
  585. dwWait = WaitForSingleObject(lpMPSWabFileInfo->hDataAccessMutex,MAX_LOCK_FILE_TIMEOUT);
  586. if ((dwWait == WAIT_TIMEOUT) || (dwWait == WAIT_FAILED))
  587. {
  588. DebugPrintError(( TEXT("Thread:%x\tWaitForSingleObject failed.\n"),GetCurrentThreadId()));
  589. bRet = FALSE;
  590. }
  591. else
  592. bRet = TRUE;
  593. }
  594. return(bRet);
  595. }
  596. //$$//////////////////////////////////////////////////////////////////////////////////
  597. //
  598. // CompressFile - Creates a compressed version of the property store
  599. // file that removes all the invlaid records.
  600. //
  601. // The compressiong function is very similar to creating a backup and hence
  602. // the exported Backup function calls CompressFile. The difference being that
  603. // in Backup, a new file is created with a new name and in CompressFile, the
  604. // newfile is renamed to the property store
  605. //
  606. // Similarly, growing the file is very similar and the internal call to Growing
  607. // the file calls CompressFile too
  608. //
  609. //
  610. // IN lpMPSWabFileInfo
  611. // IN lpsznewFileName - supplied by backup. if NULL, means that CompressFile
  612. // should rename the new file as the property store
  613. // IN BOOL bGrowFile - if specified, the new file is created with space for
  614. // an additional MAX_INITIAL_INDEX_ENTRIES
  615. // IN ULONG ulFlags - there are 2 things that can grow here - the index size and
  616. // the named property storage size. Hence we have the following flags
  617. // one or more of which can be used simultaneously
  618. // AB_GROW_INDEX | AB_GROW_NAMEDPROP
  619. //
  620. // Returns
  621. // Success: TRUE
  622. // Failure: FALSE
  623. //
  624. ////////////////////////////////////////////////////////////////////////////////////
  625. BOOL CompressFile( IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo,
  626. IN HANDLE hMPSWabFile,
  627. IN LPTSTR lpszFileName,
  628. IN BOOL bGrowFile,
  629. IN ULONG ulFlags)
  630. {
  631. BOOL bRet = FALSE;
  632. BOOL bBackup = FALSE;
  633. BOOL bRFileLocked = FALSE;
  634. BOOL bWFileLocked = FALSE;
  635. HANDLE hTempFile = NULL;
  636. struct _tagMPSWabFileHeader NewFileHeader = {0};
  637. ULONG ulNewFileMaxEntries = 0;
  638. ULONG ulNamedPropSize = 0;
  639. DWORD dwNumofBytes = 0;
  640. struct _tagMPSWabIndexEntryDataString * lpIndexStr = NULL;
  641. struct _tagMPSWabIndexEntryDataEntryID NewMPSWabIndexEID;
  642. ULONG ulNewRecordOffset = 0;
  643. ULONG ulNewEIDIndexElementOffset = 0;
  644. ULONG i = 0;
  645. LPULONG lpPropTagArray = NULL;
  646. struct _tagMPSWabRecordHeader RecordHeader;
  647. LPVOID lpRecordData = NULL;
  648. ULONG ulBytesLeftToCopy = 0;
  649. ULONG ulChunkSize = 8192; //copy 8k at a time
  650. LPVOID lpv = NULL;
  651. TCHAR szFileName[MAX_PATH];
  652. ULONG ulFileSize = 0;
  653. DebugTrace(TEXT("----Thread:%x\tCompressFile: Entry\n"),GetCurrentThreadId());
  654. // if this is a backup operation we first backup to a temp file and
  655. // then rename the temp file to the backup - this way if the process
  656. // fails we dont lose our last made backup ...
  657. if (lpszFileName != NULL)
  658. {
  659. if (!lstrcmpi(lpszFileName,lpMPSWabFileInfo->lpszMPSWabFileName))
  660. {
  661. DebugPrintError(( TEXT("Cannot backup a file over itself. Please specify new backup file name.")));
  662. goto out;
  663. }
  664. bBackup = TRUE;
  665. }
  666. else
  667. bBackup = FALSE;
  668. GetWABTempFileName(szFileName);
  669. // Find the least multiple of MAX_INITIAL_INDEX_ENTRIES that can accomodate the
  670. // existing entries in the file and set ulNewFilMaxEntries to that number
  671. ulNewFileMaxEntries = 0;
  672. {
  673. int j=0;
  674. for( j = (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries/MAX_INITIAL_INDEX_ENTRIES);j >= 0; j--)
  675. {
  676. if (lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries >= (ULONG) j*MAX_INITIAL_INDEX_ENTRIES)
  677. {
  678. ulNewFileMaxEntries = (j+1)*MAX_INITIAL_INDEX_ENTRIES;
  679. break;
  680. }
  681. }
  682. if (ulNewFileMaxEntries == 0) //this shouldnt happen
  683. ulNewFileMaxEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries;
  684. ulNamedPropSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize;
  685. }
  686. if (bGrowFile)
  687. {
  688. if(ulFlags & AB_GROW_INDEX)
  689. ulNewFileMaxEntries += MAX_INITIAL_INDEX_ENTRIES;
  690. if(ulFlags & AB_GROW_NAMEDPROP)
  691. ulNamedPropSize += NAMEDPROP_STORE_INCREMENT_SIZE;
  692. }
  693. if (!CreateMPSWabFile( IN &NewFileHeader,
  694. IN szFileName,
  695. IN ulNewFileMaxEntries,
  696. IN ulNamedPropSize))
  697. {
  698. DebugPrintError(( TEXT("Could Not Create File %s!\n"),szFileName));
  699. goto out;
  700. }
  701. if (hMPSWabFile == INVALID_HANDLE_VALUE)
  702. {
  703. DebugPrintError(( TEXT("Could not open file.\nExiting ...\n")));
  704. goto out;
  705. }
  706. hTempFile = CreateFile( szFileName,
  707. GENERIC_READ | GENERIC_WRITE,
  708. FILE_SHARE_READ | FILE_SHARE_WRITE,
  709. (LPSECURITY_ATTRIBUTES) NULL,
  710. OPEN_EXISTING,
  711. FILE_FLAG_RANDOM_ACCESS,
  712. (HANDLE) NULL);
  713. if (hTempFile == INVALID_HANDLE_VALUE)
  714. {
  715. DebugPrintError(( TEXT("Could not open file.\nExiting ...\n")));
  716. goto out;
  717. }
  718. ulFileSize = GetFileSize(hMPSWabFile, NULL);
  719. NewFileHeader.ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries;
  720. NewFileHeader.ulModificationCount = 0;
  721. NewFileHeader.dwNextEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID;
  722. NewFileHeader.ulFlags = lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags;
  723. NewFileHeader.NamedPropData.UtilizedBlockSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize;
  724. NewFileHeader.NamedPropData.ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries;
  725. NewFileHeader.ulReserved1 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved1;
  726. NewFileHeader.ulReserved2 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved2;
  727. NewFileHeader.ulReserved3 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved3;
  728. NewFileHeader.ulReserved4 = lpMPSWabFileInfo->lpMPSWabFileHeader->ulReserved4;
  729. for(i=indexEntryID; i<indexMax; i++)
  730. {
  731. NewFileHeader.IndexData[i].UtilizedBlockSize = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].UtilizedBlockSize;
  732. NewFileHeader.IndexData[i].ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries;
  733. }
  734. // write the header info
  735. //
  736. if(!WriteDataToWABFile( hTempFile,
  737. 0,
  738. (LPVOID) &NewFileHeader,
  739. sizeof(MPSWab_FILE_HEADER)))
  740. goto out;
  741. //
  742. // Copy over Named Prop Data
  743. //
  744. {
  745. lpv = NULL;
  746. lpv = LocalAlloc(LMEM_ZEROINIT, NewFileHeader.NamedPropData.UtilizedBlockSize);
  747. if(!lpv)
  748. {
  749. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  750. goto out;
  751. }
  752. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  753. lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset,
  754. NULL,
  755. FILE_BEGIN))
  756. {
  757. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  758. goto out;
  759. }
  760. if (0xFFFFFFFF == SetFilePointer ( hTempFile,
  761. NewFileHeader.NamedPropData.ulOffset,
  762. NULL,
  763. FILE_BEGIN) )
  764. {
  765. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  766. goto out;
  767. }
  768. if(!ReadFile(hMPSWabFile,
  769. (LPVOID) lpv,
  770. (DWORD) NewFileHeader.NamedPropData.UtilizedBlockSize,
  771. &dwNumofBytes,
  772. NULL) )
  773. {
  774. DebugPrintError(( TEXT("read file failed.\n")));
  775. goto out;
  776. }
  777. if(!WriteFile( hTempFile,
  778. (LPCVOID) lpv,
  779. (DWORD) NewFileHeader.NamedPropData.UtilizedBlockSize,
  780. &dwNumofBytes,
  781. NULL))
  782. {
  783. DebugPrintError(( TEXT("write file failed.\n")));
  784. goto out;
  785. }
  786. LocalFreeAndNull(&lpv);
  787. } // Copy over named prop data
  788. //
  789. // Then copy over the string indexes
  790. //
  791. for(i=indexDisplayName; i<indexMax;i++)
  792. {
  793. LocalFreeAndNull(&lpIndexStr);
  794. lpIndexStr = LocalAlloc(LMEM_ZEROINIT, NewFileHeader.IndexData[i].UtilizedBlockSize);
  795. if(!lpIndexStr)
  796. {
  797. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  798. goto out;
  799. }
  800. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  801. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulOffset,
  802. NULL,
  803. FILE_BEGIN))
  804. {
  805. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  806. goto out;
  807. }
  808. if (0xFFFFFFFF == SetFilePointer ( hTempFile,
  809. NewFileHeader.IndexData[i].ulOffset,
  810. NULL,
  811. FILE_BEGIN) )
  812. {
  813. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  814. goto out;
  815. }
  816. if(!ReadFile(hMPSWabFile,
  817. (LPVOID) lpIndexStr,
  818. (DWORD) NewFileHeader.IndexData[i].UtilizedBlockSize,
  819. &dwNumofBytes,
  820. NULL) )
  821. {
  822. DebugPrintError(( TEXT("read file failed.\n")));
  823. goto out;
  824. }
  825. if(!WriteFile( hTempFile,
  826. (LPCVOID) lpIndexStr,
  827. (DWORD) NewFileHeader.IndexData[i].UtilizedBlockSize,
  828. &dwNumofBytes,
  829. NULL))
  830. {
  831. DebugPrintError(( TEXT("write file failed.\n")));
  832. goto out;
  833. }
  834. LocalFreeAndNull(&lpIndexStr);
  835. }
  836. //
  837. // now load the entryid index from the old file
  838. //
  839. if (!LoadIndex( IN lpMPSWabFileInfo,
  840. IN indexEntryID,
  841. IN hMPSWabFile) )
  842. {
  843. DebugPrintError(( TEXT("Error Loading EntryID Index!\n")));
  844. goto out;
  845. }
  846. ulNewRecordOffset = NewFileHeader.IndexData[indexMax - 1].ulOffset + NewFileHeader.IndexData[indexMax - 1].AllocatedBlockSize;
  847. ulNewEIDIndexElementOffset = NewFileHeader.IndexData[indexEntryID].ulOffset;
  848. //
  849. // Walk through the old file entry ID index reading the
  850. // valid records one by one and writing them to the new file. Also write the
  851. // new record offset and the new EID entry into the new file (so that if we
  852. // crash we have as up to date data in the new file as possible
  853. //
  854. for(i=0;i<NewFileHeader.IndexData[indexEntryID].ulcNumEntries;i++)
  855. {
  856. NewMPSWabIndexEID.dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexEID[i].dwEntryID;
  857. NewMPSWabIndexEID.ulOffset = ulNewRecordOffset;
  858. if(!ReadDataFromWABFile(hMPSWabFile,
  859. lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset,
  860. (LPVOID) &RecordHeader,
  861. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  862. goto out;
  863. // if for some reason this was an invalid record .. skip it and go to next
  864. if(!bIsValidRecord( RecordHeader,
  865. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  866. lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset,
  867. ulFileSize))
  868. continue;
  869. LocalFreeAndNull(&lpPropTagArray);
  870. lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, RecordHeader.ulPropTagArraySize);
  871. if(!lpPropTagArray)
  872. {
  873. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  874. goto out;
  875. }
  876. if(!ReadFile( hMPSWabFile,
  877. (LPVOID) lpPropTagArray,
  878. (DWORD) RecordHeader.ulPropTagArraySize,
  879. &dwNumofBytes,
  880. NULL))
  881. {
  882. DebugPrintError(( TEXT("read file failed.\n")));
  883. goto out;
  884. }
  885. LocalFreeAndNull(&lpRecordData);
  886. lpRecordData = LocalAlloc(LMEM_ZEROINIT, RecordHeader.ulRecordDataSize);
  887. if(!lpRecordData)
  888. {
  889. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  890. goto out;
  891. }
  892. if(!ReadFile( hMPSWabFile,
  893. (LPVOID) lpRecordData,
  894. (DWORD) RecordHeader.ulRecordDataSize,
  895. &dwNumofBytes,
  896. NULL))
  897. {
  898. DebugPrintError(( TEXT("read file failed.\n")));
  899. goto out;
  900. }
  901. if(!WriteDataToWABFile(hTempFile,
  902. ulNewRecordOffset,
  903. (LPVOID) &RecordHeader,
  904. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  905. goto out;
  906. // assumes that file pointer will be at the correct spot
  907. if(!WriteFile( hTempFile,
  908. (LPCVOID) lpPropTagArray,
  909. (DWORD) RecordHeader.ulPropTagArraySize,
  910. &dwNumofBytes,
  911. NULL))
  912. {
  913. DebugPrintError(( TEXT("write file failed.\n")));
  914. goto out;
  915. }
  916. // assumes that file pointer will be at the correct spot
  917. if(!WriteFile( hTempFile,
  918. (LPCVOID) lpRecordData,
  919. (DWORD) RecordHeader.ulRecordDataSize,
  920. &dwNumofBytes,
  921. NULL))
  922. {
  923. DebugPrintError(( TEXT("write file failed.\n")));
  924. goto out;
  925. }
  926. ulNewRecordOffset += sizeof(MPSWab_RECORD_HEADER) + RecordHeader.ulPropTagArraySize + RecordHeader.ulRecordDataSize;
  927. LocalFreeAndNull(&lpPropTagArray);
  928. LocalFreeAndNull(&lpRecordData);
  929. //
  930. // Write the new entryID index element
  931. //
  932. if(!WriteDataToWABFile( hTempFile,
  933. ulNewEIDIndexElementOffset,
  934. (LPVOID) &NewMPSWabIndexEID,
  935. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)))
  936. goto out;
  937. ulNewEIDIndexElementOffset += sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
  938. // loop for next record
  939. }
  940. //
  941. // At this point in the process we have successfuly copied over all the
  942. // records from the old file to the new file
  943. //
  944. // If this is a backup operation - we delete the old backup and copy the new temp file
  945. // as the new backup ...
  946. //
  947. // If this is not a backup operation, we want to basically delete the old file
  948. // and rename the new temp file as the property store ..
  949. //
  950. // However, if we release our access to the property store, there is no gaurentee that
  951. // some other process will not grab up exclusive access to the store and we will fail in
  952. // our attempt to gain control and modify ...
  953. //
  954. // Hence the options are
  955. // (a) give up control and then hope we can regain control before someone else does something
  956. // to the file
  957. // (b) copy in the new file contents and overwrite the existing file contents - this is going
  958. // to be slower than rewriting the file but it will give us exclusive control on the
  959. // modifications and makes the process much more robust ...
  960. //
  961. if (!bBackup) // Not a backup operation
  962. {
  963. //
  964. // Save the header in the new file
  965. //
  966. if(!WriteDataToWABFile( hTempFile,
  967. 0,
  968. (LPVOID) &NewFileHeader,
  969. sizeof(MPSWab_FILE_HEADER)))
  970. goto out;
  971. //
  972. // Copy the New file into this WAB file thus replacing the old contents
  973. // and hope this never fails
  974. //
  975. if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0))
  976. {
  977. DebugPrintError(( TEXT("Unable to copy files\n")));
  978. goto out;
  979. }
  980. //
  981. // Reload this so we have the new fileheader info in our structures
  982. //
  983. if(!ReloadMPSWabFileInfo(
  984. lpMPSWabFileInfo,
  985. hMPSWabFile))
  986. {
  987. DebugPrintError(( TEXT("Reading file info failed.\n")));
  988. goto out;
  989. }
  990. //
  991. // Thats it .. we can close the files and party on ..
  992. //
  993. }
  994. else
  995. {
  996. //this is a backup operation ...
  997. // Close the temp file
  998. if (hTempFile)
  999. {
  1000. IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
  1001. hTempFile = NULL;
  1002. }
  1003. if(!CopyFile( szFileName,
  1004. lpszFileName,
  1005. FALSE))
  1006. {
  1007. DebugPrintError(( TEXT("CopyFile %s to %s failed: %d\n"),szFileName,lpszFileName, GetLastError()));
  1008. goto out;
  1009. }
  1010. }
  1011. bRet = TRUE;
  1012. out:
  1013. if (hTempFile)
  1014. IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
  1015. if( szFileName != NULL)
  1016. DeleteFile(szFileName);
  1017. LocalFreeAndNull(&lpv);
  1018. LocalFreeAndNull(&lpPropTagArray);
  1019. LocalFreeAndNull(&lpRecordData);
  1020. DebugTrace(TEXT("----Thread:%x\tCompressFile: Exit\n"),GetCurrentThreadId());
  1021. return bRet;
  1022. }
  1023. //$$//////////////////////////////////////////////////////////////////////////////////
  1024. //
  1025. // ReadRecordWithoutLocking
  1026. //
  1027. // IN lpMPSWabFileInfo
  1028. // IN dwEntryID - EntryID of record to read
  1029. // OUT ulcPropCount - number of props returned
  1030. // OUT lpPropArray - Array of Property values
  1031. //
  1032. // Returns
  1033. // Success: S_OK
  1034. // Failure: E_FAIL
  1035. //
  1036. ////////////////////////////////////////////////////////////////////////////////////
  1037. HRESULT ReadRecordWithoutLocking(
  1038. IN HANDLE hMPSWabFile,
  1039. IN struct _tagMPSWabFileInfo * lpMPSWabFileInfo,
  1040. IN DWORD dwEntryID,
  1041. OUT LPULONG lpulcPropCount,
  1042. OUT LPPROPERTY_ARRAY * lppPropArray)
  1043. {
  1044. HRESULT hr = E_FAIL;
  1045. ULONG ulRecordOffset = 0;
  1046. BOOL bErrorDetected = FALSE;
  1047. ULONG nIndexPos = 0;
  1048. ULONG ulObjType = 0;
  1049. *lpulcPropCount = 0;
  1050. *lppPropArray = NULL;
  1051. //
  1052. // First check if this is a valid entryID
  1053. //
  1054. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  1055. IN dwEntryID,
  1056. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  1057. OUT &nIndexPos))
  1058. {
  1059. DebugPrintError(( TEXT("Specified EntryID doesnt exist!\n")));
  1060. hr = MAPI_E_INVALID_ENTRYID;
  1061. goto out;
  1062. }
  1063. //if entryid exists, we can start reading the record
  1064. ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
  1065. hr = HrGetPropArrayFromFileRecord(hMPSWabFile,
  1066. ulRecordOffset,
  1067. &bErrorDetected,
  1068. &ulObjType,
  1069. NULL,
  1070. lpulcPropCount,
  1071. lppPropArray);
  1072. if(!HR_FAILED(hr))
  1073. {
  1074. // reset the backward compatibility thing-um-a-jig we did between
  1075. // MAPI_ABCONT and MAPI_MAILUSER
  1076. if(ulObjType == RECORD_CONTAINER)
  1077. SetContainerObjectType(*lpulcPropCount, *lppPropArray, FALSE);
  1078. }
  1079. out:
  1080. //a little cleanup on failure
  1081. if (FAILED(hr))
  1082. {
  1083. if(bErrorDetected)
  1084. {
  1085. TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader,
  1086. hMPSWabFile);
  1087. }
  1088. if ((*lppPropArray) && (*lpulcPropCount > 0))
  1089. {
  1090. LocalFreePropArray(NULL, *lpulcPropCount, lppPropArray);
  1091. *lppPropArray = NULL;
  1092. }
  1093. }
  1094. return(hr);
  1095. }
  1096. //$$//////////////////////////////////////////////////////////////////////////////
  1097. //
  1098. // GetWABBackupFileName - derives the backup file name from the WAB file by changing
  1099. // the extension from WAB to BWB
  1100. //
  1101. // lpszWabFileName - WAB file name
  1102. // lpszBackupFileName - Backup File name - points to a preallocated buffer big enough to
  1103. // hold the backup file name
  1104. //
  1105. // This generates a backup name in which the last character is turned into a ~
  1106. ////////////////////////////////////////////////////////////////////////////////////
  1107. void GetWABBackupFileName(LPTSTR lpszWab, LPTSTR lpszBackup, ULONG cchBackup)
  1108. {
  1109. ULONG nLen;
  1110. if(!lpszWab || !lpszBackup)
  1111. goto out;
  1112. nLen = lstrlen(lpszWab);
  1113. // if((nLen < 4) || (lpszWab[nLen-4] != '.'))
  1114. // goto out;
  1115. StrCpyN(lpszBackup,lpszWab, cchBackup);
  1116. lpszBackup[nLen-1]='\0';
  1117. StrCpyN(lpszBackup,TEXT("~"), cchBackup);
  1118. out:
  1119. return;
  1120. }
  1121. //$$//////////////////////////////////////////////////////////////////////////////
  1122. //
  1123. // HrDoQuickWABIntegrityCheck - does a quick integrity check of the WAB indexes
  1124. // Verifies that:
  1125. //
  1126. // - Indexes contain the correct number of entries which is equal to or less than
  1127. // the max number of entries
  1128. // - Indexes dont contain duplicate entry-ids
  1129. // - Indexes point to valid and existing data ...
  1130. //
  1131. // If there are problems, this function attempts to fix them - if it cant fix them
  1132. // we fail and caller should call HrDoDetailedWABIntegrityCheck which will rebuild
  1133. // the indexes from the actual WAB data.
  1134. //
  1135. ////////////////////////////////////////////////////////////////////////////////////
  1136. HRESULT HrDoQuickWABIntegrityCheck(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile)
  1137. {
  1138. HRESULT hr = E_FAIL;
  1139. BOOL bError = FALSE;
  1140. ULONG ulcNumWABEntries = 0,ulcNumIndexEntries = 0;
  1141. LPMPSWab_FILE_HEADER lpMPSWabFileHeader = NULL;
  1142. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  1143. ULONG i=0,j=0;
  1144. DWORD dwNumofBytes = 0;
  1145. ULONG ulFileSize = GetFileSize(hMPSWabFile,NULL);
  1146. lpMPSWabFileHeader = lpMPSWabFileInfo->lpMPSWabFileHeader;
  1147. ulcNumWABEntries = lpMPSWabFileHeader->ulcNumEntries;
  1148. //
  1149. // First check the EntryID index
  1150. //
  1151. if (!LoadIndex( IN lpMPSWabFileInfo,
  1152. IN indexEntryID,
  1153. IN hMPSWabFile) )
  1154. {
  1155. DebugPrintError(( TEXT("Error Loading Index!\n")));
  1156. goto out;
  1157. }
  1158. ulcNumIndexEntries = lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries;
  1159. if(ulcNumIndexEntries != ulcNumWABEntries)
  1160. {
  1161. hr = MAPI_E_INVALID_ENTRYID;
  1162. DebugPrintError(( TEXT("EntryID index has incorrect number of elements\n")));
  1163. goto out;
  1164. }
  1165. if(ulcNumIndexEntries > 0)
  1166. {
  1167. for(i=0;i<ulcNumIndexEntries-1;i++)
  1168. {
  1169. // Since this is a sorted array, the indexes will be in sorted order
  1170. // So we just compare one with the next
  1171. if(lpMPSWabFileInfo->lpMPSWabIndexEID[i].dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexEID[i+1].dwEntryID)
  1172. {
  1173. hr = MAPI_E_INVALID_ENTRYID;
  1174. DebugPrintError(( TEXT("EntryID index has duplicate elements\n")));
  1175. goto out;
  1176. }
  1177. }
  1178. }
  1179. /*
  1180. // This is painfully slowing things down
  1181. // Comment out for now
  1182. //
  1183. // Now we walk through the index and verify that each entry is a valid entry ....
  1184. for(i=0;i<ulcNumIndexEntries;i++)
  1185. {
  1186. ULONG ulOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[i].ulOffset;
  1187. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  1188. if(!ReadDataFromWABFile(hMPSWabFile,
  1189. ulOffset,
  1190. (LPVOID) &MPSWabRecordHeader,
  1191. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  1192. goto out;
  1193. if(!bIsValidRecord( MPSWabRecordHeader,
  1194. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  1195. ulOffset,
  1196. ulFileSize))
  1197. {
  1198. DebugPrintError(( TEXT("Index points to an invalid record\n")));
  1199. hr = MAPI_E_INVALID_ENTRYID;
  1200. goto out;
  1201. }
  1202. }
  1203. */
  1204. // if we're here, then the entry id index checks out ok ...
  1205. //
  1206. // Check out the other indexes also ... we will start backwards since we want to fix potential
  1207. // problems in the First/Last name indexes before we do the more stringent display name case
  1208. //
  1209. for(j=indexMax-1;j>=indexDisplayName;j--)
  1210. {
  1211. if (!LoadIndex( IN lpMPSWabFileInfo,
  1212. IN j,
  1213. IN hMPSWabFile) )
  1214. {
  1215. DebugPrintError(( TEXT("Error Loading Index!\n")));
  1216. goto out;
  1217. }
  1218. ulcNumIndexEntries = lpMPSWabFileHeader->IndexData[j].ulcNumEntries;
  1219. if(j == indexDisplayName)
  1220. {
  1221. if(ulcNumIndexEntries != ulcNumWABEntries)
  1222. {
  1223. DebugPrintError(( TEXT("Display Name index has incorrect number of elements\n")));
  1224. goto out;
  1225. }
  1226. }
  1227. else if(ulcNumIndexEntries > ulcNumWABEntries)
  1228. {
  1229. bError = TRUE;
  1230. goto endloop;
  1231. }
  1232. if(ulcNumIndexEntries > 0)
  1233. {
  1234. for(i=0;i<ulcNumIndexEntries-1;i++)
  1235. {
  1236. // Since this is a sorted array, the indexes will be in sorted order
  1237. // So we just compare one with the next
  1238. if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexStr[i+1].dwEntryID)
  1239. {
  1240. DebugPrintError(( TEXT("String index has duplicate elements\n")));
  1241. if(j == indexDisplayName)
  1242. goto out;
  1243. else
  1244. {
  1245. bError = TRUE;
  1246. goto endloop;
  1247. }
  1248. }
  1249. }
  1250. }
  1251. // Now we walk through the index and verify that each entry is a valid entry ....
  1252. for(i=0;i<ulcNumIndexEntries;i++)
  1253. {
  1254. DWORD dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
  1255. ULONG nIndexPos;
  1256. // All we need to do is to check that the entry id exists in the EntryID index since we
  1257. // have already verified the entryid index
  1258. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  1259. IN dwEntryID,
  1260. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, //IndexEntries,
  1261. OUT &nIndexPos))
  1262. {
  1263. DebugPrintError(( TEXT("Specified EntryID: %d doesnt exist!\n"),dwEntryID));
  1264. hr = MAPI_E_NOT_FOUND;
  1265. if(j == indexDisplayName)
  1266. goto out;
  1267. else
  1268. {
  1269. bError = TRUE;
  1270. goto endloop;
  1271. }
  1272. }
  1273. }
  1274. endloop:
  1275. if(bError &&
  1276. ( (j==indexFirstName) || (j==indexLastName) ))
  1277. {
  1278. // if the problem is in the first/last indexes, we can reset these indexes safely
  1279. //Assert(FALSE);
  1280. ulcNumIndexEntries = 0;
  1281. lpMPSWabFileHeader->IndexData[j].ulcNumEntries = 0;
  1282. lpMPSWabFileHeader->IndexData[j].ulcNumEntries = 0;
  1283. if(!WriteDataToWABFile( hMPSWabFile,
  1284. 0,
  1285. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  1286. sizeof(MPSWab_FILE_HEADER)))
  1287. goto out;
  1288. }
  1289. }
  1290. hr = hrSuccess;
  1291. out:
  1292. return hr;
  1293. }
  1294. //$$///////////////////////////////////////////////////////////////////////////////////////////
  1295. //
  1296. // CopySrcFileToDestFile - replaces contents of Dest file with contents of source file
  1297. // starting at the ulsrcStartOffset and ulDestStartOffset respectively
  1298. // hSrc, hDest - handles to already open files
  1299. // ulSrcStartOffset - start copying from this offset
  1300. // ulDestStartOffset - start copying to this offset
  1301. //
  1302. //////////////////////////////////////////////////////////////////////////////////////////////////
  1303. BOOL CopySrcFileToDestFile(HANDLE hSrc, ULONG ulSrcStartOffset,
  1304. HANDLE hDest,ULONG ulDestStartOffset)
  1305. {
  1306. BOOL bRet = FALSE;
  1307. ULONG ulBytesLeftToCopy = 0;
  1308. DWORD dwNumofBytes = 0;
  1309. ULONG ulChunkSize = 8192; //size of block of bytes to copy from one file into the other
  1310. LPVOID lpv = NULL;
  1311. // copy contents of hSrc into hDest
  1312. //
  1313. // Set the hDest File to 0 length
  1314. //
  1315. if (0xFFFFFFFF == SetFilePointer ( hDest,
  1316. ulDestStartOffset,
  1317. NULL,
  1318. FILE_BEGIN))
  1319. {
  1320. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  1321. goto out;
  1322. }
  1323. //
  1324. // Set end of file to the current file pointer position to discard everything
  1325. // in the file after this point
  1326. //
  1327. if (!SetEndOfFile(hDest))
  1328. {
  1329. DebugPrintError(( TEXT("SetEndofFile Failed\n")));
  1330. goto out;
  1331. }
  1332. //
  1333. // Go to beginning of the source File
  1334. //
  1335. if (0xFFFFFFFF == SetFilePointer( hSrc,
  1336. ulSrcStartOffset,
  1337. NULL,
  1338. FILE_BEGIN))
  1339. {
  1340. DebugPrintError(( TEXT("SetFilePointer Failed\n")));
  1341. goto out;
  1342. }
  1343. //
  1344. // figure out how many bytes to read ...
  1345. //
  1346. ulBytesLeftToCopy = GetFileSize(hSrc, NULL);
  1347. if (0xFFFFFFFF == ulBytesLeftToCopy)
  1348. {
  1349. DebugPrintError(( TEXT("GetFileSize Failed: %d\n"),GetLastError()));
  1350. goto out;
  1351. }
  1352. if(ulSrcStartOffset > ulBytesLeftToCopy)
  1353. {
  1354. DebugPrintError(( TEXT("Error in File Sizes\n")));
  1355. goto out;
  1356. }
  1357. ulBytesLeftToCopy -= ulSrcStartOffset;
  1358. lpv = LocalAlloc(LMEM_ZEROINIT, ulChunkSize);
  1359. if(!lpv)
  1360. {
  1361. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1362. goto out;
  1363. }
  1364. //
  1365. // Loop copying bytes from one file to the other
  1366. while(ulBytesLeftToCopy > 0)
  1367. {
  1368. if (ulBytesLeftToCopy < ulChunkSize)
  1369. ulChunkSize = ulBytesLeftToCopy;
  1370. if(!ReadFile(hSrc,(LPVOID) lpv,(DWORD) ulChunkSize,&dwNumofBytes,NULL))
  1371. {
  1372. DebugPrintError(( TEXT("Read file failed.\n")));
  1373. goto out;
  1374. }
  1375. if (dwNumofBytes != ulChunkSize)
  1376. {
  1377. DebugPrintError(( TEXT("Read file failed.\n")));
  1378. goto out;
  1379. }
  1380. if(!WriteFile(hDest,(LPVOID) lpv,(DWORD) ulChunkSize,&dwNumofBytes,NULL))
  1381. {
  1382. DebugPrintError(( TEXT("Write file failed.\n")));
  1383. goto out;
  1384. }
  1385. if (dwNumofBytes != ulChunkSize)
  1386. {
  1387. DebugPrintError(( TEXT("Write file failed.\n")));
  1388. goto out;
  1389. }
  1390. ulBytesLeftToCopy -= ulChunkSize;
  1391. }
  1392. bRet = TRUE;
  1393. out:
  1394. LocalFreeAndNull(&lpv);
  1395. return bRet;
  1396. }
  1397. //$$//////////////////////////////////////////////////////////////////////////////
  1398. //
  1399. // HrResetWABFileContents - This is called as a last ditch error recovery attempt at
  1400. // deleting the file and reseting its contents in the event that a recovery from
  1401. // backup also failed...
  1402. //
  1403. //
  1404. ////////////////////////////////////////////////////////////////////////////////////
  1405. HRESULT HrResetWABFileContents(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile)
  1406. {
  1407. HRESULT hr = E_FAIL;
  1408. TCHAR szFileName[MAX_PATH];
  1409. MPSWab_FILE_HEADER NewFileHeader;
  1410. HANDLE hTempFile = NULL;
  1411. DebugTrace(TEXT("#####HrResetWABFileContents Entry\n"));
  1412. // Get a temporary file name ...
  1413. GetWABTempFileName(szFileName);
  1414. if (!CreateMPSWabFile( IN &NewFileHeader,
  1415. IN szFileName,
  1416. IN MAX_INITIAL_INDEX_ENTRIES,
  1417. IN NAMEDPROP_STORE_SIZE))
  1418. {
  1419. DebugTrace(TEXT("Could Not Create File %s!\n"),szFileName);
  1420. goto out;
  1421. }
  1422. hTempFile = CreateFile( szFileName,
  1423. GENERIC_READ | GENERIC_WRITE,
  1424. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1425. (LPSECURITY_ATTRIBUTES) NULL,
  1426. OPEN_EXISTING,
  1427. FILE_FLAG_RANDOM_ACCESS,
  1428. (HANDLE) NULL);
  1429. if (hTempFile == INVALID_HANDLE_VALUE)
  1430. {
  1431. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  1432. goto out;
  1433. }
  1434. if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0))
  1435. {
  1436. DebugTrace(TEXT("Unable to copy files\n"));
  1437. goto out;
  1438. }
  1439. //
  1440. // Reload this so we have the new fileheader info in our structures
  1441. //
  1442. if(!ReloadMPSWabFileInfo(
  1443. lpMPSWabFileInfo,
  1444. hMPSWabFile))
  1445. {
  1446. DebugTrace(TEXT("Reading file info failed.\n"));
  1447. goto out;
  1448. }
  1449. hr = hrSuccess;
  1450. out:
  1451. if(HR_FAILED(hr))
  1452. {
  1453. // This is totally unexpected and basically we couldnt even fix the file so tell
  1454. // the user to restart the application - meanwhile we will delete the file
  1455. ShowMessageBox(NULL, idsWABUnexpectedError, MB_ICONHAND | MB_OK);
  1456. // Hope that no one comes and locks this file between the next 2 calls
  1457. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  1458. hMPSWabFile = NULL;
  1459. DeleteFile(lpMPSWabFileInfo->lpszMPSWabFileName);
  1460. }
  1461. if(hTempFile)
  1462. IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
  1463. DebugTrace(TEXT("#####HrResetWABFileContents Exit\n"));
  1464. return hr;
  1465. }
  1466. //$$//////////////////////////////////////////////////////////////////////////////
  1467. //
  1468. // HrRestoreFromBackup - attempts to replace WAB file contents from contents of
  1469. // Backup file
  1470. //
  1471. //
  1472. ////////////////////////////////////////////////////////////////////////////////////
  1473. HRESULT HrRestoreFromBackup(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile)
  1474. {
  1475. HRESULT hr = E_FAIL;
  1476. HANDLE hBackupFile = NULL;
  1477. TCHAR szBackupFileName[MAX_PATH];
  1478. HCURSOR hOldCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
  1479. // Steps to this process are:
  1480. // - Open Backup File
  1481. // - Reset contents of WABFile
  1482. // - Copy Backup into WAB
  1483. // - Close BackupFile
  1484. // - Reload WAB Indexes
  1485. DebugTrace(TEXT("+++++HrRestoreFromBackup Entry\n"));
  1486. // Get the backup file name
  1487. szBackupFileName[0]='\0';
  1488. GetWABBackupFileName(lpMPSWabFileInfo->lpszMPSWabFileName, szBackupFileName, ARRAYSIZE(szBackupFileName));
  1489. hBackupFile = CreateFile( szBackupFileName,
  1490. GENERIC_READ,
  1491. FILE_SHARE_READ,
  1492. (LPSECURITY_ATTRIBUTES) NULL,
  1493. OPEN_EXISTING,
  1494. FILE_FLAG_SEQUENTIAL_SCAN, //FILE_FLAG_RANDOM_ACCESS,
  1495. (HANDLE) NULL);
  1496. if (hBackupFile == INVALID_HANDLE_VALUE)
  1497. {
  1498. DebugTrace(TEXT("Could not open backup file.\nExiting ...\n"));
  1499. hr = MAPI_E_DISK_ERROR;
  1500. goto out;
  1501. }
  1502. if(!CopySrcFileToDestFile(hBackupFile, 0, hMPSWabFile, 0))
  1503. {
  1504. DebugTrace(TEXT("Unable to copy files\n"));
  1505. goto out;
  1506. }
  1507. //
  1508. // Reload this so we have the new fileheader info in our structures
  1509. //
  1510. if(!ReloadMPSWabFileInfo(
  1511. lpMPSWabFileInfo,
  1512. hMPSWabFile))
  1513. {
  1514. DebugTrace(TEXT("Reading file info failed.\n"));
  1515. goto out;
  1516. }
  1517. hr = hrSuccess;
  1518. out:
  1519. // close the backup file
  1520. if(hBackupFile)
  1521. IF_WIN32(CloseHandle(hBackupFile);) IF_WIN16(CloseFile(hBackupFile);)
  1522. SetCursor(hOldCursor);
  1523. DebugTrace(TEXT("+++++HrRestoreFromBackup Exit\n"));
  1524. return hr;
  1525. }
  1526. //$$//////////////////////////////////////////////////////////////////////////////
  1527. //
  1528. // HrDoDetailedWABIntegrityCheck - does a thorough integrity check
  1529. // This is triggered only when an index error was detected or if a write
  1530. // transaction failed.
  1531. //
  1532. // - We step through all the records validating them and their size data
  1533. // - From each valid record we create the sorted entryid index
  1534. // - From the sorted entryid index we read the records and create the
  1535. // - display name index and reset the first last name indexes for now
  1536. //
  1537. // This function should not fail but should try to recover from errors
  1538. // If this function fails we need to break out the backup of the wab file
  1539. //
  1540. ////////////////////////////////////////////////////////////////////////////////////
  1541. HRESULT HrDoDetailedWABIntegrityCheck(LPMPSWab_FILE_INFO lpMPSWabFileInfo, HANDLE hMPSWabFile)
  1542. {
  1543. HRESULT hr = E_FAIL;
  1544. BOOL bEID = FALSE;
  1545. ULONG ulcNumWABEntries = 0,ulcNumIndexEntries = 0;
  1546. MPSWab_FILE_HEADER MPSWabFileHeader = {0};
  1547. MPSWab_FILE_HEADER NewMPSWabFileHeader = {0};
  1548. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  1549. ULONG i=0,j=0;
  1550. DWORD dwNumofBytes = 0;
  1551. DWORD dwEntryID = 0;
  1552. ULONG ulcPropCount = 0;
  1553. LPSPropValue lpPropArray = NULL;
  1554. ULONG ulRecordOffset = 0;
  1555. ULONG ulFileSize = 0;
  1556. ULONG ulcWABEntryCount = 0;
  1557. ULONG nIndexPos = 0;
  1558. MPSWab_INDEX_ENTRY_DATA_ENTRYID MPSWabIndexEID = {0};
  1559. LPMPSWab_INDEX_ENTRY_DATA_ENTRYID lpIndexEID = NULL;
  1560. MPSWab_INDEX_ENTRY_DATA_STRING MPSWabIndexString = {0};
  1561. LPMPSWab_INDEX_ENTRY_DATA_STRING lpIndexString = NULL;
  1562. LPVOID lpTmp = NULL;
  1563. HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
  1564. DebugTrace(TEXT("---DoDetailedWABIntegrityCheck Entry\n"));
  1565. //
  1566. // We will go with the assumption that this WAB is currently a proper wab file
  1567. // otherwise OpenPropertyStore would have failed while opening it.
  1568. //
  1569. // Consequently, we should be able to read the header of the file
  1570. // update the file header
  1571. if(!ReadDataFromWABFile(hMPSWabFile,
  1572. 0,
  1573. (LPVOID) &MPSWabFileHeader,
  1574. (DWORD) sizeof(MPSWab_FILE_HEADER)))
  1575. goto out;
  1576. // We are going to reset the file header for now so that if this process fails,
  1577. // this file will think that there is nothing in the file rather than crashing
  1578. NewMPSWabFileHeader = MPSWabFileHeader;
  1579. NewMPSWabFileHeader.ulModificationCount = 0;
  1580. NewMPSWabFileHeader.ulcNumEntries = 0;
  1581. for(i=0;i<indexMax;i++)
  1582. {
  1583. if(i != indexDisplayName)// Temp Temp TBD TBD
  1584. {
  1585. NewMPSWabFileHeader.IndexData[i].UtilizedBlockSize = 0;
  1586. NewMPSWabFileHeader.IndexData[i].ulcNumEntries = 0;
  1587. }
  1588. }
  1589. //
  1590. // Write this NewMPSWabFileHeader to the file
  1591. //
  1592. if(!WriteDataToWABFile( hMPSWabFile,
  1593. 0,
  1594. (LPVOID) &NewMPSWabFileHeader,
  1595. sizeof(MPSWab_FILE_HEADER)))
  1596. goto out;
  1597. ulFileSize = GetFileSize(hMPSWabFile, NULL);
  1598. if(ulFileSize == 0xFFFFFFFF)
  1599. {
  1600. DebugTrace(TEXT("Error retrieving file size: %d"),GetLastError());
  1601. hr = MAPI_E_DISK_ERROR;
  1602. goto out;
  1603. }
  1604. //
  1605. // Allocate some working space
  1606. //
  1607. lpIndexEID = LocalAlloc(LMEM_ZEROINIT,
  1608. MPSWabFileHeader.IndexData[indexEntryID].AllocatedBlockSize);
  1609. if(!lpIndexEID)
  1610. {
  1611. DebugTrace(TEXT("Error allocating memory\n"));
  1612. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1613. goto out;
  1614. }
  1615. lpTmp = LocalAlloc(LMEM_ZEROINIT,
  1616. MPSWabFileHeader.IndexData[indexEntryID].AllocatedBlockSize);
  1617. if(!lpTmp)
  1618. {
  1619. DebugTrace(TEXT("Error allocating memory\n"));
  1620. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1621. goto out;
  1622. }
  1623. //
  1624. // Now start reading the records 1 by one
  1625. //
  1626. ulRecordOffset = MPSWabFileHeader.IndexData[indexMax-1].ulOffset +
  1627. MPSWabFileHeader.IndexData[indexMax-1].AllocatedBlockSize;
  1628. ulcWABEntryCount = 0;
  1629. while(ulRecordOffset < ulFileSize)
  1630. {
  1631. if(!ReadDataFromWABFile(hMPSWabFile,
  1632. ulRecordOffset,
  1633. (LPVOID) &MPSWabRecordHeader,
  1634. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  1635. goto out;
  1636. //
  1637. // if this is an invalid record ignore it
  1638. //
  1639. if( (MPSWabRecordHeader.bValidRecord != FALSE) &&
  1640. (!bIsValidRecord( MPSWabRecordHeader,
  1641. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  1642. ulRecordOffset,
  1643. ulFileSize)))
  1644. {
  1645. DebugTrace(TEXT("Something seriously screwed up in the file\n"));
  1646. hr = MAPI_E_CORRUPT_DATA;
  1647. goto out;
  1648. }
  1649. else if(MPSWabRecordHeader.bValidRecord == FALSE)
  1650. {
  1651. // if this is a deleted obsolete record, ignore it
  1652. ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) +
  1653. MPSWabRecordHeader.ulPropTagArraySize +
  1654. MPSWabRecordHeader.ulRecordDataSize;
  1655. continue;
  1656. }
  1657. //
  1658. // We have a live one ... create an entryid index structure for this
  1659. //
  1660. MPSWabIndexEID.dwEntryID = MPSWabRecordHeader.dwEntryID;
  1661. MPSWabIndexEID.ulOffset = ulRecordOffset;
  1662. //
  1663. // We are creating a shadow index in memory in the lpIndexEID block
  1664. // We then write this index into the file ..
  1665. //
  1666. //
  1667. // Find the position in the index where this entry will go
  1668. //
  1669. bEID = BinSearchEID(lpIndexEID,
  1670. MPSWabIndexEID.dwEntryID,
  1671. ulcWABEntryCount,
  1672. &nIndexPos);
  1673. if(bEID)
  1674. {
  1675. //
  1676. // This means that the entryid exists in the index which is messed up
  1677. // since we dont support duplicate entryids ...
  1678. // In this case, just ignore this entry and continue
  1679. ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) +
  1680. MPSWabRecordHeader.ulPropTagArraySize +
  1681. MPSWabRecordHeader.ulRecordDataSize;
  1682. continue;
  1683. }
  1684. if(nIndexPos != ulcWABEntryCount)
  1685. {
  1686. CopyMemory( lpTmp,
  1687. &(lpIndexEID[nIndexPos]),
  1688. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID) * (ulcWABEntryCount - nIndexPos));
  1689. }
  1690. CopyMemory( &(lpIndexEID[nIndexPos]),
  1691. &(MPSWabIndexEID),
  1692. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID));
  1693. if(nIndexPos != ulcWABEntryCount)
  1694. {
  1695. CopyMemory( &(lpIndexEID[nIndexPos+1]),
  1696. lpTmp,
  1697. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID) * (ulcWABEntryCount - nIndexPos));
  1698. }
  1699. ulcWABEntryCount++;
  1700. // Write this entry id index from memory to file
  1701. //
  1702. if(!WriteDataToWABFile( hMPSWabFile,
  1703. MPSWabFileHeader.IndexData[indexEntryID].ulOffset,
  1704. (LPVOID) lpIndexEID,
  1705. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*ulcWABEntryCount))
  1706. goto out;
  1707. NewMPSWabFileHeader.ulcNumEntries = ulcWABEntryCount;
  1708. NewMPSWabFileHeader.IndexData[indexEntryID].UtilizedBlockSize = sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*ulcWABEntryCount;
  1709. NewMPSWabFileHeader.IndexData[indexEntryID].ulcNumEntries = ulcWABEntryCount;
  1710. //
  1711. // Write this NewMPSWabFileHeader to the file
  1712. //
  1713. if(!WriteDataToWABFile( hMPSWabFile,
  1714. 0,
  1715. (LPVOID) &NewMPSWabFileHeader,
  1716. sizeof(MPSWab_FILE_HEADER)))
  1717. goto out;
  1718. // go onto next record
  1719. ulRecordOffset += sizeof(MPSWab_RECORD_HEADER) +
  1720. MPSWabRecordHeader.ulPropTagArraySize +
  1721. MPSWabRecordHeader.ulRecordDataSize;
  1722. } // while loop
  1723. // Now we have the correct entryid index,
  1724. // we want to build the display name index from scratch ...
  1725. LocalFreeAndNull(&lpTmp);
  1726. lpTmp = LocalAlloc( LMEM_ZEROINIT,
  1727. MPSWabFileHeader.IndexData[indexDisplayName].AllocatedBlockSize);
  1728. if(!lpTmp)
  1729. {
  1730. DebugTrace(TEXT("LocalAlloc failed\n"));
  1731. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1732. goto out;
  1733. }
  1734. lpIndexString = LocalAlloc( LMEM_ZEROINIT,
  1735. MPSWabFileHeader.IndexData[indexDisplayName].AllocatedBlockSize);
  1736. if(!lpIndexString)
  1737. {
  1738. DebugTrace(TEXT("LocalAlloc failed\n"));
  1739. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1740. goto out;
  1741. }
  1742. //
  1743. // Get the Entry iD index
  1744. //
  1745. if (!LoadIndex( IN lpMPSWabFileInfo,
  1746. IN indexEntryID,
  1747. IN hMPSWabFile) )
  1748. {
  1749. DebugTrace(TEXT("Error Loading EntryID Index!\n"));
  1750. goto out;
  1751. }
  1752. if(!ReadDataFromWABFile(hMPSWabFile,
  1753. 0,
  1754. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  1755. (DWORD) sizeof(MPSWab_FILE_HEADER)))
  1756. goto out;
  1757. for(i=0;i<ulcWABEntryCount;i++)
  1758. {
  1759. DWORD dwEntryID = lpIndexEID[i].dwEntryID;
  1760. ULONG j = 0;
  1761. LPTSTR lpszDisplayName = NULL;
  1762. hr = ReadRecordWithoutLocking( hMPSWabFile,
  1763. lpMPSWabFileInfo,
  1764. dwEntryID,
  1765. &ulcPropCount,
  1766. &lpPropArray);
  1767. if (HR_FAILED(hr))
  1768. {
  1769. // Since there are a lot of implicit expectations in the WAB that the
  1770. // EntryID and DisplayName indexes should have a one to one correspondence,
  1771. // we cant really have an entry in the EntryID index and not have it in
  1772. // the display name index. Hence an error in reading the record is serious
  1773. // and we should either
  1774. // - remove the corresponding entry from the EID index; or
  1775. // - fail and restore from backup;
  1776. // For the time being we will do (a)
  1777. hr = MAPI_E_CORRUPT_DATA;
  1778. goto out;
  1779. }
  1780. //reset hr
  1781. hr = E_FAIL;
  1782. for(j=0;j<ulcPropCount;j++)
  1783. {
  1784. if (lpPropArray[j].ulPropTag == PR_DISPLAY_NAME)
  1785. {
  1786. lpszDisplayName = lpPropArray[j].Value.LPSZ;
  1787. break;
  1788. }
  1789. }
  1790. if(!lpszDisplayName)
  1791. {
  1792. //we should remove this index from the EID index since this record
  1793. //seems to have some errors <TBD>
  1794. hr = MAPI_E_CORRUPT_DATA;
  1795. goto out;
  1796. }
  1797. else
  1798. {
  1799. // We have a display name so create an index and write it to file ..
  1800. ULONG nLen = TruncatePos(lpszDisplayName, MAX_INDEX_STRING-1);
  1801. CopyMemory(MPSWabIndexString.szIndex,lpszDisplayName,sizeof(TCHAR)*nLen);
  1802. MPSWabIndexString.szIndex[nLen]='\0';
  1803. MPSWabIndexString.dwEntryID = dwEntryID;
  1804. //
  1805. // We are cerating a shadow index in memory in the lpIndexEID block
  1806. // We then write this index into the file ..
  1807. //
  1808. //
  1809. // Find the position in the index where this entry will go
  1810. //
  1811. bEID = BinSearchStr(lpIndexString,
  1812. MPSWabIndexString.szIndex,
  1813. i,
  1814. &nIndexPos);
  1815. if(nIndexPos != i)
  1816. {
  1817. CopyMemory( lpTmp,
  1818. &(lpIndexString[nIndexPos]),
  1819. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING) * (i - nIndexPos));
  1820. }
  1821. CopyMemory( &(lpIndexString[nIndexPos]),
  1822. &(MPSWabIndexString),
  1823. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING));
  1824. if(nIndexPos != i)
  1825. {
  1826. CopyMemory( &(lpIndexString[nIndexPos+1]),
  1827. lpTmp,
  1828. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING) * (i - nIndexPos));
  1829. }
  1830. if(!WriteDataToWABFile( hMPSWabFile,
  1831. MPSWabFileHeader.IndexData[indexDisplayName].ulOffset,
  1832. (LPVOID) lpIndexString,
  1833. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(i+1)))
  1834. goto out;
  1835. NewMPSWabFileHeader.IndexData[indexDisplayName].UtilizedBlockSize = sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(i+1);
  1836. NewMPSWabFileHeader.IndexData[indexDisplayName].ulcNumEntries = (i+1);
  1837. //
  1838. // Write this NewMPSWabFileHeader to the file
  1839. //
  1840. if(!WriteDataToWABFile( hMPSWabFile,
  1841. 0,
  1842. (LPVOID) &NewMPSWabFileHeader,
  1843. sizeof(MPSWab_FILE_HEADER)))
  1844. goto out;
  1845. }
  1846. LocalFreePropArray(NULL, ulcPropCount,&lpPropArray);
  1847. lpPropArray = NULL;
  1848. ulcPropCount = 0;
  1849. } //for loop
  1850. // check that we have the correct number of entries in the both indexes
  1851. //
  1852. if (NewMPSWabFileHeader.IndexData[indexDisplayName].ulcNumEntries != NewMPSWabFileHeader.ulcNumEntries)
  1853. {
  1854. // If the 2 indexes dont contain the same number of elements, something failed above
  1855. // Big problem ... cant recover
  1856. hr = MAPI_E_CORRUPT_DATA;
  1857. goto out;
  1858. }
  1859. //
  1860. // Clear out the error tag from the File Header so we dont keep falling back
  1861. // into this function ...
  1862. //
  1863. NewMPSWabFileHeader.ulFlags = WAB_CLEAR;
  1864. //
  1865. // Write this NewMPSWabFileHeader to the file
  1866. //
  1867. if(!WriteDataToWABFile( hMPSWabFile,
  1868. 0,
  1869. (LPVOID) &NewMPSWabFileHeader,
  1870. sizeof(MPSWab_FILE_HEADER)))
  1871. goto out;
  1872. hr = hrSuccess;
  1873. out:
  1874. LocalFreeAndNull(&lpTmp);
  1875. LocalFreeAndNull(&lpIndexEID);
  1876. LocalFreeAndNull(&lpIndexString);
  1877. LocalFreePropArray(NULL, ulcPropCount,&lpPropArray);
  1878. // fix the return error code
  1879. switch(hr)
  1880. {
  1881. case MAPI_E_NOT_ENOUGH_MEMORY:
  1882. case MAPI_E_DISK_ERROR:
  1883. case S_OK:
  1884. break;
  1885. default:
  1886. hr = MAPI_E_CORRUPT_DATA;
  1887. break;
  1888. }
  1889. DebugTrace(TEXT("---DoDetailedWABIntegrityCheck Exit: %x\n"),hr);
  1890. SetCursor(hOldCur);
  1891. return hr;
  1892. }
  1893. //$$////////////////////////////////////////////////////////////////////////////////
  1894. //
  1895. // bIsValidRecord - This function looks at the Record Header components to determine if
  1896. // the record is valid or not
  1897. //
  1898. // It follows some very simple rules that can detect record header corruptions
  1899. //
  1900. // dwNextEntryID value will not be used if it is 0xFFFFFFFF
  1901. ////////////////////////////////////////////////////////////////////////////////////////
  1902. BOOL bIsValidRecord(MPSWab_RECORD_HEADER rh,
  1903. DWORD dwNextEntryID,
  1904. ULONG ulRecordOffset,
  1905. ULONG ulFileSize)
  1906. {
  1907. BOOL bRet = FALSE;
  1908. // is this tagged as an invalid record (or something else)
  1909. if ((rh.bValidRecord == FALSE) && (rh.bValidRecord != TRUE))
  1910. goto out;
  1911. // is this entry id value acceptable and correct
  1912. if(dwNextEntryID != 0xFFFFFFFF)
  1913. {
  1914. if (rh.dwEntryID > dwNextEntryID)
  1915. goto out;
  1916. }
  1917. // are the offsets in the header correct
  1918. if (rh.ulPropTagArraySize != rh.ulcPropCount * sizeof(ULONG))
  1919. goto out;
  1920. if (rh.ulRecordDataOffset != rh.ulPropTagArraySize)
  1921. goto out;
  1922. if (rh.ulPropTagArrayOffset != 32) /***TBD - this is dependent on the struct elements***/
  1923. goto out;
  1924. if (ulRecordOffset + rh.ulRecordDataOffset + rh.ulRecordDataSize > ulFileSize)
  1925. goto out;
  1926. bRet = TRUE;
  1927. out:
  1928. if(!bRet)
  1929. DebugTrace(TEXT("\n@@@@@@@@@@\n@@@Invalid Record Detected\n@@@@@@@@@@\n"));
  1930. return bRet;
  1931. }
  1932. //$$////////////////////////////////////////////////////////////////////////
  1933. //
  1934. // TagWABFileError -
  1935. //
  1936. // If an error is detected while reading a files contents, we can tag the error
  1937. // in the file so that the next access will attempt to fix it
  1938. //
  1939. ////////////////////////////////////////////////////////////////////////////
  1940. BOOL TagWABFileError( LPMPSWab_FILE_HEADER lpMPSWabFileHeader,
  1941. HANDLE hMPSWabFile)
  1942. {
  1943. BOOL bRet = FALSE;
  1944. DWORD dwNumofBytes = 0;
  1945. if(!lpMPSWabFileHeader || !hMPSWabFile)
  1946. {
  1947. DebugTrace(TEXT("Invalid Parameter\n"));
  1948. goto out;
  1949. }
  1950. lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  1951. // update the file header
  1952. if(!WriteDataToWABFile( hMPSWabFile,
  1953. 0,
  1954. (LPVOID) lpMPSWabFileHeader,
  1955. sizeof(MPSWab_FILE_HEADER)))
  1956. goto out;
  1957. bRet = TRUE;
  1958. out:
  1959. return bRet;
  1960. }
  1961. /*
  1962. -
  1963. - SetNextEntryID - sets the next entryid to use in a file. Called durimg migration
  1964. *
  1965. */
  1966. void SetNextEntryID(HANDLE hPropertyStoreTemp, DWORD dwEID)
  1967. {
  1968. MPSWab_FILE_HEADER WABHeader = {0};
  1969. HANDLE hWABFile = NULL;
  1970. LPMPSWab_FILE_INFO lpMPSWabFI = hPropertyStoreTemp;
  1971. // First read the header from the existing file
  1972. if(!HR_FAILED(OpenWABFile(lpMPSWabFI->lpszMPSWabFileName, NULL, &hWABFile)))
  1973. {
  1974. if(!ReadDataFromWABFile(hWABFile, 0, (LPVOID) &WABHeader, sizeof(MPSWab_FILE_HEADER)))
  1975. goto out;
  1976. WABHeader.dwNextEntryID = dwEID;
  1977. if(!WriteDataToWABFile(hWABFile, 0, (LPVOID) &WABHeader, sizeof(MPSWab_FILE_HEADER)))
  1978. goto out;
  1979. }
  1980. out:
  1981. if ((hWABFile != NULL) && (hWABFile != INVALID_HANDLE_VALUE))
  1982. CloseHandle(hWABFile);
  1983. return;
  1984. }
  1985. enum WABVersion
  1986. {
  1987. W05 =0,
  1988. W2,
  1989. W3,
  1990. W4,
  1991. };
  1992. //$$////////////////////////////////////////////////////////////////////////////
  1993. //
  1994. // HrMigrateFromOldWABtoNew - Migrates older versions of the wab into current ones
  1995. //
  1996. // IN hMPSWabFile
  1997. // IN lpMPSWabFileInfo
  1998. // hWnd .. used for displaying a "Please wait" dialog
  1999. // returns:
  2000. // E_FAIL or S_OK
  2001. // MAPI_E_CORRUPT_DATA if GUID is unrecognizable
  2002. //
  2003. ////////////////////////////////////////////////////////////////////////////////
  2004. HRESULT HrMigrateFromOldWABtoNew(HWND hWnd, HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, GUID WabGUID)
  2005. {
  2006. HRESULT hr = E_FAIL;
  2007. int WABVersion;
  2008. HANDLE hTempFile = NULL;
  2009. MPSWab_FILE_HEADER NewFileHeader = {0};
  2010. ULONG ulcMaxEntries = 0;
  2011. MPSWab_FILE_HEADER_W2 MPSWabFileHeaderW2 = {0};
  2012. MPSWab_FILE_HEADER MPSWabFileHeader = {0};
  2013. TCHAR szFileName[MAX_PATH];
  2014. ULONG ulAdditionalRecordOffset=0;
  2015. LPVOID lpv = NULL;
  2016. LPMPSWab_INDEX_ENTRY_DATA_ENTRYID lpeid = NULL;
  2017. ULONG i = 0;
  2018. DWORD dwOldEID = 0, dwNextEID = 0;
  2019. HCURSOR hOldC = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2020. if (IsEqualGUID(&WabGUID,&MPSWab_OldBeta1_GUID))
  2021. {
  2022. WABVersion = W05;
  2023. }
  2024. else if (IsEqualGUID(&WabGUID,&MPSWab_W2_GUID))
  2025. {
  2026. WABVersion = W2;
  2027. }
  2028. else if (IsEqualGUID(&WabGUID,&MPSWab_GUID_V4))
  2029. {
  2030. WABVersion = W4;
  2031. }
  2032. // For WABVersion 1 and 2, we will read in the file header and
  2033. // save it to the new file. We will then read in the records one by
  2034. // one and write them to the file through the interface retaining the
  2035. // old entryid. Version 1 and 2 did not have named prop support and also
  2036. // had lesser numbers of indices. The individual record layour was the same as before
  2037. // WABVersion 4 is the conversion from the ANSI store to the Unicode store ..
  2038. // We can copy the file header and the named prop info as it is but we'll need
  2039. // to read the records one by one, convert them to Unicode and then write it to the
  2040. // new file so that all the indexes etc are rebuild correctly ...
  2041. //
  2042. // As long as all the entryids are retained, the relationship between the address
  2043. // book data elements is the same.
  2044. // Get a temp file name
  2045. szFileName[0]='\0';
  2046. GetWABTempFileName(szFileName);
  2047. if(WABVersion <= W2)
  2048. {
  2049. // First read the header from the existing file
  2050. if(!ReadDataFromWABFile(hMPSWabFile,
  2051. 0,
  2052. (LPVOID) &MPSWabFileHeaderW2,
  2053. sizeof(MPSWab_FILE_HEADER_W2)))
  2054. goto out;
  2055. // Create a new Temp WAB File
  2056. if (!CreateMPSWabFile( IN &NewFileHeader,
  2057. IN szFileName,
  2058. IN MPSWabFileHeaderW2.ulcMaxNumEntries,
  2059. IN NAMEDPROP_STORE_SIZE))
  2060. {
  2061. DebugTrace(TEXT("Error creating new file\n"));
  2062. goto out;
  2063. }
  2064. //Update header information
  2065. NewFileHeader.ulModificationCount = MPSWabFileHeaderW2.ulModificationCount;
  2066. dwNextEID = NewFileHeader.dwNextEntryID = MPSWabFileHeaderW2.dwNextEntryID;
  2067. NewFileHeader.ulcNumEntries = MPSWabFileHeaderW2.ulcNumEntries;
  2068. NewFileHeader.ulFlags = MPSWabFileHeaderW2.ulFlags;
  2069. NewFileHeader.ulReserved1 = MPSWabFileHeaderW2.ulReserved;
  2070. }
  2071. else
  2072. {
  2073. // First read the header from the existing file
  2074. if(!ReadDataFromWABFile(hMPSWabFile,
  2075. 0,
  2076. (LPVOID) &MPSWabFileHeader,
  2077. sizeof(MPSWab_FILE_HEADER)))
  2078. goto out;
  2079. // Create a new Temp WAB File
  2080. if (!CreateMPSWabFile( IN &NewFileHeader,
  2081. IN szFileName,
  2082. IN MPSWabFileHeader.ulcMaxNumEntries,
  2083. IN MPSWabFileHeader.NamedPropData.AllocatedBlockSize))
  2084. {
  2085. DebugTrace(TEXT("Error creating new file\n"));
  2086. goto out;
  2087. }
  2088. //Update header information
  2089. dwOldEID = dwNextEID = NewFileHeader.dwNextEntryID = MPSWabFileHeader.dwNextEntryID;
  2090. }
  2091. {
  2092. // Update the file header info from current file to the new file
  2093. // now we open the new temp file and get a handle to it
  2094. hTempFile = CreateFile( szFileName,
  2095. GENERIC_READ | GENERIC_WRITE,
  2096. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2097. (LPSECURITY_ATTRIBUTES) NULL,
  2098. OPEN_EXISTING,
  2099. FILE_FLAG_RANDOM_ACCESS,
  2100. (HANDLE) NULL);
  2101. if (hTempFile == INVALID_HANDLE_VALUE)
  2102. {
  2103. DebugTrace(TEXT("Could not open Temp file.\nExiting ...\n"));
  2104. goto out;
  2105. }
  2106. if(WABVersion == W4)
  2107. {
  2108. DWORD dwNP = MPSWabFileHeader.NamedPropData.AllocatedBlockSize;
  2109. LPBYTE lpNP = LocalAlloc(LMEM_ZEROINIT, dwNP);
  2110. LPGUID_NAMED_PROPS lpgnp = NULL;
  2111. if(lpNP)
  2112. {
  2113. if(!ReadDataFromWABFile(hMPSWabFile,
  2114. MPSWabFileHeader.NamedPropData.ulOffset,
  2115. (LPVOID) lpNP,
  2116. dwNP))
  2117. goto out;
  2118. if(GetNamedPropsFromBuffer(lpNP, MPSWabFileHeader.NamedPropData.ulcNumEntries,
  2119. TRUE, &lpgnp))
  2120. {
  2121. LocalFreeAndNull(&lpNP);
  2122. if(SetNamedPropsToBuffer( MPSWabFileHeader.NamedPropData.ulcNumEntries,
  2123. lpgnp, &dwNP, &lpNP))
  2124. {
  2125. if(!WriteDataToWABFile(hTempFile,
  2126. NewFileHeader.NamedPropData.ulOffset,
  2127. (LPVOID) lpNP,
  2128. dwNP))
  2129. goto out;
  2130. LocalFreeAndNull(&lpNP);
  2131. }
  2132. NewFileHeader.NamedPropData.UtilizedBlockSize = MPSWabFileHeader.NamedPropData.UtilizedBlockSize;
  2133. NewFileHeader.NamedPropData.ulcNumEntries = MPSWabFileHeader.NamedPropData.ulcNumEntries;
  2134. if(lpgnp)
  2135. FreeGuidnamedprops(MPSWabFileHeader.NamedPropData.ulcNumEntries, lpgnp);
  2136. }
  2137. }
  2138. }
  2139. //Save this fileheader information
  2140. if(!WriteDataToWABFile(hTempFile, 0, (LPVOID) &NewFileHeader, sizeof(MPSWab_FILE_HEADER)))
  2141. goto out;
  2142. CloseHandle(hTempFile);
  2143. hTempFile = NULL;
  2144. }
  2145. {
  2146. HANDLE hPropertyStoreTemp = NULL;
  2147. ULONG ulOldRecordOffset = 0;
  2148. ULONG ulWABFileSize = GetFileSize(hMPSWabFile,NULL);
  2149. LPSPropValue lpPropArray = NULL;
  2150. ULONG ulcValues = 0;
  2151. hr = OpenPropertyStore( szFileName,
  2152. AB_OPEN_EXISTING | AB_DONT_RESTORE,
  2153. NULL,
  2154. &hPropertyStoreTemp);
  2155. if(HR_FAILED(hr))
  2156. {
  2157. DebugTrace(TEXT("Could not open Temp PropStore\n"));
  2158. goto endW05;
  2159. }
  2160. // Get the start of the record data from this file
  2161. if(WABVersion <= W2)
  2162. {
  2163. ulOldRecordOffset = MPSWabFileHeaderW2.IndexData[indexFirstName].ulOffset +
  2164. MPSWabFileHeaderW2.IndexData[indexFirstName].AllocatedBlockSize;
  2165. }
  2166. else
  2167. {
  2168. ulOldRecordOffset = MPSWabFileHeader.IndexData[indexAlias].ulOffset +
  2169. MPSWabFileHeader.IndexData[indexAlias].AllocatedBlockSize;
  2170. }
  2171. // walk the file record by record
  2172. while (ulOldRecordOffset < ulWABFileSize)
  2173. {
  2174. ULONG ulRecordSize = 0;
  2175. ULONG ulObjType = 0;
  2176. //Read the record prop array from the old WAB file
  2177. hr = HrGetPropArrayFromFileRecord(hMPSWabFile,
  2178. ulOldRecordOffset,
  2179. NULL,
  2180. &ulObjType,
  2181. &ulRecordSize,
  2182. &ulcValues,
  2183. &lpPropArray);
  2184. if(ulRecordSize == 0)
  2185. {
  2186. // If this happens we will get caught in a loop
  2187. // Better to exit.
  2188. DebugTrace(TEXT("Zero-lengthrecord found\n"));
  2189. goto endW05;
  2190. }
  2191. if(!HR_FAILED(hr))
  2192. {
  2193. LPSBinary lpsbEID = NULL;
  2194. ULONG i = 0, iEID = 0;
  2195. DWORD dwEID = 0;
  2196. // The above PropArray has a PR_ENTRY_ID that has a value
  2197. // from the old store. We want to retain this entryid value
  2198. for(i=0;i<ulcValues;i++)
  2199. {
  2200. if(lpPropArray[i].ulPropTag == PR_ENTRYID)
  2201. {
  2202. lpsbEID = &lpPropArray[i].Value.bin;
  2203. iEID = i;
  2204. break;
  2205. }
  2206. }
  2207. // However, when we save this entry to the new store, the new
  2208. // store does not have an index and so the entryid will be rejected and
  2209. // a new one assigned .. so to trick the WAB into reusing the entryid, we will
  2210. // just set the entryid in the file header as the next one to use ..
  2211. {
  2212. AssertSz(lpsbEID->cb == SIZEOF_WAB_ENTRYID, TEXT("Entryid has unknown size!"));
  2213. CopyMemory(&dwEID, lpsbEID->lpb, sizeof(DWORD));
  2214. if(dwNextEID <= dwEID)
  2215. dwNextEID = dwEID + 1;
  2216. SetNextEntryID(hPropertyStoreTemp, dwEID);
  2217. //lpPropArray[iEID].ulPropTag = PR_NULL;
  2218. //lpsbEID->cb = 0;
  2219. //LocalFreeAndNull(&lpsbEID->lpb);
  2220. //lpsbEID = NULL;
  2221. }
  2222. // Convert any A props read in into W props
  2223. ConvertAPropsToWCLocalAlloc(lpPropArray, ulcValues);
  2224. // We have a valid record (otherwise ignore it)
  2225. hr = WriteRecord(IN hPropertyStoreTemp,
  2226. NULL,
  2227. &lpsbEID,
  2228. 0,
  2229. ulObjType,
  2230. ulcValues,
  2231. lpPropArray);
  2232. if(HR_FAILED(hr))
  2233. {
  2234. DebugTrace(TEXT("WriteRecord failed\n"));
  2235. goto endW05;
  2236. }
  2237. //if(lpsbEID)
  2238. // FreeEntryIDs(NULL, 1, lpsbEID);
  2239. }
  2240. ulOldRecordOffset += ulRecordSize;
  2241. LocalFreePropArray(NULL, ulcValues, &lpPropArray);
  2242. }
  2243. if(hr == MAPI_E_INVALID_OBJECT)
  2244. hr = S_OK;
  2245. // Just in case the Next Entryid value has changed (for whatever reason)(though this shouldnt happen)
  2246. // update the value in the file ..
  2247. if(dwOldEID != dwNextEID)
  2248. SetNextEntryID(hPropertyStoreTemp, dwNextEID);
  2249. endW05:
  2250. LocalFreePropArray(NULL, ulcValues, &lpPropArray);
  2251. if(hPropertyStoreTemp)
  2252. ClosePropertyStore(hPropertyStoreTemp, AB_DONT_BACKUP);
  2253. if(!HR_FAILED(hr))
  2254. {
  2255. hr = E_FAIL;
  2256. hTempFile = CreateFile( szFileName,
  2257. GENERIC_READ | GENERIC_WRITE,
  2258. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2259. (LPSECURITY_ATTRIBUTES) NULL,
  2260. OPEN_EXISTING,
  2261. FILE_FLAG_RANDOM_ACCESS,
  2262. (HANDLE) NULL);
  2263. if (hTempFile == INVALID_HANDLE_VALUE)
  2264. {
  2265. DebugTrace(TEXT("Could not open Temp file.\nExiting ...\n"));
  2266. goto out;
  2267. }
  2268. if(!CopySrcFileToDestFile(hTempFile, 0, hMPSWabFile, 0))
  2269. {
  2270. DebugTrace(TEXT("Could not copy file\n"));
  2271. goto out;
  2272. }
  2273. hr = S_OK;
  2274. }
  2275. }
  2276. out:
  2277. LocalFreeAndNull(&lpv);
  2278. LocalFreeAndNull(&lpeid);
  2279. if(hTempFile)
  2280. IF_WIN32(CloseHandle(hTempFile);) IF_WIN16(CloseFile(hTempFile);)
  2281. if(lstrlen(szFileName))
  2282. DeleteFile(szFileName);
  2283. if(hOldC)
  2284. SetCursor(hOldC);
  2285. return hr;
  2286. }
  2287. //$$////////////////////////////////////////////////////////////////////////////
  2288. //
  2289. // HrVerifyWABVersionAndUpdate - Looks at the WAB File version and migrates
  2290. // older versions into newer versions
  2291. //
  2292. // IN hMPSWabFile
  2293. // IN lpMPSWabFileInfo
  2294. // hWnd - used for displaying some kind of dialog if necessary
  2295. //
  2296. // BUG 16681:
  2297. // In randomly occuring cases, the wab file seems to get totally wiped and turned
  2298. // into 0's ... In such events, we will rename the file and try again .. we
  2299. // indicate this condition to the OpenPropertyStore function by returning
  2300. // MAPI_E_VERSION ..
  2301. //
  2302. // returns:
  2303. // E_FAIL or S_OK
  2304. // MAPI_E_CORRUPT_DATA if GUID is unrecognizable
  2305. //
  2306. ////////////////////////////////////////////////////////////////////////////////
  2307. HRESULT HrVerifyWABVersionAndUpdate(HWND hWnd,
  2308. HANDLE hMPSWabFile,
  2309. LPMPSWab_FILE_INFO lpMPSWabFileInfo)
  2310. {
  2311. GUID TmpGuid = {0};
  2312. HRESULT hr = E_FAIL;
  2313. DWORD dwNumofBytes = 0;
  2314. // First read the GUID from the file
  2315. //
  2316. if(!ReadDataFromWABFile(hMPSWabFile,
  2317. 0,
  2318. (LPVOID) &TmpGuid,
  2319. (DWORD) sizeof(GUID)))
  2320. goto out;
  2321. //
  2322. // Check if this is a Microsoft Property Store by looking for MPSWab GUID in header
  2323. // (If this was an old file it should have been updated above)(If not, we should
  2324. // avoid an error and go ahead and open it)
  2325. // However if the guids dont match, we cant tell if this is a WAB file or not
  2326. // because it could also be a valid corrupt wab file ... so when the guids dont
  2327. // match, we will assume that the file is a corrupt wab file.
  2328. //
  2329. if ( (!IsEqualGUID(&TmpGuid,&MPSWab_GUID)) &&
  2330. (!IsEqualGUID(&TmpGuid,&MPSWab_GUID_V4)) &&
  2331. (!IsEqualGUID(&TmpGuid,&MPSWab_W2_GUID)) &&
  2332. (!IsEqualGUID(&TmpGuid,&MPSWab_OldBeta1_GUID)) )
  2333. {
  2334. DebugTrace(TEXT("%s is not a Microsoft Property Store File. GUIDS don't match\n"),lpMPSWabFileInfo->lpszMPSWabFileName);
  2335. hr = MAPI_E_INVALID_OBJECT;
  2336. //Bug 16681:
  2337. //Check the special condition where everything is all zero's
  2338. {
  2339. if ( (TmpGuid.Data1 == 0) &&
  2340. (TmpGuid.Data2 == 0) &&
  2341. (TmpGuid.Data3 == 0) &&
  2342. (lstrlen((LPTSTR)TmpGuid.Data4) == 0) )
  2343. {
  2344. hr = MAPI_E_VERSION;
  2345. }
  2346. }
  2347. goto out;
  2348. }
  2349. //
  2350. // If this is an older version of the file, update it to a more current
  2351. // store format.
  2352. //
  2353. if ( (IsEqualGUID(&TmpGuid,&MPSWab_GUID_V4)) ||
  2354. (IsEqualGUID(&TmpGuid,&MPSWab_OldBeta1_GUID)) ||
  2355. (IsEqualGUID(&TmpGuid,&MPSWab_W2_GUID)) )
  2356. {
  2357. // We will basically scavenge the old file for records out of the
  2358. // file (ignoring the indexes so we can avoid all errors)
  2359. // and put them in a new prop store file which we will then
  2360. // populate with the old records and finally use to replace the
  2361. // current file - very similar to how CompressFile works
  2362. DebugTrace(TEXT("Old WAB File Found. Migrating to new ...\n"));
  2363. hr = HrMigrateFromOldWABtoNew( hWnd, hMPSWabFile,
  2364. lpMPSWabFileInfo,
  2365. TmpGuid);
  2366. if(HR_FAILED(hr))
  2367. {
  2368. DebugTrace(TEXT("MPSWabUpdateAndVerifyOldWAB: %x\n"));
  2369. goto out;
  2370. }
  2371. }
  2372. //reset hr
  2373. hr = E_FAIL;
  2374. lpMPSWabFileInfo->nCurrentlyLoadedStrIndexType = indexDisplayName;
  2375. // Reload whatever new info we added as a result of the above.
  2376. if(!ReloadMPSWabFileInfo(
  2377. lpMPSWabFileInfo,
  2378. hMPSWabFile))
  2379. {
  2380. DebugTrace(TEXT("Reading file info failed.\n"));
  2381. goto out;
  2382. }
  2383. hr = S_OK;
  2384. out:
  2385. return hr;
  2386. }
  2387. //$$////////////////////////////////////////////////////////////////////////////////
  2388. //
  2389. // HrGetBufferFromPropArray - translates a prop array into a flat buffer.
  2390. // The format of the data in the buffer is the same as
  2391. // the format of data in the .wab file
  2392. //
  2393. //
  2394. // Params:
  2395. // ulcPropCount- # of props in array
  2396. // lpPropArray - prop array
  2397. // lpcbBuf - size of returned buffer
  2398. // lppBuf - returned buffer
  2399. //
  2400. ////////////////////////////////////////////////////////////////////////////////////
  2401. HRESULT HrGetBufferFromPropArray( ULONG ulcPropCount,
  2402. LPSPropValue lpPropArray,
  2403. ULONG * lpcbBuf,
  2404. LPBYTE * lppBuf)
  2405. {
  2406. HRESULT hr = E_FAIL;
  2407. LPULONG lpulrgPropDataSize = NULL;
  2408. ULONG ulRecordDataSize = 0;
  2409. LPBYTE lp = NULL;
  2410. LPBYTE szBuf = NULL;
  2411. ULONG i=0,j=0,k=0;
  2412. if(!lpcbBuf || !lppBuf)
  2413. goto out;
  2414. *lpcbBuf = 0;
  2415. *lppBuf = NULL;
  2416. // _DebugProperties(lpPropArray, ulcPropCount, TEXT("GetBufferFromPropArray"));
  2417. //
  2418. // We will go through the given data and determine how much space we need for each
  2419. // property. lpulrgPropDataSize is an array of ULONGs in which we store the calculated sizes
  2420. // temporarily.
  2421. //
  2422. lpulrgPropDataSize = LocalAlloc(LMEM_ZEROINIT, ulcPropCount * sizeof(ULONG));
  2423. if (!lpulrgPropDataSize)
  2424. {
  2425. DebugTrace(TEXT("Error allocating memory\n"));
  2426. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2427. goto out;
  2428. }
  2429. //
  2430. // Get an estimate of how big the data portion of this record will be ...
  2431. // We need this estimate to allocate a block of memory into which we will
  2432. // write the data and then blt the block into the file
  2433. //
  2434. for(i=0;i<ulcPropCount;i++)
  2435. {
  2436. // This is the eventual data format:
  2437. //
  2438. // If (SingleValued)
  2439. // <PropTag><DataSize><Data>
  2440. // else
  2441. // <MultiPropTag><cValues><DataSize><data>
  2442. // unless PropType is MV_BINARY or MV_TSTRING in which case we need a
  2443. // more flexible data storage
  2444. // <MultiPropTag><cValues><DataSize>
  2445. // <cb/strlen><Data>
  2446. // <cb/strlen><Data> ...
  2447. //
  2448. ulRecordDataSize += sizeof(ULONG); // holds <PropTag>
  2449. if ((lpPropArray[i].ulPropTag & MV_FLAG))
  2450. {
  2451. //
  2452. // multi-valued
  2453. //
  2454. lpulrgPropDataSize[i] = SizeOfMultiPropData(lpPropArray[i]); //Data
  2455. ulRecordDataSize += sizeof(ULONG); // holds <CValues>
  2456. }
  2457. else
  2458. {
  2459. //
  2460. // single-valued
  2461. //
  2462. lpulrgPropDataSize[i] = SizeOfSinglePropData(lpPropArray[i]); //Data
  2463. }
  2464. ulRecordDataSize += sizeof(ULONG) // holds <DataSize>
  2465. + lpulrgPropDataSize[i]; //holds <Data>
  2466. }
  2467. lp = LocalAlloc(LMEM_ZEROINIT, ulRecordDataSize);
  2468. if (!lp)
  2469. {
  2470. DebugTrace(TEXT("Error allocating memory\n"));
  2471. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2472. goto out;
  2473. }
  2474. szBuf = lp;
  2475. for (i = 0; i<ulcPropCount; i++)
  2476. {
  2477. //
  2478. // copy the prop tag
  2479. //
  2480. CopyMemory(szBuf,&lpPropArray[i].ulPropTag, sizeof(ULONG));
  2481. szBuf += sizeof(ULONG);
  2482. //
  2483. // difference between handling of multivalued and singlevalued
  2484. //
  2485. if (!(lpPropArray[i].ulPropTag & MV_FLAG))
  2486. {
  2487. // Single Valued
  2488. //
  2489. // Record the size of data
  2490. //
  2491. CopyMemory(szBuf,&lpulrgPropDataSize[i], sizeof(ULONG));
  2492. szBuf += sizeof(ULONG);
  2493. ////DebugTrace(TEXT("%x: "),lpPropArray[i].ulPropTag);
  2494. switch(PROP_TYPE(lpPropArray[i].ulPropTag))
  2495. {
  2496. case(PT_STRING8):
  2497. //
  2498. // Record the data ...
  2499. //
  2500. CopyMemory(szBuf,lpPropArray[i].Value.lpszA, lpulrgPropDataSize[i]);
  2501. ////DebugTrace(TEXT("%s\n"),lpPropArray[i].Value.LPSZ);
  2502. break;
  2503. case(PT_UNICODE):
  2504. //
  2505. // Record the data ...
  2506. //
  2507. CopyMemory(szBuf,lpPropArray[i].Value.lpszW, lpulrgPropDataSize[i]);
  2508. ////DebugTrace(TEXT("%s\n"),lpPropArray[i].Value.LPSZ);
  2509. break;
  2510. case(PT_CLSID):
  2511. //
  2512. // Record the data ...
  2513. //
  2514. CopyMemory(szBuf,lpPropArray[i].Value.lpguid, lpulrgPropDataSize[i]);
  2515. ////DebugTrace(TEXT("%x-%x-%x-%x\n"),lpPropArray[i].Value.lpguid->Data1,lpPropArray[i].Value.lpguid->Data2,lpPropArray[i].Value.lpguid->Data3,lpPropArray[i].Value.lpguid->Data4);
  2516. break;
  2517. case(PT_BINARY):
  2518. //
  2519. // Record the data ...
  2520. //
  2521. CopyMemory(szBuf,lpPropArray[i].Value.bin.lpb, lpulrgPropDataSize[i]);
  2522. break;
  2523. case(PT_SHORT):
  2524. //Record the data ...
  2525. CopyMemory(szBuf,&lpPropArray[i].Value.i, lpulrgPropDataSize[i]);
  2526. ////DebugTrace(TEXT("%d\n"),lpPropArray[i].Value.i);
  2527. break;
  2528. case(PT_LONG):
  2529. case(PT_R4):
  2530. case(PT_DOUBLE):
  2531. case(PT_BOOLEAN):
  2532. case(PT_APPTIME):
  2533. case(PT_CURRENCY):
  2534. //Record the data ...
  2535. CopyMemory(szBuf,&lpPropArray[i].Value.i, lpulrgPropDataSize[i]);
  2536. ////DebugTrace(TEXT("%d\n"),lpPropArray[i].Value.l);
  2537. break;
  2538. case(PT_SYSTIME):
  2539. //Record the data ...
  2540. CopyMemory(szBuf,&lpPropArray[i].Value.ft, lpulrgPropDataSize[i]);
  2541. ////DebugTrace(TEXT("%d,%d\n"),lpPropArray[i].Value.ft.dwLowDateTime,lpPropArray[i].Value.ft.dwHighDateTime);
  2542. break;
  2543. default:
  2544. DebugTrace(TEXT("Unknown PropTag !!\n"));
  2545. break;
  2546. }
  2547. szBuf += lpulrgPropDataSize[i];
  2548. }
  2549. else
  2550. {
  2551. //multivalued
  2552. //copy the # of multi-values
  2553. CopyMemory(szBuf,&lpPropArray[i].Value.MVi.cValues, sizeof(ULONG));
  2554. szBuf += sizeof(ULONG);
  2555. //Record the size of data
  2556. CopyMemory(szBuf,&lpulrgPropDataSize[i], sizeof(ULONG));
  2557. szBuf += sizeof(ULONG);
  2558. ////DebugTrace(TEXT("%x: MV_PROP\n"),lpPropArray[i].ulPropTag);
  2559. switch(PROP_TYPE(lpPropArray[i].ulPropTag))
  2560. {
  2561. case(PT_MV_I2):
  2562. case(PT_MV_LONG):
  2563. case(PT_MV_R4):
  2564. case(PT_MV_DOUBLE):
  2565. case(PT_MV_CURRENCY):
  2566. case(PT_MV_APPTIME):
  2567. case(PT_MV_SYSTIME):
  2568. CopyMemory(szBuf,lpPropArray[i].Value.MVft.lpft, lpulrgPropDataSize[i]);
  2569. szBuf += lpulrgPropDataSize[i];
  2570. break;
  2571. case(PT_MV_I8):
  2572. CopyMemory(szBuf,lpPropArray[i].Value.MVli.lpli, lpulrgPropDataSize[i]);
  2573. szBuf += lpulrgPropDataSize[i];
  2574. break;
  2575. case(PT_MV_BINARY):
  2576. for (j=0;j<lpPropArray[i].Value.MVbin.cValues;j++)
  2577. {
  2578. CopyMemory(szBuf,&lpPropArray[i].Value.MVbin.lpbin[j].cb, sizeof(ULONG));
  2579. szBuf += sizeof(ULONG);
  2580. CopyMemory(szBuf,lpPropArray[i].Value.MVbin.lpbin[j].lpb, lpPropArray[i].Value.MVbin.lpbin[j].cb);
  2581. szBuf += lpPropArray[i].Value.MVbin.lpbin[j].cb;
  2582. }
  2583. break;
  2584. case(PT_MV_STRING8):
  2585. for (j=0;j<lpPropArray[i].Value.MVszA.cValues;j++)
  2586. {
  2587. ULONG nLen;
  2588. nLen = lstrlenA(lpPropArray[i].Value.MVszA.lppszA[j])+1;
  2589. CopyMemory(szBuf,&nLen, sizeof(ULONG));
  2590. szBuf += sizeof(ULONG);
  2591. CopyMemory(szBuf,lpPropArray[i].Value.MVszA.lppszA[j], nLen);
  2592. szBuf += nLen;
  2593. }
  2594. break;
  2595. case(PT_MV_UNICODE):
  2596. for (j=0;j<lpPropArray[i].Value.MVszW.cValues;j++)
  2597. {
  2598. ULONG nLen;
  2599. nLen = sizeof(TCHAR)*(lstrlenW(lpPropArray[i].Value.MVszW.lppszW[j])+1);
  2600. CopyMemory(szBuf,&nLen, sizeof(ULONG));
  2601. szBuf += sizeof(ULONG);
  2602. CopyMemory(szBuf,lpPropArray[i].Value.MVszW.lppszW[j], nLen);
  2603. szBuf += nLen;
  2604. }
  2605. break;
  2606. case(PT_MV_CLSID):
  2607. CopyMemory(szBuf,lpPropArray[i].Value.MVguid.lpguid, lpulrgPropDataSize[i]);
  2608. szBuf += lpulrgPropDataSize[i];
  2609. break;
  2610. } //switch
  2611. } //if
  2612. } //for
  2613. *lpcbBuf = ulRecordDataSize;
  2614. *lppBuf = lp;
  2615. hr = S_OK;
  2616. out:
  2617. LocalFreeAndNull(&lpulrgPropDataSize);
  2618. return hr;
  2619. }
  2620. //$$////////////////////////////////////////////////////////////////////////////////
  2621. //
  2622. // HrGetPropArrayFromBuffer - translates a buffer (from file or memory) into
  2623. // a prop array. The format of the data in the buffer is the same as
  2624. // the format of data in the .wab file
  2625. //
  2626. //
  2627. // Params: char * szBuf- buffer to interpret
  2628. // cbBuf - sizeof buffer
  2629. // ulcPropCount- # of props in buffer
  2630. // lppPropArray - returned prop array
  2631. //
  2632. // ulcNumExtraProps - an extra number of props to add to the PropArray
  2633. // during allocation. These blank props are later used for
  2634. // extending the prop array easily ..
  2635. //
  2636. ////////////////////////////////////////////////////////////////////////////////////
  2637. HRESULT HrGetPropArrayFromBuffer( LPBYTE szBuf,
  2638. ULONG cbBuf,
  2639. ULONG ulcPropCount,
  2640. ULONG ulcNumExtraProps,
  2641. LPSPropValue * lppPropArray)
  2642. {
  2643. HRESULT hr = S_OK;
  2644. LPBYTE lp = NULL;
  2645. ULONG i = 0,j=0, k=0;
  2646. DWORD cbBufLeft = cbBuf;
  2647. if(!lppPropArray)
  2648. {
  2649. hr = MAPI_E_INVALID_PARAMETER;
  2650. goto out;
  2651. }
  2652. *lppPropArray = NULL;
  2653. *lppPropArray = LocalAlloc(LMEM_ZEROINIT, (ulcPropCount+ulcNumExtraProps) * sizeof(SPropValue));
  2654. if (!(*lppPropArray))
  2655. {
  2656. DebugTrace(TEXT("Error allocating memory\n"));
  2657. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2658. goto out;
  2659. }
  2660. for(i=0;i<(ulcPropCount+ulcNumExtraProps);i++)
  2661. (*lppPropArray)[i].ulPropTag = PR_NULL;
  2662. lp = szBuf;
  2663. for(i=0;i<ulcPropCount;i++)
  2664. {
  2665. ULONG ulDataSize = 0;
  2666. ULONG ulcValues = 0;
  2667. // Copy PropTag
  2668. CopyMemory(&((*lppPropArray)[i].ulPropTag),lp,sizeof(ULONG));
  2669. lp+=sizeof(ULONG);
  2670. AssertSz((*lppPropArray)[i].ulPropTag, TEXT("Null PropertyTag"));
  2671. if(ulDataSize > cbBuf)
  2672. {
  2673. hr = MAPI_E_CORRUPT_DATA;
  2674. goto out;
  2675. }
  2676. if (((*lppPropArray)[i].ulPropTag & MV_FLAG))
  2677. {
  2678. //multi-valued
  2679. //DebugTrace(TEXT("MV_PROP\n"));
  2680. //Copy cValues
  2681. CopyMemory(&ulcValues,lp,sizeof(ULONG));
  2682. lp+=sizeof(ULONG);
  2683. //Copy DataSize
  2684. CopyMemory(&ulDataSize,lp,sizeof(ULONG));
  2685. lp+=sizeof(ULONG);
  2686. switch(PROP_TYPE((*lppPropArray)[i].ulPropTag))
  2687. {
  2688. case(PT_MV_I2):
  2689. case(PT_MV_LONG):
  2690. case(PT_MV_R4):
  2691. case(PT_MV_DOUBLE):
  2692. case(PT_MV_CURRENCY):
  2693. case(PT_MV_APPTIME):
  2694. case(PT_MV_SYSTIME):
  2695. case(PT_MV_CLSID):
  2696. case(PT_MV_I8):
  2697. (*lppPropArray)[i].Value.MVi.lpi = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  2698. if (!((*lppPropArray)[i].Value.MVi.lpi))
  2699. {
  2700. DebugTrace(TEXT("Error allocating memory\n"));
  2701. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2702. goto out;
  2703. }
  2704. (*lppPropArray)[i].Value.MVi.cValues = ulcValues;
  2705. CopyMemory((*lppPropArray)[i].Value.MVi.lpi, lp, ulDataSize);
  2706. lp += ulDataSize;
  2707. break;
  2708. case(PT_MV_BINARY):
  2709. (*lppPropArray)[i].Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary));
  2710. if (!((*lppPropArray)[i].Value.MVbin.lpbin))
  2711. {
  2712. DebugTrace(TEXT("Error allocating memory\n"));
  2713. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2714. goto out;
  2715. }
  2716. (*lppPropArray)[i].Value.MVbin.cValues = ulcValues;
  2717. for (j=0;j<ulcValues;j++)
  2718. {
  2719. ULONG nLen;
  2720. CopyMemory(&nLen, lp, sizeof(ULONG));
  2721. lp += sizeof(ULONG);
  2722. (*lppPropArray)[i].Value.MVbin.lpbin[j].cb = nLen;
  2723. (*lppPropArray)[i].Value.MVbin.lpbin[j].lpb = LocalAlloc(LMEM_ZEROINIT, nLen);
  2724. if (!((*lppPropArray)[i].Value.MVbin.lpbin[j].lpb))
  2725. {
  2726. DebugTrace(TEXT("Error allocating memory\n"));
  2727. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2728. goto out;
  2729. }
  2730. CopyMemory((*lppPropArray)[i].Value.MVbin.lpbin[j].lpb, lp, nLen);
  2731. lp += nLen;
  2732. }
  2733. // hack: we want to upgrade the old WAB_FOLDER_PARENT_OLDPROP props to a new WAB_FOLDER_PARENT
  2734. // This is the best place to do it and the check only happens on contacts with MV_BINARY props
  2735. if((*lppPropArray)[i].ulPropTag == PR_WAB_FOLDER_PARENT_OLDPROP && PR_WAB_FOLDER_PARENT)
  2736. (*lppPropArray)[i].ulPropTag = PR_WAB_FOLDER_PARENT;
  2737. break;
  2738. case(PT_MV_STRING8):
  2739. (*lppPropArray)[i].Value.MVszA.lppszA = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPSTR));
  2740. if (!((*lppPropArray)[i].Value.MVszA.lppszA))
  2741. {
  2742. DebugTrace(TEXT("Error allocating memory\n"));
  2743. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2744. goto out;
  2745. }
  2746. for (j=0;j<ulcValues;j++)
  2747. {
  2748. ULONG nLen;
  2749. CopyMemory(&nLen, lp, sizeof(ULONG));
  2750. lp += sizeof(ULONG);
  2751. (*lppPropArray)[i].Value.MVszA.lppszA[j] = LocalAlloc(LMEM_ZEROINIT, nLen);
  2752. if (!((*lppPropArray)[i].Value.MVszA.lppszA[j]))
  2753. {
  2754. DebugTrace(TEXT("Error allocating memory\n"));
  2755. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2756. goto out;
  2757. }
  2758. CopyMemory((*lppPropArray)[i].Value.MVszA.lppszA[j], lp, nLen);
  2759. lp += nLen;
  2760. }
  2761. (*lppPropArray)[i].Value.MVszA.cValues = ulcValues;
  2762. break;
  2763. case(PT_MV_UNICODE):
  2764. (*lppPropArray)[i].Value.MVszW.lppszW = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR));
  2765. if (!((*lppPropArray)[i].Value.MVszW.lppszW))
  2766. {
  2767. DebugTrace(TEXT("Error allocating memory\n"));
  2768. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2769. goto out;
  2770. }
  2771. for (j=0;j<ulcValues;j++)
  2772. {
  2773. ULONG nLen;
  2774. CopyMemory(&nLen, lp, sizeof(ULONG));
  2775. lp += sizeof(ULONG);
  2776. (*lppPropArray)[i].Value.MVszW.lppszW[j] = LocalAlloc(LMEM_ZEROINIT, nLen);
  2777. if (!((*lppPropArray)[i].Value.MVszW.lppszW[j]))
  2778. {
  2779. DebugTrace(TEXT("Error allocating memory\n"));
  2780. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2781. goto out;
  2782. }
  2783. CopyMemory((*lppPropArray)[i].Value.MVszW.lppszW[j], lp, nLen);
  2784. lp += nLen;
  2785. }
  2786. (*lppPropArray)[i].Value.MVszW.cValues = ulcValues;
  2787. break;
  2788. default:
  2789. DebugTrace(TEXT("Unknown Prop Type\n"));
  2790. break;
  2791. }
  2792. }
  2793. else
  2794. {
  2795. //Single Valued
  2796. CopyMemory(&ulDataSize,lp,sizeof(ULONG));
  2797. lp+=sizeof(ULONG);
  2798. if(ulDataSize > cbBuf)
  2799. {
  2800. hr = MAPI_E_CORRUPT_DATA;
  2801. goto out;
  2802. }
  2803. switch(PROP_TYPE((*lppPropArray)[i].ulPropTag))
  2804. {
  2805. case(PT_CLSID):
  2806. (*lppPropArray)[i].Value.lpguid = (LPGUID) LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  2807. if (!((*lppPropArray)[i].Value.lpguid))
  2808. {
  2809. DebugTrace(TEXT("Error allocating memory\n"));
  2810. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2811. goto out;
  2812. }
  2813. CopyMemory((*lppPropArray)[i].Value.lpguid, lp, ulDataSize);
  2814. lp += ulDataSize;
  2815. break;
  2816. case(PT_STRING8):
  2817. (*lppPropArray)[i].Value.lpszA = (LPSTR) LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  2818. if (!((*lppPropArray)[i].Value.lpszA))
  2819. {
  2820. DebugTrace(TEXT("Error allocating memory\n"));
  2821. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2822. goto out;
  2823. }
  2824. CopyMemory((*lppPropArray)[i].Value.lpszA, lp, ulDataSize);
  2825. lp += ulDataSize;
  2826. break;
  2827. case(PT_UNICODE):
  2828. (*lppPropArray)[i].Value.lpszW = (LPTSTR) LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  2829. if (!((*lppPropArray)[i].Value.lpszW))
  2830. {
  2831. DebugTrace(TEXT("Error allocating memory\n"));
  2832. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2833. goto out;
  2834. }
  2835. CopyMemory((*lppPropArray)[i].Value.lpszW, lp, ulDataSize);
  2836. lp += ulDataSize;
  2837. break;
  2838. case(PT_BINARY):
  2839. (*lppPropArray)[i].Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  2840. if (!((*lppPropArray)[i].Value.bin.lpb))
  2841. {
  2842. DebugTrace(TEXT("Error allocating memory\n"));
  2843. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2844. goto out;
  2845. }
  2846. (*lppPropArray)[i].Value.bin.cb = ulDataSize;
  2847. CopyMemory((*lppPropArray)[i].Value.bin.lpb, lp, ulDataSize);
  2848. lp += ulDataSize;
  2849. break;
  2850. case(PT_SHORT):
  2851. CopyMemory(&((*lppPropArray)[i].Value.i),lp,ulDataSize);
  2852. lp += ulDataSize;
  2853. break;
  2854. case(PT_LONG):
  2855. CopyMemory(&((*lppPropArray)[i].Value.l),lp,ulDataSize);
  2856. lp += ulDataSize;
  2857. break;
  2858. case(PT_R4):
  2859. CopyMemory(&((*lppPropArray)[i].Value.flt),lp,ulDataSize);
  2860. lp += ulDataSize;
  2861. break;
  2862. case(PT_DOUBLE):
  2863. case(PT_APPTIME):
  2864. CopyMemory(&((*lppPropArray)[i].Value.dbl),lp,ulDataSize);
  2865. lp += ulDataSize;
  2866. break;
  2867. case(PT_BOOLEAN):
  2868. CopyMemory(&((*lppPropArray)[i].Value.b),lp,ulDataSize);
  2869. lp += ulDataSize;
  2870. break;
  2871. case(PT_SYSTIME):
  2872. CopyMemory(&((*lppPropArray)[i].Value.ft),lp,ulDataSize);
  2873. lp += ulDataSize;
  2874. break;
  2875. case(PT_CURRENCY):
  2876. CopyMemory(&((*lppPropArray)[i].Value.cur),lp,ulDataSize);
  2877. lp += ulDataSize;
  2878. break;
  2879. default:
  2880. DebugTrace(TEXT("Unknown Prop Type\n"));
  2881. CopyMemory(&((*lppPropArray)[i].Value.i),lp,ulDataSize);
  2882. lp += ulDataSize;
  2883. break;
  2884. }
  2885. }
  2886. }
  2887. hr = S_OK;
  2888. out:
  2889. if (FAILED(hr))
  2890. {
  2891. if ((*lppPropArray) && (ulcPropCount > 0))
  2892. {
  2893. LocalFreePropArray(NULL, ulcPropCount, lppPropArray);
  2894. *lppPropArray = NULL;
  2895. }
  2896. }
  2897. // _DebugProperties(*lppPropArray, ulcPropCount, TEXT("GetPropArrayFromBuffer"));
  2898. return hr;
  2899. }
  2900. //$$////////////////////////////////////////////////////////////////////////////////
  2901. //
  2902. // HrGetPropArrayFromFileRecord - goes into a file, reads the record at the
  2903. // given offset, and turns the record data into a lpPropArray
  2904. //
  2905. // IN
  2906. // hFile - the WAB file to read from
  2907. // ulOffset - the record offset within the file
  2908. //
  2909. // OUT
  2910. // ulcValues - # of props in the prop array
  2911. // lpPropArray - the prop array from the record
  2912. //
  2913. // Returns
  2914. // E_FAIL, S_OK,
  2915. // MAPI_E_INVALID_OBJECT
  2916. // MAPI_E_CORRUPT_DATA
  2917. // MAPI_E_NOT_ENOUGH_MEMORY
  2918. //
  2919. ////////////////////////////////////////////////////////////////////////////////////
  2920. HRESULT HrGetPropArrayFromFileRecord(HANDLE hMPSWabFile,
  2921. ULONG ulRecordOffset,
  2922. BOOL * lpbErrorDetected,
  2923. ULONG * lpulObjType,
  2924. ULONG * lpulRecordSize,
  2925. ULONG * lpulcPropCount,
  2926. LPSPropValue * lppPropArray)
  2927. {
  2928. HRESULT hr = S_OK;
  2929. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  2930. DWORD dwNumofBytes = 0;
  2931. LPBYTE szBuf = NULL;
  2932. LPBYTE lp = NULL;
  2933. ULONG i = 0,j=0, k=0;
  2934. ULONG nIndexPos = 0;
  2935. BOOL bErrorDetected = FALSE;
  2936. if(!ReadDataFromWABFile(hMPSWabFile,
  2937. ulRecordOffset,
  2938. (LPVOID) &MPSWabRecordHeader,
  2939. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  2940. goto out;
  2941. // Its important that we get the record size first because a
  2942. // calling client may depend on the size to move to the
  2943. // next record if they want to skip invalid ones.
  2944. if(lpulRecordSize)
  2945. {
  2946. *lpulRecordSize = sizeof(MPSWab_RECORD_HEADER) +
  2947. MPSWabRecordHeader.ulPropTagArraySize +
  2948. MPSWabRecordHeader.ulRecordDataSize;
  2949. }
  2950. if(lpulObjType)
  2951. {
  2952. *lpulObjType = MPSWabRecordHeader.ulObjType;
  2953. }
  2954. if(!bIsValidRecord( MPSWabRecordHeader,
  2955. 0xFFFFFFFF,
  2956. ulRecordOffset,
  2957. GetFileSize(hMPSWabFile,NULL)))
  2958. {
  2959. //this should never happen but who knows
  2960. DebugTrace(TEXT("Error: Obtained an invalid record ...\n"));
  2961. hr = MAPI_E_INVALID_OBJECT;
  2962. goto out;
  2963. }
  2964. szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize);
  2965. if (!szBuf)
  2966. {
  2967. DebugTrace(TEXT("Error allocating memory\n"));
  2968. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2969. goto out;
  2970. }
  2971. // Set File Pointer to beginning of Data Section
  2972. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  2973. MPSWabRecordHeader.ulPropTagArraySize,
  2974. NULL,
  2975. FILE_CURRENT))
  2976. {
  2977. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2978. goto out;
  2979. }
  2980. //Read in the data
  2981. // Read record header
  2982. if(!ReadFile( hMPSWabFile,
  2983. (LPVOID) szBuf,
  2984. (DWORD) MPSWabRecordHeader.ulRecordDataSize,
  2985. &dwNumofBytes,
  2986. NULL))
  2987. {
  2988. DebugTrace(TEXT("Reading Record Header failed.\n"));
  2989. goto out;
  2990. }
  2991. if(HR_FAILED(hr = HrGetPropArrayFromBuffer( szBuf,
  2992. MPSWabRecordHeader.ulRecordDataSize,
  2993. MPSWabRecordHeader.ulcPropCount, 0,
  2994. lppPropArray) ))
  2995. {
  2996. goto out;
  2997. }
  2998. *lpulcPropCount = MPSWabRecordHeader.ulcPropCount;
  2999. hr = S_OK;
  3000. out:
  3001. // if this is a container, make sure its object type is correct
  3002. if(!HR_FAILED(hr) && MPSWabRecordHeader.ulObjType == RECORD_CONTAINER)
  3003. SetContainerObjectType(*lpulcPropCount, *lppPropArray, FALSE);
  3004. if(hr == MAPI_E_CORRUPT_DATA)
  3005. bErrorDetected = TRUE;
  3006. if (lpbErrorDetected)
  3007. *lpbErrorDetected = bErrorDetected;
  3008. LocalFreeAndNull(&szBuf);
  3009. return hr;
  3010. }
  3011. //$$////////////////////////////////////////////////////////////////////////////
  3012. //
  3013. // Space saver function for writing data to the file
  3014. //
  3015. ////////////////////////////////////////////////////////////////////////////////
  3016. BOOL WriteDataToWABFile(HANDLE hMPSWabFile,
  3017. ULONG ulOffset,
  3018. LPVOID lpData,
  3019. ULONG ulDataSize)
  3020. {
  3021. DWORD dwNumofBytes = 0;
  3022. if (0xFFFFFFFF != SetFilePointer ( hMPSWabFile,
  3023. ulOffset,
  3024. NULL,
  3025. FILE_BEGIN))
  3026. {
  3027. return WriteFile( hMPSWabFile,
  3028. lpData,
  3029. (DWORD) ulDataSize,
  3030. &dwNumofBytes,
  3031. NULL);
  3032. }
  3033. return FALSE;
  3034. }
  3035. //$$////////////////////////////////////////////////////////////////////////////////
  3036. //
  3037. // Space saver function for reading data from the file
  3038. //
  3039. ////////////////////////////////////////////////////////////////////////////////////
  3040. BOOL ReadDataFromWABFile(HANDLE hMPSWabFile,
  3041. ULONG ulOffset,
  3042. LPVOID lpData,
  3043. ULONG ulDataSize)
  3044. {
  3045. DWORD dwNumofBytes = 0;
  3046. if (0xFFFFFFFF != SetFilePointer ( hMPSWabFile,
  3047. ulOffset,
  3048. NULL,
  3049. FILE_BEGIN))
  3050. {
  3051. return ReadFile(hMPSWabFile,
  3052. lpData,
  3053. (DWORD) ulDataSize,
  3054. &dwNumofBytes,
  3055. NULL);
  3056. }
  3057. return FALSE;
  3058. }
  3059. //$$****************************************************************************
  3060. //
  3061. // FreeGuidnamedprops - frees a GUID_NAMED_PROPS array
  3062. //
  3063. // ulcGUIDCount - number of elements in the lpgnp array
  3064. // lpgnp - arry of GUID_NAMED_PROPS
  3065. //****************************************************************************//
  3066. void FreeGuidnamedprops(ULONG ulcGUIDCount,
  3067. LPGUID_NAMED_PROPS lpgnp)
  3068. {
  3069. ULONG i=0,j=0;
  3070. if(lpgnp)
  3071. {
  3072. // for(i=ulcGUIDCount;i>0;--i)
  3073. for (i = 0; i < ulcGUIDCount; i++)
  3074. {
  3075. if(lpgnp[i].lpnm)
  3076. {
  3077. // for(j=lpgnp[i].cValues;j>0;--j)
  3078. for (j = 0; j < lpgnp[i].cValues; j++)
  3079. {
  3080. LocalFreeAndNull(&lpgnp[i].lpnm[j].lpsz);
  3081. }
  3082. LocalFreeAndNull(&lpgnp[i].lpnm);
  3083. }
  3084. LocalFreeAndNull(&lpgnp[i].lpGUID);
  3085. }
  3086. LocalFreeAndNull(&lpgnp);
  3087. }
  3088. return;
  3089. }
  3090. //$$////////////////////////////////////////////////////////////////////////////////////////////////
  3091. //
  3092. // OpenWABFile - Opens the WAB file. If file is missing, restores from backup. If backup is missing
  3093. // creates a new file
  3094. //
  3095. // hWndParent - parent for opening message boxes - no message boxesif null
  3096. // lphMPSWabFile - returned file pointer
  3097. //
  3098. ////////////////////////////////////////////////////////////////////////////////////////////////////
  3099. HRESULT OpenWABFile(LPTSTR lpszFileName, HWND hWndParent, HANDLE * lphMPSWabFile)
  3100. {
  3101. HANDLE hMPSWabFile = NULL;
  3102. TCHAR szBackupFileName[MAX_PATH];
  3103. WIN32_FIND_DATA wfd = {0};
  3104. HANDLE hff = NULL;
  3105. HRESULT hr = E_FAIL;
  3106. DWORD dwErr = 0;
  3107. hMPSWabFile = CreateFile( lpszFileName,
  3108. GENERIC_READ | GENERIC_WRITE,
  3109. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3110. (LPSECURITY_ATTRIBUTES) NULL,
  3111. OPEN_EXISTING,
  3112. FILE_FLAG_RANDOM_ACCESS,
  3113. (HANDLE) NULL);
  3114. if(hMPSWabFile != INVALID_HANDLE_VALUE)
  3115. {
  3116. hr = S_OK;
  3117. goto out;
  3118. }
  3119. // Something happened find out what..
  3120. dwErr = GetLastError();
  3121. if(dwErr == ERROR_ACCESS_DENIED)
  3122. {
  3123. hr = MAPI_E_NO_ACCESS;
  3124. goto out;
  3125. }
  3126. if(dwErr != ERROR_FILE_NOT_FOUND)
  3127. {
  3128. hr = E_FAIL;
  3129. goto out;
  3130. }
  3131. // Get the backup file name
  3132. szBackupFileName[0]='\0';
  3133. GetWABBackupFileName(lpszFileName, szBackupFileName, ARRAYSIZE(szBackupFileName));
  3134. hff = FindFirstFile(szBackupFileName,&wfd);
  3135. if(hff != INVALID_HANDLE_VALUE)
  3136. {
  3137. // we found the backup file
  3138. // copy it into the wab file name
  3139. CopyFile(szBackupFileName, lpszFileName, FALSE);
  3140. hMPSWabFile = CreateFile( lpszFileName,
  3141. GENERIC_READ | GENERIC_WRITE,
  3142. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3143. (LPSECURITY_ATTRIBUTES) NULL,
  3144. OPEN_EXISTING,
  3145. FILE_FLAG_RANDOM_ACCESS,
  3146. (HANDLE) NULL);
  3147. if(hMPSWabFile != INVALID_HANDLE_VALUE)
  3148. {
  3149. hr = S_OK;
  3150. goto out;
  3151. }
  3152. }
  3153. // if we're still here .. nothing worked .. so create a new file
  3154. {
  3155. MPSWab_FILE_HEADER MPSWabFileHeader;
  3156. if(CreateMPSWabFile(IN &MPSWabFileHeader,
  3157. lpszFileName,
  3158. MAX_INITIAL_INDEX_ENTRIES,
  3159. NAMEDPROP_STORE_SIZE))
  3160. {
  3161. hMPSWabFile = CreateFile( lpszFileName,
  3162. GENERIC_READ | GENERIC_WRITE,
  3163. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3164. (LPSECURITY_ATTRIBUTES) NULL,
  3165. OPEN_EXISTING,
  3166. FILE_FLAG_RANDOM_ACCESS,
  3167. (HANDLE) NULL);
  3168. if(hMPSWabFile != INVALID_HANDLE_VALUE)
  3169. hr = S_OK;
  3170. }
  3171. }
  3172. out:
  3173. *lphMPSWabFile = hMPSWabFile;
  3174. if(hff)
  3175. FindClose(hff);
  3176. return hr;
  3177. }
  3178. //$$/////////////////////////////////////////////////////////////////////////////////
  3179. //
  3180. //
  3181. // nCountSubStrings - counts space-delimted substrings in a given string
  3182. //
  3183. //
  3184. /////////////////////////////////////////////////////////////////////////////////////
  3185. int nCountSubStrings(LPTSTR lpszSearchStr)
  3186. {
  3187. int nSubStr = 0;
  3188. LPTSTR lpTemp = lpszSearchStr;
  3189. LPTSTR lpStart = lpszSearchStr;
  3190. if (!lpszSearchStr)
  3191. goto out;
  3192. if (!lstrlen(lpszSearchStr))
  3193. goto out;
  3194. TrimSpaces(lpszSearchStr);
  3195. // Count the spaces
  3196. while(*lpTemp)
  3197. {
  3198. if (IsSpace(lpTemp) &&
  3199. ! IsSpace(CharNext(lpTemp))) {
  3200. nSubStr++;
  3201. }
  3202. lpTemp = CharNext(lpTemp);
  3203. }
  3204. // Number of substrings is 1 more than number of spaces
  3205. nSubStr++;
  3206. out:
  3207. return nSubStr;
  3208. }
  3209. #define DONTFIND 0
  3210. #define DOFIND 1
  3211. #define NOTFOUND 0
  3212. #define FOUND 1
  3213. extern BOOL SubstringSearchEx(LPTSTR pszTarget, LPTSTR pszSearch, LCID lcid);
  3214. extern int my_atoi(LPTSTR lpsz);
  3215. //$$////////////////////////////////////////////////////////////////////////////////
  3216. //
  3217. // HrDoLocalWABSearch
  3218. //
  3219. //
  3220. //
  3221. //
  3222. //
  3223. ////////////////////////////////////////////////////////////////////////////////////
  3224. HRESULT HrDoLocalWABSearch( IN HANDLE hPropertyStore,
  3225. IN LPSBinary lpsbCont, //container entryid for Outlook stores
  3226. IN LDAP_SEARCH_PARAMS LDAPsp,
  3227. OUT LPULONG lpulFoundCount,
  3228. OUT LPSBinary * lprgsbEntryIDs )
  3229. {
  3230. int bFindName = DONTFIND;
  3231. int bFindEmail = DONTFIND;
  3232. int bFindAddress = DONTFIND;
  3233. int bFindPhone = DONTFIND;
  3234. int bFindOther = DONTFIND;
  3235. LCID lcid = 0;
  3236. int nUseLCID = 0;
  3237. TCHAR szUseLCID[2];
  3238. int bFoundName = NOTFOUND;
  3239. int bFoundEmail = NOTFOUND;
  3240. int bFoundAddress = NOTFOUND;
  3241. int bFoundPhone = NOTFOUND;
  3242. int bFoundOther = NOTFOUND;
  3243. ULONG nSubStr[ldspMAX];
  3244. LPTSTR * lppszSubStr[ldspMAX];
  3245. HRESULT hr = E_FAIL;
  3246. SPropertyRestriction PropRes;
  3247. ULONG ulPropCount = 0;
  3248. ULONG ulEIDCount = 0;
  3249. LPSBinary rgsbEntryIDs = NULL;
  3250. LPSPropValue lpPropArray = NULL;
  3251. ULONG ulcPropCount = 0;
  3252. ULONG i,j,k;
  3253. ULONG ulFoundIndex = 0;
  3254. BOOL bFileLocked = FALSE;
  3255. BOOL bFound = FALSE;
  3256. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  3257. HANDLE hMPSWabFile = NULL;
  3258. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3259. ULONG cchSize;
  3260. if(!lpulFoundCount || !lprgsbEntryIDs)
  3261. goto out;
  3262. *lpulFoundCount = 0;
  3263. *lprgsbEntryIDs = NULL;
  3264. LoadString(hinstMapiX, idsUseLCID, szUseLCID, CharSizeOf(szUseLCID));
  3265. nUseLCID = my_atoi(szUseLCID);
  3266. if(nUseLCID)
  3267. lcid = GetUserDefaultLCID();
  3268. if(lstrlen(LDAPsp.szData[ldspDisplayName]))
  3269. bFindName = DOFIND;
  3270. if(lstrlen(LDAPsp.szData[ldspEmail]))
  3271. bFindEmail = DOFIND;
  3272. if(lstrlen(LDAPsp.szData[ldspAddress]))
  3273. bFindAddress = DOFIND;
  3274. if(lstrlen(LDAPsp.szData[ldspPhone]))
  3275. bFindPhone = DOFIND;
  3276. if(lstrlen(LDAPsp.szData[ldspOther]))
  3277. bFindOther = DOFIND;
  3278. if (bFindName +bFindEmail +bFindPhone +bFindAddress +bFindOther == 0)
  3279. goto out;
  3280. for(i=0;i<ldspMAX;i++)
  3281. {
  3282. nSubStr[i] = (ULONG) nCountSubStrings(LDAPsp.szData[i]);
  3283. if(!nSubStr[i])
  3284. {
  3285. lppszSubStr[i] = NULL;
  3286. continue;
  3287. }
  3288. lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * nSubStr[i]);
  3289. if(!lppszSubStr[i])
  3290. {
  3291. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3292. goto out;
  3293. }
  3294. {
  3295. // Fill in the substrings
  3296. ULONG nIndex = 0;
  3297. LPTSTR lpTemp = NULL;
  3298. LPTSTR lpStart = NULL;
  3299. TCHAR szBuf[MAX_UI_STR];
  3300. StrCpyN(szBuf, LDAPsp.szData[i], ARRAYSIZE(szBuf));
  3301. lpTemp = szBuf;
  3302. lpStart = szBuf;
  3303. // Bug 2558 - filter out commas from display name
  3304. if(i == ldspDisplayName)
  3305. {
  3306. while(lpTemp && *lpTemp)
  3307. {
  3308. if(*lpTemp == ',')
  3309. *lpTemp = ' ';
  3310. lpTemp++;
  3311. }
  3312. lpTemp = szBuf;
  3313. }
  3314. while(*lpTemp)
  3315. {
  3316. if (IsSpace(lpTemp) &&
  3317. ! IsSpace(CharNext(lpTemp))) {
  3318. LPTSTR lpNextString = CharNext(lpTemp);
  3319. *lpTemp = '\0';
  3320. lpTemp = lpNextString;
  3321. cchSize = lstrlen(lpStart)+1;
  3322. lppszSubStr[i][nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  3323. if(!lppszSubStr[i][nIndex])
  3324. {
  3325. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3326. goto out;
  3327. }
  3328. StrCpyN(lppszSubStr[i][nIndex], lpStart, cchSize);
  3329. lpStart = lpTemp;
  3330. nIndex++;
  3331. }
  3332. else
  3333. lpTemp = CharNext(lpTemp);
  3334. }
  3335. if(nIndex==nSubStr[i]-1)
  3336. {
  3337. //we're off by one
  3338. cchSize = lstrlen(lpStart)+1;
  3339. lppszSubStr[i][nIndex] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  3340. if(!lppszSubStr[i][nIndex])
  3341. {
  3342. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3343. goto out;
  3344. }
  3345. StrCpyN(lppszSubStr[i][nIndex], lpStart, cchSize);
  3346. }
  3347. for(j=0;j<nSubStr[i];j++)
  3348. TrimSpaces(lppszSubStr[i][j]);
  3349. }
  3350. } // for i ...
  3351. if(!pt_bIsWABOpenExSession)
  3352. {
  3353. // Lock the file
  3354. if(!LockFileAccess(lpMPSWabFileInfo))
  3355. {
  3356. DebugTrace(TEXT("LockFileAccess Failed\n"));
  3357. hr = MAPI_E_NO_ACCESS;
  3358. goto out;
  3359. }
  3360. else
  3361. {
  3362. bFileLocked = TRUE;
  3363. }
  3364. }
  3365. // Get an index of all entries in the WAB
  3366. PropRes.ulPropTag = PR_DISPLAY_NAME;
  3367. PropRes.relop = RELOP_EQ;
  3368. PropRes.lpProp = NULL;
  3369. hr = FindRecords( IN hPropertyStore,
  3370. IN lpsbCont,
  3371. IN AB_MATCH_PROP_ONLY,
  3372. FALSE,
  3373. &PropRes,
  3374. &ulEIDCount,
  3375. &rgsbEntryIDs);
  3376. ulFoundIndex = 0;
  3377. if(!pt_bIsWABOpenExSession)
  3378. {
  3379. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  3380. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  3381. HR_FAILED(hr))
  3382. {
  3383. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  3384. goto out;
  3385. }
  3386. }
  3387. for(i=0;i<ulEIDCount;i++)
  3388. {
  3389. if(!pt_bIsWABOpenExSession)
  3390. {
  3391. DWORD dwEID = 0;
  3392. CopyMemory(&dwEID, rgsbEntryIDs[i].lpb, rgsbEntryIDs[i].cb);
  3393. hr = ReadRecordWithoutLocking(
  3394. hMPSWabFile,
  3395. lpMPSWabFileInfo,
  3396. dwEID,
  3397. &ulcPropCount,
  3398. &lpPropArray);
  3399. }
  3400. else
  3401. {
  3402. hr = ReadRecord(hPropertyStore,
  3403. &rgsbEntryIDs[i],
  3404. 0,
  3405. &ulcPropCount,
  3406. &lpPropArray);
  3407. }
  3408. if(HR_FAILED(hr))
  3409. goto endloop;
  3410. bFoundName = NOTFOUND;
  3411. bFoundEmail = NOTFOUND;
  3412. bFoundAddress = NOTFOUND;
  3413. bFoundPhone = NOTFOUND;
  3414. bFoundOther = NOTFOUND;
  3415. for(j=0;j<ulcPropCount;j++)
  3416. {
  3417. switch(lpPropArray[j].ulPropTag)
  3418. {
  3419. case PR_DISPLAY_NAME:
  3420. case PR_GIVEN_NAME:
  3421. case PR_SURNAME:
  3422. case PR_NICKNAME:
  3423. case PR_MIDDLE_NAME:
  3424. case PR_COMPANY_NAME:
  3425. if(bFindName == DONTFIND)
  3426. continue;
  3427. if(bFoundName == FOUND)
  3428. continue;
  3429. bFound = TRUE;
  3430. for(k=0;k<nSubStr[ldspDisplayName];k++)
  3431. {
  3432. if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspDisplayName][k],lcid))
  3433. {
  3434. bFound = FALSE;
  3435. break;
  3436. }
  3437. }
  3438. if(bFound)
  3439. {
  3440. bFoundName = FOUND;
  3441. continue;
  3442. }
  3443. break;
  3444. case PR_EMAIL_ADDRESS:
  3445. case PR_ADDRTYPE:
  3446. if(bFindEmail == DONTFIND)
  3447. continue;
  3448. if(bFoundEmail == FOUND)
  3449. continue;
  3450. bFound = TRUE;
  3451. for(k=0;k<nSubStr[ldspEmail];k++)
  3452. {
  3453. if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspEmail][k],lcid))
  3454. {
  3455. bFound = FALSE;
  3456. break;
  3457. }
  3458. }
  3459. if(bFound)
  3460. {
  3461. bFoundEmail = FOUND;
  3462. continue;
  3463. }
  3464. break;
  3465. case PR_HOME_ADDRESS_STREET:
  3466. case PR_HOME_ADDRESS_CITY:
  3467. case PR_HOME_ADDRESS_POSTAL_CODE:
  3468. case PR_HOME_ADDRESS_STATE_OR_PROVINCE:
  3469. case PR_HOME_ADDRESS_COUNTRY:
  3470. case PR_BUSINESS_ADDRESS_STREET:
  3471. case PR_BUSINESS_ADDRESS_CITY:
  3472. case PR_BUSINESS_ADDRESS_POSTAL_CODE:
  3473. case PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE:
  3474. case PR_BUSINESS_ADDRESS_COUNTRY:
  3475. if(bFindAddress == DONTFIND)
  3476. continue;
  3477. if(bFoundAddress == FOUND)
  3478. continue;
  3479. bFound = TRUE;
  3480. for(k=0;k<nSubStr[ldspAddress];k++)
  3481. {
  3482. if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspAddress][k],lcid))
  3483. {
  3484. bFound = FALSE;
  3485. break;
  3486. }
  3487. }
  3488. if(bFound)
  3489. {
  3490. bFoundAddress = FOUND;
  3491. continue;
  3492. }
  3493. break;
  3494. case PR_HOME_TELEPHONE_NUMBER:
  3495. case PR_HOME_FAX_NUMBER:
  3496. case PR_CELLULAR_TELEPHONE_NUMBER:
  3497. case PR_BUSINESS_TELEPHONE_NUMBER:
  3498. case PR_BUSINESS_FAX_NUMBER:
  3499. case PR_PAGER_TELEPHONE_NUMBER:
  3500. if(bFindPhone == DONTFIND)
  3501. continue;
  3502. if(bFoundPhone == FOUND)
  3503. continue;
  3504. bFound = TRUE;
  3505. for(k=0;k<nSubStr[ldspPhone];k++)
  3506. {
  3507. if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspPhone][k],lcid))
  3508. {
  3509. bFound = FALSE;
  3510. break;
  3511. }
  3512. }
  3513. if(bFound)
  3514. {
  3515. bFoundPhone = FOUND;
  3516. continue;
  3517. }
  3518. break;
  3519. case PR_TITLE:
  3520. case PR_DEPARTMENT_NAME:
  3521. case PR_OFFICE_LOCATION:
  3522. case PR_COMMENT:
  3523. case PR_BUSINESS_HOME_PAGE:
  3524. case PR_PERSONAL_HOME_PAGE:
  3525. if(bFindOther == DONTFIND)
  3526. continue;
  3527. if(bFoundOther == FOUND)
  3528. continue;
  3529. bFound = TRUE;
  3530. for(k=0;k<nSubStr[ldspOther];k++)
  3531. {
  3532. if(!SubstringSearchEx(lpPropArray[j].Value.LPSZ, lppszSubStr[ldspOther][k],lcid))
  3533. {
  3534. bFound = FALSE;
  3535. break;
  3536. }
  3537. }
  3538. if(bFound)
  3539. {
  3540. bFoundOther = FOUND;
  3541. continue;
  3542. }
  3543. break;
  3544. } //switch
  3545. }// for j
  3546. if ((bFindName +bFindEmail +bFindPhone +bFindAddress +bFindOther) !=
  3547. (bFoundName+bFoundEmail+bFoundPhone+bFoundAddress+bFoundOther))
  3548. goto endloop;
  3549. // doublecheck that we didnt get a container entry here
  3550. for(j=0;j<ulcPropCount;j++)
  3551. {
  3552. if( lpPropArray[j].ulPropTag == PR_OBJECT_TYPE)
  3553. {
  3554. if(lpPropArray[j].Value.l == MAPI_ABCONT)
  3555. goto endloop;
  3556. break;
  3557. }
  3558. }
  3559. // match!
  3560. CopyMemory(rgsbEntryIDs[ulFoundIndex].lpb, rgsbEntryIDs[i].lpb, rgsbEntryIDs[i].cb);
  3561. ulFoundIndex++;
  3562. endloop:
  3563. if(ulcPropCount && lpPropArray)
  3564. {
  3565. ReadRecordFreePropArray(hPropertyStore, ulcPropCount, &lpPropArray);
  3566. lpPropArray = NULL;
  3567. }
  3568. } // for i
  3569. if(ulFoundIndex)
  3570. {
  3571. *lpulFoundCount = ulFoundIndex;
  3572. *lprgsbEntryIDs = rgsbEntryIDs;
  3573. }
  3574. hr = S_OK;
  3575. out:
  3576. ReadRecordFreePropArray(hPropertyStore, ulcPropCount, &lpPropArray);
  3577. for(i=0;i<ldspMAX;i++)
  3578. {
  3579. if(lppszSubStr[i])
  3580. {
  3581. for(j=0;j<nSubStr[i];j++)
  3582. LocalFree(lppszSubStr[i][j]);
  3583. LocalFree(lppszSubStr[i]);
  3584. }
  3585. }
  3586. if(!*lpulFoundCount || !*lprgsbEntryIDs)
  3587. {
  3588. if(rgsbEntryIDs)
  3589. FreeEntryIDs(hPropertyStore, ulEIDCount, rgsbEntryIDs);
  3590. }
  3591. else if(ulFoundIndex && (ulFoundIndex < ulEIDCount) && !pt_bIsWABOpenExSession)
  3592. {
  3593. // We will leak anything we are not using here so clear up before exiting
  3594. // Do this only if this is a WAB session because then that memory was LocalAlloced
  3595. // and can be partially freed up here
  3596. for(i=ulFoundIndex;i<ulEIDCount;i++)
  3597. {
  3598. if(rgsbEntryIDs[i].lpb)
  3599. LocalFree(rgsbEntryIDs[i].lpb);
  3600. }
  3601. }
  3602. if(!pt_bIsWABOpenExSession)
  3603. {
  3604. if(hMPSWabFile)
  3605. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  3606. }
  3607. if(!pt_bIsWABOpenExSession && bFileLocked)
  3608. UnLockFileAccess(lpMPSWabFileInfo);
  3609. return hr;
  3610. }
  3611. //$$
  3612. //
  3613. // Determines if the disk on which WAB resides has free space or not..
  3614. // Free space is defined as space being equal too or more than the size
  3615. // of the current WAB file. If the available space is less than the size
  3616. // of the WAB file, this function will return false ...
  3617. //
  3618. BOOL WABHasFreeDiskSpace(LPTSTR lpszName, HANDLE hFile)
  3619. {
  3620. TCHAR szBuf[MAX_PATH];
  3621. DWORD dwWABSize=0;
  3622. DWORDLONG dwDiskFreeSpace = 0;
  3623. DWORD SectorsPerCluster=0;
  3624. DWORD BytesPerSector=0;
  3625. DWORD NumberOfFreeClusters=0;
  3626. DWORD TotalNumberOfClusters=0;
  3627. BOOL bRet = TRUE;
  3628. szBuf[0]='\0';
  3629. StrCpyN(szBuf, lpszName, ARRAYSIZE(szBuf));
  3630. TrimSpaces(szBuf);
  3631. if(lstrlen(szBuf))
  3632. {
  3633. dwWABSize = GetFileSize(hFile, NULL);
  3634. {
  3635. LPTSTR lpszFirst = szBuf;
  3636. LPTSTR lpszSecond = CharNext(szBuf);
  3637. LPTSTR lpRoot = NULL;
  3638. LPTSTR lpTemp;
  3639. ULONG ulCount = 0;
  3640. if(*lpszFirst == '\\' && *lpszSecond == '\\')
  3641. {
  3642. // This looks like a network share ..
  3643. // There doesnt seem to be any way to determine disk space
  3644. // on a network share .. so we will try to copy the wab
  3645. // file into a tmp file and delete the tmp file. If this operation
  3646. // succeeds we have plenty of disk space. If it fails we dont have any
  3647. // space
  3648. TCHAR szTmp[MAX_PATH];
  3649. StrCpyN(szTmp, szBuf, ARRAYSIZE(szTmp));
  3650. // our temp file name is the wab file name with a - instead of the last char
  3651. lpTemp = szTmp;
  3652. while(*lpTemp)
  3653. lpTemp = CharNext(lpTemp);
  3654. lpTemp = CharPrev(szTmp, lpTemp);
  3655. if(*lpTemp != '-')
  3656. *lpTemp = '-';
  3657. else
  3658. *lpTemp = '_';
  3659. if(!CopyFile(szBuf, szTmp, FALSE))
  3660. {
  3661. bRet = FALSE;
  3662. }
  3663. else
  3664. DeleteFile(szTmp);
  3665. /***
  3666. lpTemp = CharNext(lpszSecond);
  3667. while(*lpTemp)
  3668. {
  3669. if(*lpTemp == '\\')
  3670. {
  3671. ulCount++;
  3672. if (ulCount == 1)
  3673. {
  3674. //lpTemp=CharNext(lpTemp);
  3675. *lpTemp = '\0';
  3676. break;
  3677. }
  3678. }
  3679. lpTemp = CharNext(lpTemp);
  3680. }
  3681. ***/
  3682. }
  3683. else
  3684. {
  3685. if(*lpszSecond == ':')
  3686. {
  3687. lpTemp = CharNext(lpszSecond);
  3688. if(*lpTemp != '\\')
  3689. *lpTemp = '\0';
  3690. else
  3691. {
  3692. lpTemp = CharNext(lpTemp);
  3693. *lpTemp = '\0';
  3694. }
  3695. }
  3696. else
  3697. {
  3698. *lpszFirst = '\0';
  3699. }
  3700. if(lstrlen(szBuf))
  3701. lpRoot = szBuf;
  3702. if( GetDiskFreeSpace(lpRoot,
  3703. &SectorsPerCluster, // address of sectors per cluster
  3704. &BytesPerSector, // address of bytes per sector
  3705. &NumberOfFreeClusters, // address of number of free clusters
  3706. &TotalNumberOfClusters // address of total number of clusters
  3707. ) )
  3708. {
  3709. dwDiskFreeSpace = BytesPerSector * SectorsPerCluster * NumberOfFreeClusters;
  3710. if(dwDiskFreeSpace < ((DWORDLONG) dwWABSize) )
  3711. bRet = FALSE;
  3712. }
  3713. else
  3714. {
  3715. DebugTrace(TEXT("GetDiskFreeSpace failed: %d\n"),GetLastError());
  3716. }
  3717. }
  3718. }
  3719. }
  3720. return bRet;
  3721. }