mirror of https://github.com/tongzx/nt5src
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.
1362 lines
31 KiB
1362 lines
31 KiB
/*++
|
|
|
|
© 1998 Seagate Software, Inc. All rights reserved
|
|
|
|
Module Name:
|
|
|
|
RmsDrive.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of CRmsDrive
|
|
|
|
Author:
|
|
|
|
Brian Dodd [brian] 15-Nov-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "RmsDrive.h"
|
|
#include "RmsServr.h"
|
|
|
|
int CRmsDrive::s_InstanceCount = 0;
|
|
|
|
#define RMS_CRITICAL_SECTION 1
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::CompareTo(
|
|
IN IUnknown *pCollectable,
|
|
OUT SHORT *pResult
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IWsbCollectable::CompareTo
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
SHORT result = 1;
|
|
|
|
WsbTraceIn( OLESTR("CRmsDrive::CompareTo"), OLESTR("") );
|
|
|
|
try {
|
|
|
|
// Validate arguments - Okay if pResult is NULL
|
|
WsbAssertPointer( pCollectable );
|
|
|
|
// !!!!!
|
|
//
|
|
// IMPORTANT: The collectable coming in may not be a CRmsDrive if the collection
|
|
// is the unconfigured device list.
|
|
//
|
|
// !!!!!
|
|
|
|
CComQIPtr<IRmsComObject, &IID_IRmsComObject> pObject = pCollectable;
|
|
|
|
// Every collectable should be an CRmsComObject
|
|
WsbAssertPointer( pObject );
|
|
|
|
switch ( m_findBy ) {
|
|
|
|
case RmsFindByDeviceInfo:
|
|
case RmsFindByDeviceAddress:
|
|
case RmsFindByDeviceName:
|
|
case RmsFindByDeviceType:
|
|
|
|
// Do CompareTo for device
|
|
hr = CRmsDevice::CompareTo( pCollectable, &result );
|
|
break;
|
|
|
|
case RmsFindByElementNumber:
|
|
case RmsFindByMediaSupported:
|
|
|
|
// Do CompareTo for changer element
|
|
hr = CRmsChangerElement::CompareTo( pCollectable, &result );
|
|
break;
|
|
|
|
case RmsFindByObjectId:
|
|
default:
|
|
|
|
// Do CompareTo for object
|
|
hr = CRmsComObject::CompareTo( pCollectable, &result );
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
WsbCatch( hr );
|
|
|
|
if ( SUCCEEDED(hr) && (0 != pResult) ){
|
|
*pResult = result;
|
|
}
|
|
|
|
WsbTraceOut( OLESTR("CRmsDrive::CompareTo"),
|
|
OLESTR("hr = <%ls>, result = <%ls>"),
|
|
WsbHrAsString( hr ), WsbPtrToShortAsString( pResult ) );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::FinalConstruct(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
CComObjectRoot::FinalConstruct
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::FinalConstruct"), OLESTR(""));
|
|
|
|
try {
|
|
WsbAssertHr(CWsbObject::FinalConstruct());
|
|
|
|
// Initialize values
|
|
m_MountReference = 0;
|
|
m_UnloadNowTime.dwHighDateTime = 0;
|
|
m_UnloadNowTime.dwLowDateTime = 0;
|
|
m_UnloadThreadHandle = NULL;
|
|
|
|
try {
|
|
|
|
// May raise STATUS_NO_MEMORY exception
|
|
InitializeCriticalSection(&m_CriticalSection);
|
|
|
|
} catch(DWORD status) {
|
|
WsbLogEvent(status, 0, NULL, NULL);
|
|
switch (status) {
|
|
case STATUS_NO_MEMORY:
|
|
WsbThrow(E_OUTOFMEMORY);
|
|
break;
|
|
default:
|
|
WsbThrow(E_UNEXPECTED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_UnloadNowEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
m_UnloadedEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
|
|
|
|
} WsbCatch(hr);
|
|
|
|
s_InstanceCount++;
|
|
WsbTraceAlways(OLESTR("CRmsDrive::s_InstanceCount += %d\n"), s_InstanceCount);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::FinalRelease(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::FinalRelease"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// InitializeCriticalSection raises an exception. Delete may too.
|
|
DeleteCriticalSection(&m_CriticalSection);
|
|
|
|
} catch(DWORD status) {
|
|
WsbLogEvent(status, 0, NULL, NULL);
|
|
}
|
|
|
|
CloseHandle(m_UnloadNowEvent);
|
|
CloseHandle(m_UnloadedEvent);
|
|
|
|
|
|
CWsbObject::FinalRelease();
|
|
|
|
} WsbCatch(hr);
|
|
|
|
s_InstanceCount--;
|
|
WsbTraceAlways(OLESTR("CRmsDrive::s_InstanceCount -= %d\n"), s_InstanceCount);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::FinalRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::GetClassID(
|
|
OUT CLSID* pClsid
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersist::GetClassId
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::GetClassID"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != pClsid, E_POINTER);
|
|
|
|
*pClsid = CLSID_CRmsDrive;
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::GetSizeMax(
|
|
OUT ULARGE_INTEGER* pcbSize
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::GetSizeMax
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::GetSizeMax"), OLESTR(""));
|
|
|
|
// try {
|
|
// WsbAssert(0 != pcbSize, E_POINTER);
|
|
|
|
// // Set up max size
|
|
// pcbSize->QuadPart = WsbPersistSizeOf(LONG); // m_MountReference
|
|
|
|
// } WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pcbSize));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::Load(
|
|
IN IStream* pStream
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::Load
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulBytes = 0;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Load"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
WsbAssert(0 != pStream, E_POINTER);
|
|
|
|
WsbAffirmHr(CRmsDevice::Load(pStream));
|
|
|
|
// Read value
|
|
WsbAffirmHr(WsbLoadFromStream(pStream, &m_MountReference));
|
|
|
|
// We just reset to zero, one day we could try to reconnect to
|
|
// the process that issued the mount...
|
|
|
|
m_MountReference = 0;
|
|
|
|
}
|
|
WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::Save(
|
|
IN IStream* pStream,
|
|
IN BOOL clearDirty
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IPersistStream::Save
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ulBytes = 0;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
|
|
|
|
try {
|
|
WsbAssert(0 != pStream, E_POINTER);
|
|
|
|
WsbAffirmHr(CRmsDevice::Save(pStream, clearDirty));
|
|
|
|
// Write value
|
|
WsbAffirmHr(WsbSaveToStream(pStream, m_MountReference));
|
|
|
|
|
|
// Do we need to clear the dirty bit?
|
|
if (clearDirty) {
|
|
m_isDirty = FALSE;
|
|
}
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::Test(
|
|
OUT USHORT *pPassed,
|
|
OUT USHORT *pFailed
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IWsbTestable::Test
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CComPtr<IRmsDrive> pDrive1;
|
|
CComPtr<IRmsDrive> pDrive2;
|
|
|
|
CComPtr<IPersistFile> pFile1;
|
|
CComPtr<IPersistFile> pFile2;
|
|
|
|
LONG i;
|
|
|
|
LONG longWork1;
|
|
|
|
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Test"), OLESTR(""));
|
|
|
|
try {
|
|
// Get the Drive interface.
|
|
hr = S_OK;
|
|
try {
|
|
WsbAssertHr(((IUnknown*) (IRmsDrive*) this)->QueryInterface(IID_IRmsDrive, (void**) &pDrive1));
|
|
|
|
// Test All of MountReference Functions
|
|
ResetMountReference();
|
|
|
|
GetMountReference(&longWork1);
|
|
|
|
if(longWork1 == 0) {
|
|
(*pPassed)++;
|
|
} else {
|
|
(*pFailed)++;
|
|
}
|
|
|
|
for(i = 1; i < 20; i++){
|
|
AddMountReference();
|
|
|
|
GetMountReference(&longWork1);
|
|
|
|
if(longWork1 == i){
|
|
(*pPassed)++;
|
|
} else {
|
|
(*pFailed)++;
|
|
}
|
|
}
|
|
|
|
for(i = 19; i == 0; i--){
|
|
ReleaseMountReference();
|
|
|
|
GetMountReference(&longWork1);
|
|
|
|
if(longWork1 == i){
|
|
(*pPassed)++;
|
|
} else {
|
|
(*pFailed)++;
|
|
}
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
// Tally up the results
|
|
|
|
hr = S_OK;
|
|
if (*pFailed) {
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Test"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::GetMountReference(
|
|
OUT LONG *pRefs
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::GetMountReference
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::GetMountReference"), OLESTR(""));
|
|
|
|
LONG refs = -999;
|
|
|
|
try {
|
|
WsbAssertPointer(pRefs);
|
|
|
|
refs = m_MountReference;
|
|
*pRefs = refs;
|
|
|
|
} WsbCatch(hr)
|
|
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::GetMountReference"), OLESTR("hr = <%ls>, refs = %d"),
|
|
WsbHrAsString(hr), refs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::ResetMountReference(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::ResetMountReference
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::ResetMountReference"), OLESTR(""));
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
try {
|
|
// <<<<< ENTER SINGLE THREADED SECTION
|
|
WsbAffirmHr(Lock());
|
|
|
|
m_MountReference = 0;
|
|
m_isDirty = TRUE;
|
|
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
|
|
} WsbCatch(hr)
|
|
#else
|
|
InterlockedExchange( &m_MountReference, 0);
|
|
m_isDirty = TRUE;
|
|
#endif
|
|
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::ResetMountReference"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::AddMountReference(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::AddMountReference
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::AddMountReference"), OLESTR(""));
|
|
|
|
LONG refs = -999;
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
try {
|
|
// <<<<< ENTER SINGLE THREADED SECTION
|
|
WsbAffirmHr(Lock());
|
|
|
|
m_MountReference++;
|
|
m_isDirty = TRUE;
|
|
refs = m_MountReference;
|
|
|
|
WsbAffirmStatus(ResetEvent(m_UnloadedEvent));
|
|
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
|
|
} WsbCatch(hr)
|
|
#else
|
|
refs = InterlockedIncrement( &m_MountReference );
|
|
m_isDirty = TRUE;
|
|
#endif
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::AddMountReference"), OLESTR("hr = <%ls>, refs = %d"),
|
|
WsbHrAsString(hr), refs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::ReleaseMountReference(
|
|
IN DWORD dwOptions
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::ReleaseMountReference
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::ReleaseMountReference"), OLESTR("<%ld>"), dwOptions);
|
|
|
|
// We need to be sure this object doesn't go away until we're done.
|
|
// This happens when we dismount a NTMS managed cartridge.
|
|
CComPtr<IRmsDrive> thisDrive = this;
|
|
|
|
LONG refs = -999;
|
|
|
|
BOOL bUnloadNow =
|
|
( (dwOptions & RMS_DISMOUNT_IMMEDIATE) || (dwOptions & RMS_DISMOUNT_DEFERRED_ONLY) ) ? TRUE : FALSE;
|
|
|
|
try {
|
|
#if RMS_CRITICAL_SECTION
|
|
// <<<<< ENTER SINGLE THREADED SECTION
|
|
WsbAffirmHr(Lock());
|
|
|
|
m_MountReference--;
|
|
m_isDirty = TRUE;
|
|
|
|
refs = m_MountReference;
|
|
#else
|
|
refs = InterlockedDecrement( &m_MountReference );
|
|
m_isDirty = TRUE;
|
|
#endif
|
|
|
|
// Note:
|
|
// Even if the caller requests immediate dismount, if the ref count is > 0,
|
|
// the media is not dismounted (only the ref count is decreased).
|
|
// This is necessary because positive ref count means that some other component
|
|
// is also using the media (possible for Optical). The media must be dismounted
|
|
// only when this other component is done as well.
|
|
|
|
if (refs < 0) {
|
|
//
|
|
// This shouldn't happen under normal conditions... if it does,
|
|
// we quiety reset the the reference count and try to recover.
|
|
//
|
|
WsbLogEvent(E_UNEXPECTED, sizeof(refs), &refs, NULL);
|
|
|
|
InterlockedExchange( &m_MountReference, 0);
|
|
refs = 0;
|
|
|
|
// If we don't have a cartridge in the drive, there's no point
|
|
// in continueing.
|
|
WsbAffirm(S_OK == IsOccupied(), E_ABORT);
|
|
}
|
|
|
|
if (0 == refs) {
|
|
|
|
//
|
|
// Deferred Dismount Logic: We wait the specified time before
|
|
// dismounting the media. Each dismount request resets the dismount
|
|
// now time. As long as the media is actively used, it will not be
|
|
// dismounted.
|
|
//
|
|
|
|
// Retrieve the DeferredDismountWaitTime parameter
|
|
|
|
DWORD size;
|
|
OLECHAR tmpString[256];
|
|
DWORD waitTime = RMS_DEFAULT_DISMOUNT_WAIT_TIME;
|
|
if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_DISMOUNT_WAIT_TIME, tmpString, 256, &size))) {
|
|
waitTime = wcstol(tmpString, NULL, 10);
|
|
WsbTrace(OLESTR("DismountWaitTime is %d milliseconds.\n"), waitTime);
|
|
}
|
|
|
|
if (waitTime > 0 && !bUnloadNow) {
|
|
|
|
// convert waitTime to 100-nanosecond units
|
|
waitTime *= 10000;
|
|
|
|
FILETIME now;
|
|
GetSystemTimeAsFileTime(&now);
|
|
|
|
ULARGE_INTEGER time;
|
|
|
|
time.LowPart = now.dwLowDateTime;
|
|
time.HighPart = now.dwHighDateTime;
|
|
|
|
time.QuadPart += waitTime;
|
|
|
|
m_UnloadNowTime.dwLowDateTime = time.LowPart;
|
|
m_UnloadNowTime.dwHighDateTime = time.HighPart;
|
|
|
|
WsbTrace(OLESTR("Target Unload Time = <%ls>\n"),
|
|
WsbQuickString(WsbFiletimeAsString(FALSE, m_UnloadNowTime)));
|
|
|
|
// If we already have an active unload thread we skip this step.
|
|
if (!m_UnloadThreadHandle) {
|
|
|
|
//
|
|
// Create a thread to wait for dismount
|
|
//
|
|
|
|
WsbTrace(OLESTR("Starting thread for deferred dismount.\n"));
|
|
DWORD threadId;
|
|
WsbAffirmHandle(m_UnloadThreadHandle = CreateThread(NULL, 1024, CRmsDrive::StartUnloadThread, this, 0, &threadId));
|
|
CloseHandle(m_UnloadThreadHandle);
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Dismount the media now
|
|
|
|
// Double check that we still have something to dismount
|
|
|
|
if (S_OK == IsOccupied()) {
|
|
|
|
// Best effort - home
|
|
// Fixed drives are always occupied and we shouldn't call Home for their cartridge
|
|
|
|
FlushBuffers();
|
|
if (RmsDeviceFixedDisk != m_deviceType) {
|
|
if (S_OK == m_pCartridge->Home(dwOptions)) {
|
|
SetIsOccupied(FALSE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// set event that blocks immediate unload
|
|
SetEvent(m_UnloadedEvent);
|
|
}
|
|
}
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
|
|
} WsbCatchAndDo(hr,
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
);
|
|
#else
|
|
} WsbCatch(hr)
|
|
#endif
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::ReleaseMountReference"), OLESTR("hr = <%ls>, refs = %d"),
|
|
WsbHrAsString(hr), refs);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::SelectForMount(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::SelectForMount
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::SelectForMount"), OLESTR(""));
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
try {
|
|
|
|
// <<<<< ENTER SINGLE THREADED SECTION
|
|
WsbAffirmHr(Lock());
|
|
|
|
if (!m_MountReference) {
|
|
|
|
m_MountReference++;
|
|
m_isDirty = TRUE;
|
|
|
|
} else {
|
|
hr = RMS_E_DRIVE_BUSY;
|
|
}
|
|
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
|
|
} WsbCatch(hr)
|
|
#else
|
|
LONG one = 1;
|
|
LONG zero = 0;
|
|
|
|
LONG flag = InterlockedCompareExchange( &m_MountReference, one, zero );
|
|
|
|
hr = ( flag > 0 ) ? RMS_E_DRIVE_BUSY : S_OK;
|
|
#endif
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::SelectForMount"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::CreateDataMover(
|
|
IDataMover **ptr)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::CreateDataMover
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::CreateDataMover"), OLESTR(""));
|
|
|
|
try {
|
|
WsbAssertPointer(ptr);
|
|
|
|
if (m_isOccupied) {
|
|
|
|
switch (m_mediaSupported) {
|
|
|
|
case RmsMedia8mm:
|
|
case RmsMedia4mm:
|
|
case RmsMediaDLT:
|
|
case RmsMediaTape:
|
|
{
|
|
//
|
|
// Create a tape style data mover to the drive
|
|
//
|
|
|
|
WsbAssertHr(CoCreateInstance(CLSID_CNtTapeIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)ptr));
|
|
|
|
}
|
|
break;
|
|
|
|
case RmsMediaWORM:
|
|
break;
|
|
|
|
case RmsMediaOptical:
|
|
case RmsMediaMO35:
|
|
case RmsMediaCDR:
|
|
case RmsMediaDVD:
|
|
case RmsMediaDisk:
|
|
case RmsMediaFixed:
|
|
{
|
|
//
|
|
// Create a file style data mover to the drive
|
|
//
|
|
|
|
WsbAssertHr(CoCreateInstance(CLSID_CNtFileIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)ptr));
|
|
|
|
}
|
|
break;
|
|
default:
|
|
WsbThrow(E_UNEXPECTED);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
WsbThrow(RMS_E_RESOURCE_UNAVAILABLE);
|
|
}
|
|
|
|
// Initialize the data mover
|
|
WsbAffirmHr((*ptr)->SetDeviceName(m_deviceName));
|
|
WsbAffirmHr((*ptr)->SetCartridge(m_pCartridge));
|
|
|
|
// Update stroage info for this cartridge.
|
|
//
|
|
// IMPORTANT NOTE: This also needs to touch the physical device
|
|
// to make sure the device is ready for I/O.
|
|
// If we get device errors here, we must fail the
|
|
// mount.
|
|
|
|
CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
|
|
|
|
// marking the FreeSpace to -1 gaurantees it's stale for the
|
|
// following GetLargestFreeSpace() call.
|
|
WsbAffirmHr(pInfo->SetFreeSpace(-1));
|
|
hr = (*ptr)->GetLargestFreeSpace(NULL, NULL);
|
|
if (MVR_E_UNRECOGNIZED_VOLUME == hr) {
|
|
// This is expected if this is an unformatted optical media
|
|
hr = S_OK;
|
|
}
|
|
WsbAffirmHr(hr);
|
|
|
|
WsbAssertHrOk(hr);
|
|
|
|
/*
|
|
|
|
Tracking DataMovers is only partially implemented.
|
|
|
|
|
|
CComQIPtr<IRmsServer, &IID_IRmsServer> pServer = g_pServer;
|
|
CComPtr<IWsbIndexedCollection> pDataMovers;
|
|
WsbAffirmHr(pServer->GetDataMovers(&pDataMovers));
|
|
WsbAffirmHr(pDataMovers->Add((IDataMover *)(*ptr)));
|
|
*/
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::CreateDataMover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::ReleaseDataMover(
|
|
IN IDataMover *ptr)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::ReleaseDataMover
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::ReleaseDataMover"), OLESTR(""));
|
|
|
|
try {
|
|
WsbAssertPointer(ptr);
|
|
WsbThrow(E_NOTIMPL);
|
|
|
|
/*
|
|
|
|
Tracking DataMovers is only partially implemented.
|
|
|
|
|
|
CComQIPtr<IRmsServer, &IID_IRmsServer> pServer = g_pServer;
|
|
CComPtr<IWsbIndexedCollection> pDataMovers;
|
|
WsbAffirmHr(pServer->GetDataMovers(&pDataMovers));
|
|
|
|
WsbAffirmHr(pDataMovers->RemoveAndRelease((IDataMover *)ptr));
|
|
|
|
ULONG activeDataMovers;
|
|
WsbAffirmHr(pDataMovers->GetEntries( &activeDataMovers));
|
|
WsbTrace(OLESTR("activeDataMovers = <%u>\n"), activeDataMovers);
|
|
*/
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::ReleaseDataMover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::Eject(
|
|
void
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::Eject
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Eject"), OLESTR(""));
|
|
|
|
HANDLE hDrive = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
|
|
CWsbBstrPtr drive = "";
|
|
|
|
switch ( m_mediaSupported ) {
|
|
|
|
case RmsMedia8mm:
|
|
case RmsMedia4mm:
|
|
case RmsMediaDLT:
|
|
case RmsMediaTape:
|
|
|
|
drive = m_deviceName;
|
|
break;
|
|
|
|
case RmsMediaWORM:
|
|
break;
|
|
|
|
case RmsMediaOptical:
|
|
case RmsMediaMO35:
|
|
case RmsMediaCDR:
|
|
case RmsMediaDVD:
|
|
case RmsMediaDisk:
|
|
case RmsMediaFixed:
|
|
|
|
// TODO: permanently remove trailing \ from device name ????
|
|
WsbAffirmHr(drive.Realloc(2));
|
|
wcsncpy(drive, m_deviceName, 2);
|
|
drive.Prepend( OLESTR( "\\\\.\\" ) );
|
|
break;
|
|
|
|
}
|
|
|
|
int retry = 0;
|
|
|
|
do {
|
|
|
|
hDrive = CreateFile( drive,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
0,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if ( INVALID_HANDLE_VALUE == hDrive )
|
|
Sleep(2000);
|
|
else
|
|
break;
|
|
|
|
} while ( retry++ < 10 );
|
|
|
|
WsbAssertHandle( hDrive );
|
|
|
|
DWORD dwReturn;
|
|
|
|
WsbAffirmHr(PrepareTape(hDrive, TAPE_UNLOAD, FALSE));
|
|
WsbAffirmHr(PrepareTape(hDrive, TAPE_UNLOCK, FALSE));
|
|
|
|
WsbAssertStatus( DeviceIoControl( hDrive,
|
|
IOCTL_STORAGE_EJECT_MEDIA,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&dwReturn,
|
|
NULL ));
|
|
|
|
WsbAssertStatus( CloseHandle( hDrive ) );
|
|
|
|
hr = S_OK;
|
|
|
|
}
|
|
WsbCatchAndDo( hr,
|
|
if ( INVALID_HANDLE_VALUE != hDrive )
|
|
CloseHandle( hDrive );
|
|
);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Eject"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRmsDrive::GetLargestFreeSpace(
|
|
LONGLONG *pFreeSpace,
|
|
LONGLONG *pCapacity
|
|
)
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::GetLargestFreeSpace
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::GetLargestFreeSpace"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
CComPtr<IDataMover> pDataMover;
|
|
|
|
WsbAffirmHr(CreateDataMover(&pDataMover));
|
|
WsbAffirmHr(pDataMover->GetLargestFreeSpace(pFreeSpace, pCapacity));
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::GetLargestFreeSpace"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRmsDrive::UnloadNow(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::UnloadNow"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
WsbAffirmHr(Lock());
|
|
|
|
WsbAffirmStatus(SetEvent(m_UnloadNowEvent));
|
|
|
|
WsbAffirmHr(Unlock());
|
|
|
|
switch(WaitForSingleObject(m_UnloadedEvent, INFINITE)) {
|
|
case WAIT_FAILED:
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
WsbTrace(OLESTR("CRmsDrive::UnloadNow - Wait for Single Object returned error: %ls\n"),
|
|
WsbHrAsString(hr));
|
|
WsbAffirmHr(hr);
|
|
break;
|
|
case WAIT_TIMEOUT:
|
|
WsbTrace(OLESTR("CRmsDrive::UnloadNow - Awakened by timeout.\n"));
|
|
break;
|
|
default:
|
|
WsbTrace(OLESTR("CRmsDrive::UnloadNow - Awakened by external signal.\n"));
|
|
GetSystemTimeAsFileTime(&m_UnloadNowTime);
|
|
break;
|
|
}
|
|
|
|
} WsbCatch(hr);
|
|
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::UnloadNow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI
|
|
CRmsDrive::StartUnloadThread(
|
|
IN LPVOID pv)
|
|
{
|
|
return(((CRmsDrive*) pv)->Unload());
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRmsDrive::Unload(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Unload"), OLESTR(""));
|
|
|
|
// We need to be sure this object doesn't go away until we're done.
|
|
// This happens when we dismount a NTMS managed cartridge.
|
|
CComPtr<IRmsDrive> thisDrive = this;
|
|
|
|
try {
|
|
|
|
BOOL waiting = TRUE;
|
|
LARGE_INTEGER delta = {0,0};
|
|
|
|
while (waiting) {
|
|
|
|
//
|
|
// !!!!! VERY IMPORTANT !!!!
|
|
//
|
|
// no 'break' in this loop, we're entering
|
|
// a critical section!
|
|
//
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
// <<<<< ENTER SINGLE THREADED SECTION
|
|
WsbAffirmHr(Lock());
|
|
#endif
|
|
WsbTrace(OLESTR("Refs = %d\n"), m_MountReference);
|
|
|
|
if (0 == m_MountReference) {
|
|
|
|
FILETIME now;
|
|
GetSystemTimeAsFileTime(&now);
|
|
|
|
|
|
ULARGE_INTEGER time0;
|
|
ULARGE_INTEGER time1;
|
|
|
|
time0.LowPart = m_UnloadNowTime.dwLowDateTime;
|
|
time0.HighPart = m_UnloadNowTime.dwHighDateTime;
|
|
|
|
time1.LowPart = now.dwLowDateTime;
|
|
time1.HighPart = now.dwHighDateTime;
|
|
|
|
|
|
// time0 is the target time for dismount.
|
|
// When delta goes negative, we've expired our
|
|
// wait time.
|
|
delta.QuadPart = time0.QuadPart-time1.QuadPart;
|
|
|
|
// convert delta to 100-ns to milliseconds
|
|
delta.QuadPart /= 10000;
|
|
|
|
WsbTrace(OLESTR("Time = <%ls>; Unload Time = <%ls>; delta = %I64d (ms)\n"),
|
|
WsbQuickString(WsbFiletimeAsString(FALSE, now)),
|
|
WsbQuickString(WsbFiletimeAsString(FALSE, m_UnloadNowTime)),
|
|
delta.QuadPart);
|
|
|
|
if (delta.QuadPart <= 0) {
|
|
|
|
// Dismount wait time has expired
|
|
|
|
// Double check that we still have something to dismount
|
|
|
|
if (S_OK == IsOccupied()) {
|
|
|
|
// Best effort home
|
|
// Fixed drives are always occupied and we shouldn't call Home for their cartridge
|
|
|
|
FlushBuffers();
|
|
if (RmsDeviceFixedDisk != m_deviceType) {
|
|
if (S_OK == m_pCartridge->Home()) {
|
|
SetIsOccupied(FALSE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
m_UnloadThreadHandle = NULL;
|
|
waiting = FALSE;
|
|
|
|
SetEvent(m_UnloadedEvent);
|
|
|
|
}
|
|
}
|
|
else {
|
|
hr = S_FALSE;
|
|
|
|
m_UnloadThreadHandle = NULL;
|
|
waiting = FALSE;
|
|
}
|
|
|
|
#if RMS_CRITICAL_SECTION
|
|
WsbAffirmHr(Unlock());
|
|
// >>>>> LEAVE SINGLE THREADED SECTION
|
|
#endif
|
|
|
|
if ( waiting ) {
|
|
|
|
switch(WaitForSingleObject(m_UnloadNowEvent, delta.LowPart)) {
|
|
case WAIT_FAILED:
|
|
WsbTrace(OLESTR("CRmsDrive::Unload - Wait for Single Object returned error: %ls\n"),
|
|
WsbHrAsString(HRESULT_FROM_WIN32(GetLastError())));
|
|
break;
|
|
case WAIT_TIMEOUT:
|
|
WsbTrace(OLESTR("CRmsDrive::Unload - Awakened by timeout.\n"));
|
|
break;
|
|
default:
|
|
WsbTrace(OLESTR("CRmsDrive::Unload - Awakened by external signal.\n"));
|
|
GetSystemTimeAsFileTime(&m_UnloadNowTime);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // waiting
|
|
|
|
|
|
} WsbCatch(hr);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Unload"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRmsDrive::FlushBuffers( void )
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::FlushBuffers
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::FlushBuffers"), OLESTR("Device=<%ls>"), (WCHAR *) m_deviceName);
|
|
|
|
HANDLE hDrive = INVALID_HANDLE_VALUE;
|
|
|
|
try {
|
|
|
|
// First flush system buffers
|
|
|
|
switch (m_mediaSupported) {
|
|
|
|
case RmsMedia8mm:
|
|
case RmsMedia4mm:
|
|
case RmsMediaDLT:
|
|
case RmsMediaTape:
|
|
case RmsMediaWORM:
|
|
break;
|
|
|
|
case RmsMediaOptical:
|
|
case RmsMediaMO35:
|
|
case RmsMediaCDR:
|
|
case RmsMediaDVD:
|
|
case RmsMediaDisk:
|
|
// No need to flush for Optical media - RSM should flush the system buffers before dismounting
|
|
break;
|
|
|
|
case RmsMediaFixed:
|
|
{
|
|
// This is special code to flush the file system buffers.
|
|
|
|
// Create an exclusive handle
|
|
CWsbStringPtr drive;
|
|
WsbAffirmHr(drive.Alloc(10));
|
|
wcsncat( drive, m_deviceName, 2 );
|
|
drive.Prepend( OLESTR( "\\\\.\\" ) );
|
|
|
|
hDrive = CreateFile( drive,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
WsbAffirmHandle(hDrive);
|
|
|
|
// Flush buffers
|
|
WsbAffirmStatus(FlushFileBuffers(hDrive));
|
|
|
|
CloseHandle(hDrive);
|
|
hDrive = INVALID_HANDLE_VALUE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
} WsbCatchAndDo(hr,
|
|
if (INVALID_HANDLE_VALUE != hDrive) {
|
|
CloseHandle(hDrive);
|
|
}
|
|
);
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::FlushBuffers"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRmsDrive::Lock( void )
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::Lock
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Lock"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// InitializeCriticalSection raises an exception. Enter/Leave may too.
|
|
EnterCriticalSection(&m_CriticalSection);
|
|
|
|
} catch(DWORD status) {
|
|
WsbLogEvent(status, 0, NULL, NULL);
|
|
WsbThrow(E_UNEXPECTED);
|
|
}
|
|
|
|
} WsbCatch(hr)
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Lock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRmsDrive::Unlock( void )
|
|
/*++
|
|
|
|
Implements:
|
|
|
|
IRmsDrive::Unlock
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr S_OK;
|
|
|
|
WsbTraceIn(OLESTR("CRmsDrive::Unlock"), OLESTR(""));
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// InitializeCriticalSection raises an exception. Enter/Leave may too.
|
|
LeaveCriticalSection(&m_CriticalSection);
|
|
|
|
} catch(DWORD status) {
|
|
WsbLogEvent(status, 0, NULL, NULL);
|
|
WsbThrow(E_UNEXPECTED);
|
|
}
|
|
|
|
} WsbCatch(hr)
|
|
|
|
WsbTraceOut(OLESTR("CRmsDrive::Unlock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
|
|
|
|
return hr;
|
|
}
|
|
|