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.

2814 lines
82 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, int, DWORD);
  202. PRIVATE_CODE BOOL ResolveRemoteILinkInfo(PCILINKINFO, LPTSTR, DWORD, HWND, PDWORD);
  203. PRIVATE_CODE BOOL ResolveILinkInfo(PCILINKINFO, LPTSTR, int, DWORD, HWND, PDWORD);
  204. PRIVATE_CODE BOOL ResolveLocalPathFromServer(PCILINKINFO, LPTSTR, PDWORD);
  205. PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO, LPTSTR, int);
  206. PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO, LPTSTR, int);
  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, ARRAYSIZE(rgchLocalBasePath),
  287. &pcszCommonPathSuffix);
  288. if (bResult)
  289. {
  290. /* Wrap them up. */
  291. bResult = UnifyILinkInfo(pvolid, ucbVolumeIDLen, rgchLocalBasePath,
  292. pcnrl, ucbCNRLinkLen, pcszCommonPathSuffix,
  293. ppili);
  294. if (ucbCNRLinkLen > 0)
  295. DestroyCNRLink(pcnrl);
  296. }
  297. if (ucbVolumeIDLen > 0)
  298. DestroyVolumeID(pvolid);
  299. }
  300. ASSERT(! bResult ||
  301. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  302. return(bResult);
  303. }
  304. /*
  305. ** CreateRemoteILinkInfo()
  306. **
  307. **
  308. **
  309. ** Arguments:
  310. **
  311. ** Returns:
  312. **
  313. ** Side Effects: none
  314. */
  315. PRIVATE_CODE BOOL CreateRemoteILinkInfo(LPCTSTR pcszRemotePath,
  316. LPCTSTR pcszCNRName,
  317. LPCTSTR pcszRootPathSuffix,
  318. PILINKINFO *ppili)
  319. {
  320. BOOL bResult;
  321. PCNRLINK pcnrl;
  322. UINT ucbCNRLinkLen;
  323. ASSERT(IsCanonicalPath(pcszRemotePath));
  324. ASSERT(IsValidCNRName(pcszCNRName));
  325. ASSERT(IS_VALID_STRING_PTR(pcszRootPathSuffix, CSTR));
  326. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  327. bResult = CreateRemoteCNRLink(pcszRemotePath, pcszCNRName, &pcnrl,
  328. &ucbCNRLinkLen);
  329. if (bResult)
  330. {
  331. /* Wrap it up. */
  332. bResult = UnifyILinkInfo(NULL, 0, EMPTY_STRING, pcnrl, ucbCNRLinkLen,
  333. pcszRootPathSuffix, ppili);
  334. if (EVAL(ucbCNRLinkLen > 0))
  335. DestroyCNRLink(pcnrl);
  336. }
  337. ASSERT(! bResult ||
  338. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  339. return(bResult);
  340. }
  341. /*
  342. ** UnifyILinkInfo()
  343. **
  344. **
  345. **
  346. ** Arguments:
  347. **
  348. ** Returns:
  349. **
  350. ** Side Effects: none
  351. */
  352. PRIVATE_CODE BOOL UnifyILinkInfo(PCVOLUMEID pcvolid, UINT ucbVolumeIDLen,
  353. LPCTSTR pcszLocalBasePath, PCCNRLINK pccnrl,
  354. UINT ucbCNRLinkLen, LPCTSTR pcszCommonPathSuffix,
  355. PILINKINFO *ppili)
  356. {
  357. BOOL bResult;
  358. UINT ucbILinkInfoLen;
  359. UINT ucbDataOffset;
  360. UINT cbAnsiLocalBasePath;
  361. UINT cbAnsiCommonPathSuffix;
  362. #ifdef UNICODE
  363. BOOL bUnicode;
  364. UINT cchChars;
  365. CHAR szAnsiLocalBasePath[MAX_PATH*2];
  366. CHAR szAnsiCommonPathSuffix[MAX_PATH*2];
  367. UINT cbWideLocalBasePath;
  368. UINT cbWideCommonPathSuffix;
  369. UINT cbChars;
  370. #endif
  371. ASSERT(! ucbVolumeIDLen ||
  372. (IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID) &&
  373. IsDrivePath(pcszLocalBasePath)));
  374. ASSERT(! ucbCNRLinkLen ||
  375. IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  376. ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
  377. ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
  378. #ifdef UNICODE
  379. bUnicode = FALSE;
  380. /*
  381. ** Convert the common-path string from UNICODE->ansi and back again
  382. ** to determine if the string contains any non-ansi characters. If no
  383. ** characters are lost in the conversion then the string contains only
  384. ** ansi chars.
  385. */
  386. cbAnsiCommonPathSuffix = WideCharToMultiByte(CP_ACP, 0, 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, szAnsiCommonPathSuffix, -1,
  397. szWideCommonPathSuffix, ARRAYSIZE(szWideCommonPathSuffix));
  398. if ( cbChars == 0 || lstrcmp(pcszCommonPathSuffix,szWideCommonPathSuffix) != 0 )
  399. {
  400. bUnicode = TRUE;
  401. }
  402. }
  403. if (ucbVolumeIDLen > 0)
  404. {
  405. /*
  406. ** Convert the localbase-path string from UNICODE->ansi and back again
  407. ** to determine if the string contains any non-ansi characters. If no
  408. ** characters are lost in the conversion then the string contains only
  409. ** ansi chars.
  410. */
  411. cbAnsiLocalBasePath = WideCharToMultiByte(CP_ACP, 0, pcszLocalBasePath, -1,
  412. szAnsiLocalBasePath, ARRAYSIZE(szAnsiLocalBasePath),
  413. 0, 0);
  414. if ( cbAnsiLocalBasePath == 0 )
  415. {
  416. bUnicode = FALSE;
  417. }
  418. else
  419. {
  420. WCHAR szWideLocalBasePath[MAX_PATH];
  421. cchChars = MultiByteToWideChar(CP_ACP, 0, szAnsiLocalBasePath, -1,
  422. szWideLocalBasePath, ARRAYSIZE(szWideLocalBasePath));
  423. if ( cchChars == 0 || lstrcmp(pcszLocalBasePath,szWideLocalBasePath) != 0 )
  424. {
  425. bUnicode = TRUE;
  426. }
  427. }
  428. }
  429. else
  430. {
  431. cbAnsiLocalBasePath = 0;
  432. }
  433. if ( bUnicode )
  434. {
  435. ucbDataOffset = SIZEOF(ILINKINFOW);
  436. /* (+ 1) for null terminator. */
  437. cbWideCommonPathSuffix = (lstrlen(pcszCommonPathSuffix) + 1) * sizeof(TCHAR);
  438. if (ucbVolumeIDLen > 0)
  439. cbWideLocalBasePath = (lstrlen(pcszLocalBasePath) + 1) * sizeof(TCHAR);
  440. else
  441. cbWideLocalBasePath = 0;
  442. }
  443. else
  444. {
  445. ucbDataOffset = SIZEOF(ILINKINFOA);
  446. cbWideCommonPathSuffix = 0;
  447. cbWideLocalBasePath = 0;
  448. }
  449. ucbILinkInfoLen = ucbDataOffset +
  450. ucbVolumeIDLen +
  451. cbAnsiLocalBasePath;
  452. if ( bUnicode && ucbVolumeIDLen > 0 )
  453. {
  454. ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
  455. ucbILinkInfoLen += cbWideLocalBasePath;
  456. }
  457. if ( ucbCNRLinkLen > 0 )
  458. {
  459. ucbILinkInfoLen = ALIGN_DWORD_CNT(ucbILinkInfoLen);
  460. ucbILinkInfoLen += ucbCNRLinkLen;
  461. }
  462. ucbILinkInfoLen += cbAnsiCommonPathSuffix;
  463. if ( bUnicode )
  464. {
  465. ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
  466. ucbILinkInfoLen += cbWideCommonPathSuffix;
  467. }
  468. #else
  469. /* Calculate total length. */
  470. /* Assume we don't overflow ucbILinkInfoLen here. */
  471. /*
  472. * Base structure size plus common path suffix length. (+ 1) for null
  473. * terminator.
  474. */
  475. cbAnsiCommonPathSuffix = lstrlen(pcszCommonPathSuffix) + 1;
  476. ucbILinkInfoLen = SIZEOF(**ppili) +
  477. cbAnsiCommonPathSuffix;
  478. /* Plus size of local information. */
  479. if (ucbVolumeIDLen > 0)
  480. {
  481. /* (+ 1) for null terminator. */
  482. cbAnsiLocalBasePath = lstrlen(pcszLocalBasePath) + 1;
  483. ucbILinkInfoLen += ucbVolumeIDLen +
  484. cbAnsiLocalBasePath;
  485. }
  486. /* Plus size of remote information. */
  487. if (ucbCNRLinkLen > 0)
  488. /* (+ 1) for null terminator. */
  489. ucbILinkInfoLen += ucbCNRLinkLen;
  490. ucbDataOffset = SIZEOF(**ppili);
  491. #endif
  492. /* Try to allocate a container. */
  493. bResult = AllocateMemory(ucbILinkInfoLen, ppili);
  494. if (bResult)
  495. {
  496. (*ppili)->li.ucbSize = ucbILinkInfoLen;
  497. (*ppili)->ucbHeaderSize = ucbDataOffset;
  498. (*ppili)->dwFlags = 0;
  499. /* Do we have local information? */
  500. if (ucbVolumeIDLen > 0)
  501. {
  502. /* Yes. Add it to the structure. */
  503. ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID));
  504. ASSERT(IsDrivePath(pcszLocalBasePath));
  505. /* Append local volume ID. */
  506. (*ppili)->ucbVolumeIDOffset = ucbDataOffset;
  507. CopyMemory(ILI_Volume_ID_Ptr(*ppili), pcvolid, ucbVolumeIDLen);
  508. ucbDataOffset += ucbVolumeIDLen;
  509. /* Append local path. */
  510. // lstrcpy: Enough memory is allocated above so unnecessary to do a
  511. // bounded copy
  512. (*ppili)->ucbLocalBasePathOffset = ucbDataOffset;
  513. #ifdef UNICODE
  514. lstrcpyA(ILI_Local_Base_Path_PtrA(*ppili), szAnsiLocalBasePath);
  515. ucbDataOffset += cbAnsiLocalBasePath;
  516. if ( bUnicode )
  517. {
  518. ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
  519. (*ppili)->ucbLocalBasePathOffsetW = ucbDataOffset;
  520. lstrcpy(ILI_Local_Base_Path_PtrW(*ppili), pcszLocalBasePath);
  521. ucbDataOffset += cbWideLocalBasePath;
  522. }
  523. #else
  524. lstrcpy(ILI_Local_Base_Path_Ptr(*ppili), pcszLocalBasePath);
  525. ucbDataOffset += cbAnsiLocalBasePath;
  526. #endif
  527. SET_FLAG((*ppili)->dwFlags, ILI_FL_LOCAL_INFO_VALID);
  528. }
  529. /* Do we have remote information? */
  530. if (ucbCNRLinkLen > 0)
  531. {
  532. ucbDataOffset = ALIGN_DWORD_CNT(ucbDataOffset);
  533. /* Yes. Add it to the structure. */
  534. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  535. /* Append CNR link. */
  536. (*ppili)->ucbCNRLinkOffset = ucbDataOffset;
  537. CopyMemory(ILI_CNR_Link_Ptr(*ppili), pccnrl, ucbCNRLinkLen);
  538. ucbDataOffset += ucbCNRLinkLen;
  539. SET_FLAG((*ppili)->dwFlags, ILI_FL_REMOTE_INFO_VALID);
  540. }
  541. /* Append common path suffix. */
  542. ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
  543. (*ppili)->ucbCommonPathSuffixOffset = ucbDataOffset;
  544. #ifdef UNICODE
  545. lstrcpyA(ILI_Common_Path_Suffix_PtrA(*ppili), szAnsiCommonPathSuffix);
  546. ucbDataOffset += cbAnsiCommonPathSuffix;
  547. if ( bUnicode )
  548. {
  549. ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
  550. (*ppili)->ucbCommonPathSuffixOffsetW = ucbDataOffset;
  551. lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
  552. ucbDataOffset += cbWideCommonPathSuffix;
  553. }
  554. #else /* UNICODE */
  555. lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
  556. #ifdef DEBUG
  557. /*
  558. ** NOTE: This same increment was present above in the UNICODE section
  559. ** enclosed in an #ifdef DEBUG block.
  560. ** It was causing the assertion below (ucbDataOffset == ucbILinkInfoLen)
  561. ** to fail. I have left stmt instance in the ansi build untouched.
  562. ** If the assertion fails in the ansi build you should
  563. ** try removing this next statement. [brianau - 4/15/99]
  564. */
  565. ucbDataOffset += cbAnsiCommonPathSuffix;
  566. #endif
  567. #endif
  568. /* Do all the calculated lengths match? */
  569. // ASSERT(ucbDataOffset == (*ppili)->li.ucbSize);
  570. ASSERT(ucbDataOffset == ucbILinkInfoLen);
  571. }
  572. ASSERT(! bResult ||
  573. IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
  574. return(bResult);
  575. }
  576. /*
  577. ** DestroyILinkInfo()
  578. **
  579. **
  580. **
  581. ** Arguments:
  582. **
  583. ** Returns:
  584. **
  585. ** Side Effects: none
  586. */
  587. PRIVATE_CODE void DestroyILinkInfo(PILINKINFO pili)
  588. {
  589. ASSERT(IS_VALID_STRUCT_PTR(pili, CILINKINFO));
  590. FreeMemory(pili);
  591. return;
  592. }
  593. /*
  594. ** UpdateILinkInfo()
  595. **
  596. **
  597. **
  598. ** Arguments:
  599. **
  600. ** Returns:
  601. **
  602. ** Side Effects: none
  603. **
  604. ** An ILinkInfo structure is updated in the following cases:
  605. **
  606. ** local information:
  607. **
  608. ** 1) the local path has changed
  609. ** 2) remote information is available for the local path
  610. **
  611. ** remote information:
  612. **
  613. ** 3) the remote information is local to this machine, and local information
  614. ** is available for the remote path
  615. */
  616. PRIVATE_CODE BOOL UpdateILinkInfo(PCILINKINFO pcili, LPCTSTR pcszResolvedPath,
  617. PDWORD pdwOutFlags, PILINKINFO *ppiliUpdated)
  618. {
  619. BOOL bResult;
  620. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  621. ASSERT(IS_VALID_STRING_PTR(pcszResolvedPath, CSTR));
  622. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  623. ASSERT(IS_VALID_WRITE_PTR(ppiliUpdated, PILINKINFO));
  624. *pdwOutFlags = 0;
  625. bResult = CreateILinkInfo(pcszResolvedPath, ppiliUpdated);
  626. if (bResult)
  627. {
  628. if (UseNewILinkInfo(pcili, *ppiliUpdated))
  629. {
  630. SET_FLAG(*pdwOutFlags, RLI_OFL_UPDATED);
  631. WARNING_OUT((TEXT("UpdateILinkInfo(): Updating ILinkInfo for path %s."),
  632. pcszResolvedPath));
  633. }
  634. }
  635. ASSERT(! bResult ||
  636. (IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
  637. IS_VALID_STRUCT_PTR(*ppiliUpdated, CILINKINFO)));
  638. return(bResult);
  639. }
  640. /*
  641. ** UseNewILinkInfo()
  642. **
  643. **
  644. **
  645. ** Arguments:
  646. **
  647. ** Returns: TRUE if the new ILinkInfo structure contains more or
  648. ** different information than the old ILinkInfo structure.
  649. **
  650. ** Side Effects: none
  651. */
  652. PRIVATE_CODE BOOL UseNewILinkInfo(PCILINKINFO pciliOld, PCILINKINFO pciliNew)
  653. {
  654. BOOL bUpdate = FALSE;
  655. ASSERT(IS_VALID_STRUCT_PTR(pciliOld, CILINKINFO));
  656. ASSERT(IS_VALID_STRUCT_PTR(pciliNew, CILINKINFO));
  657. /* Does the new ILinkInfo structure contain local information? */
  658. if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  659. {
  660. /* Yes. Does the old ILinkInfo structure contain local information? */
  661. if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  662. /*
  663. * Yes. Update the old ILinkInfo structure if local information
  664. * differs.
  665. */
  666. bUpdate = (CompareILinkInfoLocalData(pciliOld, pciliNew) != CR_EQUAL);
  667. else
  668. /* No. Update the old ILinkInfo structure. */
  669. bUpdate = TRUE;
  670. }
  671. else
  672. /* No. Do not update the old ILinkInfo structure. */
  673. bUpdate = FALSE;
  674. /*
  675. * Do we already need to update the old ILinkInfo structure based on local
  676. * information comparison?
  677. */
  678. if (! bUpdate)
  679. {
  680. /* No. Compare remote information. */
  681. /* Does the new ILinkInfo structure contain remote information? */
  682. if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  683. {
  684. /*
  685. * Yes. Does the old ILinkInfo structure contain remote information?
  686. */
  687. if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  688. /*
  689. * Yes. Update the old ILinkInfo structure if remote information
  690. * differs.
  691. */
  692. bUpdate = (CompareILinkInfoRemoteData(pciliOld, pciliNew)
  693. != CR_EQUAL);
  694. else
  695. /* No. Update the old ILinkInfo structure. */
  696. bUpdate = TRUE;
  697. }
  698. }
  699. return(bUpdate);
  700. }
  701. /*
  702. ** ResolveLocalILinkInfo()
  703. **
  704. **
  705. **
  706. ** Arguments:
  707. **
  708. ** Returns:
  709. **
  710. ** Side Effects: none
  711. */
  712. PRIVATE_CODE BOOL ResolveLocalILinkInfo(PCILINKINFO pcili,
  713. LPTSTR pszResolvedPathBuf,
  714. int cchMax,
  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, ARRAYSIZE(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, cchMax);
  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, ARRAYSIZE(szWideCommonPathSuffix));
  788. }
  789. else
  790. {
  791. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  792. }
  793. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix, MAX_PATH_LEN);
  794. #else
  795. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili), MAX_PATH_LEN);
  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, MAX_PATH_LEN);
  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. int cchMax, 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, cchMax, 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, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  931. szWideCommonPathSuffix, MAX_PATH);
  932. }
  933. else
  934. {
  935. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  936. }
  937. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix, MAX_PATH_LEN);
  938. #else
  939. ASSERT(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL));
  940. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili), MAX_PATH_LEN);
  941. #endif
  942. }
  943. ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) &&
  944. (! bResult ||
  945. (EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) &&
  946. EVAL(IsLocalDrivePath(pszResolvedPathBuf)))));
  947. return(bResult);
  948. }
  949. /*
  950. ** GetLocalPathFromILinkInfo()
  951. **
  952. **
  953. **
  954. ** Arguments:
  955. **
  956. ** Returns:
  957. **
  958. ** Side Effects: none
  959. */
  960. PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO pcili,
  961. LPTSTR pszResolvedPathBuf,
  962. int cchMax)
  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, cchMax));
  972. #ifdef UNICODE
  973. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  974. {
  975. pszWideLocalBasePath = szWideLocalBasePath;
  976. MultiByteToWideChar(CP_ACP, 0, ILI_Local_Base_Path_PtrA(pcili), -1,
  977. szWideLocalBasePath, ARRAYSIZE(szWideLocalBasePath));
  978. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  979. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  980. szWideCommonPathSuffix, ARRAYSIZE(szWideCommonPathSuffix));
  981. }
  982. else
  983. {
  984. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  985. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  986. }
  987. lstrcpyn(pszResolvedPathBuf, pszWideLocalBasePath, cchMax);
  988. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix, cchMax);
  989. #else
  990. lstrcpyn(pszResolvedPathBuf, ILI_Local_Base_Path_Ptr(pcili), cchMax);
  991. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili), cchMax);
  992. #endif
  993. ASSERT(lstrlen(pszResolvedPathBuf) < cchMax);
  994. ASSERT(IsDrivePath(pszResolvedPathBuf));
  995. return;
  996. }
  997. /*
  998. ** GetRemotePathFromILinkInfo()
  999. **
  1000. **
  1001. **
  1002. ** Arguments:
  1003. **
  1004. ** Returns:
  1005. **
  1006. ** Side Effects: none
  1007. */
  1008. PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO pcili,
  1009. LPTSTR pszResolvedPathBuf,
  1010. int cchMax)
  1011. {
  1012. #ifdef UNICODE
  1013. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1014. LPWSTR pszWideCommonPathSuffix;
  1015. #endif
  1016. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1017. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, cchMax));
  1018. /* It's ok that this is broken for non-UNC CNR names. */
  1019. GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), pszResolvedPathBuf, cchMax);
  1020. #ifdef UNICODE
  1021. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1022. {
  1023. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1024. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1025. szWideCommonPathSuffix, ARRAYSIZE(szWideCommonPathSuffix));
  1026. }
  1027. else
  1028. {
  1029. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1030. }
  1031. CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix, cchMax);
  1032. #else
  1033. CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili), cchMax);
  1034. #endif
  1035. return;
  1036. }
  1037. /*
  1038. ** CompareILinkInfoReferents()
  1039. **
  1040. ** Compares the referents of two ILINKINFO structures.
  1041. **
  1042. ** Arguments:
  1043. **
  1044. ** Returns:
  1045. **
  1046. ** Side Effects: none
  1047. **
  1048. ** Comparison is performed on ILINKINFO data in only one of the following ways
  1049. ** in the following order:
  1050. **
  1051. ** 1) local data compared with local data
  1052. ** 2) remote data compared with remote data
  1053. ** 3) local data only < remote data only
  1054. */
  1055. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoReferents(PCILINKINFO pciliFirst,
  1056. PCILINKINFO pciliSecond)
  1057. {
  1058. COMPARISONRESULT cr;
  1059. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1060. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1061. /*
  1062. * We can't just perform a binary comparison of the two ILinkInfos here. We
  1063. * may have two LinkInfos that refer to the same path, but differ in case on
  1064. * a non-case-sensitive file system.
  1065. */
  1066. /* Compare ILinkInfos by local or remote data. */
  1067. if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID) &&
  1068. IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1069. /* Compare local data. */
  1070. cr = CompareILinkInfoLocalData(pciliFirst, pciliSecond);
  1071. else if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_REMOTE_INFO_VALID) &&
  1072. IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1073. /* Compare remote data. */
  1074. cr = CompareILinkInfoRemoteData(pciliFirst, pciliSecond);
  1075. else
  1076. {
  1077. /*
  1078. * One contains only valid local information and the other contains only
  1079. * valid remote information.
  1080. */
  1081. ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
  1082. (pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
  1083. /* By fiat, local only < remote only. */
  1084. if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1085. cr = CR_FIRST_SMALLER;
  1086. else
  1087. cr = CR_FIRST_LARGER;
  1088. }
  1089. ASSERT(IsValidCOMPARISONRESULT(cr));
  1090. return(cr);
  1091. }
  1092. /*
  1093. ** CompareILinkInfoLocalData()
  1094. **
  1095. **
  1096. **
  1097. ** Arguments:
  1098. **
  1099. ** Returns:
  1100. **
  1101. ** Side Effects: none
  1102. **
  1103. ** Local ILinkInfo data is compared in the following order:
  1104. **
  1105. ** 1) volume ID
  1106. ** 2) sub path from root
  1107. */
  1108. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoLocalData(PCILINKINFO pciliFirst,
  1109. PCILINKINFO pciliSecond)
  1110. {
  1111. COMPARISONRESULT cr;
  1112. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1113. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1114. cr = CompareVolumeIDs(ILI_Volume_ID_Ptr(pciliFirst),
  1115. ILI_Volume_ID_Ptr(pciliSecond));
  1116. if (cr == CR_EQUAL)
  1117. cr = CompareLocalPaths(pciliFirst, pciliSecond);
  1118. ASSERT(IsValidCOMPARISONRESULT(cr));
  1119. return(cr);
  1120. }
  1121. /*
  1122. ** CompareLocalPaths()
  1123. **
  1124. **
  1125. **
  1126. ** Arguments:
  1127. **
  1128. ** Returns:
  1129. **
  1130. ** Side Effects: none
  1131. */
  1132. PRIVATE_CODE COMPARISONRESULT CompareLocalPaths(PCILINKINFO pciliFirst,
  1133. PCILINKINFO pciliSecond)
  1134. {
  1135. COMPARISONRESULT cr;
  1136. TCHAR rgchFirstLocalPath[MAX_PATH_LEN];
  1137. TCHAR rgchSecondLocalPath[MAX_PATH_LEN];
  1138. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1139. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1140. GetLocalPathFromILinkInfo(pciliFirst, rgchFirstLocalPath, ARRAYSIZE(rgchFirstLocalPath));
  1141. GetLocalPathFromILinkInfo(pciliSecond, rgchSecondLocalPath, ARRAYSIZE(rgchSecondLocalPath));
  1142. cr = ComparePathStrings(rgchFirstLocalPath, rgchSecondLocalPath);
  1143. ASSERT(IsValidCOMPARISONRESULT(cr));
  1144. return(cr);
  1145. }
  1146. /*
  1147. ** CompareILinkInfoRemoteData()
  1148. **
  1149. **
  1150. **
  1151. ** Arguments:
  1152. **
  1153. ** Returns:
  1154. **
  1155. ** Side Effects: none
  1156. */
  1157. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoRemoteData(PCILINKINFO pciliFirst,
  1158. PCILINKINFO pciliSecond)
  1159. {
  1160. COMPARISONRESULT cr;
  1161. #ifdef UNICODE
  1162. WCHAR szWideCommonPathSuffixFirst[MAX_PATH];
  1163. WCHAR szWideCommonPathSuffixSecond[MAX_PATH];
  1164. LPWSTR pszWideCommonPathSuffixFirst;
  1165. LPWSTR pszWideCommonPathSuffixSecond;
  1166. #endif
  1167. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1168. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1169. cr = CompareCNRLinks(ILI_CNR_Link_Ptr(pciliFirst),
  1170. ILI_CNR_Link_Ptr(pciliSecond));
  1171. #ifdef UNICODE
  1172. if (pciliFirst->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1173. {
  1174. pszWideCommonPathSuffixFirst = szWideCommonPathSuffixFirst;
  1175. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pciliFirst), -1,
  1176. szWideCommonPathSuffixFirst, MAX_PATH);
  1177. }
  1178. else
  1179. {
  1180. pszWideCommonPathSuffixFirst = ILI_Common_Path_Suffix_Ptr(pciliFirst);
  1181. }
  1182. if (pciliSecond->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1183. {
  1184. pszWideCommonPathSuffixSecond = szWideCommonPathSuffixSecond;
  1185. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pciliSecond), -1,
  1186. szWideCommonPathSuffixSecond, MAX_PATH);
  1187. }
  1188. else
  1189. {
  1190. pszWideCommonPathSuffixSecond = ILI_Common_Path_Suffix_Ptr(pciliSecond);
  1191. }
  1192. #else
  1193. if (cr == CR_EQUAL)
  1194. cr = ComparePathStrings(ILI_Common_Path_Suffix_Ptr(pciliFirst),
  1195. ILI_Common_Path_Suffix_Ptr(pciliSecond));
  1196. #endif
  1197. ASSERT(IsValidCOMPARISONRESULT(cr));
  1198. return(cr);
  1199. }
  1200. /*
  1201. ** CompareILinkInfoVolumes()
  1202. **
  1203. **
  1204. **
  1205. ** Arguments:
  1206. **
  1207. ** Returns:
  1208. **
  1209. ** Side Effects: none
  1210. */
  1211. PRIVATE_CODE COMPARISONRESULT CompareILinkInfoVolumes(PCILINKINFO pciliFirst,
  1212. PCILINKINFO pciliSecond)
  1213. {
  1214. COMPARISONRESULT cr;
  1215. BOOL bFirstLocal;
  1216. BOOL bFirstRemote;
  1217. BOOL bSecondLocal;
  1218. BOOL bSecondRemote;
  1219. ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
  1220. ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
  1221. bFirstLocal = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
  1222. ILI_FL_LOCAL_INFO_VALID);
  1223. bFirstRemote = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
  1224. ILI_FL_REMOTE_INFO_VALID);
  1225. bSecondLocal = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
  1226. ILI_FL_LOCAL_INFO_VALID);
  1227. bSecondRemote = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
  1228. ILI_FL_REMOTE_INFO_VALID);
  1229. if (bFirstLocal && bSecondLocal)
  1230. /* First and second have local information. */
  1231. cr = CompareVolumeIDs(ILI_Volume_ID_Ptr((PCILINKINFO)pciliFirst),
  1232. ILI_Volume_ID_Ptr((PCILINKINFO)pciliSecond));
  1233. else if (bFirstRemote && bSecondRemote)
  1234. /* First and second have remote information. */
  1235. cr = CompareCNRLinks(ILI_CNR_Link_Ptr((PCILINKINFO)pciliFirst),
  1236. ILI_CNR_Link_Ptr((PCILINKINFO)pciliSecond));
  1237. else
  1238. {
  1239. /*
  1240. * One contains only valid local information and the other contains only
  1241. * valid remote information.
  1242. */
  1243. ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
  1244. (pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
  1245. /* By fiat, local only < remote only. */
  1246. if (bFirstLocal)
  1247. /*
  1248. * First has only local information. Second has only remote
  1249. * information.
  1250. */
  1251. cr = CR_FIRST_SMALLER;
  1252. else
  1253. /*
  1254. * First has only remote information. Second has only local
  1255. * information.
  1256. */
  1257. cr = CR_FIRST_LARGER;
  1258. }
  1259. return(cr);
  1260. }
  1261. /*
  1262. ** CheckCombinedPathLen()
  1263. **
  1264. **
  1265. **
  1266. ** Arguments:
  1267. **
  1268. ** Returns:
  1269. **
  1270. ** Side Effects: none
  1271. */
  1272. PRIVATE_CODE BOOL CheckCombinedPathLen(LPCTSTR pcszBase, LPCTSTR pcszSuffix)
  1273. {
  1274. BOOL bResult;
  1275. ASSERT(IS_VALID_STRING_PTR(pcszBase, CSTR));
  1276. ASSERT(IS_VALID_STRING_PTR(pcszSuffix, CSTR));
  1277. bResult = EVAL(lstrlen(pcszBase) + lstrlen(pcszSuffix) < MAX_PATH_LEN);
  1278. if (bResult)
  1279. {
  1280. TCHAR rgchCombinedPath[MAX_PATH_LEN + 1];
  1281. lstrcpyn(rgchCombinedPath, pcszBase, ARRAYSIZE(rgchCombinedPath));
  1282. CatPath(rgchCombinedPath, pcszSuffix, ARRAYSIZE(rgchCombinedPath));
  1283. bResult = EVAL(lstrlen(rgchCombinedPath) < MAX_PATH_LEN);
  1284. }
  1285. return(bResult);
  1286. }
  1287. /*
  1288. ** GetILinkInfoData()
  1289. **
  1290. **
  1291. **
  1292. ** Arguments:
  1293. **
  1294. ** Returns:
  1295. **
  1296. ** Side Effects: none
  1297. */
  1298. PRIVATE_CODE BOOL GetILinkInfoData(PCILINKINFO pcili, LINKINFODATATYPE lidt,
  1299. PCVOID *ppcvData)
  1300. {
  1301. BOOL bResult = FALSE;
  1302. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1303. ASSERT(IsValidLINKINFODATATYPE(lidt));
  1304. ASSERT(IS_VALID_WRITE_PTR(ppcvData, PCVOID));
  1305. switch (lidt)
  1306. {
  1307. case LIDT_VOLUME_SERIAL_NUMBER:
  1308. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1309. bResult = GetVolumeSerialNumber(ILI_Volume_ID_Ptr(pcili),
  1310. (PCDWORD *)ppcvData);
  1311. break;
  1312. case LIDT_DRIVE_TYPE:
  1313. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1314. bResult = GetVolumeDriveType(ILI_Volume_ID_Ptr(pcili),
  1315. (PCUINT *)ppcvData);
  1316. break;
  1317. case LIDT_VOLUME_LABEL:
  1318. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1319. bResult = GetVolumeLabel(ILI_Volume_ID_Ptr(pcili),
  1320. (LPCSTR *)ppcvData);
  1321. break;
  1322. case LIDT_VOLUME_LABELW:
  1323. #ifdef UNICODE
  1324. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1325. bResult = GetVolumeLabelW(ILI_Volume_ID_Ptr(pcili),
  1326. (LPCTSTR *)ppcvData);
  1327. #endif
  1328. break;
  1329. case LIDT_LOCAL_BASE_PATH:
  1330. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1331. {
  1332. *ppcvData = ILI_Local_Base_Path_PtrA(pcili);
  1333. bResult = TRUE;
  1334. }
  1335. break;
  1336. case LIDT_LOCAL_BASE_PATHW:
  1337. #ifdef UNICODE
  1338. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1339. {
  1340. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1341. *ppcvData = NULL;
  1342. else
  1343. *ppcvData = ILI_Local_Base_Path_PtrW(pcili);
  1344. bResult = TRUE;
  1345. }
  1346. #endif
  1347. break;
  1348. case LIDT_NET_TYPE:
  1349. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1350. bResult = GetCNRNetType(ILI_CNR_Link_Ptr(pcili),
  1351. (PCDWORD *)ppcvData);
  1352. break;
  1353. case LIDT_NET_RESOURCE:
  1354. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1355. bResult = GetCNRName(ILI_CNR_Link_Ptr(pcili),
  1356. (LPCSTR *)ppcvData);
  1357. break;
  1358. case LIDT_NET_RESOURCEW:
  1359. #ifdef UNICODE
  1360. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1361. bResult = GetCNRNameW(ILI_CNR_Link_Ptr(pcili),
  1362. (LPCWSTR *)ppcvData);
  1363. #endif
  1364. break;
  1365. case LIDT_REDIRECTED_DEVICE:
  1366. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1367. bResult = GetLastRedirectedDevice(ILI_CNR_Link_Ptr(pcili),
  1368. (LPCSTR *)ppcvData);
  1369. break;
  1370. case LIDT_REDIRECTED_DEVICEW:
  1371. #ifdef UNICODE
  1372. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1373. bResult = GetLastRedirectedDeviceW(ILI_CNR_Link_Ptr(pcili),
  1374. (LPCWSTR *)ppcvData);
  1375. #endif
  1376. break;
  1377. case LIDT_COMMON_PATH_SUFFIX:
  1378. *ppcvData = ILI_Common_Path_Suffix_PtrA(pcili);
  1379. bResult = TRUE;
  1380. break;
  1381. case LIDT_COMMON_PATH_SUFFIXW:
  1382. #ifdef UNICODE
  1383. if (pcili->ucbHeaderSize == sizeof(ILINKINFOA))
  1384. {
  1385. *ppcvData = NULL;
  1386. }
  1387. else
  1388. {
  1389. *ppcvData = ILI_Common_Path_Suffix_PtrW(pcili);
  1390. }
  1391. bResult = TRUE;
  1392. #endif
  1393. break;
  1394. default:
  1395. bResult = FALSE;
  1396. ERROR_OUT((TEXT("GetILinkInfoData(): Bad LINKINFODATATYPE %d."),
  1397. lidt));
  1398. break;
  1399. }
  1400. return(bResult);
  1401. }
  1402. /*
  1403. ** DisconnectILinkInfo()
  1404. **
  1405. **
  1406. **
  1407. ** Arguments:
  1408. **
  1409. ** Returns:
  1410. **
  1411. ** Side Effects: none
  1412. */
  1413. PRIVATE_CODE BOOL DisconnectILinkInfo(PCILINKINFO pcili)
  1414. {
  1415. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1416. return(DisconnectFromCNR(ILI_CNR_Link_Ptr(pcili)));
  1417. }
  1418. #if defined(DEBUG) || defined(EXPV)
  1419. /*
  1420. ** IsValidLINKINFODATATYPE()
  1421. **
  1422. **
  1423. **
  1424. ** Arguments:
  1425. **
  1426. ** Returns:
  1427. **
  1428. ** Side Effects: none
  1429. */
  1430. PRIVATE_CODE BOOL IsValidLINKINFODATATYPE(LINKINFODATATYPE lidt)
  1431. {
  1432. BOOL bResult;
  1433. switch (lidt)
  1434. {
  1435. case LIDT_VOLUME_SERIAL_NUMBER:
  1436. case LIDT_DRIVE_TYPE:
  1437. case LIDT_VOLUME_LABEL:
  1438. case LIDT_VOLUME_LABELW:
  1439. case LIDT_LOCAL_BASE_PATH:
  1440. case LIDT_LOCAL_BASE_PATHW:
  1441. case LIDT_NET_TYPE:
  1442. case LIDT_NET_RESOURCE:
  1443. case LIDT_NET_RESOURCEW:
  1444. case LIDT_REDIRECTED_DEVICE:
  1445. case LIDT_COMMON_PATH_SUFFIX:
  1446. case LIDT_COMMON_PATH_SUFFIXW:
  1447. bResult = TRUE;
  1448. break;
  1449. default:
  1450. bResult = FALSE;
  1451. ERROR_OUT((TEXT("IsValidLINKINFODATATYPE(): Invalid LINKINFODATATYPE %d."),
  1452. lidt));
  1453. break;
  1454. }
  1455. return(bResult);
  1456. }
  1457. #endif
  1458. #if defined(DEBUG) || defined(VSTF)
  1459. /*
  1460. ** CheckILIFlags()
  1461. **
  1462. **
  1463. **
  1464. ** Arguments:
  1465. **
  1466. ** Returns:
  1467. **
  1468. ** Side Effects: none
  1469. */
  1470. PRIVATE_CODE BOOL CheckILIFlags(PCILINKINFO pcili)
  1471. {
  1472. return(FLAGS_ARE_VALID(pcili->dwFlags, ALL_ILINKINFO_FLAGS) &&
  1473. (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
  1474. IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID)));
  1475. }
  1476. /*
  1477. ** CheckILICommonPathSuffix()
  1478. **
  1479. **
  1480. **
  1481. ** Arguments:
  1482. **
  1483. ** Returns:
  1484. **
  1485. ** Side Effects: none
  1486. */
  1487. PRIVATE_CODE BOOL CheckILICommonPathSuffix(PCILINKINFO pcili)
  1488. {
  1489. return(IS_VALID_STRING_PTRA(ILI_Common_Path_Suffix_PtrA(pcili), CSTR) &&
  1490. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1491. ILI_Common_Path_Suffix_PtrA(pcili),
  1492. lstrlenA(ILI_Common_Path_Suffix_PtrA(pcili)))) &&
  1493. EVAL(! IS_SLASH(*ILI_Common_Path_Suffix_PtrA(pcili))));
  1494. }
  1495. /*
  1496. ** CheckILILocalInfo()
  1497. **
  1498. **
  1499. **
  1500. ** Arguments:
  1501. **
  1502. ** Returns:
  1503. **
  1504. ** Side Effects: none
  1505. */
  1506. PRIVATE_CODE BOOL CheckILILocalInfo(PCILINKINFO pcili)
  1507. {
  1508. #ifdef UNICODE
  1509. WCHAR szWideLocalBasePath[MAX_PATH];
  1510. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1511. LPWSTR pszWideLocalBasePath;
  1512. LPWSTR pszWideCommonPathSuffix;
  1513. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1514. return FALSE;
  1515. if (!IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID))
  1516. return FALSE;
  1517. if (!EVAL(IsContained(pcili, pcili->li.ucbSize,ILI_Volume_ID_Ptr(pcili),
  1518. GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))))
  1519. return FALSE;
  1520. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1521. {
  1522. pszWideLocalBasePath = szWideLocalBasePath;
  1523. MultiByteToWideChar(CP_ACP, 0, ILI_Local_Base_Path_PtrA(pcili), -1,
  1524. szWideLocalBasePath, MAX_PATH);
  1525. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1526. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1527. szWideCommonPathSuffix, MAX_PATH);
  1528. }
  1529. else
  1530. {
  1531. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  1532. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1533. }
  1534. if (!EVAL(IsDrivePath(pszWideLocalBasePath)))
  1535. return FALSE;
  1536. if (!EVAL(IsContained(pcili, pcili->li.ucbSize,
  1537. ILI_Local_Base_Path_PtrA(pcili),
  1538. lstrlenA(ILI_Local_Base_Path_PtrA(pcili)))))
  1539. return FALSE;
  1540. if (!EVAL(CheckCombinedPathLen(pszWideLocalBasePath,
  1541. pszWideCommonPathSuffix)))
  1542. return FALSE;
  1543. return TRUE;
  1544. #else
  1545. return(IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
  1546. /* Check volume ID. */
  1547. (IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID) &&
  1548. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1549. ILI_Volume_ID_Ptr(pcili),
  1550. GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))) &&
  1551. /* Check local base path. */
  1552. EVAL(IsDrivePath(ILI_Local_Base_Path_Ptr(pcili))) &&
  1553. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1554. ILI_Local_Base_Path_PtrA(pcili),
  1555. lstrlen(ILI_Local_Base_Path_Ptr(pcili)))) &&
  1556. EVAL(CheckCombinedPathLen(ILI_Local_Base_Path_Ptr(pcili),
  1557. ILI_Common_Path_Suffix_Ptr(pcili)))));
  1558. #endif
  1559. }
  1560. /*
  1561. ** CheckILIRemoteInfo()
  1562. **
  1563. **
  1564. **
  1565. ** Arguments:
  1566. **
  1567. ** Returns:
  1568. **
  1569. ** Side Effects: none
  1570. */
  1571. PRIVATE_CODE BOOL CheckILIRemoteInfo(PCILINKINFO pcili)
  1572. {
  1573. BOOL bResult;
  1574. if (IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1575. bResult = TRUE;
  1576. else
  1577. {
  1578. /* Check CNR link. */
  1579. if (IS_VALID_STRUCT_PTR(ILI_CNR_Link_Ptr(pcili), CCNRLINK) &&
  1580. EVAL(IsContained(pcili, pcili->li.ucbSize,
  1581. ILI_CNR_Link_Ptr(pcili),
  1582. GetCNRLinkLen(ILI_CNR_Link_Ptr(pcili)))))
  1583. {
  1584. TCHAR rgchRemoteBasePath[MAX_PATH_LEN];
  1585. #ifdef UNICODE
  1586. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1587. LPWSTR pszWideCommonPathSuffix;
  1588. #endif
  1589. /* RAIDRAID: (15724) This is broken for non-UNC CNR names. */
  1590. GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), rgchRemoteBasePath, ARRAYSIZE(rgchRemoteBasePath));
  1591. #ifdef UNICODE
  1592. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1593. {
  1594. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1595. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1596. szWideCommonPathSuffix, ARRAYSIZE(szWideCommonPathSuffix));
  1597. }
  1598. else
  1599. {
  1600. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1601. }
  1602. bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
  1603. pszWideCommonPathSuffix));
  1604. #else
  1605. bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
  1606. ILI_Common_Path_Suffix_Ptr(pcili)));
  1607. #endif
  1608. }
  1609. else
  1610. bResult = FALSE;
  1611. }
  1612. return(bResult);
  1613. }
  1614. /*
  1615. ** IsValidPCLINKINFO()
  1616. **
  1617. **
  1618. **
  1619. ** Arguments:
  1620. **
  1621. ** Returns:
  1622. **
  1623. ** Side Effects: none
  1624. */
  1625. PRIVATE_CODE BOOL IsValidPCLINKINFO(PCLINKINFO pcli)
  1626. {
  1627. return(IS_VALID_STRUCT_PTR((PCILINKINFO)pcli, CILINKINFO));
  1628. }
  1629. /*
  1630. ** IsValidPCILINKINFO()
  1631. **
  1632. **
  1633. **
  1634. ** Arguments:
  1635. **
  1636. ** Returns:
  1637. **
  1638. ** Side Effects: none
  1639. */
  1640. PRIVATE_CODE BOOL IsValidPCILINKINFO(PCILINKINFO pcili)
  1641. {
  1642. /*
  1643. * A "valid" LinkInfo structure has the following characteristics:
  1644. *
  1645. * 1) entire structure is readable
  1646. * 2) size of ILINKINFO header structure >= SIZEOF(CILINKINFO)
  1647. * 3) flags are valid
  1648. * 4) either local info or remote info or both are valid
  1649. * 5) contained structures and strings are valid and are entirely contained
  1650. * in LinkInfo structure
  1651. * 6) lstrlen() of combined paths < MAX_PATH_LEN
  1652. */
  1653. return(IS_VALID_READ_PTR(pcili, CILINKINFO) &&
  1654. IS_VALID_READ_BUFFER_PTR(pcili, CILINKINFO, pcili->li.ucbSize) &&
  1655. EVAL(pcili->ucbHeaderSize >= SIZEOF(*pcili)) &&
  1656. EVAL(CheckILIFlags(pcili)) &&
  1657. EVAL(CheckILICommonPathSuffix(pcili)) &&
  1658. EVAL(CheckILILocalInfo(pcili)) &&
  1659. EVAL(CheckILIRemoteInfo(pcili)));
  1660. }
  1661. #endif
  1662. #ifdef DEBUG
  1663. /*
  1664. ** DumpILinkInfo()
  1665. **
  1666. **
  1667. **
  1668. ** Arguments:
  1669. **
  1670. ** Returns:
  1671. **
  1672. ** Side Effects: none
  1673. */
  1674. PRIVATE_CODE void DumpILinkInfo(PCILINKINFO pcili)
  1675. {
  1676. #ifdef UNICODE
  1677. WCHAR szWideCommonPathSuffix[MAX_PATH];
  1678. LPWSTR pszWideCommonPathSuffix;
  1679. #endif
  1680. ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
  1681. PLAIN_TRACE_OUT((TEXT("%s[LinkInfo] ucbSize = %#x"),
  1682. INDENT_STRING,
  1683. pcili->li.ucbSize));
  1684. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] ucbHeaderSize = %#x"),
  1685. INDENT_STRING,
  1686. INDENT_STRING,
  1687. pcili->ucbHeaderSize));
  1688. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] dwFLags = %#08lx"),
  1689. INDENT_STRING,
  1690. INDENT_STRING,
  1691. pcili->dwFlags));
  1692. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  1693. {
  1694. #ifdef UNICODE
  1695. WCHAR szWideLocalBasePath[MAX_PATH];
  1696. LPWSTR pszWideLocalBasePath;
  1697. #endif
  1698. DumpVolumeID(ILI_Volume_ID_Ptr(pcili));
  1699. #ifdef UNICODE
  1700. if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1701. {
  1702. pszWideLocalBasePath = szWideLocalBasePath;
  1703. MultiByteToWideChar(CP_ACP, 0, ILI_Local_Base_Path_PtrA(pcili), -1,
  1704. szWideLocalBasePath, ARRAYSIZE(szWideLocalBasePath));
  1705. }
  1706. else
  1707. {
  1708. pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
  1709. }
  1710. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
  1711. INDENT_STRING,
  1712. INDENT_STRING,
  1713. pszWideLocalBasePath));
  1714. #else
  1715. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
  1716. INDENT_STRING,
  1717. INDENT_STRING,
  1718. ILI_Local_Base_Path_Ptr(pcili)));
  1719. #endif
  1720. }
  1721. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  1722. DumpCNRLink(ILI_CNR_Link_Ptr(pcili));
  1723. #ifdef UNICODE
  1724. if ( pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
  1725. {
  1726. pszWideCommonPathSuffix = szWideCommonPathSuffix;
  1727. MultiByteToWideChar(CP_ACP, 0, ILI_Common_Path_Suffix_PtrA(pcili), -1,
  1728. szWideCommonPathSuffix, ARRAYSIZE(szWideCommonPathSuffix));
  1729. }
  1730. else
  1731. {
  1732. pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
  1733. }
  1734. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
  1735. INDENT_STRING,
  1736. INDENT_STRING,
  1737. pszWideCommonPathSuffix));
  1738. #else
  1739. PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
  1740. INDENT_STRING,
  1741. INDENT_STRING,
  1742. ILI_Common_Path_Suffix_Ptr(pcili)));
  1743. #endif
  1744. return;
  1745. }
  1746. #endif
  1747. /***************************** Exported Functions ****************************/
  1748. /******************************************************************************
  1749. @doc LINKINFOAPI
  1750. @func BOOL | CreateLinkInfo | Creates a LinkInfo structure for a path.
  1751. @parm PCSTR | pcszPath | A pointer to the path string that a LinkInfo structure
  1752. is to be created for.
  1753. @parm PLINKINFO * | ppli | A pointer to a PLINKINFO to be filled in with a
  1754. pointer to the new LinkInfo structure. *ppli is only valid if TRUE is
  1755. returned.
  1756. @rdesc If a LinkInfo structure was created successfully, TRUE is returned, and
  1757. *ppli contains a pointer to the new LinkInfo structure. Otherwise, a LinkInfo
  1758. structure was not created successfully, and *ppli is undefined. The reason for
  1759. failure may be determined by calling GetLastError().
  1760. @comm Once the caller is finshed with the LinkInfo structure returned by
  1761. CreateLinkInfo(), DestroyLinkInfo() should be called to free the LinkInfo
  1762. structure.<nl>
  1763. The contents of the LinkInfo structure returned are opaque to the caller, with
  1764. the exception of the first field of the LinkInfo structure. The first field of
  1765. the LinkInfo structure, ucbSize, is a UINT containing the size of the LinkInfo
  1766. structure in bytes, including the ucbSize field.<nl>
  1767. The LinkInfo structure is created in memory that is private to the LinkInfo
  1768. APIs. The returned LinkInfo structure should be copied into the caller's
  1769. memory, and the DestroyLinkInfo() should be called to free the LinkInfo
  1770. structure from the LinkInfo APIs' private memory.
  1771. @xref DestroyLinkInfo
  1772. ******************************************************************************/
  1773. LINKINFOAPI BOOL WINAPI CreateLinkInfo(LPCTSTR pcszPath, PLINKINFO *ppli)
  1774. {
  1775. BOOL bResult;
  1776. DebugEntry(CreateLinkInfo);
  1777. #ifdef EXPV
  1778. /* Verify parameters. */
  1779. if (IS_VALID_STRING_PTR(pcszPath, CSTR) &&
  1780. IS_VALID_WRITE_PTR(ppli, PLINKINFO))
  1781. #endif
  1782. {
  1783. bResult = CreateILinkInfo(pcszPath, (PILINKINFO *)ppli);
  1784. #ifdef DEBUG
  1785. if (bResult)
  1786. {
  1787. TRACE_OUT((TEXT("CreateLinkInfo(): LinkInfo created for path %s:"),
  1788. pcszPath));
  1789. DumpILinkInfo(*(PILINKINFO *)ppli);
  1790. }
  1791. #endif
  1792. }
  1793. #ifdef EXPV
  1794. else
  1795. {
  1796. SetLastError(ERROR_INVALID_PARAMETER);
  1797. bResult = FALSE;
  1798. }
  1799. #endif
  1800. ASSERT(! bResult ||
  1801. IS_VALID_STRUCT_PTR(*ppli, CLINKINFO));
  1802. DebugExitBOOL(CreateLinkInfo, bResult);
  1803. return(bResult);
  1804. }
  1805. #ifdef UNICODE
  1806. LINKINFOAPI BOOL WINAPI CreateLinkInfoA(LPCSTR pcszPath, PLINKINFO *ppli)
  1807. {
  1808. LPWSTR lpwstr;
  1809. UINT cchPath;
  1810. cchPath = lstrlenA(pcszPath) + 1;
  1811. lpwstr = (LPWSTR)_alloca(cchPath*SIZEOF(WCHAR));
  1812. if (MultiByteToWideChar(CP_ACP, 0, pcszPath, cchPath,
  1813. lpwstr, cchPath) == 0)
  1814. {
  1815. return FALSE;
  1816. }
  1817. else
  1818. {
  1819. return CreateLinkInfo(lpwstr,ppli);
  1820. }
  1821. }
  1822. #endif
  1823. /******************************************************************************
  1824. @doc LINKINFOAPI
  1825. @func void | DestroyLinkInfo | Destroys a LinkInfo structure created by
  1826. CreateLinkInfo().
  1827. @parm PLINKINFO | pli | A pointer to the LinkInfo structure to be destroyed.
  1828. @xref CreateLinkInfo
  1829. ******************************************************************************/
  1830. LINKINFOAPI void WINAPI DestroyLinkInfo(PLINKINFO pli)
  1831. {
  1832. DebugEntry(DestroyLinkInfo);
  1833. #ifdef EXPV
  1834. /* Verify parameters. */
  1835. if (
  1836. IS_VALID_STRUCT_PTR(pli, CLINKINFO))
  1837. #endif
  1838. {
  1839. DestroyILinkInfo((PILINKINFO)pli);
  1840. }
  1841. DebugExitVOID(DestroyLinkInfo);
  1842. return;
  1843. }
  1844. /******************************************************************************
  1845. @doc LINKINFOAPI
  1846. @func int | CompareLinkInfoReferents | Compares the referents of two LinkInfo
  1847. structures.
  1848. @parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
  1849. referent is to be compared.
  1850. @parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
  1851. whose referent is to be compared.
  1852. @rdesc If the referent of the first LinkInfo structure is less than the
  1853. referent of the second LinkInfo structure, a negative value is returned. If
  1854. the referent of the first LinkInfo structure is the same as the referent of the
  1855. second LinkInfo structure, zero is returned. If the referent of the first
  1856. LinkInfo structure is larger than the referent of the second LinkInfo
  1857. structure, a positive value is returned. An invalid LinkInfo structure is
  1858. considered to have a referent that is less than the referent of any valid
  1859. LinkInfo structure. All invalid LinkInfo structures are considered to have the
  1860. same referent.
  1861. @comm The value returned is actually a COMPARISONRESULT, for clients that
  1862. understand COMPARISONRESULTs, like SYNCENG.DLL.
  1863. @xref CompareLinkInfoVolumes
  1864. ******************************************************************************/
  1865. LINKINFOAPI int WINAPI CompareLinkInfoReferents(PCLINKINFO pcliFirst,
  1866. PCLINKINFO pcliSecond)
  1867. {
  1868. COMPARISONRESULT cr;
  1869. BOOL bFirstValid;
  1870. BOOL bSecondValid;
  1871. DebugEntry(CompareLinkInfoReferents);
  1872. bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
  1873. bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
  1874. if (bFirstValid)
  1875. {
  1876. if (bSecondValid)
  1877. cr = CompareILinkInfoReferents((PCILINKINFO)pcliFirst,
  1878. (PCILINKINFO)pcliSecond);
  1879. else
  1880. cr = CR_FIRST_LARGER;
  1881. }
  1882. else
  1883. {
  1884. if (bSecondValid)
  1885. cr = CR_FIRST_SMALLER;
  1886. else
  1887. cr = CR_EQUAL;
  1888. }
  1889. ASSERT(IsValidCOMPARISONRESULT(cr));
  1890. DebugExitCOMPARISONRESULT(CompareLinkInfoReferents, cr);
  1891. return(cr);
  1892. }
  1893. /******************************************************************************
  1894. @doc LINKINFOAPI
  1895. @func int | CompareLinkInfoVolumes | Compares the volumes of the referents of
  1896. two LinkInfo structures.
  1897. @parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
  1898. referent's volume is to be compared.
  1899. @parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
  1900. referent's volume is to be compared.
  1901. @rdesc If the volume of the referent of the first LinkInfo structure is less
  1902. than the volume of the referent of the second LinkInfo structure, a negative
  1903. value is returned. If the volume of the referent of the first LinkInfo
  1904. structure is the same as the volume of the referent of the second LinkInfo
  1905. structure, zero is returned. If the volume of the referent of the first
  1906. LinkInfo structure is larger than the volume of the referent of the second
  1907. LinkInfo structure, a positive value is returned. An invalid LinkInfo
  1908. structure is considered to have a referent's volume that is less than the
  1909. referent's volume of any valid LinkInfo structure. All invalid LinkInfo
  1910. structures are considered to have the same referent's volume.
  1911. @comm The value returned is actually a COMPARISONRESULT, for clients that
  1912. understand COMPARISONRESULTs, like SYNCENG.DLL.
  1913. @xref CompareLinkInfoReferents
  1914. ******************************************************************************/
  1915. LINKINFOAPI int WINAPI CompareLinkInfoVolumes(PCLINKINFO pcliFirst,
  1916. PCLINKINFO pcliSecond)
  1917. {
  1918. COMPARISONRESULT cr;
  1919. BOOL bFirstValid;
  1920. BOOL bSecondValid;
  1921. DebugEntry(CompareLinkInfoVolumes);
  1922. bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
  1923. bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
  1924. if (bFirstValid)
  1925. {
  1926. if (bSecondValid)
  1927. cr = CompareILinkInfoVolumes((PCILINKINFO)pcliFirst,
  1928. (PCILINKINFO)pcliSecond);
  1929. else
  1930. cr = CR_FIRST_LARGER;
  1931. }
  1932. else
  1933. {
  1934. if (bSecondValid)
  1935. cr = CR_FIRST_SMALLER;
  1936. else
  1937. cr = CR_EQUAL;
  1938. }
  1939. ASSERT(IsValidCOMPARISONRESULT(cr));
  1940. DebugExitCOMPARISONRESULT(CompareLinkInfoVolumes, cr);
  1941. return(cr);
  1942. }
  1943. /******************************************************************************
  1944. @doc LINKINFOAPI
  1945. @func BOOL | ResolveLinkInfo | Resolves a LinkInfo structure into a file system
  1946. path on an available volume.
  1947. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be resolved.
  1948. @parm PSTR | pszResolvedPathBuf | A pointer to a buffer to be filled in with
  1949. the path resolved to the LinkInfo structure's referent.
  1950. @parm DWORD | dwInFlags | A bit mask of flags. This parameter may be any
  1951. combination of the following values:
  1952. @flag RLI_IFL_CONNECT | If set, connect to the referent's parent connectable
  1953. network resource if necessary. If clear, no connection is established.
  1954. @flag RLI_IFL_ALLOW_UI | If set, interaction with the user is permitted, and
  1955. the hwndOwner parameter identifies the parent window to be used for any ui
  1956. required. If clear, interaction with the user is not permitted.
  1957. @flag RLI_IFL_REDIRECT | If set, the resolved path is a redirected logical
  1958. device path. If clear, the resolved path is only a redirected logical device
  1959. path if the RLI_IFL_CONNECT flag is set, and the network requires a redirected
  1960. logical device path to make a connection.
  1961. @flag RLI_IFL_UPDATE | If set and the source LinkInfo structure needs updating,
  1962. RLI_OFL_UPDATED will be set in *pdwOutFlags and *ppliUpdated will point to an
  1963. updated LinkInfo structure. If clear, RLI_OFL_UPDATED will be clear in
  1964. *pdwOutFlags and *ppliUpdated is undefined.
  1965. @flag RLI_IFL_LOCAL_SEARCH | If set, first the last known logical device for
  1966. the referent's volume is checked for the volume, followed by all other local
  1967. logical devices that handle the referent's volume's media type. If clear, only
  1968. the last known logical device for the referent's volume is checked for the
  1969. volume.
  1970. @parm HWND | hwndOwner | A handle to the parent window to be used to bring up
  1971. any ui required. This parameter is only used if RLI_IFL_ALLOW_UI is set in
  1972. dwInFlags. Otherwise, it is ignored.
  1973. @parm PDWORD | pdwOutFlags | A pointer to a DWORD to be filled in with a bit
  1974. mask of flags. *pdwOutFlags is only valid if TRUE is returned. *pdwOutFlags
  1975. may be any combination of the following values:
  1976. @flag RLI_OFL_UPDATED | Only set if RLI_IFL_UPDATE was set in dwInFlags. If
  1977. set, the source LinkInfo structure needed updating, and *ppliUpdated points to
  1978. an updated LinkInfo structure. If clear, either RLI_IFL_UPDATE was clear in
  1979. dwInFlags or the source LinkInfo structure didn't need updating, and
  1980. *ppliUpdated is undefined.
  1981. @parm PLINKINFO * | ppliUpdated | If RLI_IFL_UPDATE is set in dwInFlags,
  1982. ppliUpdated is a pointer to a PLINKINFO to be filled in with a pointer to an
  1983. updated LinkInfo structure, if necessary. If RLI_IFL_UPDATE is clear in
  1984. dwInFlags, ppliUpdated is ignored. *ppliUpdated is only valid if
  1985. RLI_OFL_UPDATED is set in *pdwOutFlags
  1986. @rdesc If the LinkInfo was resolved to a path on an available successfully,
  1987. TRUE is returned, pszResolvedPathBuf's buffer is filled in with a file system
  1988. path to the LinkInfo structure's referent, and *pdwOutFlags is filled in as
  1989. described above. Otherwise, FALSE is returned, the contents of pszResolved's
  1990. buffer are undefined, and the contents of *pdwOutFlags are undefined. The
  1991. reason for failure may be determined by calling GetLastError().
  1992. @comm Once the caller is finshed with any new, updated LinkInfo structure
  1993. returned by ResolveLinkInfo(), DestroyLinkInfo() should be called to free the
  1994. LinkInfo structure.
  1995. @xref DestroyLinkInfo DisconnectLinkInfo
  1996. ******************************************************************************/
  1997. LINKINFOAPI BOOL WINAPI ResolveLinkInfo(PCLINKINFO pcli,
  1998. LPTSTR pszResolvedPathBuf, // MUST BE MAX_PATH_LEN SIZE
  1999. DWORD dwInFlags, HWND hwndOwner,
  2000. PDWORD pdwOutFlags,
  2001. PLINKINFO *ppliUpdated)
  2002. {
  2003. BOOL bResult;
  2004. DebugEntry(ResolveLinkInfo);
  2005. #ifdef EXPV
  2006. /* Verify parameters. */
  2007. if (
  2008. IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
  2009. IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN) &&
  2010. FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS) &&
  2011. (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
  2012. IS_VALID_HANDLE(hwndOwner, WND)) &&
  2013. IS_VALID_WRITE_PTR(pdwOutFlags, DWORD) &&
  2014. (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) ||
  2015. IS_VALID_WRITE_PTR(ppliUpdated, PLINKINFO)) &&
  2016. EVAL(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_TEMPORARY) ||
  2017. IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT)))
  2018. #endif
  2019. {
  2020. DWORD dwTempFlags;
  2021. *pdwOutFlags = 0;
  2022. bResult = ResolveILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf, MAX_PATH_LEN,
  2023. dwInFlags, hwndOwner, &dwTempFlags);
  2024. if (bResult)
  2025. {
  2026. *pdwOutFlags |= dwTempFlags;
  2027. if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
  2028. {
  2029. bResult = UpdateILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf,
  2030. &dwTempFlags,
  2031. (PILINKINFO *)ppliUpdated);
  2032. if (bResult)
  2033. *pdwOutFlags |= dwTempFlags;
  2034. }
  2035. }
  2036. #ifdef DEBUG
  2037. TRACE_OUT((TEXT("ResolveLinkInfo(): flags %#08lx, given LinkInfo:"),
  2038. dwInFlags));
  2039. DumpILinkInfo((PCILINKINFO)pcli);
  2040. if (bResult)
  2041. {
  2042. TRACE_OUT((TEXT("ResolveLinkInfo(): Resolved path %s with flags %#08lx."),
  2043. pszResolvedPathBuf,
  2044. *pdwOutFlags));
  2045. if (IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))
  2046. {
  2047. ASSERT(IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE));
  2048. TRACE_OUT((TEXT("UpdateLinkInfo(): updated LinkInfo:")));
  2049. DumpILinkInfo(*(PILINKINFO *)ppliUpdated);
  2050. }
  2051. else
  2052. {
  2053. if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
  2054. TRACE_OUT((TEXT("UpdateLinkInfo(): No update required.")));
  2055. else
  2056. TRACE_OUT((TEXT("UpdateLinkInfo(): No update requested.")));
  2057. }
  2058. }
  2059. else
  2060. WARNING_OUT((TEXT("ResolveLinkInfo(): Referent's volume is unavailable.")));
  2061. #endif
  2062. }
  2063. #ifdef EXPV
  2064. else
  2065. {
  2066. SetLastError(ERROR_INVALID_PARAMETER);
  2067. bResult = FALSE;
  2068. }
  2069. #endif
  2070. ASSERT(! bResult ||
  2071. (FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS) &&
  2072. EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
  2073. EVAL(! (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) &&
  2074. IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))) &&
  2075. (IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
  2076. IS_VALID_STRUCT_PTR(*ppliUpdated, CLINKINFO))));
  2077. DebugExitBOOL(ResolveLinkInfo, bResult);
  2078. return(bResult);
  2079. }
  2080. #ifdef UNICODE
  2081. LINKINFOAPI BOOL WINAPI ResolveLinkInfoA(PCLINKINFO pcli,
  2082. LPSTR pszResolvedPathBuf,
  2083. DWORD dwInFlags, HWND hwndOwner,
  2084. PDWORD pdwOutFlags,
  2085. PLINKINFO *ppliUpdated)
  2086. {
  2087. WCHAR szWideResolvedPathBuf[MAX_PATH];
  2088. BOOL fResolved;
  2089. fResolved = ResolveLinkInfo(pcli, szWideResolvedPathBuf, dwInFlags,
  2090. hwndOwner, pdwOutFlags, ppliUpdated);
  2091. if ( fResolved )
  2092. {
  2093. if (WideCharToMultiByte( CP_ACP, 0, szWideResolvedPathBuf, -1,
  2094. pszResolvedPathBuf, MAX_PATH, NULL, NULL ) == 0)
  2095. {
  2096. return FALSE;
  2097. }
  2098. }
  2099. return fResolved;
  2100. }
  2101. #endif
  2102. /******************************************************************************
  2103. @doc LINKINFOAPI
  2104. @func BOOL | DisconnectLinkInfo | Cancels a connection to a net resource
  2105. established by a previous call to ResolveLinkInfo(). DisconnectLinkInfo()
  2106. should only be called if RLI_OFL_DISCONNECT was set in *pdwOutFlags on return
  2107. from ResolveLinkInfo() on the given LinkInfo structure, or its updated
  2108. equivalent.
  2109. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure whose connection
  2110. is to be canceled.
  2111. @rdesc If the function completed successfully, TRUE is returned. Otherwise,
  2112. FALSE is returned. The reason for failure may be determined by calling
  2113. GetLastError().
  2114. @xref ResolveLinkInfo
  2115. ******************************************************************************/
  2116. LINKINFOAPI BOOL WINAPI DisconnectLinkInfo(PCLINKINFO pcli)
  2117. {
  2118. BOOL bResult;
  2119. DebugEntry(DisconnectLinkInfo);
  2120. #ifdef EXPV
  2121. /* Verify parameters. */
  2122. if (
  2123. IS_VALID_STRUCT_PTR(pcli, CLINKINFO))
  2124. #endif
  2125. {
  2126. bResult = DisconnectILinkInfo((PCILINKINFO)pcli);
  2127. }
  2128. #ifdef EXPV
  2129. else
  2130. {
  2131. SetLastError(ERROR_INVALID_PARAMETER);
  2132. bResult = FALSE;
  2133. }
  2134. #endif
  2135. DebugExitBOOL(DisconnectLinkInfo, bResult);
  2136. return(bResult);
  2137. }
  2138. /******************************************************************************
  2139. @doc LINKINFOAPI
  2140. @func BOOL | GetLinkInfoData | Retrieves a pointer to data in a LinkInfo
  2141. structure.
  2142. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to retrieve data
  2143. from.
  2144. @parm LINKINFODATATYPE | lidt | The type of data to be retrieved from the
  2145. LinkInfo structure. lidt may be one of the following values:
  2146. @flag LIDT_VOLUME_SERIAL_NUMBER | *ppcvData is a PCDWORD that points to the
  2147. LinkInfo structure's referent's volume's serial number.
  2148. @flag LIDT_DRIVE_TYPE | *ppcvData is a PCUINT that points to the LinkInfo
  2149. structure's referent's volume's host drive type.
  2150. @flag LIDT_VOLUME_LABEL | *ppcvData is a PCSTR that points to the LinkInfo
  2151. structure's referent's volume's label.
  2152. @flag LIDT_LOCAL_BASE_PATH | *ppcvData is a PCSTR that points to the LinkInfo
  2153. structure's referent's local base path.
  2154. @flag LIDT_NET_RESOURCE | *ppcvData is a PCSTR that points to the LinkInfo
  2155. structure's referent's parent network resource's name.
  2156. @flag LIDT_COMMON_PATH_SUFFIX | *ppcvData is a PCSTR that points to the
  2157. LinkInfo structure's referent's common path suffix.
  2158. @rdesc If the function completed successfully, TRUE is returned, and *ppcvData
  2159. is filled in with a pointer to the data requested from LinkInfo structure or NULL
  2160. if that was a valid field, but empty.
  2161. Otherwise, FALSE is returned, and the contents of *ppcvData are undefined. The
  2162. reason for failure may be determined by calling GetLastError().
  2163. @comm A LinkInfo structure may only contain some of the LinkInfo data listed
  2164. above.
  2165. ******************************************************************************/
  2166. LINKINFOAPI BOOL WINAPI GetLinkInfoData(PCLINKINFO pcli, LINKINFODATATYPE lidt,
  2167. PCVOID *ppcvData)
  2168. {
  2169. BOOL bResult;
  2170. DebugEntry(GetLinkInfoData);
  2171. #ifdef EXPV
  2172. /* Verify parameters. */
  2173. if (
  2174. IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
  2175. EVAL(IsValidLINKINFODATATYPE(lidt)) &&
  2176. IS_VALID_WRITE_PTR(ppcvData, PCVOID))
  2177. #endif
  2178. {
  2179. bResult = GetILinkInfoData((PCILINKINFO)pcli, lidt, ppcvData);
  2180. }
  2181. #ifdef EXPV
  2182. else
  2183. {
  2184. SetLastError(ERROR_INVALID_PARAMETER);
  2185. bResult = FALSE;
  2186. }
  2187. #endif
  2188. ASSERT(!bResult ||
  2189. ((NULL == *ppcvData) || IS_VALID_READ_BUFFER_PTR(*ppcvData, LinkInfoData, 1)));
  2190. DebugExitBOOL(GetLinkInfoData, bResult);
  2191. return(bResult);
  2192. }
  2193. /******************************************************************************
  2194. @doc LINKINFOAPI
  2195. @func BOOL | IsValidLinkInfo | Determines whether or not a LinkInfo structure
  2196. is valid.
  2197. @parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be checked for
  2198. validity.
  2199. @rdesc If the function completed successfully, TRUE is returned. Otherwise,
  2200. FALSE is returned.
  2201. ******************************************************************************/
  2202. //
  2203. // IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT validates alignment only on
  2204. // alignment machines. For machines that are not alignment-sensitive,
  2205. // it declares that all values are aligned.
  2206. //
  2207. #ifdef ALIGNMENT_MACHINE
  2208. #define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) IS_ALIGNED_DWORD_CNT(x)
  2209. #else
  2210. #define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) TRUE
  2211. #endif
  2212. LINKINFOAPI BOOL WINAPI IsValidLinkInfo(PCLINKINFO pcli)
  2213. {
  2214. BOOL bResult;
  2215. PCILINKINFO pcili = (PCILINKINFO)pcli;
  2216. DebugEntry(IsValidLinkInfo);
  2217. // First make sure it's readable and not ridiculously small
  2218. if ((pcli == NULL) || // read the ucbSize
  2219. pcli->ucbSize < pcili->ucbHeaderSize || // header fits in buffer
  2220. pcili->ucbHeaderSize < sizeof(ILINKINFOA)// smallest supported header
  2221. )
  2222. {
  2223. bResult = FALSE;
  2224. goto exit;
  2225. }
  2226. // Make sure no field points outside our buffer
  2227. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
  2228. {
  2229. if (pcili->ucbVolumeIDOffset >= pcli->ucbSize ||
  2230. pcili->ucbLocalBasePathOffset >= pcli->ucbSize ||
  2231. pcili->ucbCommonPathSuffixOffset >= pcli->ucbSize ||
  2232. !IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbVolumeIDOffset))
  2233. {
  2234. bResult = FALSE;
  2235. goto exit;
  2236. }
  2237. }
  2238. // The ucbCNRLinkOffset field is valid only sometimes
  2239. if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
  2240. {
  2241. if (pcili->ucbCNRLinkOffset >= pcli->ucbSize ||
  2242. !IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbCNRLinkOffset))
  2243. {
  2244. bResult = FALSE;
  2245. goto exit;
  2246. }
  2247. }
  2248. // The UNICODE version has some more fields than the ANSI version.
  2249. // Those UNICODE fields must be WORD-aligned.
  2250. if (pcili->ucbHeaderSize >= sizeof(ILINKINFOW))
  2251. {
  2252. if (pcili->ucbLocalBasePathOffsetW >= pcli->ucbSize ||
  2253. pcili->ucbCommonPathSuffixOffsetW >= pcli->ucbSize ||
  2254. !IS_ALIGNED_WORD_CNT(pcili->ucbLocalBasePathOffsetW) ||
  2255. !IS_ALIGNED_WORD_CNT(pcili->ucbCommonPathSuffixOffsetW))
  2256. {
  2257. bResult = FALSE;
  2258. goto exit;
  2259. }
  2260. }
  2261. // Survived the validation ordeal!
  2262. bResult = TRUE;
  2263. exit:;
  2264. DebugExitBOOL(IsValidLinkInfo, bResult);
  2265. return(bResult);
  2266. }