Source code of Windows XP (NT5)
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.

441 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. static UINT rgids[2] = { IDS_ERR_1_CorruptDB, IDS_ERR_2_CorruptDB };
  251. ASSERT(pszPath);
  252. // Create the new database name
  253. //
  254. SzFromIDS(IDS_BOGUSDBTEMPLATE, szTemplate, ARRAYSIZE(szTemplate));
  255. PathMakeUniqueName(szNewFile, ARRAYSIZE(szNewFile), TEXT("badbc.dat"), szTemplate,
  256. pszPath);
  257. lstrcpy(pszNewPath, pszPath);
  258. PathAppend(pszNewPath, szNewFile);
  259. // Move the database
  260. //
  261. MoveFile(pszDatPath, pszNewPath);
  262. // Unhide the corrupt database
  263. //
  264. dwAttr = GetFileAttributes(pszNewPath);
  265. if (dwAttr != 0xFFFFFFFF)
  266. {
  267. ClearFlag(dwAttr, FILE_ATTRIBUTE_HIDDEN);
  268. SetFileAttributes(pszNewPath, dwAttr);
  269. }
  270. if (FmtString(&psz, IDS_ERR_F_CorruptDB, rgids, ARRAYSIZE(rgids)))
  271. {
  272. MsgBox(hwndOwner, psz, MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_ERROR);
  273. GFree(psz);
  274. }
  275. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Renaming corrupt database to %s"), pszNewPath); )
  276. // Retry opening...
  277. //
  278. return OpenTheBriefcase(pszDatPath, atomPath, pcbs, hwndOwner);
  279. }
  280. /*----------------------------------------------------------
  281. Purpose: Add the atomPath to the cache. We open the briefcase
  282. database if it needs opening. If atomPath is already
  283. in the cache, simply return the pointer to the entry.
  284. Returns: standard hresult
  285. Cond: Must call CBS_Delete for every call to this function
  286. */
  287. HRESULT PUBLIC CBS_Add(
  288. PCBS * ppcbs,
  289. int atomPath,
  290. HWND hwndOwner)
  291. {
  292. HRESULT hres = NOERROR;
  293. TCHAR szDatPath[MAXPATHLEN];
  294. CBS * pcbs;
  295. CBS_EnterCS();
  296. {
  297. pcbs = Cache_GetPtr(&g_cacheCBS, atomPath);
  298. if (NULL == pcbs)
  299. {
  300. // Allocate using commctrl's Alloc, so the structure will be in
  301. // shared heap space across processes.
  302. pcbs = SharedAllocType(CBS);
  303. if (NULL == pcbs)
  304. {
  305. hres = ResultFromScode(E_OUTOFMEMORY);
  306. }
  307. else
  308. {
  309. LPCTSTR pszPath = Atom_GetName(atomPath);
  310. LPCTSTR pszDBName;
  311. ASSERT(pszPath);
  312. pcbs->atomBrf = atomPath;
  313. pcbs->uFlags = 0;
  314. // Create an abort event object simply so we can programmatically
  315. // cancel a createreclist call in the worker thread. This
  316. // would happen if the user closed the briefcase during
  317. // CreateRecList.
  318. // (it is ok if this fails)
  319. AbortEvt_Create(&pcbs->pabortevt, AEF_SHARED);
  320. DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Opening Briefcase %s..."), pszPath); )
  321. if (IsLFNDrive(pszPath))
  322. {
  323. pszDBName = g_szDBName;
  324. SetFlag(pcbs->uFlags, CBSF_LFNDRIVE);
  325. }
  326. else
  327. pszDBName = g_szDBNameShort;
  328. if (PathsTooLong(pszPath, pszDBName))
  329. {
  330. MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_ERR_OPEN_TOOLONG),
  331. MAKEINTRESOURCE(IDS_CAP_OPEN), NULL, MB_ERROR);
  332. hres = E_FAIL;
  333. }
  334. else
  335. {
  336. PathCombine(szDatPath, pszPath, pszDBName);
  337. hres = OpenTheBriefcase(szDatPath, atomPath, pcbs, hwndOwner);
  338. if (FAILED(hres))
  339. {
  340. DEBUG_CODE( TRACE_MSG(TF_ERROR, TEXT("Open failed. Error is %s"), SzFromTR(GET_TR(hres))); )
  341. SEMsgBox(hwndOwner, IDS_CAP_OPEN, hres, c_rgseOpenBriefcase, ARRAYSIZE(c_rgseOpenBriefcase));
  342. // Is this a corrupt briefcase?
  343. if (E_TR_CORRUPT_BRIEFCASE == hres)
  344. {
  345. // Yes; try to create a new database
  346. hres = HandleCorruptDatabase(pcbs, atomPath, szDatPath, hwndOwner);
  347. }
  348. }
  349. }
  350. }
  351. }
  352. // Did something fail above?
  353. if (FAILED(hres))
  354. {
  355. // Yes; cleanup
  356. if (pcbs)
  357. {
  358. if (pcbs->hbrf)
  359. Sync_CloseBriefcase(pcbs->hbrf);
  360. SharedFree(&pcbs);
  361. }
  362. }
  363. *ppcbs = pcbs;
  364. }
  365. CBS_LeaveCS();
  366. return hres;
  367. }