2826 lines
78 KiB
C
2826 lines
78 KiB
C
/*
|
|
* linkinfo.c - LinkInfo ADT module.
|
|
*/
|
|
|
|
|
|
/* Headers
|
|
**********/
|
|
|
|
#include "project.h"
|
|
#pragma hdrstop
|
|
|
|
#include "volumeid.h"
|
|
#include "cnrlink.h"
|
|
#include <uastrfnc.h> // for ALIGNMENT_MACHINE
|
|
|
|
|
|
/* Macros
|
|
*********/
|
|
|
|
/* macros for accessing ILINKINFO data */
|
|
|
|
#define ILI_Volume_ID_Ptr(pili) \
|
|
((PVOLUMEID)(((PBYTE)(pili)) + (pili)->ucbVolumeIDOffset))
|
|
|
|
#define ILI_Local_Base_Path_PtrA(pili) \
|
|
((LPSTR)(((PBYTE)(pili)) + (pili)->ucbLocalBasePathOffset))
|
|
|
|
#define ILI_CNR_Link_Ptr(pili) \
|
|
((PCNRLINK)(((PBYTE)(pili)) + (pili)->ucbCNRLinkOffset))
|
|
|
|
#define ILI_Common_Path_Suffix_PtrA(pili) \
|
|
((LPSTR)(((PBYTE)(pili)) + (pili)->ucbCommonPathSuffixOffset))
|
|
|
|
#define ILI_Local_Base_Path_PtrW(pili) \
|
|
((LPWSTR)(((PBYTE)(pili)) + (pili)->ucbLocalBasePathOffsetW))
|
|
|
|
#define ILI_Common_Path_Suffix_PtrW(pili) \
|
|
((LPWSTR)(((PBYTE)(pili)) + (pili)->ucbCommonPathSuffixOffsetW))
|
|
|
|
#ifdef UNICODE
|
|
#define ILI_Local_Base_Path_Ptr(pili) ILI_Local_Base_Path_PtrW(pili)
|
|
#define ILI_Common_Path_Suffix_Ptr(pili) ILI_Common_Path_Suffix_PtrW(pili)
|
|
#else
|
|
#define ILI_Local_Base_Path_Ptr(pili) ILI_Local_Base_Path_PtrA(pili)
|
|
#define ILI_Common_Path_Suffix_Ptr(pili) ILI_Common_Path_Suffix_PtrA(pili)
|
|
#endif
|
|
|
|
/* Types
|
|
********/
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@struct LINKINFO | External definition of LinkInfo structure.
|
|
|
|
@field UINT | ucbSize | The size of the LINKINFO structure in bytes, including
|
|
the ucbSize field. An ILINKINFO structure consists of a header described as
|
|
below, followed by variable-length data that is opaque to the caller.
|
|
|
|
******************************************************************************/
|
|
|
|
/*
|
|
@doc INTERNAL
|
|
|
|
@enum ILINKINFOFLAGS | Internal LinkInfo structure flags.
|
|
*/
|
|
|
|
typedef enum _ilinkinfoflags
|
|
{
|
|
/*
|
|
@emem ILI_FL_LOCAL_INFO_VALID | If set, volume ID and local path are
|
|
valid. If clear, volume ID and local path are not valid.
|
|
*/
|
|
|
|
ILI_FL_LOCAL_INFO_VALID = 0x0001,
|
|
|
|
/*
|
|
@emem ILI_FL_REMOTE_INFO_VALID | If set, CNRLink and path suffix are
|
|
valid. If clear, CNRLink and path suffix not valid.
|
|
*/
|
|
|
|
ILI_FL_REMOTE_INFO_VALID = 0x0002,
|
|
|
|
/* @emem ALL_ILINKINFO_FLAGS | All internal LinkInfo structure flags. */
|
|
|
|
ALL_ILINKINFO_FLAGS = (ILI_FL_LOCAL_INFO_VALID |\
|
|
ILI_FL_REMOTE_INFO_VALID)
|
|
}
|
|
ILINKINFOFLAGS;
|
|
|
|
/*
|
|
@doc INTERNAL
|
|
|
|
@struct ILINKINFO | Internal definition of relocatable, extensible, internal
|
|
LinkInfo structure. An ILINKINFO structure may contain an <t IVOLUMEID>
|
|
structure and an <t ICNRLINK> structure. An ILINKINFO structure consists of
|
|
a header described as below, followed by variable-length data.
|
|
*/
|
|
|
|
typedef struct _ilinkinfoA
|
|
{
|
|
/* @field LINKINFO | li | External <t LINKINFO> sub-structure. */
|
|
|
|
LINKINFO li;
|
|
|
|
/*
|
|
@field UINT | ucbHeaderSize | Size of the ILINKINFO header structure in
|
|
bytes.
|
|
*/
|
|
|
|
UINT ucbHeaderSize;
|
|
|
|
/*
|
|
@field DWORD | dwFlags | A bit mask of flags from the <t ILINKINFOFLAGS>
|
|
enumeration.
|
|
*/
|
|
|
|
DWORD dwFlags;
|
|
|
|
/*
|
|
@field UINT | ucbVolumeIDOffset | Offset in bytes of <t IVOLUMEID>
|
|
sub-structure from base of structure.
|
|
*/
|
|
|
|
UINT ucbVolumeIDOffset;
|
|
|
|
/*
|
|
@field UINT | ucbLocalBasePathOffset | Offset in bytes of local base path
|
|
string from base of structure. The local base path is a valid file
|
|
system path. The local base path string + the common path suffix string
|
|
form the local path string, which is a valid file system path. The local
|
|
base path string refers to the same resource as the CNRLink's CNR name
|
|
string.<nl>
|
|
|
|
Example local base path string: "c:\\work".<nl>
|
|
E.g., if local path "c:\\work" is shared as "\\\\fredbird\\work", an
|
|
ILinkInfo structure would break local path
|
|
"c:\\work\\footwear\\sneakers.doc" up into local base path "c:\\work",
|
|
CNRLink CNR name "\\\\fredbird\\work", and common path suffix
|
|
"footwear\\sneakers.doc".
|
|
*/
|
|
|
|
UINT ucbLocalBasePathOffset;
|
|
|
|
/*
|
|
@field UINT | ucbCNRLinkOffset | Offset in bytes of <t CNRLINK>
|
|
sub-structure from base of structure. The file system name of the
|
|
CNRLink's CNR name + the common path suffix string form the remote path
|
|
string, which is a valid file system path. The CNRLink's CNR name string
|
|
refers to the same resource as the local base path string.
|
|
*/
|
|
|
|
UINT ucbCNRLinkOffset;
|
|
|
|
/*
|
|
@field UINT | ucbCommonPathSuffixOffset | Offset in bytes of common path
|
|
suffix string from base of structure.<nl> Example common path suffix
|
|
string: "footwear\\sneakers.doc".
|
|
*/
|
|
|
|
UINT ucbCommonPathSuffixOffset;
|
|
}
|
|
ILINKINFOA;
|
|
DECLARE_STANDARD_TYPES(ILINKINFOA);
|
|
|
|
#ifdef UNICODE
|
|
typedef struct _ilinkinfoW
|
|
{
|
|
/* @field LINKINFO | li | External <t LINKINFO> sub-structure. */
|
|
|
|
LINKINFO li;
|
|
|
|
/*
|
|
@field UINT | ucbHeaderSize | Size of the ILINKINFO header structure in
|
|
bytes.
|
|
*/
|
|
|
|
UINT ucbHeaderSize;
|
|
|
|
/*
|
|
@field DWORD | dwFlags | A bit mask of flags from the <t ILINKINFOFLAGS>
|
|
enumeration.
|
|
*/
|
|
|
|
DWORD dwFlags;
|
|
|
|
/*
|
|
@field UINT | ucbVolumeIDOffset | Offset in bytes of <t IVOLUMEID>
|
|
sub-structure from base of structure.
|
|
*/
|
|
|
|
UINT ucbVolumeIDOffset;
|
|
|
|
/*
|
|
@field UINT | ucbLocalBasePathOffset | Offset in bytes of local base path
|
|
string from base of structure. The local base path is a valid file
|
|
system path. The local base path string + the common path suffix string
|
|
form the local path string, which is a valid file system path. The local
|
|
base path string refers to the same resource as the CNRLink's CNR name
|
|
string.<nl>
|
|
|
|
Example local base path string: "c:\\work".<nl>
|
|
E.g., if local path "c:\\work" is shared as "\\\\fredbird\\work", an
|
|
ILinkInfo structure would break local path
|
|
"c:\\work\\footwear\\sneakers.doc" up into local base path "c:\\work",
|
|
CNRLink CNR name "\\\\fredbird\\work", and common path suffix
|
|
"footwear\\sneakers.doc".
|
|
*/
|
|
|
|
UINT ucbLocalBasePathOffset;
|
|
|
|
/*
|
|
@field UINT | ucbCNRLinkOffset | Offset in bytes of <t CNRLINK>
|
|
sub-structure from base of structure. The file system name of the
|
|
CNRLink's CNR name + the common path suffix string form the remote path
|
|
string, which is a valid file system path. The CNRLink's CNR name string
|
|
refers to the same resource as the local base path string.
|
|
*/
|
|
|
|
UINT ucbCNRLinkOffset;
|
|
|
|
/*
|
|
@field UINT | ucbCommonPathSuffixOffset | Offset in bytes of common path
|
|
suffix string from base of structure.<nl> Example common path suffix
|
|
string: "footwear\\sneakers.doc".
|
|
*/
|
|
|
|
UINT ucbCommonPathSuffixOffset;
|
|
|
|
/*
|
|
These fields duplicate the above ones except that they are for the unicode
|
|
versions of the strings.
|
|
*/
|
|
UINT ucbLocalBasePathOffsetW;
|
|
UINT ucbCommonPathSuffixOffsetW;
|
|
|
|
}
|
|
ILINKINFOW;
|
|
DECLARE_STANDARD_TYPES(ILINKINFOW);
|
|
|
|
#endif
|
|
|
|
#ifdef UNICODE
|
|
#define ILINKINFO ILINKINFOW
|
|
#define PILINKINFO PILINKINFOW
|
|
#define CILINKINFO CILINKINFOW
|
|
#define PCILINKINFO PCILINKINFOW
|
|
#else
|
|
#define ILINKINFO ILINKINFOA
|
|
#define PILINKINFO PILINKINFOA
|
|
#define CILINKINFO CILINKINFOA
|
|
#define PCILINKINFO PCILINKINFOA
|
|
#endif
|
|
|
|
|
|
/***************************** Private Functions *****************************/
|
|
|
|
/* Module Prototypes
|
|
********************/
|
|
|
|
PRIVATE_CODE BOOL CreateILinkInfo(LPCTSTR, PILINKINFO *);
|
|
PRIVATE_CODE BOOL CreateLocalILinkInfo(LPCTSTR, PILINKINFO *);
|
|
PRIVATE_CODE BOOL CreateRemoteILinkInfo(LPCTSTR, LPCTSTR, LPCTSTR, PILINKINFO *);
|
|
PRIVATE_CODE BOOL UnifyILinkInfo(PCVOLUMEID, UINT, LPCTSTR, PCCNRLINK, UINT, LPCTSTR, PILINKINFO *);
|
|
PRIVATE_CODE void DestroyILinkInfo(PILINKINFO);
|
|
PRIVATE_CODE BOOL UpdateILinkInfo(PCILINKINFO, LPCTSTR, PDWORD, PILINKINFO *);
|
|
PRIVATE_CODE BOOL UseNewILinkInfo(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE BOOL ResolveLocalILinkInfo(PCILINKINFO, LPTSTR, DWORD);
|
|
PRIVATE_CODE BOOL ResolveRemoteILinkInfo(PCILINKINFO, LPTSTR, DWORD, HWND, PDWORD);
|
|
PRIVATE_CODE BOOL ResolveILinkInfo(PCILINKINFO, LPTSTR, DWORD, HWND, PDWORD);
|
|
PRIVATE_CODE BOOL ResolveLocalPathFromServer(PCILINKINFO, LPTSTR, PDWORD);
|
|
PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO, LPTSTR);
|
|
PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO, LPTSTR);
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoReferents(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoLocalData(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE COMPARISONRESULT CompareLocalPaths(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoRemoteData(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoVolumes(PCILINKINFO, PCILINKINFO);
|
|
PRIVATE_CODE BOOL CheckCombinedPathLen(LPCTSTR, LPCTSTR);
|
|
PRIVATE_CODE BOOL GetILinkInfoData(PCILINKINFO, LINKINFODATATYPE, PCVOID *);
|
|
PRIVATE_CODE BOOL DisconnectILinkInfo(PCILINKINFO);
|
|
|
|
#if defined(DEBUG) || defined(EXPV)
|
|
|
|
PRIVATE_CODE BOOL IsValidLINKINFODATATYPE(LINKINFODATATYPE);
|
|
|
|
#endif
|
|
|
|
#if defined(DEBUG) || defined(VSTF)
|
|
|
|
PRIVATE_CODE BOOL CheckILIFlags(PCILINKINFO);
|
|
PRIVATE_CODE BOOL CheckILICommonPathSuffix(PCILINKINFO);
|
|
PRIVATE_CODE BOOL CheckILILocalInfo(PCILINKINFO);
|
|
PRIVATE_CODE BOOL CheckILIRemoteInfo(PCILINKINFO);
|
|
PRIVATE_CODE BOOL IsValidPCLINKINFO(PCLINKINFO);
|
|
PRIVATE_CODE BOOL IsValidPCILINKINFO(PCILINKINFO);
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRIVATE_CODE void DumpILinkInfo(PCILINKINFO);
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
** CreateILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CreateILinkInfo(LPCTSTR pcszPath, PILINKINFO *ppili)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
TCHAR rgchCanonicalPath[MAX_PATH_LEN];
|
|
DWORD dwCanonicalPathFlags;
|
|
TCHAR rgchCNRName[MAX_PATH_LEN];
|
|
LPTSTR pszRootPathSuffix;
|
|
|
|
ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
|
|
|
|
if (GetCanonicalPathInfo(pcszPath, rgchCanonicalPath, &dwCanonicalPathFlags,
|
|
rgchCNRName, &pszRootPathSuffix))
|
|
{
|
|
if (IS_FLAG_SET(dwCanonicalPathFlags, GCPI_OFL_REMOTE))
|
|
bResult = CreateRemoteILinkInfo(rgchCanonicalPath, rgchCNRName,
|
|
pszRootPathSuffix, ppili);
|
|
else
|
|
bResult = CreateLocalILinkInfo(rgchCanonicalPath, ppili);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** CreateLocalILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CreateLocalILinkInfo(LPCTSTR pcszLocalPath, PILINKINFO *ppili)
|
|
{
|
|
BOOL bResult;
|
|
PVOLUMEID pvolid;
|
|
UINT ucbVolumeIDLen;
|
|
|
|
ASSERT(IsLocalDrivePath(pcszLocalPath));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
|
|
|
|
bResult = CreateVolumeID(pcszLocalPath, &pvolid, &ucbVolumeIDLen);
|
|
|
|
if (bResult)
|
|
{
|
|
PCNRLINK pcnrl;
|
|
UINT ucbCNRLinkLen;
|
|
TCHAR rgchLocalBasePath[MAX_PATH_LEN];
|
|
LPCTSTR pcszCommonPathSuffix;
|
|
|
|
bResult = CreateLocalCNRLink(pcszLocalPath, &pcnrl, &ucbCNRLinkLen,
|
|
rgchLocalBasePath, &pcszCommonPathSuffix);
|
|
|
|
if (bResult)
|
|
{
|
|
/* Wrap them up. */
|
|
|
|
bResult = UnifyILinkInfo(pvolid, ucbVolumeIDLen, rgchLocalBasePath,
|
|
pcnrl, ucbCNRLinkLen, pcszCommonPathSuffix,
|
|
ppili);
|
|
|
|
if (ucbCNRLinkLen > 0)
|
|
DestroyCNRLink(pcnrl);
|
|
}
|
|
|
|
if (ucbVolumeIDLen > 0)
|
|
DestroyVolumeID(pvolid);
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** CreateRemoteILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CreateRemoteILinkInfo(LPCTSTR pcszRemotePath,
|
|
LPCTSTR pcszCNRName,
|
|
LPCTSTR pcszRootPathSuffix,
|
|
PILINKINFO *ppili)
|
|
{
|
|
BOOL bResult;
|
|
PCNRLINK pcnrl;
|
|
UINT ucbCNRLinkLen;
|
|
|
|
ASSERT(IsCanonicalPath(pcszRemotePath));
|
|
ASSERT(IsValidCNRName(pcszCNRName));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszRootPathSuffix, CSTR));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
|
|
|
|
bResult = CreateRemoteCNRLink(pcszRemotePath, pcszCNRName, &pcnrl,
|
|
&ucbCNRLinkLen);
|
|
|
|
if (bResult)
|
|
{
|
|
/* Wrap it up. */
|
|
|
|
bResult = UnifyILinkInfo(NULL, 0, EMPTY_STRING, pcnrl, ucbCNRLinkLen,
|
|
pcszRootPathSuffix, ppili);
|
|
|
|
if (EVAL(ucbCNRLinkLen > 0))
|
|
DestroyCNRLink(pcnrl);
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** UnifyILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL UnifyILinkInfo(PCVOLUMEID pcvolid, UINT ucbVolumeIDLen,
|
|
LPCTSTR pcszLocalBasePath, PCCNRLINK pccnrl,
|
|
UINT ucbCNRLinkLen, LPCTSTR pcszCommonPathSuffix,
|
|
PILINKINFO *ppili)
|
|
{
|
|
BOOL bResult;
|
|
UINT ucbILinkInfoLen;
|
|
UINT ucbDataOffset;
|
|
UINT cbAnsiLocalBasePath;
|
|
UINT cbAnsiCommonPathSuffix;
|
|
#ifdef UNICODE
|
|
BOOL bUnicode;
|
|
UINT cchChars;
|
|
CHAR szAnsiLocalBasePath[MAX_PATH*2];
|
|
CHAR szAnsiCommonPathSuffix[MAX_PATH*2];
|
|
UINT cbWideLocalBasePath;
|
|
UINT cbWideCommonPathSuffix;
|
|
UINT cbChars;
|
|
#endif
|
|
|
|
ASSERT(! ucbVolumeIDLen ||
|
|
(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID) &&
|
|
IsDrivePath(pcszLocalBasePath)));
|
|
ASSERT(! ucbCNRLinkLen ||
|
|
IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppili, PILINKINFO));
|
|
|
|
#ifdef UNICODE
|
|
bUnicode = FALSE;
|
|
|
|
/*
|
|
** Convert the common-path string from UNICODE->ansi and back again
|
|
** to determine if the string contains any non-ansi characters. If no
|
|
** characters are lost in the conversion then the string contains only
|
|
** ansi chars.
|
|
*/
|
|
cbAnsiCommonPathSuffix = WideCharToMultiByte(CP_ACP, 0,
|
|
pcszCommonPathSuffix, -1,
|
|
szAnsiCommonPathSuffix, ARRAYSIZE(szAnsiCommonPathSuffix),
|
|
0, 0);
|
|
if ( cbAnsiCommonPathSuffix == 0 )
|
|
{
|
|
bUnicode = FALSE;
|
|
}
|
|
else
|
|
{
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
|
|
cbChars = MultiByteToWideChar(CP_ACP, 0,
|
|
szAnsiCommonPathSuffix, -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
if ( cbChars == 0 || lstrcmp(pcszCommonPathSuffix,szWideCommonPathSuffix) != 0 )
|
|
{
|
|
bUnicode = TRUE;
|
|
}
|
|
}
|
|
|
|
if (ucbVolumeIDLen > 0)
|
|
{
|
|
/*
|
|
** Convert the localbase-path string from UNICODE->ansi and back again
|
|
** to determine if the string contains any non-ansi characters. If no
|
|
** characters are lost in the conversion then the string contains only
|
|
** ansi chars.
|
|
*/
|
|
cbAnsiLocalBasePath = WideCharToMultiByte(CP_ACP, 0,
|
|
pcszLocalBasePath, -1,
|
|
szAnsiLocalBasePath, MAX_PATH*2,
|
|
0, 0);
|
|
if ( cbAnsiLocalBasePath == 0 )
|
|
{
|
|
bUnicode = FALSE;
|
|
}
|
|
else
|
|
{
|
|
WCHAR szWideLocalBasePath[MAX_PATH];
|
|
|
|
cchChars = MultiByteToWideChar(CP_ACP, 0,
|
|
szAnsiLocalBasePath, -1,
|
|
szWideLocalBasePath, ARRAYSIZE(szWideLocalBasePath));
|
|
if ( cchChars == 0 || lstrcmp(pcszLocalBasePath,szWideLocalBasePath) != 0 )
|
|
{
|
|
bUnicode = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cbAnsiLocalBasePath = 0;
|
|
}
|
|
|
|
if ( bUnicode )
|
|
{
|
|
ucbDataOffset = SIZEOF(ILINKINFOW);
|
|
|
|
/* (+ 1) for null terminator. */
|
|
cbWideCommonPathSuffix = (lstrlen(pcszCommonPathSuffix) + 1) * sizeof(TCHAR);
|
|
|
|
if (ucbVolumeIDLen > 0)
|
|
cbWideLocalBasePath = (lstrlen(pcszLocalBasePath) + 1) * sizeof(TCHAR);
|
|
else
|
|
cbWideLocalBasePath = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
ucbDataOffset = SIZEOF(ILINKINFOA);
|
|
|
|
cbWideCommonPathSuffix = 0;
|
|
cbWideLocalBasePath = 0;
|
|
}
|
|
|
|
ucbILinkInfoLen = ucbDataOffset +
|
|
ucbVolumeIDLen +
|
|
cbAnsiLocalBasePath;
|
|
if ( bUnicode && ucbVolumeIDLen > 0 )
|
|
{
|
|
ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
|
|
ucbILinkInfoLen += cbWideLocalBasePath;
|
|
}
|
|
if ( ucbCNRLinkLen > 0 )
|
|
{
|
|
ucbILinkInfoLen = ALIGN_DWORD_CNT(ucbILinkInfoLen);
|
|
ucbILinkInfoLen += ucbCNRLinkLen;
|
|
}
|
|
ucbILinkInfoLen += cbAnsiCommonPathSuffix;
|
|
if ( bUnicode )
|
|
{
|
|
ucbILinkInfoLen = ALIGN_WORD_CNT(ucbILinkInfoLen);
|
|
ucbILinkInfoLen += cbWideCommonPathSuffix;
|
|
}
|
|
|
|
#else
|
|
|
|
/* Calculate total length. */
|
|
|
|
/* Assume we don't overflow ucbILinkInfoLen here. */
|
|
|
|
/*
|
|
* Base structure size plus common path suffix length. (+ 1) for null
|
|
* terminator.
|
|
*/
|
|
cbAnsiCommonPathSuffix = lstrlen(pcszCommonPathSuffix) + 1;
|
|
|
|
ucbILinkInfoLen = SIZEOF(**ppili) +
|
|
cbAnsiCommonPathSuffix;
|
|
|
|
/* Plus size of local information. */
|
|
|
|
if (ucbVolumeIDLen > 0)
|
|
{
|
|
/* (+ 1) for null terminator. */
|
|
cbAnsiLocalBasePath = lstrlen(pcszLocalBasePath) + 1;
|
|
|
|
ucbILinkInfoLen += ucbVolumeIDLen +
|
|
cbAnsiLocalBasePath;
|
|
}
|
|
|
|
/* Plus size of remote information. */
|
|
|
|
if (ucbCNRLinkLen > 0)
|
|
/* (+ 1) for null terminator. */
|
|
ucbILinkInfoLen += ucbCNRLinkLen;
|
|
|
|
ucbDataOffset = SIZEOF(**ppili);
|
|
#endif
|
|
|
|
/* Try to allocate a container. */
|
|
|
|
bResult = AllocateMemory(ucbILinkInfoLen, ppili);
|
|
|
|
if (bResult)
|
|
{
|
|
(*ppili)->li.ucbSize = ucbILinkInfoLen;
|
|
|
|
(*ppili)->ucbHeaderSize = ucbDataOffset;
|
|
(*ppili)->dwFlags = 0;
|
|
|
|
/* Do we have local information? */
|
|
|
|
if (ucbVolumeIDLen > 0)
|
|
{
|
|
/* Yes. Add it to the structure. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcvolid, CVOLUMEID));
|
|
ASSERT(IsDrivePath(pcszLocalBasePath));
|
|
|
|
/* Append local volume ID. */
|
|
|
|
(*ppili)->ucbVolumeIDOffset = ucbDataOffset;
|
|
CopyMemory(ILI_Volume_ID_Ptr(*ppili), pcvolid, ucbVolumeIDLen);
|
|
ucbDataOffset += ucbVolumeIDLen;
|
|
|
|
/* Append local path. */
|
|
|
|
(*ppili)->ucbLocalBasePathOffset = ucbDataOffset;
|
|
#ifdef UNICODE
|
|
lstrcpyA(ILI_Local_Base_Path_PtrA(*ppili), szAnsiLocalBasePath);
|
|
ucbDataOffset += cbAnsiLocalBasePath;
|
|
|
|
if ( bUnicode )
|
|
{
|
|
ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
|
|
(*ppili)->ucbLocalBasePathOffsetW = ucbDataOffset;
|
|
lstrcpy(ILI_Local_Base_Path_PtrW(*ppili), pcszLocalBasePath);
|
|
ucbDataOffset += cbWideLocalBasePath;
|
|
}
|
|
#else
|
|
lstrcpy(ILI_Local_Base_Path_Ptr(*ppili), pcszLocalBasePath);
|
|
ucbDataOffset += cbAnsiLocalBasePath;
|
|
#endif
|
|
SET_FLAG((*ppili)->dwFlags, ILI_FL_LOCAL_INFO_VALID);
|
|
}
|
|
|
|
/* Do we have remote information? */
|
|
|
|
if (ucbCNRLinkLen > 0)
|
|
{
|
|
ucbDataOffset = ALIGN_DWORD_CNT(ucbDataOffset);
|
|
|
|
/* Yes. Add it to the structure. */
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pccnrl, CCNRLINK));
|
|
|
|
/* Append CNR link. */
|
|
|
|
(*ppili)->ucbCNRLinkOffset = ucbDataOffset;
|
|
CopyMemory(ILI_CNR_Link_Ptr(*ppili), pccnrl, ucbCNRLinkLen);
|
|
ucbDataOffset += ucbCNRLinkLen;
|
|
|
|
SET_FLAG((*ppili)->dwFlags, ILI_FL_REMOTE_INFO_VALID);
|
|
}
|
|
|
|
/* Append common path suffix. */
|
|
|
|
ASSERT(IS_VALID_STRING_PTR(pcszCommonPathSuffix, CSTR));
|
|
|
|
(*ppili)->ucbCommonPathSuffixOffset = ucbDataOffset;
|
|
#ifdef UNICODE
|
|
lstrcpyA(ILI_Common_Path_Suffix_PtrA(*ppili), szAnsiCommonPathSuffix);
|
|
ucbDataOffset += cbAnsiCommonPathSuffix;
|
|
if ( bUnicode )
|
|
{
|
|
ucbDataOffset = ALIGN_WORD_CNT(ucbDataOffset);
|
|
|
|
(*ppili)->ucbCommonPathSuffixOffsetW = ucbDataOffset;
|
|
lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
|
|
ucbDataOffset += cbWideCommonPathSuffix;
|
|
}
|
|
#else /* UNICODE */
|
|
lstrcpy(ILI_Common_Path_Suffix_Ptr(*ppili), pcszCommonPathSuffix);
|
|
#ifdef DEBUG
|
|
/*
|
|
** NOTE: This same increment was present above in the UNICODE section
|
|
** enclosed in an #ifdef DEBUG block.
|
|
** It was causing the assertion below (ucbDataOffset == ucbILinkInfoLen)
|
|
** to fail. I have left stmt instance in the ansi build untouched.
|
|
** If the assertion fails in the ansi build you should
|
|
** try removing this next statement. [brianau - 4/15/99]
|
|
*/
|
|
ucbDataOffset += cbAnsiCommonPathSuffix;
|
|
#endif
|
|
#endif
|
|
|
|
/* Do all the calculated lengths match? */
|
|
|
|
// ASSERT(ucbDataOffset == (*ppili)->li.ucbSize);
|
|
ASSERT(ucbDataOffset == ucbILinkInfoLen);
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
IS_VALID_STRUCT_PTR(*ppili, CILINKINFO));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** DestroyILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void DestroyILinkInfo(PILINKINFO pili)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pili, CILINKINFO));
|
|
|
|
FreeMemory(pili);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** UpdateILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** An ILinkInfo structure is updated in the following cases:
|
|
**
|
|
** local information:
|
|
**
|
|
** 1) the local path has changed
|
|
** 2) remote information is available for the local path
|
|
**
|
|
** remote information:
|
|
**
|
|
** 3) the remote information is local to this machine, and local information
|
|
** is available for the remote path
|
|
*/
|
|
PRIVATE_CODE BOOL UpdateILinkInfo(PCILINKINFO pcili, LPCTSTR pcszResolvedPath,
|
|
PDWORD pdwOutFlags, PILINKINFO *ppiliUpdated)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszResolvedPath, CSTR));
|
|
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppiliUpdated, PILINKINFO));
|
|
|
|
*pdwOutFlags = 0;
|
|
|
|
bResult = CreateILinkInfo(pcszResolvedPath, ppiliUpdated);
|
|
|
|
if (bResult)
|
|
{
|
|
if (UseNewILinkInfo(pcili, *ppiliUpdated))
|
|
{
|
|
SET_FLAG(*pdwOutFlags, RLI_OFL_UPDATED);
|
|
|
|
WARNING_OUT((TEXT("UpdateILinkInfo(): Updating ILinkInfo for path %s."),
|
|
pcszResolvedPath));
|
|
}
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
(IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
|
|
IS_VALID_STRUCT_PTR(*ppiliUpdated, CILINKINFO)));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** UseNewILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns: TRUE if the new ILinkInfo structure contains more or
|
|
** different information than the old ILinkInfo structure.
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL UseNewILinkInfo(PCILINKINFO pciliOld, PCILINKINFO pciliNew)
|
|
{
|
|
BOOL bUpdate = FALSE;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliOld, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliNew, CILINKINFO));
|
|
|
|
/* Does the new ILinkInfo structure contain local information? */
|
|
|
|
if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
{
|
|
/* Yes. Does the old ILinkInfo structure contain local information? */
|
|
|
|
if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
/*
|
|
* Yes. Update the old ILinkInfo structure if local information
|
|
* differs.
|
|
*/
|
|
bUpdate = (CompareILinkInfoLocalData(pciliOld, pciliNew) != CR_EQUAL);
|
|
else
|
|
/* No. Update the old ILinkInfo structure. */
|
|
bUpdate = TRUE;
|
|
}
|
|
else
|
|
/* No. Do not update the old ILinkInfo structure. */
|
|
bUpdate = FALSE;
|
|
|
|
/*
|
|
* Do we already need to update the old ILinkInfo structure based on local
|
|
* information comparison?
|
|
*/
|
|
|
|
if (! bUpdate)
|
|
{
|
|
/* No. Compare remote information. */
|
|
|
|
/* Does the new ILinkInfo structure contain remote information? */
|
|
|
|
if (IS_FLAG_SET(pciliNew->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
{
|
|
/*
|
|
* Yes. Does the old ILinkInfo structure contain remote information?
|
|
*/
|
|
|
|
if (IS_FLAG_SET(pciliOld->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
/*
|
|
* Yes. Update the old ILinkInfo structure if remote information
|
|
* differs.
|
|
*/
|
|
bUpdate = (CompareILinkInfoRemoteData(pciliOld, pciliNew)
|
|
!= CR_EQUAL);
|
|
else
|
|
/* No. Update the old ILinkInfo structure. */
|
|
bUpdate = TRUE;
|
|
}
|
|
}
|
|
|
|
return(bUpdate);
|
|
}
|
|
|
|
|
|
/*
|
|
** ResolveLocalILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL ResolveLocalILinkInfo(PCILINKINFO pcili,
|
|
LPTSTR pszResolvedPathBuf,
|
|
DWORD dwInFlags)
|
|
{
|
|
BOOL bResult;
|
|
DWORD dwLocalSearchFlags;
|
|
TCHAR rgchLocalPath[MAX_PATH_LEN];
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
|
|
|
|
/* Search for local path. */
|
|
|
|
TRACE_OUT((TEXT("ResolveLocalILinkInfo(): Attempting to resolve LinkInfo locally.")));
|
|
|
|
GetLocalPathFromILinkInfo(pcili, rgchLocalPath);
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_LOCAL_SEARCH))
|
|
dwLocalSearchFlags = SFLP_IFL_LOCAL_SEARCH;
|
|
else
|
|
dwLocalSearchFlags = 0;
|
|
|
|
bResult = SearchForLocalPath(ILI_Volume_ID_Ptr(pcili), rgchLocalPath,
|
|
dwLocalSearchFlags, pszResolvedPathBuf);
|
|
|
|
ASSERT(! bResult ||
|
|
EVAL(IsCanonicalPath(pszResolvedPathBuf)));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** ResolveRemoteILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL ResolveRemoteILinkInfo(PCILINKINFO pcili,
|
|
LPTSTR pszResolvedPathBuf,
|
|
DWORD dwInFlags, HWND hwndOwner,
|
|
PDWORD pdwOutFlags)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
|
|
ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
|
|
IS_VALID_HANDLE(hwndOwner, WND));
|
|
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
|
|
|
|
ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_TEMPORARY) ||
|
|
IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT));
|
|
|
|
TRACE_OUT((TEXT("ResolveRemoteILinkInfo(): Attempting to resolve LinkInfo remotely.")));
|
|
|
|
/* Connect if requested. */
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT))
|
|
{
|
|
DWORD dwConnectInFlags;
|
|
DWORD dwConnectOutFlags;
|
|
|
|
dwConnectInFlags = 0;
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_TEMPORARY))
|
|
dwConnectInFlags = CONNECT_TEMPORARY;
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_ALLOW_UI))
|
|
SET_FLAG(dwConnectInFlags, CONNECT_INTERACTIVE);
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_REDIRECT))
|
|
SET_FLAG(dwConnectInFlags, CONNECT_REDIRECT);
|
|
|
|
bResult = ConnectToCNR(ILI_CNR_Link_Ptr(pcili), dwConnectInFlags,
|
|
hwndOwner, pszResolvedPathBuf,
|
|
&dwConnectOutFlags);
|
|
|
|
if (bResult)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
|
|
#else
|
|
CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
|
|
#endif
|
|
|
|
if (IS_FLAG_SET(dwConnectOutFlags, CONNECT_REFCOUNT))
|
|
{
|
|
ASSERT(IS_FLAG_CLEAR(dwConnectOutFlags, CONNECT_LOCALDRIVE));
|
|
|
|
SET_FLAG(*pdwOutFlags, RLI_OFL_DISCONNECT);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* It's ok that IsCNRAvailable() and GetRemotePathFromILinkInfo() are
|
|
* broken for NPs whose CNR names are not valid file system root paths.
|
|
*
|
|
* For NPs whose CNR names are valid file system root paths,
|
|
* IsCNRAvailable() will succeed or fail, and
|
|
* GetRemotePathFromILinkInfo() will be called only on success.
|
|
*
|
|
* For NPs whose CNR names are not valid file system root paths,
|
|
* IsCNRAvailable() will fail and GetRemotePathFromILinkInfo() will not
|
|
* be called.
|
|
*/
|
|
|
|
bResult = IsCNRAvailable(ILI_CNR_Link_Ptr(pcili));
|
|
|
|
if (bResult)
|
|
GetRemotePathFromILinkInfo(pcili, pszResolvedPathBuf);
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
(EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
|
|
FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS)));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** ResolveILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL ResolveILinkInfo(PCILINKINFO pcili, LPTSTR pszResolvedPathBuf,
|
|
DWORD dwInFlags, HWND hwndOwner,
|
|
PDWORD pdwOutFlags)
|
|
{
|
|
BOOL bResult;
|
|
BOOL bLocalInfoValid;
|
|
BOOL bRemoteInfoValid;
|
|
BOOL bLocalShare;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS));
|
|
ASSERT(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
|
|
IS_VALID_HANDLE(hwndOwner, WND));
|
|
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
|
|
|
|
*pdwOutFlags = 0;
|
|
|
|
/* Describe LinkInfo contents. */
|
|
|
|
bRemoteInfoValid = IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID);
|
|
bLocalInfoValid = IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID);
|
|
|
|
ASSERT(bLocalInfoValid || bRemoteInfoValid);
|
|
|
|
/*
|
|
* RAIDRAID: (15703) We will resolve to the wrong local path for a share
|
|
* that has been moved to another path here.
|
|
*/
|
|
|
|
bLocalShare = FALSE;
|
|
|
|
if (bRemoteInfoValid)
|
|
{
|
|
DWORD dwLocalShareFlags;
|
|
|
|
/* Ask the server for the local path. */
|
|
|
|
bResult = ResolveLocalPathFromServer(pcili, pszResolvedPathBuf,
|
|
&dwLocalShareFlags);
|
|
|
|
if (IS_FLAG_SET(dwLocalShareFlags, CNR_FL_LOCAL))
|
|
bLocalShare = TRUE;
|
|
|
|
if (bResult)
|
|
{
|
|
ASSERT(IS_FLAG_SET(dwLocalShareFlags, CNR_FL_LOCAL));
|
|
|
|
TRACE_OUT((TEXT("ResolveILinkInfo(): Resolved local path from server.")));
|
|
}
|
|
}
|
|
else
|
|
/* Can't tell if the referent is local or not. */
|
|
bResult = FALSE;
|
|
|
|
if (! bResult)
|
|
{
|
|
/* Try local path. */
|
|
|
|
if (bLocalInfoValid)
|
|
bResult = ResolveLocalILinkInfo(pcili, pszResolvedPathBuf, dwInFlags);
|
|
|
|
if (! bResult)
|
|
{
|
|
/* Try remote path. */
|
|
|
|
if (bRemoteInfoValid && ! bLocalShare)
|
|
bResult = ResolveRemoteILinkInfo(pcili, pszResolvedPathBuf,
|
|
dwInFlags, hwndOwner,
|
|
pdwOutFlags);
|
|
}
|
|
}
|
|
|
|
ASSERT(! bResult ||
|
|
(EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
|
|
FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS)));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** ResolveLocalPathFromServer()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL ResolveLocalPathFromServer(PCILINKINFO pcili,
|
|
LPTSTR pszResolvedPathBuf,
|
|
PDWORD pdwOutFlags)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
|
|
|
|
ASSERT(IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID));
|
|
|
|
/* Try to get local path from server. */
|
|
|
|
bResult = GetLocalPathFromCNRLink(ILI_CNR_Link_Ptr(pcili),
|
|
pszResolvedPathBuf, pdwOutFlags);
|
|
|
|
if (bResult)
|
|
{
|
|
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
|
|
ASSERT(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL));
|
|
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
|
|
#else
|
|
ASSERT(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL));
|
|
|
|
CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
|
|
#endif
|
|
}
|
|
|
|
ASSERT(FLAGS_ARE_VALID(*pdwOutFlags, ALL_CNR_FLAGS) &&
|
|
(! bResult ||
|
|
(EVAL(IS_FLAG_SET(*pdwOutFlags, CNR_FL_LOCAL)) &&
|
|
EVAL(IsLocalDrivePath(pszResolvedPathBuf)))));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** GetLocalPathFromILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void GetLocalPathFromILinkInfo(PCILINKINFO pcili,
|
|
LPTSTR pszResolvedPathBuf)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideLocalBasePath[MAX_PATH];
|
|
LPWSTR pszWideLocalBasePath;
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
#endif
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
|
|
#ifdef UNICODE
|
|
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideLocalBasePath = szWideLocalBasePath;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Local_Base_Path_PtrA(pcili), -1,
|
|
szWideLocalBasePath, MAX_PATH);
|
|
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
lstrcpy(pszResolvedPathBuf, pszWideLocalBasePath);
|
|
CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
|
|
#else
|
|
lstrcpy(pszResolvedPathBuf, ILI_Local_Base_Path_Ptr(pcili));
|
|
CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
|
|
#endif
|
|
|
|
ASSERT(lstrlen(pszResolvedPathBuf) < MAX_PATH_LEN);
|
|
ASSERT(IsDrivePath(pszResolvedPathBuf));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** GetRemotePathFromILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void GetRemotePathFromILinkInfo(PCILINKINFO pcili,
|
|
LPTSTR pszResolvedPathBuf)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
#endif
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN));
|
|
|
|
/* It's ok that this is broken for non-UNC CNR names. */
|
|
|
|
GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), pszResolvedPathBuf);
|
|
|
|
#ifdef UNICODE
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
CatPath(pszResolvedPathBuf, pszWideCommonPathSuffix);
|
|
#else
|
|
CatPath(pszResolvedPathBuf, ILI_Common_Path_Suffix_Ptr(pcili));
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareILinkInfoReferents()
|
|
**
|
|
** Compares the referents of two ILINKINFO structures.
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** Comparison is performed on ILINKINFO data in only one of the following ways
|
|
** in the following order:
|
|
**
|
|
** 1) local data compared with local data
|
|
** 2) remote data compared with remote data
|
|
** 3) local data only < remote data only
|
|
*/
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoReferents(PCILINKINFO pciliFirst,
|
|
PCILINKINFO pciliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
|
|
|
|
/*
|
|
* We can't just perform a binary comparison of the two ILinkInfos here. We
|
|
* may have two LinkInfos that refer to the same path, but differ in case on
|
|
* a non-case-sensitive file system.
|
|
*/
|
|
|
|
/* Compare ILinkInfos by local or remote data. */
|
|
|
|
if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID) &&
|
|
IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
/* Compare local data. */
|
|
cr = CompareILinkInfoLocalData(pciliFirst, pciliSecond);
|
|
else if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_REMOTE_INFO_VALID) &&
|
|
IS_FLAG_SET(pciliSecond->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
/* Compare remote data. */
|
|
cr = CompareILinkInfoRemoteData(pciliFirst, pciliSecond);
|
|
else
|
|
{
|
|
/*
|
|
* One contains only valid local information and the other contains only
|
|
* valid remote information.
|
|
*/
|
|
|
|
ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
|
|
(pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
|
|
|
|
/* By fiat, local only < remote only. */
|
|
|
|
if (IS_FLAG_SET(pciliFirst->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
cr = CR_FIRST_SMALLER;
|
|
else
|
|
cr = CR_FIRST_LARGER;
|
|
}
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareILinkInfoLocalData()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
**
|
|
** Local ILinkInfo data is compared in the following order:
|
|
**
|
|
** 1) volume ID
|
|
** 2) sub path from root
|
|
*/
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoLocalData(PCILINKINFO pciliFirst,
|
|
PCILINKINFO pciliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
|
|
|
|
cr = CompareVolumeIDs(ILI_Volume_ID_Ptr(pciliFirst),
|
|
ILI_Volume_ID_Ptr(pciliSecond));
|
|
|
|
if (cr == CR_EQUAL)
|
|
cr = CompareLocalPaths(pciliFirst, pciliSecond);
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareLocalPaths()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE COMPARISONRESULT CompareLocalPaths(PCILINKINFO pciliFirst,
|
|
PCILINKINFO pciliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
TCHAR rgchFirstLocalPath[MAX_PATH_LEN];
|
|
TCHAR rgchSecondLocalPath[MAX_PATH_LEN];
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
|
|
|
|
GetLocalPathFromILinkInfo(pciliFirst, rgchFirstLocalPath);
|
|
GetLocalPathFromILinkInfo(pciliSecond, rgchSecondLocalPath);
|
|
|
|
cr = ComparePathStrings(rgchFirstLocalPath, rgchSecondLocalPath);
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareILinkInfoRemoteData()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoRemoteData(PCILINKINFO pciliFirst,
|
|
PCILINKINFO pciliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffixFirst[MAX_PATH];
|
|
WCHAR szWideCommonPathSuffixSecond[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffixFirst;
|
|
LPWSTR pszWideCommonPathSuffixSecond;
|
|
#endif
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
|
|
|
|
cr = CompareCNRLinks(ILI_CNR_Link_Ptr(pciliFirst),
|
|
ILI_CNR_Link_Ptr(pciliSecond));
|
|
|
|
#ifdef UNICODE
|
|
if (pciliFirst->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffixFirst = szWideCommonPathSuffixFirst;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pciliFirst), -1,
|
|
szWideCommonPathSuffixFirst, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffixFirst = ILI_Common_Path_Suffix_Ptr(pciliFirst);
|
|
}
|
|
|
|
if (pciliSecond->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffixSecond = szWideCommonPathSuffixSecond;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pciliSecond), -1,
|
|
szWideCommonPathSuffixSecond, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffixSecond = ILI_Common_Path_Suffix_Ptr(pciliSecond);
|
|
}
|
|
#else
|
|
if (cr == CR_EQUAL)
|
|
cr = ComparePathStrings(ILI_Common_Path_Suffix_Ptr(pciliFirst),
|
|
ILI_Common_Path_Suffix_Ptr(pciliSecond));
|
|
#endif
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CompareILinkInfoVolumes()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE COMPARISONRESULT CompareILinkInfoVolumes(PCILINKINFO pciliFirst,
|
|
PCILINKINFO pciliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
BOOL bFirstLocal;
|
|
BOOL bFirstRemote;
|
|
BOOL bSecondLocal;
|
|
BOOL bSecondRemote;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliFirst, CILINKINFO));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pciliSecond, CILINKINFO));
|
|
|
|
bFirstLocal = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
|
|
ILI_FL_LOCAL_INFO_VALID);
|
|
bFirstRemote = IS_FLAG_SET(((PCILINKINFO)pciliFirst)->dwFlags,
|
|
ILI_FL_REMOTE_INFO_VALID);
|
|
|
|
bSecondLocal = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
|
|
ILI_FL_LOCAL_INFO_VALID);
|
|
bSecondRemote = IS_FLAG_SET(((PCILINKINFO)pciliSecond)->dwFlags,
|
|
ILI_FL_REMOTE_INFO_VALID);
|
|
|
|
if (bFirstLocal && bSecondLocal)
|
|
/* First and second have local information. */
|
|
cr = CompareVolumeIDs(ILI_Volume_ID_Ptr((PCILINKINFO)pciliFirst),
|
|
ILI_Volume_ID_Ptr((PCILINKINFO)pciliSecond));
|
|
else if (bFirstRemote && bSecondRemote)
|
|
/* First and second have remote information. */
|
|
cr = CompareCNRLinks(ILI_CNR_Link_Ptr((PCILINKINFO)pciliFirst),
|
|
ILI_CNR_Link_Ptr((PCILINKINFO)pciliSecond));
|
|
else
|
|
{
|
|
/*
|
|
* One contains only valid local information and the other contains only
|
|
* valid remote information.
|
|
*/
|
|
|
|
ASSERT(! ((pciliFirst->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID)) &
|
|
(pciliSecond->dwFlags & (ILI_FL_LOCAL_INFO_VALID | ILI_FL_REMOTE_INFO_VALID))));
|
|
|
|
/* By fiat, local only < remote only. */
|
|
|
|
if (bFirstLocal)
|
|
/*
|
|
* First has only local information. Second has only remote
|
|
* information.
|
|
*/
|
|
cr = CR_FIRST_SMALLER;
|
|
else
|
|
/*
|
|
* First has only remote information. Second has only local
|
|
* information.
|
|
*/
|
|
cr = CR_FIRST_LARGER;
|
|
}
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/*
|
|
** CheckCombinedPathLen()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CheckCombinedPathLen(LPCTSTR pcszBase, LPCTSTR pcszSuffix)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_STRING_PTR(pcszBase, CSTR));
|
|
ASSERT(IS_VALID_STRING_PTR(pcszSuffix, CSTR));
|
|
|
|
bResult = EVAL(lstrlen(pcszBase) + lstrlen(pcszSuffix) < MAX_PATH_LEN);
|
|
|
|
if (bResult)
|
|
{
|
|
TCHAR rgchCombinedPath[MAX_PATH_LEN + 1];
|
|
|
|
lstrcpy(rgchCombinedPath, pcszBase);
|
|
CatPath(rgchCombinedPath, pcszSuffix);
|
|
|
|
bResult = EVAL(lstrlen(rgchCombinedPath) < MAX_PATH_LEN);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** GetILinkInfoData()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL GetILinkInfoData(PCILINKINFO pcili, LINKINFODATATYPE lidt,
|
|
PCVOID *ppcvData)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
ASSERT(IsValidLINKINFODATATYPE(lidt));
|
|
ASSERT(IS_VALID_WRITE_PTR(ppcvData, PCVOID));
|
|
|
|
switch (lidt)
|
|
{
|
|
case LIDT_VOLUME_SERIAL_NUMBER:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
bResult = GetVolumeSerialNumber(ILI_Volume_ID_Ptr(pcili),
|
|
(PCDWORD *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_DRIVE_TYPE:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
bResult = GetVolumeDriveType(ILI_Volume_ID_Ptr(pcili),
|
|
(PCUINT *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_VOLUME_LABEL:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
bResult = GetVolumeLabel(ILI_Volume_ID_Ptr(pcili),
|
|
(LPCSTR *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_VOLUME_LABELW:
|
|
#ifdef UNICODE
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
bResult = GetVolumeLabelW(ILI_Volume_ID_Ptr(pcili),
|
|
(LPCTSTR *)ppcvData);
|
|
#endif
|
|
break;
|
|
|
|
case LIDT_LOCAL_BASE_PATH:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
{
|
|
*ppcvData = ILI_Local_Base_Path_PtrA(pcili);
|
|
bResult = TRUE;
|
|
}
|
|
break;
|
|
|
|
case LIDT_LOCAL_BASE_PATHW:
|
|
#ifdef UNICODE
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
{
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
*ppcvData = NULL;
|
|
else
|
|
*ppcvData = ILI_Local_Base_Path_PtrW(pcili);
|
|
bResult = TRUE;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case LIDT_NET_TYPE:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = GetCNRNetType(ILI_CNR_Link_Ptr(pcili),
|
|
(PCDWORD *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_NET_RESOURCE:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = GetCNRName(ILI_CNR_Link_Ptr(pcili),
|
|
(LPCSTR *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_NET_RESOURCEW:
|
|
#ifdef UNICODE
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = GetCNRNameW(ILI_CNR_Link_Ptr(pcili),
|
|
(LPCWSTR *)ppcvData);
|
|
#endif
|
|
break;
|
|
|
|
case LIDT_REDIRECTED_DEVICE:
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = GetLastRedirectedDevice(ILI_CNR_Link_Ptr(pcili),
|
|
(LPCSTR *)ppcvData);
|
|
break;
|
|
|
|
case LIDT_REDIRECTED_DEVICEW:
|
|
#ifdef UNICODE
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = GetLastRedirectedDeviceW(ILI_CNR_Link_Ptr(pcili),
|
|
(LPCWSTR *)ppcvData);
|
|
#endif
|
|
break;
|
|
|
|
case LIDT_COMMON_PATH_SUFFIX:
|
|
*ppcvData = ILI_Common_Path_Suffix_PtrA(pcili);
|
|
bResult = TRUE;
|
|
break;
|
|
|
|
case LIDT_COMMON_PATH_SUFFIXW:
|
|
#ifdef UNICODE
|
|
if (pcili->ucbHeaderSize == sizeof(ILINKINFOA))
|
|
{
|
|
*ppcvData = NULL;
|
|
}
|
|
else
|
|
{
|
|
*ppcvData = ILI_Common_Path_Suffix_PtrW(pcili);
|
|
}
|
|
bResult = TRUE;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
ERROR_OUT((TEXT("GetILinkInfoData(): Bad LINKINFODATATYPE %d."),
|
|
lidt));
|
|
break;
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** DisconnectILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL DisconnectILinkInfo(PCILINKINFO pcili)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
|
|
return(DisconnectFromCNR(ILI_CNR_Link_Ptr(pcili)));
|
|
}
|
|
|
|
|
|
#if defined(DEBUG) || defined(EXPV)
|
|
|
|
/*
|
|
** IsValidLINKINFODATATYPE()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL IsValidLINKINFODATATYPE(LINKINFODATATYPE lidt)
|
|
{
|
|
BOOL bResult;
|
|
|
|
switch (lidt)
|
|
{
|
|
case LIDT_VOLUME_SERIAL_NUMBER:
|
|
case LIDT_DRIVE_TYPE:
|
|
case LIDT_VOLUME_LABEL:
|
|
case LIDT_VOLUME_LABELW:
|
|
case LIDT_LOCAL_BASE_PATH:
|
|
case LIDT_LOCAL_BASE_PATHW:
|
|
case LIDT_NET_TYPE:
|
|
case LIDT_NET_RESOURCE:
|
|
case LIDT_NET_RESOURCEW:
|
|
case LIDT_REDIRECTED_DEVICE:
|
|
case LIDT_COMMON_PATH_SUFFIX:
|
|
case LIDT_COMMON_PATH_SUFFIXW:
|
|
bResult = TRUE;
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
ERROR_OUT((TEXT("IsValidLINKINFODATATYPE(): Invalid LINKINFODATATYPE %d."),
|
|
lidt));
|
|
break;
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if defined(DEBUG) || defined(VSTF)
|
|
|
|
/*
|
|
** CheckILIFlags()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CheckILIFlags(PCILINKINFO pcili)
|
|
{
|
|
return(FLAGS_ARE_VALID(pcili->dwFlags, ALL_ILINKINFO_FLAGS) &&
|
|
(IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
|
|
IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID)));
|
|
}
|
|
|
|
|
|
/*
|
|
** CheckILICommonPathSuffix()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CheckILICommonPathSuffix(PCILINKINFO pcili)
|
|
{
|
|
return(IS_VALID_STRING_PTRA(ILI_Common_Path_Suffix_PtrA(pcili), CSTR) &&
|
|
EVAL(IsContained(pcili, pcili->li.ucbSize,
|
|
ILI_Common_Path_Suffix_PtrA(pcili),
|
|
lstrlenA(ILI_Common_Path_Suffix_PtrA(pcili)))) &&
|
|
EVAL(! IS_SLASH(*ILI_Common_Path_Suffix_PtrA(pcili))));
|
|
}
|
|
|
|
|
|
/*
|
|
** CheckILILocalInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CheckILILocalInfo(PCILINKINFO pcili)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideLocalBasePath[MAX_PATH];
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideLocalBasePath;
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
return FALSE;
|
|
if (!IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID))
|
|
return FALSE;
|
|
if (!EVAL(IsContained(pcili, pcili->li.ucbSize,ILI_Volume_ID_Ptr(pcili),
|
|
GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))))
|
|
return FALSE;
|
|
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideLocalBasePath = szWideLocalBasePath;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Local_Base_Path_PtrA(pcili), -1,
|
|
szWideLocalBasePath, MAX_PATH);
|
|
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
|
|
}
|
|
else
|
|
{
|
|
pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
|
|
if (!EVAL(IsDrivePath(pszWideLocalBasePath)))
|
|
return FALSE;
|
|
if (!EVAL(IsContained(pcili, pcili->li.ucbSize,
|
|
ILI_Local_Base_Path_PtrA(pcili),
|
|
lstrlenA(ILI_Local_Base_Path_PtrA(pcili)))))
|
|
return FALSE;
|
|
if (!EVAL(CheckCombinedPathLen(pszWideLocalBasePath,
|
|
pszWideCommonPathSuffix)))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
#else
|
|
return(IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID) ||
|
|
|
|
/* Check volume ID. */
|
|
|
|
(IS_VALID_STRUCT_PTR(ILI_Volume_ID_Ptr(pcili), CVOLUMEID) &&
|
|
EVAL(IsContained(pcili, pcili->li.ucbSize,
|
|
ILI_Volume_ID_Ptr(pcili),
|
|
GetVolumeIDLen(ILI_Volume_ID_Ptr(pcili)))) &&
|
|
|
|
/* Check local base path. */
|
|
|
|
EVAL(IsDrivePath(ILI_Local_Base_Path_Ptr(pcili))) &&
|
|
EVAL(IsContained(pcili, pcili->li.ucbSize,
|
|
ILI_Local_Base_Path_PtrA(pcili),
|
|
lstrlen(ILI_Local_Base_Path_Ptr(pcili)))) &&
|
|
EVAL(CheckCombinedPathLen(ILI_Local_Base_Path_Ptr(pcili),
|
|
ILI_Common_Path_Suffix_Ptr(pcili)))));
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
** CheckILIRemoteInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL CheckILIRemoteInfo(PCILINKINFO pcili)
|
|
{
|
|
BOOL bResult;
|
|
|
|
if (IS_FLAG_CLEAR(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
bResult = TRUE;
|
|
else
|
|
{
|
|
/* Check CNR link. */
|
|
|
|
if (IS_VALID_STRUCT_PTR(ILI_CNR_Link_Ptr(pcili), CCNRLINK) &&
|
|
EVAL(IsContained(pcili, pcili->li.ucbSize,
|
|
ILI_CNR_Link_Ptr(pcili),
|
|
GetCNRLinkLen(ILI_CNR_Link_Ptr(pcili)))))
|
|
{
|
|
TCHAR rgchRemoteBasePath[MAX_PATH_LEN];
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
#endif
|
|
/* RAIDRAID: (15724) This is broken for non-UNC CNR names. */
|
|
|
|
GetRemotePathFromCNRLink(ILI_CNR_Link_Ptr(pcili), rgchRemoteBasePath);
|
|
|
|
#ifdef UNICODE
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
|
|
pszWideCommonPathSuffix));
|
|
#else
|
|
bResult = EVAL(CheckCombinedPathLen(rgchRemoteBasePath,
|
|
ILI_Common_Path_Suffix_Ptr(pcili)));
|
|
#endif
|
|
|
|
}
|
|
else
|
|
bResult = FALSE;
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/*
|
|
** IsValidPCLINKINFO()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL IsValidPCLINKINFO(PCLINKINFO pcli)
|
|
{
|
|
return(IS_VALID_STRUCT_PTR((PCILINKINFO)pcli, CILINKINFO));
|
|
}
|
|
|
|
|
|
/*
|
|
** IsValidPCILINKINFO()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE BOOL IsValidPCILINKINFO(PCILINKINFO pcili)
|
|
{
|
|
/*
|
|
* A "valid" LinkInfo structure has the following characteristics:
|
|
*
|
|
* 1) entire structure is readable
|
|
* 2) size of ILINKINFO header structure >= SIZEOF(CILINKINFO)
|
|
* 3) flags are valid
|
|
* 4) either local info or remote info or both are valid
|
|
* 5) contained structures and strings are valid and are entirely contained
|
|
* in LinkInfo structure
|
|
* 6) lstrlen() of combined paths < MAX_PATH_LEN
|
|
*/
|
|
|
|
return(IS_VALID_READ_PTR(pcili, CILINKINFO) &&
|
|
IS_VALID_READ_BUFFER_PTR(pcili, CILINKINFO, pcili->li.ucbSize) &&
|
|
EVAL(pcili->ucbHeaderSize >= SIZEOF(*pcili)) &&
|
|
EVAL(CheckILIFlags(pcili)) &&
|
|
EVAL(CheckILICommonPathSuffix(pcili)) &&
|
|
EVAL(CheckILILocalInfo(pcili)) &&
|
|
EVAL(CheckILIRemoteInfo(pcili)));
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*
|
|
** DumpILinkInfo()
|
|
**
|
|
**
|
|
**
|
|
** Arguments:
|
|
**
|
|
** Returns:
|
|
**
|
|
** Side Effects: none
|
|
*/
|
|
PRIVATE_CODE void DumpILinkInfo(PCILINKINFO pcili)
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideCommonPathSuffix[MAX_PATH];
|
|
LPWSTR pszWideCommonPathSuffix;
|
|
#endif
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcili, CILINKINFO));
|
|
|
|
PLAIN_TRACE_OUT((TEXT("%s[LinkInfo] ucbSize = %#x"),
|
|
INDENT_STRING,
|
|
pcili->li.ucbSize));
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] ucbHeaderSize = %#x"),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
pcili->ucbHeaderSize));
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] dwFLags = %#08lx"),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
pcili->dwFlags));
|
|
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_LOCAL_INFO_VALID))
|
|
{
|
|
#ifdef UNICODE
|
|
WCHAR szWideLocalBasePath[MAX_PATH];
|
|
LPWSTR pszWideLocalBasePath;
|
|
#endif
|
|
DumpVolumeID(ILI_Volume_ID_Ptr(pcili));
|
|
#ifdef UNICODE
|
|
if (pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideLocalBasePath = szWideLocalBasePath;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Local_Base_Path_PtrA(pcili), -1,
|
|
szWideLocalBasePath, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
pszWideLocalBasePath = ILI_Local_Base_Path_Ptr(pcili);
|
|
}
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
pszWideLocalBasePath));
|
|
#else
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] local base path \"%s\""),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
ILI_Local_Base_Path_Ptr(pcili)));
|
|
#endif
|
|
}
|
|
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
DumpCNRLink(ILI_CNR_Link_Ptr(pcili));
|
|
|
|
#ifdef UNICODE
|
|
if ( pcili->ucbHeaderSize == SIZEOF(ILINKINFOA))
|
|
{
|
|
pszWideCommonPathSuffix = szWideCommonPathSuffix;
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
ILI_Common_Path_Suffix_PtrA(pcili), -1,
|
|
szWideCommonPathSuffix, MAX_PATH);
|
|
|
|
}
|
|
else
|
|
{
|
|
pszWideCommonPathSuffix = ILI_Common_Path_Suffix_Ptr(pcili);
|
|
}
|
|
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
pszWideCommonPathSuffix));
|
|
#else
|
|
PLAIN_TRACE_OUT((TEXT("%s%s[ILinkInfo] common path suffix \"%s\""),
|
|
INDENT_STRING,
|
|
INDENT_STRING,
|
|
ILI_Common_Path_Suffix_Ptr(pcili)));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***************************** Exported Functions ****************************/
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func BOOL | CreateLinkInfo | Creates a LinkInfo structure for a path.
|
|
|
|
@parm PCSTR | pcszPath | A pointer to the path string that a LinkInfo structure
|
|
is to be created for.
|
|
|
|
@parm PLINKINFO * | ppli | A pointer to a PLINKINFO to be filled in with a
|
|
pointer to the new LinkInfo structure. *ppli is only valid if TRUE is
|
|
returned.
|
|
|
|
@rdesc If a LinkInfo structure was created successfully, TRUE is returned, and
|
|
*ppli contains a pointer to the new LinkInfo structure. Otherwise, a LinkInfo
|
|
structure was not created successfully, and *ppli is undefined. The reason for
|
|
failure may be determined by calling GetLastError().
|
|
|
|
@comm Once the caller is finshed with the LinkInfo structure returned by
|
|
CreateLinkInfo(), DestroyLinkInfo() should be called to free the LinkInfo
|
|
structure.<nl>
|
|
The contents of the LinkInfo structure returned are opaque to the caller, with
|
|
the exception of the first field of the LinkInfo structure. The first field of
|
|
the LinkInfo structure, ucbSize, is a UINT containing the size of the LinkInfo
|
|
structure in bytes, including the ucbSize field.<nl>
|
|
The LinkInfo structure is created in memory that is private to the LinkInfo
|
|
APIs. The returned LinkInfo structure should be copied into the caller's
|
|
memory, and the DestroyLinkInfo() should be called to free the LinkInfo
|
|
structure from the LinkInfo APIs' private memory.
|
|
|
|
@xref DestroyLinkInfo
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI BOOL WINAPI CreateLinkInfo(LPCTSTR pcszPath, PLINKINFO *ppli)
|
|
{
|
|
BOOL bResult;
|
|
|
|
DebugEntry(CreateLinkInfo);
|
|
|
|
#ifdef EXPV
|
|
/* Verify parameters. */
|
|
|
|
if (IS_VALID_STRING_PTR(pcszPath, CSTR) &&
|
|
IS_VALID_WRITE_PTR(ppli, PLINKINFO))
|
|
#endif
|
|
{
|
|
bResult = CreateILinkInfo(pcszPath, (PILINKINFO *)ppli);
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (bResult)
|
|
{
|
|
TRACE_OUT((TEXT("CreateLinkInfo(): LinkInfo created for path %s:"),
|
|
pcszPath));
|
|
DumpILinkInfo(*(PILINKINFO *)ppli);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
#ifdef EXPV
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
bResult = FALSE;
|
|
}
|
|
#endif
|
|
|
|
ASSERT(! bResult ||
|
|
IS_VALID_STRUCT_PTR(*ppli, CLINKINFO));
|
|
|
|
DebugExitBOOL(CreateLinkInfo, bResult);
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
LINKINFOAPI BOOL WINAPI CreateLinkInfoA(LPCSTR pcszPath, PLINKINFO *ppli)
|
|
{
|
|
LPWSTR lpwstr;
|
|
UINT cchPath;
|
|
|
|
cchPath = lstrlenA(pcszPath) + 1;
|
|
|
|
lpwstr = (LPWSTR)_alloca(cchPath*SIZEOF(WCHAR));
|
|
|
|
if ( MultiByteToWideChar( CP_ACP, 0,
|
|
pcszPath, cchPath,
|
|
lpwstr, cchPath) == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return CreateLinkInfo(lpwstr,ppli);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func void | DestroyLinkInfo | Destroys a LinkInfo structure created by
|
|
CreateLinkInfo().
|
|
|
|
@parm PLINKINFO | pli | A pointer to the LinkInfo structure to be destroyed.
|
|
|
|
@xref CreateLinkInfo
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI void WINAPI DestroyLinkInfo(PLINKINFO pli)
|
|
{
|
|
DebugEntry(DestroyLinkInfo);
|
|
|
|
#ifdef EXPV
|
|
/* Verify parameters. */
|
|
if (
|
|
IS_VALID_STRUCT_PTR(pli, CLINKINFO))
|
|
#endif
|
|
{
|
|
DestroyILinkInfo((PILINKINFO)pli);
|
|
}
|
|
|
|
DebugExitVOID(DestroyLinkInfo);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func int | CompareLinkInfoReferents | Compares the referents of two LinkInfo
|
|
structures.
|
|
|
|
@parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
|
|
referent is to be compared.
|
|
|
|
@parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
|
|
whose referent is to be compared.
|
|
|
|
@rdesc If the referent of the first LinkInfo structure is less than the
|
|
referent of the second LinkInfo structure, a negative value is returned. If
|
|
the referent of the first LinkInfo structure is the same as the referent of the
|
|
second LinkInfo structure, zero is returned. If the referent of the first
|
|
LinkInfo structure is larger than the referent of the second LinkInfo
|
|
structure, a positive value is returned. An invalid LinkInfo structure is
|
|
considered to have a referent that is less than the referent of any valid
|
|
LinkInfo structure. All invalid LinkInfo structures are considered to have the
|
|
same referent.
|
|
|
|
@comm The value returned is actually a COMPARISONRESULT, for clients that
|
|
understand COMPARISONRESULTs, like SYNCENG.DLL.
|
|
|
|
@xref CompareLinkInfoVolumes
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI int WINAPI CompareLinkInfoReferents(PCLINKINFO pcliFirst,
|
|
PCLINKINFO pcliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
BOOL bFirstValid;
|
|
BOOL bSecondValid;
|
|
|
|
DebugEntry(CompareLinkInfoReferents);
|
|
|
|
bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
|
|
|
|
bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
|
|
|
|
if (bFirstValid)
|
|
{
|
|
if (bSecondValid)
|
|
cr = CompareILinkInfoReferents((PCILINKINFO)pcliFirst,
|
|
(PCILINKINFO)pcliSecond);
|
|
else
|
|
cr = CR_FIRST_LARGER;
|
|
}
|
|
else
|
|
{
|
|
if (bSecondValid)
|
|
cr = CR_FIRST_SMALLER;
|
|
else
|
|
cr = CR_EQUAL;
|
|
}
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
DebugExitCOMPARISONRESULT(CompareLinkInfoReferents, cr);
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func int | CompareLinkInfoVolumes | Compares the volumes of the referents of
|
|
two LinkInfo structures.
|
|
|
|
@parm PCLINKINFO | pcliFirst | A pointer to the first LinkInfo structure whose
|
|
referent's volume is to be compared.
|
|
|
|
@parm PCLINKINFO | pcliSecond | A pointer to the second LinkInfo structure
|
|
referent's volume is to be compared.
|
|
|
|
@rdesc If the volume of the referent of the first LinkInfo structure is less
|
|
than the volume of the referent of the second LinkInfo structure, a negative
|
|
value is returned. If the volume of the referent of the first LinkInfo
|
|
structure is the same as the volume of the referent of the second LinkInfo
|
|
structure, zero is returned. If the volume of the referent of the first
|
|
LinkInfo structure is larger than the volume of the referent of the second
|
|
LinkInfo structure, a positive value is returned. An invalid LinkInfo
|
|
structure is considered to have a referent's volume that is less than the
|
|
referent's volume of any valid LinkInfo structure. All invalid LinkInfo
|
|
structures are considered to have the same referent's volume.
|
|
|
|
@comm The value returned is actually a COMPARISONRESULT, for clients that
|
|
understand COMPARISONRESULTs, like SYNCENG.DLL.
|
|
|
|
@xref CompareLinkInfoReferents
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI int WINAPI CompareLinkInfoVolumes(PCLINKINFO pcliFirst,
|
|
PCLINKINFO pcliSecond)
|
|
{
|
|
COMPARISONRESULT cr;
|
|
BOOL bFirstValid;
|
|
BOOL bSecondValid;
|
|
|
|
DebugEntry(CompareLinkInfoVolumes);
|
|
|
|
bFirstValid = IS_VALID_STRUCT_PTR(pcliFirst, CLINKINFO);
|
|
bSecondValid = IS_VALID_STRUCT_PTR(pcliSecond, CLINKINFO);
|
|
|
|
if (bFirstValid)
|
|
{
|
|
if (bSecondValid)
|
|
cr = CompareILinkInfoVolumes((PCILINKINFO)pcliFirst,
|
|
(PCILINKINFO)pcliSecond);
|
|
else
|
|
cr = CR_FIRST_LARGER;
|
|
}
|
|
else
|
|
{
|
|
if (bSecondValid)
|
|
cr = CR_FIRST_SMALLER;
|
|
else
|
|
cr = CR_EQUAL;
|
|
}
|
|
|
|
ASSERT(IsValidCOMPARISONRESULT(cr));
|
|
|
|
DebugExitCOMPARISONRESULT(CompareLinkInfoVolumes, cr);
|
|
|
|
return(cr);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func BOOL | ResolveLinkInfo | Resolves a LinkInfo structure into a file system
|
|
path on an available volume.
|
|
|
|
@parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be resolved.
|
|
|
|
@parm PSTR | pszResolvedPathBuf | A pointer to a buffer to be filled in with
|
|
the path resolved to the LinkInfo structure's referent.
|
|
|
|
@parm DWORD | dwInFlags | A bit mask of flags. This parameter may be any
|
|
combination of the following values:
|
|
|
|
@flag RLI_IFL_CONNECT | If set, connect to the referent's parent connectable
|
|
network resource if necessary. If clear, no connection is established.
|
|
|
|
@flag RLI_IFL_ALLOW_UI | If set, interaction with the user is permitted, and
|
|
the hwndOwner parameter identifies the parent window to be used for any ui
|
|
required. If clear, interaction with the user is not permitted.
|
|
|
|
@flag RLI_IFL_REDIRECT | If set, the resolved path is a redirected logical
|
|
device path. If clear, the resolved path is only a redirected logical device
|
|
path if the RLI_IFL_CONNECT flag is set, and the network requires a redirected
|
|
logical device path to make a connection.
|
|
|
|
@flag RLI_IFL_UPDATE | If set and the source LinkInfo structure needs updating,
|
|
RLI_OFL_UPDATED will be set in *pdwOutFlags and *ppliUpdated will point to an
|
|
updated LinkInfo structure. If clear, RLI_OFL_UPDATED will be clear in
|
|
*pdwOutFlags and *ppliUpdated is undefined.
|
|
|
|
@flag RLI_IFL_LOCAL_SEARCH | If set, first the last known logical device for
|
|
the referent's volume is checked for the volume, followed by all other local
|
|
logical devices that handle the referent's volume's media type. If clear, only
|
|
the last known logical device for the referent's volume is checked for the
|
|
volume.
|
|
|
|
@parm HWND | hwndOwner | A handle to the parent window to be used to bring up
|
|
any ui required. This parameter is only used if RLI_IFL_ALLOW_UI is set in
|
|
dwInFlags. Otherwise, it is ignored.
|
|
|
|
@parm PDWORD | pdwOutFlags | A pointer to a DWORD to be filled in with a bit
|
|
mask of flags. *pdwOutFlags is only valid if TRUE is returned. *pdwOutFlags
|
|
may be any combination of the following values:
|
|
|
|
@flag RLI_OFL_UPDATED | Only set if RLI_IFL_UPDATE was set in dwInFlags. If
|
|
set, the source LinkInfo structure needed updating, and *ppliUpdated points to
|
|
an updated LinkInfo structure. If clear, either RLI_IFL_UPDATE was clear in
|
|
dwInFlags or the source LinkInfo structure didn't need updating, and
|
|
*ppliUpdated is undefined.
|
|
|
|
@parm PLINKINFO * | ppliUpdated | If RLI_IFL_UPDATE is set in dwInFlags,
|
|
ppliUpdated is a pointer to a PLINKINFO to be filled in with a pointer to an
|
|
updated LinkInfo structure, if necessary. If RLI_IFL_UPDATE is clear in
|
|
dwInFlags, ppliUpdated is ignored. *ppliUpdated is only valid if
|
|
RLI_OFL_UPDATED is set in *pdwOutFlags
|
|
|
|
@rdesc If the LinkInfo was resolved to a path on an available successfully,
|
|
TRUE is returned, pszResolvedPathBuf's buffer is filled in with a file system
|
|
path to the LinkInfo structure's referent, and *pdwOutFlags is filled in as
|
|
described above. Otherwise, FALSE is returned, the contents of pszResolved's
|
|
buffer are undefined, and the contents of *pdwOutFlags are undefined. The
|
|
reason for failure may be determined by calling GetLastError().
|
|
|
|
@comm Once the caller is finshed with any new, updated LinkInfo structure
|
|
returned by ResolveLinkInfo(), DestroyLinkInfo() should be called to free the
|
|
LinkInfo structure.
|
|
|
|
@xref DestroyLinkInfo DisconnectLinkInfo
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI BOOL WINAPI ResolveLinkInfo(PCLINKINFO pcli,
|
|
LPTSTR pszResolvedPathBuf,
|
|
DWORD dwInFlags, HWND hwndOwner,
|
|
PDWORD pdwOutFlags,
|
|
PLINKINFO *ppliUpdated)
|
|
{
|
|
BOOL bResult;
|
|
|
|
DebugEntry(ResolveLinkInfo);
|
|
|
|
#ifdef EXPV
|
|
/* Verify parameters. */
|
|
|
|
if (
|
|
IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
|
|
IS_VALID_WRITE_BUFFER_PTR(pszResolvedPathBuf, STR, MAX_PATH_LEN) &&
|
|
FLAGS_ARE_VALID(dwInFlags, ALL_RLI_IFLAGS) &&
|
|
(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_ALLOW_UI) ||
|
|
IS_VALID_HANDLE(hwndOwner, WND)) &&
|
|
IS_VALID_WRITE_PTR(pdwOutFlags, DWORD) &&
|
|
(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) ||
|
|
IS_VALID_WRITE_PTR(ppliUpdated, PLINKINFO)) &&
|
|
EVAL(IS_FLAG_CLEAR(dwInFlags, RLI_IFL_TEMPORARY) ||
|
|
IS_FLAG_SET(dwInFlags, RLI_IFL_CONNECT)))
|
|
#endif
|
|
{
|
|
DWORD dwTempFlags;
|
|
|
|
*pdwOutFlags = 0;
|
|
|
|
bResult = ResolveILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf,
|
|
dwInFlags, hwndOwner, &dwTempFlags);
|
|
|
|
if (bResult)
|
|
{
|
|
*pdwOutFlags |= dwTempFlags;
|
|
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
|
|
{
|
|
bResult = UpdateILinkInfo((PCILINKINFO)pcli, pszResolvedPathBuf,
|
|
&dwTempFlags,
|
|
(PILINKINFO *)ppliUpdated);
|
|
|
|
if (bResult)
|
|
*pdwOutFlags |= dwTempFlags;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
TRACE_OUT((TEXT("ResolveLinkInfo(): flags %#08lx, given LinkInfo:"),
|
|
dwInFlags));
|
|
DumpILinkInfo((PCILINKINFO)pcli);
|
|
|
|
if (bResult)
|
|
{
|
|
TRACE_OUT((TEXT("ResolveLinkInfo(): Resolved path %s with flags %#08lx."),
|
|
pszResolvedPathBuf,
|
|
*pdwOutFlags));
|
|
|
|
if (IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))
|
|
{
|
|
ASSERT(IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE));
|
|
|
|
TRACE_OUT((TEXT("UpdateLinkInfo(): updated LinkInfo:")));
|
|
DumpILinkInfo(*(PILINKINFO *)ppliUpdated);
|
|
}
|
|
else
|
|
{
|
|
if (IS_FLAG_SET(dwInFlags, RLI_IFL_UPDATE))
|
|
TRACE_OUT((TEXT("UpdateLinkInfo(): No update required.")));
|
|
else
|
|
TRACE_OUT((TEXT("UpdateLinkInfo(): No update requested.")));
|
|
}
|
|
}
|
|
else
|
|
WARNING_OUT((TEXT("ResolveLinkInfo(): Referent's volume is unavailable.")));
|
|
|
|
#endif
|
|
|
|
}
|
|
#ifdef EXPV
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
bResult = FALSE;
|
|
}
|
|
#endif
|
|
|
|
ASSERT(! bResult ||
|
|
(FLAGS_ARE_VALID(*pdwOutFlags, ALL_RLI_OFLAGS) &&
|
|
EVAL(IsCanonicalPath(pszResolvedPathBuf)) &&
|
|
EVAL(! (IS_FLAG_CLEAR(dwInFlags, RLI_IFL_UPDATE) &&
|
|
IS_FLAG_SET(*pdwOutFlags, RLI_OFL_UPDATED))) &&
|
|
(IS_FLAG_CLEAR(*pdwOutFlags, RLI_OFL_UPDATED) ||
|
|
IS_VALID_STRUCT_PTR(*ppliUpdated, CLINKINFO))));
|
|
|
|
DebugExitBOOL(ResolveLinkInfo, bResult);
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
LINKINFOAPI BOOL WINAPI ResolveLinkInfoA(PCLINKINFO pcli,
|
|
LPSTR pszResolvedPathBuf,
|
|
DWORD dwInFlags, HWND hwndOwner,
|
|
PDWORD pdwOutFlags,
|
|
PLINKINFO *ppliUpdated)
|
|
{
|
|
WCHAR szWideResolvedPathBuf[MAX_PATH];
|
|
BOOL fResolved;
|
|
|
|
fResolved = ResolveLinkInfo(pcli,
|
|
szWideResolvedPathBuf,
|
|
dwInFlags, hwndOwner, pdwOutFlags, ppliUpdated);
|
|
if ( fResolved )
|
|
{
|
|
if ( WideCharToMultiByte( CP_ACP, 0,
|
|
szWideResolvedPathBuf, -1,
|
|
pszResolvedPathBuf, MAX_PATH,
|
|
NULL, NULL ) == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
return fResolved;
|
|
}
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func BOOL | DisconnectLinkInfo | Cancels a connection to a net resource
|
|
established by a previous call to ResolveLinkInfo(). DisconnectLinkInfo()
|
|
should only be called if RLI_OFL_DISCONNECT was set in *pdwOutFlags on return
|
|
from ResolveLinkInfo() on the given LinkInfo structure, or its updated
|
|
equivalent.
|
|
|
|
@parm PCLINKINFO | pcli | A pointer to the LinkInfo structure whose connection
|
|
is to be canceled.
|
|
|
|
@rdesc If the function completed successfully, TRUE is returned. Otherwise,
|
|
FALSE is returned. The reason for failure may be determined by calling
|
|
GetLastError().
|
|
|
|
@xref ResolveLinkInfo
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI BOOL WINAPI DisconnectLinkInfo(PCLINKINFO pcli)
|
|
{
|
|
BOOL bResult;
|
|
|
|
DebugEntry(DisconnectLinkInfo);
|
|
|
|
#ifdef EXPV
|
|
/* Verify parameters. */
|
|
|
|
if (
|
|
IS_VALID_STRUCT_PTR(pcli, CLINKINFO))
|
|
#endif
|
|
{
|
|
bResult = DisconnectILinkInfo((PCILINKINFO)pcli);
|
|
}
|
|
#ifdef EXPV
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
bResult = FALSE;
|
|
}
|
|
#endif
|
|
|
|
DebugExitBOOL(DisconnectLinkInfo, bResult);
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func BOOL | GetLinkInfoData | Retrieves a pointer to data in a LinkInfo
|
|
structure.
|
|
|
|
@parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to retrieve data
|
|
from.
|
|
|
|
@parm LINKINFODATATYPE | lidt | The type of data to be retrieved from the
|
|
LinkInfo structure. lidt may be one of the following values:
|
|
|
|
@flag LIDT_VOLUME_SERIAL_NUMBER | *ppcvData is a PCDWORD that points to the
|
|
LinkInfo structure's referent's volume's serial number.
|
|
|
|
@flag LIDT_DRIVE_TYPE | *ppcvData is a PCUINT that points to the LinkInfo
|
|
structure's referent's volume's host drive type.
|
|
|
|
@flag LIDT_VOLUME_LABEL | *ppcvData is a PCSTR that points to the LinkInfo
|
|
structure's referent's volume's label.
|
|
|
|
@flag LIDT_LOCAL_BASE_PATH | *ppcvData is a PCSTR that points to the LinkInfo
|
|
structure's referent's local base path.
|
|
|
|
@flag LIDT_NET_RESOURCE | *ppcvData is a PCSTR that points to the LinkInfo
|
|
structure's referent's parent network resource's name.
|
|
|
|
@flag LIDT_COMMON_PATH_SUFFIX | *ppcvData is a PCSTR that points to the
|
|
LinkInfo structure's referent's common path suffix.
|
|
|
|
@rdesc If the function completed successfully, TRUE is returned, and *ppcvData
|
|
is filled in with a pointer to the data requested from LinkInfo structure or NULL
|
|
if that was a valid field, but empty.
|
|
Otherwise, FALSE is returned, and the contents of *ppcvData are undefined. The
|
|
reason for failure may be determined by calling GetLastError().
|
|
|
|
@comm A LinkInfo structure may only contain some of the LinkInfo data listed
|
|
above.
|
|
|
|
******************************************************************************/
|
|
|
|
LINKINFOAPI BOOL WINAPI GetLinkInfoData(PCLINKINFO pcli, LINKINFODATATYPE lidt,
|
|
PCVOID *ppcvData)
|
|
{
|
|
BOOL bResult;
|
|
|
|
DebugEntry(GetLinkInfoData);
|
|
|
|
#ifdef EXPV
|
|
/* Verify parameters. */
|
|
|
|
if (
|
|
IS_VALID_STRUCT_PTR(pcli, CLINKINFO) &&
|
|
EVAL(IsValidLINKINFODATATYPE(lidt)) &&
|
|
IS_VALID_WRITE_PTR(ppcvData, PCVOID))
|
|
#endif
|
|
{
|
|
bResult = GetILinkInfoData((PCILINKINFO)pcli, lidt, ppcvData);
|
|
}
|
|
#ifdef EXPV
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
bResult = FALSE;
|
|
}
|
|
#endif
|
|
|
|
ASSERT(!bResult ||
|
|
((NULL == *ppcvData) || IS_VALID_READ_BUFFER_PTR(*ppcvData, LinkInfoData, 1)));
|
|
|
|
DebugExitBOOL(GetLinkInfoData, bResult);
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
@doc LINKINFOAPI
|
|
|
|
@func BOOL | IsValidLinkInfo | Determines whether or not a LinkInfo structure
|
|
is valid.
|
|
|
|
@parm PCLINKINFO | pcli | A pointer to the LinkInfo structure to be checked for
|
|
validity.
|
|
|
|
@rdesc If the function completed successfully, TRUE is returned. Otherwise,
|
|
FALSE is returned.
|
|
|
|
******************************************************************************/
|
|
|
|
//
|
|
// IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT validates alignment only on
|
|
// alignment machines. For machines that are not alignment-sensitive,
|
|
// it declares that all values are aligned.
|
|
//
|
|
|
|
#ifdef ALIGNMENT_MACHINE
|
|
#define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) IS_ALIGNED_DWORD_CNT(x)
|
|
#else
|
|
#define IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(x) TRUE
|
|
#endif
|
|
|
|
LINKINFOAPI BOOL WINAPI IsValidLinkInfo(PCLINKINFO pcli)
|
|
{
|
|
BOOL bResult;
|
|
PCILINKINFO pcili = (PCILINKINFO)pcli;
|
|
|
|
DebugEntry(IsValidLinkInfo);
|
|
|
|
// First make sure it's readable and not ridiculously small
|
|
if (IsBadReadPtr(pcli, sizeof(LINKINFO)) || // read the ucbSize
|
|
IsBadReadPtr(pcli, pcli->ucbSize) || // entire buffer is valid
|
|
pcli->ucbSize < pcili->ucbHeaderSize || // header fits in buffer
|
|
pcili->ucbHeaderSize < sizeof(ILINKINFOA)// smallest supported header
|
|
)
|
|
{
|
|
bResult = FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Make sure no field points outside our buffer
|
|
if (pcili->ucbVolumeIDOffset >= pcli->ucbSize ||
|
|
pcili->ucbLocalBasePathOffset >= pcli->ucbSize ||
|
|
pcili->ucbCommonPathSuffixOffset >= pcli->ucbSize ||
|
|
!IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbVolumeIDOffset))
|
|
{
|
|
bResult = FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// The ucbCNRLinkOffset field is valid only sometimes
|
|
if (IS_FLAG_SET(pcili->dwFlags, ILI_FL_REMOTE_INFO_VALID))
|
|
{
|
|
if (pcili->ucbCNRLinkOffset >= pcli->ucbSize ||
|
|
!IS_ALIGNMENT_MACHINE_ALIGNED_DWORD_CNT(pcili->ucbCNRLinkOffset))
|
|
{
|
|
bResult = FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// The UNICODE version has some more fields than the ANSI version.
|
|
// Those UNICODE fields must be WORD-aligned.
|
|
|
|
if (pcili->ucbHeaderSize >= sizeof(ILINKINFOW))
|
|
{
|
|
if (pcili->ucbLocalBasePathOffsetW >= pcli->ucbSize ||
|
|
pcili->ucbCommonPathSuffixOffsetW >= pcli->ucbSize ||
|
|
!IS_ALIGNED_WORD_CNT(pcili->ucbLocalBasePathOffsetW) ||
|
|
!IS_ALIGNED_WORD_CNT(pcili->ucbCommonPathSuffixOffsetW))
|
|
{
|
|
bResult = FALSE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Survived the validation ordeal!
|
|
bResult = TRUE;
|
|
|
|
exit:;
|
|
DebugExitBOOL(IsValidLinkInfo, bResult);
|
|
|
|
return(bResult);
|
|
}
|