volume.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 41k
Category:

Windows Kernel

Development Platform:

Visual C++

  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);
  119. PRIVATE_CODE BOOL VerifyAvailableVolume(PVOLUME);
  120. PRIVATE_CODE void ExpensiveResolveVolumeRootPath(PVOLUME, LPTSTR);
  121. PRIVATE_CODE void ResolveVolumeRootPath(PVOLUME, LPTSTR);
  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. {
  452.    LPCSTR pcszLinkInfoData;
  453.    ASSERT(IS_VALID_STRUCT_PTR(pcli, CLINKINFO));
  454.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
  455.    /*
  456.     * Try unavailable volume root paths in the following order:
  457.     *    1) last redirected device
  458.     *    2) net resource name
  459.     *    3) local path           ...and take the _last_ good one!
  460.     */
  461.    if (GetLinkInfoData(pcli, LIDT_REDIRECTED_DEVICE, &pcszLinkInfoData) ||
  462.        GetLinkInfoData(pcli, LIDT_NET_RESOURCE, &pcszLinkInfoData) ||
  463.        GetLinkInfoData(pcli, LIDT_LOCAL_BASE_PATH, &pcszLinkInfoData))
  464.    {
  465.       //ASSERT(IS_VALID_STRING_PTR(pcszLinkInfoData, CSTR));
  466.       ASSERT(lstrlenA(pcszLinkInfoData) < MAX_PATH_LEN);
  467.       // BUGBUG somewhere, someone might need to handle unicode base paths 
  468. #ifdef UNICODE
  469.       {
  470.         TCHAR szTmp[MAX_PATH] = TEXT("");
  471.         MultiByteToWideChar(CP_ACP, 0, pcszLinkInfoData, -1, szTmp, MAX_PATH);
  472.         ComposePath(pszRootPathBuf, szTmp, TEXT("\"));
  473.       }
  474. #else
  475.       ComposePath(pszRootPathBuf, pcszLinkInfoData, TEXT("\"));
  476. #endif
  477.    }
  478.    else
  479.    {
  480.       pszRootPathBuf[0] = TEXT('');
  481.       ERROR_OUT((TEXT("GetUnavailableVolumeRootPath(): Net resource name and local base path unavailable.  Using empty string as unavailable root path.")));
  482.    }
  483.    ASSERT(IsRootPath(pszRootPathBuf) &&
  484.           EVAL(lstrlen(pszRootPathBuf) < MAX_PATH_LEN));
  485.    return;
  486. }
  487. /*
  488. ** VerifyAvailableVolume()
  489. **
  490. **
  491. **
  492. ** Arguments:
  493. **
  494. ** Returns:
  495. **
  496. ** Side Effects:  none
  497. */
  498. PRIVATE_CODE BOOL VerifyAvailableVolume(PVOLUME pvol)
  499. {
  500.    BOOL bResult = FALSE;
  501.    PLINKINFO pli;
  502.    ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  503.    ASSERT(pvol->vs == VS_AVAILABLE);
  504.    ASSERT(IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID));
  505.    WARNING_OUT((TEXT("VerifyAvailableVolume(): Calling CreateLinkInfo() to verify volume on %s."),
  506.                 GetString(pvol->hsRootPath)));
  507.    if (CreateLinkInfo(GetString(pvol->hsRootPath), &pli))
  508.    {
  509.       bResult = (CompareLinkInfoReferents(pvol->pli, pli) == CR_EQUAL);
  510.       DestroyLinkInfo(pli);
  511.       if (bResult)
  512.          TRACE_OUT((TEXT("VerifyAvailableVolume(): Volume %s has not changed."),
  513.                     GetString(pvol->hsRootPath)));
  514.       else
  515.          WARNING_OUT((TEXT("VerifyAvailableVolume(): Volume %s has changed."),
  516.                       GetString(pvol->hsRootPath)));
  517.    }
  518.    else
  519.       WARNING_OUT((TEXT("VerifyAvailableVolume(): CreateLinkInfo() failed for %s."),
  520.                    GetString(pvol->hsRootPath)));
  521.    return(bResult);
  522. }
  523. /*
  524. ** ExpensiveResolveVolumeRootPath()
  525. **
  526. **
  527. **
  528. ** Arguments:
  529. **
  530. ** Returns:
  531. **
  532. ** Side Effects:  none
  533. */
  534. PRIVATE_CODE void ExpensiveResolveVolumeRootPath(PVOLUME pvol,
  535.                                                  LPTSTR pszVolumeRootPathBuf)
  536. {
  537.    BOOL bResult;
  538.    DWORD dwOutFlags;
  539.    PLINKINFO pliUpdated;
  540.    HSTRING hsRootPath;
  541.    ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  542.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszVolumeRootPathBuf, STR, MAX_PATH_LEN));
  543.    if (pvol->vs == VS_UNKNOWN ||
  544.        pvol->vs == VS_AVAILABLE)
  545.    {
  546.       /*
  547.        * Only request a connection if connections are still permitted in this
  548.        * volume list.
  549.        */
  550.       WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Calling ResolveLinkInfo() to determine volume availability and root path.")));
  551.       bResult = ResolveLinkInfo(pvol->pli, pszVolumeRootPathBuf,
  552.                                 pvol->pvlParent->dwFlags,
  553.                                 pvol->pvlParent->hwndOwner, &dwOutFlags,
  554.                                 &pliUpdated);
  555.       if (bResult)
  556.       {
  557.          pvol->vs = VS_AVAILABLE;
  558.          if (IS_FLAG_SET(dwOutFlags, RLI_OFL_UPDATED))
  559.          {
  560.             PLINKINFO pliUpdatedCopy;
  561.             ASSERT(IS_FLAG_SET(pvol->pvlParent->dwFlags, RLI_IFL_UPDATE));
  562.             if (CopyLinkInfo(pliUpdated, &pliUpdatedCopy))
  563.             {
  564.                FreeMemory(pvol->pli);
  565.                pvol->pli = pliUpdatedCopy;
  566.             }
  567.             DestroyLinkInfo(pliUpdated);
  568.             WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Updating LinkInfo for volume %s."),
  569.                          pszVolumeRootPathBuf));
  570.          }
  571.          if (IS_FLAG_SET(dwOutFlags, RLI_OFL_DISCONNECT))
  572.          {
  573.             SET_FLAG(pvol->dwFlags, VOLUME_FL_DISCONNECT);
  574.             WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Volume %s must be disconnected when finished."),
  575.                          pszVolumeRootPathBuf));
  576.          }
  577.          TRACE_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Volume %s is available."),
  578.                     pszVolumeRootPathBuf));
  579.       }
  580.       else
  581.          ASSERT(GetLastError() != ERROR_INVALID_PARAMETER);
  582.    }
  583.    else
  584.    {
  585.       ASSERT(pvol->vs == VS_UNAVAILABLE);
  586.       bResult = FALSE;
  587.    }
  588.    if (! bResult)
  589.    {
  590.       pvol->vs = VS_UNAVAILABLE;
  591.       if (GetLastError() == ERROR_CANCELLED)
  592.       {
  593.          ASSERT(IS_FLAG_SET(pvol->pvlParent->dwFlags, RLI_IFL_CONNECT));
  594.          CLEAR_FLAG(pvol->pvlParent->dwFlags, RLI_IFL_CONNECT);
  595.          WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Connection attempt cancelled.  No subsequent connections will be attempted.")));
  596.       }
  597.       GetUnavailableVolumeRootPath(pvol->pli, pszVolumeRootPathBuf);
  598.       WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Using %s as unavailable volume root path."),
  599.                    pszVolumeRootPathBuf));
  600.    }
  601.    /* Add volume root path string to volume list's string table. */
  602.    if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  603.    {
  604.       CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID);
  605.       DeleteString(pvol->hsRootPath);
  606.    }
  607.    if (AddString(pszVolumeRootPathBuf, pvol->pvlParent->hst, GetHashBucketIndex, &hsRootPath))
  608.    {
  609.       SET_FLAG(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID);
  610.       pvol->hsRootPath = hsRootPath;
  611.    }
  612.    else
  613.       WARNING_OUT((TEXT("ExpensiveResolveVolumeRootPath(): Unable to save %s as volume root path."),
  614.                    pszVolumeRootPathBuf));
  615.    return;
  616. }
  617. /*
  618. ** ResolveVolumeRootPath()
  619. **
  620. **
  621. **
  622. ** Arguments:
  623. **
  624. ** Returns:
  625. **
  626. ** Side Effects:  none
  627. */
  628. PRIVATE_CODE void ResolveVolumeRootPath(PVOLUME pvol,
  629.                                         LPTSTR pszVolumeRootPathBuf)
  630. {
  631.    ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  632.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszVolumeRootPathBuf, STR, MAX_PATH_LEN));
  633.    /* Do we have a cached volume root path to use? */
  634.    if (IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID) &&
  635.        (IS_FLAG_CLEAR(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME) ||
  636.         (pvol->vs == VS_AVAILABLE &&
  637.          VerifyAvailableVolume(pvol))))
  638.    {
  639.       /* Yes. */
  640.       MyLStrCpyN(pszVolumeRootPathBuf, GetString(pvol->hsRootPath), MAX_PATH_LEN);
  641.       ASSERT(lstrlen(pszVolumeRootPathBuf) < MAX_PATH_LEN);
  642.       ASSERT(pvol->vs != VS_UNKNOWN);
  643.    }
  644.    else
  645.       /* No.  Welcome in I/O City. */
  646.       ExpensiveResolveVolumeRootPath(pvol, pszVolumeRootPathBuf);
  647.    CLEAR_FLAG(pvol->dwFlags, VOLUME_FL_VERIFY_VOLUME);
  648.    ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  649.    return;
  650. }
  651. /*
  652. ** VOLUMERESULTFromLastError()
  653. **
  654. **
  655. **
  656. ** Arguments:
  657. **
  658. ** Returns:
  659. **
  660. ** Side Effects:  none
  661. */
  662. PRIVATE_CODE VOLUMERESULT VOLUMERESULTFromLastError(VOLUMERESULT vr)
  663. {
  664.    switch (GetLastError())
  665.    {
  666.       case ERROR_OUTOFMEMORY:
  667.          vr = VR_OUT_OF_MEMORY;
  668.          break;
  669.       case ERROR_BAD_PATHNAME:
  670.          vr = VR_INVALID_PATH;
  671.          break;
  672.       default:
  673.          break;
  674.    }
  675.    return(vr);
  676. }
  677. /*
  678. ** WriteVolume()
  679. **
  680. **
  681. **
  682. ** Arguments:
  683. **
  684. ** Returns:
  685. **
  686. ** Side Effects:  none
  687. */
  688. PRIVATE_CODE TWINRESULT WriteVolume(HCACHEDFILE hcf, PVOLUME pvol)
  689. {
  690.    TWINRESULT tr;
  691.    DBVOLUME dbvol;
  692.    ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  693.    ASSERT(IS_VALID_STRUCT_PTR(pvol, CVOLUME));
  694.    /* Write database volume followed by LinkInfo structure. */
  695.    dbvol.hvol = (HVOLUME)pvol;
  696.    if (WriteToCachedFile(hcf, (PCVOID)&dbvol, sizeof(dbvol), NULL) &&
  697.        WriteToCachedFile(hcf, pvol->pli, *(PDWORD)(pvol->pli), NULL))
  698.       tr = TR_SUCCESS;
  699.    else
  700.       tr = TR_BRIEFCASE_WRITE_FAILED;
  701.    return(tr);
  702. }
  703. /*
  704. ** ReadVolume()
  705. **
  706. **
  707. **
  708. ** Arguments:
  709. **
  710. ** Returns:
  711. **
  712. ** Side Effects:  none
  713. */
  714. PRIVATE_CODE TWINRESULT ReadVolume(HCACHEDFILE hcf, PVOLUMELIST pvl,
  715.                                    PLINKINFO pliBuf, UINT ucbLinkInfoBufLen,
  716.                                    HHANDLETRANS hhtVolumes)
  717. {
  718.    TWINRESULT tr = TR_CORRUPT_BRIEFCASE;
  719.    DBVOLUME dbvol;
  720.    DWORD dwcbRead;
  721.    UINT ucbLinkInfoLen;
  722.    ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  723.    ASSERT(IS_VALID_STRUCT_PTR(pvl, CVOLUMELIST));
  724.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pliBuf, LINKINFO, ucbLinkInfoBufLen));
  725.    ASSERT(IS_VALID_HANDLE(hhtVolumes, HANDLETRANS));
  726.    if (ReadFromCachedFile(hcf, &dbvol, sizeof(dbvol), &dwcbRead) &&
  727.        dwcbRead == sizeof(dbvol) &&
  728.        ReadFromCachedFile(hcf, &ucbLinkInfoLen, sizeof(ucbLinkInfoLen), &dwcbRead) &&
  729.        dwcbRead == sizeof(ucbLinkInfoLen) &&
  730.        ucbLinkInfoLen <= ucbLinkInfoBufLen)
  731.    {
  732.       /* Read the remainder of the LinkInfo structure into memory. */
  733.       DWORD dwcbRemainder;
  734.       pliBuf->ucbSize = ucbLinkInfoLen;
  735.       dwcbRemainder = ucbLinkInfoLen - sizeof(ucbLinkInfoLen);
  736.       if (ReadFromCachedFile(hcf, (PBYTE)pliBuf + sizeof(ucbLinkInfoLen),
  737.                              dwcbRemainder, &dwcbRead) &&
  738.           dwcbRead == dwcbRemainder &&
  739.           IsValidLinkInfo(pliBuf))
  740.       {
  741.          PVOLUME pvol;
  742.          if (CreateVolume(pvl, pliBuf, &pvol))
  743.          {
  744.             /*
  745.              * To leave read volumes with 0 initial lock count, we must undo
  746.              * the LockVolume() performed by CreateVolume().
  747.              */
  748.             UnlockVolume(pvol);
  749.             if (AddHandleToHandleTranslator(hhtVolumes,
  750.                                             (HGENERIC)(dbvol.hvol),
  751.                                             (HGENERIC)pvol))
  752.                tr = TR_SUCCESS;
  753.             else
  754.             {
  755.                UnlinkVolume(pvol);
  756.                DestroyVolume(pvol);
  757.                tr = TR_OUT_OF_MEMORY;
  758.             }
  759.          }
  760.          else
  761.             tr = TR_OUT_OF_MEMORY;
  762.       }
  763.    }
  764.    return(tr);
  765. }
  766. #if defined(DEBUG) || defined(VSTF)
  767. /*
  768. ** IsValidPCVOLUMELIST()
  769. **
  770. **
  771. **
  772. ** Arguments:
  773. **
  774. ** Returns:
  775. **
  776. ** Side Effects:  none
  777. */
  778. PRIVATE_CODE BOOL IsValidPCVOLUMELIST(PCVOLUMELIST pcvl)
  779. {
  780.    return(IS_VALID_READ_PTR(pcvl, CVOLUMELIST) &&
  781.           IS_VALID_HANDLE(pcvl->hpa, PTRARRAY) &&
  782.           IS_VALID_HANDLE(pcvl->hst, STRINGTABLE) &&
  783.           FLAGS_ARE_VALID(pcvl->dwFlags, ALL_RLI_IFLAGS) &&
  784.           (IS_FLAG_CLEAR(pcvl->dwFlags, RLI_IFL_ALLOW_UI) ||
  785.            IS_VALID_HANDLE(pcvl->hwndOwner, WND)));
  786. }
  787. /*
  788. ** IsValidVOLUMESTATE()
  789. **
  790. **
  791. **
  792. ** Arguments:
  793. **
  794. ** Returns:
  795. **
  796. ** Side Effects:  none
  797. */
  798. PRIVATE_CODE BOOL IsValidVOLUMESTATE(VOLUMESTATE vs)
  799. {
  800.    BOOL bResult;
  801.    switch (vs)
  802.    {
  803.       case VS_UNKNOWN:
  804.       case VS_AVAILABLE:
  805.       case VS_UNAVAILABLE:
  806.          bResult = TRUE;
  807.          break;
  808.       default:
  809.          ERROR_OUT((TEXT("IsValidVOLUMESTATE(): Invalid VOLUMESTATE %d."),
  810.                     vs));
  811.          bResult = FALSE;
  812.          break;
  813.    }
  814.    return(bResult);
  815. }
  816. /*
  817. ** IsValidPCVOLUME()
  818. **
  819. **
  820. **
  821. ** Arguments:
  822. **
  823. ** Returns:
  824. **
  825. ** Side Effects:  none
  826. */
  827. PRIVATE_CODE BOOL IsValidPCVOLUME(PCVOLUME pcvol)
  828. {
  829.    return(IS_VALID_READ_PTR(pcvol, CVOLUME) &&
  830.           FLAGS_ARE_VALID(pcvol->dwFlags, ALL_VOLUME_FLAGS) &&
  831.           EVAL(IsValidVOLUMESTATE(pcvol->vs)) &&
  832.           IS_VALID_STRUCT_PTR(pcvol->pli, CLINKINFO) &&
  833.           (IS_FLAG_CLEAR(pcvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID) ||
  834.            IS_VALID_HANDLE(pcvol->hsRootPath, STRING)) &&
  835.           IS_VALID_STRUCT_PTR(pcvol->pvlParent, CVOLUMELIST));
  836. }
  837. #endif
  838. #ifdef DEBUG
  839. /*
  840. ** IsValidPCVOLUMEDESC()
  841. **
  842. **
  843. **
  844. ** Arguments:
  845. **
  846. ** Returns:
  847. **
  848. ** Side Effects:  none
  849. */
  850. PRIVATE_CODE BOOL IsValidPCVOLUMEDESC(PCVOLUMEDESC pcvoldesc)
  851. {
  852.    /*
  853.     * A set dwSerialNumber may be any value.  An unset dwSerialNumber must be
  854.     * 0.  A set strings may be any valid string.  An unset string must be the
  855.     * empty string.
  856.     */
  857.    return(IS_VALID_READ_PTR(pcvoldesc, CVOLUMEDESC) &&
  858.           EVAL(pcvoldesc->ulSize == sizeof(*pcvoldesc)) &&
  859.           FLAGS_ARE_VALID(pcvoldesc->dwFlags, ALL_VD_FLAGS) &&
  860.           (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_SERIAL_NUMBER_VALID) ||
  861.            ! pcvoldesc->dwSerialNumber) &&
  862.           ((IS_FLAG_CLEAR(pcvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID) &&
  863.             ! pcvoldesc->rgchVolumeLabel[0]) ||
  864.            (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID) &&
  865.             IS_VALID_STRING_PTR(pcvoldesc->rgchVolumeLabel, CSTR) &&
  866.             EVAL(lstrlen(pcvoldesc->rgchVolumeLabel) < ARRAYSIZE(pcvoldesc->rgchVolumeLabel)))) &&
  867.           ((IS_FLAG_CLEAR(pcvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID) &&
  868.             ! pcvoldesc->rgchNetResource[0]) ||
  869.            (IS_FLAG_SET(pcvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID) &&
  870.             IS_VALID_STRING_PTR(pcvoldesc->rgchNetResource, CSTR) &&
  871.             EVAL(lstrlen(pcvoldesc->rgchNetResource) < ARRAYSIZE(pcvoldesc->rgchNetResource)))));
  872. }
  873. #endif
  874. /****************************** Public Functions *****************************/
  875. /*
  876. ** CreateVolumeList()
  877. **
  878. **
  879. **
  880. ** Arguments:
  881. **
  882. ** Returns:
  883. **
  884. ** Side Effects:  none
  885. */
  886. PUBLIC_CODE BOOL CreateVolumeList(DWORD dwFlags, HWND hwndOwner,
  887.                                   PHVOLUMELIST phvl)
  888. {
  889.    BOOL bResult = FALSE;
  890.    PVOLUMELIST pvl;
  891.    ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_RLI_IFLAGS));
  892.    ASSERT(IS_FLAG_CLEAR(dwFlags, RLI_IFL_ALLOW_UI) ||
  893.           IS_VALID_HANDLE(hwndOwner, WND));
  894.    ASSERT(IS_VALID_WRITE_PTR(phvl, HVOLUMELIST));
  895.    if (AllocateMemory(sizeof(*pvl), &pvl))
  896.    {
  897.       NEWSTRINGTABLE nszt;
  898.       /* Create string table for volume root path strngs. */
  899.       nszt.hbc = NUM_VOLUME_HASH_BUCKETS;
  900.       if (CreateStringTable(&nszt, &(pvl->hst)))
  901.       {
  902.          NEWPTRARRAY npa;
  903.          /* Create pointer array of volumes. */
  904.          npa.aicInitialPtrs = NUM_START_VOLUMES;
  905.          npa.aicAllocGranularity = NUM_VOLUMES_TO_ADD;
  906.          npa.dwFlags = NPA_FL_SORTED_ADD;
  907.          if (CreatePtrArray(&npa, &(pvl->hpa)))
  908.          {
  909.             pvl->dwFlags = dwFlags;
  910.             pvl->hwndOwner = hwndOwner;
  911.             *phvl = (HVOLUMELIST)pvl;
  912.             bResult = TRUE;
  913.          }
  914.          else
  915.          {
  916.             DestroyStringTable(pvl->hst);
  917. CREATEVOLUMELIST_BAIL:
  918.             FreeMemory(pvl);
  919.          }
  920.       }
  921.       else
  922.          goto CREATEVOLUMELIST_BAIL;
  923.    }
  924.    ASSERT(! bResult ||
  925.           IS_VALID_HANDLE(*phvl, VOLUMELIST));
  926.    return(bResult);
  927. }
  928. /*
  929. ** DestroyVolumeList()
  930. **
  931. **
  932. **
  933. ** Arguments:
  934. **
  935. ** Returns:
  936. **
  937. ** Side Effects:  none
  938. */
  939. PUBLIC_CODE void DestroyVolumeList(HVOLUMELIST hvl)
  940. {
  941.    ARRAYINDEX aicPtrs;
  942.    ARRAYINDEX ai;
  943.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  944.    /* First free all volumes in array. */
  945.    aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  946.    for (ai = 0; ai < aicPtrs; ai++)
  947.       DestroyVolume(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  948.    /* Now wipe out the array. */
  949.    DestroyPtrArray(((PCVOLUMELIST)hvl)->hpa);
  950.    ASSERT(! GetStringCount(((PCVOLUMELIST)hvl)->hst));
  951.    DestroyStringTable(((PCVOLUMELIST)hvl)->hst);
  952.    FreeMemory((PVOLUMELIST)hvl);
  953.    return;
  954. }
  955. /*
  956. ** InvalidateVolumeListInfo()
  957. **
  958. **
  959. **
  960. ** Arguments:
  961. **
  962. ** Returns:
  963. **
  964. ** Side Effects:  none
  965. */
  966. PUBLIC_CODE void InvalidateVolumeListInfo(HVOLUMELIST hvl)
  967. {
  968.    ARRAYINDEX aicPtrs;
  969.    ARRAYINDEX ai;
  970.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  971.    aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  972.    for (ai = 0; ai < aicPtrs; ai++)
  973.       InvalidateVolumeInfo(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  974.    WARNING_OUT((TEXT("InvalidateVolumeListInfo(): Volume cache invalidated.")));
  975.    return;
  976. }
  977. /*
  978. ** ClearVolumeListInfo()
  979. **
  980. **
  981. **
  982. ** Arguments:
  983. **
  984. ** Returns:
  985. **
  986. ** Side Effects:  none
  987. */
  988. PUBLIC_CODE void ClearVolumeListInfo(HVOLUMELIST hvl)
  989. {
  990.    ARRAYINDEX aicPtrs;
  991.    ARRAYINDEX ai;
  992.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  993.    aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  994.    for (ai = 0; ai < aicPtrs; ai++)
  995.       ClearVolumeInfo(GetPtr(((PCVOLUMELIST)hvl)->hpa, ai));
  996.    WARNING_OUT((TEXT("ClearVolumeListInfo(): Volume cache cleared.")));
  997.    return;
  998. }
  999. /*
  1000. ** AddVolume()
  1001. **
  1002. **
  1003. **
  1004. ** Arguments:
  1005. **
  1006. ** Returns:
  1007. **
  1008. ** Side Effects:  none
  1009. */
  1010. PUBLIC_CODE VOLUMERESULT AddVolume(HVOLUMELIST hvl, LPCTSTR pcszPath,
  1011.                                    PHVOLUME phvol, LPTSTR pszPathSuffixBuf)
  1012. {
  1013.    VOLUMERESULT vr;
  1014.    TCHAR rgchPath[MAX_PATH_LEN];
  1015.    LPTSTR pszFileName;
  1016.    DWORD dwPathLen;
  1017.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1018.    ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  1019.    ASSERT(IS_VALID_WRITE_PTR(phvol, HVOLUME));
  1020.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPathSuffixBuf, STR, MAX_PATH_LEN));
  1021.    dwPathLen = GetFullPathName(pcszPath, ARRAYSIZE(rgchPath), rgchPath,
  1022.                                &pszFileName);
  1023.    if (dwPathLen > 0 && dwPathLen < ARRAYSIZE(rgchPath))
  1024.    {
  1025.       ARRAYINDEX aiFound;
  1026.       /* Does a volume for this root path already exist? */
  1027.       if (LinearSearchArray(((PVOLUMELIST)hvl)->hpa,
  1028.                             &SearchForVolumeByRootPathCmp, rgchPath,
  1029.                             &aiFound))
  1030.       {
  1031.          PVOLUME pvol;
  1032.          LPCTSTR pcszVolumeRootPath;
  1033.          /* Yes. */
  1034.          pvol = GetPtr(((PVOLUMELIST)hvl)->hpa, aiFound);
  1035.          LockVolume(pvol);
  1036.          ASSERT(pvol->vs == VS_AVAILABLE &&
  1037.                 IS_FLAG_SET(pvol->dwFlags, VOLUME_FL_ROOT_PATH_VALID));
  1038.          pcszVolumeRootPath = GetString(pvol->hsRootPath);
  1039.          ASSERT(lstrlen(pcszVolumeRootPath) <= lstrlen(rgchPath));
  1040.          lstrcpy(pszPathSuffixBuf, rgchPath + lstrlen(pcszVolumeRootPath));
  1041.          *phvol = (HVOLUME)pvol;
  1042.          vr = VR_SUCCESS;
  1043.       }
  1044.       else
  1045.       {
  1046.          DWORD dwOutFlags;
  1047.          TCHAR rgchNetResource[MAX_PATH_LEN];
  1048.          LPTSTR pszRootPathSuffix;
  1049.          /* No.  Create a new volume. */
  1050.          if (GetCanonicalPathInfo(pcszPath, rgchPath, &dwOutFlags,
  1051.                                   rgchNetResource, &pszRootPathSuffix))
  1052.          {
  1053.             PLINKINFO pli;
  1054.             lstrcpy(pszPathSuffixBuf, pszRootPathSuffix);
  1055.             *pszRootPathSuffix = TEXT('');
  1056.             WARNING_OUT((TEXT("AddVolume(): Creating LinkInfo for root path %s."),
  1057.                          rgchPath));
  1058.             if (CreateLinkInfo(rgchPath, &pli))
  1059.             {
  1060.                PVOLUME pvol;
  1061.                if (CreateVolume((PVOLUMELIST)hvl, pli, &pvol))
  1062.                {
  1063.                   TCHAR rgchUnusedVolumeRootPath[MAX_PATH_LEN];
  1064.                   ResolveVolumeRootPath(pvol, rgchUnusedVolumeRootPath);
  1065.                   *phvol = (HVOLUME)pvol;
  1066.                   vr = VR_SUCCESS;
  1067.                }
  1068.                else
  1069.                   vr = VR_OUT_OF_MEMORY;
  1070.                DestroyLinkInfo(pli);
  1071.             }
  1072.             else
  1073.                /*
  1074.                 * Differentiate between VR_UNAVAILABLE_VOLUME and
  1075.                 * VR_OUT_OF_MEMORY.
  1076.                 */
  1077.                vr = VOLUMERESULTFromLastError(VR_UNAVAILABLE_VOLUME);
  1078.          }
  1079.          else
  1080.             vr = VOLUMERESULTFromLastError(VR_INVALID_PATH);
  1081.       }
  1082.    }
  1083.    else
  1084.    {
  1085.       ASSERT(! dwPathLen);
  1086.       vr = VOLUMERESULTFromLastError(VR_INVALID_PATH);
  1087.    }
  1088.    ASSERT(vr != VR_SUCCESS ||
  1089.           (IS_VALID_HANDLE(*phvol, VOLUME) &&
  1090.            EVAL(IsValidPathSuffix(pszPathSuffixBuf))));
  1091.    return(vr);
  1092. }
  1093. /*
  1094. ** DeleteVolume()
  1095. **
  1096. **
  1097. **
  1098. ** Arguments:
  1099. **
  1100. ** Returns:
  1101. **
  1102. ** Side Effects:  none
  1103. */
  1104. PUBLIC_CODE void DeleteVolume(HVOLUME hvol)
  1105. {
  1106.    ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1107.    if (! UnlockVolume((PVOLUME)hvol))
  1108.    {
  1109.       UnlinkVolume((PVOLUME)hvol);
  1110.       DestroyVolume((PVOLUME)hvol);
  1111.    }
  1112.    return;
  1113. }
  1114. /*
  1115. ** CompareVolumes()
  1116. **
  1117. **
  1118. **
  1119. ** Arguments:
  1120. **
  1121. ** Returns:
  1122. **
  1123. ** Side Effects:  none
  1124. */
  1125. PUBLIC_CODE COMPARISONRESULT CompareVolumes(HVOLUME hvolFirst,
  1126.                                             HVOLUME hvolSecond)
  1127. {
  1128.    ASSERT(IS_VALID_HANDLE(hvolFirst, VOLUME));
  1129.    ASSERT(IS_VALID_HANDLE(hvolSecond, VOLUME));
  1130.    /* This comparison works across volume lists. */
  1131.    return(CompareLinkInfoVolumes(((PCVOLUME)hvolFirst)->pli,
  1132.                                  ((PCVOLUME)hvolSecond)->pli));
  1133. }
  1134. /*
  1135. ** CopyVolume()
  1136. **
  1137. **
  1138. **
  1139. ** Arguments:
  1140. **
  1141. ** Returns:
  1142. **
  1143. ** Side Effects:  none
  1144. */
  1145. PUBLIC_CODE BOOL CopyVolume(HVOLUME hvolSrc, HVOLUMELIST hvlDest,
  1146.                             PHVOLUME phvolCopy)
  1147. {
  1148.    BOOL bResult;
  1149.    PVOLUME pvol;
  1150.    ASSERT(IS_VALID_HANDLE(hvolSrc, VOLUME));
  1151.    ASSERT(IS_VALID_HANDLE(hvlDest, VOLUMELIST));
  1152.    ASSERT(IS_VALID_WRITE_PTR(phvolCopy, HVOLUME));
  1153.    /* Is the destination volume list the source volume's volume list? */
  1154.    if (((PCVOLUME)hvolSrc)->pvlParent == (PCVOLUMELIST)hvlDest)
  1155.    {
  1156.       /* Yes.  Use the source volume. */
  1157.       LockVolume((PVOLUME)hvolSrc);
  1158.       pvol = (PVOLUME)hvolSrc;
  1159.       bResult = TRUE;
  1160.    }
  1161.    else
  1162.       bResult = CreateVolume((PVOLUMELIST)hvlDest, ((PCVOLUME)hvolSrc)->pli,
  1163.                              &pvol);
  1164.    if (bResult)
  1165.       *phvolCopy = (HVOLUME)pvol;
  1166.    ASSERT(! bResult ||
  1167.           IS_VALID_HANDLE(*phvolCopy, VOLUME));
  1168.    return(bResult);
  1169. }
  1170. /*
  1171. ** IsVolumeAvailable()
  1172. **
  1173. **
  1174. **
  1175. ** Arguments:
  1176. **
  1177. ** Returns:
  1178. **
  1179. ** Side Effects:  none
  1180. */
  1181. PUBLIC_CODE BOOL IsVolumeAvailable(HVOLUME hvol)
  1182. {
  1183.    TCHAR rgchUnusedVolumeRootPath[MAX_PATH_LEN];
  1184.    ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1185.    ResolveVolumeRootPath((PVOLUME)hvol, rgchUnusedVolumeRootPath);
  1186.    ASSERT(IsValidVOLUMESTATE(((PCVOLUME)hvol)->vs) &&
  1187.           ((PCVOLUME)hvol)->vs != VS_UNKNOWN);
  1188.    return(((PCVOLUME)hvol)->vs == VS_AVAILABLE);
  1189. }
  1190. /*
  1191. ** GetVolumeRootPath()
  1192. **
  1193. **
  1194. **
  1195. ** Arguments:
  1196. **
  1197. ** Returns:
  1198. **
  1199. ** Side Effects:  none
  1200. */
  1201. PUBLIC_CODE void GetVolumeRootPath(HVOLUME hvol, LPTSTR pszRootPathBuf)
  1202. {
  1203.    ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1204.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
  1205.    ResolveVolumeRootPath((PVOLUME)hvol, pszRootPathBuf);
  1206.    ASSERT(IsRootPath(pszRootPathBuf));
  1207.    return;
  1208. }
  1209. #ifdef DEBUG
  1210. /*
  1211. ** DebugGetVolumeRootPath()
  1212. **
  1213. **
  1214. **
  1215. ** Arguments:
  1216. **
  1217. ** Returns:
  1218. **
  1219. ** Side Effects:  none
  1220. **
  1221. ** N.b., DebugGetVolumeRootPath() must be non-intrusive.
  1222. */
  1223. PUBLIC_CODE LPTSTR DebugGetVolumeRootPath(HVOLUME hvol, LPTSTR pszRootPathBuf)
  1224. {
  1225.    ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1226.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
  1227.    if (IS_FLAG_SET(((PVOLUME)hvol)->dwFlags, VOLUME_FL_ROOT_PATH_VALID))
  1228.       MyLStrCpyN(pszRootPathBuf, GetString(((PVOLUME)hvol)->hsRootPath), MAX_PATH_LEN);
  1229.    else
  1230.       GetUnavailableVolumeRootPath(((PVOLUME)hvol)->pli, pszRootPathBuf);
  1231.    ASSERT(IsRootPath(pszRootPathBuf));
  1232.    return(pszRootPathBuf);
  1233. }
  1234. /*
  1235. ** GetVolumeCount()
  1236. **
  1237. **
  1238. **
  1239. ** Arguments:
  1240. **
  1241. ** Returns:
  1242. **
  1243. ** Side Effects:  none
  1244. */
  1245. PUBLIC_CODE ULONG GetVolumeCount(HVOLUMELIST hvl)
  1246. {
  1247.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1248.    return(GetPtrCount(((PCVOLUMELIST)hvl)->hpa));
  1249. }
  1250. #endif
  1251. /*
  1252. ** DescribeVolume()
  1253. **
  1254. **
  1255. **
  1256. ** Arguments:
  1257. **
  1258. ** Returns:
  1259. **
  1260. ** Side Effects:  none
  1261. */
  1262. PUBLIC_CODE void DescribeVolume(HVOLUME hvol, PVOLUMEDESC pvoldesc)
  1263. {
  1264.    PCVOID pcv;
  1265.    ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  1266.    ASSERT(IS_VALID_WRITE_PTR(pvoldesc, VOLUMEDESC));
  1267.    ASSERT(pvoldesc->ulSize == sizeof(*pvoldesc));
  1268.    pvoldesc->dwFlags = 0;
  1269.    if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_SERIAL_NUMBER, &pcv))
  1270.    {
  1271.       pvoldesc->dwSerialNumber = *(PCDWORD)pcv;
  1272.       SET_FLAG(pvoldesc->dwFlags, VD_FL_SERIAL_NUMBER_VALID);
  1273.    }
  1274.    else
  1275.       pvoldesc->dwSerialNumber = 0;
  1276.    if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_LABELW, &pcv) && pcv)
  1277.    {
  1278.       lstrcpy(pvoldesc->rgchVolumeLabel, pcv);
  1279.       SET_FLAG(pvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID);
  1280.    }
  1281.    else if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_VOLUME_LABEL, &pcv) && pcv)
  1282.    {
  1283.       MultiByteToWideChar(CP_ACP, 0, pcv, -1, pvoldesc->rgchVolumeLabel, MAX_PATH);
  1284.       SET_FLAG(pvoldesc->dwFlags, VD_FL_VOLUME_LABEL_VALID);
  1285.    }
  1286.    else
  1287.    {
  1288.       pvoldesc->rgchVolumeLabel[0] = TEXT('');
  1289.    }
  1290.    if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_NET_RESOURCEW, &pcv) && pcv)
  1291.    {
  1292.         lstrcpy(pvoldesc->rgchNetResource, pcv);
  1293.         SET_FLAG(pvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID);
  1294.    }
  1295.    else if (GetLinkInfoData(((PCVOLUME)hvol)->pli, LIDT_NET_RESOURCE, &pcv) && pcv)
  1296.    {
  1297.         MultiByteToWideChar(CP_ACP, 0, pcv, -1, pvoldesc->rgchNetResource, MAX_PATH);
  1298.         SET_FLAG(pvoldesc->dwFlags, VD_FL_NET_RESOURCE_VALID);
  1299.    }
  1300.    else
  1301.       pvoldesc->rgchNetResource[0] = TEXT('');
  1302.    ASSERT(IS_VALID_STRUCT_PTR(pvoldesc, CVOLUMEDESC));
  1303.    return;
  1304. }
  1305. /*
  1306. ** WriteVolumeList()
  1307. **
  1308. **
  1309. **
  1310. ** Arguments:
  1311. **
  1312. ** Returns:
  1313. **
  1314. ** Side Effects:  none
  1315. */
  1316. PUBLIC_CODE TWINRESULT WriteVolumeList(HCACHEDFILE hcf, HVOLUMELIST hvl)
  1317. {
  1318.    TWINRESULT tr = TR_BRIEFCASE_WRITE_FAILED;
  1319.    DWORD dwcbDBVolumeListHeaderOffset;
  1320.    ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1321.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1322.    /* Save initial file position. */
  1323.    dwcbDBVolumeListHeaderOffset = GetCachedFilePointerPosition(hcf);
  1324.    if (dwcbDBVolumeListHeaderOffset != INVALID_SEEK_POSITION)
  1325.    {
  1326.       DBVOLUMELISTHEADER dbvlh;
  1327.       /* Leave space for volume list header. */
  1328.       ZeroMemory(&dbvlh, sizeof(dbvlh));
  1329.       if (WriteToCachedFile(hcf, (PCVOID)&dbvlh, sizeof(dbvlh), NULL))
  1330.       {
  1331.          ARRAYINDEX aicPtrs;
  1332.          ARRAYINDEX ai;
  1333.          UINT ucbMaxLinkInfoLen = 0;
  1334.          LONG lcVolumes = 0;
  1335.          tr = TR_SUCCESS;
  1336.          aicPtrs = GetPtrCount(((PCVOLUMELIST)hvl)->hpa);
  1337.          /* Write all volumes. */
  1338.          for (ai = 0; ai < aicPtrs; ai++)
  1339.          {
  1340.             PVOLUME pvol;
  1341.             pvol = GetPtr(((PCVOLUMELIST)hvl)->hpa, ai);
  1342.             /*
  1343.              * As a sanity check, don't save any volume with a lock count of 0.
  1344.              * A 0 lock count implies that the volume has not been referenced
  1345.              * since it was restored from the database, or something is broken.
  1346.              */
  1347.             if (pvol->ulcLock > 0)
  1348.             {
  1349.                tr = WriteVolume(hcf, pvol);
  1350.                if (tr == TR_SUCCESS)
  1351.                {
  1352.                   ASSERT(lcVolumes < LONG_MAX);
  1353.                   lcVolumes++;
  1354.                   if (pvol->pli->ucbSize > ucbMaxLinkInfoLen)
  1355.                      ucbMaxLinkInfoLen = pvol->pli->ucbSize;
  1356.                }
  1357.                else
  1358.                   break;
  1359.             }
  1360.             else
  1361.                ERROR_OUT((TEXT("WriteVolumeList(): VOLUME has 0 lock count and will not be written.")));
  1362.          }
  1363.          /* Save volume list header. */
  1364.          if (tr == TR_SUCCESS)
  1365.          {
  1366.             dbvlh.lcVolumes = lcVolumes;
  1367.             dbvlh.ucbMaxLinkInfoLen = ucbMaxLinkInfoLen;
  1368.             tr = WriteDBSegmentHeader(hcf, dwcbDBVolumeListHeaderOffset,
  1369.                                       &dbvlh, sizeof(dbvlh));
  1370.             TRACE_OUT((TEXT("WriteVolumeList(): Wrote %ld volumes; maximum LinkInfo length %u bytes."),
  1371.                        dbvlh.lcVolumes,
  1372.                        dbvlh.ucbMaxLinkInfoLen));
  1373.          }
  1374.       }
  1375.    }
  1376.    return(tr);
  1377. }
  1378. /*
  1379. ** ReadVolumeList()
  1380. **
  1381. **
  1382. **
  1383. ** Arguments:
  1384. **
  1385. ** Returns:
  1386. **
  1387. ** Side Effects:  none
  1388. */
  1389. PUBLIC_CODE TWINRESULT ReadVolumeList(HCACHEDFILE hcf, HVOLUMELIST hvl,
  1390.                                       PHHANDLETRANS phht)
  1391. {
  1392.    TWINRESULT tr;
  1393.    DBVOLUMELISTHEADER dbvlh;
  1394.    DWORD dwcbRead;
  1395.    ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1396.    ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1397.    ASSERT(IS_VALID_WRITE_PTR(phht, HHANDLETRANS));
  1398.    if (ReadFromCachedFile(hcf, &dbvlh, sizeof(dbvlh), &dwcbRead) &&
  1399.        dwcbRead == sizeof(dbvlh))
  1400.    {
  1401.       HHANDLETRANS hht;
  1402.       tr = TR_OUT_OF_MEMORY;
  1403.       if (CreateHandleTranslator(dbvlh.lcVolumes, &hht))
  1404.       {
  1405.          PLINKINFO pliBuf;
  1406.          if (AllocateMemory(dbvlh.ucbMaxLinkInfoLen, &pliBuf))
  1407.          {
  1408.             LONG l;
  1409.             tr = TR_SUCCESS;
  1410.             TRACE_OUT((TEXT("ReadPathList(): Reading %ld volumes; maximum LinkInfo length %u bytes."),
  1411.                        dbvlh.lcVolumes,
  1412.                        dbvlh.ucbMaxLinkInfoLen));
  1413.             for (l = 0; l < dbvlh.lcVolumes; l++)
  1414.             {
  1415.                tr = ReadVolume(hcf, (PVOLUMELIST)hvl, pliBuf,
  1416.                                dbvlh.ucbMaxLinkInfoLen, hht);
  1417.                if (tr != TR_SUCCESS)
  1418.                   break;
  1419.             }
  1420.             if (tr == TR_SUCCESS)
  1421.             {
  1422.                PrepareForHandleTranslation(hht);
  1423.                *phht = hht;
  1424.                ASSERT(IS_VALID_HANDLE(hvl, VOLUMELIST));
  1425.                ASSERT(IS_VALID_HANDLE(*phht, HANDLETRANS));
  1426.             }
  1427.             else
  1428.                DestroyHandleTranslator(hht);
  1429.             FreeMemory(pliBuf);
  1430.          }
  1431.       }
  1432.    }
  1433.    else
  1434.       tr = TR_CORRUPT_BRIEFCASE;
  1435.    ASSERT(tr != TR_SUCCESS ||
  1436.           (IS_VALID_HANDLE(hvl, VOLUMELIST) &&
  1437.            IS_VALID_HANDLE(*phht, HANDLETRANS)));
  1438.    return(tr);
  1439. }
  1440. /*
  1441. ** IsValidHVOLUME()
  1442. **
  1443. **
  1444. **
  1445. ** Arguments:
  1446. **
  1447. ** Returns:
  1448. **
  1449. ** Side Effects:  none
  1450. */
  1451. PUBLIC_CODE BOOL IsValidHVOLUME(HVOLUME hvol)
  1452. {
  1453.    return(IS_VALID_STRUCT_PTR((PCVOLUME)hvol, CVOLUME));
  1454. }
  1455. #if defined(DEBUG) || defined(VSTF)
  1456. /*
  1457. ** IsValidHVOLUMELIST()
  1458. **
  1459. **
  1460. **
  1461. ** Arguments:
  1462. **
  1463. ** Returns:
  1464. **
  1465. ** Side Effects:  none
  1466. */
  1467. PUBLIC_CODE BOOL IsValidHVOLUMELIST(HVOLUMELIST hvl)
  1468. {
  1469.    return(IS_VALID_STRUCT_PTR((PCVOLUMELIST)hvl, CVOLUMELIST));
  1470. }
  1471. #endif