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.

1890 lines
42 KiB

  1. /*
  2. * path.c - Path ADT module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "volume.h"
  9. /* Constants
  10. ************/
  11. /* PATHLIST PTRARRAY allocation parameters */
  12. #define NUM_START_PATHS (32)
  13. #define NUM_PATHS_TO_ADD (32)
  14. /* PATHLIST string table allocation parameters */
  15. #define NUM_PATH_HASH_BUCKETS (67)
  16. /* Types
  17. ********/
  18. /* path list */
  19. typedef struct _pathlist
  20. {
  21. /* array of pointers to PATHs */
  22. HPTRARRAY hpa;
  23. /* list of volumes */
  24. HVOLUMELIST hvl;
  25. /* table of path suffix strings */
  26. HSTRINGTABLE hst;
  27. }
  28. PATHLIST;
  29. DECLARE_STANDARD_TYPES(PATHLIST);
  30. /* path structure */
  31. typedef struct _path
  32. {
  33. /* reference count */
  34. ULONG ulcLock;
  35. /* handle to parent volume */
  36. HVOLUME hvol;
  37. /* handle to path suffix string */
  38. HSTRING hsPathSuffix;
  39. /* pointer to PATH's parent PATHLIST */
  40. PPATHLIST pplParent;
  41. }
  42. PATH;
  43. DECLARE_STANDARD_TYPES(PATH);
  44. /* PATH search structure used by PathSearchCmp() */
  45. typedef struct _pathsearchinfo
  46. {
  47. HVOLUME hvol;
  48. LPCTSTR pcszPathSuffix;
  49. }
  50. PATHSEARCHINFO;
  51. DECLARE_STANDARD_TYPES(PATHSEARCHINFO);
  52. /* database path list header */
  53. typedef struct _dbpathlistheader
  54. {
  55. /* number of paths in list */
  56. LONG lcPaths;
  57. }
  58. DBPATHLISTHEADER;
  59. DECLARE_STANDARD_TYPES(DBPATHLISTHEADER);
  60. /* database path structure */
  61. typedef struct _dbpath
  62. {
  63. /* old handle to path */
  64. HPATH hpath;
  65. /* old handle to parent volume */
  66. HVOLUME hvol;
  67. /* old handle to path suffix string */
  68. HSTRING hsPathSuffix;
  69. }
  70. DBPATH;
  71. DECLARE_STANDARD_TYPES(DBPATH);
  72. /***************************** Private Functions *****************************/
  73. /* Module Prototypes
  74. ********************/
  75. PRIVATE_CODE COMPARISONRESULT PathSortCmp(PCVOID, PCVOID);
  76. PRIVATE_CODE COMPARISONRESULT PathSearchCmp(PCVOID, PCVOID);
  77. PRIVATE_CODE BOOL UnifyPath(PPATHLIST, HVOLUME, LPCTSTR, PPATH *);
  78. PRIVATE_CODE BOOL CreatePath(PPATHLIST, HVOLUME, LPCTSTR, PPATH *);
  79. PRIVATE_CODE void DestroyPath(PPATH);
  80. PRIVATE_CODE void UnlinkPath(PCPATH);
  81. PRIVATE_CODE void LockPath(PPATH);
  82. PRIVATE_CODE BOOL UnlockPath(PPATH);
  83. PRIVATE_CODE PATHRESULT TranslateVOLUMERESULTToPATHRESULT(VOLUMERESULT);
  84. PRIVATE_CODE TWINRESULT WritePath(HCACHEDFILE, PPATH);
  85. PRIVATE_CODE TWINRESULT ReadPath(HCACHEDFILE, PPATHLIST, HHANDLETRANS, HHANDLETRANS, HHANDLETRANS);
  86. #if defined(DEBUG) || defined(VSTF)
  87. PRIVATE_CODE BOOL IsValidPCPATHLIST(PCPATHLIST);
  88. PRIVATE_CODE BOOL IsValidPCPATH(PCPATH);
  89. #endif
  90. #if defined(DEBUG)
  91. PRIVATE_CODE BOOL IsValidPCPATHSEARCHINFO(PCPATHSEARCHINFO);
  92. #endif
  93. /*
  94. ** PathSortCmp()
  95. **
  96. ** Pointer comparison function used to sort the module array of paths.
  97. **
  98. ** Arguments: pcpath1 - pointer to first path
  99. ** pcpath2 - pointer to second path
  100. **
  101. ** Returns:
  102. **
  103. ** Side Effects: none
  104. **
  105. ** The internal paths are sorted by:
  106. ** 1) volume
  107. ** 2) path suffix
  108. ** 3) pointer value
  109. */
  110. PRIVATE_CODE COMPARISONRESULT PathSortCmp(PCVOID pcpath1, PCVOID pcpath2)
  111. {
  112. COMPARISONRESULT cr;
  113. ASSERT(IS_VALID_STRUCT_PTR(pcpath1, CPATH));
  114. ASSERT(IS_VALID_STRUCT_PTR(pcpath2, CPATH));
  115. cr = CompareVolumes(((PCPATH)pcpath1)->hvol,
  116. ((PCPATH)pcpath2)->hvol);
  117. if (cr == CR_EQUAL)
  118. {
  119. cr = ComparePathStringsByHandle(((PCPATH)pcpath1)->hsPathSuffix,
  120. ((PCPATH)pcpath2)->hsPathSuffix);
  121. if (cr == CR_EQUAL)
  122. cr = ComparePointers(pcpath1, pcpath2);
  123. }
  124. return(cr);
  125. }
  126. /*
  127. ** PathSearchCmp()
  128. **
  129. ** Pointer comparison function used to search for a path.
  130. **
  131. ** Arguments: pcpathsi - pointer to PATHSEARCHINFO describing path to
  132. ** search for
  133. ** pcpath - pointer to path to examine
  134. **
  135. ** Returns:
  136. **
  137. ** Side Effects: none
  138. **
  139. ** The internal paths are searched by:
  140. ** 1) volume
  141. ** 2) path suffix string
  142. */
  143. PRIVATE_CODE COMPARISONRESULT PathSearchCmp(PCVOID pcpathsi, PCVOID pcpath)
  144. {
  145. COMPARISONRESULT cr;
  146. ASSERT(IS_VALID_STRUCT_PTR(pcpathsi, CPATHSEARCHINFO));
  147. ASSERT(IS_VALID_STRUCT_PTR(pcpath, CPATH));
  148. cr = CompareVolumes(((PCPATHSEARCHINFO)pcpathsi)->hvol,
  149. ((PCPATH)pcpath)->hvol);
  150. if (cr == CR_EQUAL)
  151. cr = ComparePathStrings(((PCPATHSEARCHINFO)pcpathsi)->pcszPathSuffix,
  152. GetString(((PCPATH)pcpath)->hsPathSuffix));
  153. return(cr);
  154. }
  155. /*
  156. ** UnifyPath()
  157. **
  158. **
  159. **
  160. ** Arguments:
  161. **
  162. ** Returns:
  163. **
  164. ** Side Effects: none
  165. */
  166. PRIVATE_CODE BOOL UnifyPath(PPATHLIST ppl, HVOLUME hvol, LPCTSTR pcszPathSuffix,
  167. PPATH *pppath)
  168. {
  169. BOOL bResult = FALSE;
  170. ASSERT(IS_VALID_STRUCT_PTR(ppl, CPATHLIST));
  171. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  172. ASSERT(IsValidPathSuffix(pcszPathSuffix));
  173. ASSERT(IS_VALID_WRITE_PTR(pppath, PPATH));
  174. /* Allocate space for PATH structure. */
  175. if (AllocateMemory(sizeof(**pppath), pppath))
  176. {
  177. if (CopyVolume(hvol, ppl->hvl, &((*pppath)->hvol)))
  178. {
  179. if (AddString(pcszPathSuffix, ppl->hst, GetHashBucketIndex, &((*pppath)->hsPathSuffix)))
  180. {
  181. ARRAYINDEX aiUnused;
  182. /* Initialize remaining PATH fields. */
  183. (*pppath)->ulcLock = 0;
  184. (*pppath)->pplParent = ppl;
  185. /* Add new PATH to array. */
  186. if (AddPtr(ppl->hpa, PathSortCmp, *pppath, &aiUnused))
  187. bResult = TRUE;
  188. else
  189. {
  190. DeleteString((*pppath)->hsPathSuffix);
  191. UNIFYPATH_BAIL1:
  192. DeleteVolume((*pppath)->hvol);
  193. UNIFYPATH_BAIL2:
  194. FreeMemory(*pppath);
  195. }
  196. }
  197. else
  198. goto UNIFYPATH_BAIL1;
  199. }
  200. else
  201. goto UNIFYPATH_BAIL2;
  202. }
  203. ASSERT(! bResult ||
  204. IS_VALID_STRUCT_PTR(*pppath, CPATH));
  205. return(bResult);
  206. }
  207. /*
  208. ** CreatePath()
  209. **
  210. **
  211. **
  212. ** Arguments:
  213. **
  214. ** Returns:
  215. **
  216. ** Side Effects: none
  217. */
  218. PRIVATE_CODE BOOL CreatePath(PPATHLIST ppl, HVOLUME hvol, LPCTSTR pcszPathSuffix,
  219. PPATH *pppath)
  220. {
  221. BOOL bResult;
  222. ARRAYINDEX aiFound;
  223. PATHSEARCHINFO pathsi;
  224. ASSERT(IS_VALID_STRUCT_PTR(ppl, CPATHLIST));
  225. ASSERT(IS_VALID_HANDLE(hvol, VOLUME));
  226. ASSERT(IsValidPathSuffix(pcszPathSuffix));
  227. ASSERT(IS_VALID_WRITE_PTR(pppath, CPATH));
  228. /* Does a path for the given volume and path suffix already exist? */
  229. pathsi.hvol = hvol;
  230. pathsi.pcszPathSuffix = pcszPathSuffix;
  231. bResult = SearchSortedArray(ppl->hpa, &PathSearchCmp, &pathsi, &aiFound);
  232. if (bResult)
  233. /* Yes. Return it. */
  234. *pppath = GetPtr(ppl->hpa, aiFound);
  235. else
  236. bResult = UnifyPath(ppl, hvol, pcszPathSuffix, pppath);
  237. if (bResult)
  238. LockPath(*pppath);
  239. ASSERT(! bResult ||
  240. IS_VALID_STRUCT_PTR(*pppath, CPATH));
  241. return(bResult);
  242. }
  243. /*
  244. ** DestroyPath()
  245. **
  246. **
  247. **
  248. ** Arguments:
  249. **
  250. ** Returns:
  251. **
  252. ** Side Effects: none
  253. */
  254. PRIVATE_CODE void DestroyPath(PPATH ppath)
  255. {
  256. ASSERT(IS_VALID_STRUCT_PTR(ppath, CPATH));
  257. DeleteVolume(ppath->hvol);
  258. DeleteString(ppath->hsPathSuffix);
  259. FreeMemory(ppath);
  260. return;
  261. }
  262. /*
  263. ** UnlinkPath()
  264. **
  265. **
  266. **
  267. ** Arguments:
  268. **
  269. ** Returns:
  270. **
  271. ** Side Effects: none
  272. */
  273. PRIVATE_CODE void UnlinkPath(PCPATH pcpath)
  274. {
  275. HPTRARRAY hpa;
  276. ARRAYINDEX aiFound;
  277. ASSERT(IS_VALID_STRUCT_PTR(pcpath, CPATH));
  278. hpa = pcpath->pplParent->hpa;
  279. if (EVAL(SearchSortedArray(hpa, &PathSortCmp, pcpath, &aiFound)))
  280. {
  281. ASSERT(GetPtr(hpa, aiFound) == pcpath);
  282. DeletePtr(hpa, aiFound);
  283. }
  284. return;
  285. }
  286. /*
  287. ** LockPath()
  288. **
  289. **
  290. **
  291. ** Arguments:
  292. **
  293. ** Returns:
  294. **
  295. ** Side Effects: none
  296. */
  297. PRIVATE_CODE void LockPath(PPATH ppath)
  298. {
  299. ASSERT(IS_VALID_STRUCT_PTR(ppath, CPATH));
  300. ASSERT(ppath->ulcLock < ULONG_MAX);
  301. ppath->ulcLock++;
  302. return;
  303. }
  304. /*
  305. ** UnlockPath()
  306. **
  307. **
  308. **
  309. ** Arguments:
  310. **
  311. ** Returns:
  312. **
  313. ** Side Effects: none
  314. */
  315. PRIVATE_CODE BOOL UnlockPath(PPATH ppath)
  316. {
  317. ASSERT(IS_VALID_STRUCT_PTR(ppath, CPATH));
  318. if (EVAL(ppath->ulcLock > 0))
  319. ppath->ulcLock--;
  320. return(ppath->ulcLock > 0);
  321. }
  322. /*
  323. ** TranslateVOLUMERESULTToPATHRESULT()
  324. **
  325. **
  326. **
  327. ** Arguments:
  328. **
  329. ** Returns:
  330. **
  331. ** Side Effects: none
  332. */
  333. PRIVATE_CODE PATHRESULT TranslateVOLUMERESULTToPATHRESULT(VOLUMERESULT vr)
  334. {
  335. PATHRESULT pr;
  336. switch (vr)
  337. {
  338. case VR_SUCCESS:
  339. pr = PR_SUCCESS;
  340. break;
  341. case VR_UNAVAILABLE_VOLUME:
  342. pr = PR_UNAVAILABLE_VOLUME;
  343. break;
  344. case VR_OUT_OF_MEMORY:
  345. pr = PR_OUT_OF_MEMORY;
  346. break;
  347. default:
  348. ASSERT(vr == VR_INVALID_PATH);
  349. pr = PR_INVALID_PATH;
  350. break;
  351. }
  352. return(pr);
  353. }
  354. /*
  355. ** WritePath()
  356. **
  357. **
  358. **
  359. ** Arguments:
  360. **
  361. ** Returns:
  362. **
  363. ** Side Effects: none
  364. */
  365. PRIVATE_CODE TWINRESULT WritePath(HCACHEDFILE hcf, PPATH ppath)
  366. {
  367. TWINRESULT tr;
  368. DBPATH dbpath;
  369. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  370. ASSERT(IS_VALID_STRUCT_PTR(ppath, CPATH));
  371. /* Write database path. */
  372. dbpath.hpath = (HPATH)ppath;
  373. dbpath.hvol = ppath->hvol;
  374. dbpath.hsPathSuffix = ppath->hsPathSuffix;
  375. if (WriteToCachedFile(hcf, (PCVOID)&dbpath, sizeof(dbpath), NULL))
  376. tr = TR_SUCCESS;
  377. else
  378. tr = TR_BRIEFCASE_WRITE_FAILED;
  379. return(tr);
  380. }
  381. /*
  382. ** ReadPath()
  383. **
  384. **
  385. **
  386. ** Arguments:
  387. **
  388. ** Returns:
  389. **
  390. ** Side Effects: none
  391. */
  392. PRIVATE_CODE TWINRESULT ReadPath(HCACHEDFILE hcf, PPATHLIST ppl,
  393. HHANDLETRANS hhtVolumes,
  394. HHANDLETRANS hhtStrings,
  395. HHANDLETRANS hhtPaths)
  396. {
  397. TWINRESULT tr;
  398. DBPATH dbpath;
  399. DWORD dwcbRead;
  400. HVOLUME hvol;
  401. HSTRING hsPathSuffix;
  402. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  403. ASSERT(IS_VALID_STRUCT_PTR(ppl, CPATHLIST));
  404. ASSERT(IS_VALID_HANDLE(hhtVolumes, HANDLETRANS));
  405. ASSERT(IS_VALID_HANDLE(hhtStrings, HANDLETRANS));
  406. ASSERT(IS_VALID_HANDLE(hhtPaths, HANDLETRANS));
  407. if (ReadFromCachedFile(hcf, &dbpath, sizeof(dbpath), &dwcbRead) &&
  408. dwcbRead == sizeof(dbpath) &&
  409. TranslateHandle(hhtVolumes, (HGENERIC)(dbpath.hvol), (PHGENERIC)&hvol) &&
  410. TranslateHandle(hhtStrings, (HGENERIC)(dbpath.hsPathSuffix), (PHGENERIC)&hsPathSuffix))
  411. {
  412. PPATH ppath;
  413. if (CreatePath(ppl, hvol, GetString(hsPathSuffix), &ppath))
  414. {
  415. /*
  416. * To leave read paths with 0 initial lock count, we must undo
  417. * the LockPath() performed by CreatePath().
  418. */
  419. UnlockPath(ppath);
  420. if (AddHandleToHandleTranslator(hhtPaths,
  421. (HGENERIC)(dbpath.hpath),
  422. (HGENERIC)ppath))
  423. tr = TR_SUCCESS;
  424. else
  425. {
  426. UnlinkPath(ppath);
  427. DestroyPath(ppath);
  428. tr = TR_OUT_OF_MEMORY;
  429. }
  430. }
  431. else
  432. tr = TR_OUT_OF_MEMORY;
  433. }
  434. else
  435. tr = TR_CORRUPT_BRIEFCASE;
  436. return(tr);
  437. }
  438. #if defined(DEBUG) || defined(VSTF)
  439. /*
  440. ** IsValidPCPATHLIST()
  441. **
  442. **
  443. **
  444. ** Arguments:
  445. **
  446. ** Returns:
  447. **
  448. ** Side Effects: none
  449. */
  450. PRIVATE_CODE BOOL IsValidPCPATHLIST(PCPATHLIST pcpl)
  451. {
  452. return(IS_VALID_READ_PTR(pcpl, CPATHLIST) &&
  453. IS_VALID_HANDLE(pcpl->hpa, PTRARRAY) &&
  454. IS_VALID_HANDLE(pcpl->hvl, VOLUMELIST) &&
  455. IS_VALID_HANDLE(pcpl->hst, STRINGTABLE));
  456. }
  457. /*
  458. ** IsValidPCPATH()
  459. **
  460. **
  461. **
  462. ** Arguments:
  463. **
  464. ** Returns:
  465. **
  466. ** Side Effects: none
  467. */
  468. PRIVATE_CODE BOOL IsValidPCPATH(PCPATH pcpath)
  469. {
  470. return(IS_VALID_READ_PTR(pcpath, CPATH) &&
  471. IS_VALID_HANDLE(pcpath->hvol, VOLUME) &&
  472. IS_VALID_HANDLE(pcpath->hsPathSuffix, STRING) &&
  473. IsValidPathSuffix(GetString(pcpath->hsPathSuffix)) &&
  474. IS_VALID_READ_PTR(pcpath->pplParent, CPATHLIST));
  475. }
  476. #endif
  477. #if defined(DEBUG)
  478. /*
  479. ** IsValidPCPATHSEARCHINFO()
  480. **
  481. **
  482. **
  483. ** Arguments:
  484. **
  485. ** Returns:
  486. **
  487. ** Side Effects: none
  488. */
  489. PRIVATE_CODE BOOL IsValidPCPATHSEARCHINFO(PCPATHSEARCHINFO pcpathsi)
  490. {
  491. return(IS_VALID_READ_PTR(pcpathsi, CPATHSEARCHINFO) &&
  492. IS_VALID_HANDLE(pcpathsi->hvol, VOLUME) &&
  493. IsValidPathSuffix(pcpathsi->pcszPathSuffix));
  494. }
  495. #endif
  496. /****************************** Public Functions *****************************/
  497. /*
  498. ** CreatePathList()
  499. **
  500. **
  501. **
  502. ** Arguments:
  503. **
  504. ** Returns:
  505. **
  506. ** Side Effects: none
  507. */
  508. PUBLIC_CODE BOOL CreatePathList(DWORD dwFlags, HWND hwndOwner, PHPATHLIST phpl)
  509. {
  510. BOOL bResult = FALSE;
  511. PPATHLIST ppl;
  512. ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_RLI_IFLAGS));
  513. ASSERT(IS_FLAG_CLEAR(dwFlags, RLI_IFL_ALLOW_UI) ||
  514. IS_VALID_HANDLE(hwndOwner, WND));
  515. ASSERT(IS_VALID_WRITE_PTR(phpl, HPATHLIST));
  516. if (AllocateMemory(sizeof(*ppl), &ppl))
  517. {
  518. NEWPTRARRAY npa;
  519. /* Create pointer array of paths. */
  520. npa.aicInitialPtrs = NUM_START_PATHS;
  521. npa.aicAllocGranularity = NUM_PATHS_TO_ADD;
  522. npa.dwFlags = NPA_FL_SORTED_ADD;
  523. if (CreatePtrArray(&npa, &(ppl->hpa)))
  524. {
  525. if (CreateVolumeList(dwFlags, hwndOwner, &(ppl->hvl)))
  526. {
  527. NEWSTRINGTABLE nszt;
  528. /* Create string table for path suffix strings. */
  529. nszt.hbc = NUM_PATH_HASH_BUCKETS;
  530. if (CreateStringTable(&nszt, &(ppl->hst)))
  531. {
  532. *phpl = (HPATHLIST)ppl;
  533. bResult = TRUE;
  534. }
  535. else
  536. {
  537. DestroyVolumeList(ppl->hvl);
  538. CREATEPATHLIST_BAIL1:
  539. DestroyPtrArray(ppl->hpa);
  540. CREATEPATHLIST_BAIL2:
  541. FreeMemory(ppl);
  542. }
  543. }
  544. else
  545. goto CREATEPATHLIST_BAIL1;
  546. }
  547. else
  548. goto CREATEPATHLIST_BAIL2;
  549. }
  550. ASSERT(! bResult ||
  551. IS_VALID_HANDLE(*phpl, PATHLIST));
  552. return(bResult);
  553. }
  554. /*
  555. ** DestroyPathList()
  556. **
  557. **
  558. **
  559. ** Arguments:
  560. **
  561. ** Returns:
  562. **
  563. ** Side Effects: none
  564. */
  565. PUBLIC_CODE void DestroyPathList(HPATHLIST hpl)
  566. {
  567. ARRAYINDEX aicPtrs;
  568. ARRAYINDEX ai;
  569. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  570. /* First free all paths in array. */
  571. aicPtrs = GetPtrCount(((PCPATHLIST)hpl)->hpa);
  572. for (ai = 0; ai < aicPtrs; ai++)
  573. DestroyPath(GetPtr(((PCPATHLIST)hpl)->hpa, ai));
  574. /* Now wipe out the array. */
  575. DestroyPtrArray(((PCPATHLIST)hpl)->hpa);
  576. ASSERT(! GetVolumeCount(((PCPATHLIST)hpl)->hvl));
  577. DestroyVolumeList(((PCPATHLIST)hpl)->hvl);
  578. ASSERT(! GetStringCount(((PCPATHLIST)hpl)->hst));
  579. DestroyStringTable(((PCPATHLIST)hpl)->hst);
  580. FreeMemory((PPATHLIST)hpl);
  581. return;
  582. }
  583. /*
  584. ** InvalidatePathListInfo()
  585. **
  586. **
  587. **
  588. ** Arguments:
  589. **
  590. ** Returns:
  591. **
  592. ** Side Effects: none
  593. */
  594. PUBLIC_CODE void InvalidatePathListInfo(HPATHLIST hpl)
  595. {
  596. InvalidateVolumeListInfo(((PCPATHLIST)hpl)->hvl);
  597. return;
  598. }
  599. /*
  600. ** ClearPathListInfo()
  601. **
  602. **
  603. **
  604. ** Arguments:
  605. **
  606. ** Returns:
  607. **
  608. ** Side Effects: none
  609. */
  610. PUBLIC_CODE void ClearPathListInfo(HPATHLIST hpl)
  611. {
  612. ClearVolumeListInfo(((PCPATHLIST)hpl)->hvl);
  613. return;
  614. }
  615. /*
  616. ** AddPath()
  617. **
  618. **
  619. **
  620. ** Arguments:
  621. **
  622. ** Returns:
  623. **
  624. ** Side Effects: none
  625. */
  626. PUBLIC_CODE PATHRESULT AddPath(HPATHLIST hpl, LPCTSTR pcszPath, PHPATH phpath)
  627. {
  628. PATHRESULT pr;
  629. HVOLUME hvol;
  630. TCHAR rgchPathSuffix[MAX_PATH_LEN];
  631. LPCTSTR pszPath;
  632. #ifdef UNICODE
  633. WCHAR szUnicode[MAX_PATH];
  634. #endif
  635. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  636. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  637. ASSERT(IS_VALID_WRITE_PTR(phpath, HPATH));
  638. // On NT, we want to convert a unicode string to an ANSI shortened path for
  639. // the sake of interop
  640. #if defined(UNICODE)
  641. {
  642. CHAR szAnsi[MAX_PATH];
  643. szUnicode[0] = L'\0';
  644. WideCharToMultiByte(CP_ACP, 0, pcszPath, -1, szAnsi, ARRAYSIZE(szAnsi), NULL, NULL);
  645. MultiByteToWideChar(CP_ACP, 0, szAnsi, -1, szUnicode, ARRAYSIZE(szUnicode));
  646. if (lstrcmp(szUnicode, pcszPath))
  647. {
  648. // Cannot convert losslessly from Unicode -> Ansi, so get the short path
  649. lstrcpyn(szUnicode, pcszPath, ARRAYSIZE(szUnicode));
  650. SheShortenPath(szUnicode, TRUE);
  651. pszPath = szUnicode;
  652. }
  653. else
  654. {
  655. // It will convert OK, so just use the original
  656. pszPath = pcszPath;
  657. }
  658. }
  659. #else
  660. pszPath = pcszPath;
  661. #endif
  662. pr = TranslateVOLUMERESULTToPATHRESULT(
  663. AddVolume(((PCPATHLIST)hpl)->hvl, pszPath, &hvol, rgchPathSuffix, ARRAYSIZE(rgchPathSuffix)));
  664. if (pr == PR_SUCCESS)
  665. {
  666. PPATH ppath;
  667. if (CreatePath((PPATHLIST)hpl, hvol, rgchPathSuffix, &ppath))
  668. *phpath = (HPATH)ppath;
  669. else
  670. pr = PR_OUT_OF_MEMORY;
  671. DeleteVolume(hvol);
  672. }
  673. ASSERT(pr != PR_SUCCESS ||
  674. IS_VALID_HANDLE(*phpath, PATH));
  675. return(pr);
  676. }
  677. /*
  678. ** AddChildPath()
  679. **
  680. **
  681. **
  682. ** Arguments:
  683. **
  684. ** Returns:
  685. **
  686. ** Side Effects: none
  687. */
  688. PUBLIC_CODE BOOL AddChildPath(HPATHLIST hpl, HPATH hpathParent,
  689. LPCTSTR pcszSubPath, PHPATH phpathChild)
  690. {
  691. BOOL bResult;
  692. TCHAR rgchChildPathSuffix[MAX_PATH_LEN];
  693. LPCTSTR pcszPathSuffix;
  694. LPTSTR pszPathSuffixEnd;
  695. PPATH ppathChild;
  696. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  697. ASSERT(IS_VALID_HANDLE(hpathParent, PATH));
  698. ASSERT(IS_VALID_STRING_PTR(pcszSubPath, CSTR));
  699. ASSERT(IS_VALID_WRITE_PTR(phpathChild, HPATH));
  700. ComposePath(rgchChildPathSuffix,
  701. GetString(((PCPATH)hpathParent)->hsPathSuffix),
  702. pcszSubPath, ARRAYSIZE(rgchChildPathSuffix));
  703. pcszPathSuffix = rgchChildPathSuffix;
  704. if (IS_SLASH(*pcszPathSuffix))
  705. pcszPathSuffix++;
  706. pszPathSuffixEnd = CharPrev(pcszPathSuffix,
  707. pcszPathSuffix + lstrlen(pcszPathSuffix));
  708. if (IS_SLASH(*pszPathSuffixEnd))
  709. *pszPathSuffixEnd = TEXT('\0');
  710. ASSERT(IsValidPathSuffix(pcszPathSuffix));
  711. bResult = CreatePath((PPATHLIST)hpl, ((PCPATH)hpathParent)->hvol,
  712. pcszPathSuffix, &ppathChild);
  713. if (bResult)
  714. *phpathChild = (HPATH)ppathChild;
  715. ASSERT(! bResult ||
  716. IS_VALID_HANDLE(*phpathChild, PATH));
  717. return(bResult);
  718. }
  719. /*
  720. ** DeletePath()
  721. **
  722. **
  723. **
  724. ** Arguments:
  725. **
  726. ** Returns:
  727. **
  728. ** Side Effects: none
  729. */
  730. PUBLIC_CODE void DeletePath(HPATH hpath)
  731. {
  732. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  733. if (! UnlockPath((PPATH)hpath))
  734. {
  735. UnlinkPath((PPATH)hpath);
  736. DestroyPath((PPATH)hpath);
  737. }
  738. return;
  739. }
  740. /*
  741. ** CopyPath()
  742. **
  743. **
  744. **
  745. ** Arguments:
  746. **
  747. ** Returns:
  748. **
  749. ** Side Effects: none
  750. */
  751. PUBLIC_CODE BOOL CopyPath(HPATH hpathSrc, HPATHLIST hplDest, PHPATH phpathCopy)
  752. {
  753. BOOL bResult;
  754. PPATH ppath;
  755. ASSERT(IS_VALID_HANDLE(hpathSrc, PATH));
  756. ASSERT(IS_VALID_HANDLE(hplDest, PATHLIST));
  757. ASSERT(IS_VALID_WRITE_PTR(phpathCopy, HPATH));
  758. /* Is the destination path list the source path's path list? */
  759. if (((PCPATH)hpathSrc)->pplParent == (PCPATHLIST)hplDest)
  760. {
  761. /* Yes. Use the source path. */
  762. LockPath((PPATH)hpathSrc);
  763. ppath = (PPATH)hpathSrc;
  764. bResult = TRUE;
  765. }
  766. else
  767. bResult = CreatePath((PPATHLIST)hplDest, ((PCPATH)hpathSrc)->hvol,
  768. GetString(((PCPATH)hpathSrc)->hsPathSuffix),
  769. &ppath);
  770. if (bResult)
  771. *phpathCopy = (HPATH)ppath;
  772. ASSERT(! bResult ||
  773. IS_VALID_HANDLE(*phpathCopy, PATH));
  774. return(bResult);
  775. }
  776. /*
  777. ** GetPathString()
  778. **
  779. **
  780. **
  781. ** Arguments:
  782. **
  783. ** Returns:
  784. **
  785. ** Side Effects: none
  786. */
  787. PUBLIC_CODE void GetPathString(HPATH hpath, LPTSTR pszPathBuf, int cchMax)
  788. {
  789. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  790. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPathBuf, STR, cchMax));
  791. GetPathRootString(hpath, pszPathBuf, cchMax);
  792. CatPath(pszPathBuf, GetString(((PPATH)hpath)->hsPathSuffix), cchMax);
  793. ASSERT(IsCanonicalPath(pszPathBuf));
  794. return;
  795. }
  796. /*
  797. ** GetPathRootString()
  798. **
  799. **
  800. **
  801. ** Arguments:
  802. **
  803. ** Returns:
  804. **
  805. ** Side Effects: none
  806. */
  807. PUBLIC_CODE void GetPathRootString(HPATH hpath, LPTSTR pszPathRootBuf, int cchMax)
  808. {
  809. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  810. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPathRootBuf, STR, cchMax));
  811. GetVolumeRootPath(((PPATH)hpath)->hvol, pszPathRootBuf, cchMax);
  812. ASSERT(IsCanonicalPath(pszPathRootBuf));
  813. return;
  814. }
  815. /*
  816. ** GetPathSuffixString()
  817. **
  818. **
  819. **
  820. ** Arguments:
  821. **
  822. ** Returns:
  823. **
  824. ** Side Effects: none
  825. */
  826. PUBLIC_CODE void GetPathSuffixString(HPATH hpath, LPTSTR pszPathSuffixBuf)
  827. {
  828. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  829. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszPathSuffixBuf, STR, MAX_PATH_LEN));
  830. ASSERT(lstrlen(GetString(((PPATH)hpath)->hsPathSuffix)) < MAX_PATH_LEN);
  831. MyLStrCpyN(pszPathSuffixBuf, GetString(((PPATH)hpath)->hsPathSuffix), MAX_PATH_LEN);
  832. ASSERT(IsValidPathSuffix(pszPathSuffixBuf));
  833. return;
  834. }
  835. /*
  836. ** AllocatePathString()
  837. **
  838. **
  839. **
  840. ** Arguments:
  841. **
  842. ** Returns:
  843. **
  844. ** Side Effects: none
  845. */
  846. PUBLIC_CODE BOOL AllocatePathString(HPATH hpath, LPTSTR *ppszPath)
  847. {
  848. TCHAR rgchPath[MAX_PATH_LEN];
  849. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  850. ASSERT(IS_VALID_WRITE_PTR(ppszPath, LPTSTR));
  851. GetPathString(hpath, rgchPath, ARRAYSIZE(rgchPath));
  852. return(StringCopy(rgchPath, ppszPath));
  853. }
  854. #ifdef DEBUG
  855. /*
  856. ** DebugGetPathString()
  857. **
  858. **
  859. **
  860. ** Arguments:
  861. **
  862. ** Returns:
  863. **
  864. ** Side Effects: none
  865. **
  866. ** N.b., DebugGetPathString() must be non-intrusive.
  867. */
  868. PUBLIC_CODE LPCTSTR DebugGetPathString(HPATH hpath)
  869. {
  870. /* Allow 4 debug paths. */
  871. static TCHAR SrgrgchPaths[][MAX_PATH_LEN] = { TEXT(""), TEXT(""), TEXT(""), TEXT("") };
  872. static UINT SuiPath = 0;
  873. LPTSTR pszPath;
  874. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  875. pszPath = SrgrgchPaths[SuiPath];
  876. DebugGetVolumeRootPath(((PPATH)hpath)->hvol, pszPath, ARRAYSIZE(SrgrchPaths[SuiPath]));
  877. CatPath(pszPath, GetString(((PPATH)hpath)->hsPathSuffix), ARRAYSIZE(SrgrchPaths[SuiPath]));
  878. SuiPath++;
  879. SuiPath %= ARRAY_ELEMENTS(SrgrgchPaths);
  880. return(pszPath);
  881. }
  882. /*
  883. ** GetPathCount()
  884. **
  885. **
  886. **
  887. ** Arguments:
  888. **
  889. ** Returns:
  890. **
  891. ** Side Effects: none
  892. */
  893. PUBLIC_CODE ULONG GetPathCount(HPATHLIST hpl)
  894. {
  895. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  896. return(GetPtrCount(((PCPATHLIST)hpl)->hpa));
  897. }
  898. #endif
  899. /*
  900. ** IsPathVolumeAvailable()
  901. **
  902. **
  903. **
  904. ** Arguments:
  905. **
  906. ** Returns:
  907. **
  908. ** Side Effects: none
  909. */
  910. PUBLIC_CODE BOOL IsPathVolumeAvailable(HPATH hpath)
  911. {
  912. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  913. return(IsVolumeAvailable(((PCPATH)hpath)->hvol));
  914. }
  915. /*
  916. ** GetPathVolumeID()
  917. **
  918. **
  919. **
  920. ** Arguments:
  921. **
  922. ** Returns:
  923. **
  924. ** Side Effects: none
  925. */
  926. PUBLIC_CODE HVOLUMEID GetPathVolumeID(HPATH hpath)
  927. {
  928. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  929. return((HVOLUMEID)hpath);
  930. }
  931. /*
  932. ** MyIsPathOnVolume()
  933. **
  934. **
  935. **
  936. ** Arguments:
  937. **
  938. ** Returns:
  939. **
  940. ** Side Effects: none
  941. **
  942. ** MyIsPathOnVolume() will fail for a new root path alias for a volume. E.g.,
  943. ** if the same net resource is connected to both X: and Y:, MyIsPathOnVolume()
  944. ** will only return TRUE for the drive root path that the net resource was
  945. ** connected to through the given HVOLUME.
  946. */
  947. PUBLIC_CODE BOOL MyIsPathOnVolume(LPCTSTR pcszPath, HPATH hpath)
  948. {
  949. BOOL bResult;
  950. TCHAR rgchVolumeRootPath[MAX_PATH_LEN];
  951. ASSERT(IsFullPath(pcszPath));
  952. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  953. rgchVolumeRootPath[0] = TEXT('\0');
  954. if (IsVolumeAvailable(((PPATH)hpath)->hvol))
  955. {
  956. GetVolumeRootPath(((PPATH)hpath)->hvol, rgchVolumeRootPath, ARRAYSIZE(rgchVolumeRootPath));
  957. bResult = (MyLStrCmpNI(pcszPath, rgchVolumeRootPath,
  958. lstrlen(rgchVolumeRootPath))
  959. == CR_EQUAL);
  960. }
  961. else
  962. {
  963. TRACE_OUT((TEXT("MyIsPathOnVolume(): Failing on unavailable volume %s."),
  964. DebugGetVolumeRootPath(((PPATH)hpath)->hvol, rgchVolumeRootPath,
  965. ARRAYSIZE(rgchVolumeRootPath))));
  966. bResult = FALSE;
  967. }
  968. return(bResult);
  969. }
  970. /*
  971. ** ComparePaths()
  972. **
  973. **
  974. **
  975. ** Arguments:
  976. **
  977. ** Returns:
  978. **
  979. ** Side Effects: none
  980. **
  981. ** PATHs are compared by:
  982. ** 1) volume
  983. ** 2) path suffix
  984. */
  985. PUBLIC_CODE COMPARISONRESULT ComparePaths(HPATH hpath1, HPATH hpath2)
  986. {
  987. COMPARISONRESULT cr;
  988. ASSERT(IS_VALID_HANDLE(hpath1, PATH));
  989. ASSERT(IS_VALID_HANDLE(hpath2, PATH));
  990. /* This comparison works across path lists. */
  991. cr = ComparePathVolumes(hpath1, hpath2);
  992. if (cr == CR_EQUAL)
  993. cr = ComparePathStringsByHandle(((PCPATH)hpath1)->hsPathSuffix,
  994. ((PCPATH)hpath2)->hsPathSuffix);
  995. return(cr);
  996. }
  997. /*
  998. ** ComparePathVolumes()
  999. **
  1000. **
  1001. **
  1002. ** Arguments:
  1003. **
  1004. ** Returns:
  1005. **
  1006. ** Side Effects: none
  1007. */
  1008. PUBLIC_CODE COMPARISONRESULT ComparePathVolumes(HPATH hpath1, HPATH hpath2)
  1009. {
  1010. ASSERT(IS_VALID_HANDLE(hpath1, PATH));
  1011. ASSERT(IS_VALID_HANDLE(hpath2, PATH));
  1012. return(CompareVolumes(((PCPATH)hpath1)->hvol, ((PCPATH)hpath2)->hvol));
  1013. }
  1014. /*
  1015. ** IsPathPrefix()
  1016. **
  1017. ** Determines whether or not one path is a prefix of another.
  1018. **
  1019. ** Arguments: hpathChild - whole path (longer or same length)
  1020. ** hpathParent - prefix path to test (shorter or same length)
  1021. **
  1022. ** Returns: TRUE if the second path is a prefix of the first path. FALSE
  1023. ** if not.
  1024. **
  1025. ** Side Effects: none
  1026. **
  1027. ** Read 'IsPathPrefix(A, B)' as 'Is A in B's subtree?'.
  1028. */
  1029. PUBLIC_CODE BOOL IsPathPrefix(HPATH hpathChild, HPATH hpathParent)
  1030. {
  1031. BOOL bResult;
  1032. ASSERT(IS_VALID_HANDLE(hpathParent, PATH));
  1033. ASSERT(IS_VALID_HANDLE(hpathChild, PATH));
  1034. if (ComparePathVolumes(hpathParent, hpathChild) == CR_EQUAL)
  1035. {
  1036. TCHAR rgchParentSuffix[MAX_PATH_LEN];
  1037. TCHAR rgchChildSuffix[MAX_PATH_LEN];
  1038. int nParentSuffixLen;
  1039. int nChildSuffixLen;
  1040. /* Ignore path roots when comparing path strings. */
  1041. GetPathSuffixString(hpathParent, rgchParentSuffix);
  1042. GetPathSuffixString(hpathChild, rgchChildSuffix);
  1043. /* Only root paths should have no path suffix off the root. */
  1044. nParentSuffixLen = lstrlen(rgchParentSuffix);
  1045. nChildSuffixLen = lstrlen(rgchChildSuffix);
  1046. /*
  1047. * The parent path is a path prefix of the child path iff:
  1048. * 1) The parent's path suffix string is shorter than or the same
  1049. * length as the child's path suffix string.
  1050. * 2) The two path suffix strings match through the length of the
  1051. * parent's path suffix string.
  1052. * 3) The prefix of the child's path suffix string is followed
  1053. * immediately by a null terminator or a path separator.
  1054. */
  1055. bResult = (nChildSuffixLen >= nParentSuffixLen &&
  1056. MyLStrCmpNI(rgchParentSuffix, rgchChildSuffix,
  1057. nParentSuffixLen) == CR_EQUAL &&
  1058. (nChildSuffixLen == nParentSuffixLen || /* same paths */
  1059. ! nParentSuffixLen || /* root parent */
  1060. IS_SLASH(rgchChildSuffix[nParentSuffixLen]))); /* non-root parent */
  1061. }
  1062. else
  1063. bResult = FALSE;
  1064. return(bResult);
  1065. }
  1066. /*
  1067. ** SubtreesIntersect()
  1068. **
  1069. **
  1070. **
  1071. ** Arguments:
  1072. **
  1073. ** Returns:
  1074. **
  1075. ** Side Effects: none
  1076. **
  1077. ** N.b., two subtrees cannot both intersect a third subtree unless they
  1078. ** intersect each other.
  1079. */
  1080. PUBLIC_CODE BOOL SubtreesIntersect(HPATH hpath1, HPATH hpath2)
  1081. {
  1082. ASSERT(IS_VALID_HANDLE(hpath1, PATH));
  1083. ASSERT(IS_VALID_HANDLE(hpath2, PATH));
  1084. return(IsPathPrefix(hpath1, hpath2) ||
  1085. IsPathPrefix(hpath2, hpath1));
  1086. }
  1087. /*
  1088. ** FindEndOfRootSpec()
  1089. **
  1090. ** Finds the end of the root specification in a path string.
  1091. **
  1092. ** Arguments: pcszPath - path to examine for root specification
  1093. ** hpath - handle to PATH that path string was generated from
  1094. **
  1095. ** Returns: pointer to first character after end of root specification
  1096. **
  1097. ** Side Effects: none
  1098. **
  1099. ** Examples:
  1100. **
  1101. ** input path output string
  1102. ** ---------- -------------
  1103. ** c:\ <empty string>
  1104. ** c:\foo foo
  1105. ** c:\foo\bar foo\bar
  1106. ** \\pyrex\user\ <empty string>
  1107. ** \\pyrex\user\foo foo
  1108. ** \\pyrex\user\foo\bar foo\bar
  1109. */
  1110. PUBLIC_CODE LPTSTR FindEndOfRootSpec(LPCTSTR pcszFullPath, HPATH hpath)
  1111. {
  1112. LPCTSTR pcsz;
  1113. UINT ucchPathLen;
  1114. UINT ucchSuffixLen;
  1115. ASSERT(IsCanonicalPath(pcszFullPath));
  1116. ASSERT(IS_VALID_HANDLE(hpath, PATH));
  1117. ucchPathLen = lstrlen(pcszFullPath);
  1118. ucchSuffixLen = lstrlen(GetString(((PCPATH)hpath)->hsPathSuffix));
  1119. pcsz = pcszFullPath + ucchPathLen;
  1120. if (ucchPathLen > ucchSuffixLen)
  1121. pcsz -= ucchSuffixLen;
  1122. else
  1123. /* Assume path is root path. */
  1124. ERROR_OUT((TEXT("FindEndOfRootSpec(): Path suffix %s is longer than full path %s."),
  1125. GetString(((PCPATH)hpath)->hsPathSuffix),
  1126. pcszFullPath));
  1127. ASSERT(IsValidPathSuffix(pcsz));
  1128. return((LPTSTR)pcsz);
  1129. }
  1130. /*
  1131. ** FindPathSuffix()
  1132. **
  1133. **
  1134. **
  1135. ** Arguments:
  1136. **
  1137. ** Returns:
  1138. **
  1139. ** Side Effects: none
  1140. */
  1141. PUBLIC_CODE LPTSTR FindChildPathSuffix(HPATH hpathParent, HPATH hpathChild,
  1142. LPTSTR pszChildSuffixBuf)
  1143. {
  1144. LPCTSTR pcszChildSuffix;
  1145. TCHAR rgchParentSuffix[MAX_PATH_LEN];
  1146. ASSERT(IS_VALID_HANDLE(hpathParent, PATH));
  1147. ASSERT(IS_VALID_HANDLE(hpathChild, PATH));
  1148. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszChildSuffixBuf, STR, MAX_PATH_LEN));
  1149. ASSERT(IsPathPrefix(hpathChild, hpathParent));
  1150. GetPathSuffixString(hpathParent, rgchParentSuffix);
  1151. GetPathSuffixString(hpathChild, pszChildSuffixBuf);
  1152. ASSERT(lstrlen(rgchParentSuffix) <= lstrlen(pszChildSuffixBuf));
  1153. pcszChildSuffix = pszChildSuffixBuf + lstrlen(rgchParentSuffix);
  1154. if (IS_SLASH(*pcszChildSuffix))
  1155. pcszChildSuffix++;
  1156. ASSERT(IsValidPathSuffix(pcszChildSuffix));
  1157. return((LPTSTR)pcszChildSuffix);
  1158. }
  1159. /*
  1160. ** ComparePointers()
  1161. **
  1162. **
  1163. **
  1164. ** Arguments:
  1165. **
  1166. ** Returns:
  1167. **
  1168. ** Side Effects: none
  1169. */
  1170. PUBLIC_CODE COMPARISONRESULT ComparePointers(PCVOID pcv1, PCVOID pcv2)
  1171. {
  1172. COMPARISONRESULT cr;
  1173. /* pcv1 and pcv2 may be any value. */
  1174. if (pcv1 < pcv2)
  1175. cr = CR_FIRST_SMALLER;
  1176. else if (pcv1 > pcv2)
  1177. cr = CR_FIRST_LARGER;
  1178. else
  1179. cr = CR_EQUAL;
  1180. return(cr);
  1181. }
  1182. /*
  1183. ** TWINRESULTFromLastError()
  1184. **
  1185. **
  1186. **
  1187. ** Arguments:
  1188. **
  1189. ** Returns:
  1190. **
  1191. ** Side Effects: none
  1192. */
  1193. PUBLIC_CODE TWINRESULT TWINRESULTFromLastError(TWINRESULT tr)
  1194. {
  1195. switch (GetLastError())
  1196. {
  1197. case ERROR_OUTOFMEMORY:
  1198. tr = TR_OUT_OF_MEMORY;
  1199. break;
  1200. default:
  1201. break;
  1202. }
  1203. return(tr);
  1204. }
  1205. /*
  1206. ** WritePathList()
  1207. **
  1208. **
  1209. **
  1210. ** Arguments:
  1211. **
  1212. ** Returns:
  1213. **
  1214. ** Side Effects: none
  1215. */
  1216. PUBLIC_CODE TWINRESULT WritePathList(HCACHEDFILE hcf, HPATHLIST hpl)
  1217. {
  1218. TWINRESULT tr;
  1219. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1220. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  1221. tr = WriteVolumeList(hcf, ((PCPATHLIST)hpl)->hvl);
  1222. if (tr == TR_SUCCESS)
  1223. {
  1224. tr = WriteStringTable(hcf, ((PCPATHLIST)hpl)->hst);
  1225. if (tr == TR_SUCCESS)
  1226. {
  1227. DWORD dwcbDBPathListHeaderOffset;
  1228. tr = TR_BRIEFCASE_WRITE_FAILED;
  1229. /* Save initial file position. */
  1230. dwcbDBPathListHeaderOffset = GetCachedFilePointerPosition(hcf);
  1231. if (dwcbDBPathListHeaderOffset != INVALID_SEEK_POSITION)
  1232. {
  1233. DBPATHLISTHEADER dbplh;
  1234. /* Leave space for path list header. */
  1235. ZeroMemory(&dbplh, sizeof(dbplh));
  1236. if (WriteToCachedFile(hcf, (PCVOID)&dbplh, sizeof(dbplh), NULL))
  1237. {
  1238. ARRAYINDEX aicPtrs;
  1239. ARRAYINDEX ai;
  1240. LONG lcPaths = 0;
  1241. tr = TR_SUCCESS;
  1242. aicPtrs = GetPtrCount(((PCPATHLIST)hpl)->hpa);
  1243. /* Write all paths. */
  1244. for (ai = 0; ai < aicPtrs; ai++)
  1245. {
  1246. PPATH ppath;
  1247. ppath = GetPtr(((PCPATHLIST)hpl)->hpa, ai);
  1248. /*
  1249. * As a sanity check, don't save any path with a lock count
  1250. * of 0. A 0 lock count implies that the path has not been
  1251. * referenced since it was restored from the database, or
  1252. * something is broken.
  1253. */
  1254. if (ppath->ulcLock > 0)
  1255. {
  1256. tr = WritePath(hcf, ppath);
  1257. if (tr == TR_SUCCESS)
  1258. {
  1259. ASSERT(lcPaths < LONG_MAX);
  1260. lcPaths++;
  1261. }
  1262. else
  1263. break;
  1264. }
  1265. else
  1266. ERROR_OUT((TEXT("WritePathList(): PATH for path %s has 0 lock count and will not be written."),
  1267. DebugGetPathString((HPATH)ppath)));
  1268. }
  1269. /* Save path list header. */
  1270. if (tr == TR_SUCCESS)
  1271. {
  1272. dbplh.lcPaths = lcPaths;
  1273. tr = WriteDBSegmentHeader(hcf, dwcbDBPathListHeaderOffset, &dbplh,
  1274. sizeof(dbplh));
  1275. TRACE_OUT((TEXT("WritePathList(): Wrote %ld paths."),
  1276. dbplh.lcPaths));
  1277. }
  1278. }
  1279. }
  1280. }
  1281. }
  1282. return(tr);
  1283. }
  1284. /*
  1285. ** ReadPathList()
  1286. **
  1287. **
  1288. **
  1289. ** Arguments:
  1290. **
  1291. ** Returns:
  1292. **
  1293. ** Side Effects: none
  1294. */
  1295. PUBLIC_CODE TWINRESULT ReadPathList(HCACHEDFILE hcf, HPATHLIST hpl,
  1296. PHHANDLETRANS phht)
  1297. {
  1298. TWINRESULT tr;
  1299. HHANDLETRANS hhtVolumes;
  1300. ASSERT(IS_VALID_HANDLE(hcf, CACHEDFILE));
  1301. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  1302. ASSERT(IS_VALID_WRITE_PTR(phht, HHANDLETRANS));
  1303. tr = ReadVolumeList(hcf, ((PCPATHLIST)hpl)->hvl, &hhtVolumes);
  1304. if (tr == TR_SUCCESS)
  1305. {
  1306. HHANDLETRANS hhtStrings;
  1307. tr = ReadStringTable(hcf, ((PCPATHLIST)hpl)->hst, &hhtStrings);
  1308. if (tr == TR_SUCCESS)
  1309. {
  1310. DBPATHLISTHEADER dbplh;
  1311. DWORD dwcbRead;
  1312. tr = TR_CORRUPT_BRIEFCASE;
  1313. if (ReadFromCachedFile(hcf, &dbplh, sizeof(dbplh), &dwcbRead) &&
  1314. dwcbRead == sizeof(dbplh))
  1315. {
  1316. HHANDLETRANS hht;
  1317. if (CreateHandleTranslator(dbplh.lcPaths, &hht))
  1318. {
  1319. LONG l;
  1320. tr = TR_SUCCESS;
  1321. TRACE_OUT((TEXT("ReadPathList(): Reading %ld paths."),
  1322. dbplh.lcPaths));
  1323. for (l = 0; l < dbplh.lcPaths; l++)
  1324. {
  1325. tr = ReadPath(hcf, (PPATHLIST)hpl, hhtVolumes, hhtStrings,
  1326. hht);
  1327. if (tr != TR_SUCCESS)
  1328. break;
  1329. }
  1330. if (tr == TR_SUCCESS)
  1331. {
  1332. PrepareForHandleTranslation(hht);
  1333. *phht = hht;
  1334. ASSERT(IS_VALID_HANDLE(hpl, PATHLIST));
  1335. ASSERT(IS_VALID_HANDLE(*phht, HANDLETRANS));
  1336. }
  1337. else
  1338. DestroyHandleTranslator(hht);
  1339. }
  1340. else
  1341. tr = TR_OUT_OF_MEMORY;
  1342. }
  1343. DestroyHandleTranslator(hhtStrings);
  1344. }
  1345. DestroyHandleTranslator(hhtVolumes);
  1346. }
  1347. return(tr);
  1348. }
  1349. /*
  1350. ** IsValidHPATH()
  1351. **
  1352. **
  1353. **
  1354. ** Arguments:
  1355. **
  1356. ** Returns:
  1357. **
  1358. ** Side Effects: none
  1359. */
  1360. PUBLIC_CODE BOOL IsValidHPATH(HPATH hp)
  1361. {
  1362. return(IS_VALID_STRUCT_PTR((PCPATH)hp, CPATH));
  1363. }
  1364. /*
  1365. ** IsValidHVOLUMEID()
  1366. **
  1367. **
  1368. **
  1369. ** Arguments:
  1370. **
  1371. ** Returns:
  1372. **
  1373. ** Side Effects: none
  1374. */
  1375. PUBLIC_CODE BOOL IsValidHVOLUMEID(HVOLUMEID hvid)
  1376. {
  1377. return(IS_VALID_HANDLE((HPATH)hvid, PATH));
  1378. }
  1379. #if defined(DEBUG) || defined(VSTF)
  1380. /*
  1381. ** IsValidHPATHLIST()
  1382. **
  1383. **
  1384. **
  1385. ** Arguments:
  1386. **
  1387. ** Returns:
  1388. **
  1389. ** Side Effects: none
  1390. */
  1391. PUBLIC_CODE BOOL IsValidHPATHLIST(HPATHLIST hpl)
  1392. {
  1393. return(IS_VALID_STRUCT_PTR((PCPATHLIST)hpl, CPATHLIST));
  1394. }
  1395. #endif
  1396. /***************************** Exported Functions ****************************/
  1397. /******************************************************************************
  1398. @doc SYNCENGAPI
  1399. @api TWINRESULT | IsPathOnVolume | Determines whether or not a given path is on
  1400. a given volume.
  1401. @parm PCSTR | pcszPath | A pointer to a string indicating the path to be
  1402. checked.
  1403. @parm HVOLUMEID | hvid | A handle to a volume ID.
  1404. @parm PBOOL | pbOnVolume | A pointer to a BOOL to be filled in with TRUE if the
  1405. given path is on the given volume, or FALSE if not. *pbOnVolume is only valid
  1406. if TR_SUCCESS is returned.
  1407. @rdesc If the volume check was successful, TR_SUCCESS is returned. Otherwise,
  1408. the volume check was not successful, and the return value indicates the error
  1409. that occurred.
  1410. ******************************************************************************/
  1411. SYNCENGAPI TWINRESULT WINAPI IsPathOnVolume(LPCTSTR pcszPath, HVOLUMEID hvid,
  1412. PBOOL pbOnVolume)
  1413. {
  1414. TWINRESULT tr;
  1415. if (BeginExclusiveBriefcaseAccess())
  1416. {
  1417. DebugEntry(IsPathOnVolume);
  1418. #ifdef EXPV
  1419. /* Verify parameters. */
  1420. if (IS_VALID_STRING_PTR(pcszPath, CSTR) &&
  1421. IS_VALID_HANDLE(hvid, VOLUMEID) &&
  1422. IS_VALID_WRITE_PTR(pbOnVolume, BOOL))
  1423. #endif
  1424. {
  1425. TCHAR rgchFullPath[MAX_PATH_LEN];
  1426. LPTSTR pszFileName;
  1427. DWORD dwPathLen;
  1428. dwPathLen = GetFullPathName(pcszPath, ARRAYSIZE(rgchFullPath),
  1429. rgchFullPath, &pszFileName);
  1430. if (dwPathLen > 0 && dwPathLen < ARRAYSIZE(rgchFullPath))
  1431. {
  1432. *pbOnVolume = MyIsPathOnVolume(rgchFullPath, (HPATH)hvid);
  1433. tr = TR_SUCCESS;
  1434. }
  1435. else
  1436. {
  1437. ASSERT(! dwPathLen);
  1438. tr = TR_INVALID_PARAMETER;
  1439. }
  1440. }
  1441. #ifdef EXPV
  1442. else
  1443. tr = TR_INVALID_PARAMETER;
  1444. #endif
  1445. DebugExitTWINRESULT(IsPathOnVolume, tr);
  1446. EndExclusiveBriefcaseAccess();
  1447. }
  1448. else
  1449. tr = TR_REENTERED;
  1450. return(tr);
  1451. }
  1452. /******************************************************************************
  1453. @doc SYNCENGAPI
  1454. @api TWINRESULT | GetVolumeDescription | Retrieves some descriptive information
  1455. for a volume, if that information is available.
  1456. @parm HVOLUMEID | hvid | A handle to a volume ID.
  1457. @parm PVOLUMEDESC | pvoldesc | A pointer to a VOLUMEDESC to be filled in with
  1458. information describing the volume. The ulSize field of the VOLUMEDESC
  1459. structure should be filled in with sizeof(VOLUMEDESC) before calling
  1460. GetVolumeDescription().
  1461. @rdesc If the volume was described successfully, TR_SUCCESS is returned.
  1462. Otherwise, the volume was not described successfully, and the return value
  1463. indicates the error that occurred.
  1464. ******************************************************************************/
  1465. SYNCENGAPI TWINRESULT WINAPI GetVolumeDescription(HVOLUMEID hvid,
  1466. PVOLUMEDESC pvoldesc)
  1467. {
  1468. TWINRESULT tr;
  1469. if (BeginExclusiveBriefcaseAccess())
  1470. {
  1471. DebugEntry(GetVolumeDescription);
  1472. #ifdef EXPV
  1473. /* Verify parameters. */
  1474. if (IS_VALID_HANDLE(hvid, VOLUMEID) &&
  1475. IS_VALID_WRITE_PTR(pvoldesc, VOLUMEDESC) &&
  1476. EVAL(pvoldesc->ulSize == sizeof(*pvoldesc)))
  1477. #endif
  1478. {
  1479. DescribeVolume(((PCPATH)hvid)->hvol, pvoldesc);
  1480. tr = TR_SUCCESS;
  1481. }
  1482. #ifdef EXPV
  1483. else
  1484. tr = TR_INVALID_PARAMETER;
  1485. #endif
  1486. DebugExitTWINRESULT(GetVolumeDescription, tr);
  1487. EndExclusiveBriefcaseAccess();
  1488. }
  1489. else
  1490. tr = TR_REENTERED;
  1491. return(tr);
  1492. }