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.

447 lines
13 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: cbs.c
  6. //
  7. // This files contains code for the cached briefcase structs
  8. //
  9. // History:
  10. // 09-02-93 ScottH Created
  11. // 01-31-94 ScottH Moved from cache.c
  12. //
  13. //---------------------------------------------------------------------------
  14. ///////////////////////////////////////////////////// INCLUDES
  15. #include "brfprv.h" // common headers
  16. #include "res.h"
  17. CACHE g_cacheCBS = {0, 0, 0}; // Briefcase structure cache
  18. #define CBS_EnterCS() EnterCriticalSection(&g_cacheCBS.cs)
  19. #define CBS_LeaveCS() LeaveCriticalSection(&g_cacheCBS.cs)
  20. SETbl const c_rgseOpenBriefcase[] = {
  21. { E_TR_OUT_OF_MEMORY, IDS_OOM_OPENBRIEFCASE, MB_ERROR },
  22. { E_OUTOFMEMORY, IDS_OOM_OPENBRIEFCASE, MB_ERROR },
  23. { E_TR_BRIEFCASE_LOCKED, IDS_ERR_BRIEFCASE_LOCKED, MB_WARNING },
  24. { E_TR_BRIEFCASE_OPEN_FAILED, IDS_ERR_OPEN_ACCESS_DENIED, MB_WARNING },
  25. { E_TR_NEWER_BRIEFCASE, IDS_ERR_NEWER_BRIEFCASE, MB_INFO },
  26. { E_TR_SUBTREE_CYCLE_FOUND, IDS_ERR_OPEN_SUBTREECYCLE, MB_WARNING },
  27. };
  28. #ifdef DEBUG
  29. void PRIVATE CBS_DumpEntry(
  30. CBS * pcbs)
  31. {
  32. ASSERT(pcbs);
  33. TRACE_MSG(TF_ALWAYS, TEXT("CBS: Atom %d: %s"), pcbs->atomBrf, Atom_GetName(pcbs->atomBrf));
  34. TRACE_MSG(TF_ALWAYS, TEXT(" Ref [%u] Hbrf = %lx "),
  35. Cache_GetRefCount(&g_cacheCBS, pcbs->atomBrf),
  36. pcbs->hbrf);
  37. }
  38. void PUBLIC CBS_DumpAll()
  39. {
  40. CBS * pcbs;
  41. int atom;
  42. BOOL bDump;
  43. ENTEREXCLUSIVE();
  44. {
  45. bDump = IsFlagSet(g_uDumpFlags, DF_CBS);
  46. }
  47. LEAVEEXCLUSIVE();
  48. if (!bDump)
  49. return ;
  50. atom = Cache_FindFirstKey(&g_cacheCBS);
  51. while (atom != ATOM_ERR)
  52. {
  53. pcbs = Cache_GetPtr(&g_cacheCBS, atom);
  54. ASSERT(pcbs);
  55. if (pcbs)
  56. {
  57. CBS_DumpEntry(pcbs);
  58. CBS_Delete(atom, NULL); // Decrement count
  59. }
  60. atom = Cache_FindNextKey(&g_cacheCBS, atom);
  61. }
  62. }
  63. #endif
  64. /*----------------------------------------------------------
  65. Purpose: Save and close the briefcase.
  66. Returns: --
  67. Cond:
  68. This function is serialized by the caller (Cache_Term or
  69. Cache_DeleteItem).
  70. */
  71. void CALLBACK CBS_Free(
  72. LPVOID lpv,
  73. HWND hwndOwner)
  74. {
  75. HBRFCASE hbrf;
  76. CBS * pcbs = (CBS *)lpv;
  77. CRL * pcrl;
  78. int atomPath = pcbs->atomBrf;
  79. int atom;
  80. TWINRESULT tr1;
  81. TWINRESULT tr2;
  82. DECLAREHOURGLASS;
  83. hbrf = pcbs->hbrf;
  84. // Save the briefcase with the same name it was opened
  85. //
  86. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Saving and closing Briefcase %s (0x%lx)"),
  87. Atom_GetName(atomPath), hbrf); )
  88. // Search thru the CRL cache for entries
  89. // sharing the same partial path as this briefcase
  90. // and nuke them.
  91. //
  92. atom = Cache_FindFirstKey(&g_cacheCRL);
  93. while (atom != ATOM_ERR)
  94. {
  95. pcrl = Cache_GetPtr(&g_cacheCRL, atom);
  96. ASSERT(pcrl);
  97. if (pcrl)
  98. {
  99. if (hbrf == pcrl->hbrf)
  100. {
  101. // This atomKey belongs to this briefcase. Nuke it.
  102. //
  103. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE Nuking CRL %d"), atom); )
  104. CRL_Nuke(atom);
  105. }
  106. #ifdef DEBUG
  107. else
  108. DEBUG_CODE( TRACE_MSG(TF_CACHE, TEXT("CACHE NOT Nuking CRL %d"), atom); )
  109. #endif
  110. Cache_DeleteItem(&g_cacheCRL, atom, FALSE, hwndOwner, CRL_Free); // Decrement count
  111. }
  112. atom = Cache_FindNextKey(&g_cacheCRL, atom);
  113. }
  114. // Save the briefcase. We normally (re)specify the database
  115. // pathname to handle the rename case. However, if the
  116. // move bit has been set, then we use the NULL parameter
  117. // (save under current name) because we will depend on the
  118. // shell to move the database.
  119. //
  120. ASSERT(Sync_IsEngineLoaded());
  121. // First check if the disk is available. If it isn't, Windows will
  122. // blue-screen because we cannot close the database file. So before
  123. // that happens, bring up a friendlier retry messagebox.
  124. RETRY_BEGIN(FALSE)
  125. {
  126. // Is disk unavailable?
  127. if ( !PathExists(Atom_GetName(atomPath)) )
  128. {
  129. // Yes; ask user to retry/cancel
  130. int id = MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_CLOSE_UNAVAIL_VOL),
  131. MAKEINTRESOURCE(IDS_CAP_SAVE), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  132. if (IDRETRY == id)
  133. RETRY_SET();
  134. }
  135. }
  136. RETRY_END()
  137. SetHourglass();
  138. tr1 = Sync_SaveBriefcase(pcbs->hbrf);
  139. tr2 = Sync_CloseBriefcase(pcbs->hbrf);
  140. if (TR_SUCCESS != tr1 || TR_SUCCESS != tr2)
  141. {
  142. DWORD dwError = GetLastError();
  143. switch (dwError)
  144. {
  145. case ERROR_ACCESS_DENIED:
  146. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_SAVE_UNAVAIL_VOL),
  147. MAKEINTRESOURCE(IDS_CAP_SAVE), NULL, MB_ERROR);
  148. break;
  149. default:
  150. if (TR_BRIEFCASE_WRITE_FAILED == tr1 || TR_BRIEFCASE_WRITE_FAILED == tr2)
  151. {
  152. LPTSTR psz;
  153. static UINT rgids[2] = { IDS_ERR_1_FullDiskSave, IDS_ERR_2_FullDiskSave };
  154. if (FmtString(&psz, IDS_ERR_F_FullDiskSave, rgids, ARRAYSIZE(rgids)))
  155. {
  156. MsgBox(hwndOwner, psz, MAKEINTRESOURCE(IDS_CAP_SAVE), NULL, MB_ERROR);
  157. GFree(psz);
  158. }
  159. }
  160. break;
  161. }
  162. }
  163. ResetHourglass();
  164. AbortEvt_Free(pcbs->pabortevt);
  165. SharedFree(&pcbs);
  166. }
  167. /*----------------------------------------------------------
  168. Purpose: Actually opens the briefcase and adds the briefcase
  169. handle to the given CBS struct.
  170. Returns: standard hresult
  171. Cond: --
  172. */
  173. HRESULT PRIVATE OpenTheBriefcase(
  174. LPCTSTR pszDatPath,
  175. int atomPath,
  176. CBS * pcbs,
  177. HWND hwndOwner)
  178. {
  179. HRESULT hres;
  180. TWINRESULT tr;
  181. BOOL bRet = FALSE;
  182. DWORD dwFlags = OB_FL_OPEN_DATABASE | OB_FL_TRANSLATE_DB_FOLDER | OB_FL_ALLOW_UI;
  183. int nDrive;
  184. int nDriveType;
  185. // Determine if we want to record the existence of this briefcase.
  186. // We don't care about briefcases on remote or floppy drives.
  187. nDrive = PathGetDriveNumber(pszDatPath);
  188. // Record this briefcase?
  189. nDriveType = DriveType(nDrive);
  190. if (DRIVE_CDROM != nDriveType && DRIVE_REMOVABLE != nDriveType &&
  191. DRIVE_RAMDRIVE != nDriveType &&
  192. !PathIsUNC(pszDatPath) && !IsNetDrive(nDrive))
  193. {
  194. // Yes
  195. SetFlag(dwFlags, OB_FL_LIST_DATABASE);
  196. TRACE_MSG(TF_GENERAL, TEXT("Remembering briefcase %s"), pszDatPath);
  197. }
  198. RETRY_BEGIN(FALSE)
  199. {
  200. tr = Sync_OpenBriefcase(pszDatPath, dwFlags, GetDesktopWindow(), &pcbs->hbrf);
  201. hres = HRESULT_FROM_TR(tr);
  202. // Unavailable disk?
  203. if (FAILED(hres))
  204. {
  205. DWORD dwError = GetLastError();
  206. if (ERROR_INVALID_DATA == dwError || ERROR_ACCESS_DENIED == dwError)
  207. {
  208. // Yes; ask user to retry/cancel
  209. int id = MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_OPEN_UNAVAIL_VOL),
  210. MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_RETRYCANCEL | MB_ICONWARNING);
  211. // Set specific error value
  212. hres = E_TR_UNAVAILABLE_VOLUME;
  213. if (IDRETRY == id)
  214. {
  215. RETRY_SET(); // Try again
  216. }
  217. }
  218. }
  219. }
  220. RETRY_END()
  221. if (SUCCEEDED(hres))
  222. {
  223. if (!Cache_AddItem(&g_cacheCBS, atomPath, (LPVOID)pcbs))
  224. {
  225. Sync_CloseBriefcase(pcbs->hbrf);
  226. hres = ResultFromScode(E_OUTOFMEMORY);
  227. }
  228. }
  229. return hres;
  230. }
  231. /*----------------------------------------------------------
  232. Purpose: This function handles the case when the engine fails
  233. to open the database because the database file is
  234. corrupt.
  235. Returns: standard hresult
  236. Cond: --
  237. */
  238. HRESULT PRIVATE HandleCorruptDatabase(
  239. CBS * pcbs,
  240. int atomPath,
  241. LPCTSTR pszDatPath, // Path of database file
  242. HWND hwndOwner)
  243. {
  244. TCHAR szTemplate[MAXPATHLEN];
  245. TCHAR szNewFile[MAXPATHLEN];
  246. LPTSTR pszNewPath = szTemplate;
  247. LPCTSTR pszPath = Atom_GetName(atomPath);
  248. LPTSTR psz;
  249. DWORD dwAttr;
  250. HRESULT hr = E_FAIL;
  251. static UINT rgids[2] = { IDS_ERR_1_CorruptDB, IDS_ERR_2_CorruptDB };
  252. ASSERT(pszPath);
  253. // Create the new database name
  254. //
  255. SzFromIDS(IDS_BOGUSDBTEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  256. if (PathMakeUniqueName(szNewFile, ARRAYSIZE(szNewFile), TEXT("badbc.dat"), szTemplate,
  257. pszPath))
  258. {
  259. lstrcpyn(szTemplate, pszPath, ARRAYSIZE(szTemplate));
  260. if (PathAppend(pszNewPath, szNewFile))
  261. {
  262. // Move the database
  263. //
  264. MoveFile(pszDatPath, pszNewPath);
  265. // Unhide the corrupt database
  266. //
  267. dwAttr = GetFileAttributes(pszNewPath);
  268. if (dwAttr != 0xFFFFFFFF)
  269. {
  270. ClearFlag(dwAttr, FILE_ATTRIBUTE_HIDDEN);
  271. SetFileAttributes(pszNewPath, dwAttr);
  272. }
  273. if (FmtString(&psz, IDS_ERR_F_CorruptDB, rgids, ARRAYSIZE(rgids)))
  274. {
  275. MsgBox(hwndOwner, psz, MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_ERROR);
  276. GFree(psz);
  277. }
  278. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Renaming corrupt database to %s"), pszNewPath); )
  279. // Retry opening...
  280. //
  281. hr = OpenTheBriefcase(pszDatPath, atomPath, pcbs, hwndOwner);
  282. }
  283. }
  284. return hr;
  285. }
  286. /*----------------------------------------------------------
  287. Purpose: Add the atomPath to the cache. We open the briefcase
  288. database if it needs opening. If atomPath is already
  289. in the cache, simply return the pointer to the entry.
  290. Returns: standard hresult
  291. Cond: Must call CBS_Delete for every call to this function
  292. */
  293. HRESULT PUBLIC CBS_Add(
  294. PCBS * ppcbs,
  295. int atomPath,
  296. HWND hwndOwner)
  297. {
  298. HRESULT hres = NOERROR;
  299. TCHAR szDatPath[MAXPATHLEN];
  300. CBS * pcbs;
  301. CBS_EnterCS();
  302. {
  303. pcbs = Cache_GetPtr(&g_cacheCBS, atomPath);
  304. if (NULL == pcbs)
  305. {
  306. // Allocate using commctrl's Alloc, so the structure will be in
  307. // shared heap space across processes.
  308. pcbs = SharedAllocType(CBS);
  309. if (NULL == pcbs)
  310. {
  311. hres = ResultFromScode(E_OUTOFMEMORY);
  312. }
  313. else
  314. {
  315. LPCTSTR pszPath = Atom_GetName(atomPath);
  316. LPCTSTR pszDBName;
  317. ASSERT(pszPath);
  318. pcbs->atomBrf = atomPath;
  319. pcbs->uFlags = 0;
  320. // Create an abort event object simply so we can programmatically
  321. // cancel a createreclist call in the worker thread. This
  322. // would happen if the user closed the briefcase during
  323. // CreateRecList.
  324. // (it is ok if this fails)
  325. AbortEvt_Create(&pcbs->pabortevt, AEF_SHARED);
  326. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Opening Briefcase %s..."), pszPath); )
  327. if (IsLFNDrive(pszPath))
  328. {
  329. pszDBName = g_szDBName;
  330. SetFlag(pcbs->uFlags, CBSF_LFNDRIVE);
  331. }
  332. else
  333. pszDBName = g_szDBNameShort;
  334. if (PathsTooLong(pszPath, pszDBName))
  335. {
  336. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_OPEN_TOOLONG),
  337. MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_ERROR);
  338. hres = E_FAIL;
  339. }
  340. else
  341. {
  342. PathCombine(szDatPath, pszPath, pszDBName);
  343. hres = OpenTheBriefcase(szDatPath, atomPath, pcbs, hwndOwner);
  344. if (FAILED(hres))
  345. {
  346. DEBUG_CODE( TRACE_MSG(TF_ERROR, TEXT("Open failed. Error is %s"), SzFromTR(GET_TR(hres))); )
  347. SEMsgBox(hwndOwner, IDS_CAP_OPEN, hres, c_rgseOpenBriefcase, ARRAYSIZE(c_rgseOpenBriefcase));
  348. // Is this a corrupt briefcase?
  349. if (E_TR_CORRUPT_BRIEFCASE == hres)
  350. {
  351. // Yes; try to create a new database
  352. hres = HandleCorruptDatabase(pcbs, atomPath, szDatPath, hwndOwner);
  353. }
  354. }
  355. }
  356. }
  357. }
  358. // Did something fail above?
  359. if (FAILED(hres))
  360. {
  361. // Yes; cleanup
  362. if (pcbs)
  363. {
  364. if (pcbs->hbrf)
  365. Sync_CloseBriefcase(pcbs->hbrf);
  366. SharedFree(&pcbs);
  367. }
  368. }
  369. *ppcbs = pcbs;
  370. }
  371. CBS_LeaveCS();
  372. return hres;
  373. }