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

Windows Kernel

Development Platform:

Visual C++

  1. /*
  2.  * canon.c - Canonical path manipulation module.
  3.  */
  4. /* Headers
  5.  **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. /***************************** Private Functions *****************************/
  9. /* Module Prototypes
  10.  ********************/
  11. PRIVATE_CODE BOOL GetCNRInfoForDevice(LPTSTR, LPTSTR, PDWORD, PDWORD);
  12. PRIVATE_CODE BOOL GetDrivePathInfo(LPTSTR, PDWORD, LPTSTR, LPTSTR *);
  13. PRIVATE_CODE BOOL GetRemotePathInfo(LPTSTR, PDWORD, LPTSTR, LPTSTR *);
  14. PRIVATE_CODE void CanonicalizeTrailingSlash(LPTSTR);
  15. #ifdef DEBUG
  16. PRIVATE_CODE BOOL CheckFullPathInfo(LPCTSTR, PDWORD, LPCTSTR, LPCTSTR *);
  17. #endif
  18. /*
  19. ** GetCNRInfoForDevice()
  20. **
  21. **
  22. **
  23. ** Arguments:
  24. **
  25. ** Returns:       BOOL
  26. **
  27. ** Side Effects:  none
  28. */
  29. PRIVATE_CODE BOOL GetCNRInfoForDevice(LPTSTR pszDeviceName, LPTSTR pszNameBuf,
  30.                                       PDWORD pdwcbLen, PDWORD pdwOutFlags)
  31. {
  32.    DWORD dwNetResult;
  33.    BOOL bResult;
  34.    /* "X:" + null terminator */
  35.    TCHAR rgchDrive[2 + 1];
  36.    ASSERT(IS_VALID_STRING_PTR(pszDeviceName, CSTR));
  37.    ASSERT(IS_VALID_WRITE_PTR(pdwcbLen, DWORD));
  38.    ASSERT(*pdwcbLen > 0);
  39.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNameBuf, TCHAR, (UINT)(*pdwcbLen)));
  40.    ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  41.    /* WNetGetConnection requires the device name to have no trailing
  42.    ** backslash.
  43.    */
  44.    MyLStrCpyN(rgchDrive, pszDeviceName, ARRAYSIZE(rgchDrive));
  45.    dwNetResult = WNetGetConnection(rgchDrive, pszNameBuf, pdwcbLen);
  46.    switch (dwNetResult)
  47.    {
  48.       case NO_ERROR:
  49.          *pdwOutFlags = GCPI_OFL_REMOTE;
  50.          bResult = TRUE;
  51.          TRACE_OUT((TEXT("GetCNRInfoForDevice(): %s is redirected to net resource "%s"."),
  52.                     pszDeviceName,
  53.                     pszNameBuf));
  54.          break;
  55.       case ERROR_NOT_CONNECTED:
  56.          *pdwOutFlags = 0;
  57.          bResult = TRUE;
  58.          TRACE_OUT((TEXT("GetCNRInfoForDevice(): %s is not redirected."),
  59.                     pszDeviceName));
  60.          break;
  61.       default:
  62.          WARNING_OUT((TEXT("GetCNRInfoForDevice(): WNetGetConnection() on %s returned %lu."),
  63.                       pszDeviceName,
  64.                       dwNetResult));
  65.          bResult = FALSE;
  66.          break;
  67.    }
  68.    ASSERT(! bResult ||
  69.           FLAGS_ARE_VALID(*pdwOutFlags, ALL_GCPI_OFLAGS) &&
  70.           (IS_FLAG_CLEAR(*pdwOutFlags, GCPI_OFL_REMOTE) ||
  71.            IsValidCNRName(pszNameBuf)));
  72.    return(bResult);
  73. }
  74. /*
  75. ** GetDrivePathInfo()
  76. **
  77. **
  78. **
  79. ** Arguments:
  80. **
  81. ** Returns:
  82. **
  83. ** Side Effects:  none
  84. */
  85. PRIVATE_CODE BOOL GetDrivePathInfo(LPTSTR pszDrivePath, PDWORD pdwOutFlags,
  86.                                    LPTSTR pszNetResourceNameBuf,
  87.                                    LPTSTR *ppszRootPathSuffix)
  88. {
  89.    BOOL bResult;
  90.    /* "X:" + null terminator. */
  91.    TCHAR rgchDriveRootPath[3 + 1];
  92.    ASSERT(IsDrivePath(pszDrivePath));
  93.    ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  94.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNetResourceNameBuf, STR, MAX_PATH_LEN));
  95.    ASSERT(IS_VALID_WRITE_PTR(ppszRootPathSuffix, LPTSTR));
  96.    ASSERT(lstrlen(pszDrivePath) >= 3);
  97.    *pdwOutFlags = 0;
  98.    MyLStrCpyN(rgchDriveRootPath, pszDrivePath, ARRAYSIZE(rgchDriveRootPath));
  99.    ASSERT(IsDriveRootPath(rgchDriveRootPath));
  100.    /* Do we need to get the CNR name for this drive path? */
  101.    if (GetDriveType(rgchDriveRootPath) != DRIVE_REMOTE)
  102.       /* No. */
  103.       bResult = TRUE;
  104.    else
  105.    {
  106.       DWORD dwcbBufLen = MAX_PATH_LEN;
  107.       /* Yes. */
  108.       bResult = GetCNRInfoForDevice(rgchDriveRootPath, pszNetResourceNameBuf,
  109.                                     &dwcbBufLen, pdwOutFlags);
  110.    }
  111.    *ppszRootPathSuffix = pszDrivePath + 3;
  112.    ASSERT(! bResult ||
  113.           CheckFullPathInfo(pszDrivePath, pdwOutFlags, pszNetResourceNameBuf,
  114.                             ppszRootPathSuffix));
  115.    return(bResult);
  116. }
  117. /*
  118. ** GetRemotePathInfo()
  119. **
  120. **
  121. **
  122. ** Arguments:
  123. **
  124. ** Returns:
  125. **
  126. ** Side Effects:  none
  127. */
  128. PRIVATE_CODE BOOL GetRemotePathInfo(LPTSTR pszRemotePath, PDWORD pdwOutFlags,
  129.                                     LPTSTR pszNetResourceNameBuf,
  130.                                     LPTSTR *ppszRootPathSuffix)
  131. {
  132.    BOOL bResult;
  133.    ASSERT(IsFullPath(pszRemotePath));
  134.    ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  135.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszNetResourceNameBuf, STR, MAX_PATH_LEN));
  136.    ASSERT(IS_VALID_WRITE_PTR(ppszRootPathSuffix, LPTSTR));
  137.    /* Is this a "\servershare" name? */
  138.    bResult = IsUNCPath(pszRemotePath);
  139.    if (bResult)
  140.    {
  141.       LPTSTR psz;
  142.       *pdwOutFlags = 0;
  143.       /*
  144.        * Yes.  Skip two leading slashes and look for end of \servershare
  145.        * specification.
  146.        */
  147.       /* Assume (as above) that a slash cannot be a DBCS lead byte. */
  148.       for (psz = pszRemotePath + 2; ! IS_SLASH(*psz); psz = CharNext(psz))
  149.          ASSERT(*psz);
  150.       ASSERT(IS_SLASH(*psz));
  151.       /*
  152.        * Found first slash after double slash.  Find end of string or next
  153.        * slash as end of root specification.
  154.        */
  155.       for (psz = CharNext(psz); *psz; psz = CharNext(psz))
  156.       {
  157.          if (IS_SLASH(*psz))
  158.             break;
  159.       }
  160.       ASSERT(psz >= pszRemotePath);
  161.       /* Add trailing slash for UNC root path. */
  162.       if (! *psz)
  163.       {
  164.          *psz = SLASH;
  165.          *(psz + 1) = TEXT('');
  166.       }
  167.       *ppszRootPathSuffix = (LPTSTR)psz + 1;
  168.       ASSERT(! IS_SLASH(**ppszRootPathSuffix));
  169.       /* (+ 1) for null terminator. */
  170.       MyLStrCpyN(pszNetResourceNameBuf, pszRemotePath, (int)(psz - pszRemotePath + 1));
  171.       CharUpper(pszNetResourceNameBuf);
  172.       SET_FLAG(*pdwOutFlags, GCPI_OFL_REMOTE);
  173.       bResult = TRUE;
  174.    }
  175.    else
  176.       /* Not a UNC path. */
  177.       SetLastError(ERROR_BAD_PATHNAME);
  178.    ASSERT(! bResult ||
  179.           CheckFullPathInfo(pszRemotePath, pdwOutFlags, pszNetResourceNameBuf,
  180.                             ppszRootPathSuffix));
  181.    return(bResult);
  182. }
  183. /*
  184. ** CanonicalizeTrailingSlash()
  185. **
  186. **
  187. **
  188. ** Arguments:
  189. **
  190. ** Returns:
  191. **
  192. ** Side Effects:  none
  193. */
  194. PRIVATE_CODE void CanonicalizeTrailingSlash(LPTSTR pszRootPathSuffix)
  195. {
  196.    LPTSTR pszLast;
  197.    ASSERT(IS_VALID_STRING_PTR(pszRootPathSuffix, STR));
  198.    ASSERT(! IS_SLASH(*pszRootPathSuffix));
  199.    /* No path suffix should end in a slash. */
  200.    pszLast = CharPrev(pszRootPathSuffix,
  201.                       pszRootPathSuffix + lstrlen(pszRootPathSuffix));
  202.    if (IS_SLASH(*pszLast))
  203.       *pszLast = TEXT('');
  204.    ASSERT(IsValidPathSuffix(pszRootPathSuffix));
  205.    return;
  206. }
  207. #ifdef DEBUG
  208. /*
  209. ** CheckFullPathInfo()
  210. **
  211. **
  212. **
  213. ** Arguments:
  214. **
  215. ** Returns:
  216. **
  217. ** Side Effects:  none
  218. */
  219. PRIVATE_CODE BOOL CheckFullPathInfo(LPCTSTR pcszFullPath,
  220.                                     PDWORD pdwOutFlags,
  221.                                     LPCTSTR pcszNetResourceName,
  222.                                     LPCTSTR *ppcszRootPathSuffix)
  223. {
  224.    return(EVAL(IsFullPath(pcszFullPath)) &&
  225.           FLAGS_ARE_VALID(*pdwOutFlags, ALL_GCPI_OFLAGS) &&
  226.           (IS_FLAG_CLEAR(*pdwOutFlags, GCPI_OFL_REMOTE) ||
  227.            (EVAL(IsValidCNRName(pcszNetResourceName)) &&
  228.             EVAL(lstrlen(pcszNetResourceName) < MAX_PATH_LEN))) &&
  229.           (IS_FLAG_SET(*pdwOutFlags, GCPI_OFL_REMOTE) ||
  230.            EVAL(IsLocalDrivePath(pcszFullPath))) &&
  231.           IS_VALID_STRING_PTR(*ppcszRootPathSuffix, CSTR) &&
  232.           EVAL(IsStringContained(pcszFullPath, *ppcszRootPathSuffix)));
  233. }
  234. #endif
  235. /***************************** Exported Functions ****************************/
  236. /******************************************************************************
  237. @doc LINKINFOAPI
  238. @func BOOL | GetCanonicalPathInfo | Retrieves information about the canonical
  239. form of a path.
  240. @parm PCSTR | pcszPath | A pointer to the path string whose canonical form
  241. information is to be retrieved.
  242. @parm PSTR | pszCanonicalBuf | A pointer to a buffer to be filled in with the
  243. full canonical form of the path.  This buffer must be at least MAX_PATH_LEN
  244. bytes long.
  245. @parm PDWORD | pdwOutFlags | A pointer to a DWORD bit mask of flags to be
  246. filled in with flags from the <t GETCANONICALPATHINFOOUTFLAGS> enumeration.
  247. @parm PSTR | pszNetResourceNameBuf | A pointer to a buffer to be filled in with
  248. the name of the net resource parent of the path.  This buffer must be at least
  249. MAX_PATH_LEN bytes long.  This buffer is only filled in if GCPI_OFL_REMOTE is
  250. set in *pdwOutFlags.
  251. @parm PSTR * | ppszRootPathSuffix | A pointer to a PSTR to be filled in with a
  252. pointer to the file system root path suffix, not including the leading slash,
  253. of the canonical path in pszCanonicalBuf's buffer.
  254. @rdesc If the function completed successfully, TRUE is returned.  Otherwise,
  255. FALSE is returned.  The reason for failure may be determined by calling
  256. GetLastError().
  257. ******************************************************************************/
  258. LINKINFOAPI BOOL WINAPI GetCanonicalPathInfo(LPCTSTR pcszPath,
  259.                                              LPTSTR pszCanonicalBuf,
  260.                                              PDWORD pdwOutFlags,
  261.                                              LPTSTR pszNetResourceNameBuf,
  262.                                              LPTSTR *ppszRootPathSuffix)
  263. {
  264.    BOOL bResult;
  265.    LPTSTR pszFileName;
  266.    DWORD dwPathLen;
  267.    ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  268.    ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszCanonicalBuf, STR, MAX_PATH_LEN));
  269.    ASSERT(IS_VALID_WRITE_PTR(pdwOutFlags, DWORD));
  270.    ASSERT(IS_VALID_WRITE_PTR(ppszRootPathSuffix, LPTSTR));
  271.    dwPathLen = GetFullPathName(pcszPath, MAX_PATH_LEN, pszCanonicalBuf,
  272.                                &pszFileName);
  273.    if (dwPathLen > 0 && dwPathLen < MAX_PATH_LEN)
  274.    {
  275.       /*
  276.        * Assume that GetFullPathName() changed all back slashes ('/') to
  277.        * forward slashes ('\').
  278.        */
  279.       ASSERT(! MyStrChr(pszCanonicalBuf, TEXT('/'), NULL));
  280.       if (IsDrivePath(pszCanonicalBuf))
  281.          bResult = GetDrivePathInfo(pszCanonicalBuf, pdwOutFlags,
  282.                                     pszNetResourceNameBuf,
  283.                                     ppszRootPathSuffix);
  284.       else
  285.          bResult = GetRemotePathInfo(pszCanonicalBuf, pdwOutFlags,
  286.                                      pszNetResourceNameBuf,
  287.                                      ppszRootPathSuffix);
  288.       if (bResult)
  289.          CanonicalizeTrailingSlash(*ppszRootPathSuffix);
  290.    }
  291.    else
  292.    {
  293.       // BOGUS ASSERT:  We can also get here if the resulting full path
  294.       // is bigger than MAX_PATH_LEN.
  295.       // ASSERT(! dwPathLen);
  296.       WARNING_OUT((TEXT("GetFullPathName() failed on path %s, returning %lu."),
  297.                    pcszPath,
  298.                    dwPathLen));
  299.       bResult = FALSE;
  300.    }
  301.    ASSERT(! bResult ||
  302.           (CheckFullPathInfo(pszCanonicalBuf, pdwOutFlags,
  303.                              pszNetResourceNameBuf, ppszRootPathSuffix) &&
  304.            IsValidPathSuffix(*ppszRootPathSuffix)));
  305.    return(bResult);
  306. }
  307. #ifdef UNICODE
  308. LINKINFOAPI BOOL WINAPI GetCanonicalPathInfoA(LPCSTR pcszPath,
  309.                                              LPSTR pszCanonicalBuf,
  310.                                              PDWORD pdwOutFlags,
  311.                                              LPSTR pszNetResourceNameBuf,
  312.                                              LPSTR *ppszRootPathSuffix)
  313. {
  314.     LPWSTR  pcszWidePath;
  315.     UINT    cchPath;
  316.     WCHAR   szWideCanonicalBuf[MAX_PATH];
  317.     WCHAR   szWideNetResourceNameBuf[MAX_PATH];
  318.     LPWSTR  pszWideRootPathSuffix;
  319.     UINT_PTR chOffset;
  320.     BOOL    fCanonical;
  321.     cchPath = lstrlenA(pcszPath) + 1;
  322.     pcszWidePath = (LPWSTR)_alloca(cchPath*SIZEOF(WCHAR));
  323.     if ( MultiByteToWideChar( CP_ACP, 0,
  324.                               pcszPath, cchPath,
  325.                               pcszWidePath, cchPath) == 0)
  326.     {
  327.         return FALSE;
  328.     }
  329.     fCanonical = GetCanonicalPathInfo( pcszWidePath,
  330.                                        szWideCanonicalBuf,
  331.                                        pdwOutFlags,
  332.                                        szWideNetResourceNameBuf,
  333.                                        &pszWideRootPathSuffix );
  334.     if ( fCanonical )
  335.     {
  336.         if ( WideCharToMultiByte( CP_ACP, 0,
  337.                                   szWideCanonicalBuf, -1,
  338.                                   pszCanonicalBuf, MAX_PATH,
  339.                                   NULL, NULL ) == 0)
  340.         {
  341.             return FALSE;
  342.         }
  343.         if ( *pdwOutFlags & GCPI_OFL_REMOTE )
  344.         {
  345.             if ( WideCharToMultiByte( CP_ACP, 0,
  346.                                       szWideNetResourceNameBuf, -1,
  347.                                       pszNetResourceNameBuf, MAX_PATH,
  348.                                       NULL, NULL ) == 0)
  349.             {
  350.                 return FALSE;
  351.             }
  352.         }
  353.         chOffset = pszWideRootPathSuffix - szWideCanonicalBuf;
  354.         *ppszRootPathSuffix = pszCanonicalBuf;
  355.         while ( chOffset-- )
  356.         {
  357.             *ppszRootPathSuffix = CharNextA(*ppszRootPathSuffix);
  358.         }
  359.     }
  360.     return(fCanonical);
  361. }
  362. #endif