linkinfo.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 82k
Category:

Windows Kernel

Development Platform:

Visual C++

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