windows-nt/Source/XPSP1/NT/shell/ext/brfcase/filesync/linkinfo/cnrlink.c
2020-09-26 16:20:57 +08:00

1957 lines
50 KiB
C

/*
* cnrlink.c - CNRLink ADT module.
*/
/* Headers
**********/
#include "project.h"
#pragma hdrstop
#include "cnrlink.h"
#include "server.h"
/* Constants
************/
/* WNetUseConnection() flag combinations */
#define ALL_CONNECT_IN_FLAGS (CONNECT_UPDATE_PROFILE |\
CONNECT_UPDATE_RECENT |\
CONNECT_TEMPORARY |\
CONNECT_INTERACTIVE |\
CONNECT_PROMPT |\
CONNECT_REDIRECT)
#define ALL_CONNECT_OUT_FLAGS (CONNECT_REFCOUNT |\
CONNECT_LOCALDRIVE)
/* Macros
*********/
/* macros for accessing ICNRLINK data */
#define ICNRL_Remote_Name_PtrA(picnrl) \
((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffset))
#define ICNRL_Device_PtrA(picnrl) \
((LPSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffset))
#define ICNRL_Remote_Name_PtrW(picnrl) \
((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbNetNameOffsetW))
#define ICNRL_Device_PtrW(picnrl) \
((LPWSTR)(((PBYTE)(picnrl)) + (picnrl)->ucbDeviceOffsetW))
#define IS_ICNRL_ANSI(picnrl) \
((PBYTE)(picnrl) + ((PICNRLINKW)(picnrl))->ucbNetNameOffset) == (PBYTE)&(((PICNRLINKW)(picnrl))->ucbNetNameOffsetW)
#ifdef UNICODE
#define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrW(picnrl)
#define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrW(picnrl)
#else
#define ICNRL_Remote_Name_Ptr(picnrl) ICNRL_Remote_Name_PtrA(picnrl)
#define ICNRL_Device_Ptr(picnrl) ICNRL_Device_PtrA(picnrl)
#endif
/* Types
********/
/*
@doc INTERNAL
@enum ICNRLINKFLAGS | Internal CNRLink structure flags.
*/
typedef enum _icnrlinkflags
{
/*
@emem ICNRL_FL_VALID_DEVICE | If set, last redirected drive is valid. If
clear, last redirected drive is not valid.
*/
ICNRL_FL_VALID_DEVICE = 0x0001,
/*
@emem ICNRL_FL_VALID_NET_TYPE | If set, net type is valid. If clear, net
type is not valid.
*/
ICNRL_FL_VALID_NET_TYPE = 0x0002,
/* @emem ALL_ICNRL_FLAGS | All internal CNRLink structure flags. */
ALL_ICNRL_FLAGS = (ICNRL_FL_VALID_DEVICE |
ICNRL_FL_VALID_NET_TYPE)
}
ICNRLINKFLAGS;
/*
@doc INTERNAL
@struct ICNRLINK | Internal definition of relocatable connectable network
resource (CNR) link structure. An <t ILINKINFO> structure may contain an
ICNRLINK structure. An ICNRLINK structure consists of a header described as
below, followed by variable-length data.
*/
typedef struct _icnrlinkA
{
/*
@field UINT | ucbSize | Length of ICNRLINK structure in bytes, including
ucbSize field.
*/
UINT ucbSize;
/*
@field DWORD | dwFlags | A bit mask of flags from the <t ICNRLINKFLAGS>
enumeration.
*/
DWORD dwFlags;
/*
@field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from
base of structure. The CNR name string may be passed to
WNetUseConnection() to add a connection to the CNR.<nl>
Example CNRLink name string: "\\\\fredbird\\work".
*/
UINT ucbNetNameOffset;
/*
@field UINT | ucbDeviceOffset | Offset in bytes of last redirected local
device string from base of structure. This field is only valid if
ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local
device string may be passed to WNetUseConnection() to add a redirected
device connection to the CNR.<nl>
Example last redirected local device string: "D:".
*/
UINT ucbDeviceOffset;
/*
@field DWORD | dwNetType | The network type as returned in a
NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is
set in dwFlags. The net type is used to retrieve the host net resource's
host NP's name to use in calling WNetUseConnection().<nl>
Example net type: WNNC_NET_NETWARE.
*/
DWORD dwNetType;
}
ICNRLINKA;
DECLARE_STANDARD_TYPES(ICNRLINKA);
#ifdef UNICODE
typedef struct _icnrlinkW
{
/*
@field UINT | ucbSize | Length of ICNRLINK structure in bytes, including
ucbSize field.
*/
UINT ucbSize;
/*
@field DWORD | dwFlags | A bit mask of flags from the <t ICNRLINKFLAGS>
enumeration.
*/
DWORD dwFlags;
/*
@field UINT | ucbNetNameOffset | Offset in bytes of CNR name string from
base of structure. The CNR name string may be passed to
WNetUseConnection() to add a connection to the CNR.<nl>
Example CNRLink name string: "\\\\fredbird\\work".
*/
UINT ucbNetNameOffset;
/*
@field UINT | ucbDeviceOffset | Offset in bytes of last redirected local
device string from base of structure. This field is only valid if
ICNRL_FL_VALID_DEVICE is set in dwFlags. The last redirected local
device string may be passed to WNetUseConnection() to add a redirected
device connection to the CNR.<nl>
Example last redirected local device string: "D:".
*/
UINT ucbDeviceOffset;
/*
@field DWORD | dwNetType | The network type as returned in a
NETINFOSTRUCT. This field is only valid if ICNRL_FL_VALID_NET_TYPE is
set in dwFlags. The net type is used to retrieve the host net resource's
host NP's name to use in calling WNetUseConnection().<nl>
Example net type: WNNC_NET_NETWARE.
*/
DWORD dwNetType;
/*
These members are for storing the unicode version of the strings
*/
UINT ucbNetNameOffsetW;
UINT ucbDeviceOffsetW;
}
ICNRLINKW;
DECLARE_STANDARD_TYPES(ICNRLINKW);
#endif
#ifdef UNICODE
#define ICNRLINK ICNRLINKW
#define PICNRLINK PICNRLINKW
#define CICNRLINK CICNRLINKW
#define PCICNRLINK PCICNRLINKW
#else
#define ICNRLINK ICNRLINKA
#define PICNRLINK PICNRLINKA
#define CICNRLINK CICNRLINKA
#define PCICNRLINK PCICNRLINKA
#endif
/* Exported from MPR.DLL, but not in winnetwk.h
*/
#ifdef UNICODE
DWORD APIENTRY WNetGetResourceInformationW (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem);
#define WNetGetResourceInformation WNetGetResourceInformationW
#else
DWORD APIENTRY WNetGetResourceInformationA (LPNETRESOURCE lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPTSTR * lplpSystem);
#define WNetGetResourceInformation WNetGetResourceInformationA
#endif
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR, LPTSTR, LPCTSTR *, PBOOL, PDWORD);
PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR, DWORD, LPCTSTR, DWORD, PICNRLINK *, PUINT);
PRIVATE_CODE BOOL GetNetType(LPCTSTR, PDWORD);
PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK, LPTSTR);
PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR, LPCTSTR);
PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK, LPTSTR);
#if defined(DEBUG) || defined (VSTF)
PRIVATE_CODE BOOL IsValidDevice(LPCTSTR);
PRIVATE_CODE BOOL IsValidNetType(DWORD);
PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK);
#endif
#if defined(DEBUG)
PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR);
#endif
#if 0
DWORD APIENTRY
WNetGetNetworkInformationW(
LPCWSTR lpProvider,
LPNETINFOSTRUCT lpNetInfoStruct
)
{
if (wcsicmp(lpProvider, L"Microsoft Windows Network") == 0)
{
lpNetInfoStruct->wNetType = (WORD)WNNC_NET_LANMAN;
return ERROR_SUCCESS;
}
else if (wcsicmp(lpProvider, L"Novell Network") == 0)
{
lpNetInfoStruct->wNetType = (WORD)WNNC_NET_NETWARE;
return ERROR_SUCCESS;
}
else
{
return ERROR_NOT_SUPPORTED;
}
}
#endif
/*
** GetNetPathFromLocalPath()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL GetNetPathFromLocalPath(LPCTSTR pcszLocalPath,
LPTSTR pszNetNameBuf,
LPCTSTR *ppcszCommonPathSuffix,
PBOOL pbIsShared, PDWORD pdwNetType)
{
BOOL bResult = TRUE;
PCSERVERVTABLE pcsvt;
ASSERT(IsDrivePath(pcszLocalPath));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNetNameBuf, STR, MAX_PATH_LEN));
ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR));
ASSERT(IS_VALID_WRITE_PTR(pbIsShared, BOOL));
ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD));
*pbIsShared = FALSE;
if (GetServerVTable(&pcsvt))
{
TCHAR rgchSharedPath[MAX_PATH_LEN];
ASSERT(lstrlen(pcszLocalPath) < ARRAYSIZE(rgchSharedPath));
lstrcpy(rgchSharedPath, pcszLocalPath);
FOREVER
{
if ((pcsvt->GetNetResourceFromLocalPath)(rgchSharedPath,
pszNetNameBuf, MAX_PATH_LEN,
pdwNetType))
{
ASSERT(lstrlen(pszNetNameBuf) < MAX_PATH_LEN);
/* Determine common path suffix. */
*ppcszCommonPathSuffix = pcszLocalPath + lstrlen(rgchSharedPath);
/* Skip any leading slash. */
if (IS_SLASH(**ppcszCommonPathSuffix))
*ppcszCommonPathSuffix = CharNext(*ppcszCommonPathSuffix);
ASSERT(! IS_SLASH(**ppcszCommonPathSuffix));
// if it is terminated with a $ it is a hidden share, in that
// case don't consider this shared
*pbIsShared = pszNetNameBuf[lstrlen(pszNetNameBuf) -1] != TEXT('$');
break;
}
else
{
if (! DeleteLastDrivePathElement(rgchSharedPath))
break;
}
}
}
ASSERT(! bResult ||
! *pbIsShared ||
(EVAL(IsUNCPath(pszNetNameBuf)) &&
IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) &&
EVAL(*ppcszCommonPathSuffix >= pcszLocalPath) &&
EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) &&
EVAL(IsValidNetType(*pdwNetType))));
return(bResult);
}
/*
** UnifyICNRLinkInfo()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL UnifyICNRLinkInfo(LPCTSTR pcszNetName, DWORD dwFlags,
LPCTSTR pcszDevice, DWORD dwNetType,
PICNRLINK *ppicnrl, PUINT pucbICNRLinkLen)
{
BOOL bResult;
UINT ucbDataOffset;
#ifdef UNICODE
BOOL bUnicode;
UINT cchChars;
CHAR szAnsiNetName[MAX_PATH];
CHAR szAnsiDevice[MAX_PATH];
UINT cbAnsiNetName;
UINT cbWideNetName;
UINT cbAnsiDevice;
UINT cbWideDevice;
UINT cbChars;
#endif
ASSERT(IsUNCPath(pcszNetName));
ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_ICNRL_FLAGS));
ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_DEVICE) ||
IsValidDevice(pcszDevice));
ASSERT(IS_FLAG_CLEAR(dwFlags, ICNRL_FL_VALID_NET_TYPE) ||
IsValidNetType(dwNetType));
ASSERT(IS_VALID_WRITE_PTR(ppicnrl, PCNRLINK));
ASSERT(IS_VALID_WRITE_PTR(pucbICNRLinkLen, UINT));
#ifdef UNICODE
bUnicode = FALSE;
cbAnsiNetName = WideCharToMultiByte(CP_ACP, 0,
pcszNetName, -1,
szAnsiNetName, MAX_PATH,
0, 0);
if ( cbAnsiNetName == 0 )
{
bUnicode = FALSE;
}
else
{
WCHAR szWideNetName[MAX_PATH];
cbChars = MultiByteToWideChar(CP_ACP, 0,
szAnsiNetName, -1,
szWideNetName, MAX_PATH);
if ( cbChars == 0 || lstrcmp(pcszNetName,szWideNetName) != 0 )
{
bUnicode = TRUE;
}
}
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
{
cbAnsiDevice = WideCharToMultiByte(CP_ACP, 0,
pcszDevice, -1,
szAnsiDevice, MAX_PATH,
0, 0);
if ( cbAnsiDevice == 0 )
{
bUnicode = FALSE;
}
else
{
WCHAR szWideDevice[MAX_PATH];
cchChars = MultiByteToWideChar(CP_ACP, 0,
szAnsiDevice, -1,
szWideDevice, MAX_PATH);
if ( cchChars == 0 || lstrcmp(pcszDevice,szWideDevice) != 0 )
{
bUnicode = TRUE;
}
}
}
else
{
cbAnsiDevice = 0;
}
if ( bUnicode )
{
ucbDataOffset = SIZEOF(ICNRLINKW);
/* (+ 1) for null terminator. */
cbWideNetName = (lstrlen(pcszNetName) + 1) * sizeof(TCHAR);
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
cbWideDevice = (lstrlen(pcszDevice) + 1) * sizeof(TCHAR);
else
cbWideDevice = 0;
}
else
{
ucbDataOffset = SIZEOF(ICNRLINKA);
cbWideNetName = 0;
cbWideDevice = 0;
}
*pucbICNRLinkLen = ucbDataOffset +
cbAnsiNetName +
cbAnsiDevice;
if ( bUnicode )
{
*pucbICNRLinkLen = ALIGN_WORD_CNT(*pucbICNRLinkLen) +
cbWideNetName +
cbWideDevice;
}
#else
/* Assume we won't overflow *pucbICNRLinkLen here. */
/* (+ 1) for null terminator. */
*pucbICNRLinkLen = SIZEOF(**ppicnrl) +
(lstrlen(pcszNetName) + 1) * SIZEOF(TCHAR);
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
/* (+ 1) for null terminator. */
*pucbICNRLinkLen += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR);
ucbDataOffset = SIZEOF(ICNRLINKA);
#endif
bResult = AllocateMemory(*pucbICNRLinkLen, ppicnrl);
if (bResult)
{
(*ppicnrl)->ucbSize = *pucbICNRLinkLen;
(*ppicnrl)->dwFlags = dwFlags;
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_NET_TYPE))
(*ppicnrl)->dwNetType = dwNetType;
else
(*ppicnrl)->dwNetType = 0;
/* Append remote name. */
(*ppicnrl)->ucbNetNameOffset = ucbDataOffset;
#ifdef UNICODE
lstrcpyA(ICNRL_Remote_Name_PtrA(*ppicnrl), szAnsiNetName);
ucbDataOffset += cbAnsiNetName;
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
{
/* Append device name. */
(*ppicnrl)->ucbDeviceOffset = ucbDataOffset;
lstrcpyA(ICNRL_Device_PtrA(*ppicnrl), szAnsiDevice);
ucbDataOffset += cbAnsiDevice;
}
else
{
(*ppicnrl)->ucbDeviceOffset = 0;
}
if ( bUnicode )
{
ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
(*ppicnrl)->ucbNetNameOffsetW = ucbDataOffset;
lstrcpy(ICNRL_Remote_Name_PtrW(*ppicnrl), pcszNetName);
ucbDataOffset += cbWideNetName;
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
{
/* Append device name. */
(*ppicnrl)->ucbDeviceOffsetW = ucbDataOffset;
lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice);
/* (+ 1) for null terminator. */
ucbDataOffset += cbWideDevice;
}
else
{
(*ppicnrl)->ucbDeviceOffsetW = 0;
}
}
#else
lstrcpy(ICNRL_Remote_Name_Ptr(*ppicnrl), pcszNetName);
/* (+ 1) for null terminator. */
ucbDataOffset += lstrlen(pcszNetName) + 1;
if (IS_FLAG_SET(dwFlags, ICNRL_FL_VALID_DEVICE))
{
/* Append device name. */
(*ppicnrl)->ucbDeviceOffset = ucbDataOffset;
lstrcpy(ICNRL_Device_Ptr(*ppicnrl), pcszDevice);
#ifdef DEBUG
/* (+ 1) for null terminator. */
ucbDataOffset += (lstrlen(pcszDevice) + 1) * SIZEOF(TCHAR);
#endif
}
else
(*ppicnrl)->ucbDeviceOffset = 0;
#endif
/* Do all the calculated lengths match? */
ASSERT(ucbDataOffset == (*ppicnrl)->ucbSize);
ASSERT(ucbDataOffset == *pucbICNRLinkLen);
}
ASSERT(! bResult ||
(IS_VALID_STRUCT_PTR(*ppicnrl, CICNRLINK) &&
EVAL(*pucbICNRLinkLen == GetCNRLinkLen((PCCNRLINK)*ppicnrl))));
return(bResult);
}
/*
** GetNetType()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL GetNetType(LPCTSTR pcszCNRName, PDWORD pdwNetType)
{
BOOL bResult = FALSE;
NETRESOURCE nrIn;
NETRESOURCEBUF nrbufOut;
DWORD dwcbBufLen = SIZEOF(nrbufOut);
LPTSTR pszFileSysPath;
DWORD dwNetResult;
#ifdef DEBUG
DWORD dwcmsTicks;
#endif
ASSERT(IsValidCNRName(pcszCNRName));
ASSERT(IS_VALID_WRITE_PTR(pdwNetType, DWORD));
/* RAIDRAID: (15691) We only support disk resource connections here. */
ZeroMemory(&nrIn, SIZEOF(nrIn));
nrIn.lpRemoteName = (LPTSTR)pcszCNRName;
nrIn.dwType = RESOURCETYPE_DISK;
#ifdef DEBUG
dwcmsTicks = GetTickCount();
#endif
dwNetResult = WNetGetResourceInformation(&nrIn, &(nrbufOut.rgbyte),
&dwcbBufLen, &pszFileSysPath);
#ifdef DEBUG
dwcmsTicks = GetTickCount() - dwcmsTicks;
TRACE_OUT((TEXT("GetRemotePathInfo(): WNetGetResourceInformation() on net resource %s took %lu.%03lu seconds."),
pcszCNRName,
(dwcmsTicks / 1000),
(dwcmsTicks % 1000)));
#endif
if (dwNetResult == ERROR_SUCCESS)
{
if (nrbufOut.nr.lpProvider)
{
NETINFOSTRUCT nis;
ASSERT(IS_VALID_STRING_PTR(nrbufOut.nr.lpProvider, STR));
nis.cbStructure = SIZEOF(nis);
dwNetResult = WNetGetNetworkInformation(nrbufOut.nr.lpProvider, &nis);
if (dwNetResult == ERROR_SUCCESS)
{
*pdwNetType = ((nis.wNetType) << 16);
bResult = TRUE;
TRACE_OUT((TEXT("GetNetType(): Net type for CNR %s is %#08lx."),
pcszCNRName,
*pdwNetType));
}
else
WARNING_OUT((TEXT("GetNetType(): WNetGetNetworkInformation() failed for %s NP, returning %lu."),
nrbufOut.nr.lpProvider,
dwNetResult));
}
else
WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() was unable to determine the NP for CNR %s."),
pcszCNRName));
}
else
WARNING_OUT((TEXT("GetNetType(): WNetGetResourceInformation() failed for CNR %s, returning %lu."),
pcszCNRName,
dwNetResult));
ASSERT(! bResult ||
IsValidNetType(*pdwNetType));
return(bResult);
}
/*
** GetNetProviderName()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL GetNetProviderName(PCICNRLINK pcicnrl, LPTSTR pszNPNameBuf)
{
BOOL bResult = FALSE;
ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNPNameBuf, STR, MAX_PATH_LEN));
if (IS_FLAG_SET(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE))
{
DWORD dwcbNPNameBufLen;
DWORD dwNetResult;
dwcbNPNameBufLen = MAX_PATH_LEN;
dwNetResult = WNetGetProviderName(pcicnrl->dwNetType, pszNPNameBuf,
&dwcbNPNameBufLen);
if (dwNetResult == ERROR_SUCCESS)
{
bResult = TRUE;
#ifdef UNICODE
//
// Unicode builds need to accept both ansi and unicode ICNRLINK structures.
// Note the use of '%S' (upper case). This will accept an ANSI string
// in a UNICODE build environment.
//
if (IS_ICNRL_ANSI(pcicnrl))
TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %S is %s."),
ICNRL_Remote_Name_PtrA(pcicnrl),
pszNPNameBuf));
else
#endif
TRACE_OUT((TEXT("GetNetProviderName(): NP for CNR %s is %s."),
ICNRL_Remote_Name_Ptr(pcicnrl),
pszNPNameBuf));
}
else
WARNING_OUT((TEXT("GetNetProviderName(): WNetGetProviderName() failed for CNR %s's net type %#08lx, returning %lu."),
TEXT("<Remote Name>"), // ICNRL_Remote_Name_Ptr(pcicnrl),
pcicnrl->dwNetType,
dwNetResult));
}
else
WARNING_OUT((TEXT("GetNetProviderName(): Net type for CNR %s is not known. Unable to determine NP name."),
TEXT("<Remote Name>"))); // ICNRL_Remote_Name_Ptr(pcicnrl)));
ASSERT(! bResult ||
IsValidNetProviderName(pszNPNameBuf));
return(bResult);
}
/*
** CompareNetNames()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE COMPARISONRESULT CompareNetNames(LPCTSTR pcszFirstNetName,
LPCTSTR pcszSecondNetName)
{
ASSERT(IS_VALID_STRING_PTR(pcszFirstNetName, CSTR));
ASSERT(IS_VALID_STRING_PTR(pcszSecondNetName, CSTR));
return(MapIntToComparisonResult(lstrcmp(pcszFirstNetName,
pcszSecondNetName)));
}
/*
** SearchForRedirectedConnection()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL SearchForRedirectedConnection(PCICNRLINK pcicnrl,
LPTSTR pszRootPathBuf)
{
BOOL bResult = FALSE;
HANDLE henum;
DWORD dwNetResult;
ASSERT(IS_VALID_STRUCT_PTR(pcicnrl, CICNRLINK));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
#ifdef DEBUG
#ifdef UNICODE
{
LPWSTR pszWideNetName;
WCHAR szWideNetName[MAX_PATH];
if (IS_ICNRL_ANSI(pcicnrl))
{
pszWideNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA(pcicnrl), -1,
szWideNetName, MAX_PATH);
} else {
pszWideNetName = ICNRL_Remote_Name_PtrW(pcicnrl);
}
WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."),
pszWideNetName));
}
#else
WARNING_OUT((TEXT("SearchForRedirectedConnection(): Enumerating local connections searching for redirected connection to CNR \"%s\"."),
ICNRL_Remote_Name_Ptr(pcicnrl)));
#endif
#endif
/* RAIDRAID: (15691) We only support container resources here. */
dwNetResult = WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_DISK,
RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED,
NULL, &henum);
if (dwNetResult == WN_SUCCESS)
{
DWORD dwc = 1;
NETRESOURCEBUF nrbuf;
DWORD dwcbBufLen = SIZEOF(nrbuf);
while ((dwNetResult = WNetEnumResource(henum, &dwc, &(nrbuf.rgbyte),
&dwcbBufLen))
== WN_SUCCESS)
{
/* Is this a redirected connection? */
if (nrbuf.nr.lpRemoteName != NULL)
{
if (nrbuf.nr.lpLocalName != NULL)
{
/* Yes. Is it a redirected connection to the desired CNR? */
#ifdef UNICODE
WCHAR szWideNetName[MAX_PATH];
LPWSTR pszWideNetName;
if (IS_ICNRL_ANSI(pcicnrl))
{
pszWideNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA(pcicnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszWideNetName = ICNRL_Remote_Name_Ptr(pcicnrl);
}
if (CompareNetNames(pszWideNetName,
nrbuf.nr.lpRemoteName)
== CR_EQUAL)
#else
if (CompareNetNames(ICNRL_Remote_Name_Ptr(pcicnrl),
nrbuf.nr.lpRemoteName)
== CR_EQUAL)
#endif
{
/* Yes. */
ASSERT(lstrlen(nrbuf.nr.lpLocalName) < MAX_PATH_LEN);
lstrcpy(pszRootPathBuf, nrbuf.nr.lpLocalName);
bResult = TRUE;
TRACE_OUT((TEXT("SearchForRedirectedConnection(): Found CNR \"%s\" connected to %s."),
nrbuf.nr.lpRemoteName,
pszRootPathBuf));
break;
}
else
/* No. */
TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping unmatched enumerated connection to CNR \"%s\" on %s."),
nrbuf.nr.lpRemoteName,
nrbuf.nr.lpLocalName));
}
else
/* No. */
TRACE_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated deviceless connection to CNR \"%s\"."),
nrbuf.nr.lpRemoteName));
}
else
WARNING_OUT((TEXT("SearchForRedirectedConnection(): Skipping enumerated connection with no CNR name.")));
}
if (! bResult && dwNetResult != WN_NO_MORE_ENTRIES)
WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetEnumResource() failed, returning %lu."),
dwNetResult));
dwNetResult = WNetCloseEnum(henum);
if (dwNetResult != WN_SUCCESS)
WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetCloseEnum() failed, returning %lu."),
dwNetResult));
}
else
WARNING_OUT((TEXT("SearchForRedirectedConnection(): WNetOpenEnum() failed, returning %lu."),
dwNetResult));
return(bResult);
}
#if defined(DEBUG) || defined (VSTF)
/*
** IsValidDevice()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidDevice(LPCTSTR pcszDevice)
{
/* Any valid string < MAX_PATH_LEN bytes long is a valid device name. */
return(IS_VALID_STRING_PTR(pcszDevice, CSTR) &&
EVAL(lstrlen(pcszDevice) < MAX_PATH_LEN));
}
/*
** IsValidNetType()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidNetType(DWORD dwNetType)
{
BOOL bResult;
switch (dwNetType & 0xffff0000)
{
default:
WARNING_OUT((TEXT("IsValidNetType(): Unexpected net type %#08lx is neither NetWare nor LANMan."),
dwNetType));
/* Fall through... */
case WNNC_NET_LANMAN:
case WNNC_NET_NETWARE:
bResult = TRUE;
break;
}
if (dwNetType & 0x0000ffff)
WARNING_OUT((TEXT("IsValidNetType(): Low word of net type %#08lx is non-zero."),
dwNetType));
return(bResult);
}
/*
** IsValidPCICNRLINK()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidPCICNRLINK(PCICNRLINK pcicnrl)
{
BOOL bResult;
if (IS_VALID_READ_PTR(pcicnrl, CICNRLINK) &&
IS_VALID_READ_BUFFER_PTR(pcicnrl, CICNRLINK, pcicnrl->ucbSize) &&
FLAGS_ARE_VALID(pcicnrl->dwFlags, ALL_ICNRL_FLAGS) &&
EVAL(IsValidCNRName(ICNRL_Remote_Name_Ptr(pcicnrl))) &&
EVAL(IsContained(pcicnrl, pcicnrl->ucbSize,
ICNRL_Remote_Name_PtrA(pcicnrl),
lstrlenA(ICNRL_Remote_Name_PtrA(pcicnrl)))) &&
(IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_NET_TYPE) ||
EVAL(IsValidNetType(pcicnrl->dwNetType))))
{
if (IS_FLAG_CLEAR(pcicnrl->dwFlags, ICNRL_FL_VALID_DEVICE))
{
ASSERT(! pcicnrl->ucbDeviceOffset);
bResult = TRUE;
}
else
bResult = (EVAL(IsValidDevice(ICNRL_Device_Ptr(pcicnrl))) &&
EVAL(IsContained(pcicnrl, pcicnrl->ucbSize,
ICNRL_Device_PtrA(pcicnrl),
lstrlenA(ICNRL_Device_PtrA(pcicnrl)))));
}
else
bResult = FALSE;
return(bResult);
}
#endif
#if defined(DEBUG)
/*
** IsValidNetProviderName()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidNetProviderName(LPCTSTR pcszNetProvider)
{
/* Any string < MAX_PATH_LEN characters long is a valid NP name. */
return(IS_VALID_STRING_PTR(pcszNetProvider, CSTR) &&
lstrlen(pcszNetProvider) < MAX_PATH_LEN);
}
#endif
/****************************** Public Functions *****************************/
/*
** CreateLocalCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
**
** If TRUE is returned:
** 1) *ppcnrl is only valid if *pucbCNRLinkLen > 0.
** 2) pszLocalBasePathBuf is valid.
** 3) *ppcszCommonPathSuffix is valid.
**
** If *pucbCNRLinkLen == 0, pszLocalBasePathBuf is a copy of pcszLocalPath, and
** *ppcszCommonPathSuffix points at the null terminator of pcszLocalPath.
**
** If *pucbCNRLinkLen > 0, pszLocalBasePathBuf is the closest shared local base
** path, and *ppcszCommonPathSuffix points at that path's suffix in
** pcszLocalPath.
*/
PUBLIC_CODE BOOL CreateLocalCNRLink(LPCTSTR pcszLocalPath, PCNRLINK *ppcnrl,
PUINT pucbCNRLinkLen,
LPTSTR pszLocalBasePathBuf,
LPCTSTR *ppcszCommonPathSuffix)
{
BOOL bResult;
TCHAR rgchNetName[MAX_PATH_LEN];
BOOL bShared;
DWORD dwNetType;
ASSERT(IsDrivePath(pcszLocalPath));
ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK));
ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalBasePathBuf, STR, MAX_PATH_LEN));
ASSERT(IS_VALID_WRITE_PTR(ppcszCommonPathSuffix, LPCTSTR));
bResult = GetNetPathFromLocalPath(pcszLocalPath, rgchNetName,
ppcszCommonPathSuffix, &bShared,
&dwNetType);
if (bResult)
{
if (bShared)
{
bResult = UnifyICNRLinkInfo(rgchNetName, ICNRL_FL_VALID_NET_TYPE,
NULL, dwNetType, (PICNRLINK *)ppcnrl,
pucbCNRLinkLen);
if (bResult)
{
UINT ucbLocalBasePathLen;
/* Copy local base path into output buffer. */
ASSERT(*ppcszCommonPathSuffix >= pcszLocalPath);
ucbLocalBasePathLen = (UINT)(*ppcszCommonPathSuffix - pcszLocalPath);
CopyMemory(pszLocalBasePathBuf, pcszLocalPath, ucbLocalBasePathLen * sizeof(TCHAR));
pszLocalBasePathBuf[ucbLocalBasePathLen] = TEXT('\0');
}
}
else
{
/* Not shared. No CNRLink. */
*pucbCNRLinkLen = 0;
/* Copy entire local path into output buffer. */
lstrcpy(pszLocalBasePathBuf, pcszLocalPath);
/* Common path suffix is the empty string. */
*ppcszCommonPathSuffix = pcszLocalPath + lstrlen(pcszLocalPath);
}
}
ASSERT(! bResult ||
(EVAL(IsDrivePath(pszLocalBasePathBuf)) &&
IS_VALID_STRING_PTR(*ppcszCommonPathSuffix, CSTR) &&
EVAL(IsStringContained(pcszLocalPath, *ppcszCommonPathSuffix)) &&
(! *pucbCNRLinkLen ||
(IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) &&
EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl))))));
return(bResult);
}
/*
** CreateRemoteCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL CreateRemoteCNRLink(LPCTSTR pcszRemotePath, LPCTSTR pcszCNRName,
PCNRLINK *ppcnrl, PUINT pucbCNRLinkLen)
{
BOOL bResult;
/* "D:" + null terminator. */
TCHAR rgchDrive[3];
DWORD dwNetType;
ASSERT(IsCanonicalPath(pcszRemotePath));
ASSERT(IsValidCNRName(pcszCNRName));
ASSERT(IS_VALID_WRITE_PTR(ppcnrl, PCNRLINK));
ASSERT(IS_VALID_WRITE_PTR(pucbCNRLinkLen, UINT));
/* Determine net provider. */
bResult = GetNetType(pcszCNRName, &dwNetType);
if (bResult)
{
DWORD dwFlags = ICNRL_FL_VALID_NET_TYPE;
/* Determine last redirected drive, if any. */
if (IsDrivePath(pcszRemotePath))
{
MyLStrCpyN(rgchDrive, pcszRemotePath, ARRAYSIZE(rgchDrive));
SET_FLAG(dwFlags, ICNRL_FL_VALID_DEVICE);
}
else
rgchDrive[0] = TEXT('\0');
bResult = UnifyICNRLinkInfo(pcszCNRName, dwFlags, rgchDrive, dwNetType,
(PICNRLINK *)ppcnrl, pucbCNRLinkLen);
}
ASSERT(! bResult ||
(IS_VALID_STRUCT_PTR((PCICNRLINK)*ppcnrl, CICNRLINK) &&
EVAL(*pucbCNRLinkLen == GetCNRLinkLen(*ppcnrl))));
return(bResult);
}
/*
** DestroyCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void DestroyCNRLink(PCNRLINK pcnrl)
{
ASSERT(IS_VALID_STRUCT_PTR(pcnrl, CCNRLINK));
FreeMemory(pcnrl);
return;
}
/*
** CompareCNRLinks()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
**
** CNR link data is compared in the following order:
**
** 1) net name
**
** N.b., net types are ignored when comparing CNRLinks.
*/
PUBLIC_CODE COMPARISONRESULT CompareCNRLinks(PCCNRLINK pccnrlFirst,
PCCNRLINK pccnrlSecond)
{
#ifdef UNICODE
WCHAR szWideNetNameFirst[MAX_PATH];
LPWSTR pszWideNetNameFirst;
WCHAR szWideNetNameSecond[MAX_PATH];
LPWSTR pszWideNetNameSecond;
#endif
ASSERT(IS_VALID_STRUCT_PTR(pccnrlFirst, CCNRLINK));
ASSERT(IS_VALID_STRUCT_PTR(pccnrlSecond, CCNRLINK));
#ifdef UNICODE
if (IS_ICNRL_ANSI(pccnrlFirst))
{
pszWideNetNameFirst = szWideNetNameFirst;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlFirst), -1,
szWideNetNameFirst, MAX_PATH);
}
else
{
pszWideNetNameFirst = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst);
}
if (IS_ICNRL_ANSI(pccnrlSecond))
{
pszWideNetNameSecond = szWideNetNameSecond;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrlSecond), -1,
szWideNetNameSecond, MAX_PATH);
}
else
{
pszWideNetNameSecond = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond);
}
return(CompareNetNames(pszWideNetNameFirst,pszWideNetNameSecond));
#else
return(CompareNetNames(ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlFirst),
ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrlSecond)));
#endif
}
/*
** GetLocalPathFromCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetLocalPathFromCNRLink(PCCNRLINK pccnrl,
LPTSTR pszLocalPathBuf,
PDWORD pdwOutFlags)
{
BOOL bResult;
PCSERVERVTABLE pcsvt;
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszLocalPathBuf, STR, MAX_PATH_LEN));
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
*pdwOutFlags = 0;
bResult = GetServerVTable(&pcsvt);
if (bResult)
{
DWORD dwNetType;
BOOL bIsLocal;
/*
* Get local path for share. N.b., the share name must be in upper case
* here for MSSHRUI.DLL.
*/
dwNetType = (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
ICNRL_FL_VALID_NET_TYPE) ?
((PCICNRLINK)pccnrl)->dwNetType :
0);
#ifdef UNICODE
{
WCHAR szWideNetName[MAX_PATH];
LPWSTR pszWideNetName = szWideNetName;
if (IS_ICNRL_ANSI(pccnrl))
{
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
}
bResult = (pcsvt->GetLocalPathFromNetResource)(
pszWideNetName, dwNetType,
pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal);
}
#else
bResult = (pcsvt->GetLocalPathFromNetResource)(
ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl), dwNetType,
pszLocalPathBuf, MAX_PATH_LEN, &bIsLocal);
#endif
if (bIsLocal)
SET_FLAG(*pdwOutFlags, CNR_FL_LOCAL);
}
ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) &&
(! bResult ||
(EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) &&
EVAL(IsLocalDrivePath(pszLocalPathBuf)))));
return(bResult);
}
/*
** GetRemotePathFromCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void GetRemotePathFromCNRLink(PCCNRLINK pccnrl,
LPTSTR pszRemotePathBuf)
{
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRemotePathBuf, STR, MAX_PATH_LEN));
/* It's ok that this is broken for non-UNC CNR names. */
/* (- 1) for trailing slash. */
#ifdef UNICODE
ASSERT(IS_ICNRL_ANSI(pccnrl) ? (lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1) :
(lstrlenW(ICNRL_Remote_Name_PtrW((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1));
#else
ASSERT(lstrlenA(ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN - 1);
#endif
#ifdef UNICODE
{
WCHAR szWideNetName[MAX_PATH];
LPWSTR pszWideNetName;
if (IS_ICNRL_ANSI(pccnrl))
{
pszWideNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszWideNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
}
lstrcpy(pszRemotePathBuf, pszWideNetName);
}
#else
lstrcpy(pszRemotePathBuf, ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl));
#endif
CatPath(pszRemotePathBuf, TEXT("\\"));
return;
}
/*
** ConnectToCNR()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL ConnectToCNR(PCCNRLINK pccnrl, DWORD dwInFlags,
HWND hwndOwner, LPTSTR pszRootPathBuf,
PDWORD pdwOutFlags)
{
BOOL bResult = FALSE;
BOOL bValidDevice;
BOOL bRedirect;
BOOL bTryLastDevice = FALSE;
DWORD dwcbRootPathBufLen;
LPTSTR pszNetName;
LPTSTR pszDevice;
#ifdef UNICODE
WCHAR szWideNetName[MAX_PATH];
WCHAR szWideDevice[MAX_PATH];
#endif
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_CONNECT_IN_FLAGS));
ASSERT(IS_FLAG_CLEAR(dwInFlags, CONNECT_INTERACTIVE) ||
IS_VALID_HANDLE(hwndOwner, WND));
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszRootPathBuf, STR, MAX_PATH_LEN));
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
*pdwOutFlags = 0;
#ifdef UNICODE
if (IS_ICNRL_ANSI(pccnrl))
{
pszNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
}
#else
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
#endif
/* Do we have an old redirected device to try? */
bValidDevice = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
ICNRL_FL_VALID_DEVICE);
#ifdef UNICODE
if ( bValidDevice )
{
if (IS_ICNRL_ANSI(pccnrl))
{
pszDevice = szWideDevice;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Device_PtrA((PCICNRLINK)pccnrl), -1,
szWideDevice, MAX_PATH);
}
else
{
pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
}
}
#else
pszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
#endif
bRedirect = (bValidDevice || IS_FLAG_SET(dwInFlags, CONNECT_REDIRECT));
if (bRedirect)
{
if (bValidDevice)
{
DWORD dwNetResult;
/* "X:" + null terminator */
TCHAR rgchDrive[2 + 1];
/* Yes. Is it already connected to the desired CNR? */
TRACE_OUT((TEXT("ConnectToCNR(): Calling WNetGetConnection() to check %s for CNR \"%s\"."),
pszDevice, pszNetName));
dwcbRootPathBufLen = MAX_PATH_LEN;
/* WNetGetConnection requires the device name to have no trailing
** backslash.
*/
MyLStrCpyN(rgchDrive, pszDevice, ARRAYSIZE(rgchDrive));
dwNetResult = WNetGetConnection(rgchDrive, pszRootPathBuf, &dwcbRootPathBufLen);
if (dwNetResult == WN_SUCCESS)
{
if (CompareNetNames(pszNetName, pszRootPathBuf)
== CR_EQUAL)
{
TRACE_OUT((TEXT("ConnectToCNR(): Found matching CNR \"%s\" on %s."),
pszRootPathBuf,
pszDevice));
ASSERT(lstrlenA(ICNRL_Device_PtrA((PCICNRLINK)pccnrl)) < MAX_PATH_LEN);
lstrcpy(pszRootPathBuf, pszDevice);
bResult = TRUE;
}
else
TRACE_OUT((TEXT("ConnectToCNR(): Found unmatched CNR \"%s\" on %s."),
pszRootPathBuf,
pszDevice));
}
else
{
TRACE_OUT((TEXT("ConnectToCNR(): WNetGetConnection() failed on %s."),
pszDevice));
/*
* Only attempt a connection to the last redirected device if that
* device is not already in use.
*/
bTryLastDevice = (GetDriveType(pszDevice)
== DRIVE_NO_ROOT_DIR);
}
}
if (! bResult)
/* See if the desired CNR is connected to any local device. */
bResult = SearchForRedirectedConnection((PCICNRLINK)pccnrl,
pszRootPathBuf);
/*
* Assume that no reference count is maintained for redirected device
* connections, so we do not have to add a found redirected device
* connection again.
*/
}
if (! bResult)
{
NETRESOURCE nr;
TCHAR rgchNPName[MAX_PATH_LEN];
/* RAIDRAID: (15691) We only support disk resource connections here. */
ZeroMemory(&nr, SIZEOF(nr));
nr.lpRemoteName = pszNetName;
nr.dwType = RESOURCETYPE_DISK;
if (GetNetProviderName((PCICNRLINK)pccnrl, rgchNPName))
nr.lpProvider = rgchNPName;
/* Shall we try the old device? */
if (bTryLastDevice)
{
/* Yes. */
ASSERT(bValidDevice);
nr.lpLocalName = pszDevice;
WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to attempt to connect %s to CNR \"%s\"."),
nr.lpLocalName,
nr.lpRemoteName));
}
else
{
/* No. Shall we attempt to force a redirected connection? */
if (bValidDevice)
{
/*
* Yes. N.b., the caller may already have set CONNECT_REDIRECT in
* dwInFlags here.
*/
SET_FLAG(dwInFlags, CONNECT_REDIRECT);
WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish auto-picked redirected connection to CNR \"%s\"."),
nr.lpRemoteName));
}
else
/* No. */
WARNING_OUT((TEXT("ConnectToCNR(): Calling WNetUseConnection() to establish connection to CNR \"%s\"."),
TEXT("<nr.lpRemoteName>"))); // nr.lpRemoteName));
ASSERT(! nr.lpLocalName);
}
dwcbRootPathBufLen = MAX_PATH_LEN;
bResult = (WNetUseConnection(hwndOwner, &nr, NULL, NULL, dwInFlags,
pszRootPathBuf, &dwcbRootPathBufLen,
pdwOutFlags)
== NO_ERROR);
}
if (bResult)
CatPath(pszRootPathBuf, TEXT("\\"));
ASSERT(! bResult ||
(IS_VALID_STRING_PTR(pszRootPathBuf, STR) &&
FLAGS_ARE_VALID(*pdwOutFlags, ALL_CONNECT_OUT_FLAGS)));
return(bResult);
}
/*
** DisconnectFromCNR()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL DisconnectFromCNR(PCCNRLINK pccnrl)
{
DWORD dwNetResult;
LPTSTR pszNetName;
#ifdef UNICODE
WCHAR szWideNetName[MAX_PATH];
#endif
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
#ifdef UNICODE
if (IS_ICNRL_ANSI(pccnrl))
{
pszNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
}
#else
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
#endif
dwNetResult = WNetCancelConnection2(pszNetName,
CONNECT_REFCOUNT, FALSE);
if (dwNetResult == NO_ERROR)
WARNING_OUT((TEXT("DisconnectFromCNR(): Reduced connection reference count on CNR \"%s\"."),
pszNetName));
else
WARNING_OUT((TEXT("DisconnectFromCNR(): Failed to reduce connection reference count on CNR \"%s\". WNetCancelConnection2() returned %lu."),
pszNetName));
return(dwNetResult == NO_ERROR);
}
/*
** IsCNRAvailable()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL IsCNRAvailable(PCCNRLINK pccnrl)
{
TCHAR rgchCNRRoot[MAX_PATH_LEN];
LPTSTR pszNetName;
#ifdef UNICODE
WCHAR szWideNetName[MAX_PATH];
#endif
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
#ifdef UNICODE
if (IS_ICNRL_ANSI(pccnrl))
{
pszNetName = szWideNetName;
MultiByteToWideChar(CP_ACP, 0,
ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl), -1,
szWideNetName, MAX_PATH);
}
else
{
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
}
#else
pszNetName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
#endif
ASSERT(lstrlen(pszNetName) < ARRAYSIZE(rgchCNRRoot) - 1);
lstrcpy(rgchCNRRoot, pszNetName);
CatPath(rgchCNRRoot, TEXT("\\"));
return(PathExists(rgchCNRRoot));
}
/*
** GetCNRLinkLen()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE UINT GetCNRLinkLen(PCCNRLINK pccnrl)
{
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
return(((PCICNRLINK)pccnrl)->ucbSize);
}
/*
** GetCNRNetType()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetCNRNetType(PCCNRLINK pccnrl, PCDWORD *ppcdwNetType)
{
BOOL bResult;
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags,
ICNRL_FL_VALID_NET_TYPE);
if (bResult)
*ppcdwNetType = &(((PCICNRLINK)pccnrl)->dwNetType);
ASSERT(! bResult ||
IsValidNetType(**ppcdwNetType));
return(bResult);
}
/*
** GetCNRName()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetCNRName(PCCNRLINK pccnrl, LPCSTR *ppcszCNRName)
{
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
*ppcszCNRName = ICNRL_Remote_Name_PtrA((PCICNRLINK)pccnrl);
ASSERT(IS_VALID_STRING_PTRA(*ppcszCNRName, CSTR));
return(TRUE);
}
#ifdef UNICODE
/*
** GetCNRNameW()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetCNRNameW(PCCNRLINK pccnrl, LPCWSTR *ppcszCNRName)
{
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
if (IS_ICNRL_ANSI(pccnrl))
*ppcszCNRName = NULL;
else
{
*ppcszCNRName = ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl);
ASSERT(IS_VALID_STRING_PTR(*ppcszCNRName, CSTR));
}
return(TRUE);
}
#endif
/*
** GetLastRedirectedDevice()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetLastRedirectedDevice(PCCNRLINK pccnrl, LPCSTR *ppcszDevice)
{
BOOL bResult;
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE);
if (bResult)
*ppcszDevice = ICNRL_Device_PtrA((PCICNRLINK)pccnrl);
ASSERT(! bResult ||
IS_VALID_STRING_PTRA(*ppcszDevice, CSTR));
return(bResult);
}
#ifdef UNICODE
/*
** GetLastRedirectedDeviceW()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL GetLastRedirectedDeviceW(PCCNRLINK pccnrl, LPCWSTR *ppcszDevice)
{
BOOL bResult;
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
bResult = IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE);
if (bResult)
if (IS_ICNRL_ANSI(pccnrl))
*ppcszDevice = NULL;
else
{
*ppcszDevice = ICNRL_Device_Ptr((PCICNRLINK)pccnrl);
ASSERT(! bResult ||
IS_VALID_STRING_PTR(*ppcszDevice, CSTR));
}
return(bResult);
}
#endif
#if defined(DEBUG) || defined (VSTF)
/*
** IsValidPCCNRLINK()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL IsValidPCCNRLINK(PCCNRLINK pccnrl)
{
return(IS_VALID_STRUCT_PTR((PCICNRLINK)pccnrl, CICNRLINK));
}
#endif
#ifdef DEBUG
/*
** DumpCNRLink()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void DumpCNRLink(PCCNRLINK pccnrl)
{
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] ucbSize %#x"),
INDENT_STRING,
INDENT_STRING,
((PCICNRLINK)pccnrl)->ucbSize));
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] dwFLags = %#08lx"),
INDENT_STRING,
INDENT_STRING,
((PCICNRLINK)pccnrl)->dwFlags));
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] CNR name \"%s\""),
INDENT_STRING,
INDENT_STRING,
ICNRL_Remote_Name_Ptr((PCICNRLINK)pccnrl)));
if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_NET_TYPE))
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type %#08lx"),
INDENT_STRING,
INDENT_STRING,
((PCICNRLINK)pccnrl)->dwNetType));
else
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] net type unknown"),
INDENT_STRING,
INDENT_STRING));
if (IS_FLAG_SET(((PCICNRLINK)pccnrl)->dwFlags, ICNRL_FL_VALID_DEVICE))
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] last redirected local device \"%s\""),
INDENT_STRING,
INDENT_STRING,
ICNRL_Device_Ptr((PCICNRLINK)pccnrl)));
else
PLAIN_TRACE_OUT((TEXT("%s%s[CNR link] no last redirected local device"),
INDENT_STRING,
INDENT_STRING));
return;
}
#endif