Leaked source code of windows server 2003
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.

564 lines
14 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. RsClnVol.cpp
  5. Abstract:
  6. Implements CRsClnVolume. This class represents a volume on a Remote
  7. Storage server which might contain Remote Storage files. This class
  8. examines the volume for Remote Storage files and cleans it upon request.
  9. Cleaning means removing all Remote Storage reparse points and truncated
  10. files. CRsClnVolume creates zero or more instances of CRsClnFile and is
  11. created by CRsClnServer.
  12. Author:
  13. Carl Hagerstrom [carlh] 20-Aug-1998
  14. Revision History:
  15. --*/
  16. #include <stdafx.h>
  17. /*++
  18. Implements:
  19. CRsClnVolume Constructor
  20. Routine Description:
  21. Initializes object.
  22. --*/
  23. CRsClnVolume::CRsClnVolume( CRsClnServer* pServer, WCHAR* StickyName ) :
  24. m_pServer( pServer ), m_StickyName( StickyName )
  25. {
  26. TRACEFN("CRsClnVolume::CRsClnVolume");
  27. memset((void *)m_fsName, 0, sizeof(m_fsName));
  28. memset((void *)m_bestName, 0, sizeof(m_bestName));
  29. memset((void *)m_volumeName, 0, sizeof(m_volumeName));
  30. memset((void *)m_dosName, 0, sizeof(m_dosName));
  31. m_fsFlags = 0;
  32. m_hRpi = INVALID_HANDLE_VALUE;
  33. m_hVolume = INVALID_HANDLE_VALUE;
  34. }
  35. /*++
  36. Implements:
  37. CRsClnVolume Destructor
  38. --*/
  39. CRsClnVolume::~CRsClnVolume()
  40. {
  41. TRACEFN("CRsClnVolume::~CRsClnVolume");
  42. if( INVALID_HANDLE_VALUE != m_hVolume ) CloseHandle( m_hVolume );
  43. }
  44. /*++
  45. Implements:
  46. CRsClnVolume::VolumeHasRsData
  47. Routine Description:
  48. Determines whether this volume contains Remote Storage data.
  49. If this volume is on a fixed local disk, and it is an
  50. NTFS volume which supports reparse points and sparce
  51. files, and it has at least one Remote Storage reparse point,
  52. it contains Remote Storage data.
  53. Arguments:
  54. hasData - returned: whether volume contains Remote
  55. Storage data
  56. Return Value:
  57. S_OK - Success
  58. HRESULT - Any unexpected exceptions from lower level routines
  59. --*/
  60. HRESULT CRsClnVolume::VolumeHasRsData(BOOL *hasData)
  61. {
  62. TRACEFNHR("CRsClnVolume::VolumeHasRsData");
  63. LONGLONG fileReference;
  64. BOOL foundOne;
  65. *hasData = FALSE;
  66. try {
  67. if( DRIVE_FIXED == GetDriveType( m_StickyName ) ) {
  68. RsOptAffirmDw( GetVolumeInfo( ) );
  69. if( _wcsicmp( m_fsName, L"NTFS" ) == 0 &&
  70. m_fsFlags & FILE_SUPPORTS_REPARSE_POINTS &&
  71. m_fsFlags & FILE_SUPPORTS_SPARSE_FILES ) {
  72. RsOptAffirmDw( FirstRsReparsePoint( &fileReference, &foundOne ) );
  73. if( foundOne ) {
  74. *hasData = TRUE;
  75. }
  76. }
  77. }
  78. }
  79. RsOptCatch( hrRet );
  80. return hrRet;
  81. }
  82. /*++
  83. Implements:
  84. CRsClnVolume::GetBestName
  85. Routine Description:
  86. Returns the best user friendly name for this volume. The best
  87. name is either the DOS drive letter if one exists, the user
  88. assigned volume name if one exists, or the sticky name which
  89. always exists.
  90. Arguments:
  91. bestName - returned: user friendly volume name
  92. Return Value:
  93. S_OK - Success
  94. HRESULT - Any unexpected exceptions from lower level routines
  95. --*/
  96. CString CRsClnVolume::GetBestName( )
  97. {
  98. TRACEFNHR("CRsClnVolume::GetBestName");
  99. return( m_bestName );
  100. }
  101. /*++
  102. Implements:
  103. CRsClnVolume::RemoveRsDataFromVolume
  104. Routine Description:
  105. Removes all Remote Storage data from this volume.
  106. - Opens this volume using the sticky name.
  107. - Enumerates each file in the reparse point index
  108. with a Remote Storage reparse point. In the reparse
  109. index, each file is represented by a number called the
  110. file reference.
  111. - Removes the reparse point and the file if it is
  112. truncated.
  113. Arguments:
  114. Return Value:
  115. S_OK - Success
  116. HRESULT - Any unexpected exceptions from lower level routines
  117. --*/
  118. HRESULT CRsClnVolume::RemoveRsDataFromVolume( )
  119. {
  120. TRACEFNHR("CRsClnVolume::RemoveRsDataFromVolume");
  121. LONGLONG fileReference;
  122. BOOL foundOne;
  123. try
  124. {
  125. RsOptAffirmDw( GetVolumeInfo( ) );
  126. for( BOOL firstLoop = TRUE;; firstLoop = FALSE ) {
  127. if( firstLoop ) {
  128. RsOptAffirmDw( FirstRsReparsePoint( &fileReference, &foundOne ) );
  129. } else {
  130. RsOptAffirmDw( NextRsReparsePoint( &fileReference, &foundOne ) );
  131. }
  132. if( !foundOne ) {
  133. break;
  134. }
  135. //
  136. // Just in case something strange happens in removing reparse
  137. // point or such, wrap in its own try block
  138. //
  139. HRESULT hrRemove = S_OK;
  140. try {
  141. CRsClnFile fileObj( this, fileReference );
  142. if( FAILED( fileObj.RemoveReparsePointAndFile( ) ) ) {
  143. m_pServer->AddErrorFile( fileObj.GetFileName( ) );
  144. }
  145. } RsOptCatch( hrRemove );
  146. // Do not affirm hrRemove - we don't want to stop on an error
  147. }
  148. } RsOptCatch( hrRet );
  149. return( hrRet );
  150. }
  151. /*++
  152. Implements:
  153. CRsClnVolume::GetVolumeInfo
  154. Routine Description:
  155. Load information about this volume.
  156. - Get the sticky name and the user assigned volume name,
  157. if one exists.
  158. - See if there is a DOS drive letter for this volume.
  159. For each possible drive letter, see if it represents
  160. a volume whose sticky name matches this volume.
  161. - Choose the best user friendly volume name according
  162. to the following precedence: DOS drive letter, user
  163. assigned volume name, sticky name.
  164. Arguments:
  165. Return Value:
  166. S_OK - Success
  167. HRESULT - Any unexpected exceptions from lower level routines
  168. --*/
  169. HRESULT CRsClnVolume::GetVolumeInfo( )
  170. {
  171. TRACEFNHR("CRsClnVolume::GetVolumeInfo");
  172. WCHAR dosName[MAX_DOS_NAME];
  173. WCHAR stickyName2[MAX_STICKY_NAME];
  174. DWORD volumeSerial;
  175. DWORD maxCompLen;
  176. BOOL bStatus;
  177. try {
  178. bStatus = GetVolumeInformation( m_StickyName,
  179. m_volumeName,
  180. (sizeof(m_volumeName)) / (sizeof(m_volumeName[0])),
  181. &volumeSerial,
  182. &maxCompLen,
  183. &m_fsFlags,
  184. m_fsName,
  185. (sizeof(m_fsName)) / (sizeof(m_fsName[0]))
  186. );
  187. RsOptAffirmStatus(bStatus);
  188. for (wcscpy(dosName, L"A:\\"); dosName[0] <= L'Z'; ++(dosName[0]))
  189. {
  190. if (GetVolumeNameForVolumeMountPoint(dosName,
  191. stickyName2,
  192. (sizeof(stickyName2) / sizeof(stickyName2[0])) ))
  193. {
  194. if( m_StickyName.CompareNoCase( stickyName2 ) == 0 )
  195. {
  196. wcscpy(m_dosName, dosName);
  197. break;
  198. }
  199. }
  200. }
  201. if (*m_dosName != L'\0')
  202. {
  203. wcscpy(m_bestName, m_dosName);
  204. }
  205. else if (*m_volumeName != L'\0')
  206. {
  207. wcscpy(m_bestName, m_volumeName);
  208. }
  209. else
  210. {
  211. wcscpy(m_bestName, m_StickyName);
  212. }
  213. m_hVolume = CreateFile( m_StickyName.Left( m_StickyName.GetLength() - 1 ),
  214. GENERIC_READ,
  215. FILE_SHARE_READ | FILE_SHARE_WRITE,
  216. (LPSECURITY_ATTRIBUTES)0,
  217. OPEN_EXISTING,
  218. (DWORD)0,
  219. (HANDLE)0 );
  220. RsOptAffirmHandle( m_hVolume );
  221. }
  222. RsOptCatch(hrRet);
  223. return hrRet;
  224. }
  225. /*++
  226. Implements:
  227. CRsClnVolume::FirstRsReparsePoint
  228. Routine Description:
  229. Returns the file reference of the first file in the
  230. reparse point index which contains a Remote Storage
  231. reparse point, if one exists.
  232. - Construct the name of the reparse point index from
  233. the sticky name.
  234. - Open the index.
  235. - Read the first entry. If it is a Remote Storage
  236. entry, return it. Otherwise, try the next one.
  237. Arguments:
  238. stickyName - long volume name
  239. fileReference - returned: file reference from first
  240. Remote Storage reparse index entry.
  241. The file reference is a number which
  242. can be used to open a file.
  243. foundOne - returned: TRUE if there is at least one
  244. Remote Storage reparse point
  245. Return Value:
  246. S_OK - Success
  247. HRESULT - Any unexpected exceptions from lower level routines
  248. --*/
  249. HRESULT CRsClnVolume::FirstRsReparsePoint(
  250. LONGLONG* fileReference,
  251. BOOL* foundOne)
  252. {
  253. TRACEFNHR("CRsClnVolume::FirstRsReparsePoint");
  254. NTSTATUS ntStatus;
  255. IO_STATUS_BLOCK ioStatusBlock;
  256. FILE_REPARSE_POINT_INFORMATION reparsePointInfo;
  257. WCHAR rpiSuffix[] = L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION";
  258. WCHAR rpiName[MAX_STICKY_NAME + (sizeof(rpiSuffix) / sizeof(WCHAR))];
  259. wcscpy(rpiName, m_StickyName);
  260. wcscat(rpiName, rpiSuffix);
  261. *foundOne = FALSE;
  262. try
  263. {
  264. m_hRpi = CreateFile(rpiName,
  265. GENERIC_READ,
  266. FILE_SHARE_READ,
  267. (LPSECURITY_ATTRIBUTES)0,
  268. OPEN_EXISTING,
  269. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  270. (HANDLE)0);
  271. if (m_hRpi != INVALID_HANDLE_VALUE)
  272. {
  273. ntStatus = NtQueryDirectoryFile(m_hRpi,
  274. (HANDLE)0,
  275. (PIO_APC_ROUTINE)0,
  276. (PVOID)0,
  277. &ioStatusBlock,
  278. &reparsePointInfo,
  279. sizeof(reparsePointInfo),
  280. FileReparsePointInformation,
  281. TRUE,
  282. (PUNICODE_STRING)0,
  283. TRUE);
  284. if (ntStatus == STATUS_NO_MORE_FILES)
  285. {
  286. RsOptAffirmStatus(CloseHandle(m_hRpi));
  287. }
  288. else
  289. {
  290. RsOptAffirmNtStatus(ntStatus);
  291. if (reparsePointInfo.Tag == IO_REPARSE_TAG_HSM)
  292. {
  293. *fileReference = reparsePointInfo.FileReference;
  294. *foundOne = TRUE;
  295. }
  296. else
  297. {
  298. RsOptAffirmDw(NextRsReparsePoint(fileReference, foundOne));
  299. }
  300. }
  301. }
  302. }
  303. RsOptCatch(hrRet);
  304. return hrRet;
  305. }
  306. /*++
  307. Implements:
  308. CRsClnVolume::NextRsReparsePoint
  309. Routine Description:
  310. Continue searching the reparse point index on this volume and
  311. return the file reference for the next Remote Storage reparse
  312. point.
  313. Arguments:
  314. fileReference - returned: file reference from first
  315. Remote Storage reparse index entry.
  316. The file reference is a number which
  317. can be used to open a file.
  318. foundOne - returned: FALSE if there are no more Remote
  319. Storage reparse points
  320. Return Value:
  321. S_OK - Success
  322. HRESULT - Any unexpected exceptions from lower level routines
  323. --*/
  324. HRESULT CRsClnVolume::NextRsReparsePoint(
  325. LONGLONG* fileReference,
  326. BOOL* foundOne)
  327. {
  328. TRACEFNHR("CRsClnVolume::NextRsReparsePoint");
  329. NTSTATUS ntStatus;
  330. IO_STATUS_BLOCK ioStatusBlock;
  331. FILE_REPARSE_POINT_INFORMATION reparsePointInfo;
  332. *foundOne = FALSE;
  333. try
  334. {
  335. for (;;)
  336. {
  337. ntStatus = NtQueryDirectoryFile(m_hRpi,
  338. (HANDLE)0,
  339. (PIO_APC_ROUTINE)0,
  340. (PVOID)0,
  341. &ioStatusBlock,
  342. &reparsePointInfo,
  343. sizeof(reparsePointInfo),
  344. FileReparsePointInformation,
  345. TRUE,
  346. (PUNICODE_STRING)0,
  347. FALSE);
  348. if (ntStatus == STATUS_NO_MORE_FILES)
  349. {
  350. RsOptAffirmStatus(CloseHandle(m_hRpi));
  351. break;
  352. }
  353. else
  354. {
  355. RsOptAffirmNtStatus(ntStatus);
  356. if (reparsePointInfo.Tag == IO_REPARSE_TAG_HSM)
  357. {
  358. *fileReference = reparsePointInfo.FileReference;
  359. *foundOne = TRUE;
  360. break;
  361. }
  362. }
  363. }
  364. }
  365. RsOptCatch(hrRet);
  366. return hrRet;
  367. }
  368. /*++
  369. Implements:
  370. CRsClnVolume::GetHandle
  371. Routine Description:
  372. Returns a handle to the volume.
  373. Arguments:
  374. Return Value:
  375. Volume HANDLE
  376. --*/
  377. HANDLE CRsClnVolume::GetHandle( )
  378. {
  379. return( m_hVolume );
  380. }
  381. /*++
  382. Implements:
  383. CRsClnVolume::GetStickyName
  384. Routine Description:
  385. Returns the sticky name of the volume.
  386. Arguments:
  387. Return Value:
  388. Volume sticky name
  389. --*/
  390. CString CRsClnVolume::GetStickyName( )
  391. {
  392. return( m_StickyName );
  393. }