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.

1326 lines
31 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved
  3. Module Name:
  4. RmsDrive.cpp
  5. Abstract:
  6. Implementation of CRmsDrive
  7. Author:
  8. Brian Dodd [brian] 15-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "RmsDrive.h"
  13. #include "RmsServr.h"
  14. int CRmsDrive::s_InstanceCount = 0;
  15. #define RMS_CRITICAL_SECTION 1
  16. ////////////////////////////////////////////////////////////////////////////////
  17. //
  18. STDMETHODIMP
  19. CRmsDrive::CompareTo(
  20. IN IUnknown *pCollectable,
  21. OUT SHORT *pResult
  22. )
  23. /*++
  24. Implements:
  25. IWsbCollectable::CompareTo
  26. --*/
  27. {
  28. HRESULT hr = E_FAIL;
  29. SHORT result = 1;
  30. WsbTraceIn( OLESTR("CRmsDrive::CompareTo"), OLESTR("") );
  31. try {
  32. // Validate arguments - Okay if pResult is NULL
  33. WsbAssertPointer( pCollectable );
  34. // !!!!!
  35. //
  36. // IMPORTANT: The collectable coming in may not be a CRmsDrive if the collection
  37. // is the unconfigured device list.
  38. //
  39. // !!!!!
  40. CComQIPtr<IRmsComObject, &IID_IRmsComObject> pObject = pCollectable;
  41. // Every collectable should be an CRmsComObject
  42. WsbAssertPointer( pObject );
  43. switch ( m_findBy ) {
  44. case RmsFindByDeviceInfo:
  45. case RmsFindByDeviceAddress:
  46. case RmsFindByDeviceName:
  47. case RmsFindByDeviceType:
  48. // Do CompareTo for device
  49. hr = CRmsDevice::CompareTo( pCollectable, &result );
  50. break;
  51. case RmsFindByElementNumber:
  52. case RmsFindByMediaSupported:
  53. // Do CompareTo for changer element
  54. hr = CRmsChangerElement::CompareTo( pCollectable, &result );
  55. break;
  56. case RmsFindByObjectId:
  57. default:
  58. // Do CompareTo for object
  59. hr = CRmsComObject::CompareTo( pCollectable, &result );
  60. break;
  61. }
  62. }
  63. WsbCatch( hr );
  64. if ( SUCCEEDED(hr) && (0 != pResult) ){
  65. *pResult = result;
  66. }
  67. WsbTraceOut( OLESTR("CRmsDrive::CompareTo"),
  68. OLESTR("hr = <%ls>, result = <%ls>"),
  69. WsbHrAsString( hr ), WsbPtrToShortAsString( pResult ) );
  70. return hr;
  71. }
  72. STDMETHODIMP
  73. CRmsDrive::FinalConstruct(
  74. void
  75. )
  76. /*++
  77. Implements:
  78. CComObjectRoot::FinalConstruct
  79. --*/
  80. {
  81. HRESULT hr = S_OK;
  82. WsbTraceIn(OLESTR("CRmsDrive::FinalConstruct"), OLESTR(""));
  83. try {
  84. m_bCritSecCreated = FALSE;
  85. m_UnloadNowEvent = NULL;
  86. m_UnloadedEvent = NULL;
  87. WsbAssertHr(CWsbObject::FinalConstruct());
  88. // Initialize values
  89. m_MountReference = 0;
  90. m_UnloadNowTime.dwHighDateTime = 0;
  91. m_UnloadNowTime.dwLowDateTime = 0;
  92. m_UnloadThreadHandle = NULL;
  93. WsbAffirmStatus(InitializeCriticalSectionAndSpinCount(&m_CriticalSection, 0));
  94. m_bCritSecCreated = TRUE;
  95. WsbAffirmHandle(m_UnloadNowEvent = CreateEvent(NULL, FALSE, FALSE, NULL));
  96. WsbAffirmHandle(m_UnloadedEvent = CreateEvent(NULL, TRUE, TRUE, NULL));
  97. } WsbCatch(hr);
  98. s_InstanceCount++;
  99. WsbTraceAlways(OLESTR("CRmsDrive::s_InstanceCount += %d\n"), s_InstanceCount);
  100. WsbTraceOut(OLESTR("CRmsDrive::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  101. return(hr);
  102. }
  103. STDMETHODIMP
  104. CRmsDrive::FinalRelease(void)
  105. {
  106. HRESULT hr = S_OK;
  107. WsbTraceIn(OLESTR("CRmsDrive::FinalRelease"), OLESTR(""));
  108. try {
  109. if (m_bCritSecCreated) {
  110. DeleteCriticalSection(&m_CriticalSection);
  111. }
  112. if (m_UnloadNowEvent) {
  113. CloseHandle(m_UnloadNowEvent);
  114. }
  115. if (m_UnloadedEvent) {
  116. CloseHandle(m_UnloadedEvent);
  117. }
  118. CWsbObject::FinalRelease();
  119. } WsbCatch(hr);
  120. s_InstanceCount--;
  121. WsbTraceAlways(OLESTR("CRmsDrive::s_InstanceCount -= %d\n"), s_InstanceCount);
  122. WsbTraceOut(OLESTR("CRmsDrive::FinalRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  123. return(hr);
  124. }
  125. STDMETHODIMP
  126. CRmsDrive::GetClassID(
  127. OUT CLSID* pClsid
  128. )
  129. /*++
  130. Implements:
  131. IPersist::GetClassId
  132. --*/
  133. {
  134. HRESULT hr = S_OK;
  135. WsbTraceIn(OLESTR("CRmsDrive::GetClassID"), OLESTR(""));
  136. try {
  137. WsbAssert(0 != pClsid, E_POINTER);
  138. *pClsid = CLSID_CRmsDrive;
  139. } WsbCatch(hr);
  140. WsbTraceOut(OLESTR("CRmsDrive::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  141. return(hr);
  142. }
  143. STDMETHODIMP
  144. CRmsDrive::GetSizeMax(
  145. OUT ULARGE_INTEGER* pcbSize
  146. )
  147. /*++
  148. Implements:
  149. IPersistStream::GetSizeMax
  150. --*/
  151. {
  152. HRESULT hr = E_NOTIMPL;
  153. WsbTraceIn(OLESTR("CRmsDrive::GetSizeMax"), OLESTR(""));
  154. // try {
  155. // WsbAssert(0 != pcbSize, E_POINTER);
  156. // // Set up max size
  157. // pcbSize->QuadPart = WsbPersistSizeOf(LONG); // m_MountReference
  158. // } WsbCatch(hr);
  159. WsbTraceOut(OLESTR("CRmsDrive::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pcbSize));
  160. return(hr);
  161. }
  162. STDMETHODIMP
  163. CRmsDrive::Load(
  164. IN IStream* pStream
  165. )
  166. /*++
  167. Implements:
  168. IPersistStream::Load
  169. --*/
  170. {
  171. HRESULT hr = S_OK;
  172. ULONG ulBytes = 0;
  173. WsbTraceIn(OLESTR("CRmsDrive::Load"), OLESTR(""));
  174. try {
  175. WsbAssert(0 != pStream, E_POINTER);
  176. WsbAffirmHr(CRmsDevice::Load(pStream));
  177. // Read value
  178. WsbAffirmHr(WsbLoadFromStream(pStream, &m_MountReference));
  179. // We just reset to zero, one day we could try to reconnect to
  180. // the process that issued the mount...
  181. m_MountReference = 0;
  182. }
  183. WsbCatch(hr);
  184. WsbTraceOut(OLESTR("CRmsDrive::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  185. return(hr);
  186. }
  187. STDMETHODIMP
  188. CRmsDrive::Save(
  189. IN IStream* pStream,
  190. IN BOOL clearDirty
  191. )
  192. /*++
  193. Implements:
  194. IPersistStream::Save
  195. --*/
  196. {
  197. HRESULT hr = S_OK;
  198. ULONG ulBytes = 0;
  199. WsbTraceIn(OLESTR("CRmsDrive::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
  200. try {
  201. WsbAssert(0 != pStream, E_POINTER);
  202. WsbAffirmHr(CRmsDevice::Save(pStream, clearDirty));
  203. // Write value
  204. WsbAffirmHr(WsbSaveToStream(pStream, m_MountReference));
  205. // Do we need to clear the dirty bit?
  206. if (clearDirty) {
  207. m_isDirty = FALSE;
  208. }
  209. } WsbCatch(hr);
  210. WsbTraceOut(OLESTR("CRmsDrive::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  211. return(hr);
  212. }
  213. STDMETHODIMP
  214. CRmsDrive::Test(
  215. OUT USHORT *pPassed,
  216. OUT USHORT *pFailed
  217. )
  218. /*++
  219. Implements:
  220. IWsbTestable::Test
  221. --*/
  222. {
  223. HRESULT hr = S_OK;
  224. CComPtr<IRmsDrive> pDrive1;
  225. CComPtr<IRmsDrive> pDrive2;
  226. CComPtr<IPersistFile> pFile1;
  227. CComPtr<IPersistFile> pFile2;
  228. LONG i;
  229. LONG longWork1;
  230. WsbTraceIn(OLESTR("CRmsDrive::Test"), OLESTR(""));
  231. try {
  232. // Get the Drive interface.
  233. hr = S_OK;
  234. try {
  235. WsbAssertHr(((IUnknown*) (IRmsDrive*) this)->QueryInterface(IID_IRmsDrive, (void**) &pDrive1));
  236. // Test All of MountReference Functions
  237. ResetMountReference();
  238. GetMountReference(&longWork1);
  239. if(longWork1 == 0) {
  240. (*pPassed)++;
  241. } else {
  242. (*pFailed)++;
  243. }
  244. for(i = 1; i < 20; i++){
  245. AddMountReference();
  246. GetMountReference(&longWork1);
  247. if(longWork1 == i){
  248. (*pPassed)++;
  249. } else {
  250. (*pFailed)++;
  251. }
  252. }
  253. for(i = 19; i == 0; i--){
  254. ReleaseMountReference();
  255. GetMountReference(&longWork1);
  256. if(longWork1 == i){
  257. (*pPassed)++;
  258. } else {
  259. (*pFailed)++;
  260. }
  261. }
  262. } WsbCatch(hr);
  263. // Tally up the results
  264. hr = S_OK;
  265. if (*pFailed) {
  266. hr = S_FALSE;
  267. }
  268. } WsbCatch(hr);
  269. WsbTraceOut(OLESTR("CRmsDrive::Test"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  270. return(hr);
  271. }
  272. STDMETHODIMP
  273. CRmsDrive::GetMountReference(
  274. OUT LONG *pRefs
  275. )
  276. /*++
  277. Implements:
  278. IRmsDrive::GetMountReference
  279. --*/
  280. {
  281. HRESULT hr = S_OK;
  282. WsbTraceIn(OLESTR("CRmsDrive::GetMountReference"), OLESTR(""));
  283. LONG refs = -999;
  284. try {
  285. WsbAssertPointer(pRefs);
  286. refs = m_MountReference;
  287. *pRefs = refs;
  288. } WsbCatch(hr)
  289. WsbTraceOut(OLESTR("CRmsDrive::GetMountReference"), OLESTR("hr = <%ls>, refs = %d"),
  290. WsbHrAsString(hr), refs);
  291. return hr;
  292. }
  293. STDMETHODIMP
  294. CRmsDrive::ResetMountReference(
  295. void
  296. )
  297. /*++
  298. Implements:
  299. IRmsDrive::ResetMountReference
  300. --*/
  301. {
  302. HRESULT hr = S_OK;
  303. WsbTraceIn(OLESTR("CRmsDrive::ResetMountReference"), OLESTR(""));
  304. #if RMS_CRITICAL_SECTION
  305. try {
  306. // <<<<< ENTER SINGLE THREADED SECTION
  307. WsbAffirmHr(Lock());
  308. m_MountReference = 0;
  309. m_isDirty = TRUE;
  310. WsbAffirmHr(Unlock());
  311. // >>>>> LEAVE SINGLE THREADED SECTION
  312. } WsbCatch(hr)
  313. #else
  314. InterlockedExchange( &m_MountReference, 0);
  315. m_isDirty = TRUE;
  316. #endif
  317. WsbTraceOut(OLESTR("CRmsDrive::ResetMountReference"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  318. return hr;
  319. }
  320. STDMETHODIMP
  321. CRmsDrive::AddMountReference(
  322. void
  323. )
  324. /*++
  325. Implements:
  326. IRmsDrive::AddMountReference
  327. --*/
  328. {
  329. HRESULT hr = S_OK;
  330. WsbTraceIn(OLESTR("CRmsDrive::AddMountReference"), OLESTR(""));
  331. LONG refs = -999;
  332. #if RMS_CRITICAL_SECTION
  333. try {
  334. // <<<<< ENTER SINGLE THREADED SECTION
  335. WsbAffirmHr(Lock());
  336. m_MountReference++;
  337. m_isDirty = TRUE;
  338. refs = m_MountReference;
  339. WsbAffirmStatus(ResetEvent(m_UnloadedEvent));
  340. WsbAffirmHr(Unlock());
  341. // >>>>> LEAVE SINGLE THREADED SECTION
  342. } WsbCatch(hr)
  343. #else
  344. refs = InterlockedIncrement( &m_MountReference );
  345. m_isDirty = TRUE;
  346. #endif
  347. WsbTraceOut(OLESTR("CRmsDrive::AddMountReference"), OLESTR("hr = <%ls>, refs = %d"),
  348. WsbHrAsString(hr), refs);
  349. return hr;
  350. }
  351. STDMETHODIMP
  352. CRmsDrive::ReleaseMountReference(
  353. IN DWORD dwOptions
  354. )
  355. /*++
  356. Implements:
  357. IRmsDrive::ReleaseMountReference
  358. --*/
  359. {
  360. HRESULT hr S_OK;
  361. WsbTraceIn(OLESTR("CRmsDrive::ReleaseMountReference"), OLESTR("<%ld>"), dwOptions);
  362. // We need to be sure this object doesn't go away until we're done.
  363. // This happens when we dismount a NTMS managed cartridge.
  364. CComPtr<IRmsDrive> thisDrive = this;
  365. LONG refs = -999;
  366. BOOL bUnloadNow =
  367. ( (dwOptions & RMS_DISMOUNT_IMMEDIATE) || (dwOptions & RMS_DISMOUNT_DEFERRED_ONLY) ) ? TRUE : FALSE;
  368. try {
  369. #if RMS_CRITICAL_SECTION
  370. // <<<<< ENTER SINGLE THREADED SECTION
  371. WsbAffirmHr(Lock());
  372. m_MountReference--;
  373. m_isDirty = TRUE;
  374. refs = m_MountReference;
  375. #else
  376. refs = InterlockedDecrement( &m_MountReference );
  377. m_isDirty = TRUE;
  378. #endif
  379. // Note:
  380. // Even if the caller requests immediate dismount, if the ref count is > 0,
  381. // the media is not dismounted (only the ref count is decreased).
  382. // This is necessary because positive ref count means that some other component
  383. // is also using the media (possible for Optical). The media must be dismounted
  384. // only when this other component is done as well.
  385. if (refs < 0) {
  386. //
  387. // This shouldn't happen under normal conditions... if it does,
  388. // we quiety reset the the reference count and try to recover.
  389. //
  390. WsbLogEvent(E_UNEXPECTED, sizeof(refs), &refs, NULL);
  391. InterlockedExchange( &m_MountReference, 0);
  392. refs = 0;
  393. // If we don't have a cartridge in the drive, there's no point
  394. // in continueing.
  395. WsbAffirm(S_OK == IsOccupied(), E_ABORT);
  396. }
  397. if (0 == refs) {
  398. //
  399. // Deferred Dismount Logic: We wait the specified time before
  400. // dismounting the media. Each dismount request resets the dismount
  401. // now time. As long as the media is actively used, it will not be
  402. // dismounted.
  403. //
  404. // Retrieve the DeferredDismountWaitTime parameter
  405. DWORD size;
  406. OLECHAR tmpString[256];
  407. DWORD waitTime = RMS_DEFAULT_DISMOUNT_WAIT_TIME;
  408. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_DISMOUNT_WAIT_TIME, tmpString, 256, &size))) {
  409. waitTime = wcstol(tmpString, NULL, 10);
  410. WsbTrace(OLESTR("DismountWaitTime is %d milliseconds.\n"), waitTime);
  411. }
  412. if (waitTime > 0 && !bUnloadNow) {
  413. // convert waitTime to 100-nanosecond units
  414. waitTime *= 10000;
  415. FILETIME now;
  416. GetSystemTimeAsFileTime(&now);
  417. ULARGE_INTEGER time;
  418. time.LowPart = now.dwLowDateTime;
  419. time.HighPart = now.dwHighDateTime;
  420. time.QuadPart += waitTime;
  421. m_UnloadNowTime.dwLowDateTime = time.LowPart;
  422. m_UnloadNowTime.dwHighDateTime = time.HighPart;
  423. WsbTrace(OLESTR("Target Unload Time = <%ls>\n"),
  424. WsbQuickString(WsbFiletimeAsString(FALSE, m_UnloadNowTime)));
  425. // If we already have an active unload thread we skip this step.
  426. if (!m_UnloadThreadHandle) {
  427. //
  428. // Create a thread to wait for dismount
  429. //
  430. WsbTrace(OLESTR("Starting thread for deferred dismount.\n"));
  431. DWORD threadId;
  432. WsbAffirmHandle(m_UnloadThreadHandle = CreateThread(NULL, 1024, CRmsDrive::StartUnloadThread, this, 0, &threadId));
  433. CloseHandle(m_UnloadThreadHandle);
  434. }
  435. }
  436. else {
  437. // Dismount the media now
  438. // Double check that we still have something to dismount
  439. if (S_OK == IsOccupied()) {
  440. // Best effort - home
  441. // Fixed drives are always occupied and we shouldn't call Home for their cartridge
  442. FlushBuffers();
  443. if (RmsDeviceFixedDisk != m_deviceType) {
  444. if (S_OK == m_pCartridge->Home(dwOptions)) {
  445. SetIsOccupied(FALSE);
  446. }
  447. }
  448. }
  449. // set event that blocks immediate unload
  450. SetEvent(m_UnloadedEvent);
  451. }
  452. }
  453. #if RMS_CRITICAL_SECTION
  454. WsbAffirmHr(Unlock());
  455. // >>>>> LEAVE SINGLE THREADED SECTION
  456. } WsbCatchAndDo(hr,
  457. WsbAffirmHr(Unlock());
  458. // >>>>> LEAVE SINGLE THREADED SECTION
  459. );
  460. #else
  461. } WsbCatch(hr)
  462. #endif
  463. WsbTraceOut(OLESTR("CRmsDrive::ReleaseMountReference"), OLESTR("hr = <%ls>, refs = %d"),
  464. WsbHrAsString(hr), refs);
  465. return hr;
  466. }
  467. STDMETHODIMP
  468. CRmsDrive::SelectForMount(
  469. void
  470. )
  471. /*++
  472. Implements:
  473. IRmsDrive::SelectForMount
  474. --*/
  475. {
  476. HRESULT hr = S_OK;
  477. WsbTraceIn(OLESTR("CRmsDrive::SelectForMount"), OLESTR(""));
  478. #if RMS_CRITICAL_SECTION
  479. try {
  480. // <<<<< ENTER SINGLE THREADED SECTION
  481. WsbAffirmHr(Lock());
  482. if (!m_MountReference) {
  483. m_MountReference++;
  484. m_isDirty = TRUE;
  485. } else {
  486. hr = RMS_E_DRIVE_BUSY;
  487. }
  488. WsbAffirmHr(Unlock());
  489. // >>>>> LEAVE SINGLE THREADED SECTION
  490. } WsbCatch(hr)
  491. #else
  492. LONG one = 1;
  493. LONG zero = 0;
  494. LONG flag = InterlockedCompareExchange( &m_MountReference, one, zero );
  495. hr = ( flag > 0 ) ? RMS_E_DRIVE_BUSY : S_OK;
  496. #endif
  497. WsbTraceOut(OLESTR("CRmsDrive::SelectForMount"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  498. return hr;
  499. }
  500. STDMETHODIMP
  501. CRmsDrive::CreateDataMover(
  502. IDataMover **ptr)
  503. /*++
  504. Implements:
  505. IRmsDrive::CreateDataMover
  506. --*/
  507. {
  508. HRESULT hr = S_OK;
  509. WsbTraceIn(OLESTR("CRmsDrive::CreateDataMover"), OLESTR(""));
  510. try {
  511. WsbAssertPointer(ptr);
  512. if (m_isOccupied) {
  513. switch (m_mediaSupported) {
  514. case RmsMedia8mm:
  515. case RmsMedia4mm:
  516. case RmsMediaDLT:
  517. case RmsMediaTape:
  518. {
  519. //
  520. // Create a tape style data mover to the drive
  521. //
  522. WsbAssertHr(CoCreateInstance(CLSID_CNtTapeIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)ptr));
  523. }
  524. break;
  525. case RmsMediaWORM:
  526. break;
  527. case RmsMediaOptical:
  528. case RmsMediaMO35:
  529. case RmsMediaCDR:
  530. case RmsMediaDVD:
  531. case RmsMediaDisk:
  532. case RmsMediaFixed:
  533. {
  534. //
  535. // Create a file style data mover to the drive
  536. //
  537. WsbAssertHr(CoCreateInstance(CLSID_CNtFileIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)ptr));
  538. }
  539. break;
  540. default:
  541. WsbThrow(E_UNEXPECTED);
  542. break;
  543. }
  544. }
  545. else {
  546. WsbThrow(RMS_E_RESOURCE_UNAVAILABLE);
  547. }
  548. // Initialize the data mover
  549. WsbAffirmHr((*ptr)->SetDeviceName(m_deviceName));
  550. WsbAffirmHr((*ptr)->SetCartridge(m_pCartridge));
  551. // Update stroage info for this cartridge.
  552. //
  553. // IMPORTANT NOTE: This also needs to touch the physical device
  554. // to make sure the device is ready for I/O.
  555. // If we get device errors here, we must fail the
  556. // mount.
  557. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  558. // marking the FreeSpace to -1 gaurantees it's stale for the
  559. // following GetLargestFreeSpace() call.
  560. WsbAffirmHr(pInfo->SetFreeSpace(-1));
  561. hr = (*ptr)->GetLargestFreeSpace(NULL, NULL);
  562. if (MVR_E_UNRECOGNIZED_VOLUME == hr) {
  563. // This is expected if this is an unformatted optical media
  564. hr = S_OK;
  565. }
  566. WsbAffirmHr(hr);
  567. WsbAssertHrOk(hr);
  568. /*
  569. Tracking DataMovers is only partially implemented.
  570. CComQIPtr<IRmsServer, &IID_IRmsServer> pServer = g_pServer;
  571. CComPtr<IWsbIndexedCollection> pDataMovers;
  572. WsbAffirmHr(pServer->GetDataMovers(&pDataMovers));
  573. WsbAffirmHr(pDataMovers->Add((IDataMover *)(*ptr)));
  574. */
  575. } WsbCatch(hr);
  576. WsbTraceOut(OLESTR("CRmsDrive::CreateDataMover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  577. return hr;
  578. }
  579. STDMETHODIMP
  580. CRmsDrive::ReleaseDataMover(
  581. IN IDataMover *ptr)
  582. /*++
  583. Implements:
  584. IRmsDrive::ReleaseDataMover
  585. --*/
  586. {
  587. HRESULT hr = S_OK;
  588. WsbTraceIn(OLESTR("CRmsDrive::ReleaseDataMover"), OLESTR(""));
  589. try {
  590. WsbAssertPointer(ptr);
  591. WsbThrow(E_NOTIMPL);
  592. /*
  593. Tracking DataMovers is only partially implemented.
  594. CComQIPtr<IRmsServer, &IID_IRmsServer> pServer = g_pServer;
  595. CComPtr<IWsbIndexedCollection> pDataMovers;
  596. WsbAffirmHr(pServer->GetDataMovers(&pDataMovers));
  597. WsbAffirmHr(pDataMovers->RemoveAndRelease((IDataMover *)ptr));
  598. ULONG activeDataMovers;
  599. WsbAffirmHr(pDataMovers->GetEntries( &activeDataMovers));
  600. WsbTrace(OLESTR("activeDataMovers = <%u>\n"), activeDataMovers);
  601. */
  602. } WsbCatch(hr);
  603. WsbTraceOut(OLESTR("CRmsDrive::ReleaseDataMover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  604. return hr;
  605. }
  606. STDMETHODIMP
  607. CRmsDrive::Eject(
  608. void
  609. )
  610. /*++
  611. Implements:
  612. IRmsDrive::Eject
  613. --*/
  614. {
  615. HRESULT hr = E_FAIL;
  616. WsbTraceIn(OLESTR("CRmsDrive::Eject"), OLESTR(""));
  617. HANDLE hDrive = INVALID_HANDLE_VALUE;
  618. try {
  619. CWsbBstrPtr drive = "";
  620. switch ( m_mediaSupported ) {
  621. case RmsMedia8mm:
  622. case RmsMedia4mm:
  623. case RmsMediaDLT:
  624. case RmsMediaTape:
  625. drive = m_deviceName;
  626. break;
  627. case RmsMediaWORM:
  628. break;
  629. case RmsMediaOptical:
  630. case RmsMediaMO35:
  631. case RmsMediaCDR:
  632. case RmsMediaDVD:
  633. case RmsMediaDisk:
  634. case RmsMediaFixed:
  635. // TODO: permanently remove trailing \ from device name ????
  636. WsbAffirmHr(drive.Realloc(2));
  637. wcsncpy(drive, m_deviceName, 2);
  638. drive.Prepend( OLESTR( "\\\\.\\" ) );
  639. break;
  640. }
  641. int retry = 0;
  642. do {
  643. hDrive = CreateFile( drive,
  644. GENERIC_READ | GENERIC_WRITE,
  645. 0,
  646. 0,
  647. OPEN_EXISTING,
  648. 0,
  649. NULL
  650. );
  651. if ( INVALID_HANDLE_VALUE == hDrive )
  652. Sleep(2000);
  653. else
  654. break;
  655. } while ( retry++ < 10 );
  656. WsbAssertHandle( hDrive );
  657. DWORD dwReturn;
  658. WsbAffirmHr(PrepareTape(hDrive, TAPE_UNLOAD, FALSE));
  659. WsbAffirmHr(PrepareTape(hDrive, TAPE_UNLOCK, FALSE));
  660. WsbAssertStatus( DeviceIoControl( hDrive,
  661. IOCTL_STORAGE_EJECT_MEDIA,
  662. NULL,
  663. 0,
  664. NULL,
  665. 0,
  666. &dwReturn,
  667. NULL ));
  668. WsbAssertStatus( CloseHandle( hDrive ) );
  669. hr = S_OK;
  670. }
  671. WsbCatchAndDo( hr,
  672. if ( INVALID_HANDLE_VALUE != hDrive )
  673. CloseHandle( hDrive );
  674. );
  675. WsbTraceOut(OLESTR("CRmsDrive::Eject"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  676. return hr;
  677. }
  678. STDMETHODIMP
  679. CRmsDrive::GetLargestFreeSpace(
  680. LONGLONG *pFreeSpace,
  681. LONGLONG *pCapacity
  682. )
  683. /*++
  684. Implements:
  685. IRmsDrive::GetLargestFreeSpace
  686. --*/
  687. {
  688. HRESULT hr = S_OK;
  689. WsbTraceIn(OLESTR("CRmsDrive::GetLargestFreeSpace"), OLESTR(""));
  690. try {
  691. CComPtr<IDataMover> pDataMover;
  692. WsbAffirmHr(CreateDataMover(&pDataMover));
  693. WsbAffirmHr(pDataMover->GetLargestFreeSpace(pFreeSpace, pCapacity));
  694. } WsbCatch(hr);
  695. WsbTraceOut(OLESTR("CRmsDrive::GetLargestFreeSpace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  696. return hr;
  697. }
  698. HRESULT
  699. CRmsDrive::UnloadNow(void)
  700. {
  701. HRESULT hr = S_OK;
  702. WsbTraceIn(OLESTR("CRmsDrive::UnloadNow"), OLESTR(""));
  703. try {
  704. WsbAffirmHr(Lock());
  705. WsbAffirmStatus(SetEvent(m_UnloadNowEvent));
  706. WsbAffirmHr(Unlock());
  707. switch(WaitForSingleObject(m_UnloadedEvent, INFINITE)) {
  708. case WAIT_FAILED:
  709. hr = HRESULT_FROM_WIN32(GetLastError());
  710. WsbTrace(OLESTR("CRmsDrive::UnloadNow - Wait for Single Object returned error: %ls\n"),
  711. WsbHrAsString(hr));
  712. WsbAffirmHr(hr);
  713. break;
  714. case WAIT_TIMEOUT:
  715. WsbTrace(OLESTR("CRmsDrive::UnloadNow - Awakened by timeout.\n"));
  716. break;
  717. default:
  718. WsbTrace(OLESTR("CRmsDrive::UnloadNow - Awakened by external signal.\n"));
  719. GetSystemTimeAsFileTime(&m_UnloadNowTime);
  720. break;
  721. }
  722. } WsbCatch(hr);
  723. WsbTraceOut(OLESTR("CRmsDrive::UnloadNow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  724. return hr;
  725. }
  726. DWORD WINAPI
  727. CRmsDrive::StartUnloadThread(
  728. IN LPVOID pv)
  729. {
  730. return(((CRmsDrive*) pv)->Unload());
  731. }
  732. HRESULT
  733. CRmsDrive::Unload(void)
  734. {
  735. HRESULT hr = S_OK;
  736. WsbTraceIn(OLESTR("CRmsDrive::Unload"), OLESTR(""));
  737. // We need to be sure this object doesn't go away until we're done.
  738. // This happens when we dismount a NTMS managed cartridge.
  739. CComPtr<IRmsDrive> thisDrive = this;
  740. try {
  741. BOOL waiting = TRUE;
  742. LARGE_INTEGER delta = {0,0};
  743. while (waiting) {
  744. //
  745. // !!!!! VERY IMPORTANT !!!!
  746. //
  747. // no 'break' in this loop, we're entering
  748. // a critical section!
  749. //
  750. #if RMS_CRITICAL_SECTION
  751. // <<<<< ENTER SINGLE THREADED SECTION
  752. WsbAffirmHr(Lock());
  753. #endif
  754. WsbTrace(OLESTR("Refs = %d\n"), m_MountReference);
  755. if (0 == m_MountReference) {
  756. FILETIME now;
  757. GetSystemTimeAsFileTime(&now);
  758. ULARGE_INTEGER time0;
  759. ULARGE_INTEGER time1;
  760. time0.LowPart = m_UnloadNowTime.dwLowDateTime;
  761. time0.HighPart = m_UnloadNowTime.dwHighDateTime;
  762. time1.LowPart = now.dwLowDateTime;
  763. time1.HighPart = now.dwHighDateTime;
  764. // time0 is the target time for dismount.
  765. // When delta goes negative, we've expired our
  766. // wait time.
  767. delta.QuadPart = time0.QuadPart-time1.QuadPart;
  768. // convert delta to 100-ns to milliseconds
  769. delta.QuadPart /= 10000;
  770. WsbTrace(OLESTR("Time = <%ls>; Unload Time = <%ls>; delta = %I64d (ms)\n"),
  771. WsbQuickString(WsbFiletimeAsString(FALSE, now)),
  772. WsbQuickString(WsbFiletimeAsString(FALSE, m_UnloadNowTime)),
  773. delta.QuadPart);
  774. if (delta.QuadPart <= 0) {
  775. // Dismount wait time has expired
  776. // Double check that we still have something to dismount
  777. if (S_OK == IsOccupied()) {
  778. // Best effort home
  779. // Fixed drives are always occupied and we shouldn't call Home for their cartridge
  780. FlushBuffers();
  781. if (RmsDeviceFixedDisk != m_deviceType) {
  782. if (S_OK == m_pCartridge->Home()) {
  783. SetIsOccupied(FALSE);
  784. }
  785. }
  786. }
  787. m_UnloadThreadHandle = NULL;
  788. waiting = FALSE;
  789. SetEvent(m_UnloadedEvent);
  790. }
  791. }
  792. else {
  793. hr = S_FALSE;
  794. m_UnloadThreadHandle = NULL;
  795. waiting = FALSE;
  796. }
  797. #if RMS_CRITICAL_SECTION
  798. WsbAffirmHr(Unlock());
  799. // >>>>> LEAVE SINGLE THREADED SECTION
  800. #endif
  801. if ( waiting ) {
  802. switch(WaitForSingleObject(m_UnloadNowEvent, delta.LowPart)) {
  803. case WAIT_FAILED:
  804. WsbTrace(OLESTR("CRmsDrive::Unload - Wait for Single Object returned error: %ls\n"),
  805. WsbHrAsString(HRESULT_FROM_WIN32(GetLastError())));
  806. break;
  807. case WAIT_TIMEOUT:
  808. WsbTrace(OLESTR("CRmsDrive::Unload - Awakened by timeout.\n"));
  809. break;
  810. default:
  811. WsbTrace(OLESTR("CRmsDrive::Unload - Awakened by external signal.\n"));
  812. GetSystemTimeAsFileTime(&m_UnloadNowTime);
  813. break;
  814. }
  815. }
  816. } // waiting
  817. } WsbCatch(hr);
  818. WsbTraceOut(OLESTR("CRmsDrive::Unload"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  819. return hr;
  820. }
  821. HRESULT
  822. CRmsDrive::FlushBuffers( void )
  823. /*++
  824. Implements:
  825. IRmsDrive::FlushBuffers
  826. --*/
  827. {
  828. HRESULT hr S_OK;
  829. WsbTraceIn(OLESTR("CRmsDrive::FlushBuffers"), OLESTR("Device=<%ls>"), (WCHAR *) m_deviceName);
  830. HANDLE hDrive = INVALID_HANDLE_VALUE;
  831. try {
  832. // First flush system buffers
  833. switch (m_mediaSupported) {
  834. case RmsMedia8mm:
  835. case RmsMedia4mm:
  836. case RmsMediaDLT:
  837. case RmsMediaTape:
  838. case RmsMediaWORM:
  839. break;
  840. case RmsMediaOptical:
  841. case RmsMediaMO35:
  842. case RmsMediaCDR:
  843. case RmsMediaDVD:
  844. case RmsMediaDisk:
  845. // No need to flush for Optical media - RSM should flush the system buffers before dismounting
  846. break;
  847. case RmsMediaFixed:
  848. {
  849. // This is special code to flush the file system buffers.
  850. // Create an exclusive handle
  851. CWsbStringPtr drive;
  852. WsbAffirmHr(drive.Alloc(10));
  853. wcsncat( drive, m_deviceName, 2 );
  854. drive.Prepend( OLESTR( "\\\\.\\" ) );
  855. hDrive = CreateFile( drive,
  856. GENERIC_READ | GENERIC_WRITE,
  857. FILE_SHARE_READ | FILE_SHARE_WRITE,
  858. 0,
  859. OPEN_EXISTING,
  860. 0,
  861. NULL
  862. );
  863. WsbAffirmHandle(hDrive);
  864. // Flush buffers
  865. WsbAffirmStatus(FlushFileBuffers(hDrive));
  866. CloseHandle(hDrive);
  867. hDrive = INVALID_HANDLE_VALUE;
  868. }
  869. break;
  870. }
  871. } WsbCatchAndDo(hr,
  872. if (INVALID_HANDLE_VALUE != hDrive) {
  873. CloseHandle(hDrive);
  874. }
  875. );
  876. WsbTraceOut(OLESTR("CRmsDrive::FlushBuffers"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  877. return hr;
  878. }
  879. HRESULT
  880. CRmsDrive::Lock( void )
  881. /*++
  882. Implements:
  883. IRmsDrive::Lock
  884. --*/
  885. {
  886. HRESULT hr S_OK;
  887. WsbTraceIn(OLESTR("CRmsDrive::Lock"), OLESTR(""));
  888. EnterCriticalSection(&m_CriticalSection);
  889. WsbTraceOut(OLESTR("CRmsDrive::Lock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  890. return hr;
  891. }
  892. HRESULT
  893. CRmsDrive::Unlock( void )
  894. /*++
  895. Implements:
  896. IRmsDrive::Unlock
  897. --*/
  898. {
  899. HRESULT hr S_OK;
  900. WsbTraceIn(OLESTR("CRmsDrive::Unlock"), OLESTR(""));
  901. LeaveCriticalSection(&m_CriticalSection);
  902. WsbTraceOut(OLESTR("CRmsDrive::Unlock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  903. return hr;
  904. }