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.

341 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. volstate.cpp
  5. Abstract:
  6. Contains implementation of the volume state class. This class
  7. maintains state about one volume.
  8. Author:
  9. Stefan R. Steiner [ssteiner] 03-14-2000
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. CFsdVolumeStateManager::CFsdVolumeStateManager(
  14. IN CDumpParameters *pcDumpParameters
  15. ) : m_cVolumeStateList( BSHASHMAP_MEDIUM ),
  16. m_pcParams( pcDumpParameters ),
  17. m_pcExclManager( NULL )
  18. {
  19. if ( m_pcParams->m_bUseExcludeProcessor )
  20. {
  21. m_pcExclManager = new CFsdExclusionManager( m_pcParams );
  22. if ( m_pcExclManager == NULL )
  23. {
  24. m_pcParams->ErrPrint( L"CFsdVolumeStateManager::CFsdVolumeStateManager - Can't init CFsdExclusionManager, out of memory" );
  25. throw E_OUTOFMEMORY;
  26. }
  27. }
  28. }
  29. CFsdVolumeStateManager::~CFsdVolumeStateManager()
  30. {
  31. //
  32. // Need to delete all volume state objects
  33. //
  34. SFsdVolumeId sFsdId;
  35. CFsdVolumeState *pcVolState;
  36. m_cVolumeStateList.StartEnum();
  37. while ( m_cVolumeStateList.GetNextEnum( &sFsdId, &pcVolState ) )
  38. {
  39. delete pcVolState;
  40. }
  41. m_cVolumeStateList.EndEnum();
  42. delete m_pcExclManager;
  43. }
  44. VOID
  45. CFsdVolumeStateManager::PrintHardLinkInfo()
  46. {
  47. //
  48. // Let's iterate through all of the volumes managed by this
  49. // manager.
  50. //
  51. SFsdVolumeId sFsdId;
  52. CFsdVolumeState *pcVolState;
  53. m_pcParams->DumpPrint( L"" );
  54. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  55. m_pcParams->DumpPrint( L"HardLink Information" );
  56. m_cVolumeStateList.StartEnum();
  57. while ( m_cVolumeStateList.GetNextEnum( &sFsdId, &pcVolState ) )
  58. {
  59. m_pcParams->DumpPrint( L"----------------------------------------------------------------------------" );
  60. m_pcParams->DumpPrint( L"For volume: '%s'", pcVolState->GetVolumePath() );
  61. pcVolState->PrintHardLinkInfo();
  62. }
  63. m_cVolumeStateList.EndEnum();
  64. }
  65. /*++
  66. Routine Description:
  67. <Enter description here>
  68. Arguments:
  69. Return Value:
  70. ERROR_ALREADY_EXISTS - The volume already exists. The returned
  71. volume state object pointer is valid.
  72. ERROR_CAN_NOT_COMPLETE - Unexpected error
  73. --*/
  74. DWORD
  75. CFsdVolumeStateManager::GetVolumeState(
  76. IN const CBsString& cwsVolumePath,
  77. OUT CFsdVolumeState **ppcVolState
  78. )
  79. {
  80. *ppcVolState = NULL;
  81. try
  82. {
  83. WCHAR wszVolumePath[ FSD_MAX_PATH ];
  84. //
  85. // Temporary workaround for bug in GetVolumeInformationW()
  86. //
  87. BOOL bFixed = FALSE;
  88. if ( cwsVolumePath.Left( 2 ) == L"\\\\" && cwsVolumePath.Left( 4 ) != L"\\\\?\\" )
  89. {
  90. //
  91. // reduce to the minimal \\machine\sharename\ form
  92. //
  93. ::wcscpy( wszVolumePath, cwsVolumePath );
  94. LPWSTR pswz;
  95. pswz = ::wcschr( wszVolumePath + 2, L'\\' );
  96. if ( pswz != NULL )
  97. {
  98. pswz = ::wcschr( pswz + 1, L'\\' );
  99. if ( pswz != NULL )
  100. {
  101. pswz[1] = '\0';
  102. bFixed = TRUE;
  103. }
  104. }
  105. }
  106. if ( bFixed == FALSE )
  107. {
  108. //
  109. // Get the volume path that contains this volume
  110. //
  111. if ( !::GetVolumePathNameW(
  112. cwsVolumePath,
  113. wszVolumePath,
  114. FSD_MAX_PATH ) )
  115. {
  116. m_pcParams->ErrPrint( L"CFsdVolumeStateManager - GetVolumePathName( '%s', ... ) returned dwRet: %d",
  117. cwsVolumePath.c_str(), ::GetLastError() );
  118. return ::GetLastError();
  119. }
  120. }
  121. //
  122. // Initialize a new volume state object
  123. //
  124. CFsdVolumeState *pcFsdVolumeState;
  125. pcFsdVolumeState = new CFsdVolumeState( m_pcParams, wszVolumePath );
  126. if ( pcFsdVolumeState == NULL )
  127. {
  128. m_pcParams->ErrPrint( L"CFsdVolumeStateManager, out of memory, can't get volume information" );
  129. return ::GetLastError();
  130. }
  131. //
  132. // Now get the information about the volume.
  133. // BUGBUG: Note that GetVolumeInformationW returns
  134. // ERROR_DIR_NOT_ROOT when encountering a junction on a
  135. // remote share.
  136. //
  137. if ( !::GetVolumeInformationW(
  138. wszVolumePath,
  139. NULL,
  140. 0,
  141. &pcFsdVolumeState->m_dwVolSerialNumber,
  142. &pcFsdVolumeState->m_dwMaxComponentLength,
  143. &pcFsdVolumeState->m_dwFileSystemFlags,
  144. pcFsdVolumeState->m_cwsFileSystemName.GetBufferSetLength( 64 ),
  145. 64 ) )
  146. {
  147. pcFsdVolumeState->m_cwsFileSystemName.ReleaseBuffer();
  148. m_pcParams->ErrPrint( L"CFsdVolumeStateManager - GetVolumeInformation( '%s', ... ) returned dwRet: %d "
  149. L"(if 144 probably hit bug in GetVolumeInformation when accessing remote mountpoints)",
  150. wszVolumePath, ::GetLastError() );
  151. delete pcFsdVolumeState;
  152. return ::GetLastError();
  153. }
  154. pcFsdVolumeState->m_cwsFileSystemName.ReleaseBuffer();
  155. #if 0
  156. SFsdVolumeId sVolIdTest;
  157. CBsString cwsRealVolumePath;
  158. GetVolumeIdAndPath( m_pcParams, cwsVolumePath, &sVolIdTest, cwsRealVolumePath );
  159. assert( sVolIdTest.m_dwVolSerialNumber == pcFsdVolumeState->m_dwVolSerialNumber );
  160. printf("VolumeSerialNumber: 0x%08x, 0x%08x\n", pcFsdVolumeState->m_dwVolSerialNumber,
  161. sVolIdTest.m_dwVolSerialNumber );
  162. #endif
  163. //
  164. // Now see if this volume already exists in the list of volume states
  165. //
  166. LONG lRet;
  167. SFsdVolumeId sVolId;
  168. sVolId.m_dwVolSerialNumber = pcFsdVolumeState->m_dwVolSerialNumber;
  169. if ( m_cVolumeStateList.Find( sVolId, ppcVolState ) == TRUE )
  170. {
  171. //
  172. // Already exists in the list, return it. Also delete the vol state
  173. // object that's not needed.
  174. //
  175. delete pcFsdVolumeState;
  176. return ERROR_ALREADY_EXISTS;
  177. }
  178. //
  179. // Not found, insert it into the list
  180. //
  181. lRet = m_cVolumeStateList.Insert( sVolId, pcFsdVolumeState );
  182. if ( lRet != BSHASHMAP_NO_ERROR )
  183. {
  184. assert( lRet != BSHASHMAP_ALREADY_EXISTS );
  185. delete pcFsdVolumeState;
  186. return ERROR_CAN_NOT_COMPLETE;
  187. }
  188. //
  189. // Now get the exclusion processor for this volume if necessary
  190. //
  191. if ( m_pcExclManager != NULL )
  192. {
  193. m_pcExclManager->GetFileSystemExcludeProcessor( cwsVolumePath, &sVolId, &pcFsdVolumeState->m_pcFSExclProcessor );
  194. }
  195. CFsdVolumeState *pcFindFsdVolumeState;
  196. *ppcVolState = pcFsdVolumeState;
  197. return ERROR_SUCCESS;
  198. }
  199. catch ( HRESULT hr )
  200. {
  201. if ( hr == E_OUTOFMEMORY )
  202. m_pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeState - Out of memory ( '%s' )",
  203. cwsVolumePath.c_str() );
  204. else
  205. m_pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeState - Unexpected hr exception: 0x%08x ( '%s )",
  206. hr, cwsVolumePath.c_str() );
  207. return ERROR_CAN_NOT_COMPLETE;
  208. }
  209. catch ( ... )
  210. {
  211. m_pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeState - '%s' caught an unexpected exception",
  212. cwsVolumePath.c_str() );
  213. return ERROR_CAN_NOT_COMPLETE;
  214. }
  215. }
  216. /*++
  217. Routine Description:
  218. Gets the ID of the volume containing any file.
  219. Arguments:
  220. Return Value:
  221. ERROR_CAN_NOT_COMPLETE - General error
  222. --*/
  223. DWORD
  224. CFsdVolumeStateManager::GetVolumeIdAndPath(
  225. IN CDumpParameters *pcParams,
  226. IN const CBsString& cwsPathOnVolume,
  227. OUT SFsdVolumeId *psVolId,
  228. OUT CBsString& cwsVolPath
  229. )
  230. {
  231. try
  232. {
  233. psVolId->m_dwVolSerialNumber = 0;
  234. WCHAR wszVolumePath[ FSD_MAX_PATH ];
  235. //
  236. // First get the mountpoint of the volume
  237. //
  238. if ( !GetVolumePathNameW(
  239. cwsPathOnVolume,
  240. wszVolumePath,
  241. FSD_MAX_PATH ) )
  242. {
  243. pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeIdAndPath - GetVolumePathName( '%s', ... ) returned dwRet: %d",
  244. cwsPathOnVolume.c_str(), ::GetLastError() );
  245. return ::GetLastError();
  246. }
  247. //
  248. // Now open the volume in order to query filesystem info
  249. //
  250. HANDLE hFile;
  251. hFile = ::CreateFileW(
  252. wszVolumePath,
  253. FILE_GENERIC_READ,
  254. FILE_SHARE_READ,
  255. NULL,
  256. OPEN_EXISTING,
  257. FILE_FLAG_BACKUP_SEMANTICS,
  258. NULL );
  259. if ( hFile == INVALID_HANDLE_VALUE )
  260. {
  261. //pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeIdAndPath - CreateFile( '%s', ... ) returned dwRet: %d",
  262. // wszVolumePath, ::GetLastError() );
  263. return ::GetLastError();
  264. }
  265. IO_STATUS_BLOCK iosb ;
  266. BYTE buffer[1024] ;
  267. FILE_FS_VOLUME_INFORMATION *fsinfo = (FILE_FS_VOLUME_INFORMATION *)buffer;
  268. fsinfo->VolumeSerialNumber = 0;
  269. NTSTATUS ntStat;
  270. ntStat = ::NtQueryVolumeInformationFile( hFile, &iosb, fsinfo, sizeof(buffer), FileFsVolumeInformation );
  271. ::CloseHandle( hFile );
  272. if ( ntStat != STATUS_SUCCESS )
  273. {
  274. pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeIdAndPath - NtQueryVolumeInformationFile( '%s', ... ) returned dwRet: %0x08x",
  275. wszVolumePath, ntStat );
  276. return ERROR_CAN_NOT_COMPLETE;
  277. }
  278. psVolId->m_dwVolSerialNumber = fsinfo->VolumeSerialNumber;
  279. cwsVolPath = wszVolumePath;
  280. }
  281. catch ( ... )
  282. {
  283. pcParams->ErrPrint( L"CFsdVolumeStateManager::GetVolumeIdAndPath - '%s' caught an unexpected exception",
  284. cwsPathOnVolume.c_str() );
  285. return ERROR_CAN_NOT_COMPLETE;
  286. }
  287. return ERROR_SUCCESS;
  288. }