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.

1878 lines
43 KiB

  1. /*
  2. * volume.c - Volume ADT module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "volume.h"
  9. /* Constants
  10. ************/
  11. /* VOLUMELIST PTRARRAY allocation parameters */
  12. #define NUM_START_VOLUMES (16)
  13. #define NUM_VOLUMES_TO_ADD (16)
  14. /* VOLUMELIST string table allocation parameters */
  15. #define NUM_VOLUME_HASH_BUCKETS (31)
  16. /* Types
  17. ********/
  18. /* volume list */
  19. typedef struct _volumelist
  20. {
  21. /* array of pointers to VOLUMEs */
  22. HPTRARRAY hpa;
  23. /* table of volume root path strings */
  24. HSTRINGTABLE hst;
  25. /* flags from RESOLVELINKINFOINFLAGS */
  26. DWORD dwFlags;
  27. /*
  28. * handle to parent window, only valid if RLI_IFL_ALLOW_UI is set in dwFlags
  29. * field
  30. */
  31. HWND hwndOwner;
  32. }
  33. VOLUMELIST;
  34. DECLARE_STANDARD_TYPES(VOLUMELIST);
  35. /* VOLUME flags */
  36. typedef enum _volumeflags
  37. {
  38. /* The volume root path string indicated by hsRootPath is valid. */
  39. VOLUME_FL_ROOT_PATH_VALID = 0x0001,
  40. /*
  41. * The net resource should be disconnected by calling DisconnectLinkInfo()
  42. * when finished.
  43. */
  44. VOLUME_FL_DISCONNECT = 0x0002,
  45. /* Any cached volume information should be verified before use. */
  46. VOLUME_FL_VERIFY_VOLUME = 0x0004,
  47. /* flag combinations */
  48. ALL_VOLUME_FLAGS = (VOLUME_FL_ROOT_PATH_VALID |
  49. VOLUME_FL_DISCONNECT |
  50. VOLUME_FL_VERIFY_VOLUME)
  51. }
  52. VOLUMEFLAGS;
  53. /* VOLUME states */
  54. typedef enum _volumestate
  55. {
  56. VS_UNKNOWN,
  57. VS_AVAILABLE,
  58. VS_UNAVAILABLE
  59. }
  60. VOLUMESTATE;
  61. DECLARE_STANDARD_TYPES(VOLUMESTATE);
  62. /* volume structure */
  63. typedef struct _volume
  64. {
  65. /* reference count */
  66. ULONG ulcLock;
  67. /* bit mask of flags from VOLUMEFLAGS */
  68. DWORD dwFlags;
  69. /* volume state */
  70. VOLUMESTATE vs;
  71. /* pointer to LinkInfo structure indentifying volume */
  72. PLINKINFO pli;
  73. /*
  74. * handle to volume root path string, only valid if
  75. * VOLUME_FL_ROOT_PATH_VALID is set in dwFlags field
  76. */
  77. HSTRING hsRootPath;
  78. /* pointer to parent volume list */
  79. PVOLUMELIST pvlParent;
  80. }
  81. VOLUME;
  82. DECLARE_STANDARD_TYPES(VOLUME);
  83. /* database volume list header */
  84. typedef struct _dbvolumelistheader
  85. {
  86. /* number of volumes in list */
  87. LONG lcVolumes;
  88. /* length of longest LinkInfo structure in volume list in bytes */
  89. UINT ucbMaxLinkInfoLen;
  90. }
  91. DBVOLUMELISTHEADER;
  92. DECLARE_STANDARD_TYPES(DBVOLUMELISTHEADER);
  93. /* database volume structure */
  94. typedef struct _dbvolume
  95. {
  96. /* old handle to volume */
  97. HVOLUME hvol;
  98. /* old LinkInfo structure follows */
  99. /* first DWORD of LinkInfo structure is total size in bytes */
  100. }
  101. DBVOLUME;
  102. DECLARE_STANDARD_TYPES(DBVOLUME);
  103. /***************************** Private Functions *****************************/
  104. /* Module Prototypes
  105. ********************/
  106. PRIVATE_CODE COMPARISONRESULT VolumeSortCmp(PCVOID, PCVOID);
  107. PRIVATE_CODE COMPARISONRESULT VolumeSearchCmp(PCVOID, PCVOID);
  108. PRIVATE_CODE BOOL SearchForVolumeByRootPathCmp(PCVOID, PCVOID);
  109. PRIVATE_CODE BOOL UnifyVolume(PVOLUMELIST, PLINKINFO, PVOLUME *);
  110. PRIVATE_CODE BOOL CreateVolume(PVOLUMELIST, PLINKINFO, PVOLUME *);
  111. PRIVATE_CODE void UnlinkVolume(PCVOLUME);
  112. PRIVATE_CODE BOOL DisconnectVolume(PVOLUME);
  113. PRIVATE_CODE void DestroyVolume(PVOLUME);
  114. PRIVATE_CODE void LockVolume(PVOLUME);
  115. PRIVATE_CODE BOOL UnlockVolume(PVOLUME);
  116. PRIVATE_CODE void InvalidateVolumeInfo(PVOLUME);
  117. PRIVATE_CODE void ClearVolumeInfo(PVOLUME);
  118. PRIVATE_CODE void GetUnavailableVolumeRootPath(PCLINKINFO, LPTSTR, int);
  119. PRIVATE_CODE BOOL VerifyAvailableVolume(PVOLUME);
  120. PRIVATE_CODE void ExpensiveResolveVolumeRootPath(PVOLUME, LPTSTR, int);
  121. PRIVATE_CODE void ResolveVolumeRootPath(PVOLUME, LPTSTR, int);
  122. PRIVATE_CODE VOLUMERESULT VOLUMERESULTFromLastError(VOLUMERESULT);
  123. PRIVATE_CODE TWINRESULT WriteVolume(HCACHEDFILE, PVOLUME);
  124. PRIVATE_CODE TWINRESULT ReadVolume(HCACHEDFILE, PVOLUMELIST, PLINKINFO, UINT, HHANDLETRANS);
  125. #if defined(DEBUG) || defined(VSTF)
  126. PRIVATE_CODE BOOL IsValidPCVOLUMELIST(PCVOLUMELIST);
  127. PRIVATE_CODE BOOL IsValidVOLUMESTATE(VOLUMESTATE);
  128. PRIVATE_CODE BOOL IsValidPCVOLUME(PCVOLUME);
  129. #endif
  130. #ifdef DEBUG
  131. PRIVATE_CODE BOOL IsValidPCVOLUMEDESC(PCVOLUMEDESC);
  132. #endif
  133. /*
  134. ** VolumeSortCmp()
  135. **
  136. **
  137. **
  138. ** Arguments:
  139. **
  140. ** Returns:
  141. **
  142. ** Side Effects: none
  143. **
  144. ** Volumes are sorted by:
  145. ** 1) LinkInfo volume
  146. ** 2) pointer
  147. */
  148. PRIVATE_CODE COMPARISONRESULT VolumeSortCmp(PCVOID pcvol1, PCVOID pcvol2)
  149. {
  150. COMPARISONRESULT cr;
  151. ASSERT(IS_VALID_STRUCT_PTR(pcvol1, CVOLUME));
  152. ASSERT(IS_VALID_STRUCT_PTR(pcvol2, CVOLUME));
  153. cr = CompareLinkInfoVolumes(((PCVOLUME)pcvol1)->pli,
  154. ((PCVOLUME)pcvol2)->pli);
  155. if (cr == CR_EQUAL)
  156. cr = ComparePointers(pcvol1, pcvol1);
  157. return(cr);
  158. }
  159. /*
  160. ** VolumeSearchCmp()
  161. **
  162. **
  163. **
  164. ** Arguments:
  165. **
  166. ** Returns:
  167. **
  168. ** Side Effects: none
  169. **
  170. ** Volumes are searched by:
  171. ** 1) LinkInfo volume
  172. */
  173. PRIVATE_CODE COMPARISONRESULT VolumeSearchCmp(PCVOID pcli, PCVOID pcvol)
  174. {
  175. ASSERT(IS_VALID_STRUCT_PTR(pcli, CLINKINFO));
  176. ASSERT(IS_VALID_STRUCT_PTR(pcvol, CVOLUME));
  177. return(CompareLinkInfoVolumes(pcli, ((PCVOLUME)pcvol)->pli));
  178. }
  179. /*
  180. ** SearchForVolumeByRootPathCmp()
  181. **
  182. **
  183. **
  184. ** Arguments:
  185. **
  186. ** Returns:
  187. **
  188. ** Side Effects: none
  189. **
  190. ** Volumes are searched by:
  191. ** 1) available volume root path
  192. */
  193. PRIVATE_CODE BOOL SearchForVolumeByRootPathCmp(PCVOID pcszFullPath,
  194. PCVOID pcvol)
  195. {
  196. BOOL bDifferent;
  197. ASSERT(IsFullPath(pcszFullPath));
  198. ASSERT(IS_VALID_STRUCT_PTR(pcvol, CVOLUME));
  199. if (((PCVOLUME)pcvol)->vs == VS_AVAILABLE &&
  200. IS_FLAG_SET(((PCVOLUME)pcvol)->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  201. {
  202. LPCTSTR pcszVolumeRootPath;
  203. pcszVolumeRootPath = GetString(((PCVOLUME)pcvol)->hsRootPath);
  204. bDifferent = MyLStrCmpNI(pcszFullPath, pcszVolumeRootPath,
  205. lstrlen(pcszVolumeRootPath));
  206. }
  207. else
  208. bDifferent = TRUE;
  209. return(bDifferent);
  210. }
  211. /*
  212. ** UnifyVolume()
  213. **
  214. **
  215. **
  216. ** Arguments:
  217. **
  218. ** Returns:
  219. **
  220. ** Side Effects: none
  221. */
  222. PRIVATE_CODE BOOL UnifyVolume(PVOLUMELIST pvl, PLINKINFO pliRoot,
  223. PVOLUME *ppvol)
  224. {
  225. BOOL bResult = FALSE;
  226. ASSERT(IS_VALID_STRUCT_PTR(pvl, CVOLUMELIST));
  227. ASSERT(IS_VALID_STRUCT_PTR(pliRoot, CLINKINFO));
  228. ASSERT(IS_VALID_WRITE_PTR(ppvol, PVOLUME));
  229. if (AllocateMemory(sizeof(**ppvol), ppvol))
  230. {
  231. if (CopyLinkInfo(pliRoot, &((*ppvol)->pli)))
  232. {
  233. ARRAYINDEX aiUnused;
  234. (*ppvol)->ulcLock = 0;
  235. (*ppvol)->dwFlags = 0;
  236. (*ppvol)->vs = VS_UNKNOWN;
  237. (*ppvol)->hsRootPath = NULL;
  238. (*ppvol)->pvlParent = pvl;
  239. if (AddPtr(pvl->hpa, VolumeSortCmp, *ppvol, &aiUnused))
  240. bResult = TRUE;
  241. else
  242. {
  243. FreeMemory((*ppvol)->pli);
  244. UNIFYVOLUME_BAIL:
  245. FreeMemory(*ppvol);
  246. }
  247. }
  248. else
  249. goto UNIFYVOLUME_BAIL;
  250. }
  251. ASSERT(! bResult ||
  252. IS_VALID_STRUCT_PTR(*ppvol, CVOLUME));
  253. return(bResult);
  254. }
  255. /*
  256. ** CreateVolume()
  257. **
  258. **
  259. **
  260. ** Arguments:
  261. **
  262. ** Returns:
  263. **
  264. ** Side Effects: none
  265. */
  266. PRIVATE_CODE BOOL CreateVolume(PVOLUMELIST pvl, PLINKINFO pliRoot,
  267. PVOLUME *ppvol)
  268. {
  269. BOOL bResult;
  270. PVOLUME pvol;
  271. ARRAYINDEX aiFound;
  272. ASSERT(IS_VALID_STRUCT_PTR(pvl, CVOLUMELIST));
  273. ASSERT(IS_VALID_STRUCT_PTR(pliRoot, CLINKINFO));
  274. ASSERT(IS_VALID_WRITE_PTR(ppvol, PVOLUME));
  275. /* Does a volume for the given root path already exist? */
  276. if (SearchSortedArray(pvl->hpa, &VolumeSearchCmp, pliRoot, &aiFound))
  277. {
  278. pvol = GetPtr(pvl->hpa, aiFound);
  279. bResult = TRUE;
  280. }
  281. else
  282. bResult = UnifyVolume(pvl, pliRoot, &pvol);
  283. if (bResult)
  284. {
  285. LockVolume(pvol);
  286. *ppvol = pvol;
  287. }
  288. ASSERT(! bResult ||
  289. IS_VALID_STRUCT_PTR(*ppvol, CVOLUME));
  290. return(bResult);
  291. }
  292. /*
  293. ** UnlinkVolume()
  294. **
  295. **
  296. **
  297. ** Arguments:
  298. **
  299. ** Returns:
  300. **
  301. ** Side Effects: none
  302. */
  303. PRIVATE_CODE void UnlinkVolume(PCVOLUME pcvol)
  304. {
  305. HPTRARRAY hpa;
  306. ARRAYINDEX aiFound;
  307. ASSERT(IS_VALID_STRUCT_PTR(pcvol, CVOLUME));
  308. hpa = pcvol->pvlParent->hpa;
  309. if (EVAL(SearchSortedArray(hpa, &VolumeSortCmp, pcvol, &aiFound)))
  310. {
  311. ASSERT(GetPtr(hpa, aiFound) == pcvol);
  312. DeletePtr(hpa, aiFound);
  313. }
  314. return;
  315. }
  316. /*
  317. ** DisconnectVolume()
  318. **
  319. **
  320. **
  321. ** Arguments:
  322. **
  323. ** Returns:
  324. **
  325. ** Side Effects: none
  326. */
  327. PRIVATE_CODE BOOL DisconnectVolume(PVOLUME pvol)
  328. {
  329. BOOL bResult;
  330. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  331. if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_DISCONNECT))
  332. {
  333. bResult = DisconnectLinkInfo(pvol->pli);
  334. CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_DISCONNECT);
  335. }
  336. else
  337. bResult = TRUE;
  338. return(bResult);
  339. }
  340. /*
  341. ** DestroyVolume()
  342. **
  343. **
  344. **
  345. ** Arguments:
  346. **
  347. ** Returns:
  348. **
  349. ** Side Effects: none
  350. */
  351. PRIVATE_CODE void DestroyVolume(PVOLUME pvol)
  352. {
  353. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  354. ClearVolumeInfo(pvol);
  355. FreeMemory(pvol->pli);
  356. FreeMemory(pvol);
  357. return;
  358. }
  359. /*
  360. ** LockVolume()
  361. **
  362. **
  363. **
  364. ** Arguments:
  365. **
  366. ** Returns:
  367. **
  368. ** Side Effects: none
  369. */
  370. PRIVATE_CODE void LockVolume(PVOLUME pvol)
  371. {
  372. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  373. ASSERT(pvol->ulcLock < ULONG_MAX);
  374. pvol->ulcLock++;
  375. return;
  376. }
  377. /*
  378. ** UnlockVolume()
  379. **
  380. **
  381. **
  382. ** Arguments:
  383. **
  384. ** Returns:
  385. **
  386. ** Side Effects: none
  387. */
  388. PRIVATE_CODE BOOL UnlockVolume(PVOLUME pvol)
  389. {
  390. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  391. if (EVAL(pvol->ulcLock > 0))
  392. pvol->ulcLock--;
  393. return(pvol->ulcLock > 0);
  394. }
  395. /*
  396. ** InvalidateVolumeInfo()
  397. **
  398. **
  399. **
  400. ** Arguments:
  401. **
  402. ** Returns:
  403. **
  404. ** Side Effects: none
  405. */
  406. PRIVATE_CODE void InvalidateVolumeInfo(PVOLUME pvol)
  407. {
  408. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  409. SET_FLAG(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME);
  410. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  411. return;
  412. }
  413. /*
  414. ** ClearVolumeInfo()
  415. **
  416. **
  417. **
  418. ** Arguments:
  419. **
  420. ** Returns:
  421. **
  422. ** Side Effects: none
  423. */
  424. PRIVATE_CODE void ClearVolumeInfo(PVOLUME pvol)
  425. {
  426. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  427. DisconnectVolume(pvol);
  428. if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  429. {
  430. DeleteString(pvol->hsRootPath);
  431. CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID);
  432. }
  433. CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME);
  434. pvol->vs = VS_UNKNOWN;
  435. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  436. return;
  437. }
  438. /*
  439. ** GetUnavailableVolumeRootPath()
  440. **
  441. **
  442. **
  443. ** Arguments:
  444. **
  445. ** Returns:
  446. **
  447. ** Side Effects: none
  448. */
  449. PRIVATE_CODE void GetUnavailableVolumeRootPath(PCLINKINFO pcli,
  450. LPTSTR pszRootPathBuf,
  451. int cchMax)
  452. {
  453. LPCSTR pcszLinkInfoData;
  454. ASSERT(IS_VALID_STRUCT_PTR(pcli, CLINKINFO));
  455. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, cchMax));
  456. /*
  457. * Try unavailable volume root paths in the following order:
  458. * 1) last redirected device
  459. * 2) net resource name
  460. * 3) local path ...and take the _last_ good one!
  461. */
  462. if (GetLinkInfoData(pcli, LIDT_REDIRECTED_DEVICE, &pcszLinkInfoData) ||
  463. GetLinkInfoData(pcli, LIDT_NET_RESOURCE, &pcszLinkInfoData) ||
  464. GetLinkInfoData(pcli, LIDT_LOCAL_BASE_PATH, &pcszLinkInfoData))
  465. {
  466. //ASSERT(IS_VALID_STRING_PTR(pcszLinkInfoData, CSTR));
  467. ASSERT(lstrlenA(pcszLinkInfoData) < MAX_PATH_LEN);
  468. // REARCHITECT somewhere, someone might need to handle unicode base paths
  469. #ifdef UNICODE
  470. {
  471. WCHAR szTmp[MAX_PATH] = TEXT("");
  472. MultiByteToWideChar(CP_ACP, 0, pcszLinkInfoData, -1, szTmp, ARRAYSIZE(szTmp));
  473. ComposePath(pszRootPathBuf, szTmp, TEXT("\\"), cchMax);
  474. }
  475. #else
  476. ComposePath(pszRootPathBuf, pcszLinkInfoData, TEXT("\\"), cchMax);
  477. #endif
  478. }
  479. else
  480. {
  481. pszRootPathBuf[0] = TEXT('\0');
  482. ERROR_OUT((TEXT("GetUnavailableVolumeRootPath(): Net resource name and local base path unavailable. Using empty string as unavailable root path.")));
  483. }
  484. ASSERT(IsRootPath(pszRootPathBuf) &&
  485. EVAL(lstrlen(pszRootPathBuf) < MAX_PATH_LEN));
  486. return;
  487. }
  488. /*
  489. ** VerifyAvailableVolume()
  490. **
  491. **
  492. **
  493. ** Arguments:
  494. **
  495. ** Returns:
  496. **
  497. ** Side Effects: none
  498. */
  499. PRIVATE_CODE BOOL VerifyAvailableVolume(PVOLUME pvol)
  500. {
  501. BOOL bResult = FALSE;
  502. PLINKINFO pli;
  503. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  504. ASSERT(pvol->vs == VS_AVAILABLE);
  505. ASSERT(IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID));
  506. WARNING_OUT((TEXT("VerifyAvailableVolume(): Calling CreateLinkInfo() to verify volume on %s."),
  507. GetString(pvol->hsRootPath)));
  508. if (CreateLinkInfo(GetString(pvol->hsRootPath), &pli))
  509. {
  510. bResult = (CompareLinkInfoReferents(pvol->pli, pli) == CR_EQUAL);
  511. DestroyLinkInfo(pli);
  512. if (bResult)
  513. TRACE_OUT((TEXT("VerifyAvailableVolume(): Volume %s has not changed."),
  514. GetString(pvol->hsRootPath)));
  515. else
  516. WARNING_OUT((TEXT("VerifyAvailableVolume(): Volume %s has changed."),
  517. GetString(pvol->hsRootPath)));
  518. }
  519. else
  520. WARNING_OUT((TEXT("VerifyAvailableVolume(): CreateLinkInfo() failed for %s."),
  521. GetString(pvol->hsRootPath)));
  522. return(bResult);
  523. }
  524. /*
  525. ** ExpensiveResolveVolumeRootPath()
  526. **
  527. **
  528. **
  529. ** Arguments:
  530. **
  531. ** Returns:
  532. **
  533. ** Side Effects: none
  534. */
  535. PRIVATE_CODE void ExpensiveResolveVolumeRootPath(PVOLUME pvol,
  536. LPTSTR pszVolumeRootPathBuf,
  537. int cchMax)
  538. {
  539. BOOL bResult;
  540. DWORD dwOutFlags;
  541. PLINKINFO pliUpdated;
  542. HSTRING hsRootPath;
  543. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  544. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszVolumeRootPathBuf, STR, cchMax));
  545. if (pvol->vs == VS_UNKNOWN ||
  546. pvol->vs == VS_AVAILABLE)
  547. {
  548. /*
  549. * Only request a connection if connections are still permitted in this
  550. * volume list.
  551. */
  552. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Calling ResolveLinkInfo() to determine volume availability and root path.")));
  553. bResult = ResolveLinkInfo(pvol->pli, pszVolumeRootPathBuf,
  554. pvol->pvlParent->dwFlags,
  555. pvol->pvlParent->hwndOwner, &dwOutFlags,
  556. &pliUpdated);
  557. if (bResult)
  558. {
  559. pvol->vs = VS_AVAILABLE;
  560. if (IS_FLAG_SET(dwOutFlags, RLI_OFL_UPDATED))
  561. {
  562. PLINKINFO pliUpdatedCopy;
  563. ASSERT(IS_FLAG_SET(pvol->pvlParent->dwFlags, RLI_IFL_UPDATE));
  564. if (CopyLinkInfo(pliUpdated, &pliUpdatedCopy))
  565. {
  566. FreeMemory(pvol->pli);
  567. pvol->pli = pliUpdatedCopy;
  568. }
  569. DestroyLinkInfo(pliUpdated);
  570. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Updating LinkInfo for volume %s."),
  571. pszVolumeRootPathBuf));
  572. }
  573. if (IS_FLAG_SET(dwOutFlags, RLI_OFL_DISCONNECT))
  574. {
  575. SET_FLAG(pvol->dwFlags, VOLUME_FL_DISCONNECT);
  576. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Volume %s must be disconnected when finished."),
  577. pszVolumeRootPathBuf));
  578. }
  579. TRACE_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Volume %s is available."),
  580. pszVolumeRootPathBuf));
  581. }
  582. else
  583. ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  584. }
  585. else
  586. {
  587. ASSERT(pvol->vs == VS_UNAVAILABLE);
  588. bResult = FALSE;
  589. }
  590. if (! bResult)
  591. {
  592. pvol->vs = VS_UNAVAILABLE;
  593. if (GetLastError() == ERROR_CANCELLED)
  594. {
  595. ASSERT(IS_FLAG_SET(pvol->pvlParent->dwFlags, RLI_IFL_CONNECT));
  596. CLEAR_FLAG(pvol->pvlParent->dwFlags, RLI_IFL_CONNECT);
  597. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Connection attempt cancelled. No subsequent connections will be attempted.")));
  598. }
  599. GetUnavailableVolumeRootPath(pvol->pli, pszVolumeRootPathBuf, cchMax);
  600. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Using %s as unavailable volume root path."),
  601. pszVolumeRootPathBuf));
  602. }
  603. /* Add volume root path string to volume list's string table. */
  604. if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  605. {
  606. CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID);
  607. DeleteString(pvol->hsRootPath);
  608. }
  609. if (AddString(pszVolumeRootPathBuf, pvol->pvlParent->hst, GetHashBucketIndex, &hsRootPath))
  610. {
  611. SET_FLAG(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID);
  612. pvol->hsRootPath = hsRootPath;
  613. }
  614. else
  615. WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Unable to save %s as volume root path."),
  616. pszVolumeRootPathBuf));
  617. return;
  618. }
  619. /*
  620. ** ResolveVolumeRootPath()
  621. **
  622. **
  623. **
  624. ** Arguments:
  625. **
  626. ** Returns:
  627. **
  628. ** Side Effects: none
  629. */
  630. PRIVATE_CODE void ResolveVolumeRootPath(PVOLUME pvol,
  631. LPTSTR pszVolumeRootPathBuf,
  632. int cchMax)
  633. {
  634. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  635. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszVolumeRootPathBuf, STR, MAX_PATH_LEN));
  636. /* Do we have a cached volume root path to use? */
  637. if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID) &&
  638. (IS_FLAG_CLEAR(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME) ||
  639. (pvol->vs == VS_AVAILABLE &&
  640. VerifyAvailableVolume(pvol))))
  641. {
  642. /* Yes. */
  643. MyLStrCpyN(pszVolumeRootPathBuf, GetString(pvol->hsRootPath), cchMax);
  644. ASSERT(lstrlen(pszVolumeRootPathBuf) < MAX_PATH_LEN);
  645. ASSERT(pvol->vs != VS_UNKNOWN);
  646. }
  647. else
  648. /* No. Welcome in I/O City. */
  649. ExpensiveResolveVolumeRootPath(pvol, pszVolumeRootPathBuf, cchMax);
  650. CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME);
  651. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  652. return;
  653. }
  654. /*
  655. ** VOLUMERESULTFromLastError()
  656. **
  657. **
  658. **
  659. ** Arguments:
  660. **
  661. ** Returns:
  662. **
  663. ** Side Effects: none
  664. */
  665. PRIVATE_CODE VOLUMERESULT VOLUMERESULTFromLastError(VOLUMERESULT vr)
  666. {
  667. switch (GetLastError())
  668. {
  669. case ERROR_OUTOFMEMORY:
  670. vr = VR_OUT_OF_MEMORY;
  671. break;
  672. case ERROR_BAD_PATHNAME:
  673. vr = VR_INVALID_PATH;
  674. break;
  675. default:
  676. break;
  677. }
  678. return(vr);
  679. }
  680. /*
  681. ** WriteVolume()
  682. **
  683. **
  684. **
  685. ** Arguments:
  686. **
  687. ** Returns:
  688. **
  689. ** Side Effects: none
  690. */
  691. PRIVATE_CODE TWINRESULT WriteVolume(HCACHEDFILE hcf, PVOLUME pvol)
  692. {
  693. TWINRESULT tr;
  694. DBVOLUME dbvol;
  695. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  696. ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  697. /* Write database volume followed by LinkInfo structure. */
  698. dbvol.hvol = (HVOLUME)pvol;
  699. if (WriteToCachedFile(hcf, (PCVOID)&dbvol, sizeof(dbvol), NULL) &&
  700. WriteToCachedFile(hcf, pvol->pli, *(PDWORD)(pvol->pli), NULL))
  701. tr = TR_SUCCESS;
  702. else
  703. tr = TR_BRIEFCASE_WRITE_FAILED;
  704. return(tr);
  705. }
  706. /*
  707. ** ReadVolume()
  708. **
  709. **
  710. **
  711. ** Arguments:
  712. **
  713. ** Returns:
  714. **
  715. ** Side Effects: none
  716. */
  717. PRIVATE_CODE TWINRESULT ReadVolume(HCACHEDFILE hcf, PVOLUMELIST pvl,
  718. PLINKINFO pliBuf, UINT ucbLinkInfoBufLen,
  719. HHANDLETRANS hhtVolumes)
  720. {
  721. TWINRESULT tr = TR_CORRUPT_BRIEFCASE;
  722. DBVOLUME dbvol;
  723. DWORD dwcbRead;
  724. UINT ucbLinkInfoLen;
  725. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  726. ASSERT(IS_VALID_STRUCT_PTR(pvl, CVOLUMELIST));
  727. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pliBuf, LINKINFO, ucbLinkInfoBufLen));
  728. ASSERT(IS_VALID_HANDLE(hhtVolumes, HANDLETRANS));
  729. if (ReadFromCachedFile(hcf, &dbvol, sizeof(dbvol), &dwcbRead) &&
  730. dwcbRead == sizeof(dbvol) &&
  731. ReadFromCachedFile(hcf, &ucbLinkInfoLen, sizeof(ucbLinkInfoLen), &dwcbRead) &&
  732. dwcbRead == sizeof(ucbLinkInfoLen) &&
  733. ucbLinkInfoLen <= ucbLinkInfoBufLen)
  734. {
  735. /* Read the remainder of the LinkInfo structure into memory. */
  736. DWORD dwcbRemainder;
  737. pliBuf->ucbSize = ucbLinkInfoLen;
  738. dwcbRemainder = ucbLinkInfoLen - sizeof(ucbLinkInfoLen);
  739. if (ReadFromCachedFile(hcf, (PBYTE)pliBuf + sizeof(ucbLinkInfoLen),
  740. dwcbRemainder, &dwcbRead) &&
  741. dwcbRead == dwcbRemainder &&
  742. IsValidLinkInfo(pliBuf))
  743. {
  744. PVOLUME pvol;
  745. if (CreateVolume(pvl, pliBuf, &pvol))
  746. {
  747. /*
  748. * To leave read volumes with 0 initial lock count, we must undo
  749. * the LockVolume() performed by CreateVolume().
  750. */
  751. UnlockVolume(pvol);
  752. if (AddHandleToHandleTranslator(hhtVolumes,
  753. (HGENERIC)(dbvol.hvol),
  754. (HGENERIC)pvol))
  755. tr = TR_SUCCESS;
  756. else
  757. {
  758. UnlinkVolume(pvol);
  759. DestroyVolume(pvol);
  760. tr = TR_OUT_OF_MEMORY;
  761. }
  762. }
  763. else
  764. tr = TR_OUT_OF_MEMORY;
  765. }
  766. }
  767. return(tr);
  768. }
  769. #if defined(DEBUG) || defined(VSTF)
  770. /*
  771. ** IsValidPCVOLUMELIST()
  772. **
  773. **
  774. **
  775. ** Arguments:
  776. **
  777. ** Returns:
  778. **
  779. ** Side Effects: none
  780. */
  781. PRIVATE_CODE BOOL IsValidPCVOLUMELIST(PCVOLUMELIST pcvl)
  782. {
  783. return(IS_VALID_READ_PTR(pcvl, CVOLUMELIST) &&
  784. IS_VALID_HANDLE(pcvl->hpa, PTRARRAY) &&
  785. IS_VALID_HANDLE(pcvl->hst, STRINGTABLE) &&
  786. FLAGS_ARE_VALID(pcvl->dwFlags, ALL_RLI_IFLAGS) &&
  787. (IS_FLAG_CLEAR(pcvl->dwFlags, RLI_IFL_ALLOW_UI) ||
  788. IS_VALID_HANDLE(pcvl->hwndOwner, WND)));
  789. }
  790. /*
  791. ** IsValidVOLUMESTATE()
  792. **
  793. **
  794. **
  795. ** Arguments:
  796. **
  797. ** Returns:
  798. **
  799. ** Side Effects: none
  800. */
  801. PRIVATE_CODE BOOL IsValidVOLUMESTATE(VOLUMESTATE vs)
  802. {
  803. BOOL bResult;
  804. switch (vs)
  805. {
  806. case VS_UNKNOWN:
  807. case VS_AVAILABLE:
  808. case VS_UNAVAILABLE:
  809. bResult = TRUE;
  810. break;
  811. default:
  812. ERROR_OUT((TEXT("IsValidVOLUMESTATE(): Invalid VOLUMESTATE %d."),
  813. vs));
  814. bResult = FALSE;
  815. break;
  816. }
  817. return(bResult);
  818. }
  819. /*
  820. ** IsValidPCVOLUME()
  821. **
  822. **
  823. **
  824. ** Arguments:
  825. **
  826. ** Returns:
  827. **
  828. ** Side Effects: none
  829. */
  830. PRIVATE_CODE BOOL IsValidPCVOLUME(PCVOLUME pcvol)
  831. {
  832. return(IS_VALID_READ_PTR(pcvol, CVOLUME) &&
  833. FLAGS_ARE_VALID(pcvol->dwFlags, ALL_VOLUME_FLAGS) &&
  834. EVAL(IsValidVOLUMESTATE(pcvol->vs)) &&
  835. IS_VALID_STRUCT_PTR(pcvol->pli, CLINKINFO) &&
  836. (IS_FLAG_CLEAR(pcvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID) ||
  837. IS_VALID_HANDLE(pcvol->hsRootPath, STRING)) &&
  838. IS_VALID_STRUCT_PTR(pcvol->pvlParent, CVOLUMELIST));
  839. }
  840. #endif
  841. #ifdef DEBUG
  842. /*
  843. ** IsValidPCVOLUMEDESC()
  844. **
  845. **
  846. **
  847. ** Arguments:
  848. **
  849. ** Returns:
  850. **
  851. ** Side Effects: none
  852. */
  853. PRIVATE_CODE BOOL IsValidPCVOLUMEDESC(PCVOLUMEDESC pcvoldesc)
  854. {
  855. /*
  856. * A set dwSerialNumber may be any value. An unset dwSerialNumber must be
  857. * 0. A set strings may be any valid string. An unset string must be the
  858. * empty string.
  859. */
  860. return(IS_VALID_READ_PTR(pcvoldesc, CVOLUMEDESC) &&
  861. EVAL(pcvoldesc->ulSize == sizeof(*pcvoldesc)) &&
  862. FLAGS_ARE_VALID(pcvoldesc->dwFlags, ALL_VD_FLAGS) &&
  863. (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_SERIAL_NUMBER_VALID) ||
  864. ! pcvoldesc->dwSerialNumber) &&
  865. ((IS_FLAG_CLEAR(pcvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID) &&
  866. ! pcvoldesc->rgchVolumeLabel[0]) ||
  867. (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID) &&
  868. IS_VALID_STRING_PTR(pcvoldesc->rgchVolumeLabel, CSTR) &&
  869. EVAL(lstrlen(pcvoldesc->rgchVolumeLabel) < ARRAYSIZE(pcvoldesc->rgchVolumeLabel)))) &&
  870. ((IS_FLAG_CLEAR(pcvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID) &&
  871. ! pcvoldesc->rgchNetResource[0]) ||
  872. (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID) &&
  873. IS_VALID_STRING_PTR(pcvoldesc->rgchNetResource, CSTR) &&
  874. EVAL(lstrlen(pcvoldesc->rgchNetResource) < ARRAYSIZE(pcvoldesc->rgchNetResource)))));
  875. }
  876. #endif
  877. /****************************** Public Functions *****************************/
  878. /*
  879. ** CreateVolumeList()
  880. **
  881. **
  882. **
  883. ** Arguments:
  884. **
  885. ** Returns:
  886. **
  887. ** Side Effects: none
  888. */
  889. PUBLIC_CODE BOOL CreateVolumeList(DWORD dwFlags, HWND hwndOwner,
  890. PHVOLUMELIST phvl)
  891. {
  892. BOOL bResult = FALSE;
  893. PVOLUMELIST pvl;
  894. ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_RLI_IFLAGS));
  895. ASSERT(IS_FLAG_CLEAR(dwFlags, RLI_IFL_ALLOW_UI) ||
  896. IS_VALID_HANDLE(hwndOwner, WND));
  897. ASSERT(IS_VALID_WRITE_PTR(phvl, HVOLUMELIST));
  898. if (AllocateMemory(sizeof(*pvl), &pvl))
  899. {
  900. NEWSTRINGTABLE nszt;
  901. /* Create string table for volume root path strngs. */
  902. nszt.hbc = NUM_VOLUME_HASH_BUCKETS;
  903. if (CreateStringTable(&nszt, &(pvl->hst)))
  904. {
  905. NEWPTRARRAY npa;
  906. /* Create pointer array of volumes. */
  907. npa.aicInitialPtrs = NUM_START_VOLUMES;
  908. npa.aicAllocGranularity = NUM_VOLUMES_TO_ADD;
  909. npa.dwFlags = NPA_FL_SORTED_ADD;
  910. if (CreatePtrArray(&npa, &(pvl->hpa)))
  911. {
  912. pvl->dwFlags = dwFlags;
  913. pvl->hwndOwner = hwndOwner;
  914. *phvl = (HVOLUMELIST)pvl;
  915. bResult = TRUE;
  916. }
  917. else
  918. {
  919. DestroyStringTable(pvl->hst);
  920. CREATEVOLUMELIST_BAIL:
  921. FreeMemory(pvl);
  922. }
  923. }
  924. else
  925. goto CREATEVOLUMELIST_BAIL;
  926. }
  927. ASSERT(! bResult ||
  928. IS_VALID_HANDLE(*phvl, VOLUMELIST));
  929. return(bResult);
  930. }
  931. /*
  932. ** DestroyVolumeList()
  933. **
  934. **
  935. **
  936. ** Arguments:
  937. **
  938. ** Returns:
  939. **
  940. ** Side Effects: none
  941. */
  942. PUBLIC_CODE void DestroyVolumeList(HVOLUMELIST hvl)
  943. {
  944. ARRAYINDEX aicPtrs;
  945. ARRAYINDEX ai;
  946. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  947. /* First free all volumes in array. */
  948. aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  949. for (ai = 0; ai < aicPtrs; ai++)
  950. DestroyVolume(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  951. /* Now wipe out the array. */
  952. DestroyPtrArray(((PCVOLUMELIST)hvl)->hpa);
  953. ASSERT(! GetStringCount(((PCVOLUMELIST)hvl)->hst));
  954. DestroyStringTable(((PCVOLUMELIST)hvl)->hst);
  955. FreeMemory((PVOLUMELIST)hvl);
  956. return;
  957. }
  958. /*
  959. ** InvalidateVolumeListInfo()
  960. **
  961. **
  962. **
  963. ** Arguments:
  964. **
  965. ** Returns:
  966. **
  967. ** Side Effects: none
  968. */
  969. PUBLIC_CODE void InvalidateVolumeListInfo(HVOLUMELIST hvl)
  970. {
  971. ARRAYINDEX aicPtrs;
  972. ARRAYINDEX ai;
  973. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  974. aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  975. for (ai = 0; ai < aicPtrs; ai++)
  976. InvalidateVolumeInfo(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  977. WARNING_OUT((TEXT("InvalidateVolumeListInfo(): Volume cache invalidated.")));
  978. return;
  979. }
  980. /*
  981. ** ClearVolumeListInfo()
  982. **
  983. **
  984. **
  985. ** Arguments:
  986. **
  987. ** Returns:
  988. **
  989. ** Side Effects: none
  990. */
  991. PUBLIC_CODE void ClearVolumeListInfo(HVOLUMELIST hvl)
  992. {
  993. ARRAYINDEX aicPtrs;
  994. ARRAYINDEX ai;
  995. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  996. aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  997. for (ai = 0; ai < aicPtrs; ai++)
  998. ClearVolumeInfo(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  999. WARNING_OUT((TEXT("ClearVolumeListInfo(): Volume cache cleared.")));
  1000. return;
  1001. }
  1002. /*
  1003. ** AddVolume()
  1004. **
  1005. **
  1006. **
  1007. ** Arguments:
  1008. **
  1009. ** Returns:
  1010. **
  1011. ** Side Effects: none
  1012. */
  1013. PUBLIC_CODE VOLUMERESULT AddVolume(HVOLUMELIST hvl, LPCTSTR pcszPath,
  1014. PHVOLUME phvol, LPTSTR pszPathSuffixBuf,
  1015. int cchMax)
  1016. {
  1017. VOLUMERESULT vr;
  1018. TCHAR rgchPath[MAX_PATH_LEN];
  1019. LPTSTR pszFileName;
  1020. DWORD dwPathLen;
  1021. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1022. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  1023. ASSERT(IS_VALID_WRITE_PTR(phvol, HVOLUME));
  1024. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPathSuffixBuf, STR, cchMax));
  1025. dwPathLen = GetFullPathName(pcszPath, ARRAYSIZE(rgchPath), rgchPath,
  1026. &pszFileName);
  1027. if (dwPathLen > 0 && dwPathLen < ARRAYSIZE(rgchPath))
  1028. {
  1029. ARRAYINDEX aiFound;
  1030. /* Does a volume for this root path already exist? */
  1031. if (LinearSearchArray(((PVOLUMELIST)hvl)->hpa,
  1032. &SearchForVolumeByRootPathCmp, rgchPath,
  1033. &aiFound))
  1034. {
  1035. PVOLUME pvol;
  1036. LPCTSTR pcszVolumeRootPath;
  1037. /* Yes. */
  1038. pvol = GetPtr(((PVOLUMELIST)hvl)->hpa, aiFound);
  1039. LockVolume(pvol);
  1040. ASSERT(pvol->vs == VS_AVAILABLE &&
  1041. IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID));
  1042. pcszVolumeRootPath = GetString(pvol->hsRootPath);
  1043. ASSERT(lstrlen(pcszVolumeRootPath) <= lstrlen(rgchPath));
  1044. lstrcpyn(pszPathSuffixBuf, rgchPath + lstrlen(pcszVolumeRootPath), cchMax);
  1045. *phvol = (HVOLUME)pvol;
  1046. vr = VR_SUCCESS;
  1047. }
  1048. else
  1049. {
  1050. DWORD dwOutFlags;
  1051. TCHAR rgchNetResource[MAX_PATH_LEN];
  1052. LPTSTR pszRootPathSuffix;
  1053. /* No. Create a new volume. */
  1054. if (GetCanonicalPathInfo(pcszPath, rgchPath, &dwOutFlags,
  1055. rgchNetResource, &pszRootPathSuffix))
  1056. {
  1057. PLINKINFO pli;
  1058. lstrcpyn(pszPathSuffixBuf, pszRootPathSuffix, cchMax);
  1059. *pszRootPathSuffix = TEXT('\0');
  1060. WARNING_OUT((TEXT("AddVolume(): Creating LinkInfo for root path %s."),
  1061. rgchPath));
  1062. if (CreateLinkInfo(rgchPath, &pli))
  1063. {
  1064. PVOLUME pvol;
  1065. if (CreateVolume((PVOLUMELIST)hvl, pli, &pvol))
  1066. {
  1067. TCHAR rgchUnusedVolumeRootPath[MAX_PATH_LEN];
  1068. ResolveVolumeRootPath(pvol, rgchUnusedVolumeRootPath, ARRAYSIZE(rgchUnusedVolumeRootPath));
  1069. *phvol = (HVOLUME)pvol;
  1070. vr = VR_SUCCESS;
  1071. }
  1072. else
  1073. vr = VR_OUT_OF_MEMORY;
  1074. DestroyLinkInfo(pli);
  1075. }
  1076. else
  1077. /*
  1078. * Differentiate between VR_UNAVAILABLE_VOLUME and
  1079. * VR_OUT_OF_MEMORY.
  1080. */
  1081. vr = VOLUMERESULTFromLastError(VR_UNAVAILABLE_VOLUME);
  1082. }
  1083. else
  1084. vr = VOLUMERESULTFromLastError(VR_INVALID_PATH);
  1085. }
  1086. }
  1087. else
  1088. {
  1089. ASSERT(! dwPathLen);
  1090. vr = VOLUMERESULTFromLastError(VR_INVALID_PATH);
  1091. }
  1092. ASSERT(vr != VR_SUCCESS ||
  1093. (IS_VALID_HANDLE(*phvol, VOLUME) &&
  1094. EVAL(IsValidPathSuffix(pszPathSuffixBuf))));
  1095. return(vr);
  1096. }
  1097. /*
  1098. ** DeleteVolume()
  1099. **
  1100. **
  1101. **
  1102. ** Arguments:
  1103. **
  1104. ** Returns:
  1105. **
  1106. ** Side Effects: none
  1107. */
  1108. PUBLIC_CODE void DeleteVolume(HVOLUME hvol)
  1109. {
  1110. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1111. if (! UnlockVolume((PVOLUME)hvol))
  1112. {
  1113. UnlinkVolume((PVOLUME)hvol);
  1114. DestroyVolume((PVOLUME)hvol);
  1115. }
  1116. return;
  1117. }
  1118. /*
  1119. ** CompareVolumes()
  1120. **
  1121. **
  1122. **
  1123. ** Arguments:
  1124. **
  1125. ** Returns:
  1126. **
  1127. ** Side Effects: none
  1128. */
  1129. PUBLIC_CODE COMPARISONRESULT CompareVolumes(HVOLUME hvolFirst,
  1130. HVOLUME hvolSecond)
  1131. {
  1132. ASSERT(IS_VALID_HANDLE(hvolFirst, VOLUME));
  1133. ASSERT(IS_VALID_HANDLE(hvolSecond, VOLUME));
  1134. /* This comparison works across volume lists. */
  1135. return(CompareLinkInfoVolumes(((PCVOLUME)hvolFirst)->pli,
  1136. ((PCVOLUME)hvolSecond)->pli));
  1137. }
  1138. /*
  1139. ** CopyVolume()
  1140. **
  1141. **
  1142. **
  1143. ** Arguments:
  1144. **
  1145. ** Returns:
  1146. **
  1147. ** Side Effects: none
  1148. */
  1149. PUBLIC_CODE BOOL CopyVolume(HVOLUME hvolSrc, HVOLUMELIST hvlDest,
  1150. PHVOLUME phvolCopy)
  1151. {
  1152. BOOL bResult;
  1153. PVOLUME pvol;
  1154. ASSERT(IS_VALID_HANDLE(hvolSrc, VOLUME));
  1155. ASSERT(IS_VALID_HANDLE(hvlDest, VOLUMELIST));
  1156. ASSERT(IS_VALID_WRITE_PTR(phvolCopy, HVOLUME));
  1157. /* Is the destination volume list the source volume's volume list? */
  1158. if (((PCVOLUME)hvolSrc)->pvlParent == (PCVOLUMELIST)hvlDest)
  1159. {
  1160. /* Yes. Use the source volume. */
  1161. LockVolume((PVOLUME)hvolSrc);
  1162. pvol = (PVOLUME)hvolSrc;
  1163. bResult = TRUE;
  1164. }
  1165. else
  1166. bResult = CreateVolume((PVOLUMELIST)hvlDest, ((PCVOLUME)hvolSrc)->pli,
  1167. &pvol);
  1168. if (bResult)
  1169. *phvolCopy = (HVOLUME)pvol;
  1170. ASSERT(! bResult ||
  1171. IS_VALID_HANDLE(*phvolCopy, VOLUME));
  1172. return(bResult);
  1173. }
  1174. /*
  1175. ** IsVolumeAvailable()
  1176. **
  1177. **
  1178. **
  1179. ** Arguments:
  1180. **
  1181. ** Returns:
  1182. **
  1183. ** Side Effects: none
  1184. */
  1185. PUBLIC_CODE BOOL IsVolumeAvailable(HVOLUME hvol)
  1186. {
  1187. TCHAR rgchUnusedVolumeRootPath[MAX_PATH_LEN];
  1188. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1189. ResolveVolumeRootPath((PVOLUME)hvol, rgchUnusedVolumeRootPath, ARRAYSIZE(rgchUnusedVolumeRootPath));
  1190. ASSERT(IsValidVOLUMESTATE(((PCVOLUME)hvol)->vs) &&
  1191. ((PCVOLUME)hvol)->vs != VS_UNKNOWN);
  1192. return(((PCVOLUME)hvol)->vs == VS_AVAILABLE);
  1193. }
  1194. /*
  1195. ** GetVolumeRootPath()
  1196. **
  1197. **
  1198. **
  1199. ** Arguments:
  1200. **
  1201. ** Returns:
  1202. **
  1203. ** Side Effects: none
  1204. */
  1205. PUBLIC_CODE void GetVolumeRootPath(HVOLUME hvol, LPTSTR pszRootPathBuf, int cchMax)
  1206. {
  1207. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1208. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, cchMax));
  1209. ResolveVolumeRootPath((PVOLUME)hvol, pszRootPathBuf, cchMax);
  1210. ASSERT(IsRootPath(pszRootPathBuf));
  1211. return;
  1212. }
  1213. #ifdef DEBUG
  1214. /*
  1215. ** DebugGetVolumeRootPath()
  1216. **
  1217. **
  1218. **
  1219. ** Arguments:
  1220. **
  1221. ** Returns:
  1222. **
  1223. ** Side Effects: none
  1224. **
  1225. ** N.b., DebugGetVolumeRootPath() must be non-intrusive.
  1226. */
  1227. PUBLIC_CODE LPTSTR DebugGetVolumeRootPath(HVOLUME hvol, LPTSTR pszRootPathBuf, int cchMax)
  1228. {
  1229. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1230. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, cchMax));
  1231. if (IS_FLAG_SET(((PVOLUME)hvol)->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  1232. MyLStrCpyN(pszRootPathBuf, GetString(((PVOLUME)hvol)->hsRootPath), cchMax);
  1233. else
  1234. GetUnavailableVolumeRootPath(((PVOLUME)hvol)->pli, pszRootPathBuf, cchMax);
  1235. ASSERT(IsRootPath(pszRootPathBuf));
  1236. return(pszRootPathBuf);
  1237. }
  1238. /*
  1239. ** GetVolumeCount()
  1240. **
  1241. **
  1242. **
  1243. ** Arguments:
  1244. **
  1245. ** Returns:
  1246. **
  1247. ** Side Effects: none
  1248. */
  1249. PUBLIC_CODE ULONG GetVolumeCount(HVOLUMELIST hvl)
  1250. {
  1251. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1252. return(GetPtrCount(((PCVOLUMELIST)hvl)->hpa));
  1253. }
  1254. #endif
  1255. /*
  1256. ** DescribeVolume()
  1257. **
  1258. **
  1259. **
  1260. ** Arguments:
  1261. **
  1262. ** Returns:
  1263. **
  1264. ** Side Effects: none
  1265. */
  1266. PUBLIC_CODE void DescribeVolume(HVOLUME hvol, PVOLUMEDESC pvoldesc)
  1267. {
  1268. PCVOID pcv;
  1269. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1270. ASSERT(IS_VALID_WRITE_PTR(pvoldesc, VOLUMEDESC));
  1271. ASSERT(pvoldesc->ulSize == sizeof(*pvoldesc));
  1272. pvoldesc->dwFlags = 0;
  1273. if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_SERIAL_NUMBER, &pcv))
  1274. {
  1275. pvoldesc->dwSerialNumber = *(PCDWORD)pcv;
  1276. SET_FLAG(pvoldesc->dwFlags, VD_FL_SERIAL_NUMBER_VALID);
  1277. }
  1278. else
  1279. pvoldesc->dwSerialNumber = 0;
  1280. if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_LABELW, &pcv) && pcv)
  1281. {
  1282. lstrcpyn(pvoldesc->rgchVolumeLabel, pcv, ARRAYSIZE(pvoldesc->rgchVolumeLabel));
  1283. SET_FLAG(pvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID);
  1284. }
  1285. else if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_LABEL, &pcv) && pcv)
  1286. {
  1287. MultiByteToWideChar(CP_ACP, 0, pcv, -1, pvoldesc->rgchVolumeLabel, ARRAYSIZE(pvoldesc->rgchVolumeLabel));
  1288. SET_FLAG(pvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID);
  1289. }
  1290. else
  1291. {
  1292. pvoldesc->rgchVolumeLabel[0] = TEXT('\0');
  1293. }
  1294. if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_NET_RESOURCEW, &pcv) && pcv)
  1295. {
  1296. lstrcpyn(pvoldesc->rgchNetResource, pcv, ARRAYSIZE(pvoldesc->rgchNetResource));
  1297. SET_FLAG(pvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID);
  1298. }
  1299. else if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_NET_RESOURCE, &pcv) && pcv)
  1300. {
  1301. MultiByteToWideChar(CP_ACP, 0, pcv, -1, pvoldesc->rgchNetResource, ARRAYSIZE(pvoldesc->rgchNetResource));
  1302. SET_FLAG(pvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID);
  1303. }
  1304. else
  1305. pvoldesc->rgchNetResource[0] = TEXT('\0');
  1306. ASSERT(IS_VALID_STRUCT_PTR(pvoldesc, CVOLUMEDESC));
  1307. return;
  1308. }
  1309. /*
  1310. ** WriteVolumeList()
  1311. **
  1312. **
  1313. **
  1314. ** Arguments:
  1315. **
  1316. ** Returns:
  1317. **
  1318. ** Side Effects: none
  1319. */
  1320. PUBLIC_CODE TWINRESULT WriteVolumeList(HCACHEDFILE hcf, HVOLUMELIST hvl)
  1321. {
  1322. TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
  1323. DWORD dwcbDBVolumeListHeaderOffset;
  1324. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1325. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1326. /* Save initial file position. */
  1327. dwcbDBVolumeListHeaderOffset = GetCachedFilePointerPosition(hcf);
  1328. if (dwcbDBVolumeListHeaderOffset != INVALID_SEEK_POSITION)
  1329. {
  1330. DBVOLUMELISTHEADER dbvlh;
  1331. /* Leave space for volume list header. */
  1332. ZeroMemory(&dbvlh, sizeof(dbvlh));
  1333. if (WriteToCachedFile(hcf, (PCVOID)&dbvlh, sizeof(dbvlh), NULL))
  1334. {
  1335. ARRAYINDEX aicPtrs;
  1336. ARRAYINDEX ai;
  1337. UINT ucbMaxLinkInfoLen = 0;
  1338. LONG lcVolumes = 0;
  1339. tr = TR_SUCCESS;
  1340. aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  1341. /* Write all volumes. */
  1342. for (ai = 0; ai < aicPtrs; ai++)
  1343. {
  1344. PVOLUME pvol;
  1345. pvol = GetPtr(((PCVOLUMELIST)hvl)->hpa, ai);
  1346. /*
  1347. * As a sanity check, don't save any volume with a lock count of 0.
  1348. * A 0 lock count implies that the volume has not been referenced
  1349. * since it was restored from the database, or something is broken.
  1350. */
  1351. if (pvol->ulcLock > 0)
  1352. {
  1353. tr = WriteVolume(hcf, pvol);
  1354. if (tr == TR_SUCCESS)
  1355. {
  1356. ASSERT(lcVolumes < LONG_MAX);
  1357. lcVolumes++;
  1358. if (pvol->pli->ucbSize > ucbMaxLinkInfoLen)
  1359. ucbMaxLinkInfoLen = pvol->pli->ucbSize;
  1360. }
  1361. else
  1362. break;
  1363. }
  1364. else
  1365. ERROR_OUT((TEXT("WriteVolumeList(): VOLUME has 0 lock count and will not be written.")));
  1366. }
  1367. /* Save volume list header. */
  1368. if (tr == TR_SUCCESS)
  1369. {
  1370. dbvlh.lcVolumes = lcVolumes;
  1371. dbvlh.ucbMaxLinkInfoLen = ucbMaxLinkInfoLen;
  1372. tr = WriteDBSegmentHeader(hcf, dwcbDBVolumeListHeaderOffset,
  1373. &dbvlh, sizeof(dbvlh));
  1374. TRACE_OUT((TEXT("WriteVolumeList(): Wrote %ld volumes; maximum LinkInfo length %u bytes."),
  1375. dbvlh.lcVolumes,
  1376. dbvlh.ucbMaxLinkInfoLen));
  1377. }
  1378. }
  1379. }
  1380. return(tr);
  1381. }
  1382. /*
  1383. ** ReadVolumeList()
  1384. **
  1385. **
  1386. **
  1387. ** Arguments:
  1388. **
  1389. ** Returns:
  1390. **
  1391. ** Side Effects: none
  1392. */
  1393. PUBLIC_CODE TWINRESULT ReadVolumeList(HCACHEDFILE hcf, HVOLUMELIST hvl,
  1394. PHHANDLETRANS phht)
  1395. {
  1396. TWINRESULT tr;
  1397. DBVOLUMELISTHEADER dbvlh;
  1398. DWORD dwcbRead;
  1399. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1400. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1401. ASSERT(IS_VALID_WRITE_PTR(phht, HHANDLETRANS));
  1402. if (ReadFromCachedFile(hcf, &dbvlh, sizeof(dbvlh), &dwcbRead) &&
  1403. dwcbRead == sizeof(dbvlh))
  1404. {
  1405. HHANDLETRANS hht;
  1406. tr = TR_OUT_OF_MEMORY;
  1407. if (CreateHandleTranslator(dbvlh.lcVolumes, &hht))
  1408. {
  1409. PLINKINFO pliBuf;
  1410. if (AllocateMemory(dbvlh.ucbMaxLinkInfoLen, &pliBuf))
  1411. {
  1412. LONG l;
  1413. tr = TR_SUCCESS;
  1414. TRACE_OUT((TEXT("ReadPathList(): Reading %ld volumes; maximum LinkInfo length %u bytes."),
  1415. dbvlh.lcVolumes,
  1416. dbvlh.ucbMaxLinkInfoLen));
  1417. for (l = 0; l < dbvlh.lcVolumes; l++)
  1418. {
  1419. tr = ReadVolume(hcf, (PVOLUMELIST)hvl, pliBuf,
  1420. dbvlh.ucbMaxLinkInfoLen, hht);
  1421. if (tr != TR_SUCCESS)
  1422. {
  1423. break;
  1424. }
  1425. }
  1426. if (tr == TR_SUCCESS)
  1427. {
  1428. PrepareForHandleTranslation(hht);
  1429. *phht = hht;
  1430. ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1431. ASSERT(IS_VALID_HANDLE(*phht, HANDLETRANS));
  1432. }
  1433. FreeMemory(pliBuf);
  1434. }
  1435. if (tr != TR_SUCCESS)
  1436. {
  1437. DestroyHandleTranslator(hht);
  1438. hht = NULL;
  1439. }
  1440. }
  1441. }
  1442. else
  1443. {
  1444. tr = TR_CORRUPT_BRIEFCASE;
  1445. }
  1446. ASSERT(tr != TR_SUCCESS ||
  1447. (IS_VALID_HANDLE(hvl, VOLUMELIST) &&
  1448. IS_VALID_HANDLE(*phht, HANDLETRANS)));
  1449. return(tr);
  1450. }
  1451. /*
  1452. ** IsValidHVOLUME()
  1453. **
  1454. **
  1455. **
  1456. ** Arguments:
  1457. **
  1458. ** Returns:
  1459. **
  1460. ** Side Effects: none
  1461. */
  1462. PUBLIC_CODE BOOL IsValidHVOLUME(HVOLUME hvol)
  1463. {
  1464. return(IS_VALID_STRUCT_PTR((PCVOLUME)hvol, CVOLUME));
  1465. }
  1466. #if defined(DEBUG) || defined(VSTF)
  1467. /*
  1468. ** IsValidHVOLUMELIST()
  1469. **
  1470. **
  1471. **
  1472. ** Arguments:
  1473. **
  1474. ** Returns:
  1475. **
  1476. ** Side Effects: none
  1477. */
  1478. PUBLIC_CODE BOOL IsValidHVOLUMELIST(HVOLUMELIST hvl)
  1479. {
  1480. return(IS_VALID_STRUCT_PTR((PCVOLUMELIST)hvl, CVOLUMELIST));
  1481. }
  1482. #endif