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.

1961 lines
52 KiB

  1. /*
  2. * cnrlink.c - CNRLink ADT module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #include "cnrlink.h"
  9. #include "server.h"
  10. /* Constants
  11. ************/
  12. /* WNetUseConnection() flag combinations */
  13. #define ALL_CONNECT_IN_FLAGS (CONNECT_UPDATE_PROFILE |\
  14. CONNECT_UPDATE_RECENT |\
  15. CONNECT_TEMPORARY |\
  16. CONNECT_INTERACTIVE |\
  17. CONNECT_PROMPT |\
  18. CONNECT_REDIRECT)
  19. #define ALL_CONNECT_OUT_FLAGS (CONNECT_REFCOUNT |\
  20. CONNECT_LOCALDRIVE)
  21. /* Macros
  22. *********/
  23. /* macros for accessing ICNRLINK data */
  24. #define ICNRL_Remote_Name_PtrA(picnrl) \
  25. ((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffset))
  26. #define ICNRL_Device_PtrA(picnrl) \
  27. ((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffset))
  28. #define ICNRL_Remote_Name_PtrW(picnrl) \
  29. ((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffsetW))
  30. #define ICNRL_Device_PtrW(picnrl) \
  31. ((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffsetW))
  32. #define IS_ICNRL_ANSI(picnrl) \
  33. ((PBYTE)(picnrl) + ((PICNRLINKW)(picnrl))->ucbNetNameOffset) == (PBYTE)&(((PICNRLINKW)(picnrl))->ucbNetNameOffsetW)
  34. #ifdef UNICODE
  35. #define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrW(picnrl)
  36. #define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrW(picnrl)
  37. #else
  38. #define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrA(picnrl)
  39. #define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrA(picnrl)
  40. #endif
  41. /* Types
  42. ********/
  43. /*
  44. @doc INTERNAL
  45. @enum ICNRLINKFLAGS | Internal CNRLink structure flags.
  46. */
  47. typedef enum _icnrlinkflags
  48. {
  49. /*
  50. @emem ICNRL_FL_VALID_DEVICE | If set, last redirected drive is valid. If
  51. clear, last redirected drive is not valid.
  52. */
  53. ICNRL_FL_VALID_DEVICE = 0x0001,
  54. /*
  55. @emem ICNRL_FL_VALID_NET_TYPE | If set, net type is valid. If clear, net
  56. type is not valid.
  57. */
  58. ICNRL_FL_VALID_NET_TYPE = 0x0002,
  59. /* @emem ALL_ICNRL_FLAGS | All internal CNRLink structure flags. */
  60. ALL_ICNRL_FLAGS = (ICNRL_FL_VALID_DEVICE |
  61. ICNRL_FL_VALID_NET_TYPE)
  62. }
  63. ICNRLINKFLAGS;
  64. /*
  65. @doc INTERNAL
  66. @struct ICNRLINK | Internal definition of relocatable connectable network
  67. resource (CNR) link structure. An <t ILINKINFO> structure may contain an
  68. ICNRLINK structure. An ICNRLINK structure consists of a header described as
  69. below, followed by variable-length data.
  70. */
  71. typedef struct _icnrlinkA
  72. {
  73. /*
  74. @field UINT | ucbSize | Length of ICNRLINK structure in bytes, including
  75. ucbSize field.
  76. */
  77. UINT ucbSize;
  78. /*
  79. @field DWORD | dwFlags | A bit mask of flags from the <t ICNRLINKFLAGS>
  80. enumeration.
  81. */
  82. DWORD dwFlags;
  83. /*
  84. @field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from
  85. base of structure. The CNR name string may be passed to
  86. WNetUseConnection() to add a connection to the CNR.<nl>
  87. Example CNRLink name string: "\\\\fredbird\\work".
  88. */
  89. UINT ucbNetNameOffset;
  90. /*
  91. @field UINT | ucbDeviceOffset | Offset in bytes of last redirected local
  92. device string from base of structure. This field is only valid if
  93. ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local
  94. device string may be passed to WNetUseConnection() to add a redirected
  95. device connection to the CNR.<nl>
  96. Example last redirected local device string: "D:".
  97. */
  98. UINT ucbDeviceOffset;
  99. /*
  100. @field DWORD | dwNetType | The network type as returned in a
  101. NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is
  102. set in dwFlags. The net type is used to retrieve the host net resource's
  103. host NP's name to use in calling WNetUseConnection().<nl>
  104. Example net type: WNNC_NET_NETWARE.
  105. */
  106. DWORD dwNetType;
  107. }
  108. ICNRLINKA;
  109. DECLARE_STANDARD_TYPES(ICNRLINKA);
  110. #ifdef UNICODE
  111. typedef struct _icnrlinkW
  112. {
  113. /*
  114. @field UINT | ucbSize | Length of ICNRLINK structure in bytes, including
  115. ucbSize field.
  116. */
  117. UINT ucbSize;
  118. /*
  119. @field DWORD | dwFlags | A bit mask of flags from the <t ICNRLINKFLAGS>
  120. enumeration.
  121. */
  122. DWORD dwFlags;
  123. /*
  124. @field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from
  125. base of structure. The CNR name string may be passed to
  126. WNetUseConnection() to add a connection to the CNR.<nl>
  127. Example CNRLink name string: "\\\\fredbird\\work".
  128. */
  129. UINT ucbNetNameOffset;
  130. /*
  131. @field UINT | ucbDeviceOffset | Offset in bytes of last redirected local
  132. device string from base of structure. This field is only valid if
  133. ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local
  134. device string may be passed to WNetUseConnection() to add a redirected
  135. device connection to the CNR.<nl>
  136. Example last redirected local device string: "D:".
  137. */
  138. UINT ucbDeviceOffset;
  139. /*
  140. @field DWORD | dwNetType | The network type as returned in a
  141. NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is
  142. set in dwFlags. The net type is used to retrieve the host net resource's
  143. host NP's name to use in calling WNetUseConnection().<nl>
  144. Example net type: WNNC_NET_NETWARE.
  145. */
  146. DWORD dwNetType;
  147. /*
  148. These members are for storing the unicode version of the strings
  149. */
  150. UINT ucbNetNameOffsetW;
  151. UINT ucbDeviceOffsetW;
  152. }
  153. ICNRLINKW;
  154. DECLARE_STANDARD_TYPES(ICNRLINKW);
  155. #endif
  156. #ifdef UNICODE
  157. #define ICNRLINK ICNRLINKW
  158. #define PICNRLINK PICNRLINKW
  159. #define CICNRLINK CICNRLINKW
  160. #define PCICNRLINK PCICNRLINKW
  161. #else
  162. #define ICNRLINK ICNRLINKA
  163. #define PICNRLINK PICNRLINKA
  164. #define CICNRLINK CICNRLINKA
  165. #define PCICNRLINK PCICNRLINKA
  166. #endif
  167. /* Exported from MPR.DLL, but not in winnetwk.h
  168. */
  169. #ifdef UNICODE
  170. DWORD APIENTRY WNetGetResourceInformationW (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem);
  171. #define WNetGetResourceInformation WNetGetResourceInformationW
  172. #else
  173. DWORD APIENTRY WNetGetResourceInformationA (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem);
  174. #define WNetGetResourceInformation WNetGetResourceInformationA
  175. #endif
  176. /***************************** Private Functions *****************************/
  177. /* Module Prototypes
  178. ********************/
  179. PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR, LPTSTR, LPCTSTR *, PBOOL, PDWORD);
  180. PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR, DWORD, LPCTSTR, DWORD, PICNRLINK *, PUINT);
  181. PRIVATE_CODE BOOL GetNetType(LPCTSTR, PDWORD);
  182. PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK, LPTSTR);
  183. PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR, LPCTSTR);
  184. PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK, LPTSTR, int);
  185. #if defined(DEBUG) || defined (VSTF)
  186. PRIVATE_CODE BOOL IsValidDevice(LPCTSTR);
  187. PRIVATE_CODE BOOL IsValidNetType(DWORD);
  188. PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK);
  189. #endif
  190. #if defined(DEBUG)
  191. PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR);
  192. #endif
  193. #if 0
  194. DWORD APIENTRY
  195. WNetGetNetworkInformationW(
  196. LPCWSTR lpProvider,
  197. LPNETINFOSTRUCT lpNetInfoStruct
  198. )
  199. {
  200. if (wcsicmp(lpProvider, L"Microsoft Windows Network") == 0)
  201. {
  202. lpNetInfoStruct->wNetType = (WORD)WNNC_NET_LANMAN;
  203. return ERROR_SUCCESS;
  204. }
  205. else if (wcsicmp(lpProvider, L"Novell Network") == 0)
  206. {
  207. lpNetInfoStruct->wNetType = (WORD)WNNC_NET_NETWARE;
  208. return ERROR_SUCCESS;
  209. }
  210. else
  211. {
  212. return ERROR_NOT_SUPPORTED;
  213. }
  214. }
  215. #endif
  216. /*
  217. ** GetNetPathFromLocalPath()
  218. **
  219. **
  220. **
  221. ** Arguments:
  222. **
  223. ** Returns:
  224. **
  225. ** Side Effects: none
  226. */
  227. PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR pcszLocalPath,
  228. LPTSTR pszNetNameBuf,
  229. LPCTSTR *ppcszCommonPathSuffix,
  230. PBOOL pbIsShared, PDWORD pdwNetType)
  231. {
  232. BOOL bResult = TRUE;
  233. PCSERVERVTABLE pcsvt;
  234. ASSERT(IsDrivePath(pcszLocalPath));
  235. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNetNameBuf, STR, MAX_PATH_LEN));
  236. ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR));
  237. ASSERT(IS_VALID_WRITE_PTR(pbIsShared, BOOL));
  238. ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD));
  239. *pbIsShared = FALSE;
  240. if (GetServerVTable(&pcsvt))
  241. {
  242. TCHAR rgchSharedPath[MAX_PATH_LEN];
  243. ASSERT(lstrlen(pcszLocalPath) < ARRAYSIZE(rgchSharedPath));
  244. lstrcpyn(rgchSharedPath, pcszLocalPath, ARRAYSIZE(rgchSharedPath));
  245. FOREVER
  246. {
  247. if ((pcsvt->GetNetResourceFromLocalPath)(rgchSharedPath,
  248. pszNetNameBuf, MAX_PATH_LEN,
  249. pdwNetType))
  250. {
  251. ASSERT(lstrlen(pszNetNameBuf) < MAX_PATH_LEN);
  252. /* Determine common path suffix. */
  253. *ppcszCommonPathSuffix = pcszLocalPath + lstrlen(rgchSharedPath);
  254. /* Skip any leading slash. */
  255. if (IS_SLASH(**ppcszCommonPathSuffix))
  256. *ppcszCommonPathSuffix = CharNext(*ppcszCommonPathSuffix);
  257. ASSERT(! IS_SLASH(**ppcszCommonPathSuffix));
  258. // if it is terminated with a $ it is a hidden share, in that
  259. // case don't consider this shared
  260. *pbIsShared = pszNetNameBuf[lstrlen(pszNetNameBuf) -1] != TEXT('$');
  261. break;
  262. }
  263. else
  264. {
  265. if (! DeleteLastDrivePathElement(rgchSharedPath))
  266. break;
  267. }
  268. }
  269. }
  270. ASSERT(! bResult ||
  271. ! *pbIsShared ||
  272. (EVAL(IsUNCPath(pszNetNameBuf)) &&
  273. IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) &&
  274. EVAL(*ppcszCommonPathSuffix >= pcszLocalPath) &&
  275. EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) &&
  276. EVAL(IsValidNetType(*pdwNetType))));
  277. return(bResult);
  278. }
  279. /*
  280. ** UnifyICNRLinkInfo()
  281. **
  282. **
  283. **
  284. ** Arguments:
  285. **
  286. ** Returns:
  287. **
  288. ** Side Effects: none
  289. */
  290. PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR pcszNetName, DWORD dwFlags,
  291. LPCTSTR pcszDevice, DWORD dwNetType,
  292. PICNRLINK *ppicnrl, PUINT pucbICNRLinkLen)
  293. {
  294. BOOL bResult;
  295. UINT ucbDataOffset;
  296. #ifdef UNICODE
  297. BOOL bUnicode;
  298. UINT cchChars;
  299. CHAR szAnsiNetName[MAX_PATH];
  300. CHAR szAnsiDevice[MAX_PATH];
  301. UINT cbAnsiNetName;
  302. UINT cbWideNetName;
  303. UINT cbAnsiDevice;
  304. UINT cbWideDevice;
  305. UINT cbChars;
  306. #endif
  307. ASSERT(IsUNCPath(pcszNetName));
  308. ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_ICNRL_FLAGS));
  309. ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_DEVICE) ||
  310. IsValidDevice(pcszDevice));
  311. ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_NET_TYPE) ||
  312. IsValidNetType(dwNetType));
  313. ASSERT(IS_VALID_WRITE_PTR(ppicnrl, PCNRLINK));
  314. ASSERT(IS_VALID_WRITE_PTR(pucbICNRLinkLen, UINT));
  315. #ifdef UNICODE
  316. bUnicode = FALSE;
  317. cbAnsiNetName = WideCharToMultiByte(CP_ACP, 0,
  318. pcszNetName, -1,
  319. szAnsiNetName, ARRAYSIZE(szAnsiNetName),
  320. 0, 0);
  321. if ( cbAnsiNetName == 0 )
  322. {
  323. bUnicode = FALSE;
  324. }
  325. else
  326. {
  327. WCHAR szWideNetName[MAX_PATH];
  328. cbChars = MultiByteToWideChar(CP_ACP, 0,
  329. szAnsiNetName, -1,
  330. szWideNetName, ARRAYSIZE(szWideNetName));
  331. if ( cbChars == 0 || lstrcmp(pcszNetName,szWideNetName) != 0 )
  332. {
  333. bUnicode = TRUE;
  334. }
  335. }
  336. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  337. {
  338. cbAnsiDevice = WideCharToMultiByte(CP_ACP, 0,
  339. pcszDevice, -1,
  340. szAnsiDevice, ARRAYSIZE(szAnsiDevice),
  341. 0, 0);
  342. if ( cbAnsiDevice == 0 )
  343. {
  344. bUnicode = FALSE;
  345. }
  346. else
  347. {
  348. WCHAR szWideDevice[MAX_PATH];
  349. cchChars = MultiByteToWideChar(CP_ACP, 0,
  350. szAnsiDevice, -1,
  351. szWideDevice, ARRAYSIZE(szWideDevice));
  352. if ( cchChars == 0 || lstrcmp(pcszDevice,szWideDevice) != 0 )
  353. {
  354. bUnicode = TRUE;
  355. }
  356. }
  357. }
  358. else
  359. {
  360. cbAnsiDevice = 0;
  361. }
  362. if ( bUnicode )
  363. {
  364. ucbDataOffset = SIZEOF(ICNRLINKW);
  365. /* (+ 1) for null terminator. */
  366. cbWideNetName = (lstrlen(pcszNetName) + 1) * sizeof(TCHAR);
  367. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  368. cbWideDevice = (lstrlen(pcszDevice) + 1) * sizeof(TCHAR);
  369. else
  370. cbWideDevice = 0;
  371. }
  372. else
  373. {
  374. ucbDataOffset = SIZEOF(ICNRLINKA);
  375. cbWideNetName = 0;
  376. cbWideDevice = 0;
  377. }
  378. *pucbICNRLinkLen = ucbDataOffset +
  379. cbAnsiNetName +
  380. cbAnsiDevice;
  381. if ( bUnicode )
  382. {
  383. *pucbICNRLinkLen = ALIGN_WORD_CNT(*pucbICNRLinkLen) +
  384. cbWideNetName +
  385. cbWideDevice;
  386. }
  387. #else
  388. /* Assume we won't overflow *pucbICNRLinkLen here. */
  389. /* (+ 1) for null terminator. */
  390. *pucbICNRLinkLen = SIZEOF(**ppicnrl) +
  391. (lstrlen(pcszNetName) + 1) * SIZEOF(TCHAR);
  392. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  393. /* (+ 1) for null terminator. */
  394. *pucbICNRLinkLen += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR);
  395. ucbDataOffset = SIZEOF(ICNRLINKA);
  396. #endif
  397. bResult = AllocateMemory(*pucbICNRLinkLen, ppicnrl);
  398. if (bResult)
  399. {
  400. (*ppicnrl)->ucbSize = *pucbICNRLinkLen;
  401. (*ppicnrl)->dwFlags = dwFlags;
  402. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_NET_TYPE))
  403. (*ppicnrl)->dwNetType = dwNetType;
  404. else
  405. (*ppicnrl)->dwNetType = 0;
  406. /* Append remote name. */
  407. (*ppicnrl)->ucbNetNameOffset = ucbDataOffset;
  408. // lstrcpy: Enough memory is allocated above to hold the strings
  409. // so no need to bound it here.
  410. #ifdef UNICODE
  411. lstrcpyA(ICNRL_Remote_Name_PtrA(*ppicnrl), szAnsiNetName);
  412. ucbDataOffset += cbAnsiNetName;
  413. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  414. {
  415. /* Append device name. */
  416. (*ppicnrl)->ucbDeviceOffset = ucbDataOffset;
  417. lstrcpyA(ICNRL_Device_PtrA(*ppicnrl), szAnsiDevice);
  418. ucbDataOffset += cbAnsiDevice;
  419. }
  420. else
  421. {
  422. (*ppicnrl)->ucbDeviceOffset = 0;
  423. }
  424. if ( bUnicode )
  425. {
  426. ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
  427. (*ppicnrl)->ucbNetNameOffsetW = ucbDataOffset;
  428. lstrcpy(ICNRL_Remote_Name_PtrW(*ppicnrl), pcszNetName);
  429. ucbDataOffset += cbWideNetName;
  430. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  431. {
  432. /* Append device name. */
  433. (*ppicnrl)->ucbDeviceOffsetW = ucbDataOffset;
  434. lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice);
  435. /* (+ 1) for null terminator. */
  436. ucbDataOffset += cbWideDevice;
  437. }
  438. else
  439. {
  440. (*ppicnrl)->ucbDeviceOffsetW = 0;
  441. }
  442. }
  443. #else
  444. lstrcpy(ICNRL_Remote_Name_Ptr(*ppicnrl), pcszNetName);
  445. /* (+ 1) for null terminator. */
  446. ucbDataOffset += lstrlen(pcszNetName) + 1;
  447. if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
  448. {
  449. /* Append device name. */
  450. (*ppicnrl)->ucbDeviceOffset = ucbDataOffset;
  451. lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice);
  452. #ifdef DEBUG
  453. /* (+ 1) for null terminator. */
  454. ucbDataOffset += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR);
  455. #endif
  456. }
  457. else
  458. (*ppicnrl)->ucbDeviceOffset = 0;
  459. #endif
  460. /* Do all the calculated lengths match? */
  461. ASSERT(ucbDataOffset == (*ppicnrl)->ucbSize);
  462. ASSERT(ucbDataOffset == *pucbICNRLinkLen);
  463. }
  464. ASSERT(! bResult ||
  465. (IS_VALID_STRUCT_PTR(*ppicnrl, CICNRLINK) &&
  466. EVAL(*pucbICNRLinkLen == GetCNRLinkLen((PCCNRLINK)*ppicnrl))));
  467. return(bResult);
  468. }
  469. /*
  470. ** GetNetType()
  471. **
  472. **
  473. **
  474. ** Arguments:
  475. **
  476. ** Returns:
  477. **
  478. ** Side Effects: none
  479. */
  480. PRIVATE_CODE BOOL GetNetType(LPCTSTR pcszCNRName, PDWORD pdwNetType)
  481. {
  482. BOOL bResult = FALSE;
  483. NETRESOURCE nrIn;
  484. NETRESOURCEBUF nrbufOut;
  485. DWORD dwcbBufLen = SIZEOF(nrbufOut);
  486. LPTSTR pszFileSysPath;
  487. DWORD dwNetResult;
  488. #ifdef DEBUG
  489. DWORD dwcmsTicks;
  490. #endif
  491. ASSERT(IsValidCNRName(pcszCNRName));
  492. ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD));
  493. /* RAIDRAID: (15691) We only support disk resource connections here. */
  494. ZeroMemory(&nrIn, SIZEOF(nrIn));
  495. nrIn.lpRemoteName = (LPTSTR)pcszCNRName;
  496. nrIn.dwType = RESOURCETYPE_DISK;
  497. #ifdef DEBUG
  498. dwcmsTicks = GetTickCount();
  499. #endif
  500. dwNetResult = WNetGetResourceInformation(&nrIn, &(nrbufOut.rgbyte),
  501. &dwcbBufLen, &pszFileSysPath);
  502. #ifdef DEBUG
  503. dwcmsTicks = GetTickCount() - dwcmsTicks;
  504. TRACE_OUT((TEXT("GetRemotePathInfo(): WNetGetResourceInformation() on net resource %s took %lu.%03lu seconds."),
  505. pcszCNRName,
  506. (dwcmsTicks / 1000),
  507. (dwcmsTicks % 1000)));
  508. #endif
  509. if (dwNetResult == ERROR_SUCCESS)
  510. {
  511. if (nrbufOut.nr.lpProvider)
  512. {
  513. NETINFOSTRUCT nis;
  514. ASSERT(IS_VALID_STRING_PTR(nrbufOut.nr.lpProvider, STR));
  515. nis.cbStructure = SIZEOF(nis);
  516. dwNetResult = WNetGetNetworkInformation(nrbufOut.nr.lpProvider, &nis);
  517. if (dwNetResult == ERROR_SUCCESS)
  518. {
  519. *pdwNetType = ((nis.wNetType) << 16);
  520. bResult = TRUE;
  521. TRACE_OUT((TEXT("GetNetType(): Net type for CNR %s is %#08lx."),
  522. pcszCNRName,
  523. *pdwNetType));
  524. }
  525. else
  526. WARNING_OUT((TEXT("GetNetType(): WNetGetNetworkInformation() failed for %s NP, returning %lu."),
  527. nrbufOut.nr.lpProvider,
  528. dwNetResult));
  529. }
  530. else
  531. WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() was unable to determine the NP for CNR %s."),
  532. pcszCNRName));
  533. }
  534. else
  535. WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() failed for CNR %s, returning %lu."),
  536. pcszCNRName,
  537. dwNetResult));
  538. ASSERT(! bResult ||
  539. IsValidNetType(*pdwNetType));
  540. return(bResult);
  541. }
  542. /*
  543. ** GetNetProviderName()
  544. **
  545. **
  546. **
  547. ** Arguments:
  548. **
  549. ** Returns:
  550. **
  551. ** Side Effects: none
  552. */
  553. PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK pcicnrl, LPTSTR pszNPNameBuf)
  554. {
  555. BOOL bResult = FALSE;
  556. ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK));
  557. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNPNameBuf, STR, MAX_PATH_LEN));
  558. if (IS_FLAG_SET(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE))
  559. {
  560. DWORD dwcbNPNameBufLen;
  561. DWORD dwNetResult;
  562. dwcbNPNameBufLen = MAX_PATH_LEN;
  563. dwNetResult = WNetGetProviderName(pcicnrl->dwNetType, pszNPNameBuf,
  564. &dwcbNPNameBufLen);
  565. if (dwNetResult == ERROR_SUCCESS)
  566. {
  567. bResult = TRUE;
  568. #ifdef UNICODE
  569. //
  570. // Unicode builds need to accept both ansi and unicode ICNRLINK structures.
  571. // Note the use of '%S' (upper case). This will accept an ANSI string
  572. // in a UNICODE build environment.
  573. //
  574. if (IS_ICNRL_ANSI(pcicnrl))
  575. TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %S is %s."),
  576. ICNRL_Remote_Name_PtrA(pcicnrl),
  577. pszNPNameBuf));
  578. else
  579. #endif
  580. TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %s is %s."),
  581. ICNRL_Remote_Name_Ptr(pcicnrl),
  582. pszNPNameBuf));
  583. }
  584. else
  585. WARNING_OUT((TEXT("GetNetProviderName(): WNetGetProviderName() failed for CNR %s's net type %#08lx, returning %lu."),
  586. TEXT("<Remote Name>"), // ICNRL_Remote_Name_Ptr(pcicnrl),
  587. pcicnrl->dwNetType,
  588. dwNetResult));
  589. }
  590. else
  591. WARNING_OUT((TEXT("GetNetProviderName(): Net type for CNR %s is not known. Unable to determine NP name."),
  592. TEXT("<Remote Name>"))); // ICNRL_Remote_Name_Ptr(pcicnrl)));
  593. ASSERT(! bResult ||
  594. IsValidNetProviderName(pszNPNameBuf));
  595. return(bResult);
  596. }
  597. /*
  598. ** CompareNetNames()
  599. **
  600. **
  601. **
  602. ** Arguments:
  603. **
  604. ** Returns:
  605. **
  606. ** Side Effects: none
  607. */
  608. PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR pcszFirstNetName,
  609. LPCTSTR pcszSecondNetName)
  610. {
  611. ASSERT(IS_VALID_STRING_PTR(pcszFirstNetName, CSTR));
  612. ASSERT(IS_VALID_STRING_PTR(pcszSecondNetName, CSTR));
  613. return(MapIntToComparisonResult(lstrcmp(pcszFirstNetName,
  614. pcszSecondNetName)));
  615. }
  616. /*
  617. ** SearchForRedirectedConnection()
  618. **
  619. **
  620. **
  621. ** Arguments:
  622. **
  623. ** Returns:
  624. **
  625. ** Side Effects: none
  626. */
  627. PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK pcicnrl,
  628. LPTSTR pszRootPathBuf,
  629. int cchMax)
  630. {
  631. BOOL bResult = FALSE;
  632. HANDLE henum;
  633. DWORD dwNetResult;
  634. ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK));
  635. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
  636. #ifdef DEBUG
  637. #ifdef UNICODE
  638. {
  639. LPWSTR pszWideNetName;
  640. WCHAR szWideNetName[MAX_PATH];
  641. if (IS_ICNRL_ANSI(pcicnrl))
  642. {
  643. pszWideNetName = szWideNetName;
  644. MultiByteToWideChar(CP_ACP, 0,
  645. ICNRL_Remote_Name_PtrA(pcicnrl), -1,
  646. szWideNetName, ARRAYSIZE(szWideNetName));
  647. } else {
  648. pszWideNetName = ICNRL_Remote_Name_PtrW(pcicnrl);
  649. }
  650. WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."),
  651. pszWideNetName));
  652. }
  653. #else
  654. WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."),
  655. ICNRL_Remote_Name_Ptr(pcicnrl)));
  656. #endif
  657. #endif
  658. /* RAIDRAID: (15691) We only support container resources here. */
  659. dwNetResult = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_DISK,
  660. RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED,
  661. NULL, &henum);
  662. if (dwNetResult == WN_SUCCESS)
  663. {
  664. DWORD dwc = 1;
  665. NETRESOURCEBUF nrbuf;
  666. DWORD dwcbBufLen = SIZEOF(nrbuf);
  667. while ((dwNetResult = WNetEnumResource(henum, &dwc, &(nrbuf.rgbyte),
  668. &dwcbBufLen))
  669. == WN_SUCCESS)
  670. {
  671. /* Is this a redirected connection? */
  672. if (nrbuf.nr.lpRemoteName != NULL)
  673. {
  674. if (nrbuf.nr.lpLocalName != NULL)
  675. {
  676. /* Yes. Is it a redirected connection to the desired CNR? */
  677. #ifdef UNICODE
  678. WCHAR szWideNetName[MAX_PATH];
  679. LPWSTR pszWideNetName;
  680. if (IS_ICNRL_ANSI(pcicnrl))
  681. {
  682. pszWideNetName = szWideNetName;
  683. MultiByteToWideChar(CP_ACP, 0,
  684. ICNRL_Remote_Name_PtrA(pcicnrl), -1,
  685. szWideNetName, ARRAYSIZE(szWideNetName));
  686. }
  687. else
  688. {
  689. pszWideNetName = ICNRL_Remote_Name_Ptr(pcicnrl);
  690. }
  691. if (CompareNetNames(pszWideNetName,
  692. nrbuf.nr.lpRemoteName)
  693. == CR_EQUAL)
  694. #else
  695. if (CompareNetNames(ICNRL_Remote_Name_Ptr(pcicnrl),
  696. nrbuf.nr.lpRemoteName)
  697. == CR_EQUAL)
  698. #endif
  699. {
  700. /* Yes. */
  701. ASSERT(lstrlen(nrbuf.nr.lpLocalName) < MAX_PATH_LEN);
  702. lstrcpyn(pszRootPathBuf, nrbuf.nr.lpLocalName, cchMax);
  703. bResult = TRUE;
  704. TRACE_OUT((TEXT("SearchForRedirectedConnection(): Found CNR \"%s\" connected to %s."),
  705. nrbuf.nr.lpRemoteName,
  706. pszRootPathBuf));
  707. break;
  708. }
  709. else
  710. /* No. */
  711. TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping unmatched enumerated connection to CNR \"%s\" on %s."),
  712. nrbuf.nr.lpRemoteName,
  713. nrbuf.nr.lpLocalName));
  714. }
  715. else
  716. /* No. */
  717. TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated deviceless connection to CNR \"%s\"."),
  718. nrbuf.nr.lpRemoteName));
  719. }
  720. else
  721. WARNING_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated connection with no CNR name.")));
  722. }
  723. if (! bResult && dwNetResult != WN_NO_MORE_ENTRIES)
  724. WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetEnumResource() failed, returning %lu."),
  725. dwNetResult));
  726. dwNetResult = WNetCloseEnum(henum);
  727. if (dwNetResult != WN_SUCCESS)
  728. WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetCloseEnum() failed, returning %lu."),
  729. dwNetResult));
  730. }
  731. else
  732. WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetOpenEnum() failed, returning %lu."),
  733. dwNetResult));
  734. return(bResult);
  735. }
  736. #if defined(DEBUG) || defined (VSTF)
  737. /*
  738. ** IsValidDevice()
  739. **
  740. **
  741. **
  742. ** Arguments:
  743. **
  744. ** Returns:
  745. **
  746. ** Side Effects: none
  747. */
  748. PRIVATE_CODE BOOL IsValidDevice(LPCTSTR pcszDevice)
  749. {
  750. /* Any valid string < MAX_PATH_LEN bytes long is a valid device name. */
  751. return(IS_VALID_STRING_PTR(pcszDevice, CSTR) &&
  752. EVAL(lstrlen(pcszDevice) < MAX_PATH_LEN));
  753. }
  754. /*
  755. ** IsValidNetType()
  756. **
  757. **
  758. **
  759. ** Arguments:
  760. **
  761. ** Returns:
  762. **
  763. ** Side Effects: none
  764. */
  765. PRIVATE_CODE BOOL IsValidNetType(DWORD dwNetType)
  766. {
  767. BOOL bResult;
  768. switch (dwNetType & 0xffff0000)
  769. {
  770. default:
  771. WARNING_OUT((TEXT("IsValidNetType(): Unexpected net type %#08lx is neither NetWare nor LANMan."),
  772. dwNetType));
  773. /* Fall through... */
  774. case WNNC_NET_LANMAN:
  775. case WNNC_NET_NETWARE:
  776. bResult = TRUE;
  777. break;
  778. }
  779. if (dwNetType & 0x0000ffff)
  780. WARNING_OUT((TEXT("IsValidNetType(): Low word of net type %#08lx is non-zero."),
  781. dwNetType));
  782. return(bResult);
  783. }
  784. /*
  785. ** IsValidPCICNRLINK()
  786. **
  787. **
  788. **
  789. ** Arguments:
  790. **
  791. ** Returns:
  792. **
  793. ** Side Effects: none
  794. */
  795. PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK pcicnrl)
  796. {
  797. BOOL bResult;
  798. if (IS_VALID_READ_PTR(pcicnrl, CICNRLINK) &&
  799. IS_VALID_READ_BUFFER_PTR(pcicnrl, CICNRLINK, pcicnrl->ucbSize) &&
  800. FLAGS_ARE_VALID(pcicnrl->dwFlags, ALL_ICNRL_FLAGS) &&
  801. EVAL(IsValidCNRName(ICNRL_Remote_Name_Ptr(pcicnrl))) &&
  802. EVAL(IsContained(pcicnrl, pcicnrl->ucbSize,
  803. ICNRL_Remote_Name_PtrA(pcicnrl),
  804. lstrlenA(ICNRL_Remote_Name_PtrA(pcicnrl)))) &&
  805. (IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE) ||
  806. EVAL(IsValidNetType(pcicnrl->dwNetType))))
  807. {
  808. if (IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_DEVICE))
  809. {
  810. ASSERT(! pcicnrl->ucbDeviceOffset);
  811. bResult = TRUE;
  812. }
  813. else
  814. bResult = (EVAL(IsValidDevice(ICNRL_Device_Ptr(pcicnrl))) &&
  815. EVAL(IsContained(pcicnrl, pcicnrl->ucbSize,
  816. ICNRL_Device_PtrA(pcicnrl),
  817. lstrlenA(ICNRL_Device_PtrA(pcicnrl)))));
  818. }
  819. else
  820. bResult = FALSE;
  821. return(bResult);
  822. }
  823. #endif
  824. #if defined(DEBUG)
  825. /*
  826. ** IsValidNetProviderName()
  827. **
  828. **
  829. **
  830. ** Arguments:
  831. **
  832. ** Returns:
  833. **
  834. ** Side Effects: none
  835. */
  836. PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR pcszNetProvider)
  837. {
  838. /* Any string < MAX_PATH_LEN characters long is a valid NP name. */
  839. return(IS_VALID_STRING_PTR(pcszNetProvider, CSTR) &&
  840. lstrlen(pcszNetProvider) < MAX_PATH_LEN);
  841. }
  842. #endif
  843. /****************************** Public Functions *****************************/
  844. /*
  845. ** CreateLocalCNRLink()
  846. **
  847. **
  848. **
  849. ** Arguments:
  850. **
  851. ** Returns:
  852. **
  853. ** Side Effects: none
  854. **
  855. ** If TRUE is returned:
  856. ** 1) *ppcnrl is only valid if *pucbCNRLinkLen > 0.
  857. ** 2) pszLocalBasePathBuf is valid.
  858. ** 3) *ppcszCommonPathSuffix is valid.
  859. **
  860. ** If *pucbCNRLinkLen == 0, pszLocalBasePathBuf is a copy of pcszLocalPath, and
  861. ** *ppcszCommonPathSuffix points at the null terminator of pcszLocalPath.
  862. **
  863. ** If *pucbCNRLinkLen > 0, pszLocalBasePathBuf is the closest shared local base
  864. ** path, and *ppcszCommonPathSuffix points at that path's suffix in
  865. ** pcszLocalPath.
  866. */
  867. PUBLIC_CODE BOOL CreateLocalCNRLink(LPCTSTR pcszLocalPath, PCNRLINK *ppcnrl,
  868. PUINT pucbCNRLinkLen,
  869. LPTSTR pszLocalBasePathBuf,
  870. int cchMax,
  871. LPCTSTR *ppcszCommonPathSuffix)
  872. {
  873. BOOL bResult;
  874. TCHAR rgchNetName[MAX_PATH_LEN];
  875. BOOL bShared;
  876. DWORD dwNetType;
  877. ASSERT(IsDrivePath(pcszLocalPath));
  878. ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK));
  879. ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT));
  880. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalBasePathBuf, STR, MAX_PATH_LEN));
  881. ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR));
  882. bResult = GetNetPathFromLocalPath(pcszLocalPath, rgchNetName,
  883. ppcszCommonPathSuffix, &bShared,
  884. &dwNetType);
  885. if (bResult)
  886. {
  887. if (bShared)
  888. {
  889. bResult = UnifyICNRLinkInfo(rgchNetName, ICNRL_FL_VALID_NET_TYPE,
  890. NULL, dwNetType, (PICNRLINK *)ppcnrl,
  891. pucbCNRLinkLen);
  892. if (bResult)
  893. {
  894. UINT ucbLocalBasePathLen;
  895. /* Copy local base path into output buffer. */
  896. ASSERT(*ppcszCommonPathSuffix >= pcszLocalPath);
  897. ucbLocalBasePathLen = (UINT)(*ppcszCommonPathSuffix - pcszLocalPath);
  898. CopyMemory(pszLocalBasePathBuf, pcszLocalPath, ucbLocalBasePathLen * sizeof(TCHAR));
  899. pszLocalBasePathBuf[ucbLocalBasePathLen] = TEXT('\0');
  900. }
  901. }
  902. else
  903. {
  904. /* Not shared. No CNRLink. */
  905. *pucbCNRLinkLen = 0;
  906. /* Copy entire local path into output buffer. */
  907. lstrcpyn(pszLocalBasePathBuf, pcszLocalPath, cchMax);
  908. /* Common path suffix is the empty string. */
  909. *ppcszCommonPathSuffix = pcszLocalPath + lstrlen(pcszLocalPath);
  910. }
  911. }
  912. ASSERT(! bResult ||
  913. (EVAL(IsDrivePath(pszLocalBasePathBuf)) &&
  914. IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) &&
  915. EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) &&
  916. (! *pucbCNRLinkLen ||
  917. (IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) &&
  918. EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl))))));
  919. return(bResult);
  920. }
  921. /*
  922. ** CreateRemoteCNRLink()
  923. **
  924. **
  925. **
  926. ** Arguments:
  927. **
  928. ** Returns:
  929. **
  930. ** Side Effects: none
  931. */
  932. PUBLIC_CODE BOOL CreateRemoteCNRLink(LPCTSTR pcszRemotePath, LPCTSTR pcszCNRName,
  933. PCNRLINK *ppcnrl, PUINT pucbCNRLinkLen)
  934. {
  935. BOOL bResult;
  936. /* "D:" + null terminator. */
  937. TCHAR rgchDrive[3];
  938. DWORD dwNetType;
  939. ASSERT(IsCanonicalPath(pcszRemotePath));
  940. ASSERT(IsValidCNRName(pcszCNRName));
  941. ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK));
  942. ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT));
  943. /* Determine net provider. */
  944. bResult = GetNetType(pcszCNRName, &dwNetType);
  945. if (bResult)
  946. {
  947. DWORD dwFlags = ICNRL_FL_VALID_NET_TYPE;
  948. /* Determine last redirected drive, if any. */
  949. if (IsDrivePath(pcszRemotePath))
  950. {
  951. MyLStrCpyN(rgchDrive, pcszRemotePath, ARRAYSIZE(rgchDrive));
  952. SET_FLAG(dwFlags, ICNRL_FL_VALID_DEVICE);
  953. }
  954. else
  955. rgchDrive[0] = TEXT('\0');
  956. bResult = UnifyICNRLinkInfo(pcszCNRName, dwFlags, rgchDrive, dwNetType,
  957. (PICNRLINK *)ppcnrl, pucbCNRLinkLen);
  958. }
  959. ASSERT(! bResult ||
  960. (IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) &&
  961. EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl))));
  962. return(bResult);
  963. }
  964. /*
  965. ** DestroyCNRLink()
  966. **
  967. **
  968. **
  969. ** Arguments:
  970. **
  971. ** Returns:
  972. **
  973. ** Side Effects: none
  974. */
  975. PUBLIC_CODE void DestroyCNRLink(PCNRLINK pcnrl)
  976. {
  977. ASSERT(IS_VALID_STRUCT_PTR(pcnrl, CCNRLINK));
  978. FreeMemory(pcnrl);
  979. return;
  980. }
  981. /*
  982. ** CompareCNRLinks()
  983. **
  984. **
  985. **
  986. ** Arguments:
  987. **
  988. ** Returns:
  989. **
  990. ** Side Effects: none
  991. **
  992. ** CNR link data is compared in the following order:
  993. **
  994. ** 1) net name
  995. **
  996. ** N.b., net types are ignored when comparing CNRLinks.
  997. */
  998. PUBLIC_CODE COMPARISONRESULT CompareCNRLinks(PCCNRLINK pccnrlFirst,
  999. PCCNRLINK pccnrlSecond)
  1000. {
  1001. #ifdef UNICODE
  1002. WCHAR szWideNetNameFirst[MAX_PATH];
  1003. LPWSTR pszWideNetNameFirst;
  1004. WCHAR szWideNetNameSecond[MAX_PATH];
  1005. LPWSTR pszWideNetNameSecond;
  1006. #endif
  1007. ASSERT(IS_VALID_STRUCT_PTR(pccnrlFirst, CCNRLINK));
  1008. ASSERT(IS_VALID_STRUCT_PTR(pccnrlSecond, CCNRLINK));
  1009. #ifdef UNICODE
  1010. if (IS_ICNRL_ANSI(pccnrlFirst))
  1011. {
  1012. pszWideNetNameFirst = szWideNetNameFirst;
  1013. MultiByteToWideChar(CP_ACP, 0,
  1014. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlFirst), -1,
  1015. szWideNetNameFirst, ARRAYSIZE(szWideNetNameFirst));
  1016. }
  1017. else
  1018. {
  1019. pszWideNetNameFirst = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst);
  1020. }
  1021. if (IS_ICNRL_ANSI(pccnrlSecond))
  1022. {
  1023. pszWideNetNameSecond = szWideNetNameSecond;
  1024. MultiByteToWideChar(CP_ACP, 0,
  1025. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlSecond), -1,
  1026. szWideNetNameSecond, ARRAYSIZE(szWideNetNameSecond));
  1027. }
  1028. else
  1029. {
  1030. pszWideNetNameSecond = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond);
  1031. }
  1032. return(CompareNetNames(pszWideNetNameFirst,pszWideNetNameSecond));
  1033. #else
  1034. return(CompareNetNames(ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst),
  1035. ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond)));
  1036. #endif
  1037. }
  1038. /*
  1039. ** GetLocalPathFromCNRLink()
  1040. **
  1041. **
  1042. **
  1043. ** Arguments:
  1044. **
  1045. ** Returns:
  1046. **
  1047. ** Side Effects: none
  1048. */
  1049. PUBLIC_CODE BOOL GetLocalPathFromCNRLink(PCCNRLINK pccnrl,
  1050. LPTSTR pszLocalPathBuf,
  1051. PDWORD pdwOutFlags)
  1052. {
  1053. BOOL bResult;
  1054. PCSERVERVTABLE pcsvt;
  1055. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1056. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalPathBuf, STR, MAX_PATH_LEN));
  1057. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  1058. *pdwOutFlags = 0;
  1059. bResult = GetServerVTable(&pcsvt);
  1060. if (bResult)
  1061. {
  1062. DWORD dwNetType;
  1063. BOOL bIsLocal;
  1064. /*
  1065. * Get local path for share. N.b., the share name must be in upper case
  1066. * here for MSSHRUI.DLL.
  1067. */
  1068. dwNetType = (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
  1069. ICNRL_FL_VALID_NET_TYPE) ?
  1070. ((PCICNRLINK)pccnrl)->dwNetType :
  1071. 0);
  1072. #ifdef UNICODE
  1073. {
  1074. WCHAR szWideNetName[MAX_PATH];
  1075. LPWSTR pszWideNetName = szWideNetName;
  1076. if (IS_ICNRL_ANSI(pccnrl))
  1077. {
  1078. MultiByteToWideChar(CP_ACP, 0,
  1079. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
  1080. szWideNetName, ARRAYSIZE(szWideNetName));
  1081. }
  1082. else
  1083. {
  1084. pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1085. }
  1086. bResult = (pcsvt->GetLocalPathFromNetResource)(
  1087. pszWideNetName, dwNetType,
  1088. pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal);
  1089. }
  1090. #else
  1091. bResult = (pcsvt->GetLocalPathFromNetResource)(
  1092. ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl), dwNetType,
  1093. pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal);
  1094. #endif
  1095. if (bIsLocal)
  1096. SET_FLAG(*pdwOutFlags, CNR_FL_LOCAL);
  1097. }
  1098. ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) &&
  1099. (! bResult ||
  1100. (EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) &&
  1101. EVAL(IsLocalDrivePath(pszLocalPathBuf)))));
  1102. return(bResult);
  1103. }
  1104. /*
  1105. ** GetRemotePathFromCNRLink()
  1106. **
  1107. **
  1108. **
  1109. ** Arguments:
  1110. **
  1111. ** Returns:
  1112. **
  1113. ** Side Effects: none
  1114. */
  1115. PUBLIC_CODE void GetRemotePathFromCNRLink(PCCNRLINK pccnrl,
  1116. LPTSTR pszRemotePathBuf,
  1117. int cchMax)
  1118. {
  1119. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1120. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRemotePathBuf, STR, MAX_PATH_LEN));
  1121. /* It's ok that this is broken for non-UNC CNR names. */
  1122. /* (- 1) for trailing slash. */
  1123. #ifdef UNICODE
  1124. ASSERT(IS_ICNRL_ANSI(pccnrl) ? (lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1) :
  1125. (lstrlenW(ICNRL_Remote_Name_PtrW((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1));
  1126. #else
  1127. ASSERT(lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1);
  1128. #endif
  1129. #ifdef UNICODE
  1130. {
  1131. WCHAR szWideNetName[MAX_PATH];
  1132. LPWSTR pszWideNetName;
  1133. if (IS_ICNRL_ANSI(pccnrl))
  1134. {
  1135. pszWideNetName = szWideNetName;
  1136. MultiByteToWideChar(CP_ACP, 0,
  1137. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
  1138. szWideNetName, ARRAYSIZE(szWideNetName));
  1139. }
  1140. else
  1141. {
  1142. pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1143. }
  1144. lstrcpyn(pszRemotePathBuf, pszWideNetName, cchMax);
  1145. }
  1146. #else
  1147. lstrcpyn(pszRemotePathBuf, ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl), cchMax);
  1148. #endif
  1149. CatPath(pszRemotePathBuf, TEXT("\\"), cchMax);
  1150. return;
  1151. }
  1152. /*
  1153. ** ConnectToCNR()
  1154. **
  1155. **
  1156. **
  1157. ** Arguments:
  1158. **
  1159. ** Returns:
  1160. **
  1161. ** Side Effects: none
  1162. */
  1163. PUBLIC_CODE BOOL ConnectToCNR(PCCNRLINK pccnrl, DWORD dwInFlags,
  1164. HWND hwndOwner, LPTSTR pszRootPathBuf,
  1165. PDWORD pdwOutFlags)
  1166. {
  1167. BOOL bResult = FALSE;
  1168. BOOL bValidDevice;
  1169. BOOL bRedirect;
  1170. BOOL bTryLastDevice = FALSE;
  1171. DWORD dwcbRootPathBufLen;
  1172. LPTSTR pszNetName;
  1173. LPTSTR pszDevice;
  1174. #ifdef UNICODE
  1175. WCHAR szWideNetName[MAX_PATH];
  1176. WCHAR szWideDevice[MAX_PATH];
  1177. #endif
  1178. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1179. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_CONNECT_IN_FLAGS));
  1180. ASSERT(IS_FLAG_CLEAR(dwInFlags, CONNECT_INTERACTIVE) ||
  1181. IS_VALID_HANDLE(hwndOwner, WND));
  1182. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
  1183. ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  1184. *pdwOutFlags = 0;
  1185. #ifdef UNICODE
  1186. if (IS_ICNRL_ANSI(pccnrl))
  1187. {
  1188. pszNetName = szWideNetName;
  1189. MultiByteToWideChar(CP_ACP, 0,
  1190. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
  1191. szWideNetName, ARRAYSIZE(szWideNetName));
  1192. }
  1193. else
  1194. {
  1195. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1196. }
  1197. #else
  1198. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1199. #endif
  1200. /* Do we have an old redirected device to try? */
  1201. bValidDevice = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
  1202. ICNRL_FL_VALID_DEVICE);
  1203. #ifdef UNICODE
  1204. if ( bValidDevice )
  1205. {
  1206. if (IS_ICNRL_ANSI(pccnrl))
  1207. {
  1208. pszDevice = szWideDevice;
  1209. MultiByteToWideChar(CP_ACP, 0,
  1210. ICNRL_Device_PtrA((PCICNRLINK)pccnrl), -1,
  1211. szWideDevice, ARRAYSIZE(szWideNetName));
  1212. }
  1213. else
  1214. {
  1215. pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
  1216. }
  1217. }
  1218. #else
  1219. pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
  1220. #endif
  1221. bRedirect = (bValidDevice || IS_FLAG_SET(dwInFlags, CONNECT_REDIRECT));
  1222. if (bRedirect)
  1223. {
  1224. if (bValidDevice)
  1225. {
  1226. DWORD dwNetResult;
  1227. /* "X:" + null terminator */
  1228. TCHAR rgchDrive[2 + 1];
  1229. /* Yes. Is it already connected to the desired CNR? */
  1230. TRACE_OUT((TEXT("ConnectToCNR(): Calling WNetGetConnection() to check %s for CNR \"%s\"."),
  1231. pszDevice, pszNetName));
  1232. dwcbRootPathBufLen = MAX_PATH_LEN;
  1233. /* WNetGetConnection requires the device name to have no trailing
  1234. ** backslash.
  1235. */
  1236. MyLStrCpyN(rgchDrive, pszDevice, ARRAYSIZE(rgchDrive));
  1237. dwNetResult = WNetGetConnection(rgchDrive, pszRootPathBuf, &dwcbRootPathBufLen);
  1238. if (dwNetResult == WN_SUCCESS)
  1239. {
  1240. if (CompareNetNames(pszNetName, pszRootPathBuf)
  1241. == CR_EQUAL)
  1242. {
  1243. TRACE_OUT((TEXT("ConnectToCNR(): Found matching CNR \"%s\" on %s."),
  1244. pszRootPathBuf,
  1245. pszDevice));
  1246. ASSERT(lstrlenA(ICNRL_Device_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN);
  1247. lstrcpyn(pszRootPathBuf, pszDevice, MAX_PATH_LEN);
  1248. bResult = TRUE;
  1249. }
  1250. else
  1251. TRACE_OUT((TEXT("ConnectToCNR(): Found unmatched CNR \"%s\" on %s."),
  1252. pszRootPathBuf,
  1253. pszDevice));
  1254. }
  1255. else
  1256. {
  1257. TRACE_OUT((TEXT("ConnectToCNR(): WNetGetConnection() failed on %s."),
  1258. pszDevice));
  1259. /*
  1260. * Only attempt a connection to the last redirected device if that
  1261. * device is not already in use.
  1262. */
  1263. bTryLastDevice = (GetDriveType(pszDevice)
  1264. == DRIVE_NO_ROOT_DIR);
  1265. }
  1266. }
  1267. if (! bResult)
  1268. /* See if the desired CNR is connected to any local device. */
  1269. bResult = SearchForRedirectedConnection((PCICNRLINK)pccnrl,
  1270. pszRootPathBuf, MAX_PATH_LEN);
  1271. /*
  1272. * Assume that no reference count is maintained for redirected device
  1273. * connections, so we do not have to add a found redirected device
  1274. * connection again.
  1275. */
  1276. }
  1277. if (! bResult)
  1278. {
  1279. NETRESOURCE nr;
  1280. TCHAR rgchNPName[MAX_PATH_LEN];
  1281. /* RAIDRAID: (15691) We only support disk resource connections here. */
  1282. ZeroMemory(&nr, SIZEOF(nr));
  1283. nr.lpRemoteName = pszNetName;
  1284. nr.dwType = RESOURCETYPE_DISK;
  1285. if (GetNetProviderName((PCICNRLINK)pccnrl, rgchNPName))
  1286. nr.lpProvider = rgchNPName;
  1287. /* Shall we try the old device? */
  1288. if (bTryLastDevice)
  1289. {
  1290. /* Yes. */
  1291. ASSERT(bValidDevice);
  1292. nr.lpLocalName = pszDevice;
  1293. WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to attempt to connect %s to CNR \"%s\"."),
  1294. nr.lpLocalName,
  1295. nr.lpRemoteName));
  1296. }
  1297. else
  1298. {
  1299. /* No. Shall we attempt to force a redirected connection? */
  1300. if (bValidDevice)
  1301. {
  1302. /*
  1303. * Yes. N.b., the caller may already have set CONNECT_REDIRECT in
  1304. * dwInFlags here.
  1305. */
  1306. SET_FLAG(dwInFlags, CONNECT_REDIRECT);
  1307. WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish auto-picked redirected connection to CNR \"%s\"."),
  1308. nr.lpRemoteName));
  1309. }
  1310. else
  1311. /* No. */
  1312. WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish connection to CNR \"%s\"."),
  1313. TEXT("<nr.lpRemoteName>"))); // nr.lpRemoteName));
  1314. ASSERT(! nr.lpLocalName);
  1315. }
  1316. dwcbRootPathBufLen = MAX_PATH_LEN;
  1317. bResult = (WNetUseConnection(hwndOwner, &nr, NULL, NULL, dwInFlags,
  1318. pszRootPathBuf, &dwcbRootPathBufLen,
  1319. pdwOutFlags)
  1320. == NO_ERROR);
  1321. }
  1322. if (bResult)
  1323. CatPath(pszRootPathBuf, TEXT("\\"), MAX_PATH_LEN);
  1324. ASSERT(! bResult ||
  1325. (IS_VALID_STRING_PTR(pszRootPathBuf, STR) &&
  1326. FLAGS_ARE_VALID(*pdwOutFlags, ALL_CONNECT_OUT_FLAGS)));
  1327. return(bResult);
  1328. }
  1329. /*
  1330. ** DisconnectFromCNR()
  1331. **
  1332. **
  1333. **
  1334. ** Arguments:
  1335. **
  1336. ** Returns:
  1337. **
  1338. ** Side Effects: none
  1339. */
  1340. PUBLIC_CODE BOOL DisconnectFromCNR(PCCNRLINK pccnrl)
  1341. {
  1342. DWORD dwNetResult;
  1343. LPTSTR pszNetName;
  1344. #ifdef UNICODE
  1345. WCHAR szWideNetName[MAX_PATH];
  1346. #endif
  1347. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1348. #ifdef UNICODE
  1349. if (IS_ICNRL_ANSI(pccnrl))
  1350. {
  1351. pszNetName = szWideNetName;
  1352. MultiByteToWideChar(CP_ACP, 0,
  1353. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
  1354. szWideNetName, MAX_PATH);
  1355. }
  1356. else
  1357. {
  1358. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1359. }
  1360. #else
  1361. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1362. #endif
  1363. dwNetResult = WNetCancelConnection2(pszNetName,
  1364. CONNECT_REFCOUNT, FALSE);
  1365. if (dwNetResult == NO_ERROR)
  1366. WARNING_OUT((TEXT("DisconnectFromCNR(): Reduced connection reference count on CNR \"%s\"."),
  1367. pszNetName));
  1368. else
  1369. WARNING_OUT((TEXT("DisconnectFromCNR(): Failed to reduce connection reference count on CNR \"%s\". WNetCancelConnection2() returned %lu."),
  1370. pszNetName));
  1371. return(dwNetResult == NO_ERROR);
  1372. }
  1373. /*
  1374. ** IsCNRAvailable()
  1375. **
  1376. **
  1377. **
  1378. ** Arguments:
  1379. **
  1380. ** Returns:
  1381. **
  1382. ** Side Effects: none
  1383. */
  1384. PUBLIC_CODE BOOL IsCNRAvailable(PCCNRLINK pccnrl)
  1385. {
  1386. TCHAR rgchCNRRoot[MAX_PATH_LEN];
  1387. LPTSTR pszNetName;
  1388. #ifdef UNICODE
  1389. WCHAR szWideNetName[MAX_PATH];
  1390. #endif
  1391. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1392. #ifdef UNICODE
  1393. if (IS_ICNRL_ANSI(pccnrl))
  1394. {
  1395. pszNetName = szWideNetName;
  1396. MultiByteToWideChar(CP_ACP, 0,
  1397. ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
  1398. szWideNetName, MAX_PATH);
  1399. }
  1400. else
  1401. {
  1402. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1403. }
  1404. #else
  1405. pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1406. #endif
  1407. ASSERT(lstrlen(pszNetName) < ARRAYSIZE(rgchCNRRoot) - 1);
  1408. lstrcpyn(rgchCNRRoot, pszNetName, ARRAYSIZE(rgchCNRRoot));
  1409. CatPath(rgchCNRRoot, TEXT("\\"), ARRAYSIZE(rgchCNRRoot));
  1410. return(PathExists(rgchCNRRoot));
  1411. }
  1412. /*
  1413. ** GetCNRLinkLen()
  1414. **
  1415. **
  1416. **
  1417. ** Arguments:
  1418. **
  1419. ** Returns:
  1420. **
  1421. ** Side Effects: none
  1422. */
  1423. PUBLIC_CODE UINT GetCNRLinkLen(PCCNRLINK pccnrl)
  1424. {
  1425. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1426. return(((PCICNRLINK)pccnrl)->ucbSize);
  1427. }
  1428. /*
  1429. ** GetCNRNetType()
  1430. **
  1431. **
  1432. **
  1433. ** Arguments:
  1434. **
  1435. ** Returns:
  1436. **
  1437. ** Side Effects: none
  1438. */
  1439. PUBLIC_CODE BOOL GetCNRNetType(PCCNRLINK pccnrl, PCDWORD *ppcdwNetType)
  1440. {
  1441. BOOL bResult;
  1442. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1443. bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
  1444. ICNRL_FL_VALID_NET_TYPE);
  1445. if (bResult)
  1446. *ppcdwNetType = &(((PCICNRLINK)pccnrl)->dwNetType);
  1447. ASSERT(! bResult ||
  1448. IsValidNetType(**ppcdwNetType));
  1449. return(bResult);
  1450. }
  1451. /*
  1452. ** GetCNRName()
  1453. **
  1454. **
  1455. **
  1456. ** Arguments:
  1457. **
  1458. ** Returns:
  1459. **
  1460. ** Side Effects: none
  1461. */
  1462. PUBLIC_CODE BOOL GetCNRName(PCCNRLINK pccnrl, LPCSTR *ppcszCNRName)
  1463. {
  1464. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1465. *ppcszCNRName = ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl);
  1466. ASSERT(IS_VALID_STRING_PTRA(*ppcszCNRName, CSTR));
  1467. return(TRUE);
  1468. }
  1469. #ifdef UNICODE
  1470. /*
  1471. ** GetCNRNameW()
  1472. **
  1473. **
  1474. **
  1475. ** Arguments:
  1476. **
  1477. ** Returns:
  1478. **
  1479. ** Side Effects: none
  1480. */
  1481. PUBLIC_CODE BOOL GetCNRNameW(PCCNRLINK pccnrl, LPCWSTR *ppcszCNRName)
  1482. {
  1483. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1484. if (IS_ICNRL_ANSI(pccnrl))
  1485. *ppcszCNRName = NULL;
  1486. else
  1487. {
  1488. *ppcszCNRName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
  1489. ASSERT(IS_VALID_STRING_PTR(*ppcszCNRName, CSTR));
  1490. }
  1491. return(TRUE);
  1492. }
  1493. #endif
  1494. /*
  1495. ** GetLastRedirectedDevice()
  1496. **
  1497. **
  1498. **
  1499. ** Arguments:
  1500. **
  1501. ** Returns:
  1502. **
  1503. ** Side Effects: none
  1504. */
  1505. PUBLIC_CODE BOOL GetLastRedirectedDevice(PCCNRLINK pccnrl, LPCSTR *ppcszDevice)
  1506. {
  1507. BOOL bResult;
  1508. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1509. bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE);
  1510. if (bResult)
  1511. *ppcszDevice = ICNRL_Device_PtrA((PCICNRLINK)pccnrl);
  1512. ASSERT(! bResult ||
  1513. IS_VALID_STRING_PTRA(*ppcszDevice, CSTR));
  1514. return(bResult);
  1515. }
  1516. #ifdef UNICODE
  1517. /*
  1518. ** GetLastRedirectedDeviceW()
  1519. **
  1520. **
  1521. **
  1522. ** Arguments:
  1523. **
  1524. ** Returns:
  1525. **
  1526. ** Side Effects: none
  1527. */
  1528. PUBLIC_CODE BOOL GetLastRedirectedDeviceW(PCCNRLINK pccnrl, LPCWSTR *ppcszDevice)
  1529. {
  1530. BOOL bResult;
  1531. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1532. bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE);
  1533. if (bResult)
  1534. if (IS_ICNRL_ANSI(pccnrl))
  1535. *ppcszDevice = NULL;
  1536. else
  1537. {
  1538. *ppcszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
  1539. ASSERT(! bResult ||
  1540. IS_VALID_STRING_PTR(*ppcszDevice, CSTR));
  1541. }
  1542. return(bResult);
  1543. }
  1544. #endif
  1545. #if defined(DEBUG) || defined (VSTF)
  1546. /*
  1547. ** IsValidPCCNRLINK()
  1548. **
  1549. **
  1550. **
  1551. ** Arguments:
  1552. **
  1553. ** Returns:
  1554. **
  1555. ** Side Effects: none
  1556. */
  1557. PUBLIC_CODE BOOL IsValidPCCNRLINK(PCCNRLINK pccnrl)
  1558. {
  1559. return(IS_VALID_STRUCT_PTR((PCICNRLINK)pccnrl, CICNRLINK));
  1560. }
  1561. #endif
  1562. #ifdef DEBUG
  1563. /*
  1564. ** DumpCNRLink()
  1565. **
  1566. **
  1567. **
  1568. ** Arguments:
  1569. **
  1570. ** Returns:
  1571. **
  1572. ** Side Effects: none
  1573. */
  1574. PUBLIC_CODE void DumpCNRLink(PCCNRLINK pccnrl)
  1575. {
  1576. ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
  1577. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] ucbSize %#x"),
  1578. INDENT_STRING,
  1579. INDENT_STRING,
  1580. ((PCICNRLINK)pccnrl)->ucbSize));
  1581. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] dwFLags = %#08lx"),
  1582. INDENT_STRING,
  1583. INDENT_STRING,
  1584. ((PCICNRLINK)pccnrl)->dwFlags));
  1585. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] CNR name \"%s\""),
  1586. INDENT_STRING,
  1587. INDENT_STRING,
  1588. ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl)));
  1589. if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_NET_TYPE))
  1590. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type %#08lx"),
  1591. INDENT_STRING,
  1592. INDENT_STRING,
  1593. ((PCICNRLINK)pccnrl)->dwNetType));
  1594. else
  1595. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type unknown"),
  1596. INDENT_STRING,
  1597. INDENT_STRING));
  1598. if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE))
  1599. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] last redirected local device \"%s\""),
  1600. INDENT_STRING,
  1601. INDENT_STRING,
  1602. ICNRL_Device_Ptr((PCICNRLINK)pccnrl)));
  1603. else
  1604. PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] no last redirected local device"),
  1605. INDENT_STRING,
  1606. INDENT_STRING));
  1607. return;
  1608. }
  1609. #endif