Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2825 lines
78 KiB

  1. /*
  2. * linkinfo.c - LinkInfo ADT module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "volumeid.h"
  9. #include "cnrlink.h"
  10. #include <uastrfnc.h> // for ALIGNMENT_MACHINE
  11. /* Macros
  12. *********/
  13. /* macros for accessing ILINKINFO data */
  14. #define ILI_Volume_ID_Ptr(pili) \
  15. ((PVOLUMEID)(((PBYTE)(pili)) + (pili)->ucbVolumeIDOffset))
  16. #define ILI_Local_Base_Path_PtrA(pili) \
  17. ((LPSTR)(((PBYTE)(pili)) + (pili)->ucbLocalBasePathOffset))
  18. #define ILI_CNR_Link_Ptr(pili) \
  19. ((PCNRLINK)(((PBYTE)(pili)) + (pili)->ucbCNRLinkOffset))
  20. #define ILI_Common_Path_Suffix_PtrA(pili) \
  21. ((LPSTR)(((PBYTE)(pili)) + (pili)->ucbCommonPathSuffixOffset))
  22. #define ILI_Local_Base_Path_PtrW(pili) \
  23. ((LPWSTR)(((PBYTE)(pili)) + (pili)->ucbLocalBasePathOffsetW))
  24. #define ILI_Common_Path_Suffix_PtrW(pili) \
  25. ((LPWSTR)(((PBYTE)(pili)) + (pili)->ucbCommonPathSuffixOffsetW))
  26. #ifdef UNICODE
  27. #define ILI_Local_Base_Path_Ptr(pili) ILI_Local_Base_Path_PtrW(pili)
  28. #define ILI_Common_Path_Suffix_Ptr(pili) ILI_Common_Path_Suffix_PtrW(pili)
  29. #else
  30. #define ILI_Local_Base_Path_Ptr(pili) ILI_Local_Base_Path_PtrA(pili)
  31. #define ILI_Common_Path_Suffix_Ptr(pili) ILI_Common_Path_Suffix_PtrA(pili)
  32. #endif
  33. /* Types
  34. ********/
  35. /******************************************************************************
  36. @doc LINKINFOAPI
  37. @struct LINKINFO | External definition of LinkInfo structure.
  38. @field UINT | ucbSize | The size of the LINKINFO structure in bytes, including
  39. the ucbSize field. An ILINKINFO structure consists of a header described as
  40. below, followed by variable-length data that is opaque to the caller.
  41. ******************************************************************************/
  42. /*
  43. @doc INTERNAL
  44. @enum ILINKINFOFLAGS | Internal LinkInfo structure flags.
  45. */
  46. typedef enum _ilinkinfoflags
  47. {
  48. /*
  49. @emem ILI_FL_LOCAL_INFO_VALID | If set, volume ID and local path are
  50. valid. If clear, volume ID and local path are not valid.
  51. */
  52. ILI_FL_LOCAL_INFO_VALID = 0x0001,
  53. /*
  54. @emem ILI_FL_REMOTE_INFO_VALID | If set, CNRLink and path suffix are
  55. valid. If clear, CNRLink and path suffix not valid.
  56. */
  57. ILI_FL_REMOTE_INFO_VALID = 0x0002,
  58. /* @emem ALL_ILINKINFO_FLAGS | All internal LinkInfo structure flags. */
  59. ALL_ILINKINFO_FLAGS = (ILI_FL_LOCAL_INFO_VALID |\
  60. ILI_FL_REMOTE_INFO_VALID)
  61. }
  62. ILINKINFOFLAGS;
  63. /*
  64. @doc INTERNAL
  65. @struct ILINKINFO | Internal definition of relocatable, extensible, internal
  66. LinkInfo structure. An ILINKINFO structure may contain an <t IVOLUMEID>
  67. structure and an <t ICNRLINK> structure. An ILINKINFO structure consists of
  68. a header described as below, followed by variable-length data.
  69. */
  70. typedef struct _ilinkinfoA
  71. {
  72. /* @field LINKINFO | li | External <t LINKINFO> sub-structure. */
  73. LINKINFO li;
  74. /*
  75. @field UINT | ucbHeaderSize | Size of the ILINKINFO header structure in
  76. bytes.
  77. */
  78. UINT ucbHeaderSize;
  79. /*
  80. @field DWORD | dwFlags | A bit mask of flags from the <t ILINKINFOFLAGS>
  81. enumeration.
  82. */
  83. DWORD dwFlags;
  84. /*
  85. @field UINT | ucbVolumeIDOffset | Offset in bytes of <t IVOLUMEID>
  86. sub-structure from base of structure.
  87. */
  88. UINT ucbVolumeIDOffset;
  89. /*
  90. @field UINT | ucbLocalBasePathOffset | Offset in bytes of local base path
  91. string from base of structure. The local base path is a valid file
  92. system path. The local base path string + the common path suffix string
  93. form the local path string, which is a valid file system path. The local
  94. base path string refers to the same resource as the CNRLink's CNR name
  95. string.<nl>
  96. Example local base path string: "c:\\work".<nl>
  97. E.g., if local path "c:\\work" is shared as "\\\\fredbird\\work", an
  98. ILinkInfo structure would break local path
  99. "c:\\work\\footwear\\sneakers.doc" up into local base path "c:\\work",
  100. CNRLink CNR name "\\\\fredbird\\work", and common path suffix
  101. "footwear\\sneakers.doc".
  102. */
  103. UINT ucbLocalBasePathOffset;
  104. /*
  105. @field UINT | ucbCNRLinkOffset | Offset in bytes of <t CNRLINK>
  106. sub-structure from base of structure. The file system name of the
  107. CNRLink's CNR name + the common path suffix string form the remote path
  108. string, which is a valid file system path. The CNRLink's CNR name string
  109. refers to the same resource as the local base path string.
  110. */
  111. UINT ucbCNRLinkOffset;
  112. /*
  113. @field UINT | ucbCommonPathSuffixOffset | Offset in bytes of common path
  114. suffix string from base of structure.<nl> Example common path suffix
  115. string: "footwear\\sneakers.doc".
  116. */
  117. UINT ucbCommonPathSuffixOffset;
  118. }
  119. ILINKINFOA;
  120. DECLARE_STANDARD_TYPES(ILINKINFOA);
  121. #ifdef UNICODE
  122. typedef struct _ilinkinfoW
  123. {
  124. /* @field LINKINFO | li | External <t LINKINFO> sub-structure. */
  125. LINKINFO li;
  126. /*
  127. @field UINT | ucbHeaderSize | Size of the ILINKINFO header structure in
  128. bytes.
  129. */
  130. UINT ucbHeaderSize;
  131. /*
  132. @field DWORD | dwFlags | A bit mask of flags from the <t ILINKINFOFLAGS>
  133. enumeration.
  134. */
  135. DWORD dwFlags;
  136. /*
  137. @field UINT | ucbVolumeIDOffset | Offset in bytes of <t IVOLUMEID>
  138. sub-structure from base of structure.
  139. */
  140. UINT ucbVolumeIDOffset;
  141. /*
  142. @field UINT | ucbLocalBasePathOffset | Offset in bytes of local base path
  143. string from base of structure. The local base path is a valid file
  144. system path. The local base path string + the common path suffix string
  145. form the local path string, which is a valid file system path. The local
  146. base path string refers to the same resource as the CNRLink's CNR name
  147. string.<nl>
  148. Example local base path string: "c:\\work".<nl>
  149. E.g., if local path "c:\\work" is shared as "\\\\fredbird\\work", an
  150. ILinkInfo structure would break local path
  151. "c:\\work\\footwear\\sneakers.doc" up into local base path "c:\\work",
  152. CNRLink CNR name "\\\\fredbird\\work", and common path suffix
  153. "footwear\\sneakers.doc".
  154. */
  155. UINT ucbLocalBasePathOffset;
  156. /*
  157. @field UINT | ucbCNRLinkOffset | Offset in bytes of <t CNRLINK>
  158. sub-structure from base of structure. The file system name of the
  159. CNRLink's CNR name + the common path suffix string form the remote path
  160. string, which is a valid file system path. The CNRLink's CNR name string
  161. refers to the same resource as the local base path string.
  162. */
  163. UINT ucbCNRLinkOffset;
  164. /*
  165. @field UINT | ucbCommonPathSuffixOffset | Offset in bytes of common path
  166. suffix string from base of structure.<nl> Example common path suffix
  167. string: "footwear\\sneakers.doc".
  168. */
  169. UINT ucbCommonPathSuffixOffset;
  170. /*
  171. These fields duplicate the above ones except that they are for the unicode
  172. versions of the strings.
  173. */
  174. UINT ucbLocalBasePathOffsetW;
  175. UINT ucbCommonPathSuffixOffsetW;
  176. }
  177. ILINKINFOW;
  178. DECLARE_STANDARD_TYPES(ILINKINFOW);
  179. #endif
  180. #ifdef UNICODE
  181. #define ILINKINFO ILINKINFOW
  182. #define PILINKINFO PILINKINFOW
  183. #define CILINKINFO CILINKINFOW
  184. #define PCILINKINFO PCILINKINFOW
  185. #else
  186. #define ILINKINFO ILINKINFOA
  187. #define PILINKINFO PILINKINFOA
  188. #define CILINKINFO CILINKINFOA
  189. #define PCILINKINFO PCILINKINFOA
  190. #endif
  191. /***************************** Private Functions *****************************/
  192. /* Module Prototypes
  193. ********************/
  194. PRIVATE_CODE BOOL CreateILinkInfo(LPCTSTR, PILINKINFO *);
  195. PRIVATE_CODE BOOL CreateLocalILinkInfo(LPCTSTR, PILINKINFO *);
  196. PRIVATE_CODE BOOL CreateRemoteILinkInfo(LPCTSTR, LPCTSTR, LPCTSTR, PILINKINFO *);
  197. PRIVATE_CODE BOOL UnifyILinkInfo(PCVOLUMEID, UINT, LPCTSTR, PCCNRLINK, UINT, LPCTSTR, PILINKINFO *);
  198. PRIVATE_CODE void DestroyILinkInfo(PILINKINFO);
  199. PRIVATE_CODE BOOL UpdateILinkInfo(PCILINKINFO, LPCTSTR, PDWORD, PILINKINFO *);
  200. PRIVATE_CODE BOOL UseNewILinkInfo(PCILINKINFO, PCILINKINFO);
  201. PRIVATE_CODE BOOL ResolveLocalILinkInfo(PCILINKINFO, LPTSTR, DWORD);
  202. PRIVATE_CODE BOOL ResolveRemoteILinkInfo(PCILINKINFO, LPTSTR, DWORD, HWND, PDWORD);
  203. PRIVATE_CODE BOOL ResolveILinkInfo(PCILINKINFO, LPTSTR, DWORD, HWND, PDWORD);
  204. PRIVATE_CODE BOOL ResolveLocalPathFromServer(PCILINKINFO, LPTSTR, PDWORD);
  205. PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO, LPTSTR);
  206. PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO, LPTSTR);
  207. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoReferents(PCILINKINFO, PCILINKINFO);
  208. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoLocalData(PCILINKINFO, PCILINKINFO);
  209. PRIVATE_CODE COMPARISONRESULT CompareLocalPaths(PCILINKINFO, PCILINKINFO);
  210. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoRemoteData(PCILINKINFO, PCILINKINFO);
  211. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoVolumes(PCILINKINFO, PCILINKINFO);
  212. PRIVATE_CODE BOOL CheckCombinedPathLen(LPCTSTR, LPCTSTR);
  213. PRIVATE_CODE BOOL GetILinkInfoData(PCILINKINFO, LINKINFODATATYPE, PCVOID *);
  214. PRIVATE_CODE BOOL DisconnectILinkInfo(PCILINKINFO);
  215. #if defined(DEBUG) || defined(EXPV)
  216. PRIVATE_CODE BOOL IsValidLINKINFODATATYPE(LINKINFODATATYPE);
  217. #endif
  218. #if defined(DEBUG) || defined(VSTF)
  219. PRIVATE_CODE BOOL CheckILIFlags(PCILINKINFO);
  220. PRIVATE_CODE BOOL CheckILICommonPathSuffix(PCILINKINFO);
  221. PRIVATE_CODE BOOL CheckILILocalInfo(PCILINKINFO);
  222. PRIVATE_CODE BOOL CheckILIRemoteInfo(PCILINKINFO);
  223. PRIVATE_CODE BOOL IsValidPCLINKINFO(PCLINKINFO);
  224. PRIVATE_CODE BOOL IsValidPCILINKINFO(PCILINKINFO);
  225. #endif
  226. #ifdef DEBUG
  227. PRIVATE_CODE void DumpILinkInfo(PCILINKINFO);
  228. #endif
  229. /*
  230. ** CreateILinkInfo()
  231. **
  232. **
  233. **
  234. ** Arguments:
  235. **
  236. ** Returns:
  237. **
  238. ** Side Effects: none
  239. */
  240. PRIVATE_CODE BOOL CreateILinkInfo(LPCTSTR pcszPath, PILINKINFO *ppili)
  241. {
  242. BOOL bResult = FALSE;
  243. TCHAR rgchCanonicalPath[MAX_PATH_LEN];
  244. DWORD dwCanonicalPathFlags;
  245. TCHAR rgchCNRName[MAX_PATH_LEN];
  246. LPTSTR pszRootPathSuffix;
  247. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  248. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  249. if (GetCanonicalPathInfo(pcszPath, rgchCanonicalPath, &dwCanonicalPathFlags,
  250. rgchCNRName, &pszRootPathSuffix))
  251. {
  252. if (IS_FLAG_SET(dwCanonicalPathFlags, GCPI_OFL_REMOTE))
  253. bResult = CreateRemoteILinkInfo(rgchCanonicalPath, rgchCNRName,
  254. pszRootPathSuffix, ppili);
  255. else
  256. bResult = CreateLocalILinkInfo(rgchCanonicalPath, ppili);
  257. }
  258. return(bResult);
  259. }
  260. /*
  261. ** CreateLocalILinkInfo()
  262. **
  263. **
  264. **
  265. ** Arguments:
  266. **
  267. ** Returns:
  268. **
  269. ** Side Effects: none
  270. */
  271. PRIVATE_CODE BOOL CreateLocalILinkInfo(LPCTSTR pcszLocalPath, PILINKINFO *ppili)
  272. {
  273. BOOL bResult;
  274. PVOLUMEID pvolid;
  275. UINT ucbVolumeIDLen;
  276. ASSERT(IsLocalDrivePath(pcszLocalPath));
  277. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  278. bResult = CreateVolumeID(pcszLocalPath, &pvolid, &ucbVolumeIDLen);
  279. if (bResult)
  280. {
  281. PCNRLINK pcnrl;
  282. UINT ucbCNRLinkLen;
  283. TCHAR rgchLocalBasePath[MAX_PATH_LEN];
  284. LPCTSTR pcszCommonPathSuffix;
  285. bResult = CreateLocalCNRLink(pcszLocalPath, &pcnrl, &ucbCNRLinkLen,
  286. rgchLocalBasePath, &pcszCommonPathSuffix);
  287. if (bResult)
  288. {
  289. /* Wrap them up. */
  290. bResult = UnifyILinkInfo(pvolid, ucbVolumeIDLen, rgchLocalBasePath,
  291. pcnrl, ucbCNRLinkLen, pcszCommonPathSuffix,
  292. ppili);
  293. if (ucbCNRLinkLen > 0)
  294. DestroyCNRLink(pcnrl);
  295. }
  296. if (ucbVolumeIDLen > 0)
  297. DestroyVolumeID(pvolid);
  298. }
  299. ASSERT(! bResult ||
  300. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  301. return(bResult);
  302. }
  303. /*
  304. ** CreateRemoteILinkInfo()
  305. **
  306. **
  307. **
  308. ** Arguments:
  309. **
  310. ** Returns:
  311. **
  312. ** Side Effects: none
  313. */
  314. PRIVATE_CODE BOOL CreateRemoteILinkInfo(LPCTSTR pcszRemotePath,
  315. LPCTSTR pcszCNRName,
  316. LPCTSTR pcszRootPathSuffix,
  317. PILINKINFO *ppili)
  318. {
  319. BOOL bResult;
  320. PCNRLINK pcnrl;
  321. UINT ucbCNRLinkLen;
  322. ASSERT(IsCanonicalPath(pcszRemotePath));
  323. ASSERT(IsValidCNRName(pcszCNRName));
  324. ASSERT(IS_VALID_STRING_PTR(pcszRootPathSuffix, CSTR));
  325. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  326. bResult = CreateRemoteCNRLink(pcszRemotePath, pcszCNRName, &pcnrl,
  327. &ucbCNRLinkLen);
  328. if (bResult)
  329. {
  330. /* Wrap it up. */
  331. bResult = UnifyILinkInfo(NULL, 0, EMPTY_STRING, pcnrl, ucbCNRLinkLen,
  332. pcszRootPathSuffix, ppili);
  333. if (EVAL(ucbCNRLinkLen > 0))
  334. DestroyCNRLink(pcnrl);
  335. }
  336. ASSERT(! bResult ||
  337. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  338. return(bResult);
  339. }
  340. /*
  341. ** UnifyILinkInfo()
  342. **
  343. **
  344. **
  345. ** Arguments:
  346. **
  347. ** Returns:
  348. **
  349. ** Side Effects: none
  350. */
  351. PRIVATE_CODE BOOL UnifyILinkInfo(PCVOLUMEID pcvolid, UINT ucbVolumeIDLen,
  352. LPCTSTR pcszLocalBasePath, PCCNRLINK pccnrl,
  353. UINT ucbCNRLinkLen, LPCTSTR pcszCommonPathSuffix,
  354. PILINKINFO *ppili)
  355. {
  356. BOOL bResult;
  357. UINT ucbILinkInfoLen;
  358. UINT ucbDataOffset;
  359. UINT cbAnsiLocalBasePath;
  360. UINT cbAnsiCommonPathSuffix;
  361. #ifdef UNICODE
  362. BOOL bUnicode;
  363. UINT cchChars;
  364. CHAR szAnsiLocalBasePath[MAX_PATH*2];
  365. CHAR szAnsiCommonPathSuffix[MAX_PATH*2];
  366. UINT cbWideLocalBasePath;
  367. UINT cbWideCommonPathSuffix;
  368. UINT cbChars;
  369. #endif
  370. ASSERT(! ucbVolumeIDLen ||
  371. (IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID) &&
  372. IsDrivePath(pcszLocalBasePath)));
  373. ASSERT(! ucbCNRLinkLen ||
  374. IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  375. ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
  376. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  377. #ifdef UNICODE
  378. bUnicode = FALSE;
  379. /*
  380. ** Convert the common-path string from UNICODE->ansi and back again
  381. ** to determine if the string contains any non-ansi characters. If no
  382. ** characters are lost in the conversion then the string contains only
  383. ** ansi chars.
  384. */
  385. cbAnsiCommonPathSuffix = WideCharToMultiByte(CP_ACP, 0,
  386. pcszCommonPathSuffix, -1,
  387. szAnsiCommonPathSuffix, ARRAYSIZE(szAnsiCommonPathSuffix),
  388. 0, 0);
  389. if ( cbAnsiCommonPathSuffix == 0 )
  390. {
  391. bUnicode = FALSE;
  392. }
  393. else
  394. {
  395. WCHAR szWideCommonPathSuffix[MAX_PATH];
  396. cbChars = MultiByteToWideChar(CP_ACP, 0,
  397. szAnsiCommonPathSuffix, -1,
  398. szWideCommonPathSuffix, MAX_PATH);
  399. if ( cbChars == 0 || lstrcmp(pcszCommonPathSuffix,szWideCommonPathSuffix) != 0 )
  400. {
  401. bUnicode = TRUE;
  402. }
  403. }
  404. if (ucbVolumeIDLen > 0)
  405. {
  406. /*
  407. ** Convert the localbase-path string from UNICODE->ansi and back again
  408. ** to determine if the string contains any non-ansi characters. If no
  409. ** characters are lost in the conversion then the string contains only
  410. ** ansi chars.
  411. */
  412. cbAnsiLocalBasePath = WideCharToMultiByte(CP_ACP, 0,
  413. pcszLocalBasePath, -1,
  414. szAnsiLocalBasePath, MAX_PATH*2,
  415. 0, 0);
  416. if ( cbAnsiLocalBasePath == 0 )
  417. {
  418. bUnicode = FALSE;
  419. }
  420. else
  421. {
  422. WCHAR szWideLocalBasePath[MAX_PATH];
  423. cchChars = MultiByteToWideChar(CP_ACP, 0,
  424. szAnsiLocalBasePath, -1,
  425. szWideLocalBasePath, ARRAYSIZE(szWideLocalBasePath));
  426. if ( cchChars == 0 || lstrcmp(pcszLocalBasePath,szWideLocalBasePath) != 0 )
  427. {
  428. bUnicode = TRUE;
  429. }
  430. }
  431. }
  432. else
  433. {
  434. cbAnsiLocalBasePath = 0;
  435. }
  436. if ( bUnicode )
  437. {
  438. ucbDataOffset = SIZEOF(ILINKINFOW);
  439. /* (+ 1) for null terminator. */
  440. cbWideCommonPathSuffix = (lstrlen(pcszCommonPathSuffix) + 1) * sizeof(TCHAR);
  441. if (ucbVolumeIDLen > 0)
  442. cbWideLocalBasePath = (lstrlen(pcszLocalBasePath) + 1) * sizeof(TCHAR);
  443. else
  444. cbWideLocalBasePath = 0;
  445. }
  446. else
  447. {
  448. ucbDataOffset = SIZEOF(ILINKINFOA);
  449. cbWideCommonPathSuffix = 0;
  450. cbWideLocalBasePath = 0;
  451. }
  452. ucbILinkInfoLen = ucbDataOffset +
  453. ucbVolumeIDLen +
  454. cbAnsiLocalBasePath;
  455. if ( bUnicode && ucbVolumeIDLen > 0 )
  456. {
  457. ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
  458. ucbILinkInfoLen += cbWideLocalBasePath;
  459. }
  460. if ( ucbCNRLinkLen > 0 )
  461. {
  462. ucbILinkInfoLen = ALIGN_DWORD_CNT(ucbILinkInfoLen);
  463. ucbILinkInfoLen += ucbCNRLinkLen;
  464. }
  465. ucbILinkInfoLen += cbAnsiCommonPathSuffix;
  466. if ( bUnicode )
  467. {
  468. ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
  469. ucbILinkInfoLen += cbWideCommonPathSuffix;
  470. }
  471. #else
  472. /* Calculate total length. */
  473. /* Assume we don't overflow ucbILinkInfoLen here. */
  474. /*
  475. * Base structure size plus common path suffix length. (+ 1) for null
  476. * terminator.
  477. */
  478. cbAnsiCommonPathSuffix = lstrlen(pcszCommonPathSuffix) + 1;
  479. ucbILinkInfoLen = SIZEOF(**ppili) +
  480. cbAnsiCommonPathSuffix;
  481. /* Plus size of local information. */
  482. if (ucbVolumeIDLen > 0)
  483. {
  484. /* (+ 1) for null terminator. */
  485. cbAnsiLocalBasePath = lstrlen(pcszLocalBasePath) + 1;
  486. ucbILinkInfoLen += ucbVolumeIDLen +
  487. cbAnsiLocalBasePath;
  488. }
  489. /* Plus size of remote information. */
  490. if (ucbCNRLinkLen > 0)
  491. /* (+ 1) for null terminator. */
  492. ucbILinkInfoLen += ucbCNRLinkLen;
  493. ucbDataOffset = SIZEOF(**ppili);
  494. #endif
  495. /* Try to allocate a container. */
  496. bResult = AllocateMemory(ucbILinkInfoLen, ppili);
  497. if (bResult)
  498. {
  499. (*ppili)->li.ucbSize = ucbILinkInfoLen;
  500. (*ppili)->ucbHeaderSize = ucbDataOffset;
  501. (*ppili)->dwFlags = 0;
  502. /* Do we have local information? */
  503. if (ucbVolumeIDLen > 0)
  504. {
  505. /* Yes. Add it to the structure. */
  506. ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID));
  507. ASSERT(IsDrivePath(pcszLocalBasePath));
  508. /* Append local volume ID. */
  509. (*ppili)->ucbVolumeIDOffset = ucbDataOffset;
  510. CopyMemory(ILI_Volume_ID_Ptr(*ppili), pcvolid, ucbVolumeIDLen);
  511. ucbDataOffset += ucbVolumeIDLen;
  512. /* Append local path. */
  513. (*ppili)->ucbLocalBasePathOffset = ucbDataOffset;
  514. #ifdef UNICODE
  515. lstrcpyA(ILI_Local_Base_Path_PtrA(*ppili), szAnsiLocalBasePath);
  516. ucbDataOffset += cbAnsiLocalBasePath;
  517. if ( bUnicode )
  518. {
  519. ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
  520. (*ppili)->ucbLocalBasePathOffsetW = ucbDataOffset;
  521. lstrcpy(ILI_Local_Base_Path_PtrW(*ppili), pcszLocalBasePath);
  522. ucbDataOffset += cbWideLocalBasePath;
  523. }
  524. #else
  525. lstrcpy(ILI_Local_Base_Path_Ptr(*ppili), pcszLocalBasePath);
  526. ucbDataOffset += cbAnsiLocalBasePath;
  527. #endif
  528. SET_FLAG((*ppili)->dwFlags, ILI_FL_LOCAL_INFO_VALID);
  529. }
  530. /* Do we have remote information? */
  531. if (ucbCNRLinkLen > 0)
  532. {
  533. ucbDataOffset = ALIGN_DWORD_CNT(ucbDataOffset);
  534. /* Yes. Add it to the structure. */
  535. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  536. /* Append CNR link. */
  537. (*ppili)->ucbCNRLinkOffset = ucbDataOffset;
  538. CopyMemory(ILI_CNR_Link_Ptr(*ppili), pccnrl, ucbCNRLinkLen);
  539. ucbDataOffset += ucbCNRLinkLen;
  540. SET_FLAG((*ppili)->dwFlags, ILI_FL_REMOTE_INFO_VALID);
  541. }
  542. /* Append common path suffix. */
  543. ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
  544. (*ppili)->ucbCommonPathSuffixOffset = ucbDataOffset;
  545. #ifdef UNICODE
  546. lstrcpyA(ILI_Common_Path_Suffix_PtrA(*ppili), szAnsiCommonPathSuffix);
  547. ucbDataOffset += cbAnsiCommonPathSuffix;
  548. if ( bUnicode )
  549. {
  550. ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
  551. (*ppili)->ucbCommonPathSuffixOffsetW = ucbDataOffset;
  552. lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
  553. ucbDataOffset += cbWideCommonPathSuffix;
  554. }
  555. #else /* UNICODE */
  556. lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
  557. #ifdef DEBUG
  558. /*
  559. ** NOTE: This same increment was present above in the UNICODE section
  560. ** enclosed in an #ifdef DEBUG block.
  561. ** It was causing the assertion below (ucbDataOffset == ucbILinkInfoLen)
  562. ** to fail. I have left stmt instance in the ansi build untouched.
  563. ** If the assertion fails in the ansi build you should
  564. ** try removing this next statement. [brianau - 4/15/99]
  565. */
  566. ucbDataOffset += cbAnsiCommonPathSuffix;
  567. #endif
  568. #endif
  569. /* Do all the calculated lengths match? */
  570. // ASSERT(ucbDataOffset == (*ppili)->li.ucbSize);
  571. ASSERT(ucbDataOffset == ucbILinkInfoLen);
  572. }
  573. ASSERT(! bResult ||
  574. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  575. return(bResult);
  576. }
  577. /*
  578. ** DestroyILinkInfo()
  579. **
  580. **
  581. **
  582. ** Arguments:
  583. **
  584. ** Returns:
  585. **
  586. ** Side Effects: none
  587. */
  588. PRIVATE_CODE void DestroyILinkInfo(PILINKINFO pili)
  589. {
  590. ASSERT(IS_VALID_STRUCT_PTR(pili, CILINKINFO));
  591. FreeMemory(pili);
  592. return;
  593. }
  594. /*
  595. ** UpdateILinkInfo()
  596. **
  597. **
  598. **
  599. ** Arguments:
  600. **
  601. ** Returns:
  602. **
  603. ** Side Effects: none
  604. **
  605. ** An ILinkInfo structure is updated in the following cases:
  606. **
  607. ** local information:
  608. **
  609. ** 1) the local path has changed
  610. ** 2) remote information is available for the local path
  611. **
  612. ** remote information:
  613. **
  614. ** 3) the remote information is local to this machine, and local information
  615. ** is available for the remote path
  616. */
  617. PRIVATE_CODE BOOL UpdateILinkInfo(PCILINKINFO pcili, LPCTSTR pcszResolvedPath,
  618. PDWORD pdwOutFlags, PILINKINFO *ppiliUpdated)
  619. {
  620. BOOL bResult;
  621. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  622. ASSERT(IS_VALID_STRING_PTR(pcszResolvedPath, CSTR));
  623. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  624. ASSERT(IS_VALID_WRITE_PTR(ppiliUpdated, PILINKINFO));
  625. *pdwOutFlags = 0;
  626. bResult = CreateILinkInfo(pcszResolvedPath, ppiliUpdated);
  627. if (bResult)
  628. {
  629. if (UseNewILinkInfo(pcili, *ppiliUpdated))
  630. {
  631. SET_FLAG(*pdwOutFlags, RLI_OFL_UPDATED);
  632. WARNING_OUT((TEXT("UpdateILinkInfo(): Updating ILinkInfo for path %s."),
  633. pcszResolvedPath));
  634. }
  635. }
  636. ASSERT(! bResult ||
  637. (IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
  638. IS_VALID_STRUCT_PTR(*ppiliUpdated, CILINKINFO)));
  639. return(bResult);
  640. }
  641. /*
  642. ** UseNewILinkInfo()
  643. **
  644. **
  645. **
  646. ** Arguments:
  647. **
  648. ** Returns: TRUE if the new ILinkInfo structure contains more or
  649. ** different information than the old ILinkInfo structure.
  650. **
  651. ** Side Effects: none
  652. */
  653. PRIVATE_CODE BOOL UseNewILinkInfo(PCILINKINFO pciliOld, PCILINKINFO pciliNew)
  654. {
  655. BOOL bUpdate = FALSE;
  656. ASSERT(IS_VALID_STRUCT_PTR(pciliOld, CILINKINFO));
  657. ASSERT(IS_VALID_STRUCT_PTR(pciliNew, CILINKINFO));
  658. /* Does the new ILinkInfo structure contain local information? */
  659. if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  660. {
  661. /* Yes. Does the old ILinkInfo structure contain local information? */
  662. if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  663. /*
  664. * Yes. Update the old ILinkInfo structure if local information
  665. * differs.
  666. */
  667. bUpdate = (CompareILinkInfoLocalData(pciliOld, pciliNew) != CR_EQUAL);
  668. else
  669. /* No. Update the old ILinkInfo structure. */
  670. bUpdate = TRUE;
  671. }
  672. else
  673. /* No. Do not update the old ILinkInfo structure. */
  674. bUpdate = FALSE;
  675. /*
  676. * Do we already need to update the old ILinkInfo structure based on local
  677. * information comparison?
  678. */
  679. if (! bUpdate)
  680. {
  681. /* No. Compare remote information. */
  682. /* Does the new ILinkInfo structure contain remote information? */
  683. if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  684. {
  685. /*
  686. * Yes. Does the old ILinkInfo structure contain remote information?
  687. */
  688. if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  689. /*
  690. * Yes. Update the old ILinkInfo structure if remote information
  691. * differs.
  692. */
  693. bUpdate = (CompareILinkInfoRemoteData(pciliOld, pciliNew)
  694. != CR_EQUAL);
  695. else
  696. /* No. Update the old ILinkInfo structure. */
  697. bUpdate = TRUE;
  698. }
  699. }
  700. return(bUpdate);
  701. }
  702. /*
  703. ** ResolveLocalILinkInfo()
  704. **
  705. **
  706. **
  707. ** Arguments:
  708. **
  709. ** Returns:
  710. **
  711. ** Side Effects: none
  712. */
  713. PRIVATE_CODE BOOL ResolveLocalILinkInfo(PCILINKINFO pcili,
  714. LPTSTR pszResolvedPathBuf,
  715. DWORD dwInFlags)
  716. {
  717. BOOL bResult;
  718. DWORD dwLocalSearchFlags;
  719. TCHAR rgchLocalPath[MAX_PATH_LEN];
  720. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  721. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  722. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
  723. /* Search for local path. */
  724. TRACE_OUT((TEXT("ResolveLocalILinkInfo(): Attempting to resolve LinkInfo locally.")));
  725. GetLocalPathFromILinkInfo(pcili, rgchLocalPath);
  726. if (IS_FLAG_SET(dwInFlags, RLI_IFL_LOCAL_SEARCH))
  727. dwLocalSearchFlags = SFLP_IFL_LOCAL_SEARCH;
  728. else
  729. dwLocalSearchFlags = 0;
  730. bResult = SearchForLocalPath(ILI_Volume_ID_Ptr(pcili), rgchLocalPath,
  731. dwLocalSearchFlags, pszResolvedPathBuf);
  732. ASSERT(! bResult ||
  733. EVAL(IsCanonicalPath(pszResolvedPathBuf)));
  734. return(bResult);
  735. }
  736. /*
  737. ** ResolveRemoteILinkInfo()
  738. **
  739. **
  740. **
  741. ** Arguments:
  742. **
  743. ** Returns:
  744. **
  745. ** Side Effects: none
  746. */
  747. PRIVATE_CODE BOOL ResolveRemoteILinkInfo(PCILINKINFO pcili,
  748. LPTSTR pszResolvedPathBuf,
  749. DWORD dwInFlags, HWND hwndOwner,
  750. PDWORD pdwOutFlags)
  751. {
  752. BOOL bResult;
  753. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  754. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  755. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
  756. ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
  757. IS_VALID_HANDLE(hwndOwner, WND));
  758. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  759. ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_TEMPORARY) ||
  760. IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT));
  761. TRACE_OUT((TEXT("ResolveRemoteILinkInfo(): Attempting to resolve LinkInfo remotely.")));
  762. /* Connect if requested. */
  763. if (IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT))
  764. {
  765. DWORD dwConnectInFlags;
  766. DWORD dwConnectOutFlags;
  767. dwConnectInFlags = 0;
  768. if (IS_FLAG_SET(dwInFlags, RLI_IFL_TEMPORARY))
  769. dwConnectInFlags = CONNECT_TEMPORARY;
  770. if (IS_FLAG_SET(dwInFlags, RLI_IFL_ALLOW_UI))
  771. SET_FLAG(dwConnectInFlags, CONNECT_INTERACTIVE);
  772. if (IS_FLAG_SET(dwInFlags, RLI_IFL_REDIRECT))
  773. SET_FLAG(dwConnectInFlags, CONNECT_REDIRECT);
  774. bResult = ConnectToCNR(ILI_CNR_Link_Ptr(pcili), dwConnectInFlags,
  775. hwndOwner, pszResolvedPathBuf,
  776. &dwConnectOutFlags);
  777. if (bResult)
  778. {
  779. #ifdef UNICODE
  780. WCHAR szWideCommonPathSuffix[MAX_PATH];
  781. LPWSTR pszWideCommonPathSuffix;
  782. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  783. {
  784. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  785. MultiByteToWideChar(CP_ACP, 0,
  786. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  787. szWideCommonPathSuffix, MAX_PATH);
  788. }
  789. else
  790. {
  791. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  792. }
  793. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
  794. #else
  795. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
  796. #endif
  797. if (IS_FLAG_SET(dwConnectOutFlags, CONNECT_REFCOUNT))
  798. {
  799. ASSERT(IS_FLAG_CLEAR(dwConnectOutFlags, CONNECT_LOCALDRIVE));
  800. SET_FLAG(*pdwOutFlags, RLI_OFL_DISCONNECT);
  801. }
  802. }
  803. }
  804. else
  805. {
  806. /*
  807. * It's ok that IsCNRAvailable() and GetRemotePathFromILinkInfo() are
  808. * broken for NPs whose CNR names are not valid file system root paths.
  809. *
  810. * For NPs whose CNR names are valid file system root paths,
  811. * IsCNRAvailable() will succeed or fail, and
  812. * GetRemotePathFromILinkInfo() will be called only on success.
  813. *
  814. * For NPs whose CNR names are not valid file system root paths,
  815. * IsCNRAvailable() will fail and GetRemotePathFromILinkInfo() will not
  816. * be called.
  817. */
  818. bResult = IsCNRAvailable(ILI_CNR_Link_Ptr(pcili));
  819. if (bResult)
  820. GetRemotePathFromILinkInfo(pcili, pszResolvedPathBuf);
  821. }
  822. ASSERT(! bResult ||
  823. (EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
  824. FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS)));
  825. return(bResult);
  826. }
  827. /*
  828. ** ResolveILinkInfo()
  829. **
  830. **
  831. **
  832. ** Arguments:
  833. **
  834. ** Returns:
  835. **
  836. ** Side Effects: none
  837. */
  838. PRIVATE_CODE BOOL ResolveILinkInfo(PCILINKINFO pcili, LPTSTR pszResolvedPathBuf,
  839. DWORD dwInFlags, HWND hwndOwner,
  840. PDWORD pdwOutFlags)
  841. {
  842. BOOL bResult;
  843. BOOL bLocalInfoValid;
  844. BOOL bRemoteInfoValid;
  845. BOOL bLocalShare;
  846. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  847. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  848. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
  849. ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
  850. IS_VALID_HANDLE(hwndOwner, WND));
  851. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  852. *pdwOutFlags = 0;
  853. /* Describe LinkInfo contents. */
  854. bRemoteInfoValid = IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID);
  855. bLocalInfoValid = IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID);
  856. ASSERT(bLocalInfoValid || bRemoteInfoValid);
  857. /*
  858. * RAIDRAID: (15703) We will resolve to the wrong local path for a share
  859. * that has been moved to another path here.
  860. */
  861. bLocalShare = FALSE;
  862. if (bRemoteInfoValid)
  863. {
  864. DWORD dwLocalShareFlags;
  865. /* Ask the server for the local path. */
  866. bResult = ResolveLocalPathFromServer(pcili, pszResolvedPathBuf,
  867. &dwLocalShareFlags);
  868. if (IS_FLAG_SET(dwLocalShareFlags, CNR_FL_LOCAL))
  869. bLocalShare = TRUE;
  870. if (bResult)
  871. {
  872. ASSERT(IS_FLAG_SET(dwLocalShareFlags, CNR_FL_LOCAL));
  873. TRACE_OUT((TEXT("ResolveILinkInfo(): Resolved local path from server.")));
  874. }
  875. }
  876. else
  877. /* Can't tell if the referent is local or not. */
  878. bResult = FALSE;
  879. if (! bResult)
  880. {
  881. /* Try local path. */
  882. if (bLocalInfoValid)
  883. bResult = ResolveLocalILinkInfo(pcili, pszResolvedPathBuf, dwInFlags);
  884. if (! bResult)
  885. {
  886. /* Try remote path. */
  887. if (bRemoteInfoValid && ! bLocalShare)
  888. bResult = ResolveRemoteILinkInfo(pcili, pszResolvedPathBuf,
  889. dwInFlags, hwndOwner,
  890. pdwOutFlags);
  891. }
  892. }
  893. ASSERT(! bResult ||
  894. (EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
  895. FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS)));
  896. return(bResult);
  897. }
  898. /*
  899. ** ResolveLocalPathFromServer()
  900. **
  901. **
  902. **
  903. ** Arguments:
  904. **
  905. ** Returns:
  906. **
  907. ** Side Effects: none
  908. */
  909. PRIVATE_CODE BOOL ResolveLocalPathFromServer(PCILINKINFO pcili,
  910. LPTSTR pszResolvedPathBuf,
  911. PDWORD pdwOutFlags)
  912. {
  913. BOOL bResult;
  914. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  915. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  916. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  917. ASSERT(IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID));
  918. /* Try to get local path from server. */
  919. bResult = GetLocalPathFromCNRLink(ILI_CNR_Link_Ptr(pcili),
  920. pszResolvedPathBuf, pdwOutFlags);
  921. if (bResult)
  922. {
  923. #ifdef UNICODE
  924. WCHAR szWideCommonPathSuffix[MAX_PATH];
  925. LPWSTR pszWideCommonPathSuffix;
  926. ASSERT(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL));
  927. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  928. {
  929. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  930. MultiByteToWideChar(CP_ACP, 0,
  931. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  932. szWideCommonPathSuffix, MAX_PATH);
  933. }
  934. else
  935. {
  936. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  937. }
  938. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
  939. #else
  940. ASSERT(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL));
  941. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
  942. #endif
  943. }
  944. ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) &&
  945. (! bResult ||
  946. (EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) &&
  947. EVAL(IsLocalDrivePath(pszResolvedPathBuf)))));
  948. return(bResult);
  949. }
  950. /*
  951. ** GetLocalPathFromILinkInfo()
  952. **
  953. **
  954. **
  955. ** Arguments:
  956. **
  957. ** Returns:
  958. **
  959. ** Side Effects: none
  960. */
  961. PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO pcili,
  962. LPTSTR pszResolvedPathBuf)
  963. {
  964. #ifdef UNICODE
  965. WCHAR szWideLocalBasePath[MAX_PATH];
  966. LPWSTR pszWideLocalBasePath;
  967. WCHAR szWideCommonPathSuffix[MAX_PATH];
  968. LPWSTR pszWideCommonPathSuffix;
  969. #endif
  970. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  971. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  972. #ifdef UNICODE
  973. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  974. {
  975. pszWideLocalBasePath = szWideLocalBasePath;
  976. MultiByteToWideChar(CP_ACP, 0,
  977. ILI_Local_Base_Path_PtrA(pcili), -1,
  978. szWideLocalBasePath, MAX_PATH);
  979. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  980. MultiByteToWideChar(CP_ACP, 0,
  981. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  982. szWideCommonPathSuffix, MAX_PATH);
  983. }
  984. else
  985. {
  986. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  987. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  988. }
  989. lstrcpy(pszResolvedPathBuf, pszWideLocalBasePath);
  990. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
  991. #else
  992. lstrcpy(pszResolvedPathBuf, ILI_Local_Base_Path_Ptr(pcili));
  993. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
  994. #endif
  995. ASSERT(lstrlen(pszResolvedPathBuf) < MAX_PATH_LEN);
  996. ASSERT(IsDrivePath(pszResolvedPathBuf));
  997. return;
  998. }
  999. /*
  1000. ** GetRemotePathFromILinkInfo()
  1001. **
  1002. **
  1003. **
  1004. ** Arguments:
  1005. **
  1006. ** Returns:
  1007. **
  1008. ** Side Effects: none
  1009. */
  1010. PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO pcili,
  1011. LPTSTR pszResolvedPathBuf)
  1012. {
  1013. #ifdef UNICODE
  1014. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1015. LPWSTR pszWideCommonPathSuffix;
  1016. #endif
  1017. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1018. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
  1019. /* It's ok that this is broken for non-UNC CNR names. */
  1020. GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), pszResolvedPathBuf);
  1021. #ifdef UNICODE
  1022. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1023. {
  1024. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1025. MultiByteToWideChar(CP_ACP, 0,
  1026. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1027. szWideCommonPathSuffix, MAX_PATH);
  1028. }
  1029. else
  1030. {
  1031. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1032. }
  1033. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
  1034. #else
  1035. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
  1036. #endif
  1037. return;
  1038. }
  1039. /*
  1040. ** CompareILinkInfoReferents()
  1041. **
  1042. ** Compares the referents of two ILINKINFO structures.
  1043. **
  1044. ** Arguments:
  1045. **
  1046. ** Returns:
  1047. **
  1048. ** Side Effects: none
  1049. **
  1050. ** Comparison is performed on ILINKINFO data in only one of the following ways
  1051. ** in the following order:
  1052. **
  1053. ** 1) local data compared with local data
  1054. ** 2) remote data compared with remote data
  1055. ** 3) local data only < remote data only
  1056. */
  1057. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoReferents(PCILINKINFO pciliFirst,
  1058. PCILINKINFO pciliSecond)
  1059. {
  1060. COMPARISONRESULT cr;
  1061. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1062. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1063. /*
  1064. * We can't just perform a binary comparison of the two ILinkInfos here. We
  1065. * may have two LinkInfos that refer to the same path, but differ in case on
  1066. * a non-case-sensitive file system.
  1067. */
  1068. /* Compare ILinkInfos by local or remote data. */
  1069. if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID) &&
  1070. IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1071. /* Compare local data. */
  1072. cr = CompareILinkInfoLocalData(pciliFirst, pciliSecond);
  1073. else if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_REMOTE_INFO_VALID) &&
  1074. IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1075. /* Compare remote data. */
  1076. cr = CompareILinkInfoRemoteData(pciliFirst, pciliSecond);
  1077. else
  1078. {
  1079. /*
  1080. * One contains only valid local information and the other contains only
  1081. * valid remote information.
  1082. */
  1083. ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
  1084. (pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
  1085. /* By fiat, local only < remote only. */
  1086. if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1087. cr = CR_FIRST_SMALLER;
  1088. else
  1089. cr = CR_FIRST_LARGER;
  1090. }
  1091. ASSERT(IsValidCOMPARISONRESULT(cr));
  1092. return(cr);
  1093. }
  1094. /*
  1095. ** CompareILinkInfoLocalData()
  1096. **
  1097. **
  1098. **
  1099. ** Arguments:
  1100. **
  1101. ** Returns:
  1102. **
  1103. ** Side Effects: none
  1104. **
  1105. ** Local ILinkInfo data is compared in the following order:
  1106. **
  1107. ** 1) volume ID
  1108. ** 2) sub path from root
  1109. */
  1110. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoLocalData(PCILINKINFO pciliFirst,
  1111. PCILINKINFO pciliSecond)
  1112. {
  1113. COMPARISONRESULT cr;
  1114. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1115. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1116. cr = CompareVolumeIDs(ILI_Volume_ID_Ptr(pciliFirst),
  1117. ILI_Volume_ID_Ptr(pciliSecond));
  1118. if (cr == CR_EQUAL)
  1119. cr = CompareLocalPaths(pciliFirst, pciliSecond);
  1120. ASSERT(IsValidCOMPARISONRESULT(cr));
  1121. return(cr);
  1122. }
  1123. /*
  1124. ** CompareLocalPaths()
  1125. **
  1126. **
  1127. **
  1128. ** Arguments:
  1129. **
  1130. ** Returns:
  1131. **
  1132. ** Side Effects: none
  1133. */
  1134. PRIVATE_CODE COMPARISONRESULT CompareLocalPaths(PCILINKINFO pciliFirst,
  1135. PCILINKINFO pciliSecond)
  1136. {
  1137. COMPARISONRESULT cr;
  1138. TCHAR rgchFirstLocalPath[MAX_PATH_LEN];
  1139. TCHAR rgchSecondLocalPath[MAX_PATH_LEN];
  1140. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1141. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1142. GetLocalPathFromILinkInfo(pciliFirst, rgchFirstLocalPath);
  1143. GetLocalPathFromILinkInfo(pciliSecond, rgchSecondLocalPath);
  1144. cr = ComparePathStrings(rgchFirstLocalPath, rgchSecondLocalPath);
  1145. ASSERT(IsValidCOMPARISONRESULT(cr));
  1146. return(cr);
  1147. }
  1148. /*
  1149. ** CompareILinkInfoRemoteData()
  1150. **
  1151. **
  1152. **
  1153. ** Arguments:
  1154. **
  1155. ** Returns:
  1156. **
  1157. ** Side Effects: none
  1158. */
  1159. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoRemoteData(PCILINKINFO pciliFirst,
  1160. PCILINKINFO pciliSecond)
  1161. {
  1162. COMPARISONRESULT cr;
  1163. #ifdef UNICODE
  1164. WCHAR szWideCommonPathSuffixFirst[MAX_PATH];
  1165. WCHAR szWideCommonPathSuffixSecond[MAX_PATH];
  1166. LPWSTR pszWideCommonPathSuffixFirst;
  1167. LPWSTR pszWideCommonPathSuffixSecond;
  1168. #endif
  1169. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1170. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1171. cr = CompareCNRLinks(ILI_CNR_Link_Ptr(pciliFirst),
  1172. ILI_CNR_Link_Ptr(pciliSecond));
  1173. #ifdef UNICODE
  1174. if (pciliFirst->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1175. {
  1176. pszWideCommonPathSuffixFirst = szWideCommonPathSuffixFirst;
  1177. MultiByteToWideChar(CP_ACP, 0,
  1178. ILI_Common_Path_Suffix_PtrA(pciliFirst), -1,
  1179. szWideCommonPathSuffixFirst, MAX_PATH);
  1180. }
  1181. else
  1182. {
  1183. pszWideCommonPathSuffixFirst = ILI_Common_Path_Suffix_Ptr(pciliFirst);
  1184. }
  1185. if (pciliSecond->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1186. {
  1187. pszWideCommonPathSuffixSecond = szWideCommonPathSuffixSecond;
  1188. MultiByteToWideChar(CP_ACP, 0,
  1189. ILI_Common_Path_Suffix_PtrA(pciliSecond), -1,
  1190. szWideCommonPathSuffixSecond, MAX_PATH);
  1191. }
  1192. else
  1193. {
  1194. pszWideCommonPathSuffixSecond = ILI_Common_Path_Suffix_Ptr(pciliSecond);
  1195. }
  1196. #else
  1197. if (cr == CR_EQUAL)
  1198. cr = ComparePathStrings(ILI_Common_Path_Suffix_Ptr(pciliFirst),
  1199. ILI_Common_Path_Suffix_Ptr(pciliSecond));
  1200. #endif
  1201. ASSERT(IsValidCOMPARISONRESULT(cr));
  1202. return(cr);
  1203. }
  1204. /*
  1205. ** CompareILinkInfoVolumes()
  1206. **
  1207. **
  1208. **
  1209. ** Arguments:
  1210. **
  1211. ** Returns:
  1212. **
  1213. ** Side Effects: none
  1214. */
  1215. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoVolumes(PCILINKINFO pciliFirst,
  1216. PCILINKINFO pciliSecond)
  1217. {
  1218. COMPARISONRESULT cr;
  1219. BOOL bFirstLocal;
  1220. BOOL bFirstRemote;
  1221. BOOL bSecondLocal;
  1222. BOOL bSecondRemote;
  1223. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1224. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1225. bFirstLocal = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
  1226. ILI_FL_LOCAL_INFO_VALID);
  1227. bFirstRemote = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
  1228. ILI_FL_REMOTE_INFO_VALID);
  1229. bSecondLocal = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
  1230. ILI_FL_LOCAL_INFO_VALID);
  1231. bSecondRemote = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
  1232. ILI_FL_REMOTE_INFO_VALID);
  1233. if (bFirstLocal && bSecondLocal)
  1234. /* First and second have local information. */
  1235. cr = CompareVolumeIDs(ILI_Volume_ID_Ptr((PCILINKINFO)pciliFirst),
  1236. ILI_Volume_ID_Ptr((PCILINKINFO)pciliSecond));
  1237. else if (bFirstRemote && bSecondRemote)
  1238. /* First and second have remote information. */
  1239. cr = CompareCNRLinks(ILI_CNR_Link_Ptr((PCILINKINFO)pciliFirst),
  1240. ILI_CNR_Link_Ptr((PCILINKINFO)pciliSecond));
  1241. else
  1242. {
  1243. /*
  1244. * One contains only valid local information and the other contains only
  1245. * valid remote information.
  1246. */
  1247. ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
  1248. (pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
  1249. /* By fiat, local only < remote only. */
  1250. if (bFirstLocal)
  1251. /*
  1252. * First has only local information. Second has only remote
  1253. * information.
  1254. */
  1255. cr = CR_FIRST_SMALLER;
  1256. else
  1257. /*
  1258. * First has only remote information. Second has only local
  1259. * information.
  1260. */
  1261. cr = CR_FIRST_LARGER;
  1262. }
  1263. return(cr);
  1264. }
  1265. /*
  1266. ** CheckCombinedPathLen()
  1267. **
  1268. **
  1269. **
  1270. ** Arguments:
  1271. **
  1272. ** Returns:
  1273. **
  1274. ** Side Effects: none
  1275. */
  1276. PRIVATE_CODE BOOL CheckCombinedPathLen(LPCTSTR pcszBase, LPCTSTR pcszSuffix)
  1277. {
  1278. BOOL bResult;
  1279. ASSERT(IS_VALID_STRING_PTR(pcszBase, CSTR));
  1280. ASSERT(IS_VALID_STRING_PTR(pcszSuffix, CSTR));
  1281. bResult = EVAL(lstrlen(pcszBase) + lstrlen(pcszSuffix) < MAX_PATH_LEN);
  1282. if (bResult)
  1283. {
  1284. TCHAR rgchCombinedPath[MAX_PATH_LEN + 1];
  1285. lstrcpy(rgchCombinedPath, pcszBase);
  1286. CatPath(rgchCombinedPath, pcszSuffix);
  1287. bResult = EVAL(lstrlen(rgchCombinedPath) < MAX_PATH_LEN);
  1288. }
  1289. return(bResult);
  1290. }
  1291. /*
  1292. ** GetILinkInfoData()
  1293. **
  1294. **
  1295. **
  1296. ** Arguments:
  1297. **
  1298. ** Returns:
  1299. **
  1300. ** Side Effects: none
  1301. */
  1302. PRIVATE_CODE BOOL GetILinkInfoData(PCILINKINFO pcili, LINKINFODATATYPE lidt,
  1303. PCVOID *ppcvData)
  1304. {
  1305. BOOL bResult = FALSE;
  1306. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1307. ASSERT(IsValidLINKINFODATATYPE(lidt));
  1308. ASSERT(IS_VALID_WRITE_PTR(ppcvData, PCVOID));
  1309. switch (lidt)
  1310. {
  1311. case LIDT_VOLUME_SERIAL_NUMBER:
  1312. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1313. bResult = GetVolumeSerialNumber(ILI_Volume_ID_Ptr(pcili),
  1314. (PCDWORD *)ppcvData);
  1315. break;
  1316. case LIDT_DRIVE_TYPE:
  1317. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1318. bResult = GetVolumeDriveType(ILI_Volume_ID_Ptr(pcili),
  1319. (PCUINT *)ppcvData);
  1320. break;
  1321. case LIDT_VOLUME_LABEL:
  1322. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1323. bResult = GetVolumeLabel(ILI_Volume_ID_Ptr(pcili),
  1324. (LPCSTR *)ppcvData);
  1325. break;
  1326. case LIDT_VOLUME_LABELW:
  1327. #ifdef UNICODE
  1328. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1329. bResult = GetVolumeLabelW(ILI_Volume_ID_Ptr(pcili),
  1330. (LPCTSTR *)ppcvData);
  1331. #endif
  1332. break;
  1333. case LIDT_LOCAL_BASE_PATH:
  1334. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1335. {
  1336. *ppcvData = ILI_Local_Base_Path_PtrA(pcili);
  1337. bResult = TRUE;
  1338. }
  1339. break;
  1340. case LIDT_LOCAL_BASE_PATHW:
  1341. #ifdef UNICODE
  1342. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1343. {
  1344. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1345. *ppcvData = NULL;
  1346. else
  1347. *ppcvData = ILI_Local_Base_Path_PtrW(pcili);
  1348. bResult = TRUE;
  1349. }
  1350. #endif
  1351. break;
  1352. case LIDT_NET_TYPE:
  1353. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1354. bResult = GetCNRNetType(ILI_CNR_Link_Ptr(pcili),
  1355. (PCDWORD *)ppcvData);
  1356. break;
  1357. case LIDT_NET_RESOURCE:
  1358. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1359. bResult = GetCNRName(ILI_CNR_Link_Ptr(pcili),
  1360. (LPCSTR *)ppcvData);
  1361. break;
  1362. case LIDT_NET_RESOURCEW:
  1363. #ifdef UNICODE
  1364. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1365. bResult = GetCNRNameW(ILI_CNR_Link_Ptr(pcili),
  1366. (LPCWSTR *)ppcvData);
  1367. #endif
  1368. break;
  1369. case LIDT_REDIRECTED_DEVICE:
  1370. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1371. bResult = GetLastRedirectedDevice(ILI_CNR_Link_Ptr(pcili),
  1372. (LPCSTR *)ppcvData);
  1373. break;
  1374. case LIDT_REDIRECTED_DEVICEW:
  1375. #ifdef UNICODE
  1376. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1377. bResult = GetLastRedirectedDeviceW(ILI_CNR_Link_Ptr(pcili),
  1378. (LPCWSTR *)ppcvData);
  1379. #endif
  1380. break;
  1381. case LIDT_COMMON_PATH_SUFFIX:
  1382. *ppcvData = ILI_Common_Path_Suffix_PtrA(pcili);
  1383. bResult = TRUE;
  1384. break;
  1385. case LIDT_COMMON_PATH_SUFFIXW:
  1386. #ifdef UNICODE
  1387. if (pcili->ucbHeaderSize == sizeof(ILINKINFOA))
  1388. {
  1389. *ppcvData = NULL;
  1390. }
  1391. else
  1392. {
  1393. *ppcvData = ILI_Common_Path_Suffix_PtrW(pcili);
  1394. }
  1395. bResult = TRUE;
  1396. #endif
  1397. break;
  1398. default:
  1399. bResult = FALSE;
  1400. ERROR_OUT((TEXT("GetILinkInfoData(): Bad LINKINFODATATYPE %d."),
  1401. lidt));
  1402. break;
  1403. }
  1404. return(bResult);
  1405. }
  1406. /*
  1407. ** DisconnectILinkInfo()
  1408. **
  1409. **
  1410. **
  1411. ** Arguments:
  1412. **
  1413. ** Returns:
  1414. **
  1415. ** Side Effects: none
  1416. */
  1417. PRIVATE_CODE BOOL DisconnectILinkInfo(PCILINKINFO pcili)
  1418. {
  1419. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1420. return(DisconnectFromCNR(ILI_CNR_Link_Ptr(pcili)));
  1421. }
  1422. #if defined(DEBUG) || defined(EXPV)
  1423. /*
  1424. ** IsValidLINKINFODATATYPE()
  1425. **
  1426. **
  1427. **
  1428. ** Arguments:
  1429. **
  1430. ** Returns:
  1431. **
  1432. ** Side Effects: none
  1433. */
  1434. PRIVATE_CODE BOOL IsValidLINKINFODATATYPE(LINKINFODATATYPE lidt)
  1435. {
  1436. BOOL bResult;
  1437. switch (lidt)
  1438. {
  1439. case LIDT_VOLUME_SERIAL_NUMBER:
  1440. case LIDT_DRIVE_TYPE:
  1441. case LIDT_VOLUME_LABEL:
  1442. case LIDT_VOLUME_LABELW:
  1443. case LIDT_LOCAL_BASE_PATH:
  1444. case LIDT_LOCAL_BASE_PATHW:
  1445. case LIDT_NET_TYPE:
  1446. case LIDT_NET_RESOURCE:
  1447. case LIDT_NET_RESOURCEW:
  1448. case LIDT_REDIRECTED_DEVICE:
  1449. case LIDT_COMMON_PATH_SUFFIX:
  1450. case LIDT_COMMON_PATH_SUFFIXW:
  1451. bResult = TRUE;
  1452. break;
  1453. default:
  1454. bResult = FALSE;
  1455. ERROR_OUT((TEXT("IsValidLINKINFODATATYPE(): Invalid LINKINFODATATYPE %d."),
  1456. lidt));
  1457. break;
  1458. }
  1459. return(bResult);
  1460. }
  1461. #endif
  1462. #if defined(DEBUG) || defined(VSTF)
  1463. /*
  1464. ** CheckILIFlags()
  1465. **
  1466. **
  1467. **
  1468. ** Arguments:
  1469. **
  1470. ** Returns:
  1471. **
  1472. ** Side Effects: none
  1473. */
  1474. PRIVATE_CODE BOOL CheckILIFlags(PCILINKINFO pcili)
  1475. {
  1476. return(FLAGS_ARE_VALID(pcili->dwFlags, ALL_ILINKINFO_FLAGS) &&
  1477. (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
  1478. IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID)));
  1479. }
  1480. /*
  1481. ** CheckILICommonPathSuffix()
  1482. **
  1483. **
  1484. **
  1485. ** Arguments:
  1486. **
  1487. ** Returns:
  1488. **
  1489. ** Side Effects: none
  1490. */
  1491. PRIVATE_CODE BOOL CheckILICommonPathSuffix(PCILINKINFO pcili)
  1492. {
  1493. return(IS_VALID_STRING_PTRA(ILI_Common_Path_Suffix_PtrA(pcili), CSTR) &&
  1494. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1495. ILI_Common_Path_Suffix_PtrA(pcili),
  1496. lstrlenA(ILI_Common_Path_Suffix_PtrA(pcili)))) &&
  1497. EVAL(! IS_SLASH(*ILI_Common_Path_Suffix_PtrA(pcili))));
  1498. }
  1499. /*
  1500. ** CheckILILocalInfo()
  1501. **
  1502. **
  1503. **
  1504. ** Arguments:
  1505. **
  1506. ** Returns:
  1507. **
  1508. ** Side Effects: none
  1509. */
  1510. PRIVATE_CODE BOOL CheckILILocalInfo(PCILINKINFO pcili)
  1511. {
  1512. #ifdef UNICODE
  1513. WCHAR szWideLocalBasePath[MAX_PATH];
  1514. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1515. LPWSTR pszWideLocalBasePath;
  1516. LPWSTR pszWideCommonPathSuffix;
  1517. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1518. return FALSE;
  1519. if (!IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID))
  1520. return FALSE;
  1521. if (!EVAL(IsContained(pcili, pcili->li.ucbSize,ILI_Volume_ID_Ptr(pcili),
  1522. GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))))
  1523. return FALSE;
  1524. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1525. {
  1526. pszWideLocalBasePath = szWideLocalBasePath;
  1527. MultiByteToWideChar(CP_ACP, 0,
  1528. ILI_Local_Base_Path_PtrA(pcili), -1,
  1529. szWideLocalBasePath, MAX_PATH);
  1530. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1531. MultiByteToWideChar(CP_ACP, 0,
  1532. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1533. szWideCommonPathSuffix, MAX_PATH);
  1534. }
  1535. else
  1536. {
  1537. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  1538. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1539. }
  1540. if (!EVAL(IsDrivePath(pszWideLocalBasePath)))
  1541. return FALSE;
  1542. if (!EVAL(IsContained(pcili, pcili->li.ucbSize,
  1543. ILI_Local_Base_Path_PtrA(pcili),
  1544. lstrlenA(ILI_Local_Base_Path_PtrA(pcili)))))
  1545. return FALSE;
  1546. if (!EVAL(CheckCombinedPathLen(pszWideLocalBasePath,
  1547. pszWideCommonPathSuffix)))
  1548. return FALSE;
  1549. return TRUE;
  1550. #else
  1551. return(IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
  1552. /* Check volume ID. */
  1553. (IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID) &&
  1554. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1555. ILI_Volume_ID_Ptr(pcili),
  1556. GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))) &&
  1557. /* Check local base path. */
  1558. EVAL(IsDrivePath(ILI_Local_Base_Path_Ptr(pcili))) &&
  1559. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1560. ILI_Local_Base_Path_PtrA(pcili),
  1561. lstrlen(ILI_Local_Base_Path_Ptr(pcili)))) &&
  1562. EVAL(CheckCombinedPathLen(ILI_Local_Base_Path_Ptr(pcili),
  1563. ILI_Common_Path_Suffix_Ptr(pcili)))));
  1564. #endif
  1565. }
  1566. /*
  1567. ** CheckILIRemoteInfo()
  1568. **
  1569. **
  1570. **
  1571. ** Arguments:
  1572. **
  1573. ** Returns:
  1574. **
  1575. ** Side Effects: none
  1576. */
  1577. PRIVATE_CODE BOOL CheckILIRemoteInfo(PCILINKINFO pcili)
  1578. {
  1579. BOOL bResult;
  1580. if (IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1581. bResult = TRUE;
  1582. else
  1583. {
  1584. /* Check CNR link. */
  1585. if (IS_VALID_STRUCT_PTR(ILI_CNR_Link_Ptr(pcili), CCNRLINK) &&
  1586. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1587. ILI_CNR_Link_Ptr(pcili),
  1588. GetCNRLinkLen(ILI_CNR_Link_Ptr(pcili)))))
  1589. {
  1590. TCHAR rgchRemoteBasePath[MAX_PATH_LEN];
  1591. #ifdef UNICODE
  1592. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1593. LPWSTR pszWideCommonPathSuffix;
  1594. #endif
  1595. /* RAIDRAID: (15724) This is broken for non-UNC CNR names. */
  1596. GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), rgchRemoteBasePath);
  1597. #ifdef UNICODE
  1598. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1599. {
  1600. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1601. MultiByteToWideChar(CP_ACP, 0,
  1602. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1603. szWideCommonPathSuffix, MAX_PATH);
  1604. }
  1605. else
  1606. {
  1607. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1608. }
  1609. bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
  1610. pszWideCommonPathSuffix));
  1611. #else
  1612. bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
  1613. ILI_Common_Path_Suffix_Ptr(pcili)));
  1614. #endif
  1615. }
  1616. else
  1617. bResult = FALSE;
  1618. }
  1619. return(bResult);
  1620. }
  1621. /*
  1622. ** IsValidPCLINKINFO()
  1623. **
  1624. **
  1625. **
  1626. ** Arguments:
  1627. **
  1628. ** Returns:
  1629. **
  1630. ** Side Effects: none
  1631. */
  1632. PRIVATE_CODE BOOL IsValidPCLINKINFO(PCLINKINFO pcli)
  1633. {
  1634. return(IS_VALID_STRUCT_PTR((PCILINKINFO)pcli, CILINKINFO));
  1635. }
  1636. /*
  1637. ** IsValidPCILINKINFO()
  1638. **
  1639. **
  1640. **
  1641. ** Arguments:
  1642. **
  1643. ** Returns:
  1644. **
  1645. ** Side Effects: none
  1646. */
  1647. PRIVATE_CODE BOOL IsValidPCILINKINFO(PCILINKINFO pcili)
  1648. {
  1649. /*
  1650. * A "valid" LinkInfo structure has the following characteristics:
  1651. *
  1652. * 1) entire structure is readable
  1653. * 2) size of ILINKINFO header structure >= SIZEOF(CILINKINFO)
  1654. * 3) flags are valid
  1655. * 4) either local info or remote info or both are valid
  1656. * 5) contained structures and strings are valid and are entirely contained
  1657. * in LinkInfo structure
  1658. * 6) lstrlen() of combined paths < MAX_PATH_LEN
  1659. */
  1660. return(IS_VALID_READ_PTR(pcili, CILINKINFO) &&
  1661. IS_VALID_READ_BUFFER_PTR(pcili, CILINKINFO, pcili->li.ucbSize) &&
  1662. EVAL(pcili->ucbHeaderSize >= SIZEOF(*pcili)) &&
  1663. EVAL(CheckILIFlags(pcili)) &&
  1664. EVAL(CheckILICommonPathSuffix(pcili)) &&
  1665. EVAL(CheckILILocalInfo(pcili)) &&
  1666. EVAL(CheckILIRemoteInfo(pcili)));
  1667. }
  1668. #endif
  1669. #ifdef DEBUG
  1670. /*
  1671. ** DumpILinkInfo()
  1672. **
  1673. **
  1674. **
  1675. ** Arguments:
  1676. **
  1677. ** Returns:
  1678. **
  1679. ** Side Effects: none
  1680. */
  1681. PRIVATE_CODE void DumpILinkInfo(PCILINKINFO pcili)
  1682. {
  1683. #ifdef UNICODE
  1684. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1685. LPWSTR pszWideCommonPathSuffix;
  1686. #endif
  1687. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1688. PLAIN_TRACE_OUT((TEXT("%s[LinkInfo] ucbSize = %#x"),
  1689. INDENT_STRING,
  1690. pcili->li.ucbSize));
  1691. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] ucbHeaderSize = %#x"),
  1692. INDENT_STRING,
  1693. INDENT_STRING,
  1694. pcili->ucbHeaderSize));
  1695. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] dwFLags = %#08lx"),
  1696. INDENT_STRING,
  1697. INDENT_STRING,
  1698. pcili->dwFlags));
  1699. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1700. {
  1701. #ifdef UNICODE
  1702. WCHAR szWideLocalBasePath[MAX_PATH];
  1703. LPWSTR pszWideLocalBasePath;
  1704. #endif
  1705. DumpVolumeID(ILI_Volume_ID_Ptr(pcili));
  1706. #ifdef UNICODE
  1707. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1708. {
  1709. pszWideLocalBasePath = szWideLocalBasePath;
  1710. MultiByteToWideChar(CP_ACP, 0,
  1711. ILI_Local_Base_Path_PtrA(pcili), -1,
  1712. szWideLocalBasePath, MAX_PATH);
  1713. }
  1714. else
  1715. {
  1716. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  1717. }
  1718. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
  1719. INDENT_STRING,
  1720. INDENT_STRING,
  1721. pszWideLocalBasePath));
  1722. #else
  1723. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
  1724. INDENT_STRING,
  1725. INDENT_STRING,
  1726. ILI_Local_Base_Path_Ptr(pcili)));
  1727. #endif
  1728. }
  1729. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1730. DumpCNRLink(ILI_CNR_Link_Ptr(pcili));
  1731. #ifdef UNICODE
  1732. if ( pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1733. {
  1734. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1735. MultiByteToWideChar(CP_ACP, 0,
  1736. ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1737. szWideCommonPathSuffix, MAX_PATH);
  1738. }
  1739. else
  1740. {
  1741. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1742. }
  1743. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
  1744. INDENT_STRING,
  1745. INDENT_STRING,
  1746. pszWideCommonPathSuffix));
  1747. #else
  1748. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
  1749. INDENT_STRING,
  1750. INDENT_STRING,
  1751. ILI_Common_Path_Suffix_Ptr(pcili)));
  1752. #endif
  1753. return;
  1754. }
  1755. #endif
  1756. /***************************** Exported Functions ****************************/
  1757. /******************************************************************************
  1758. @doc LINKINFOAPI
  1759. @func BOOL | CreateLinkInfo | Creates a LinkInfo structure for a path.
  1760. @parm PCSTR | pcszPath | A pointer to the path string that a LinkInfo structure
  1761. is to be created for.
  1762. @parm PLINKINFO * | ppli | A pointer to a PLINKINFO to be filled in with a
  1763. pointer to the new LinkInfo structure. *ppli is only valid if TRUE is
  1764. returned.
  1765. @rdesc If a LinkInfo structure was created successfully, TRUE is returned, and
  1766. *ppli contains a pointer to the new LinkInfo structure. Otherwise, a LinkInfo
  1767. structure was not created successfully, and *ppli is undefined. The reason for
  1768. failure may be determined by calling GetLastError().
  1769. @comm Once the caller is finshed with the LinkInfo structure returned by
  1770. CreateLinkInfo(), DestroyLinkInfo() should be called to free the LinkInfo
  1771. structure.<nl>
  1772. The contents of the LinkInfo structure returned are opaque to the caller, with
  1773. the exception of the first field of the LinkInfo structure. The first field of
  1774. the LinkInfo structure, ucbSize, is a UINT containing the size of the LinkInfo
  1775. structure in bytes, including the ucbSize field.<nl>
  1776. The LinkInfo structure is created in memory that is private to the LinkInfo
  1777. APIs. The returned LinkInfo structure should be copied into the caller's
  1778. memory, and the DestroyLinkInfo() should be called to free the LinkInfo
  1779. structure from the LinkInfo APIs' private memory.
  1780. @xref DestroyLinkInfo
  1781. ******************************************************************************/
  1782. LINKINFOAPI BOOL WINAPI CreateLinkInfo(LPCTSTR pcszPath, PLINKINFO *ppli)
  1783. {
  1784. BOOL bResult;
  1785. DebugEntry(CreateLinkInfo);
  1786. #ifdef EXPV
  1787. /* Verify parameters. */
  1788. if (IS_VALID_STRING_PTR(pcszPath, CSTR) &&
  1789. IS_VALID_WRITE_PTR(ppli, PLINKINFO))
  1790. #endif
  1791. {
  1792. bResult = CreateILinkInfo(pcszPath, (PILINKINFO *)ppli);
  1793. #ifdef DEBUG
  1794. if (bResult)
  1795. {
  1796. TRACE_OUT((TEXT("CreateLinkInfo(): LinkInfo created for path %s:"),
  1797. pcszPath));
  1798. DumpILinkInfo(*(PILINKINFO *)ppli);
  1799. }
  1800. #endif
  1801. }
  1802. #ifdef EXPV
  1803. else
  1804. {
  1805. SetLastError(ERROR_INVALID_PARAMETER);
  1806. bResult = FALSE;
  1807. }
  1808. #endif
  1809. ASSERT(! bResult ||
  1810. IS_VALID_STRUCT_PTR(*ppli, CLINKINFO));
  1811. DebugExitBOOL(CreateLinkInfo, bResult);
  1812. return(bResult);
  1813. }
  1814. #ifdef UNICODE
  1815. LINKINFOAPI BOOL WINAPI CreateLinkInfoA(LPCSTR pcszPath, PLINKINFO *ppli)
  1816. {
  1817. LPWSTR lpwstr;
  1818. UINT cchPath;
  1819. cchPath = lstrlenA(pcszPath) + 1;
  1820. lpwstr = (LPWSTR)_alloca(cchPath*SIZEOF(WCHAR));
  1821. if ( MultiByteToWideChar( CP_ACP, 0,
  1822. pcszPath, cchPath,
  1823. lpwstr, cchPath) == 0)
  1824. {
  1825. return FALSE;
  1826. }
  1827. else
  1828. {
  1829. return CreateLinkInfo(lpwstr,ppli);
  1830. }
  1831. }
  1832. #endif
  1833. /******************************************************************************
  1834. @doc LINKINFOAPI
  1835. @func void | DestroyLinkInfo | Destroys a LinkInfo structure created by
  1836. CreateLinkInfo().
  1837. @parm PLINKINFO | pli | A pointer to the LinkInfo structure to be destroyed.
  1838. @xref CreateLinkInfo
  1839. ******************************************************************************/
  1840. LINKINFOAPI void WINAPI DestroyLinkInfo(PLINKINFO pli)
  1841. {
  1842. DebugEntry(DestroyLinkInfo);
  1843. #ifdef EXPV
  1844. /* Verify parameters. */
  1845. if (
  1846. IS_VALID_STRUCT_PTR(pli, CLINKINFO))
  1847. #endif
  1848. {
  1849. DestroyILinkInfo((PILINKINFO)pli);
  1850. }
  1851. DebugExitVOID(DestroyLinkInfo);
  1852. return;
  1853. }
  1854. /******************************************************************************
  1855. @doc LINKINFOAPI
  1856. @func int | CompareLinkInfoReferents | Compares the referents of two LinkInfo
  1857. structures.
  1858. @parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
  1859. referent is to be compared.
  1860. @parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
  1861. whose referent is to be compared.
  1862. @rdesc If the referent of the first LinkInfo structure is less than the
  1863. referent of the second LinkInfo structure, a negative value is returned. If
  1864. the referent of the first LinkInfo structure is the same as the referent of the
  1865. second LinkInfo structure, zero is returned. If the referent of the first
  1866. LinkInfo structure is larger than the referent of the second LinkInfo
  1867. structure, a positive value is returned. An invalid LinkInfo structure is
  1868. considered to have a referent that is less than the referent of any valid
  1869. LinkInfo structure. All invalid LinkInfo structures are considered to have the
  1870. same referent.
  1871. @comm The value returned is actually a COMPARISONRESULT, for clients that
  1872. understand COMPARISONRESULTs, like SYNCENG.DLL.
  1873. @xref CompareLinkInfoVolumes
  1874. ******************************************************************************/
  1875. LINKINFOAPI int WINAPI CompareLinkInfoReferents(PCLINKINFO pcliFirst,
  1876. PCLINKINFO pcliSecond)
  1877. {
  1878. COMPARISONRESULT cr;
  1879. BOOL bFirstValid;
  1880. BOOL bSecondValid;
  1881. DebugEntry(CompareLinkInfoReferents);
  1882. bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
  1883. bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
  1884. if (bFirstValid)
  1885. {
  1886. if (bSecondValid)
  1887. cr = CompareILinkInfoReferents((PCILINKINFO)pcliFirst,
  1888. (PCILINKINFO)pcliSecond);
  1889. else
  1890. cr = CR_FIRST_LARGER;
  1891. }
  1892. else
  1893. {
  1894. if (bSecondValid)
  1895. cr = CR_FIRST_SMALLER;
  1896. else
  1897. cr = CR_EQUAL;
  1898. }
  1899. ASSERT(IsValidCOMPARISONRESULT(cr));
  1900. DebugExitCOMPARISONRESULT(CompareLinkInfoReferents, cr);
  1901. return(cr);
  1902. }
  1903. /******************************************************************************
  1904. @doc LINKINFOAPI
  1905. @func int | CompareLinkInfoVolumes | Compares the volumes of the referents of
  1906. two LinkInfo structures.
  1907. @parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
  1908. referent's volume is to be compared.
  1909. @parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
  1910. referent's volume is to be compared.
  1911. @rdesc If the volume of the referent of the first LinkInfo structure is less
  1912. than the volume of the referent of the second LinkInfo structure, a negative
  1913. value is returned. If the volume of the referent of the first LinkInfo
  1914. structure is the same as the volume of the referent of the second LinkInfo
  1915. structure, zero is returned. If the volume of the referent of the first
  1916. LinkInfo structure is larger than the volume of the referent of the second
  1917. LinkInfo structure, a positive value is returned. An invalid LinkInfo
  1918. structure is considered to have a referent's volume that is less than the
  1919. referent's volume of any valid LinkInfo structure. All invalid LinkInfo
  1920. structures are considered to have the same referent's volume.
  1921. @comm The value returned is actually a COMPARISONRESULT, for clients that
  1922. understand COMPARISONRESULTs, like SYNCENG.DLL.
  1923. @xref CompareLinkInfoReferents
  1924. ******************************************************************************/
  1925. LINKINFOAPI int WINAPI CompareLinkInfoVolumes(PCLINKINFO pcliFirst,
  1926. PCLINKINFO pcliSecond)
  1927. {
  1928. COMPARISONRESULT cr;
  1929. BOOL bFirstValid;
  1930. BOOL bSecondValid;
  1931. DebugEntry(CompareLinkInfoVolumes);
  1932. bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
  1933. bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
  1934. if (bFirstValid)
  1935. {
  1936. if (bSecondValid)
  1937. cr = CompareILinkInfoVolumes((PCILINKINFO)pcliFirst,
  1938. (PCILINKINFO)pcliSecond);
  1939. else
  1940. cr = CR_FIRST_LARGER;
  1941. }
  1942. else
  1943. {
  1944. if (bSecondValid)
  1945. cr = CR_FIRST_SMALLER;
  1946. else
  1947. cr = CR_EQUAL;
  1948. }
  1949. ASSERT(IsValidCOMPARISONRESULT(cr));
  1950. DebugExitCOMPARISONRESULT(CompareLinkInfoVolumes, cr);
  1951. return(cr);
  1952. }
  1953. /******************************************************************************
  1954. @doc LINKINFOAPI
  1955. @func BOOL | ResolveLinkInfo | Resolves a LinkInfo structure into a file system
  1956. path on an available volume.
  1957. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be resolved.
  1958. @parm PSTR | pszResolvedPathBuf | A pointer to a buffer to be filled in with
  1959. the path resolved to the LinkInfo structure's referent.
  1960. @parm DWORD | dwInFlags | A bit mask of flags. This parameter may be any
  1961. combination of the following values:
  1962. @flag RLI_IFL_CONNECT | If set, connect to the referent's parent connectable
  1963. network resource if necessary. If clear, no connection is established.
  1964. @flag RLI_IFL_ALLOW_UI | If set, interaction with the user is permitted, and
  1965. the hwndOwner parameter identifies the parent window to be used for any ui
  1966. required. If clear, interaction with the user is not permitted.
  1967. @flag RLI_IFL_REDIRECT | If set, the resolved path is a redirected logical
  1968. device path. If clear, the resolved path is only a redirected logical device
  1969. path if the RLI_IFL_CONNECT flag is set, and the network requires a redirected
  1970. logical device path to make a connection.
  1971. @flag RLI_IFL_UPDATE | If set and the source LinkInfo structure needs updating,
  1972. RLI_OFL_UPDATED will be set in *pdwOutFlags and *ppliUpdated will point to an
  1973. updated LinkInfo structure. If clear, RLI_OFL_UPDATED will be clear in
  1974. *pdwOutFlags and *ppliUpdated is undefined.
  1975. @flag RLI_IFL_LOCAL_SEARCH | If set, first the last known logical device for
  1976. the referent's volume is checked for the volume, followed by all other local
  1977. logical devices that handle the referent's volume's media type. If clear, only
  1978. the last known logical device for the referent's volume is checked for the
  1979. volume.
  1980. @parm HWND | hwndOwner | A handle to the parent window to be used to bring up
  1981. any ui required. This parameter is only used if RLI_IFL_ALLOW_UI is set in
  1982. dwInFlags. Otherwise, it is ignored.
  1983. @parm PDWORD | pdwOutFlags | A pointer to a DWORD to be filled in with a bit
  1984. mask of flags. *pdwOutFlags is only valid if TRUE is returned. *pdwOutFlags
  1985. may be any combination of the following values:
  1986. @flag RLI_OFL_UPDATED | Only set if RLI_IFL_UPDATE was set in dwInFlags. If
  1987. set, the source LinkInfo structure needed updating, and *ppliUpdated points to
  1988. an updated LinkInfo structure. If clear, either RLI_IFL_UPDATE was clear in
  1989. dwInFlags or the source LinkInfo structure didn't need updating, and
  1990. *ppliUpdated is undefined.
  1991. @parm PLINKINFO * | ppliUpdated | If RLI_IFL_UPDATE is set in dwInFlags,
  1992. ppliUpdated is a pointer to a PLINKINFO to be filled in with a pointer to an
  1993. updated LinkInfo structure, if necessary. If RLI_IFL_UPDATE is clear in
  1994. dwInFlags, ppliUpdated is ignored. *ppliUpdated is only valid if
  1995. RLI_OFL_UPDATED is set in *pdwOutFlags
  1996. @rdesc If the LinkInfo was resolved to a path on an available successfully,
  1997. TRUE is returned, pszResolvedPathBuf's buffer is filled in with a file system
  1998. path to the LinkInfo structure's referent, and *pdwOutFlags is filled in as
  1999. described above. Otherwise, FALSE is returned, the contents of pszResolved's
  2000. buffer are undefined, and the contents of *pdwOutFlags are undefined. The
  2001. reason for failure may be determined by calling GetLastError().
  2002. @comm Once the caller is finshed with any new, updated LinkInfo structure
  2003. returned by ResolveLinkInfo(), DestroyLinkInfo() should be called to free the
  2004. LinkInfo structure.
  2005. @xref DestroyLinkInfo DisconnectLinkInfo
  2006. ******************************************************************************/
  2007. LINKINFOAPI BOOL WINAPI ResolveLinkInfo(PCLINKINFO pcli,
  2008. LPTSTR pszResolvedPathBuf,
  2009. DWORD dwInFlags, HWND hwndOwner,
  2010. PDWORD pdwOutFlags,
  2011. PLINKINFO *ppliUpdated)
  2012. {
  2013. BOOL bResult;
  2014. DebugEntry(ResolveLinkInfo);
  2015. #ifdef EXPV
  2016. /* Verify parameters. */
  2017. if (
  2018. IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
  2019. IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN) &&
  2020. FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS) &&
  2021. (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
  2022. IS_VALID_HANDLE(hwndOwner, WND)) &&
  2023. IS_VALID_WRITE_PTR(pdwOutFlags, DWORD) &&
  2024. (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) ||
  2025. IS_VALID_WRITE_PTR(ppliUpdated, PLINKINFO)) &&
  2026. EVAL(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_TEMPORARY) ||
  2027. IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT)))
  2028. #endif
  2029. {
  2030. DWORD dwTempFlags;
  2031. *pdwOutFlags = 0;
  2032. bResult = ResolveILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf,
  2033. dwInFlags, hwndOwner, &dwTempFlags);
  2034. if (bResult)
  2035. {
  2036. *pdwOutFlags |= dwTempFlags;
  2037. if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
  2038. {
  2039. bResult = UpdateILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf,
  2040. &dwTempFlags,
  2041. (PILINKINFO *)ppliUpdated);
  2042. if (bResult)
  2043. *pdwOutFlags |= dwTempFlags;
  2044. }
  2045. }
  2046. #ifdef DEBUG
  2047. TRACE_OUT((TEXT("ResolveLinkInfo(): flags %#08lx, given LinkInfo:"),
  2048. dwInFlags));
  2049. DumpILinkInfo((PCILINKINFO)pcli);
  2050. if (bResult)
  2051. {
  2052. TRACE_OUT((TEXT("ResolveLinkInfo(): Resolved path %s with flags %#08lx."),
  2053. pszResolvedPathBuf,
  2054. *pdwOutFlags));
  2055. if (IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))
  2056. {
  2057. ASSERT(IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE));
  2058. TRACE_OUT((TEXT("UpdateLinkInfo(): updated LinkInfo:")));
  2059. DumpILinkInfo(*(PILINKINFO *)ppliUpdated);
  2060. }
  2061. else
  2062. {
  2063. if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
  2064. TRACE_OUT((TEXT("UpdateLinkInfo(): No update required.")));
  2065. else
  2066. TRACE_OUT((TEXT("UpdateLinkInfo(): No update requested.")));
  2067. }
  2068. }
  2069. else
  2070. WARNING_OUT((TEXT("ResolveLinkInfo(): Referent's volume is unavailable.")));
  2071. #endif
  2072. }
  2073. #ifdef EXPV
  2074. else
  2075. {
  2076. SetLastError(ERROR_INVALID_PARAMETER);
  2077. bResult = FALSE;
  2078. }
  2079. #endif
  2080. ASSERT(! bResult ||
  2081. (FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS) &&
  2082. EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
  2083. EVAL(! (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) &&
  2084. IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))) &&
  2085. (IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
  2086. IS_VALID_STRUCT_PTR(*ppliUpdated, CLINKINFO))));
  2087. DebugExitBOOL(ResolveLinkInfo, bResult);
  2088. return(bResult);
  2089. }
  2090. #ifdef UNICODE
  2091. LINKINFOAPI BOOL WINAPI ResolveLinkInfoA(PCLINKINFO pcli,
  2092. LPSTR pszResolvedPathBuf,
  2093. DWORD dwInFlags, HWND hwndOwner,
  2094. PDWORD pdwOutFlags,
  2095. PLINKINFO *ppliUpdated)
  2096. {
  2097. WCHAR szWideResolvedPathBuf[MAX_PATH];
  2098. BOOL fResolved;
  2099. fResolved = ResolveLinkInfo(pcli,
  2100. szWideResolvedPathBuf,
  2101. dwInFlags, hwndOwner, pdwOutFlags, ppliUpdated);
  2102. if ( fResolved )
  2103. {
  2104. if ( WideCharToMultiByte( CP_ACP, 0,
  2105. szWideResolvedPathBuf, -1,
  2106. pszResolvedPathBuf, MAX_PATH,
  2107. NULL, NULL ) == 0)
  2108. {
  2109. return FALSE;
  2110. }
  2111. }
  2112. return fResolved;
  2113. }
  2114. #endif
  2115. /******************************************************************************
  2116. @doc LINKINFOAPI
  2117. @func BOOL | DisconnectLinkInfo | Cancels a connection to a net resource
  2118. established by a previous call to ResolveLinkInfo(). DisconnectLinkInfo()
  2119. should only be called if RLI_OFL_DISCONNECT was set in *pdwOutFlags on return
  2120. from ResolveLinkInfo() on the given LinkInfo structure, or its updated
  2121. equivalent.
  2122. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure whose connection
  2123. is to be canceled.
  2124. @rdesc If the function completed successfully, TRUE is returned. Otherwise,
  2125. FALSE is returned. The reason for failure may be determined by calling
  2126. GetLastError().
  2127. @xref ResolveLinkInfo
  2128. ******************************************************************************/
  2129. LINKINFOAPI BOOL WINAPI DisconnectLinkInfo(PCLINKINFO pcli)
  2130. {
  2131. BOOL bResult;
  2132. DebugEntry(DisconnectLinkInfo);
  2133. #ifdef EXPV
  2134. /* Verify parameters. */
  2135. if (
  2136. IS_VALID_STRUCT_PTR(pcli, CLINKINFO))
  2137. #endif
  2138. {
  2139. bResult = DisconnectILinkInfo((PCILINKINFO)pcli);
  2140. }
  2141. #ifdef EXPV
  2142. else
  2143. {
  2144. SetLastError(ERROR_INVALID_PARAMETER);
  2145. bResult = FALSE;
  2146. }
  2147. #endif
  2148. DebugExitBOOL(DisconnectLinkInfo, bResult);
  2149. return(bResult);
  2150. }
  2151. /******************************************************************************
  2152. @doc LINKINFOAPI
  2153. @func BOOL | GetLinkInfoData | Retrieves a pointer to data in a LinkInfo
  2154. structure.
  2155. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to retrieve data
  2156. from.
  2157. @parm LINKINFODATATYPE | lidt | The type of data to be retrieved from the
  2158. LinkInfo structure. lidt may be one of the following values:
  2159. @flag LIDT_VOLUME_SERIAL_NUMBER | *ppcvData is a PCDWORD that points to the
  2160. LinkInfo structure's referent's volume's serial number.
  2161. @flag LIDT_DRIVE_TYPE | *ppcvData is a PCUINT that points to the LinkInfo
  2162. structure's referent's volume's host drive type.
  2163. @flag LIDT_VOLUME_LABEL | *ppcvData is a PCSTR that points to the LinkInfo
  2164. structure's referent's volume's label.
  2165. @flag LIDT_LOCAL_BASE_PATH | *ppcvData is a PCSTR that points to the LinkInfo
  2166. structure's referent's local base path.
  2167. @flag LIDT_NET_RESOURCE | *ppcvData is a PCSTR that points to the LinkInfo
  2168. structure's referent's parent network resource's name.
  2169. @flag LIDT_COMMON_PATH_SUFFIX | *ppcvData is a PCSTR that points to the
  2170. LinkInfo structure's referent's common path suffix.
  2171. @rdesc If the function completed successfully, TRUE is returned, and *ppcvData
  2172. is filled in with a pointer to the data requested from LinkInfo structure or NULL
  2173. if that was a valid field, but empty.
  2174. Otherwise, FALSE is returned, and the contents of *ppcvData are undefined. The
  2175. reason for failure may be determined by calling GetLastError().
  2176. @comm A LinkInfo structure may only contain some of the LinkInfo data listed
  2177. above.
  2178. ******************************************************************************/
  2179. LINKINFOAPI BOOL WINAPI GetLinkInfoData(PCLINKINFO pcli, LINKINFODATATYPE lidt,
  2180. PCVOID *ppcvData)
  2181. {
  2182. BOOL bResult;
  2183. DebugEntry(GetLinkInfoData);
  2184. #ifdef EXPV
  2185. /* Verify parameters. */
  2186. if (
  2187. IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
  2188. EVAL(IsValidLINKINFODATATYPE(lidt)) &&
  2189. IS_VALID_WRITE_PTR(ppcvData, PCVOID))
  2190. #endif
  2191. {
  2192. bResult = GetILinkInfoData((PCILINKINFO)pcli, lidt, ppcvData);
  2193. }
  2194. #ifdef EXPV
  2195. else
  2196. {
  2197. SetLastError(ERROR_INVALID_PARAMETER);
  2198. bResult = FALSE;
  2199. }
  2200. #endif
  2201. ASSERT(!bResult ||
  2202. ((NULL == *ppcvData) || IS_VALID_READ_BUFFER_PTR(*ppcvData, LinkInfoData, 1)));
  2203. DebugExitBOOL(GetLinkInfoData, bResult);
  2204. return(bResult);
  2205. }
  2206. /******************************************************************************
  2207. @doc LINKINFOAPI
  2208. @func BOOL | IsValidLinkInfo | Determines whether or not a LinkInfo structure
  2209. is valid.
  2210. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be checked for
  2211. validity.
  2212. @rdesc If the function completed successfully, TRUE is returned. Otherwise,
  2213. FALSE is returned.
  2214. ******************************************************************************/
  2215. //
  2216. // IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT validates alignment only on
  2217. // alignment machines. For machines that are not alignment-sensitive,
  2218. // it declares that all values are aligned.
  2219. //
  2220. #ifdef ALIGNMENT_MACHINE
  2221. #define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) IS_ALIGNED_DWORD_CNT(x)
  2222. #else
  2223. #define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) TRUE
  2224. #endif
  2225. LINKINFOAPI BOOL WINAPI IsValidLinkInfo(PCLINKINFO pcli)
  2226. {
  2227. BOOL bResult;
  2228. PCILINKINFO pcili = (PCILINKINFO)pcli;
  2229. DebugEntry(IsValidLinkInfo);
  2230. // First make sure it's readable and not ridiculously small
  2231. if (IsBadReadPtr(pcli, sizeof(LINKINFO)) || // read the ucbSize
  2232. IsBadReadPtr(pcli, pcli->ucbSize) || // entire buffer is valid
  2233. pcli->ucbSize < pcili->ucbHeaderSize || // header fits in buffer
  2234. pcili->ucbHeaderSize < sizeof(ILINKINFOA)// smallest supported header
  2235. )
  2236. {
  2237. bResult = FALSE;
  2238. goto exit;
  2239. }
  2240. // Make sure no field points outside our buffer
  2241. if (pcili->ucbVolumeIDOffset >= pcli->ucbSize ||
  2242. pcili->ucbLocalBasePathOffset >= pcli->ucbSize ||
  2243. pcili->ucbCommonPathSuffixOffset >= pcli->ucbSize ||
  2244. !IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbVolumeIDOffset))
  2245. {
  2246. bResult = FALSE;
  2247. goto exit;
  2248. }
  2249. // The ucbCNRLinkOffset field is valid only sometimes
  2250. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  2251. {
  2252. if (pcili->ucbCNRLinkOffset >= pcli->ucbSize ||
  2253. !IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbCNRLinkOffset))
  2254. {
  2255. bResult = FALSE;
  2256. goto exit;
  2257. }
  2258. }
  2259. // The UNICODE version has some more fields than the ANSI version.
  2260. // Those UNICODE fields must be WORD-aligned.
  2261. if (pcili->ucbHeaderSize >= sizeof(ILINKINFOW))
  2262. {
  2263. if (pcili->ucbLocalBasePathOffsetW >= pcli->ucbSize ||
  2264. pcili->ucbCommonPathSuffixOffsetW >= pcli->ucbSize ||
  2265. !IS_ALIGNED_WORD_CNT(pcili->ucbLocalBasePathOffsetW) ||
  2266. !IS_ALIGNED_WORD_CNT(pcili->ucbCommonPathSuffixOffsetW))
  2267. {
  2268. bResult = FALSE;
  2269. goto exit;
  2270. }
  2271. }
  2272. // Survived the validation ordeal!
  2273. bResult = TRUE;
  2274. exit:;
  2275. DebugExitBOOL(IsValidLinkInfo, bResult);
  2276. return(bResult);
  2277. }