Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
10 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. DfsPath.cpp
  5. Abstract:
  6. This is the implementation file for Dfs Shell path handling modules for the Dfs Shell
  7. Extension object.
  8. Author:
  9. Environment:
  10. NT only.
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <ntioapi.h>
  15. #include <nturtl.h>
  16. #include <windef.h>
  17. #include <winbase.h>
  18. #include <lmerr.h>
  19. #include <lmcons.h>
  20. #include <lmdfs.h>
  21. #include <lmapibuf.h>
  22. #include <tchar.h>
  23. #include "DfsPath.h"
  24. //--------------------------------------------------------------------------------------------
  25. //
  26. // caller of this function must call free() on *o_ppszRemotePath
  27. //
  28. HRESULT GetRemotePath(
  29. LPCTSTR i_pszPath,
  30. PTSTR *o_ppszRemotePath
  31. )
  32. {
  33. if (!i_pszPath || !*i_pszPath || !o_ppszRemotePath)
  34. return E_INVALIDARG;
  35. if (*o_ppszRemotePath)
  36. free(*o_ppszRemotePath); // to prevent memory leak
  37. UNICODE_STRING unicodePath;
  38. RtlInitUnicodeString(&unicodePath, i_pszPath);
  39. OBJECT_ATTRIBUTES ObjectAttributes;
  40. InitializeObjectAttributes(&ObjectAttributes,
  41. &unicodePath,
  42. OBJ_CASE_INSENSITIVE,
  43. NULL,
  44. NULL);
  45. HANDLE hFile = NULL;
  46. IO_STATUS_BLOCK ioStatusBlock;
  47. NTSTATUS ntStatus = NtOpenFile(&hFile,
  48. SYNCHRONIZE,
  49. &ObjectAttributes,
  50. &ioStatusBlock,
  51. FILE_SHARE_READ,
  52. FILE_DIRECTORY_FILE);
  53. if (!NT_SUCCESS(ntStatus))
  54. return HRESULT_FROM_WIN32(ntStatus);
  55. TCHAR buffer[MAX_PATH + sizeof(FILE_NAME_INFORMATION) + 1] = {0};
  56. PFILE_NAME_INFORMATION pFileNameInfo = (PFILE_NAME_INFORMATION)buffer;
  57. ntStatus = NtQueryInformationFile(hFile,
  58. &ioStatusBlock,
  59. pFileNameInfo,
  60. sizeof(buffer) - sizeof(TCHAR), // leave room for the ending '\0'
  61. FileNameInformation);
  62. NtClose(hFile);
  63. if (!NT_SUCCESS(ntStatus))
  64. {
  65. return HRESULT_FROM_WIN32(ntStatus);
  66. }
  67. UINT uiRequiredLength = (pFileNameInfo->FileNameLength / sizeof(TCHAR)) + 2; // +1 for prefix '\\', the other for the ending NULL
  68. *o_ppszRemotePath = (PTSTR)calloc(uiRequiredLength, sizeof(TCHAR));
  69. if (!*o_ppszRemotePath)
  70. return E_OUTOFMEMORY;
  71. // prepend a "\" as the Api puts only 1 "\" as in \dfsserver\dfsroot
  72. (*o_ppszRemotePath)[0] = _T('\\');
  73. RtlCopyMemory((BYTE*)&((*o_ppszRemotePath)[1]),
  74. pFileNameInfo->FileName,
  75. pFileNameInfo->FileNameLength);
  76. return S_OK;
  77. }
  78. bool IsPathWithDriveLetter(LPCTSTR pszPath)
  79. {
  80. if (!pszPath || lstrlen(pszPath) < 3)
  81. return false;
  82. if (*(pszPath+1) == _T(':') &&
  83. *(pszPath+2) == _T('\\') &&
  84. (*pszPath >= _T('a') && *pszPath <= _T('z') ||
  85. *pszPath >= _T('A') && *pszPath <= _T('Z')))
  86. return true;
  87. return false;
  88. }
  89. bool
  90. IsDfsPath
  91. (
  92. LPTSTR i_lpszDirPath,
  93. LPTSTR* o_plpszEntryPath,
  94. LPDFS_ALTERNATES** o_pppDfsAlternates
  95. )
  96. /*++
  97. Routine Description:
  98. Checks if the give directory path is a Dfs Path.
  99. If it is then it returns the largest Dfs entry path that matches
  100. this directory.
  101. Arguments:
  102. i_lpszDirPath - The directory path.
  103. o_plpszEntryPath - The largest Dfs entrypath is returned here.
  104. if the dir path is not Dfs path then this is NULL.
  105. o_pppDfsAlternates - If the path is a dfs path, then an array of pointers to the possible alternate
  106. paths are returned here.
  107. Return value:
  108. true if the path is determined to be a Dfs Path
  109. false if otherwise.
  110. --*/
  111. {
  112. if (!i_lpszDirPath || !*i_lpszDirPath || !o_pppDfsAlternates || !o_plpszEntryPath)
  113. {
  114. return(false);
  115. }
  116. *o_pppDfsAlternates = NULL;
  117. *o_plpszEntryPath = NULL;
  118. PTSTR lpszSharePath = NULL; // this variable will hold the path in UNC format, and with an ending whack.
  119. // Is the dir path of type d:\* or \\server\share\*?
  120. if (_T('\\') == i_lpszDirPath[0])
  121. {
  122. // This is a UNC path.
  123. lpszSharePath = (PTSTR)calloc(lstrlen(i_lpszDirPath) + 2, sizeof(TCHAR)); // + 2 to hold the ending whack and '\0'
  124. if (!lpszSharePath)
  125. return false; // out of memory
  126. _tcscpy(lpszSharePath, i_lpszDirPath);
  127. // will append the whack later if necessary
  128. }
  129. else if (!IsPathWithDriveLetter(i_lpszDirPath))
  130. {
  131. return false; // unknown path format
  132. } else
  133. {
  134. // This is a drive based path.
  135. TCHAR lpszDirPath[] = _T("\\??\\C:\\");
  136. PTSTR lpszDrive = lpszDirPath + 4;
  137. // Copy the drive letter,
  138. *lpszDrive = *i_lpszDirPath;
  139. // See if it is a remote drive. If not return false.
  140. if (DRIVE_REMOTE != GetDriveType(lpszDrive))
  141. return false;
  142. PTSTR pszRemotePath = NULL;
  143. if (FAILED(GetRemotePath(lpszDirPath, &pszRemotePath)))
  144. return false;
  145. lpszSharePath = (PTSTR)calloc(lstrlen(pszRemotePath) + lstrlen(i_lpszDirPath), sizeof(TCHAR));
  146. // since we won't copy over the 2-drive-chars c:, this is long enough to hold the ending whack and '\0'
  147. if (!lpszSharePath)
  148. {
  149. free(pszRemotePath);
  150. return false; // out of memory
  151. }
  152. _tcscpy(lpszSharePath, pszRemotePath);
  153. if (pszRemotePath[lstrlen(pszRemotePath) - 1] == _T('\\'))
  154. _tcscat(lpszSharePath, i_lpszDirPath + 3);
  155. else
  156. _tcscat(lpszSharePath, i_lpszDirPath + 2);
  157. // will append the whack later if necessary
  158. free(pszRemotePath);
  159. }
  160. // Start from the end of the path taking a component at
  161. // a time and see if it is a Dfs entry Path.
  162. // now append the whack if necessary
  163. // point lpszTemp at the ending whack
  164. LPTSTR lpszTemp = lpszSharePath + _tcslen(lpszSharePath) - 1;
  165. if (_T('\\') != *lpszTemp)
  166. *(++lpszTemp) = _T('\\');
  167. bool bIsDfsPath = false;
  168. DWORD dwStatus = NERR_Success;
  169. DFS_INFO_3* pDfsInfo3 = NULL;
  170. while (lpszTemp > (lpszSharePath + 2))
  171. {
  172. *lpszTemp = _T('\0');
  173. pDfsInfo3 = NULL;
  174. dwStatus = NetDfsGetClientInfo(
  175. lpszSharePath, // dir path as entrypath
  176. NULL, // No server name required
  177. NULL, // No share required
  178. 3L, // level 1
  179. (LPBYTE *)&pDfsInfo3 // out buffer.
  180. );
  181. *lpszTemp = _T('\\'); // Restore Component.
  182. if (NERR_Success == dwStatus)
  183. { // This component is a Dfs path.
  184. // Copy entry path.
  185. *o_plpszEntryPath = new TCHAR [_tcslen(lpszSharePath) + 1];
  186. if (!*o_plpszEntryPath)
  187. {
  188. NetApiBufferFree(pDfsInfo3);
  189. break;
  190. }
  191. _tcscpy(*o_plpszEntryPath, lpszSharePath);
  192. // Allocate null terminated array for alternate pointers.
  193. *o_pppDfsAlternates = new LPDFS_ALTERNATES[pDfsInfo3->NumberOfStorages + 1];
  194. if (!*o_pppDfsAlternates)
  195. {
  196. NetApiBufferFree(pDfsInfo3);
  197. delete[] *o_plpszEntryPath;
  198. *o_plpszEntryPath = NULL;
  199. break;
  200. }
  201. (*o_pppDfsAlternates)[pDfsInfo3->NumberOfStorages] = NULL;
  202. // Allocate space for each alternate.
  203. DWORD i = 0;
  204. for (i = 0; i < pDfsInfo3->NumberOfStorages; i++)
  205. {
  206. (*o_pppDfsAlternates)[i] = new DFS_ALTERNATES;
  207. if (NULL == (*o_pppDfsAlternates)[i])
  208. {
  209. for(int j = i-1; j >= 0; j--)
  210. delete (*o_pppDfsAlternates)[j];
  211. delete[] *o_pppDfsAlternates;
  212. *o_pppDfsAlternates = NULL;
  213. delete[] *o_plpszEntryPath;
  214. *o_plpszEntryPath = NULL;
  215. NetApiBufferFree(pDfsInfo3);
  216. free(lpszSharePath);
  217. return(false);
  218. }
  219. }
  220. // Copy alternate paths.
  221. for (i = 0; i < pDfsInfo3->NumberOfStorages; i++)
  222. {
  223. (*o_pppDfsAlternates)[i]->bstrServer = (pDfsInfo3->Storage[i]).ServerName;
  224. (*o_pppDfsAlternates)[i]->bstrShare = (pDfsInfo3->Storage[i]).ShareName;
  225. (*o_pppDfsAlternates)[i]->bstrAlternatePath = _T("\\\\");
  226. (*o_pppDfsAlternates)[i]->bstrAlternatePath += (pDfsInfo3->Storage[i]).ServerName;
  227. (*o_pppDfsAlternates)[i]->bstrAlternatePath += _T("\\");
  228. (*o_pppDfsAlternates)[i]->bstrAlternatePath += (pDfsInfo3->Storage[i]).ShareName;
  229. (*o_pppDfsAlternates)[i]->bstrAlternatePath += lpszTemp;
  230. // remove the ending whack
  231. (*o_pppDfsAlternates)[i]->bstrAlternatePath[_tcslen((*o_pppDfsAlternates)[i]->bstrAlternatePath) - 1] = _T('\0');
  232. // Set replica state.
  233. if ((pDfsInfo3->Storage[i]).State & DFS_STORAGE_STATE_ACTIVE)
  234. {
  235. (*o_pppDfsAlternates)[i]->ReplicaState = SHL_DFS_REPLICA_STATE_ACTIVE_UNKNOWN;
  236. }
  237. }
  238. bIsDfsPath = true;
  239. NetApiBufferFree(pDfsInfo3);
  240. break;
  241. }
  242. // move lpszTemp backforward to the next whack
  243. lpszTemp--;
  244. while (_T('\\') != *lpszTemp && lpszTemp > (lpszSharePath + 2))
  245. {
  246. lpszTemp--;
  247. }
  248. }
  249. if (lpszSharePath)
  250. free(lpszSharePath);
  251. return(bIsDfsPath);
  252. }
  253. //----------------------------------------------------------------------------------