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.

4241 lines
140 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. NtTapeIo.cpp
  5. Abstract:
  6. CNtTapeIo class
  7. Author:
  8. Brian Dodd [brian] 25-Nov-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "NtTapeIo.h"
  13. #include "Mll.h"
  14. int CNtTapeIo::s_InstanceCount = 0;
  15. ////////////////////////////////////////////////////////////////////////////////
  16. //
  17. // CComObjectRoot Implementation
  18. //
  19. ULONG
  20. CNtTapeIo::InternalAddRef(void) {
  21. DWORD refs = CComObjectRoot::InternalAddRef();
  22. WsbTrace(OLESTR("CNtTapeIo::InternalAddRef - Refs=%d\n"), refs);
  23. return refs;
  24. }
  25. ULONG
  26. CNtTapeIo::InternalRelease(void) {
  27. DWORD refs = CComObjectRoot::InternalRelease();
  28. WsbTrace(OLESTR("CNtTapeIo::InternalRelease - Refs=%d\n"), refs);
  29. return refs;
  30. }
  31. #pragma optimize("g", off)
  32. STDMETHODIMP
  33. CNtTapeIo::FinalConstruct(void)
  34. /*++
  35. Implements:
  36. CComObjectRoot::FinalConstruct
  37. --*/
  38. {
  39. HRESULT hr = S_OK;
  40. WsbTraceIn(OLESTR("CNtTapeIo::FinalConstruct"), OLESTR(""));
  41. try {
  42. m_bCritSecCreated = FALSE;
  43. WsbAffirmHr(CComObjectRoot::FinalConstruct());
  44. (void) CoCreateGuid( &m_ObjectId );
  45. m_pSession = NULL;
  46. m_DataSetNumber = 0;
  47. m_hTape = INVALID_HANDLE_VALUE;
  48. m_DeviceName = MVR_UNDEFINED_STRING;
  49. m_Flags = 0;
  50. m_LastVolume = OLESTR("");
  51. m_LastPath = OLESTR("");
  52. m_ValidLabel = TRUE;
  53. memset(&m_sMediaParameters, 0, sizeof(TAPE_GET_MEDIA_PARAMETERS));
  54. memset(&m_sDriveParameters, 0, sizeof(TAPE_GET_DRIVE_PARAMETERS));
  55. m_StreamName = MVR_UNDEFINED_STRING;
  56. m_Mode = 0;
  57. m_StreamOffset.QuadPart = 0;
  58. m_StreamSize.QuadPart = 0;
  59. m_pStreamBuf = NULL;
  60. m_StreamBufSize = 0;
  61. m_StreamBufUsed = 0;
  62. m_StreamBufPosition = 0;
  63. m_StreamBufStartPBA.QuadPart = 0;
  64. WsbAffirmStatus(InitializeCriticalSectionAndSpinCount(&m_CriticalSection, 0));
  65. m_bCritSecCreated = TRUE;
  66. } WsbCatch(hr);
  67. s_InstanceCount++;
  68. WsbTraceAlways(OLESTR("CNtTapeIo::s_InstanceCount += %d\n"), s_InstanceCount);
  69. WsbTraceOut(OLESTR("CNtTapeIo::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  70. return hr;
  71. }
  72. STDMETHODIMP
  73. CNtTapeIo::FinalRelease(void)
  74. /*++
  75. Implements:
  76. CComObjectRoot::FinalRelease
  77. --*/
  78. {
  79. HRESULT hr = S_OK;
  80. WsbTraceIn(OLESTR("CNtTapeIo::FinalRelease"),OLESTR(""));
  81. (void) CloseStream(); // in case anything is left open
  82. (void) CloseTape();
  83. CComObjectRoot::FinalRelease();
  84. s_InstanceCount--;
  85. WsbTraceAlways(OLESTR("CNtTapeIo::s_InstanceCount -= %d\n"), s_InstanceCount);
  86. WsbTraceOut(OLESTR("CNtTapeIo::FinalRelease"),OLESTR("hr = <%ls>"),WsbHrAsString(hr));
  87. if (m_bCritSecCreated) {
  88. DeleteCriticalSection(&m_CriticalSection);
  89. }
  90. return hr;
  91. }
  92. #pragma optimize("", on)
  93. HRESULT
  94. CNtTapeIo::CompareTo(
  95. IN IUnknown *pCollectable,
  96. OUT SHORT *pResult)
  97. /*++
  98. Implements:
  99. CRmsComObject::CompareTo
  100. --*/
  101. {
  102. HRESULT hr = E_FAIL;
  103. SHORT result = 1;
  104. WsbTraceIn( OLESTR("CNtTapeIo::CompareTo"), OLESTR("") );
  105. try {
  106. // Validate arguments - Okay if pResult is NULL
  107. WsbAssertPointer( pCollectable );
  108. // We need the IRmsComObject interface to get the value of the object.
  109. CComQIPtr<IDataMover, &IID_IDataMover> pObject = pCollectable;
  110. WsbAssertPointer( pObject );
  111. GUID objectId;
  112. // Get objectId.
  113. WsbAffirmHr( pObject->GetObjectId( &objectId ));
  114. if ( m_ObjectId == objectId ) {
  115. // Object IDs match
  116. hr = S_OK;
  117. result = 0;
  118. }
  119. else {
  120. hr = S_FALSE;
  121. result = 1;
  122. }
  123. }
  124. WsbCatch( hr );
  125. if ( SUCCEEDED(hr) && (0 != pResult) ){
  126. *pResult = result;
  127. }
  128. WsbTraceOut( OLESTR("CNtTapeIo::CompareTo"),
  129. OLESTR("hr = <%ls>, result = <%ls>"),
  130. WsbHrAsString( hr ), WsbPtrToShortAsString( pResult ) );
  131. return hr;
  132. }
  133. HRESULT
  134. CNtTapeIo::IsEqual(
  135. IUnknown* pObject
  136. )
  137. /*++
  138. Implements:
  139. IWsbCollectable::IsEqual().
  140. --*/
  141. {
  142. HRESULT hr = S_OK;
  143. WsbTraceIn(OLESTR("CNtTapeIo::IsEqual"), OLESTR(""));
  144. hr = CompareTo(pObject, NULL);
  145. WsbTraceOut(OLESTR("CNtTapeIo::IsEqual"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  146. return(hr);
  147. }
  148. ////////////////////////////////////////////////////////////////////////////////
  149. //
  150. // ISupportErrorInfo Implementation
  151. //
  152. STDMETHODIMP
  153. CNtTapeIo::InterfaceSupportsErrorInfo(REFIID riid)
  154. /*++
  155. Implements:
  156. ISupportsErrorInfo::InterfaceSupportsErrorInfo
  157. --*/
  158. {
  159. static const IID* arr[] =
  160. {
  161. &IID_IDataMover,
  162. &IID_IStream,
  163. };
  164. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  165. {
  166. if (InlineIsEqualGUID(*arr[i],riid))
  167. return S_OK;
  168. }
  169. return S_FALSE;
  170. }
  171. ////////////////////////////////////////////////////////////////////////////////
  172. //
  173. // IDataMover Implementation
  174. //
  175. STDMETHODIMP
  176. CNtTapeIo::GetObjectId(
  177. OUT GUID *pObjectId)
  178. /*++
  179. Implements:
  180. IRmsComObject::GetObjectId
  181. --*/
  182. {
  183. HRESULT hr = S_OK;
  184. WsbTraceIn(OLESTR("CNtTapeIo::GetObjectId"), OLESTR(""));
  185. try {
  186. WsbAssertPointer( pObjectId );
  187. *pObjectId = m_ObjectId;
  188. } WsbCatch(hr);
  189. WsbTraceOut(OLESTR("CNtTapeIo::GetObjectId"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  190. return hr;
  191. }
  192. STDMETHODIMP
  193. CNtTapeIo::BeginSession(
  194. IN BSTR remoteSessionName,
  195. IN BSTR remoteSessionDescription,
  196. IN SHORT remoteDataSet,
  197. IN DWORD options)
  198. /*++
  199. Implements:
  200. IDataMover::BeginSession
  201. --*/
  202. {
  203. HRESULT hr = S_OK;
  204. WsbTraceIn(OLESTR("CNtTapeIo::BeginSession"), OLESTR("<%ls> <%ls> <%d> <0x%08x>"),
  205. remoteSessionName, remoteSessionDescription, remoteDataSet, options);
  206. CComPtr<IStream> pStream;
  207. ULARGE_INTEGER nil = {0,0};
  208. try {
  209. MvrInjectError(L"Inject.CNtTapeIo::BeginSession.0");
  210. WsbAssert(remoteDataSet > 0, MVR_E_INVALIDARG);
  211. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  212. // This may be overkill, but just in case we verify we're working with the correct media.
  213. CWsbBstrPtr label;
  214. WsbAffirmHr(ReadLabel(&label));
  215. WsbAssertHr(VerifyLabel(label));
  216. // Create the remote stream used for the entire session.
  217. WsbAffirmHr(CreateRemoteStream(L"", MVR_MODE_WRITE, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  218. WsbAffirmPointer(pStream);
  219. SHORT startSet = remoteDataSet;
  220. UINT64 addr1=0, addr2=0;
  221. LONG tapeMarks=0;
  222. //
  223. // Only allow append at EOD or last data set
  224. //
  225. tapeMarks = 1 + (startSet-1)*2;
  226. if ( MVR_SESSION_APPEND_TO_DATA_SET & options ) {
  227. tapeMarks += 2;
  228. }
  229. int retry = 3; // We allow a two pass error recovery, one for each possible
  230. // missing filemark, we abort on failure of the third attempt.
  231. do {
  232. hr = S_OK;
  233. // Each pass recovers from a single missing filemark (two max).
  234. // This is the case where a files were recorded to media but the
  235. // EndSession() method was never called or did not complete (i.e. power failure).
  236. try {
  237. WsbAssertPointer(m_pSession);
  238. // Make sure we have a consistant data set. We handle a single instance of
  239. // a partially written data set, including those with a missing EOD marker.
  240. // NOTE: The MISSING EOD error may eventually be detected by ERROR_NOT_FOUND, per Chuck Parks.
  241. WsbAffirmHr(RewindTape());
  242. WsbAffirmHrOk(SpaceFilemarks(tapeMarks, &addr1));
  243. WsbAffirmHr(SpaceToEndOfData(&addr2));
  244. /*
  245. hr = SpaceFilemarks(tapeMarks, &addr1);
  246. if (S_OK != hr) {
  247. // TODO: FIX: Clean this up when missing EOD marker results in ERROR_NOT_FOUND.
  248. // We're missing Filemarks or the EOD marker.
  249. // If the EOD marker is missing the SpaceToEndOfData will again return same hr.
  250. if (hr == SpaceToEndOfData(&addr2)) {
  251. WsbAffirm(addr1 == addr2, MVR_E_OVERWRITE_NOT_ALLOWED);
  252. WsbThrow(MVR_E_NOT_FOUND); // handled by recovery code!
  253. }
  254. else {
  255. WsbThrow(hr); // Can't recover, just throw the original error
  256. }
  257. }
  258. else {
  259. WsbAffirmHr(SpaceToEndOfData(&addr2));
  260. }
  261. */
  262. //
  263. // Affirm that we are at the end of tape.
  264. //
  265. WsbAffirm(addr1 == addr2, MVR_E_OVERWRITE_NOT_ALLOWED);
  266. //
  267. // Affirm that we are starting at a consistent location.
  268. // Is there at least a TAPE DBLK + filemark.
  269. //
  270. WsbAffirm(addr1 > 1, MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  271. if ( MVR_SESSION_APPEND_TO_DATA_SET & options ) {
  272. WsbAffirmHr(SpaceToEndOfData(&addr1));
  273. WsbAffirmHrOk(SpaceFilemarks(-2, &addr2));
  274. //
  275. // Affirm that we are at the end of a data set.
  276. //
  277. WsbAffirm(addr1-3 == addr2, MVR_E_OVERWRITE_NOT_ALLOWED);
  278. // TODO: We need to read ESET/or SSET to esablish state of the
  279. // data set we're appending.
  280. m_DataSetNumber = remoteDataSet;
  281. // Align the stream I/O model
  282. LARGE_INTEGER zero = {0,0};
  283. WsbAffirmHr(Seek(zero, STREAM_SEEK_CUR, NULL));
  284. break;
  285. }
  286. else {
  287. // MVR_SESSION_OVERWRITE_DATA_SET
  288. // MVR_SESSION_AS_LAST_DATA_SET
  289. m_DataSetNumber = remoteDataSet;
  290. // Align the stream I/O model
  291. LARGE_INTEGER zero = {0,0};
  292. WsbAffirmHr(Seek(zero, STREAM_SEEK_CUR, NULL));
  293. //
  294. // Convert session option type bits to MTFSessionType
  295. //
  296. MTFSessionType type;
  297. switch (options & MVR_SESSION_TYPES) {
  298. case MVR_SESSION_TYPE_TRANSFER:
  299. type = MTFSessionTypeTransfer;
  300. break;
  301. case MVR_SESSION_TYPE_COPY:
  302. type = MTFSessionTypeCopy;
  303. break;
  304. case MVR_SESSION_TYPE_NORMAL:
  305. type = MTFSessionTypeNormal;
  306. break;
  307. case MVR_SESSION_TYPE_DIFFERENTIAL:
  308. type = MTFSessionTypeDifferential;
  309. break;
  310. case MVR_SESSION_TYPE_INCREMENTAL:
  311. type = MTFSessionTypeIncremental;
  312. break;
  313. case MVR_SESSION_TYPE_DAILY:
  314. type = MTFSessionTypeDaily;
  315. break;
  316. default:
  317. type = MTFSessionTypeCopy;
  318. break;
  319. }
  320. // Write the SSET DBLK
  321. // This does not actually write anything to tape; only writes to the transfer buffer
  322. WsbAffirmHr(m_pSession->DoSSETDblk(remoteSessionName, remoteSessionDescription, type, remoteDataSet));
  323. // After the tape head is in the right place, we want to make sure
  324. // that we ask the driver for free space and not use internal counting
  325. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  326. WsbAffirmPointer(pInfo);
  327. WsbAffirmHr(pInfo->SetFreeSpace(-1));
  328. WsbAffirmHr(GetLargestFreeSpace(NULL, NULL));
  329. break;
  330. }
  331. } catch (HRESULT catchHr) {
  332. hr = catchHr;
  333. // Only allow two attempts at recovery
  334. WsbAffirm(retry > 1, MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  335. if ( MVR_E_NOT_FOUND == hr) {
  336. // TODO: FIX: this goes away when missing EOD marker results in ERROR_NOT_FOUND.
  337. // Recovery code for missing EOD marker
  338. SpaceToEndOfData(NULL); // Redundant!
  339. WsbAffirmHr(WriteFilemarks(1));
  340. }
  341. else if ( MVR_S_NO_DATA_DETECTED == hr) {
  342. // Recovery code for missing end of data set.
  343. try {
  344. CWsbBstrPtr name;
  345. CWsbBstrPtr desc;
  346. if ( m_pCartridge ) {
  347. m_pCartridge->GetName(&name);
  348. m_pCartridge->GetDescription(&desc);
  349. }
  350. WsbLogEvent(MVR_MESSAGE_INCOMPLETE_DATA_SET_DETECTED, 0, NULL,
  351. WsbLongAsString(startSet-1),
  352. (WCHAR *) name, (WCHAR *) desc, NULL);
  353. //
  354. // Make the end data set conform to: filemark + ESET + filemark,
  355. // for the previous session. This may require two passes.
  356. //
  357. // Recoverable Exceptions:
  358. // 1) Partial data set (no trailing filemark + ESET + filemark).
  359. // This occurs from power-off during Write() of data. Two pass recovery;
  360. // write filemark, then EndSession().
  361. // 2) Partial data set (filemark with no trailing ESET + filemark).
  362. // This occurs from power-off during EndSession() before ESET.
  363. // One pass recovery; EndSession();
  364. // 3) Partial data set (ESET with no trailing filemark).
  365. // This occurs from power-off during EndSession() after ESET.
  366. // One pass recovery; write filemark.
  367. // Non-Recoverable Exceptions detected:
  368. // a) No filemarks at expected locations.
  369. // b) No data set (no data, no trailing filemark + ESET + filemark).
  370. // This occurs from power-off after BeginSession(), but before device
  371. // buffer is flushed, and no SSET is written to tape, application
  372. // database may have recorded a successfull BeginSession(). For
  373. // this case BeginSession() returns MVR_E_DATA_SET_MISSING.
  374. // c) Blank tape, no label, no filemarks, or inconsistent tape.
  375. //
  376. // From ntBackup testing this apprears to be enough, in that we do not
  377. // need to rebuild complete ESET info from previous SSET. The last
  378. // ControlBlockId is not required to be valid. (Brian, 9/23/97)
  379. //
  380. // Detect condition (a) through (c) or some variant.
  381. if ( tapeMarks-2 > 0) {
  382. // Verify that EOD is not at the beginning of the previous data set.
  383. WsbAffirmHr(RewindTape());
  384. WsbAffirmHrOk(SpaceFilemarks(tapeMarks-2, &addr1)); // (a)
  385. WsbAffirmHr(SpaceToEndOfData(&addr2));
  386. if ( addr1 == addr2 ) {
  387. WsbThrow(MVR_E_DATA_SET_MISSING); // (b)
  388. }
  389. }
  390. else {
  391. WsbThrow(MVR_E_INCONSISTENT_MEDIA_LAYOUT); // (c)
  392. }
  393. // Check for a Filemark at EOD
  394. WsbAffirmHr(SpaceToEndOfData(&addr1));
  395. WsbAffirmHrOk(SpaceFilemarks(-1, &addr2));
  396. if (addr1-1 == addr2 ) {
  397. // Align the stream I/O model to the end of the dataset;
  398. // Set the stream pointer to before the Filemark that
  399. // terminates the dataset and preceeds the ESET.
  400. LARGE_INTEGER zero = {0,0};
  401. WsbAffirmHr(Seek(zero, STREAM_SEEK_CUR, NULL));
  402. // Write the trailing filemark, ESET DBLK, and filemark
  403. WsbAffirmHr(m_pSession->DoEndOfDataSet( (USHORT) ( startSet - 1 ) ));
  404. }
  405. else {
  406. WsbAffirmHr(SpaceToEndOfData(NULL));
  407. WsbAffirmHr(WriteFilemarks(1));
  408. }
  409. WsbLogEvent(MVR_MESSAGE_DATA_SET_RECOVERED, 0, NULL, NULL);
  410. } catch (HRESULT catchHr) {
  411. hr = catchHr;
  412. WsbLogEvent(MVR_MESSAGE_DATA_SET_NOT_RECOVERABLE, 0, NULL, WsbHrAsString(hr), NULL);
  413. WsbThrow(hr);
  414. } // end catch
  415. }
  416. else {
  417. WsbThrow(hr);
  418. }
  419. } // end catch
  420. } while (retry-- > 0);
  421. } WsbCatchAndDo(hr,
  422. WsbLogEvent(MVR_MESSAGE_DATA_SET_NOT_CREATED, 0, NULL, WsbHrAsString(hr), NULL);
  423. (void) CloseStream();
  424. );
  425. WsbTraceOut(OLESTR("CNtTapeIo::BeginSession"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  426. return hr;
  427. }
  428. STDMETHODIMP
  429. CNtTapeIo::EndSession(void)
  430. /*++
  431. Implements:
  432. IDataMover::EndSession
  433. --*/
  434. {
  435. HRESULT hr = S_OK;
  436. WsbTraceIn(OLESTR("CNtTapeIo::EndSession"), OLESTR(""));
  437. try {
  438. MvrInjectError(L"Inject.CNtTapeIo::EndSession.0");
  439. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  440. // Write the trailing filemark, ESET DBLK, and filemark
  441. WsbAffirmHr(m_pSession->DoEndOfDataSet(m_DataSetNumber));
  442. } WsbCatch(hr);
  443. (void) CloseStream();
  444. WsbTraceOut(OLESTR("CNtTapeIo::EndSession"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  445. return hr;
  446. }
  447. STDMETHODIMP
  448. CNtTapeIo::StoreData(
  449. IN BSTR localName,
  450. IN ULARGE_INTEGER localDataStart,
  451. IN ULARGE_INTEGER localDataSize,
  452. IN DWORD flags,
  453. OUT ULARGE_INTEGER *pRemoteDataSetStart,
  454. OUT ULARGE_INTEGER *pRemoteFileStart,
  455. OUT ULARGE_INTEGER *pRemoteFileSize,
  456. OUT ULARGE_INTEGER *pRemoteDataStart,
  457. OUT ULARGE_INTEGER *pRemoteDataSize,
  458. OUT DWORD *pRemoteVerificationType,
  459. OUT ULARGE_INTEGER *pRemoteVerificationData,
  460. OUT DWORD *pDatastreamCRCType,
  461. OUT ULARGE_INTEGER *pDatastreamCRC,
  462. OUT ULARGE_INTEGER *pUsn)
  463. /*++
  464. Implements:
  465. IDataMover::StoreData
  466. --*/
  467. {
  468. HRESULT hr = S_OK;
  469. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  470. HANDLE hFile = INVALID_HANDLE_VALUE;
  471. WsbTraceIn(OLESTR("CNtTapeIo::StoreData"), OLESTR("<%ls> <%I64u> <%I64u> <0x%08x>"),
  472. WsbAbbreviatePath((WCHAR *) localName, 120), localDataStart.QuadPart, localDataSize.QuadPart, flags);
  473. WsbTraceAlways(OLESTR("CNtTapeIo::StoreData - Begin\n"));
  474. try {
  475. MvrInjectError(L"Inject.CNtTapeIo::StoreData.0");
  476. WsbAssertPointer(m_pSession);
  477. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  478. // Default is to perform non-case sensitive searches.
  479. // So knock down the posix flag.
  480. m_Flags &= ~MVR_FLAG_POSIX_SEMANTICS;
  481. // Default is to not commit after each file.
  482. // So knock down the commit flag.
  483. m_Flags &= ~MVR_FLAG_COMMIT_FILE;
  484. // Default is to write one DIRB containing all directory info
  485. // instead of writing a DIRB for each directory level.
  486. // So knock down the write parent dir info flag.
  487. m_Flags &= ~MVR_FLAG_WRITE_PARENT_DIR_INFO;
  488. m_Flags |= flags;
  489. m_Flags |= MVR_MODE_WRITE;
  490. // Unconditionally set the case sensitive flag for each file.
  491. // We allow this flag to be set on a per file basis
  492. WsbTrace(OLESTR("Posix Semantics Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_POSIX_SEMANTICS & m_Flags));
  493. WsbAffirmHr(m_pSession->SetUseCaseSensitiveSearch(MVR_FLAG_POSIX_SEMANTICS & m_Flags));
  494. // This tells the session object to pad to a block boundary and flush the device
  495. // after the file is written.
  496. WsbTrace(OLESTR("Commit Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_COMMIT_FILE & m_Flags));
  497. WsbAffirmHr(m_pSession->SetCommitFile(MVR_FLAG_COMMIT_FILE & m_Flags));
  498. WsbTrace(OLESTR("ParentDirInfo Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_WRITE_PARENT_DIR_INFO & m_Flags));
  499. if ((MVR_FLAG_BACKUP_SEMANTICS & m_Flags) || (MVR_FLAG_HSM_SEMANTICS & m_Flags)) {
  500. // Compare the volume and path with the last ones written to tape.
  501. CWsbStringPtr pathname;
  502. WCHAR *end;
  503. LONG numChar;
  504. pathname = localName;
  505. WsbAffirm(0 != (WCHAR *)pathname, E_OUTOFMEMORY);
  506. // strip off the path and file name
  507. end = wcschr((WCHAR *)pathname, L'\\');
  508. WsbAssert(end != NULL, MVR_E_INVALIDARG);
  509. numChar =(LONG)(end - (WCHAR *)pathname + 1); // keep the trailing backslash
  510. WsbAssert(numChar > 0, E_UNEXPECTED);
  511. ((WCHAR *)pathname)[numChar] = L'\0';
  512. // We do a case sensitive search if using Posix semantics.
  513. WsbTrace(OLESTR("Comparing with last volume: <%ls>\n"), WsbAbbreviatePath((WCHAR *) m_LastVolume, 120));
  514. if ( ((MVR_FLAG_POSIX_SEMANTICS & ~m_Flags)) && (0 != _wcsicmp((WCHAR *) m_LastVolume, (WCHAR *) pathname)) ||
  515. ((MVR_FLAG_POSIX_SEMANTICS & m_Flags) && (0 != wcscmp((WCHAR *) m_LastVolume, (WCHAR *) pathname))) ) {
  516. // write the VOLB DBLK
  517. WsbAffirmHr(m_pSession->DoVolumeDblk(pathname));
  518. m_LastVolume = pathname;
  519. }
  520. pathname = localName;
  521. // strip off the file name
  522. end = wcsrchr((WCHAR *)pathname, L'\\');
  523. WsbAssert(end != NULL, MVR_E_INVALIDARG);
  524. numChar = (LONG)(end - (WCHAR *)pathname);
  525. WsbAssert(numChar > 0, E_UNEXPECTED);
  526. ((WCHAR *)pathname)[numChar] = L'\0';
  527. // pathname is now in the form "Volume{guid}\dir1\...\dirn"
  528. // or "<drive letter>:\dir1\...\dirn"
  529. /***
  530. m_Flags |= MVR_FLAG_WRITE_PARENT_DIR_INFO;
  531. ***/
  532. WsbTrace(OLESTR("Comparing with last path: <%ls>\n"), WsbAbbreviatePath((WCHAR *) m_LastPath, 120));
  533. // We do a case sensitive search if using Posix semantics.
  534. if ( ((MVR_FLAG_POSIX_SEMANTICS & ~m_Flags)) && (0 != _wcsicmp((WCHAR *) m_LastPath, (WCHAR *) pathname)) ||
  535. ((MVR_FLAG_POSIX_SEMANTICS & m_Flags) && (0 != wcscmp((WCHAR *) m_LastPath, (WCHAR *) pathname))) ) {
  536. if (MVR_FLAG_HSM_SEMANTICS & m_Flags) {
  537. // We're not supporting this anymore!
  538. WsbThrow(E_NOTIMPL);
  539. WCHAR szRoot[16];
  540. // We use a flat file structure for MVR_FLAG_HSM_SEMANTICS
  541. WsbAffirmHr(m_pSession->SetUseFlatFileStructure(TRUE));
  542. // do DIRB DBLKs for root
  543. wcscpy(szRoot, L"X:\\");
  544. szRoot[0] = localName[0];
  545. WsbAffirmHr(m_pSession->DoParentDirectories(szRoot));
  546. }
  547. else if (MVR_FLAG_WRITE_PARENT_DIR_INFO & m_Flags) {
  548. // do a DIRB DBLK for each directory level of the file(s) to be backed up.
  549. WsbAffirmHr(m_pSession->DoParentDirectories(pathname));
  550. m_LastPath = pathname;
  551. }
  552. else {
  553. // do one DIRB DBLK for the whole directory structure of the file(s) to be backed up.
  554. WIN32_FIND_DATAW obFindData;
  555. CWsbStringPtr tempPath;
  556. DWORD additionalSearchFlags = 0;
  557. additionalSearchFlags |= (m_Flags & MVR_FLAG_POSIX_SEMANTICS) ? FIND_FIRST_EX_CASE_SENSITIVE : 0;
  558. tempPath = pathname;
  559. tempPath.Prepend(OLESTR("\\\\?\\"));
  560. if (NULL == wcschr((WCHAR *)tempPath+4, L'\\'))
  561. {
  562. // no path (i.e. we're at the root)
  563. BY_HANDLE_FILE_INFORMATION obGetFileInfoData;
  564. memset(&obGetFileInfoData, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
  565. tempPath.Append(OLESTR("\\"));
  566. // ** WIN32 API Calls
  567. WsbAffirmHandle(hFile = CreateFile(tempPath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
  568. WsbAffirmStatus(GetFileInformationByHandle(hFile, &obGetFileInfoData));
  569. // copy info from GetFileInformationByHandle call (BY_HANDLE_FILE_INFORMATION struct)
  570. // .. into obFindData (WIN32_FIND_DATAW struct) for DoDirectoryDblk call.
  571. memset(&obFindData, 0, sizeof(WIN32_FIND_DATAW));
  572. obFindData.dwFileAttributes = obGetFileInfoData.dwFileAttributes;
  573. obFindData.ftCreationTime = obGetFileInfoData.ftCreationTime;
  574. obFindData.ftLastAccessTime = obGetFileInfoData.ftLastAccessTime;
  575. obFindData.ftLastWriteTime = obGetFileInfoData.ftLastWriteTime;
  576. }
  577. else {
  578. // ** WIN32 API Call - gets file info
  579. WsbAffirmHandle(hSearchHandle = FindFirstFileEx((WCHAR *) tempPath, FindExInfoStandard, &obFindData, FindExSearchLimitToDirectories, 0, additionalSearchFlags));
  580. }
  581. WsbAffirmHr(m_pSession->DoDirectoryDblk((WCHAR *) pathname, &obFindData));
  582. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  583. FindClose(hSearchHandle);
  584. hSearchHandle = INVALID_HANDLE_VALUE;
  585. }
  586. if (hFile != INVALID_HANDLE_VALUE) {
  587. CloseHandle(hFile);
  588. hFile = INVALID_HANDLE_VALUE;
  589. }
  590. m_LastPath = pathname;
  591. }
  592. }
  593. }
  594. // The following uses code to store multiple files, but the
  595. // RS Hints is only valid for the last file. With the current
  596. // implementation, the HSM engine sends one file request through
  597. // StoreData at a time. The caveat is that Posix is case
  598. // sensitive, and therefore files created in this fashion could
  599. // overload the same filename (ignoring case) with multiple files.
  600. WsbAffirmHr(m_pSession->DoDataSet(localName));
  601. *pRemoteDataSetStart = m_pSession->m_sHints.DataSetStart;
  602. *pRemoteFileStart = m_pSession->m_sHints.FileStart;
  603. *pRemoteFileSize = m_pSession->m_sHints.FileSize;
  604. *pRemoteDataStart = m_pSession->m_sHints.DataStart;
  605. *pRemoteDataSize = m_pSession->m_sHints.DataSize;
  606. *pRemoteVerificationType = m_pSession->m_sHints.VerificationType;
  607. *pRemoteVerificationData = m_pSession->m_sHints.VerificationData;
  608. *pDatastreamCRCType = m_pSession->m_sHints.DatastreamCRCType;
  609. *pDatastreamCRC = m_pSession->m_sHints.DatastreamCRC;
  610. *pUsn = m_pSession->m_sHints.FileUSN;
  611. } WsbCatchAndDo(hr,
  612. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  613. FindClose(hSearchHandle);
  614. hSearchHandle = INVALID_HANDLE_VALUE;
  615. }
  616. if (hFile != INVALID_HANDLE_VALUE) {
  617. CloseHandle(hFile);
  618. hFile = INVALID_HANDLE_VALUE;
  619. }
  620. WsbLogEvent(MVR_MESSAGE_DATA_TRANSFER_ERROR, 0, NULL,
  621. WsbAbbreviatePath((WCHAR *) localName, 120), WsbHrAsString(hr), NULL);
  622. // All fatal device errors are converted to E_ABORT so the calling code
  623. // can detect this general class of problem.
  624. // If the device error indicates bad media, convert to a different error code.
  625. switch(hr) {
  626. case MVR_E_BUS_RESET:
  627. case MVR_E_MEDIA_CHANGED:
  628. case MVR_E_NO_MEDIA_IN_DRIVE:
  629. case MVR_E_DEVICE_REQUIRES_CLEANING:
  630. case MVR_E_SHARING_VIOLATION:
  631. case MVR_E_ERROR_IO_DEVICE:
  632. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  633. case MVR_E_ERROR_NOT_READY:
  634. hr = E_ABORT;
  635. break;
  636. case MVR_E_INVALID_BLOCK_LENGTH:
  637. case MVR_E_WRITE_PROTECT:
  638. case MVR_E_CRC:
  639. hr = MVR_E_MEDIA_ABORT;
  640. break;
  641. default:
  642. break;
  643. }
  644. );
  645. WsbTraceAlways(OLESTR("CNtTapeIo::StoreData - End\n"));
  646. WsbTraceOut(OLESTR("CNtTapeIo::StoreData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  647. return hr;
  648. }
  649. STDMETHODIMP
  650. CNtTapeIo::RecallData(
  651. IN BSTR /*localName*/,
  652. IN ULARGE_INTEGER /*localDataStart*/,
  653. IN ULARGE_INTEGER /*localDataSize*/,
  654. IN DWORD /*flags*/,
  655. IN BSTR /*migrateFileName*/,
  656. IN ULARGE_INTEGER /*remoteDataSetStart*/,
  657. IN ULARGE_INTEGER /*remoteFileStart*/,
  658. IN ULARGE_INTEGER /*remoteFileSize*/,
  659. IN ULARGE_INTEGER /*remoteDataStart*/,
  660. IN ULARGE_INTEGER /*remoteDataSize*/,
  661. IN DWORD /*verificationType*/,
  662. IN ULARGE_INTEGER /*verificationData*/)
  663. /*++
  664. Implements:
  665. IDataMover::RecallData
  666. --*/
  667. {
  668. HRESULT hr = S_OK;
  669. WsbTraceIn(OLESTR("CNtTapeIo::RecallData"), OLESTR(""));
  670. try {
  671. WsbThrow(E_NOTIMPL);
  672. } WsbCatch(hr);
  673. WsbTraceOut(OLESTR("CNtTapeIo::RecallData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  674. return hr;
  675. }
  676. STDMETHODIMP
  677. CNtTapeIo::FormatLabel(
  678. IN BSTR displayName,
  679. OUT BSTR *pLabel)
  680. /*++
  681. Implements:
  682. IDataMover::FormatLabel
  683. --*/
  684. {
  685. HRESULT hr = S_OK;
  686. WsbTraceIn(OLESTR("CNtTapeIo::FormatLabel"), OLESTR("<%ls>"), displayName);
  687. try {
  688. CWsbStringPtr strGuid;
  689. MvrInjectError(L"Inject.CNtTapeIo::FormatLabel.0");
  690. WsbAssertPointer(pLabel);
  691. WsbAssertPointer(displayName);
  692. WsbAssert(wcslen((WCHAR *)displayName) > 0, E_INVALIDARG);
  693. WsbAssertPointer(m_pCartridge);
  694. // Media Label or Description
  695. CWsbBstrPtr label;
  696. // Tag
  697. label = OLESTR("MTF Media Label"); // Required text per MTF specification.
  698. // Version
  699. WsbAffirmHr(label.Append(OLESTR("|")));
  700. WsbAffirmHr(label.Append(WsbLongAsString(MTF_FORMAT_VER_MAJOR)));
  701. WsbAffirmHr(label.Append(OLESTR(".")));
  702. WsbAffirmHr(label.Append(WsbLongAsString(MTF_FORMAT_VER_MINOR)));
  703. // Vendor
  704. WsbAffirmHr(label.Append(OLESTR("|")));
  705. WsbAffirmHr(label.Append(REMOTE_STORAGE_MTF_VENDOR_NAME));
  706. // Vendor Product ID
  707. WsbAffirmHr(label.Append(OLESTR("|")));
  708. WsbAffirmHr(label.Append(REMOTE_STORAGE_MLL_SOFTWARE_NAME));
  709. // Creation Time Stamp
  710. WsbAffirmHr(label.Append(OLESTR("|")));
  711. WCHAR timeStamp[128];
  712. time_t lTime;
  713. time(&lTime);
  714. wcsftime(timeStamp, 128, L"%Y/%m/%d.%H:%M:%S", localtime(&lTime));
  715. WsbAffirmHr(label.Append(timeStamp));
  716. // Cartridge Label
  717. WsbAffirmHr(label.Append(OLESTR("|")));
  718. if (m_pCartridge) {
  719. // Use barcode if available
  720. CWsbBstrPtr barcode;
  721. if (S_OK == m_pCartridge->GetBarcode(&barcode)) {
  722. WsbAffirmHr(label.Append(barcode));
  723. }
  724. else {
  725. WsbAffirmHr(label.Append(displayName));
  726. }
  727. }
  728. else {
  729. WsbAffirmHr(label.Append(displayName));
  730. }
  731. // Side
  732. WsbAffirmHr(label.Append(OLESTR("|")));
  733. if (m_pCartridge) {
  734. // TODO: This is broken, we need to know if the cartridge is inverted?
  735. if (S_OK == m_pCartridge->IsTwoSided()) {
  736. WsbAffirmHr(label.Append(OLESTR("2")));
  737. }
  738. else {
  739. WsbAffirmHr(label.Append(OLESTR("1")));
  740. }
  741. }
  742. else {
  743. WsbAffirmHr(label.Append(OLESTR("1"))); // Default
  744. }
  745. // Media Id
  746. GUID cartId;
  747. WsbAffirmHr(label.Append(OLESTR("|")));
  748. if (m_pCartridge) {
  749. // Use cartridge Id
  750. if (S_OK == m_pCartridge->GetCartridgeId(&cartId)) {
  751. WsbAffirmHr(WsbSafeGuidAsString(cartId, strGuid));
  752. }
  753. else {
  754. WsbAffirmHr(WsbSafeGuidAsString(GUID_NULL, strGuid));
  755. }
  756. }
  757. else {
  758. WsbAffirmHr(WsbSafeGuidAsString(GUID_NULL, strGuid));
  759. }
  760. WsbAffirmHr(label.Append(strGuid));
  761. // Media Domain Id
  762. GUID mediaSetId;
  763. WsbAffirmHr(label.Append(OLESTR("|")));
  764. if (m_pCartridge) {
  765. // Use MediaSet Id
  766. if (S_OK == m_pCartridge->GetMediaSetId(&mediaSetId)) {
  767. WsbAffirmHr(WsbSafeGuidAsString(mediaSetId, strGuid));
  768. }
  769. else {
  770. WsbAffirmHr(WsbSafeGuidAsString(GUID_NULL, strGuid));
  771. }
  772. }
  773. else {
  774. WsbAffirmHr(WsbSafeGuidAsString(GUID_NULL, strGuid));
  775. }
  776. WsbAffirmHr(label.Append(strGuid));
  777. // Vendor Specific
  778. WsbAffirmHr(label.Append(OLESTR("|VS:DisplayName=")));
  779. WsbAffirmHr(label.Append(displayName));
  780. WsbAffirmHr(label.CopyToBstr(pLabel));
  781. } WsbCatch(hr);
  782. WsbTraceOut(OLESTR("CNtTapeIo::FormatLabel"), OLESTR("hr = <%ls>, label = <%ls>"), WsbHrAsString(hr), *pLabel);
  783. return hr;
  784. }
  785. STDMETHODIMP
  786. CNtTapeIo::WriteLabel(
  787. IN BSTR label)
  788. /*++
  789. Implements:
  790. IDataMover::WriteLabel
  791. --*/
  792. {
  793. HRESULT hr = S_OK;
  794. WsbTraceIn(OLESTR("CNtTapeIo::WriteLabel"), OLESTR("<%ls>"), label);
  795. try {
  796. MvrInjectError(L"Inject.CNtTapeIo::WriteLabel.0");
  797. WsbAssertPointer(label);
  798. WsbAssert(wcslen((WCHAR *)label) > 0, E_INVALIDARG);
  799. WsbAssertPointer(m_pCartridge);
  800. const ULONG maxIdSize = 1024;
  801. BYTE identifier[maxIdSize];
  802. ULONG idSize;
  803. ULONG idType;
  804. CComPtr<IStream> pStream;
  805. ULARGE_INTEGER nil = {0,0};
  806. // Create the remote stream.
  807. WsbAffirmHr(CreateRemoteStream(L"", MVR_MODE_WRITE, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  808. WsbAssertPointer(pStream);
  809. // Write the TAPE DBLK and filemark
  810. WsbAssertPointer(m_pSession);
  811. WsbAffirmHr(m_pSession->DoTapeDblk(label, maxIdSize, identifier, &idSize, &idType));
  812. WsbAffirmHr(CloseStream());
  813. pStream = NULL;
  814. // Now verify the label
  815. CWsbBstrPtr tempLabel;
  816. WsbAffirmHr(ReadLabel(&tempLabel));
  817. WsbAffirmHr(VerifyLabel(tempLabel));
  818. // Now that the tape header is written, we update the cartridge info.
  819. if (m_pCartridge) {
  820. WsbAffirmHr(m_pCartridge->SetOnMediaLabel(label));
  821. WsbAffirmHr(m_pCartridge->SetOnMediaIdentifier(identifier, (LONG) idSize, (LONG) idType));
  822. WsbAffirmHr(m_pCartridge->SetBlockSize(m_sMediaParameters.BlockSize));
  823. }
  824. } WsbCatchAndDo(hr,
  825. (void) CloseStream();
  826. );
  827. WsbTraceOut(OLESTR("CNtTapeIo::WriteLabel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  828. return hr;
  829. }
  830. STDMETHODIMP
  831. CNtTapeIo::ReadLabel(
  832. IN OUT BSTR *pLabel)
  833. /*++
  834. Implements:
  835. IDataMover::ReadLabel
  836. --*/
  837. {
  838. HRESULT hr = S_OK;
  839. WsbTraceIn(OLESTR("CNtTapeIo::ReadLabel"), OLESTR(""));
  840. CComPtr<IStream> pStream;
  841. try {
  842. MvrInjectError(L"Inject.CNtTapeIo::ReadLabel.0");
  843. WsbAssertPointer(pLabel);
  844. // Read the MTF TAPE DBLK, and pull out the label.
  845. ULARGE_INTEGER nil = {0,0};
  846. // Create remote stream of copy
  847. WsbAffirmHr(CreateRemoteStream(L"", MVR_MODE_READ | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  848. WsbAssertPointer(pStream);
  849. // Read label
  850. CWsbStringPtr label;
  851. WsbAffirmHr(m_pSession->ReadTapeDblk(&label));
  852. WsbAffirmHr(CloseStream());
  853. pStream = NULL;
  854. WsbAffirmHr(label.CopyToBstr(pLabel));
  855. } WsbCatchAndDo(hr,
  856. if (pStream) {
  857. (void) CloseStream();
  858. }
  859. );
  860. WsbTraceOut(OLESTR("CNtTapeIo::ReadLabel"), OLESTR("hr = <%ls>, label = <%ls>"), WsbHrAsString(hr), *pLabel);
  861. return hr;
  862. }
  863. STDMETHODIMP
  864. CNtTapeIo::VerifyLabel(
  865. IN BSTR label)
  866. /*++
  867. Implements:
  868. IDataMover::VerifyLabel
  869. --*/
  870. {
  871. HRESULT hr = S_OK;
  872. WsbTraceIn(OLESTR("CNtTapeIo::VerifyLabel"), OLESTR("<%ls>"), label);
  873. GUID mediaId[2];
  874. try {
  875. MvrInjectError(L"Inject.CNtTapeIo::VerifyLabel.0");
  876. WsbAssertPointer(label);
  877. WsbAssert(wcslen((WCHAR *)label) > 0, E_INVALIDARG);
  878. WsbAssertPointer(m_pCartridge);
  879. //
  880. // To verify a label we assert that the on-media Id matches the cartridge Id.
  881. //
  882. // From the media label we obtain the on-media Id.
  883. //
  884. WCHAR delim[] = OLESTR("|");
  885. WCHAR *token;
  886. int index = 0;
  887. token = wcstok((WCHAR *)label, delim); // !!! This toasts the string !!!
  888. while( token != NULL ) {
  889. index++;
  890. switch ( index ) {
  891. case 1: // Tag
  892. case 2: // Version
  893. case 3: // Vendor
  894. case 4: // Vendor Product ID
  895. case 5: // Creation Time Stamp
  896. case 6: // Cartridge Label
  897. case 7: // Side
  898. break;
  899. case 8: // Media ID
  900. WsbGuidFromString(token, &mediaId[0]);
  901. break;
  902. case 9: // Media Domain ID
  903. default: // Vendor specific of the form: L"VS:Name=Value"
  904. break;
  905. }
  906. token = wcstok( NULL, delim );
  907. }
  908. if (m_pCartridge) {
  909. //
  910. // Now compare on-media Id taken from the label to the cartridge's object Id.
  911. //
  912. WsbAffirmHr(m_pCartridge->GetCartridgeId(&mediaId[1]));
  913. WsbAffirm(mediaId[0] == mediaId[1], MVR_E_UNEXPECTED_MEDIA_ID_DETECTED);
  914. }
  915. m_ValidLabel = TRUE;
  916. } WsbCatchAndDo(hr,
  917. m_ValidLabel = FALSE;
  918. CWsbBstrPtr name;
  919. CWsbBstrPtr desc;
  920. if ( m_pCartridge ) {
  921. m_pCartridge->GetName(&name);
  922. m_pCartridge->GetDescription(&desc);
  923. }
  924. WsbLogEvent(MVR_MESSAGE_ON_MEDIA_ID_VERIFY_FAILED, 2*sizeof(GUID), mediaId,
  925. (WCHAR *) name, (WCHAR *) desc, WsbHrAsString(hr));
  926. );
  927. WsbTraceOut(OLESTR("CNtTapeIo::VerifyLabel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  928. return hr;
  929. }
  930. STDMETHODIMP
  931. CNtTapeIo::GetDeviceName(
  932. OUT BSTR *pName)
  933. /*++
  934. Implements:
  935. IDataMover::GetDeviceName
  936. --*/
  937. {
  938. HRESULT hr = S_OK;
  939. try {
  940. WsbAssertPointer(pName);
  941. WsbAffirmHr(m_DeviceName.CopyToBstr(pName));
  942. } WsbCatch( hr );
  943. return hr;
  944. }
  945. STDMETHODIMP
  946. CNtTapeIo::SetDeviceName(
  947. IN BSTR name,
  948. IN BSTR /*unused*/)
  949. /*++
  950. Implements:
  951. IDataMover::SetDeviceName
  952. --*/
  953. {
  954. m_DeviceName = name;
  955. return S_OK;
  956. }
  957. STDMETHODIMP
  958. CNtTapeIo::GetLargestFreeSpace(
  959. OUT LONGLONG *pFreeSpace,
  960. OUT LONGLONG *pCapacity,
  961. IN ULONG defaultFreeSpaceLow,
  962. IN LONG defaultFreeSpaceHigh)
  963. /*++
  964. Implements:
  965. IDataMover::GetLargestFreeSpace
  966. Note:
  967. The defaultFreeSpace parameter is used by the mover to maintain internally
  968. media free space in case that the device doesn't provide this information.
  969. If the device supports reporting on free space, then this parameter has no affect.
  970. --*/
  971. {
  972. HRESULT hr = S_OK;
  973. WsbTraceIn(OLESTR("CNtTapeIo::GetLargestFreeSpace"), OLESTR(""));
  974. const LONGLONG MaxBytes = 0x7fffffffffffffff;
  975. LONGLONG capacity = MaxBytes;
  976. LONGLONG remaining = capacity;
  977. LARGE_INTEGER defaultFreeSpace;
  978. if ((defaultFreeSpaceLow == 0xFFFFFFFF) && (defaultFreeSpaceHigh == 0xFFFFFFFF)) {
  979. defaultFreeSpace.QuadPart = -1;
  980. } else {
  981. defaultFreeSpace.LowPart = defaultFreeSpaceLow;
  982. defaultFreeSpace.HighPart = defaultFreeSpaceHigh;
  983. }
  984. try {
  985. MvrInjectError(L"Inject.CNtTapeIo::GetLargestFreeSpace.0");
  986. // Check if we already have valid space info for the cartridge.
  987. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  988. WsbAffirmHr(pInfo->GetLargestFreeSpace(&remaining));
  989. WsbAffirmHr(pInfo->GetCapacity(&capacity));
  990. // Zero or Negative bytes remaining indicate the free space
  991. // may be stale, so go directly to the device for
  992. // the value.
  993. if (remaining <= 0) {
  994. WsbTrace(OLESTR("CNtTapeIo::GetLargestFreeSpace - Getting capacity and free-space from the device\n"));
  995. capacity = MaxBytes;
  996. remaining = capacity;
  997. if (INVALID_HANDLE_VALUE == m_hTape) {
  998. WsbAffirmHr(OpenTape());
  999. }
  1000. TAPE_GET_DRIVE_PARAMETERS sDriveParameters;
  1001. DWORD sizeOfDriveParameters = sizeof(TAPE_GET_DRIVE_PARAMETERS);
  1002. memset(&sDriveParameters, 0, sizeOfDriveParameters);
  1003. WsbAffirmHrOk(IsAccessEnabled());
  1004. try {
  1005. MvrInjectError(L"Inject.CNtTapeIo::GetLargestFreeSpace.GetTapeParameters.1.0");
  1006. // ** WIN32 Tape API Call - get the tape drive parameters
  1007. WsbAffirmNoError(GetTapeParameters(m_hTape, GET_TAPE_DRIVE_INFORMATION, &sizeOfDriveParameters, &sDriveParameters));
  1008. MvrInjectError(L"Inject.CNtTapeIo::GetLargestFreeSpace.GetTapeParameters.1.1");
  1009. } WsbCatchAndDo(hr,
  1010. CWsbStringPtr tmpString;
  1011. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_GETFREESPACE) != S_OK) {
  1012. tmpString = L"";
  1013. }
  1014. hr = MapTapeError(hr, tmpString);
  1015. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  1016. WsbThrow(hr);
  1017. );
  1018. TAPE_GET_MEDIA_PARAMETERS sMediaParameters;
  1019. DWORD sizeOfMediaParameters = sizeof(TAPE_GET_MEDIA_PARAMETERS);
  1020. memset(&sMediaParameters, 0, sizeOfMediaParameters);
  1021. try {
  1022. MvrInjectError(L"Inject.CNtTapeIo::GetLargestFreeSpace.GetTapeParameters.2.0");
  1023. // ** WIN32 Tape API Call - get the media parameters
  1024. WsbAffirmNoError(GetTapeParameters(m_hTape, GET_TAPE_MEDIA_INFORMATION, &sizeOfMediaParameters, &sMediaParameters));
  1025. MvrInjectError(L"Inject.CNtTapeIo::GetLargestFreeSpace.GetTapeParameters.2.1");
  1026. } WsbCatchAndDo(hr,
  1027. CWsbStringPtr tmpString;
  1028. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_GETFREESPACE) != S_OK) {
  1029. tmpString = L"";
  1030. }
  1031. hr = MapTapeError(hr, tmpString);
  1032. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  1033. WsbThrow(hr);
  1034. );
  1035. if ( sDriveParameters.FeaturesLow & TAPE_DRIVE_TAPE_CAPACITY ) {
  1036. capacity = sMediaParameters.Capacity.QuadPart;
  1037. if ( 0 == capacity ) {
  1038. // Bogus value!
  1039. capacity = MaxBytes;
  1040. }
  1041. }
  1042. if ( sDriveParameters.FeaturesLow & TAPE_DRIVE_TAPE_REMAINING ) {
  1043. remaining = sMediaParameters.Remaining.QuadPart;
  1044. }
  1045. else {
  1046. // Use default value if given, otherwise, set to capacity
  1047. if (defaultFreeSpace.QuadPart >= 0) {
  1048. remaining = defaultFreeSpace.QuadPart;
  1049. } else {
  1050. remaining = capacity;
  1051. }
  1052. }
  1053. WsbAffirmHr(pInfo->SetFreeSpace(remaining));
  1054. WsbAffirmHr(pInfo->SetCapacity(capacity));
  1055. }
  1056. } WsbCatch(hr);
  1057. // Fill in the return parameters
  1058. if ( pCapacity ) {
  1059. *pCapacity = capacity;
  1060. }
  1061. if ( pFreeSpace ) {
  1062. *pFreeSpace = remaining;
  1063. }
  1064. WsbTraceOut(OLESTR("CNtTapeIo::GetLargestFreeSpace"), OLESTR("hr = <%ls>, free=%I64d, capacity=%I64d"), WsbHrAsString(hr), remaining, capacity);
  1065. return hr;
  1066. }
  1067. STDMETHODIMP
  1068. CNtTapeIo::SetInitialOffset(
  1069. IN ULARGE_INTEGER initialOffset
  1070. )
  1071. /*++
  1072. Implements:
  1073. IDataMover::SetInitialOffset
  1074. Notes:
  1075. Set Initial stream offset (without explicitly seeking the stream to this offset)
  1076. --*/
  1077. {
  1078. HRESULT hr = S_OK;
  1079. WsbTraceIn(OLESTR("CNtTapeIo::SetInitialOffset"), OLESTR(""));
  1080. m_StreamOffset.QuadPart = initialOffset.QuadPart;
  1081. if (m_StreamOffset.QuadPart > m_StreamSize.QuadPart) {
  1082. m_StreamSize = m_StreamOffset;
  1083. }
  1084. WsbTraceOut(OLESTR("CNtTapeIo::SetInitialOffset"), OLESTR("hr = <%ls> offset = %I64u"), WsbHrAsString(hr), initialOffset.QuadPart);
  1085. return hr;
  1086. }
  1087. STDMETHODIMP
  1088. CNtTapeIo::GetCartridge(
  1089. OUT IRmsCartridge **ptr)
  1090. /*++
  1091. Implements:
  1092. IDataMover::GetCartridge
  1093. --*/
  1094. {
  1095. HRESULT hr = S_OK;
  1096. try {
  1097. WsbAssertPointer( ptr );
  1098. *ptr = m_pCartridge;
  1099. m_pCartridge.p->AddRef();
  1100. } WsbCatch( hr );
  1101. return hr;
  1102. }
  1103. STDMETHODIMP
  1104. CNtTapeIo::SetCartridge(
  1105. IN IRmsCartridge *ptr)
  1106. /*++
  1107. Implements:
  1108. IDataMover::SetCartridge
  1109. --*/
  1110. {
  1111. HRESULT hr = S_OK;
  1112. try {
  1113. WsbAssertPointer( ptr );
  1114. if ( m_pCartridge )
  1115. m_pCartridge = 0;
  1116. m_pCartridge = ptr;
  1117. } WsbCatch( hr );
  1118. return hr;
  1119. }
  1120. STDMETHODIMP
  1121. CNtTapeIo::Cancel(void)
  1122. /*++
  1123. Implements:
  1124. IDataMover::Cancel
  1125. --*/
  1126. {
  1127. HRESULT hr = S_OK;
  1128. WsbTraceIn(OLESTR("CNtTapeIo::Cancel"), OLESTR(""));
  1129. try {
  1130. (void) Revert();
  1131. (void) CloseStream();
  1132. (void) CloseTape();
  1133. } WsbCatch(hr);
  1134. WsbTraceOut(OLESTR("CNtTapeIo::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1135. return hr;
  1136. }
  1137. STDMETHODIMP
  1138. CNtTapeIo::CreateLocalStream(
  1139. IN BSTR /*name*/,
  1140. IN DWORD /*mode*/,
  1141. OUT IStream ** /*ppStream*/)
  1142. /*++
  1143. Implements:
  1144. IDataMover::CreateLocalStream
  1145. --*/
  1146. {
  1147. HRESULT hr = S_OK;
  1148. WsbTraceIn(OLESTR("CNtTapeIo::CreateLocalStream"), OLESTR(""));
  1149. try {
  1150. WsbThrow(E_NOTIMPL);
  1151. } WsbCatch(hr);
  1152. WsbTraceOut(OLESTR("CNtTapeIo::CreateLocalStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1153. return hr;
  1154. }
  1155. STDMETHODIMP
  1156. CNtTapeIo::CreateRemoteStream(
  1157. IN BSTR name,
  1158. IN DWORD mode,
  1159. IN BSTR remoteSessionName,
  1160. IN BSTR remoteSessionDescription,
  1161. IN ULARGE_INTEGER remoteDataSetStart,
  1162. IN ULARGE_INTEGER remoteFileStart,
  1163. IN ULARGE_INTEGER remoteFileSize,
  1164. IN ULARGE_INTEGER remoteDataStart,
  1165. IN ULARGE_INTEGER remoteDataSize,
  1166. IN DWORD remoteVerificationType,
  1167. IN ULARGE_INTEGER remoteVerificationData,
  1168. OUT IStream **ppStream)
  1169. /*++
  1170. Implements:
  1171. IDataMover::CreateRemoteStream
  1172. --*/
  1173. {
  1174. UNREFERENCED_PARAMETER(remoteSessionName);
  1175. UNREFERENCED_PARAMETER(remoteSessionDescription);
  1176. HRESULT hr = S_OK;
  1177. WsbTraceIn(OLESTR("CNtTapeIo::CreateRemoteStream"),
  1178. OLESTR("<%ls> <0x%08x> <%I64u> <%I64u> <%I64u> <%I64u> <%I64u> <0x%08x> <0x%08x> <0x%08x> <0x%08x>"),
  1179. name, mode, remoteDataSetStart.QuadPart, remoteFileStart.QuadPart, remoteFileSize.QuadPart,
  1180. remoteDataStart.QuadPart, remoteDataSize.QuadPart, remoteVerificationType,
  1181. remoteVerificationData.LowPart, remoteVerificationData.HighPart, ppStream);
  1182. try {
  1183. WsbAssertPointer(ppStream);
  1184. MvrInjectError(L"Inject.CNtTapeIo::CreateRemoteStream.0");
  1185. if (INVALID_HANDLE_VALUE == m_hTape) {
  1186. WsbAffirmHr(OpenTape());
  1187. }
  1188. WsbAffirmHrOk(IsAccessEnabled());
  1189. WsbAssert(m_sMediaParameters.BlockSize > 0, MVR_E_LOGIC_ERROR);
  1190. m_StreamName = name;
  1191. m_Mode = mode;
  1192. m_StreamPBA.QuadPart = 0xffffffffffffffff;
  1193. m_StreamOffset.QuadPart = 0;
  1194. m_StreamSize.QuadPart = remoteDataSize.QuadPart;
  1195. WsbAssert(NULL == m_pStreamBuf, MVR_E_LOGIC_ERROR); // We forgot a CloseStream somewhere
  1196. // We need to allocate memory for the internal buffer used to handle
  1197. // odd byte (non-block) size I/O requests. At a minumum we make the
  1198. // buffer 2x the block size.
  1199. ULONG bufferSize;
  1200. ULONG nBlocks = DefaultMinBufferSize/m_sMediaParameters.BlockSize;
  1201. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  1202. bufferSize = nBlocks * m_sMediaParameters.BlockSize;
  1203. WsbTrace( OLESTR("Using %d byte internal buffer.\n"), bufferSize);
  1204. m_pStreamBuf = (BYTE *) WsbAlloc(bufferSize);
  1205. WsbAssertPointer(m_pStreamBuf);
  1206. memset(m_pStreamBuf, 0, bufferSize);
  1207. m_StreamBufSize = bufferSize;
  1208. m_StreamBufUsed = 0;
  1209. m_StreamBufPosition = 0;
  1210. m_StreamBufStartPBA.QuadPart = 0;
  1211. if (m_pCartridge) {
  1212. if ( S_OK == m_pCartridge->LoadDataCache(m_pStreamBuf, &m_StreamBufSize, &m_StreamBufUsed, &m_StreamBufStartPBA) ) {
  1213. WsbTrace( OLESTR("DataCache loaded.\n"));
  1214. }
  1215. }
  1216. CComPtr<IStream> pStream;
  1217. WsbAssertHrOk(((IUnknown*) (IDataMover*) this)->QueryInterface( IID_IStream, (void **) &pStream));
  1218. WsbAssert(NULL == m_pSession, MVR_E_LOGIC_ERROR);
  1219. m_pSession = new CMTFSession();
  1220. WsbAssertPointer(m_pSession);
  1221. m_pSession->m_pStream = pStream;
  1222. m_pSession->m_sHints.DataSetStart.QuadPart = remoteDataSetStart.QuadPart;
  1223. m_pSession->m_sHints.FileStart.QuadPart = remoteFileStart.QuadPart;
  1224. m_pSession->m_sHints.FileSize.QuadPart = remoteFileSize.QuadPart;
  1225. m_pSession->m_sHints.DataStart.QuadPart = remoteDataStart.QuadPart;
  1226. m_pSession->m_sHints.DataSize.QuadPart = remoteDataSize.QuadPart;
  1227. m_pSession->m_sHints.VerificationType = remoteVerificationType;
  1228. m_pSession->m_sHints.VerificationData.QuadPart = remoteVerificationData.QuadPart;
  1229. // Set the Block Size used for the session.
  1230. WsbAffirmHr(m_pSession->SetBlockSize(m_sMediaParameters.BlockSize));
  1231. if (m_Mode & MVR_MODE_APPEND) {
  1232. // Sets the current position to the end of data.
  1233. LARGE_INTEGER zero = {0,0};
  1234. WsbAffirmHr(pStream->Seek(zero, STREAM_SEEK_END, NULL));
  1235. }
  1236. *ppStream = pStream;
  1237. pStream.p->AddRef();
  1238. } WsbCatchAndDo(hr,
  1239. (void) CloseStream();
  1240. );
  1241. WsbTraceOut(OLESTR("CNtTapeIo::CreateRemoteStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1242. return hr;
  1243. }
  1244. STDMETHODIMP
  1245. CNtTapeIo::CloseStream(void)
  1246. /*++
  1247. Implements:
  1248. IDataMover::CloseStream
  1249. --*/
  1250. {
  1251. HRESULT hr = S_OK;
  1252. WsbTraceIn(OLESTR("CNtTapeIo::CloseStream"), OLESTR("StreamName=<%ls>"), m_StreamName);
  1253. try {
  1254. //
  1255. // For unformatted I/O we add filemark on close
  1256. //
  1257. if (m_Mode & MVR_MODE_UNFORMATTED) {
  1258. if ((m_Mode & MVR_MODE_WRITE) || (m_Mode & MVR_MODE_APPEND)) {
  1259. try {
  1260. WsbAffirmHr(WriteFilemarks(1));
  1261. } WsbCatch(hr);
  1262. }
  1263. }
  1264. //
  1265. // If we may have written to tape, sync up the space stats
  1266. // to reflect what device reports.
  1267. //
  1268. if ((m_Mode & MVR_MODE_WRITE) || (m_Mode & MVR_MODE_APPEND)) {
  1269. try {
  1270. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  1271. // marking the FreeSpace to -1 gaurantees it's stale for the
  1272. // following GetLargestFreeSpace() call.
  1273. WsbAffirmPointer(pInfo);
  1274. WsbAffirmHr(pInfo->SetFreeSpace(-1));
  1275. WsbAffirmHr(GetLargestFreeSpace(NULL, NULL));
  1276. } WsbCatchAndDo(hr,
  1277. hr = S_OK;
  1278. );
  1279. }
  1280. //
  1281. // Since the stream is closed, we re-init stream member data.
  1282. //
  1283. m_StreamName = MVR_UNDEFINED_STRING;
  1284. m_Mode = 0;
  1285. if (m_pSession) {
  1286. delete m_pSession;
  1287. m_pSession = NULL;
  1288. }
  1289. if (m_pStreamBuf) {
  1290. //
  1291. // Save of the internal buffer to the cartridge.
  1292. //
  1293. if ( S_OK == m_pCartridge->SaveDataCache(m_pStreamBuf, m_StreamBufSize, m_StreamBufUsed, m_StreamBufStartPBA) ) {
  1294. WsbTrace(OLESTR("DataCache saved.\n"));
  1295. }
  1296. // Clear internal buffer state
  1297. WsbFree(m_pStreamBuf);
  1298. m_pStreamBuf = NULL;
  1299. m_StreamBufSize = 0;
  1300. m_StreamBufUsed = 0;
  1301. m_StreamBufPosition = 0;
  1302. m_StreamBufStartPBA.QuadPart = 0;
  1303. }
  1304. } WsbCatch(hr);
  1305. WsbTraceOut(OLESTR("CNtTapeIo::CloseStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1306. return hr;
  1307. }
  1308. STDMETHODIMP
  1309. CNtTapeIo::Duplicate(
  1310. IN IDataMover *pCopy,
  1311. IN DWORD options,
  1312. OUT ULARGE_INTEGER *pBytesCopied,
  1313. OUT ULARGE_INTEGER *pBytesReclaimed)
  1314. /*++
  1315. Implements:
  1316. IDataMover::Duplicate
  1317. --*/
  1318. {
  1319. HRESULT hr = S_OK;
  1320. WsbTraceIn(OLESTR("CNtTapeIo::Duplicate"), OLESTR("<0x%08x>"), options);
  1321. CComPtr<IStream> pOriginalStream;
  1322. CComPtr<IStream> pCopyStream;
  1323. ULARGE_INTEGER bytesCopied = {0,0};
  1324. ULARGE_INTEGER bytesReclaimed = {0,0};
  1325. try {
  1326. MvrInjectError(L"Inject.CNtTapeIo::Duplicate.0");
  1327. ULARGE_INTEGER nil = {0,0};
  1328. ULARGE_INTEGER position = {0,0};
  1329. LARGE_INTEGER zero = {0,0};
  1330. LARGE_INTEGER seekTo = {0,0};
  1331. ULARGE_INTEGER originalEOD = {0,0};
  1332. ULARGE_INTEGER copyEOD = {0,0};
  1333. ULARGE_INTEGER bytesRead = {0,0};
  1334. ULARGE_INTEGER bytesWritten = {0,0};
  1335. BOOL refresh = ( options & MVR_DUPLICATE_REFRESH ) ? TRUE : FALSE;
  1336. BOOL moreToCopy = TRUE;
  1337. // Duplicate the unit of media.
  1338. // MVR_DUPLICATE_UPDATE - starts from the end of the copy.
  1339. // MVR_DUPLICATE_REFRESH - starts from the beginning of the original (except tape header)
  1340. while ( moreToCopy ) {
  1341. // We copy the SSET, data, and ESET as individual streams, and continue
  1342. // until there's nothing more to copy.
  1343. if ( refresh ) {
  1344. ULONG bytesRead;
  1345. // Create remote stream of copy
  1346. WsbAffirmHr(pCopy->CreateRemoteStream(L"Copy", MVR_MODE_WRITE | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pCopyStream));
  1347. WsbAssertPointer(pCopyStream);
  1348. // Sets the current position to beginning of data.
  1349. WsbAffirmHr(pCopyStream->Seek(zero, STREAM_SEEK_SET, &position));
  1350. // The MTF labels are < 1024 bytes. We need to read 1024 bytes + the filemark
  1351. // (1 block), 3x the min block size covers all cases.
  1352. WsbAssert(m_sMediaParameters.BlockSize > 0, MVR_E_LOGIC_ERROR);
  1353. ULONG nBlocks = (3*512)/m_sMediaParameters.BlockSize;
  1354. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  1355. ULONG bytesToRead = nBlocks * m_sMediaParameters.BlockSize;
  1356. BYTE *pBuffer = (BYTE *)WsbAlloc(bytesToRead);
  1357. WsbAssertPointer(pBuffer);
  1358. memset(pBuffer, 0, bytesToRead);
  1359. // Read upto first Filemark to skip over header.
  1360. hr = pCopyStream->Read(pBuffer, bytesToRead, &bytesRead);
  1361. WsbFree(pBuffer);
  1362. pBuffer = NULL;
  1363. WsbAssert(hr == MVR_S_FILEMARK_DETECTED, E_UNEXPECTED);
  1364. // Gets the current position... this is the low water mark of the copy.
  1365. WsbAffirmHr(pCopyStream->Seek(zero, STREAM_SEEK_CUR, &position));
  1366. refresh = FALSE;
  1367. }
  1368. else {
  1369. // Create remote stream of copy
  1370. WsbAffirmHr(pCopy->CreateRemoteStream(L"Copy", MVR_MODE_APPEND | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pCopyStream));
  1371. WsbAssertPointer(pCopyStream);
  1372. // Gets the current position... this is the low water mark of the copy.
  1373. WsbAffirmHr(pCopyStream->Seek(zero, STREAM_SEEK_CUR, &position));
  1374. }
  1375. // Create remote stream or original
  1376. WsbAffirmHr(CreateRemoteStream(L"Master", MVR_MODE_READ | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pOriginalStream));
  1377. WsbAssertPointer(pOriginalStream);
  1378. // Set the current position to the high water mark.
  1379. seekTo.QuadPart = position.QuadPart;
  1380. WsbAffirmHr(pOriginalStream->Seek( seekTo, STREAM_SEEK_SET, NULL));
  1381. // Now both streams are aligned for the copy.
  1382. ULARGE_INTEGER bytesToCopy = {0xffffffff, 0xffffffff};
  1383. // Copy from original to copy until we don't having anything more to read.
  1384. hr = pOriginalStream->CopyTo(pCopyStream, bytesToCopy, &bytesRead, &bytesWritten);
  1385. bytesCopied.QuadPart += bytesWritten.QuadPart;
  1386. if ( FAILED(hr) ) {
  1387. WsbThrow(hr);
  1388. }
  1389. if ( MVR_S_FILEMARK_DETECTED == hr ) {
  1390. WsbAffirmHr(pCopy->CloseStream());
  1391. pCopyStream = 0;
  1392. }
  1393. else {
  1394. // End of data
  1395. WsbAssert(MVR_S_NO_DATA_DETECTED == hr, E_UNEXPECTED);
  1396. moreToCopy = FALSE;
  1397. //
  1398. // Verify we're where we think we are..
  1399. //
  1400. // We should always have an EOD on the copy. So affirm OK.
  1401. //
  1402. WsbAffirmHrOk(pCopyStream->Seek(zero, STREAM_SEEK_END, &copyEOD));
  1403. //
  1404. // A missing EOD which gets translated to MVR_S_NO_DATA_DETECTED, or MVR_E_CRC,
  1405. // should not cause us to fail on the Seek.
  1406. //
  1407. HRESULT hrSeek = Seek(zero, STREAM_SEEK_END, &originalEOD);
  1408. WsbAffirm(originalEOD.QuadPart == copyEOD.QuadPart, (S_OK == hrSeek) ? E_ABORT : hrSeek);
  1409. // When we get EOD we don't write a FM, so revert RW Mode to prevent
  1410. // Filemarks from being written. This leaves the copy in an identical
  1411. // state with the master.
  1412. pCopyStream->Revert();
  1413. WsbAffirmHr(pCopy->CloseStream());
  1414. pCopyStream = 0;
  1415. hr = S_OK; // Normal completion
  1416. }
  1417. WsbAffirmHr(CloseStream());
  1418. pOriginalStream = 0;
  1419. }
  1420. } WsbCatchAndDo(hr,
  1421. // Revert resets the RW Mode to prevent Filemarks from being written
  1422. // after a copy error.
  1423. if (pCopyStream) {
  1424. pCopyStream->Revert();
  1425. pCopy->CloseStream();
  1426. }
  1427. if (pOriginalStream) {
  1428. pOriginalStream->Revert();
  1429. }
  1430. CloseStream();
  1431. );
  1432. if ( pBytesCopied ) {
  1433. pBytesCopied->QuadPart = bytesCopied.QuadPart;
  1434. }
  1435. if ( pBytesReclaimed ) {
  1436. pBytesReclaimed->QuadPart = bytesReclaimed.QuadPart;
  1437. }
  1438. WsbTraceOut(OLESTR("CNtTapeIo::Duplicate"), OLESTR("hr = <%ls>, bytesCopied=%I64u, bytesReclaimed=%I64u"),
  1439. WsbHrAsString(hr), bytesCopied.QuadPart, bytesReclaimed.QuadPart);
  1440. return hr;
  1441. }
  1442. STDMETHODIMP
  1443. CNtTapeIo::FlushBuffers(void)
  1444. /*++
  1445. Implements:
  1446. IDataMover::FlushBuffers
  1447. --*/
  1448. {
  1449. HRESULT hr = S_OK;
  1450. WsbTraceIn(OLESTR("CNtTapeIo::FlushBuffers"), OLESTR(""));
  1451. try {
  1452. MvrInjectError(L"Inject.CNtTapeIo::FlushBuffers.0");
  1453. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  1454. // Pad to the next physical block boundary and flush the device bufffer.
  1455. WsbAffirmHr(m_pSession->ExtendLastPadToNextPBA());
  1456. } WsbCatch(hr);
  1457. WsbTraceOut(OLESTR("CNtTapeIo::FlushBuffers"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1458. return hr;
  1459. }
  1460. STDMETHODIMP
  1461. CNtTapeIo::Recover(OUT BOOL *pDeleteFile)
  1462. /*++
  1463. Implements:
  1464. IDataMover::Recover
  1465. --*/
  1466. {
  1467. HRESULT hr = S_OK;
  1468. *pDeleteFile = FALSE;
  1469. WsbTraceIn(OLESTR("CNtTapeIo::Recover"), OLESTR(""));
  1470. try {
  1471. // Note: Recovery of the tape stream is done explicitly in BeginSession
  1472. // We might consider moving this code over here...
  1473. WsbThrow(E_NOTIMPL);
  1474. } WsbCatch(hr);
  1475. WsbTraceOut(OLESTR("CNtTapeIo::Recover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1476. return hr;
  1477. }
  1478. ////////////////////////////////////////////////////////////////////////////////
  1479. //
  1480. // IStream Implementation
  1481. //
  1482. STDMETHODIMP
  1483. CNtTapeIo::Read(
  1484. OUT void *pv,
  1485. IN ULONG cb,
  1486. OUT ULONG *pcbRead
  1487. )
  1488. /*++
  1489. Implements:
  1490. IStream::Read
  1491. Notes:
  1492. Only MVR_FLAG_HSM_SEMANTICS is currently supported.
  1493. Returns S_FALSE when no more data can be read from the stream. EOD or FILEMARK Detected.
  1494. --*/
  1495. {
  1496. HRESULT hr = S_OK;
  1497. WsbTraceIn(OLESTR("CNtTapeIo::Read"), OLESTR("Bytes Requested = %u, offset = %I64u, mode = 0x%08x"), cb, m_StreamOffset.QuadPart, m_Mode);
  1498. ULONG bytesRead = 0;
  1499. ULONG bytesToCopy = 0;
  1500. ULONG bytesToRead = 0;
  1501. try {
  1502. MvrInjectError(L"Inject.CNtTapeIo::Read.0");
  1503. WsbAssert( pv != 0, STG_E_INVALIDPOINTER );
  1504. BOOL bUseInternalBuffer = FALSE;
  1505. ULONG offsetToData = 0;
  1506. ULARGE_INTEGER pba = {0,0};
  1507. if ( MVR_FLAG_HSM_SEMANTICS & m_Mode ) {
  1508. //
  1509. // The m_DataStart field will point to the actual start of the data stream.
  1510. // The MTF stream header will be a few bytes before that.
  1511. //
  1512. if ( MVR_VERIFICATION_TYPE_NONE == m_pSession->m_sHints.VerificationType ) {
  1513. //
  1514. // No verification - no stream header
  1515. //
  1516. pba.QuadPart = ( m_pSession->m_sHints.DataSetStart.QuadPart +
  1517. m_pSession->m_sHints.FileStart.QuadPart +
  1518. m_pSession->m_sHints.DataStart.QuadPart +
  1519. m_StreamOffset.QuadPart )
  1520. / m_sMediaParameters.BlockSize;
  1521. offsetToData = (ULONG) (( m_pSession->m_sHints.DataSetStart.QuadPart +
  1522. m_pSession->m_sHints.FileStart.QuadPart +
  1523. m_pSession->m_sHints.DataStart.QuadPart +
  1524. m_StreamOffset.QuadPart)
  1525. % (unsigned _int64) m_sMediaParameters.BlockSize);
  1526. bytesToRead = cb + offsetToData;
  1527. }
  1528. else if (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType ) {
  1529. //
  1530. // Position to the stream header and crc it first.
  1531. //
  1532. pba.QuadPart = (m_pSession->m_sHints.DataSetStart.QuadPart +
  1533. m_pSession->m_sHints.FileStart.QuadPart +
  1534. (m_pSession->m_sHints.DataStart.QuadPart - sizeof(MTF_STREAM_INFO)) )
  1535. / m_sMediaParameters.BlockSize;
  1536. offsetToData = (ULONG) (( m_pSession->m_sHints.DataSetStart.QuadPart +
  1537. m_pSession->m_sHints.FileStart.QuadPart +
  1538. m_pSession->m_sHints.DataStart.QuadPart +
  1539. m_StreamOffset.QuadPart
  1540. - sizeof(MTF_STREAM_INFO))
  1541. % (unsigned _int64) m_sMediaParameters.BlockSize);
  1542. bytesToRead = cb + offsetToData + sizeof(MTF_STREAM_INFO);
  1543. }
  1544. else {
  1545. WsbThrow( E_UNEXPECTED );
  1546. }
  1547. }
  1548. else if ( MVR_MODE_UNFORMATTED & m_Mode ) {
  1549. pba.QuadPart = m_StreamOffset.QuadPart
  1550. / m_sMediaParameters.BlockSize;
  1551. offsetToData = (ULONG) ((m_StreamOffset.QuadPart)
  1552. % (unsigned _int64) m_sMediaParameters.BlockSize);
  1553. bytesToRead = cb + offsetToData;
  1554. }
  1555. else {
  1556. WsbThrow( E_UNEXPECTED );
  1557. }
  1558. //
  1559. // Check if the current read request requires a tape access
  1560. //
  1561. if (// pba starts before the internal buffer, OR
  1562. (pba.QuadPart < m_StreamBufStartPBA.QuadPart) ||
  1563. // pba starts beyond the internal buffer, OR
  1564. (pba.QuadPart >= (m_StreamBufStartPBA.QuadPart + (m_StreamBufUsed / m_sMediaParameters.BlockSize))) ||
  1565. // the internal buffer is not valid.
  1566. (!m_StreamBufUsed) ) {
  1567. //
  1568. // Then, we must read data from tape
  1569. //
  1570. //
  1571. // Set Position
  1572. //
  1573. if ( pba.QuadPart != m_StreamPBA.QuadPart ) {
  1574. //
  1575. // AffirmOk to fail if EOD reached before desired pba.
  1576. //
  1577. WsbAffirmHrOk(SetPosition(pba.QuadPart));
  1578. }
  1579. // We should now be positioned at the beginning of the block containing
  1580. // the start of the stream OR at the beginning of data.
  1581. //
  1582. // Read data
  1583. //
  1584. // We can use the output buffer if the offset and size are aligned
  1585. // on block boundaries and there is no verification , otherwise we must use
  1586. // the internal stream buffer.
  1587. //
  1588. if ( (MVR_VERIFICATION_TYPE_NONE != m_pSession->m_sHints.VerificationType ) ||
  1589. (offsetToData) ||
  1590. (cb % m_sMediaParameters.BlockSize) ) {
  1591. /*****************************************
  1592. !!! Old Method !!!
  1593. if ( bytesToRead < m_StreamBufSize ) {
  1594. // Round up the number of bytes to read so we read full blocks
  1595. bytesToRead = bytesToRead + m_sMediaParameters.BlockSize -
  1596. (bytesToRead % m_sMediaParameters.BlockSize);
  1597. }
  1598. *****************************************/
  1599. bytesToRead = m_StreamBufSize;
  1600. WsbTrace(OLESTR("Reading %u (%u) bytes...\n"), bytesToRead, m_StreamBufSize);
  1601. m_StreamBufStartPBA = pba;
  1602. hr = ReadBuffer(m_pStreamBuf, bytesToRead, &bytesRead);
  1603. if ( FAILED(hr) ) {
  1604. m_StreamBufUsed = 0;
  1605. WsbThrow(hr)
  1606. }
  1607. bUseInternalBuffer = TRUE;
  1608. m_StreamBufUsed = bytesRead;
  1609. //
  1610. // Do the verification here, if needed
  1611. //
  1612. if (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType ) {
  1613. MTF_STREAM_INFO sSTREAM;
  1614. WIN32_STREAM_ID sStreamHeader; // comes back from Win32 BackupRead
  1615. //
  1616. // If we're positioned before a tapemark, the read will succeed,
  1617. // but no bytes will have been read. This shouldn't happen when
  1618. // recalling data.
  1619. //
  1620. WsbAssert(bytesRead > 0, MVR_E_UNEXPECTED_DATA);
  1621. ///////////////////////////////////////////////////////////////////////////////////////
  1622. //
  1623. // TODO: Special code for when:
  1624. // offsetToData + sizeof(MTF_STREAM_INFO) > nBytesRead
  1625. //
  1626. // IMPORTANT NOTE: In theory this special case should be possible,
  1627. // but this has never been observed, so we assert
  1628. // to test the special case logic.
  1629. WsbAssert(offsetToData < bytesRead, MVR_E_UNEXPECTED_DATA);
  1630. WsbAssert((offsetToData + sizeof(MTF_STREAM_INFO)) <= bytesRead, MVR_E_UNEXPECTED_DATA);
  1631. //
  1632. // TODO: Now that we asserted, let's see if the code to handle this case works!
  1633. //
  1634. ///////////////////////////////////////////////////////////////////////////////////////
  1635. if ( (offsetToData + sizeof(MTF_STREAM_INFO)) <= bytesRead ) {
  1636. CMTFApi::MTF_ReadStreamHeader(&sSTREAM, &m_pStreamBuf[offsetToData]);
  1637. offsetToData += sizeof(MTF_STREAM_INFO);
  1638. }
  1639. else {
  1640. LONG nBytes;
  1641. nBytes = bytesRead - offsetToData;
  1642. // if nBytes is negative the FILE DBLK is larger the the buffer
  1643. // and I don't think this is possible?
  1644. WsbAssert(nBytes >= 0, MVR_E_LOGIC_ERROR);
  1645. if (nBytes) {
  1646. memcpy( &sSTREAM, &m_pStreamBuf[offsetToData], nBytes);
  1647. }
  1648. m_StreamOffset.QuadPart += nBytes;
  1649. m_StreamBufStartPBA = pba;
  1650. hr = ReadBuffer(m_pStreamBuf, m_StreamBufSize, &bytesRead);
  1651. if ( FAILED(hr) ) {
  1652. m_StreamBufUsed = 0;
  1653. WsbThrow(hr)
  1654. }
  1655. m_StreamBufUsed = bytesRead;
  1656. memcpy( &sSTREAM+nBytes, m_pStreamBuf, sizeof(MTF_STREAM_INFO)-nBytes);
  1657. offsetToData = sizeof(MTF_STREAM_INFO) - nBytes;
  1658. }
  1659. // Convert STREAM to WIN32 streamID
  1660. CMTFApi::MTF_SetStreamIdFromSTREAM(&sStreamHeader, &sSTREAM, 0);
  1661. try {
  1662. // Make sure it is the correct type of header
  1663. WsbAffirm((0 == memcmp(sSTREAM.acStreamId, "STAN", 4)), MVR_E_UNEXPECTED_DATA);
  1664. // Verify the stream header checksum
  1665. WsbAffirm((m_pSession->m_sHints.VerificationData.QuadPart == sSTREAM.uCheckSum), MVR_E_UNEXPECTED_DATA);
  1666. } catch (HRESULT catchHr) {
  1667. hr = catchHr;
  1668. //
  1669. // Log the error.
  1670. //
  1671. // This is an unrecoverable recall error. We need to put as much info
  1672. // in the event log to handle the probable service call.
  1673. //
  1674. // We try to output at least MaxBytes starting with the stream
  1675. // header to give a clue of what we tried to recall. If there isn't
  1676. // enough data through the end of the buffer we back out until we
  1677. // get upto MaxBytes and record the expected location of the stream
  1678. // header in the event message.
  1679. //
  1680. const int MaxBytes = 4*1024; // Max data bytes to log
  1681. int size = 0; // Size of data to be logged.
  1682. int loc = 0; // location of start of bogus stream header in log data
  1683. int start = offsetToData - sizeof(MTF_STREAM_INFO); // start of log data relativet the data buffer.
  1684. int nBytes = bytesRead - start; // Number of bytes through the end of the data buffer
  1685. if (nBytes < MaxBytes) {
  1686. // Adjust the start/location
  1687. start = bytesRead - MaxBytes;
  1688. if (start < 0) {
  1689. start = 0;
  1690. }
  1691. nBytes = bytesRead - start;
  1692. loc = offsetToData - sizeof(MTF_STREAM_INFO) - start;
  1693. }
  1694. // Allocate and copy data to log
  1695. // Only copy user data when building debug code
  1696. if ( MVR_DEBUG_OUTPUT ) {
  1697. size = nBytes < MaxBytes ? nBytes : MaxBytes;
  1698. }
  1699. unsigned char *data = (unsigned char *) WsbAlloc(size + sizeof(MVR_REMOTESTORAGE_HINTS));
  1700. if (data) {
  1701. memset(data, 0, size + sizeof(MVR_REMOTESTORAGE_HINTS));
  1702. if ( MVR_DEBUG_OUTPUT ) {
  1703. memcpy(&data[0], &m_pStreamBuf[start], size);
  1704. }
  1705. memcpy(&data[size], &m_pSession->m_sHints, sizeof(MVR_REMOTESTORAGE_HINTS));
  1706. size += sizeof(MVR_REMOTESTORAGE_HINTS);
  1707. }
  1708. else {
  1709. size = 0;
  1710. }
  1711. //
  1712. // Output the message and data to the event log.
  1713. //
  1714. CWsbBstrPtr name;
  1715. CWsbBstrPtr desc;
  1716. if (m_pCartridge) {
  1717. m_pCartridge->GetName(&name);
  1718. m_pCartridge->GetDescription(&desc);
  1719. }
  1720. WCHAR location[16];
  1721. WCHAR offset[16];
  1722. WCHAR mark[16];
  1723. WCHAR found[16];
  1724. swprintf(found, L"0x%04x", sSTREAM.uCheckSum);
  1725. swprintf(location, L"%I64u", pba.QuadPart);
  1726. swprintf(offset, L"%d", offsetToData - sizeof(MTF_STREAM_INFO));
  1727. swprintf(mark, L"0x%04x", loc);
  1728. WsbLogEvent(MVR_MESSAGE_UNEXPECTED_DATA,
  1729. size, data,
  1730. found,
  1731. (WCHAR *) name,
  1732. (WCHAR *) desc,
  1733. location, offset, mark,
  1734. NULL);
  1735. if (data) {
  1736. WsbFree(data);
  1737. data = NULL;
  1738. }
  1739. WsbThrow(hr);
  1740. }
  1741. //
  1742. // Set the verification type to none so we only do this once
  1743. //
  1744. m_pSession->m_sHints.VerificationType = MVR_VERIFICATION_TYPE_NONE;
  1745. }
  1746. }
  1747. else {
  1748. WsbTrace(OLESTR("Reading %u bytes.\n"), cb);
  1749. hr = ReadBuffer((BYTE *) pv, cb, &bytesRead);
  1750. if ( FAILED(hr) ) {
  1751. WsbThrow(hr)
  1752. }
  1753. else {
  1754. switch (hr) {
  1755. case MVR_S_FILEMARK_DETECTED:
  1756. case MVR_S_SETMARK_DETECTED:
  1757. m_StreamOffset.QuadPart += (unsigned _int64) m_sMediaParameters.BlockSize;
  1758. break;
  1759. }
  1760. }
  1761. }
  1762. }
  1763. else {
  1764. bUseInternalBuffer = TRUE;
  1765. // We need to re-calculate the offset relative the internal buffer.
  1766. // The orginal offset is the offset from the beginning of the nearest
  1767. // block. We need an offset relative the beginning of the internal buffer.
  1768. offsetToData += (ULONG)((pba.QuadPart - m_StreamBufStartPBA.QuadPart)*(unsigned _int64) m_sMediaParameters.BlockSize);
  1769. // !!!TEMPORARY
  1770. if (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType ) {
  1771. offsetToData += sizeof(MTF_STREAM_INFO);
  1772. }
  1773. m_pSession->m_sHints.VerificationType = MVR_VERIFICATION_TYPE_NONE;
  1774. }
  1775. if ( bUseInternalBuffer ) {
  1776. //
  1777. // Just copy the previously read data from the internal stream buffer.
  1778. //
  1779. ULONG maxBytesToCopy;
  1780. maxBytesToCopy = m_StreamBufUsed - offsetToData;
  1781. bytesToCopy = ( cb < maxBytesToCopy ) ? cb : maxBytesToCopy;
  1782. memcpy( pv, &m_pStreamBuf[offsetToData], bytesToCopy );
  1783. bytesRead = bytesToCopy;
  1784. }
  1785. m_StreamOffset.QuadPart += bytesRead;
  1786. if ( pcbRead ) {
  1787. *pcbRead = bytesRead;
  1788. }
  1789. } WsbCatch(hr);
  1790. WsbTraceOut(OLESTR("CNtTapeIo::Read"), OLESTR("hr = <%ls> bytes Read = %u, new offset = %I64u"), WsbHrAsString(hr), bytesRead, m_StreamOffset.QuadPart);
  1791. return hr;
  1792. }
  1793. STDMETHODIMP
  1794. CNtTapeIo::Write(
  1795. OUT void const *pv,
  1796. IN ULONG cb,
  1797. OUT ULONG *pcbWritten)
  1798. /*++
  1799. Implements:
  1800. IStream::Write
  1801. --*/
  1802. {
  1803. HRESULT hr = S_OK;
  1804. WsbTraceIn(OLESTR("CNtTapeIo::Write"), OLESTR("Bytes Requested = %u, offset = %I64u, mode = 0x%08x"), cb, m_StreamOffset.QuadPart, m_Mode);
  1805. ULONG bytesWritten = 0;
  1806. try {
  1807. MvrInjectError(L"Inject.CNtTapeIo::Write.0");
  1808. WsbAssert(pv != 0, STG_E_INVALIDPOINTER);
  1809. UINT64 pos = m_StreamOffset.QuadPart / m_sMediaParameters.BlockSize;
  1810. int retry;
  1811. const int delta = 10;
  1812. const int MaxRetry = 0; // TODO: This needs work; disabled for now.
  1813. retry = 0;
  1814. do {
  1815. try {
  1816. // Consistency Check
  1817. // WsbAffirmHr(EnsurePosition(pos));
  1818. // UINT64 curPos;
  1819. // WsbAffirmHr(GetPosition(&curPos)); // This kills DLT performance
  1820. // WsbAssert(curPos == m_StreamOffset.QuadPart / m_sMediaParameters.BlockSize, E_UNEXPECTED);
  1821. // Can't retry if part of the buffer has already been written.
  1822. WsbAssert(0 == bytesWritten, E_ABORT);
  1823. WsbAffirmHr(WriteBuffer((BYTE *) pv, cb, &bytesWritten));
  1824. if (retry > 0) {
  1825. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_RECOVERED, sizeof(retry), &retry, NULL);
  1826. }
  1827. break;
  1828. } WsbCatchAndDo(hr,
  1829. switch (hr) {
  1830. // Can't recover from these since they indicate the media may have changed,
  1831. // or device parameters are reset to defaults.
  1832. /**************************************
  1833. case MVR_E_BUS_RESET:
  1834. case MVR_E_MEDIA_CHANGED:
  1835. case MVR_E_NO_MEDIA_IN_DRIVE:
  1836. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  1837. case MVR_E_ERROR_IO_DEVICE:
  1838. **************************************/
  1839. // This may still be unsafe... not sure if partial i/o completes
  1840. case MVR_E_CRC:
  1841. if (retry < MaxRetry) {
  1842. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_DETECTED, sizeof(retry), &retry, NULL);
  1843. WsbTrace(OLESTR("Waiting for device to come ready - Seconds remaining before timeout: %d\n"), retry*delta);
  1844. Sleep(delta*1000); // Sleep a few seconds to give the device time to quite down... This may be useless!
  1845. hr = S_OK;
  1846. }
  1847. else {
  1848. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  1849. WsbThrow(hr);
  1850. }
  1851. break;
  1852. // Can't do anything about this one... just quietly fail.
  1853. case MVR_E_END_OF_MEDIA:
  1854. WsbThrow(hr);
  1855. break;
  1856. default:
  1857. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  1858. WsbThrow(hr);
  1859. break;
  1860. }
  1861. );
  1862. } while (++retry < MaxRetry);
  1863. } WsbCatch(hr);
  1864. if (pcbWritten) {
  1865. *pcbWritten = bytesWritten;
  1866. }
  1867. // Now update the storage info stats for the cartridge.
  1868. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  1869. if (pInfo) {
  1870. pInfo->IncrementBytesWritten(bytesWritten);
  1871. }
  1872. // Update the stream model
  1873. m_StreamOffset.QuadPart += bytesWritten;
  1874. m_StreamSize = m_StreamOffset; // For tape this is always true
  1875. WsbTraceOut(OLESTR("CNtTapeIo::Write"), OLESTR("hr = <%ls>, bytesWritten=%u"), WsbHrAsString(hr), bytesWritten);
  1876. return hr;
  1877. }
  1878. STDMETHODIMP
  1879. CNtTapeIo::Seek(
  1880. IN LARGE_INTEGER dlibMove,
  1881. IN DWORD dwOrigin,
  1882. OUT ULARGE_INTEGER *plibNewPosition
  1883. )
  1884. /*++
  1885. Implements:
  1886. IStream::Seek
  1887. --*/
  1888. {
  1889. HRESULT hr = S_OK;
  1890. WsbTraceIn(OLESTR("CNtTapeIo::Seek"), OLESTR("<%I64d> <%d>; offset=%I64u"), dlibMove.QuadPart, dwOrigin, m_StreamOffset.QuadPart);
  1891. ULARGE_INTEGER newPosition;
  1892. UINT64 curPos;
  1893. try {
  1894. MvrInjectError(L"Inject.CNtTapeIo::Seek.0");
  1895. WsbAssert(m_sMediaParameters.BlockSize > 0, MVR_E_LOGIC_ERROR);
  1896. newPosition.QuadPart = 0;
  1897. switch ( (STREAM_SEEK)dwOrigin ) {
  1898. case STREAM_SEEK_SET:
  1899. // If reading, defer physical move 'til later...
  1900. if (!(m_Mode & MVR_MODE_READ)) {
  1901. WsbAffirmHr(SetPosition(dlibMove.QuadPart/m_sMediaParameters.BlockSize));
  1902. }
  1903. m_StreamOffset.QuadPart = dlibMove.QuadPart;
  1904. if (m_StreamOffset.QuadPart > m_StreamSize.QuadPart) {
  1905. m_StreamSize = m_StreamOffset;
  1906. }
  1907. break;
  1908. case STREAM_SEEK_CUR:
  1909. if (dlibMove.QuadPart != 0) {
  1910. // If reading, defer physical move 'til later...
  1911. if (!(m_Mode & MVR_MODE_READ)) {
  1912. WsbAffirmHr(SetPosition((m_StreamOffset.QuadPart + dlibMove.QuadPart)/m_sMediaParameters.BlockSize));
  1913. }
  1914. m_StreamOffset.QuadPart += dlibMove.QuadPart;
  1915. }
  1916. else {
  1917. WsbAffirmHr(GetPosition(&curPos));
  1918. m_StreamOffset.QuadPart = curPos * m_sMediaParameters.BlockSize;
  1919. }
  1920. if (m_StreamOffset.QuadPart > m_StreamSize.QuadPart) {
  1921. m_StreamSize = m_StreamOffset;
  1922. }
  1923. break;
  1924. case STREAM_SEEK_END:
  1925. // TODO: FIX: We can use WsbAffirmHrOk when missing EOD markers is translated to MVR_S_NO_DATA_DETECTED.
  1926. hr = SpaceToEndOfData(&curPos);
  1927. m_StreamOffset.QuadPart = curPos * m_sMediaParameters.BlockSize;
  1928. m_StreamSize = m_StreamOffset;
  1929. break;
  1930. case 100:
  1931. // dlibMove is a DataSet number.
  1932. WsbAffirmHrOk(RewindTape());
  1933. WsbAffirmHrOk(SpaceFilemarks((LONG)(1+(dlibMove.QuadPart-1)*2), &curPos));
  1934. m_StreamOffset.QuadPart = curPos * m_sMediaParameters.BlockSize;
  1935. m_StreamSize = m_StreamOffset;
  1936. break;
  1937. default:
  1938. WsbThrow( STG_E_INVALIDFUNCTION );
  1939. }
  1940. newPosition.QuadPart = m_StreamOffset.QuadPart;
  1941. if ( plibNewPosition ) {
  1942. plibNewPosition->QuadPart = newPosition.QuadPart;
  1943. }
  1944. } WsbCatch(hr);
  1945. //
  1946. // TODO: Do we need to invalidate the internal stream buffer, or reset the
  1947. // stream buffer position to correspond to the stream offset?
  1948. //
  1949. WsbTraceOut(OLESTR("CNtTapeIo::Seek"), OLESTR("hr = <%ls>, new offset=%I64u"), WsbHrAsString(hr), m_StreamOffset.QuadPart);
  1950. return hr;
  1951. }
  1952. STDMETHODIMP
  1953. CNtTapeIo::SetSize(
  1954. IN ULARGE_INTEGER /*libNewSize*/)
  1955. /*++
  1956. Implements:
  1957. IStream::SetSize
  1958. --*/
  1959. {
  1960. HRESULT hr = S_OK;
  1961. WsbTraceIn(OLESTR("CNtTapeIo::SetSize"), OLESTR(""));
  1962. try {
  1963. WsbThrow(E_NOTIMPL);
  1964. } WsbCatch(hr);
  1965. WsbTraceOut(OLESTR("CNtTapeIo::SetSize"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1966. return hr;
  1967. }
  1968. STDMETHODIMP
  1969. CNtTapeIo::CopyTo(
  1970. IN IStream *pstm,
  1971. IN ULARGE_INTEGER cb,
  1972. OUT ULARGE_INTEGER *pcbRead,
  1973. OUT ULARGE_INTEGER *pcbWritten)
  1974. /*++
  1975. Implements:
  1976. IStream::CopyTo
  1977. --*/
  1978. {
  1979. HRESULT hr = S_OK;
  1980. WsbTraceIn(OLESTR("CNtTapeIo::CopyTo"), OLESTR("<%I64u>"), cb.QuadPart);
  1981. ULARGE_INTEGER totalBytesRead = {0,0};
  1982. ULARGE_INTEGER totalBytesWritten = {0,0};
  1983. BYTE *pBuffer = NULL;
  1984. try {
  1985. MvrInjectError(L"Inject.CNtTapeIo::CopyTo.0");
  1986. WsbAssert(pstm != 0, STG_E_INVALIDPOINTER);
  1987. WsbAssert(m_sMediaParameters.BlockSize > 0, MVR_E_LOGIC_ERROR);
  1988. ULONG defaultBufferSize = DefaultMinBufferSize;
  1989. DWORD size;
  1990. OLECHAR tmpString[256];
  1991. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_BUFFER_SIZE, tmpString, 256, &size))) {
  1992. // Get the value.
  1993. LONG val = wcstol(tmpString, NULL, 10);
  1994. if (val > 0) {
  1995. defaultBufferSize = val;
  1996. }
  1997. }
  1998. ULONG bufferSize;
  1999. ULONG nBlocks = defaultBufferSize/m_sMediaParameters.BlockSize;
  2000. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  2001. bufferSize = nBlocks * m_sMediaParameters.BlockSize;
  2002. pBuffer = (BYTE *) WsbAlloc(bufferSize);
  2003. WsbAssertPointer(pBuffer);
  2004. memset(pBuffer, 0, bufferSize);
  2005. ULONG bytesToRead;
  2006. ULONG bytesRead;
  2007. ULONG bytesWritten;
  2008. ULARGE_INTEGER bytesToCopy;
  2009. bytesToCopy.QuadPart = cb.QuadPart;
  2010. while ((bytesToCopy.QuadPart > 0) && (S_OK == hr)) {
  2011. bytesRead = 0;
  2012. bytesWritten = 0;
  2013. bytesToRead = (bytesToCopy.QuadPart < bufferSize) ? bytesToCopy.LowPart : bufferSize;
  2014. hr = Read(pBuffer, bytesToRead, &bytesRead);
  2015. totalBytesRead.QuadPart += bytesRead;
  2016. WsbAffirmHrOk(pstm->Write(pBuffer, bytesRead, &bytesWritten));
  2017. totalBytesWritten.QuadPart += bytesWritten;
  2018. bytesToCopy.QuadPart -= bytesRead;
  2019. }
  2020. if (pcbRead) {
  2021. pcbRead->QuadPart = totalBytesRead.QuadPart;
  2022. }
  2023. if (pcbWritten) {
  2024. pcbWritten->QuadPart = totalBytesWritten.QuadPart;
  2025. }
  2026. // TODO: FIX: We'll be getting an error if there's a missing EOD marker.
  2027. // This is hacked-up until we get a correct error code from
  2028. // the drivers, at which time we can remove this code.
  2029. if (FAILED(hr)) {
  2030. LARGE_INTEGER zero = {0,0};
  2031. ULARGE_INTEGER pos1, pos2;
  2032. WsbAffirmHr(Seek(zero, STREAM_SEEK_CUR, &pos1));
  2033. // We're looking for the same error conditon and
  2034. // verifying position doesn't change.
  2035. if (hr == Seek(zero, STREAM_SEEK_END, &pos2)){
  2036. if (pos1.QuadPart == pos2.QuadPart) {
  2037. hr = MVR_S_NO_DATA_DETECTED;
  2038. }
  2039. }
  2040. else {
  2041. WsbThrow(hr);
  2042. }
  2043. }
  2044. } WsbCatch(hr);
  2045. if (pBuffer) {
  2046. WsbFree(pBuffer);
  2047. pBuffer = NULL;
  2048. }
  2049. WsbTraceOut(OLESTR("CNtTapeIo::CopyTo"), OLESTR("hr = <%ls>, bytesRead=%I64u, bytesWritten=%I64u"),
  2050. WsbHrAsString(hr), totalBytesRead.QuadPart, totalBytesWritten.QuadPart);
  2051. return hr;
  2052. }
  2053. STDMETHODIMP
  2054. CNtTapeIo::Commit(
  2055. IN DWORD grfCommitFlags)
  2056. /*++
  2057. Implements:
  2058. IStream::Commit
  2059. --*/
  2060. {
  2061. HRESULT hr = S_OK;
  2062. WsbTraceIn(OLESTR("CNtTapeIo::Commit"), OLESTR("0x%08x"), grfCommitFlags);
  2063. try {
  2064. MvrInjectError(L"Inject.CNtTapeIo::Commit.0");
  2065. // Consistency Check
  2066. // UINT64 pos = m_StreamOffset.QuadPart / m_sMediaParameters.BlockSize;;
  2067. // WsbAffirmHr(EnsurePosition(pos));
  2068. UINT64 curPos;
  2069. WsbAffirmHr(GetPosition(&curPos));
  2070. WsbAssert(curPos == m_StreamOffset.QuadPart / m_sMediaParameters.BlockSize, E_UNEXPECTED);
  2071. // This is a real stretch!
  2072. WsbAffirmHr(WriteFilemarks(grfCommitFlags));
  2073. // Now update the storage info stats for the cartridge.
  2074. CComQIPtr<IRmsStorageInfo, &IID_IRmsStorageInfo> pInfo = m_pCartridge;
  2075. pInfo->IncrementBytesWritten(grfCommitFlags*m_sMediaParameters.BlockSize);
  2076. m_StreamOffset.QuadPart += grfCommitFlags*m_sMediaParameters.BlockSize;
  2077. m_StreamSize = m_StreamOffset; // For tape this is always true
  2078. } WsbCatch(hr);
  2079. WsbTraceOut(OLESTR("CNtTapeIo::Commit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2080. return hr;
  2081. }
  2082. STDMETHODIMP
  2083. CNtTapeIo::Revert(void)
  2084. /*++
  2085. Implements:
  2086. IStream::Revert
  2087. --*/
  2088. {
  2089. HRESULT hr = S_OK;
  2090. WsbTraceIn(OLESTR("CNtTapeIo::Revert"), OLESTR(""));
  2091. try {
  2092. m_Mode = 0;
  2093. } WsbCatch(hr);
  2094. WsbTraceOut(OLESTR("CNtTapeIo::Revert"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2095. return hr;
  2096. }
  2097. STDMETHODIMP
  2098. CNtTapeIo::LockRegion(
  2099. IN ULARGE_INTEGER /*libOffset*/,
  2100. IN ULARGE_INTEGER /*cb*/,
  2101. IN DWORD /*dwLockType*/)
  2102. /*++
  2103. Implements:
  2104. IStream::LockRegion
  2105. --*/
  2106. {
  2107. HRESULT hr = S_OK;
  2108. WsbTraceIn(OLESTR("CNtTapeIo::LockRegion"), OLESTR(""));
  2109. try {
  2110. WsbThrow(E_NOTIMPL);
  2111. } WsbCatch(hr);
  2112. WsbTraceOut(OLESTR("CNtTapeIo::LockRegion"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2113. return hr;
  2114. }
  2115. STDMETHODIMP
  2116. CNtTapeIo::UnlockRegion(
  2117. IN ULARGE_INTEGER /*libOffset*/,
  2118. IN ULARGE_INTEGER /*cb*/,
  2119. IN DWORD /*dwLockType*/)
  2120. /*++
  2121. Implements:
  2122. IStream::UnlockRegion
  2123. --*/
  2124. {
  2125. HRESULT hr = S_OK;
  2126. WsbTraceIn(OLESTR("CNtTapeIo::UnlockRegion"), OLESTR(""));
  2127. try {
  2128. WsbThrow(E_NOTIMPL);
  2129. } WsbCatch(hr);
  2130. WsbTraceOut(OLESTR("CNtTapeIo::UnlockRegion"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2131. return hr;
  2132. }
  2133. STDMETHODIMP
  2134. CNtTapeIo::Stat(
  2135. OUT STATSTG * /*pstatstg*/,
  2136. IN DWORD /*grfStatFlag*/)
  2137. /*++
  2138. Implements:
  2139. IStream::Stat
  2140. --*/
  2141. {
  2142. HRESULT hr = S_OK;
  2143. WsbTraceIn(OLESTR("CNtTapeIo::Stat"), OLESTR(""));
  2144. try {
  2145. WsbThrow(E_NOTIMPL);
  2146. } WsbCatch(hr);
  2147. WsbTraceOut(OLESTR("CNtTapeIo::Stat"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2148. return hr;
  2149. }
  2150. STDMETHODIMP
  2151. CNtTapeIo::Clone(
  2152. OUT IStream ** /*ppstm*/)
  2153. /*++
  2154. Implements:
  2155. IStream::Clone
  2156. --*/
  2157. {
  2158. HRESULT hr = S_OK;
  2159. WsbTraceIn(OLESTR("CNtTapeIo::Clone"), OLESTR(""));
  2160. try {
  2161. WsbThrow(E_NOTIMPL);
  2162. } WsbCatch(hr);
  2163. WsbTraceOut(OLESTR("CNtTapeIo::Clone"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2164. return hr;
  2165. }
  2166. ////////////////////////////////////////////////////////////////////////////////
  2167. //
  2168. // Local and Static Methods
  2169. //
  2170. HRESULT
  2171. CNtTapeIo::OpenTape(void)
  2172. /*++
  2173. Routine Description:
  2174. Opens the tape drive and gets media and drive info
  2175. Arguments:
  2176. None.
  2177. Return Value:
  2178. None.
  2179. --*/
  2180. {
  2181. HRESULT hr = S_OK;
  2182. WsbTraceIn(OLESTR("CNtTapeIo::OpenTape"), OLESTR("<%ls>"), m_DeviceName);
  2183. try {
  2184. WsbAffirmHrOk(IsAccessEnabled());
  2185. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.0");
  2186. WsbAssert(wcscmp((WCHAR *)m_DeviceName, MVR_UNDEFINED_STRING), MVR_E_LOGIC_ERROR);
  2187. WsbAssertPointer(m_pCartridge);
  2188. DWORD nStructSize;
  2189. int retry;
  2190. const int delta = 10;
  2191. const int MaxRetry = 10;
  2192. retry = 0;
  2193. do {
  2194. try {
  2195. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.CreateFile.0");
  2196. // ** WIN32 Tape API Call - open the tape drive for read/write
  2197. WsbAffirmHandle(m_hTape = CreateFile(m_DeviceName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  2198. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.CreateFile.1");
  2199. if (retry > 0) {
  2200. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_RECOVERED, sizeof(retry), &retry, NULL);
  2201. }
  2202. break;
  2203. } WsbCatchAndDo(hr,
  2204. CWsbStringPtr tmpString;
  2205. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_OPENTAPE) != S_OK) {
  2206. tmpString = L"";
  2207. }
  2208. hr = MapTapeError(hr, tmpString);
  2209. switch (hr) {
  2210. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  2211. if (retry < MaxRetry){
  2212. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_DETECTED, sizeof(retry), &retry, NULL);
  2213. WsbTrace(OLESTR("Waiting for device - Seconds remaining before timeout: %d\n"), retry*delta);
  2214. Sleep(delta*1000);
  2215. hr = S_OK;
  2216. }
  2217. else {
  2218. //
  2219. // This is the last try, so log the failure.
  2220. //
  2221. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  2222. WsbThrow(hr);
  2223. }
  2224. break;
  2225. default:
  2226. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  2227. WsbThrow(hr);
  2228. break;
  2229. }
  2230. );
  2231. } while (++retry < MaxRetry);
  2232. retry = 0;
  2233. do {
  2234. try {
  2235. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeStatus.0");
  2236. // ** WIN32 Tape API Call - get the tape status
  2237. WsbAffirmNoError(GetTapeStatus(m_hTape));
  2238. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeStatus.1");
  2239. if (retry > 0) {
  2240. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_RECOVERED, sizeof(retry), &retry, NULL);
  2241. }
  2242. break;
  2243. } WsbCatchAndDo(hr,
  2244. CWsbStringPtr tmpString;
  2245. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_OPENTAPE) != S_OK) {
  2246. tmpString = L"";
  2247. }
  2248. hr = MapTapeError(hr, tmpString);
  2249. switch (hr) {
  2250. case MVR_E_BUS_RESET:
  2251. case MVR_E_MEDIA_CHANGED:
  2252. case MVR_E_NO_MEDIA_IN_DRIVE:
  2253. case MVR_E_ERROR_IO_DEVICE:
  2254. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  2255. case MVR_E_ERROR_NOT_READY:
  2256. if (retry < MaxRetry){
  2257. WsbLogEvent(MVR_MESSAGE_RECOVERABLE_DEVICE_ERROR_DETECTED, sizeof(retry), &retry, NULL);
  2258. WsbTrace(OLESTR("Waiting for device - Seconds remaining before timeout: %d\n"), retry*delta);
  2259. Sleep(delta*1000);
  2260. hr = S_OK;
  2261. }
  2262. else {
  2263. //
  2264. // This is the last try, so log the failure.
  2265. //
  2266. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  2267. WsbThrow(hr);
  2268. }
  2269. break;
  2270. default:
  2271. WsbLogEvent(MVR_MESSAGE_UNRECOVERABLE_DEVICE_ERROR, sizeof(retry), &retry, WsbHrAsString(hr), NULL);
  2272. WsbThrow(hr);
  2273. break;
  2274. }
  2275. );
  2276. } while (++retry < MaxRetry);
  2277. nStructSize = sizeof(TAPE_GET_DRIVE_PARAMETERS) ;
  2278. try {
  2279. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeParameters.0");
  2280. // ** WIN32 Tape API Call - get the tape drive parameters
  2281. WsbAffirmNoError(GetTapeParameters(m_hTape, GET_TAPE_DRIVE_INFORMATION, &nStructSize, &m_sDriveParameters));
  2282. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeParameters.1");
  2283. } WsbCatchAndDo(hr,
  2284. CWsbStringPtr tmpString;
  2285. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_OPENTAPE) != S_OK) {
  2286. tmpString = L"";
  2287. }
  2288. hr = MapTapeError(hr, tmpString);
  2289. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2290. WsbThrow(hr);
  2291. );
  2292. // Set the Block Size to the default for the device, or DefaultBlockSize.
  2293. TAPE_SET_MEDIA_PARAMETERS parms;
  2294. LONG nBlockSize = 0;
  2295. if (m_pCartridge) {
  2296. WsbAffirmHr(m_pCartridge->GetBlockSize(&nBlockSize));
  2297. }
  2298. if (0 == nBlockSize) {
  2299. // If the block size is zero, it must be scratch media!
  2300. if (m_pCartridge) {
  2301. LONG status;
  2302. WsbAffirmHr(m_pCartridge->GetStatus(&status));
  2303. WsbAssert(RmsStatusScratch == status, E_UNEXPECTED);
  2304. }
  2305. // Allow registry override!
  2306. DWORD size;
  2307. OLECHAR tmpString[256];
  2308. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_BLOCK_SIZE, tmpString, 256, &size))) {
  2309. // Get the value.
  2310. nBlockSize = wcstol(tmpString, NULL, 10);
  2311. // BlockSize must be a multiple of 512.
  2312. if (nBlockSize % 512) {
  2313. // The block size specified is not valid, revert to default setting.
  2314. nBlockSize = 0;
  2315. }
  2316. }
  2317. }
  2318. if (nBlockSize > 0) {
  2319. parms.BlockSize = nBlockSize;
  2320. }
  2321. else {
  2322. // NOTE: We can't arbitrarily use the default block size for the device. It could
  2323. // change between different devices supporting the same media format. Migrate / Recall
  2324. // operations depend on using the same block size.
  2325. parms.BlockSize = m_sDriveParameters.DefaultBlockSize;
  2326. }
  2327. WsbTrace( OLESTR("Setting Block Size to %d bytes/block.\n"), parms.BlockSize);
  2328. WsbAssert(parms.BlockSize > 0, E_UNEXPECTED);
  2329. try {
  2330. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.SetTapeParameters.1");
  2331. // ** WIN32 Tape API Call - set the tape drive parameters
  2332. WsbAffirmNoError(SetTapeParameters(m_hTape, SET_TAPE_MEDIA_INFORMATION, &parms));
  2333. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.SetTapeParameters.1");
  2334. } WsbCatchAndDo(hr,
  2335. CWsbStringPtr tmpString;
  2336. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_OPENTAPE) != S_OK) {
  2337. tmpString = L"";
  2338. }
  2339. hr = MapTapeError(hr, tmpString);
  2340. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2341. WsbThrow(hr);
  2342. );
  2343. nStructSize = sizeof( TAPE_GET_MEDIA_PARAMETERS );
  2344. try {
  2345. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeParameters.2.0");
  2346. // ** WIN32 Tape API Call - get the media parameters
  2347. WsbAffirmNoError( GetTapeParameters(m_hTape, GET_TAPE_MEDIA_INFORMATION, &nStructSize, &m_sMediaParameters));
  2348. MvrInjectError(L"Inject.CNtTapeIo::OpenTape.GetTapeParameters.2.1");
  2349. } WsbCatchAndDo(hr,
  2350. CWsbStringPtr tmpString;
  2351. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_OPENTAPE) != S_OK) {
  2352. tmpString = L"";
  2353. }
  2354. hr = MapTapeError(hr, tmpString);
  2355. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2356. WsbThrow(hr);
  2357. );
  2358. // Make sure we have a media block size that we can deal with.
  2359. WsbAssert(m_sMediaParameters.BlockSize > 0, E_UNEXPECTED);
  2360. WsbAssert(!(m_sMediaParameters.BlockSize % 512), E_UNEXPECTED);
  2361. WsbTrace( OLESTR("Media Parameters:\n"));
  2362. WsbTrace( OLESTR(" BlockSize = %d bytes/block.\n"), m_sMediaParameters.BlockSize);
  2363. WsbTrace( OLESTR(" Capacity = %I64u\n"), m_sMediaParameters.Capacity.QuadPart);
  2364. WsbTrace( OLESTR(" Remaining = %I64u\n"), m_sMediaParameters.Remaining.QuadPart);
  2365. WsbTrace( OLESTR(" PartitionCount = %d\n"), m_sMediaParameters.PartitionCount);
  2366. WsbTrace( OLESTR(" WriteProtect = %ls\n"), WsbBoolAsString(m_sMediaParameters.WriteProtected));
  2367. WsbTrace( OLESTR("Drive Parameters:\n"));
  2368. WsbTrace( OLESTR(" ECC = %ls\n"), WsbBoolAsString(m_sDriveParameters.ECC));
  2369. WsbTrace( OLESTR(" Compression = %ls\n"), WsbBoolAsString(m_sDriveParameters.Compression));
  2370. WsbTrace( OLESTR(" DataPadding = %ls\n"), WsbBoolAsString(m_sDriveParameters.DataPadding));
  2371. WsbTrace( OLESTR(" ReportSetmarks = %ls\n"), WsbBoolAsString(m_sDriveParameters.ReportSetmarks));
  2372. WsbTrace( OLESTR(" DefaultBlockSize = %d (%d, %d)\n"),
  2373. m_sDriveParameters.DefaultBlockSize,
  2374. m_sDriveParameters.MinimumBlockSize,
  2375. m_sDriveParameters.MaximumBlockSize);
  2376. WsbTrace( OLESTR(" MaxPartitionCount = %d\n"), m_sDriveParameters.MaximumPartitionCount);
  2377. WsbTrace( OLESTR(" FeaturesLow = 0x%08x FIXED(%d) SELECT(%d) INITIATOR(%d)\n"),
  2378. m_sDriveParameters.FeaturesLow,
  2379. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_FIXED ? 1 : 0,
  2380. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_SELECT ? 1 : 0,
  2381. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_INITIATOR ? 1 : 0);
  2382. WsbTrace( OLESTR(" ERASE_SHORT(%d) ERASE_LONG(%d) ERASE_BOP_ONLY(%d) ERASE_IMMEDIATE(%d)\n"),
  2383. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_ERASE_SHORT ? 1 : 0,
  2384. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_ERASE_LONG ? 1 : 0,
  2385. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_ERASE_BOP_ONLY ? 1 : 0,
  2386. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_ERASE_IMMEDIATE ? 1 : 0);
  2387. WsbTrace( OLESTR(" TAPE_CAPACITY(%d) TAPE_REMAINING(%d) FIXED_BLOCK(%d) VARIABLE_BLOCK(%d)\n"),
  2388. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_TAPE_CAPACITY ? 1 : 0,
  2389. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_TAPE_REMAINING ? 1 : 0,
  2390. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_FIXED_BLOCK ? 1 : 0,
  2391. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_VARIABLE_BLOCK ? 1 : 0);
  2392. WsbTrace( OLESTR(" WRITE_PROTECT(%d) EOT_WZ_SIZE(%d) ECC(%d) COMPRESSION(%d) PADDING(%d) REPORT_SMKS(%d)\n"),
  2393. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_WRITE_PROTECT ? 1 : 0,
  2394. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_EOT_WZ_SIZE ? 1 : 0,
  2395. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_ECC ? 1 : 0,
  2396. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_COMPRESSION ? 1 : 0,
  2397. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_PADDING ? 1 : 0,
  2398. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_REPORT_SMKS ? 1 : 0);
  2399. WsbTrace( OLESTR(" GET_ABSOLUTE_BLK(%d) GET_LOGICAL_BLK(%d) SET_EOT_WZ_SIZE(%d) EJECT_MEDIA(%d) CLEAN_REQUESTS(%d)\n"),
  2400. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_GET_ABSOLUTE_BLK ? 1 : 0,
  2401. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_GET_LOGICAL_BLK ? 1 : 0,
  2402. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_SET_EOT_WZ_SIZE ? 1 : 0,
  2403. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_EJECT_MEDIA ? 1 : 0,
  2404. m_sDriveParameters.FeaturesLow & TAPE_DRIVE_CLEAN_REQUESTS ? 1 : 0);
  2405. WsbTrace( OLESTR(" FeaturesHigh = 0x%08x LOAD_UNLOAD(%d) TENSION(%d) LOCK_UNLOCK(%d) REWIND_IMMEDIATE(%d)\n"),
  2406. m_sDriveParameters.FeaturesHigh,
  2407. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOAD_UNLOAD ? 1 : 0,
  2408. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_TENSION ? 1 : 0,
  2409. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOCK_UNLOCK ? 1 : 0,
  2410. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_REWIND_IMMEDIATE ? 1 : 0);
  2411. WsbTrace( OLESTR(" SET_BLOCK_SIZE(%d) LOAD_UNLD_IMMED(%d) TENSION_IMMED(%d) LOCK_UNLK_IMMED(%d)\n"),
  2412. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SET_BLOCK_SIZE ? 1 : 0,
  2413. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOAD_UNLD_IMMED ? 1 : 0,
  2414. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_TENSION_IMMED ? 1 : 0,
  2415. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOCK_UNLK_IMMED ? 1 : 0);
  2416. WsbTrace( OLESTR(" SET_ECC(%d) SET_COMPRESSION(%d) SET_PADDING(%d) SET_REPORT_SMKS(%d)\n"),
  2417. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SET_ECC ? 1 : 0,
  2418. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SET_COMPRESSION ? 1 : 0,
  2419. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SET_PADDING ? 1 : 0,
  2420. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SET_REPORT_SMKS ? 1 : 0);
  2421. WsbTrace( OLESTR(" ABSOLUTE_BLK(%d) ABS_BLK_IMMED(%d) LOGICAL_BLK(%d) LOG_BLK_IMMED(%d)\n"),
  2422. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_ABSOLUTE_BLK ? 1 : 0,
  2423. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_ABS_BLK_IMMED ? 1 : 0,
  2424. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOGICAL_BLK ? 1 : 0,
  2425. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_LOG_BLK_IMMED ? 1 : 0);
  2426. WsbTrace( OLESTR(" END_OF_DATA(%d) RELATIVE_BLKS(%d) FILEMARKS(%d) SEQUENTIAL_FMKS(%d)\n"),
  2427. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_END_OF_DATA ? 1 : 0,
  2428. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_RELATIVE_BLKS ? 1 : 0,
  2429. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_FILEMARKS ? 1 : 0,
  2430. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SEQUENTIAL_FMKS ? 1 : 0);
  2431. WsbTrace( OLESTR(" SETMARKS(%d) SEQUENTIAL_SMKS(%d) REVERSE_POSITION(%d) SPACE_IMMEDIATE(%d)\n"),
  2432. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SETMARKS ? 1 : 0,
  2433. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SEQUENTIAL_SMKS ? 1 : 0,
  2434. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_REVERSE_POSITION ? 1 : 0,
  2435. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_SPACE_IMMEDIATE ? 1 : 0);
  2436. WsbTrace( OLESTR(" WRITE_SETMARKS(%d) WRITE_FILEMARKS(%d) WRITE_SHORT_FMKS(%d) WRITE_LONG_FMKS(%d)\n"),
  2437. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_SETMARKS ? 1 : 0,
  2438. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_FILEMARKS ? 1 : 0,
  2439. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_SHORT_FMKS ? 1 : 0,
  2440. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_LONG_FMKS ? 1 : 0);
  2441. WsbTrace( OLESTR(" WRITE_MARK_IMMED(%d) FORMAT(%d) FORMAT_IMMEDIATE(%d)\n"),
  2442. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_MARK_IMMED ? 1 : 0,
  2443. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_FORMAT ? 1 : 0,
  2444. m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_FORMAT_IMMEDIATE ? 1 : 0);
  2445. WsbTrace( OLESTR(" EOTWarningZoneSize = %d\n"), m_sDriveParameters.EOTWarningZoneSize);
  2446. //
  2447. // We assume the label is valid unless the flag is knocked down
  2448. // while opening the device. This could happen if we get a bus
  2449. // reset between the mount the OpenTape call.
  2450. //
  2451. if (!m_ValidLabel) {
  2452. CWsbBstrPtr label;
  2453. WsbAffirmHr(ReadLabel(&label));
  2454. WsbAffirmHr(VerifyLabel(label));
  2455. }
  2456. } WsbCatchAndDo(hr,
  2457. // Clean up...
  2458. (void) CloseTape();
  2459. );
  2460. WsbTraceOut(OLESTR("CNtTapeIo::OpenTape"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2461. return hr;
  2462. }
  2463. HRESULT
  2464. CNtTapeIo::CloseTape(void)
  2465. /*++
  2466. Routine Description:
  2467. Closes the tape drive.
  2468. Arguments:
  2469. None.
  2470. Return Value:
  2471. S_OK - Success.
  2472. --*/
  2473. {
  2474. HRESULT hr = S_OK;
  2475. WsbTraceIn(OLESTR("CNtTapeIo::CloseTape"), OLESTR("DeviceName=<%ls>"), m_DeviceName);
  2476. //
  2477. // CloseTape() can be called from RsSub during dismount, and/or shutdown.
  2478. //
  2479. // <<<<< ENTER SINGLE THREADED SECTION
  2480. WsbAffirmHr(Lock());
  2481. if (INVALID_HANDLE_VALUE != m_hTape) {
  2482. try {
  2483. // ** WIN32 Tape API Call - close the tape drive
  2484. WsbTraceAlways(OLESTR("Closing %ls...\n"), m_DeviceName);
  2485. WsbAffirmStatus(CloseHandle( m_hTape ));
  2486. WsbTraceAlways(OLESTR("%ls was closed.\n"), m_DeviceName);
  2487. } WsbCatchAndDo(hr,
  2488. CWsbStringPtr tmpString;
  2489. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_CLOSETAPE) != S_OK) {
  2490. tmpString = L"";
  2491. }
  2492. hr = MapTapeError(hr, tmpString);
  2493. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2494. );
  2495. m_hTape = INVALID_HANDLE_VALUE;
  2496. m_ValidLabel = FALSE;
  2497. }
  2498. WsbAffirmHr(Unlock());
  2499. // >>>>> LEAVE SINGLE THREADED SECTION
  2500. WsbTraceOut(OLESTR("CNtTapeIo::CloseTape"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2501. return hr;
  2502. }
  2503. HRESULT
  2504. CNtTapeIo::WriteBuffer(
  2505. IN BYTE *pBuffer,
  2506. IN ULONG nBytesToWrite,
  2507. OUT ULONG *pBytesWritten)
  2508. /*++
  2509. Routine Description:
  2510. Used to write all MTF data. Guarantees full blocks are written.
  2511. Arguments:
  2512. pBuffer - Data buffer.
  2513. nBytesToWrite - number of bytes to write in buffer.
  2514. pBytesWritten - Bytes written.
  2515. Return Value:
  2516. S_OK - Success.
  2517. --*/
  2518. {
  2519. HRESULT hr = S_OK;
  2520. try {
  2521. WsbAffirmHrOk(IsAccessEnabled());
  2522. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  2523. // making sure that we are writting only full blocks
  2524. WsbAssert(!(nBytesToWrite % m_sMediaParameters.BlockSize), E_INVALIDARG);
  2525. try {
  2526. MvrInjectError(L"Inject.CNtTapeIo::WriteBuffer.WriteFile.0");
  2527. // ** WIN32 Tape API Call - write the data
  2528. WsbAffirmStatus(WriteFile(m_hTape, pBuffer, nBytesToWrite, pBytesWritten, 0));
  2529. MvrInjectError(L"Inject.CNtTapeIo::WriteBuffer.WriteFile.1");
  2530. } WsbCatchAndDo(hr,
  2531. CWsbStringPtr tmpString;
  2532. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_WRITE) != S_OK) {
  2533. tmpString = L"";
  2534. }
  2535. hr = MapTapeError(hr, tmpString);
  2536. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2537. );
  2538. // making sure that we have written only full blocks
  2539. WsbAssert(!(*pBytesWritten % m_sMediaParameters.BlockSize), E_UNEXPECTED);
  2540. } WsbCatch(hr);
  2541. return hr;
  2542. }
  2543. HRESULT
  2544. CNtTapeIo::ReadBuffer(
  2545. IN BYTE *pBuffer,
  2546. IN ULONG nBytesToRead,
  2547. OUT ULONG *pBytesRead)
  2548. /*++
  2549. Routine Description:
  2550. Used to read all MTF data. Guarantees full blocks are read.
  2551. Arguments:
  2552. pBuffer - Data buffer.
  2553. nBytesToRead - number of bytes to read into buffer.
  2554. pBytesRead - Bytes read.
  2555. Return Value:
  2556. S_OK - Success.
  2557. --*/
  2558. {
  2559. HRESULT hr = S_OK;
  2560. try {
  2561. static WCHAR errBuf[32];
  2562. static BOOL bFirstTime = TRUE;
  2563. WsbAffirmHrOk(IsAccessEnabled());
  2564. // making sure that we are reading only full blocks
  2565. WsbAssert(!(nBytesToRead % m_sMediaParameters.BlockSize), MVR_E_LOGIC_ERROR);
  2566. try {
  2567. MvrInjectError(L"Inject.CNtTapeIo::ReadBuffer.ReadFile.0");
  2568. // ** WIN32 Tape API Call - read the data
  2569. WsbAffirmStatus(ReadFile(m_hTape, pBuffer, nBytesToRead, pBytesRead, 0));
  2570. MvrInjectError(L"Inject.CNtTapeIo::ReadBuffer.ReadFile.1");
  2571. } WsbCatchAndDo(hr,
  2572. // Get error string once since Read may return a none-OK status which
  2573. // is not really an error
  2574. if (bFirstTime) {
  2575. CWsbStringPtr tmpString;
  2576. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_READ) != S_OK) {
  2577. tmpString = L"";
  2578. }
  2579. if (wcslen(tmpString) >= 32) {
  2580. tmpString = L"";
  2581. }
  2582. wcscpy(errBuf, tmpString);
  2583. bFirstTime = FALSE;
  2584. }
  2585. hr = MapTapeError(hr, errBuf);
  2586. // Errors like filemark detected and end-of-data are Okay!
  2587. if ( FAILED(hr) ) {
  2588. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, errBuf, WsbHrAsString(hr), NULL);
  2589. }
  2590. );
  2591. // making sure that we have read only full blocks
  2592. WsbAssert(!(*pBytesRead % m_sMediaParameters.BlockSize), E_UNEXPECTED);
  2593. m_StreamPBA.QuadPart += *pBytesRead / m_sMediaParameters.BlockSize;
  2594. } WsbCatch(hr);
  2595. return hr;
  2596. }
  2597. HRESULT
  2598. CNtTapeIo::WriteFilemarks(
  2599. IN ULONG nCount)
  2600. /*++
  2601. Routine Description:
  2602. Writes count filemarks at the current location.
  2603. Arguments:
  2604. nCount - Number of Filemarks to write.
  2605. Return Value:
  2606. S_OK - Success.
  2607. --*/
  2608. {
  2609. HRESULT hr = S_OK;
  2610. WsbTraceIn(OLESTR("CNtTapeIo::WriteFilemarks"), OLESTR("<%u>"), nCount);
  2611. try {
  2612. WsbAffirmHrOk(IsAccessEnabled());
  2613. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  2614. UINT64 pos;
  2615. WsbAffirmHr(GetPosition(&pos));
  2616. // Some drives support the default, others require long filemarks.
  2617. if ( m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_FILEMARKS ) {
  2618. try {
  2619. MvrInjectError(L"Inject.CNtTapeIo::WriteFilemarks.WriteTapemark.1.0");
  2620. // ** WIN32 Tape API Call - write a filemark
  2621. WsbAffirmNoError(WriteTapemark(m_hTape, TAPE_FILEMARKS, nCount, FALSE));
  2622. MvrInjectError(L"Inject.CNtTapeIo::WriteFilemarks.WriteTapemark.1.1");
  2623. } WsbCatchAndDo(hr,
  2624. CWsbStringPtr tmpString;
  2625. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_WRITEFILEMARKS) != S_OK) {
  2626. tmpString = L"";
  2627. }
  2628. hr = MapTapeError(hr, tmpString);
  2629. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2630. WsbThrow(hr);
  2631. );
  2632. WsbTrace(OLESTR(" %d Filemark(s) @ PBA %I64u\n"), nCount, pos );
  2633. }
  2634. else if ( m_sDriveParameters.FeaturesHigh & TAPE_DRIVE_WRITE_LONG_FMKS ) {
  2635. try {
  2636. MvrInjectError(L"Inject.CNtTapeIo::WriteFilemarks.WriteTapemark.2.0");
  2637. // ** WIN32 Tape API Call - write a filemark
  2638. WsbAffirmNoError(WriteTapemark(m_hTape, TAPE_LONG_FILEMARKS, nCount, FALSE));
  2639. MvrInjectError(L"Inject.CNtTapeIo::WriteFilemarks.WriteTapemark.2.1");
  2640. } WsbCatchAndDo(hr,
  2641. CWsbStringPtr tmpString;
  2642. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_WRITEFILEMARKS) != S_OK) {
  2643. tmpString = L"";
  2644. }
  2645. hr = MapTapeError(hr, tmpString);
  2646. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2647. WsbThrow(hr);
  2648. );
  2649. WsbTrace(OLESTR(" %d Long Filemark(s) @ PBA %I64u\n"), nCount, pos );
  2650. }
  2651. else {
  2652. // Short filemark???
  2653. WsbThrow( E_UNEXPECTED );
  2654. }
  2655. } WsbCatchAndDo(hr,
  2656. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, L"", WsbHrAsString(hr), NULL);
  2657. );
  2658. WsbTraceOut(OLESTR("CNtTapeIo::WriteFilemarks"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2659. return hr;
  2660. }
  2661. HRESULT
  2662. CNtTapeIo::GetPosition(
  2663. OUT UINT64 *pPosition)
  2664. /*++
  2665. Routine Description:
  2666. Returns the current physical block address relative the current partition.
  2667. Arguments:
  2668. pPostion - Receives the current physical block address.
  2669. Return Value:
  2670. S_OK - Success.
  2671. --*/
  2672. {
  2673. HRESULT hr = S_OK;
  2674. WsbTraceIn(OLESTR("CNtTapeIo::GetPosition"), OLESTR(""));
  2675. UINT64 curPos = 0xffffffffffffffff;
  2676. try {
  2677. WsbAssertPointer(pPosition);
  2678. WsbAffirmHrOk(IsAccessEnabled());
  2679. DWORD uPartition, uLSB, uMSB;
  2680. ULARGE_INTEGER pba;
  2681. try {
  2682. MvrInjectError(L"Inject.CNtTapeIo::GetPosition.GetTapePosition.0");
  2683. // ** WIN32 Tape API Call - get the PBA
  2684. WsbAffirmNoError(GetTapePosition(m_hTape, TAPE_LOGICAL_POSITION, &uPartition, &uLSB, &uMSB));
  2685. MvrInjectError(L"Inject.CNtTapeIo::GetPosition.GetTapePosition.1");
  2686. pba.LowPart = uLSB;
  2687. pba.HighPart = uMSB;
  2688. curPos = pba.QuadPart;
  2689. WsbTrace(OLESTR("CNtTapeIo::GetPosition - <%d> <%I64u>\n"), uPartition, curPos);
  2690. } WsbCatchAndDo(hr,
  2691. CWsbStringPtr tmpString;
  2692. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_GETPOSITION) != S_OK) {
  2693. tmpString = L"";
  2694. }
  2695. hr = MapTapeError(hr, tmpString);
  2696. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2697. );
  2698. if (pPosition) {
  2699. *pPosition = curPos;
  2700. }
  2701. } WsbCatch(hr);
  2702. WsbTraceOut(OLESTR("CNtTapeIo::GetPosition"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2703. return hr;
  2704. }
  2705. HRESULT
  2706. CNtTapeIo::SetPosition(
  2707. IN UINT64 position)
  2708. /*++
  2709. Routine Description:
  2710. Mover to the specified physical block address relative the current partition.
  2711. Arguments:
  2712. postion - The physical block address to position to.
  2713. Return Value:
  2714. S_OK - Success.
  2715. --*/
  2716. {
  2717. HRESULT hr = S_OK;
  2718. WsbTraceIn(OLESTR("CNtTapeIo::SetPosition"), OLESTR("<%I64u>"), position);
  2719. UINT64 curPos = 0xffffffffffffffff;
  2720. try {
  2721. WsbAffirmHrOk(IsAccessEnabled());
  2722. MvrInjectError(L"Inject.CNtTapeIo::SetPosition.0");
  2723. //
  2724. // NOTE: By first checking the current block address with the one we want we
  2725. // avoid an expensive seek in the case where the tape is already located at
  2726. // the desired block address (not all devices know where they are, and seeking
  2727. // to the current block address is expensive).
  2728. //
  2729. // TODO: It is faster to just read a few thousand blocks rather than seek to a position that
  2730. // is a few thousand blocks away. If we're within this threshold we could read from
  2731. // tape into the bit bucket to advance the tape.
  2732. //
  2733. WsbAffirmHr(GetPosition(&curPos));
  2734. if (curPos != position ) {
  2735. ULARGE_INTEGER PBA;
  2736. PBA.QuadPart = position;
  2737. try {
  2738. if (0 == position) {
  2739. WsbAffirmHr(RewindTape());
  2740. }
  2741. else {
  2742. MvrInjectError(L"Inject.CNtTapeIo::SetPosition.SetTapePosition.1");
  2743. // ** WIN32 Tape API Call - set the PBA
  2744. WsbAffirmNoError(SetTapePosition(m_hTape, TAPE_LOGICAL_BLOCK, 1, PBA.LowPart, PBA.HighPart, FALSE));
  2745. MvrInjectError(L"Inject.CNtTapeIo::SetPosition.SetTapePosition.0");
  2746. }
  2747. } WsbCatchAndDo(hr,
  2748. CWsbStringPtr tmpString;
  2749. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_SETPOSITION) != S_OK) {
  2750. tmpString = L"";
  2751. }
  2752. hr = MapTapeError(hr, tmpString);
  2753. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2754. WsbThrow(hr);
  2755. );
  2756. curPos = position;
  2757. }
  2758. m_StreamPBA.QuadPart = curPos;
  2759. } WsbCatch(hr);
  2760. WsbTraceOut(OLESTR("CNtTapeIo::SetPosition"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2761. return hr;
  2762. }
  2763. HRESULT
  2764. CNtTapeIo::EnsurePosition(
  2765. IN UINT64 position)
  2766. /*++
  2767. Routine Description:
  2768. Checks that the tape is positioned at the specified current physical block
  2769. address relative to the current partition. If it is not an attempt is made
  2770. to recover to the specified position.
  2771. Arguments:
  2772. postion - The physical block address to verify.
  2773. Return Value:
  2774. S_OK - Success.
  2775. --*/
  2776. {
  2777. HRESULT hr = S_OK;
  2778. WsbTraceIn(OLESTR("CNtTapeIo::EnsurePosition"), OLESTR("<%I64u>"), position);
  2779. UINT64 curPos = 0xffffffffffffffff;
  2780. try {
  2781. // Consistency Check
  2782. WsbAffirmHr(GetPosition(&curPos));
  2783. if (curPos != position) {
  2784. // Houston, we've got a problem here...
  2785. // Most likely a bus reset caused the tape position to change.
  2786. WsbLogEvent(MVR_MESSAGE_UNEXPECTED_DATA_SET_LOCATION_DETECTED, 0, NULL,
  2787. WsbQuickString(WsbLonglongAsString(position)),
  2788. WsbQuickString(WsbLonglongAsString(curPos)), NULL);
  2789. // Only recover from complete automatic tape rewinds after a bus reset.
  2790. if (curPos == 0) {
  2791. WsbAffirmHr(SpaceToEndOfData(&curPos));
  2792. // If we still don't line up we've got bigger problems... Note that this
  2793. // can happen if the device's internal buffer had not been flushed prior
  2794. // to the bus reset. (The different tape formats tend to have different
  2795. // rules governing when the drive buffer is flushed/committed. DLT and
  2796. // 4mm tend to commit every couple seconds, but 8mm (at least Exabyte
  2797. // 8505 8mm tape drives) do not commit until the drive buffer is full.)
  2798. // If the buffer was not committed prior to bus reset then the data
  2799. // Remote Storage thinks was written to the tape was never actually
  2800. // written, and is lost. In such a case, the 'SpaceToEndOfData()' call
  2801. // above will only position the tape to the end of the last data actually
  2802. // committed to the tape, which will not match what we are expecting, so
  2803. // the following branch will be taken.
  2804. if (curPos != position) {
  2805. WsbLogEvent(MVR_MESSAGE_UNEXPECTED_DATA_SET_LOCATION_DETECTED, 0, NULL,
  2806. WsbQuickString(WsbLonglongAsString(position)),
  2807. WsbQuickString(WsbLonglongAsString(curPos)), NULL);
  2808. WsbLogEvent(MVR_MESSAGE_DATA_SET_NOT_RECOVERABLE, 0, NULL,
  2809. WsbHrAsString(MVR_E_LOGIC_ERROR), NULL);
  2810. WsbThrow(MVR_E_LOGIC_ERROR);
  2811. }
  2812. WsbLogEvent(MVR_MESSAGE_DATA_SET_RECOVERED, 0, NULL, NULL);
  2813. }
  2814. else {
  2815. WsbLogEvent(MVR_MESSAGE_DATA_SET_NOT_RECOVERABLE, 0, NULL,
  2816. WsbHrAsString(E_ABORT), NULL);
  2817. WsbThrow(E_ABORT);
  2818. }
  2819. }
  2820. } WsbCatch(hr);
  2821. WsbTraceOut(OLESTR("CNtTapeIo::EnsurePosition"), OLESTR("hr = <%ls>"),
  2822. WsbHrAsString(hr));
  2823. return hr;
  2824. }
  2825. HRESULT
  2826. CNtTapeIo::SpaceFilemarks(
  2827. IN LONG count,
  2828. OUT UINT64 *pPosition)
  2829. /*++
  2830. Routine Description:
  2831. Spaces the tape forward or backward by the number of filesmarks specified.
  2832. Arguments:
  2833. count - Specifies the number of filemarks to space over from the current position.
  2834. A positive count spaces the tape forward, and positions after the last filemark.
  2835. A negative count spaces the tape backward, and positions to the beginning of
  2836. the last filemark. If the count is zero, the tape position is not changed.
  2837. pPostion - Receives the physical block address after positioning.
  2838. Return Value:
  2839. S_OK - Success.
  2840. --*/
  2841. {
  2842. HRESULT hr = S_OK;
  2843. WsbTraceIn(OLESTR("CNtTapeIo::SpaceFilemarks"), OLESTR("<%d>"), count);
  2844. UINT64 curPos = 0xffffffffffffffff;
  2845. try {
  2846. WsbAffirmHrOk(IsAccessEnabled());
  2847. try {
  2848. MvrInjectError(L"Inject.CNtTapeIo::SpaceFilemarks.SetTapePosition.0");
  2849. // ** WIN32 Tape API Call - position to the specified filemark
  2850. WsbAffirmNoError(SetTapePosition(m_hTape, TAPE_SPACE_FILEMARKS, 0, count, 0, FALSE));
  2851. MvrInjectError(L"Inject.CNtTapeIo::SpaceFilemarks.SetTapePosition.1");
  2852. } WsbCatchAndDo(hr,
  2853. CWsbStringPtr tmpString;
  2854. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_SETPOSITIONFILEMARKS) != S_OK) {
  2855. tmpString = L"";
  2856. }
  2857. hr = MapTapeError(hr, tmpString);
  2858. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2859. );
  2860. // We always return current position.
  2861. WsbAffirmHr(GetPosition(&curPos));
  2862. if (pPosition) {
  2863. *pPosition = curPos;
  2864. }
  2865. } WsbCatch(hr);
  2866. WsbTraceOut(OLESTR("CNtTapeIo::SpaceFilemarks"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2867. return hr;
  2868. }
  2869. HRESULT
  2870. CNtTapeIo::SpaceToEndOfData(
  2871. OUT UINT64 *pPosition)
  2872. /*++
  2873. Routine Description:
  2874. Positions the tape to the end of data of the current partition.
  2875. Arguments:
  2876. pPostion - Receives the physical block address at end of data.
  2877. Return Value:
  2878. S_OK - Success.
  2879. --*/
  2880. {
  2881. HRESULT hr = S_OK;
  2882. WsbTraceIn(OLESTR("CNtTapeIo::SpaceToEndOfData"), OLESTR(""));
  2883. UINT64 curPos = 0xffffffffffffffff;
  2884. try {
  2885. WsbAffirmHrOk(IsAccessEnabled());
  2886. try {
  2887. MvrInjectError(L"Inject.CNtTapeIo::SpaceToEndOfData.SetTapePosition.0");
  2888. // ** WIN32 Tape API Call - position to end of data
  2889. WsbAffirmNoError(SetTapePosition(m_hTape, TAPE_SPACE_END_OF_DATA, 0, 0, 0, FALSE));
  2890. MvrInjectError(L"Inject.CNtTapeIo::SpaceToEndOfData.SetTapePosition.1");
  2891. } WsbCatchAndDo(hr,
  2892. CWsbStringPtr tmpString;
  2893. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_SETPOSITIONTOEND) != S_OK) {
  2894. tmpString = L"";
  2895. }
  2896. hr = MapTapeError(hr, tmpString);
  2897. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2898. );
  2899. // We always return current position.
  2900. WsbAffirmHr(GetPosition(&curPos));
  2901. if (pPosition) {
  2902. *pPosition = curPos;
  2903. }
  2904. } WsbCatch(hr);
  2905. WsbTraceOut(OLESTR("CNtTapeIo::SpaceToEndOfData"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2906. return hr;
  2907. }
  2908. HRESULT
  2909. CNtTapeIo::RewindTape(void)
  2910. /*++
  2911. Routine Description:
  2912. Rewinds the tape to the beginnning of the current partition.
  2913. Arguments:
  2914. None.
  2915. Return Value:
  2916. S_OK - Success.
  2917. --*/
  2918. {
  2919. HRESULT hr = S_OK;
  2920. WsbTraceIn(OLESTR("CNtTapeIo::RewindTape"), OLESTR(""));
  2921. UINT64 curPos = 0xffffffffffffffff;
  2922. try {
  2923. WsbAffirmHrOk(IsAccessEnabled());
  2924. try {
  2925. MvrInjectError(L"Inject.CNtTapeIo::RewindTape.SetTapePosition.0");
  2926. // ** WIN32 Tape API Call - rewind the tape
  2927. WsbAffirmNoError(SetTapePosition(m_hTape, TAPE_REWIND, 0, 0, 0, FALSE));
  2928. MvrInjectError(L"Inject.CNtTapeIo::RewindTape.SetTapePosition.1");
  2929. } WsbCatchAndDo(hr,
  2930. CWsbStringPtr tmpString;
  2931. if (tmpString.LoadFromRsc(_Module.m_hInst, IDS_MOVER_REWINDTAPE) != S_OK) {
  2932. tmpString = L"";
  2933. }
  2934. hr = MapTapeError(hr, tmpString);
  2935. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, (WCHAR *)tmpString, WsbHrAsString(hr), NULL);
  2936. );
  2937. // We always return current position.
  2938. WsbAffirmHr(GetPosition(&curPos));
  2939. WsbAssert(0 == curPos, E_UNEXPECTED);
  2940. } WsbCatch(hr);
  2941. WsbTraceOut(OLESTR("CNtTapeIo::RewindTape"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2942. return hr;
  2943. }
  2944. HRESULT
  2945. CNtTapeIo::IsAccessEnabled(void)
  2946. {
  2947. HRESULT hr = S_OK;
  2948. //WsbTraceIn(OLESTR("CNtTapeIo::IsAccessEnabled"), OLESTR(""));
  2949. try {
  2950. if (m_pCartridge) {
  2951. // Check that the cartridge is still enable for access
  2952. CComQIPtr<IRmsComObject, &IID_IRmsComObject> pObject = m_pCartridge;
  2953. try {
  2954. WsbAffirmHrOk(pObject->IsEnabled());
  2955. } WsbCatchAndDo(hr,
  2956. HRESULT reason = E_ABORT;
  2957. m_ValidLabel = FALSE;
  2958. pObject->GetStatusCode(&reason);
  2959. WsbThrow(reason);
  2960. );
  2961. }
  2962. } WsbCatch(hr);
  2963. //WsbTraceOut(OLESTR("CNtTapeIo::IsAccessEnabled"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2964. return hr;
  2965. }
  2966. HRESULT
  2967. CNtTapeIo::Lock( void )
  2968. /*++
  2969. Implements:
  2970. IRmsDrive::Lock
  2971. --*/
  2972. {
  2973. HRESULT hr S_OK;
  2974. WsbTraceIn(OLESTR("CRmsDrive::Lock"), OLESTR(""));
  2975. EnterCriticalSection(&m_CriticalSection);
  2976. WsbTraceOut(OLESTR("CRmsDrive::Lock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2977. return hr;
  2978. }
  2979. HRESULT
  2980. CNtTapeIo::Unlock( void )
  2981. /*++
  2982. Implements:
  2983. IRmsDrive::Unlock
  2984. --*/
  2985. {
  2986. HRESULT hr S_OK;
  2987. WsbTraceIn(OLESTR("CRmsDrive::Unlock"), OLESTR(""));
  2988. LeaveCriticalSection(&m_CriticalSection);
  2989. WsbTraceOut(OLESTR("CRmsDrive::Unlock"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2990. return hr;
  2991. }
  2992. HRESULT
  2993. CNtTapeIo::MapTapeError(
  2994. IN HRESULT hrToMap,
  2995. IN WCHAR *pAction)
  2996. /*++
  2997. Routine Description:
  2998. Maps a WIN32 tape error, specified as an HRESULT, to a MVR error.
  2999. Arguments:
  3000. hrToMap - WIN32 tape error to map.
  3001. Return Value:
  3002. S_OK - Success.
  3003. MVR_E_BEGINNING_OF_MEDIA - The beginning of the tape or a partition was encountered.
  3004. MVR_E_BUS_RESET - The I/O bus was reset.
  3005. MVR_E_END_OF_MEDIA - The physical end of the tape has been reached.
  3006. MVR_S_FILEMARK_DETECTED - A tape access reached a filemark.
  3007. MVR_S_SETMARK_DETECTED - A tape access reached the end of a set of files.
  3008. MVR_S_NO_DATA_DETECTED - No more data is on the tape.
  3009. MVR_E_PARTITION_FAILURE - Tape could not be partitioned.
  3010. MVR_E_INVALID_BLOCK_LENGTH - When accessing a new tape of a multivolume partition, the current blocksize is incorrect.
  3011. MVR_E_DEVICE_NOT_PARTITIONED - Tape partition information could not be found when loading a tape.
  3012. MVR_E_MEDIA_CHANGED - The media in the drive may have changed.
  3013. MVR_E_NO_MEDIA_IN_DRIVE - No media in drive.
  3014. MVR_E_UNABLE_TO_LOCK_MEDIA - Unable to lock the media eject mechanism.
  3015. MVR_E_UNABLE_TO_UNLOAD_MEDIA - Unable to unload the media.
  3016. MVR_E_WRITE_PROTECT - The media is write protected.
  3017. MVR_E_CRC - Data error (cyclic redundancy check).
  3018. MVR_E_DEVICE_REQUIRES_CLEANING - The device has indicated that cleaning is required before further operations are attempted.
  3019. MVR_E_SHARING_VIOLATION - The process cannot access the file because it is being used by another process.
  3020. MVR_E_ERROR_IO_DEVICE - The request could not be performed because of an I/O device error. - Unknown error.
  3021. MVR_E_ERROR_DEVICE_NOT_CONNECTED - The device is not connected.
  3022. MVR_E_ERROR_NOT_READY - Device is not ready.
  3023. E_ABORT - Unknown error, abort.
  3024. --*/
  3025. {
  3026. HRESULT hr = S_OK;
  3027. WsbTraceIn(OLESTR("CNtTapeIo::MapTapeError"), OLESTR("<%ls>"), WsbHrAsString(hrToMap));
  3028. try {
  3029. // The valid label flag is knocked down when the media may have changed
  3030. // or device parameters (i.e. block size) may have been reset.
  3031. switch ( hrToMap ) {
  3032. case S_OK:
  3033. break;
  3034. case HRESULT_FROM_WIN32( ERROR_BEGINNING_OF_MEDIA ):
  3035. hr = MVR_E_BEGINNING_OF_MEDIA;
  3036. break;
  3037. case HRESULT_FROM_WIN32( ERROR_BUS_RESET ):
  3038. hr = MVR_E_BUS_RESET;
  3039. m_ValidLabel = FALSE;
  3040. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3041. break;
  3042. case HRESULT_FROM_WIN32( ERROR_END_OF_MEDIA ):
  3043. hr = MVR_E_END_OF_MEDIA;
  3044. break;
  3045. case HRESULT_FROM_WIN32( ERROR_FILEMARK_DETECTED ): // Maps to Success
  3046. hr = MVR_S_FILEMARK_DETECTED;
  3047. break;
  3048. case HRESULT_FROM_WIN32( ERROR_SETMARK_DETECTED ): // Maps to Success
  3049. hr = MVR_S_SETMARK_DETECTED;
  3050. break;
  3051. case HRESULT_FROM_WIN32( ERROR_NO_DATA_DETECTED ): // Maps to Success
  3052. // EOD
  3053. // This happens on SpaceFilemarks() and SetPosition() past end of data.
  3054. hr = MVR_S_NO_DATA_DETECTED;
  3055. break;
  3056. case HRESULT_FROM_WIN32( ERROR_PARTITION_FAILURE ):
  3057. hr = MVR_E_PARTITION_FAILURE;
  3058. break;
  3059. case HRESULT_FROM_WIN32( ERROR_INVALID_BLOCK_LENGTH ):
  3060. hr = MVR_E_INVALID_BLOCK_LENGTH;
  3061. break;
  3062. case HRESULT_FROM_WIN32( ERROR_DEVICE_NOT_PARTITIONED ):
  3063. hr = MVR_E_DEVICE_NOT_PARTITIONED;
  3064. break;
  3065. case HRESULT_FROM_WIN32( ERROR_MEDIA_CHANGED ):
  3066. hr = MVR_E_MEDIA_CHANGED;
  3067. m_ValidLabel = FALSE;
  3068. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3069. break;
  3070. case HRESULT_FROM_WIN32( ERROR_NO_MEDIA_IN_DRIVE ):
  3071. hr = MVR_E_NO_MEDIA_IN_DRIVE;
  3072. m_ValidLabel = FALSE;
  3073. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3074. break;
  3075. case HRESULT_FROM_WIN32( ERROR_UNABLE_TO_LOCK_MEDIA ):
  3076. hr = MVR_E_UNABLE_TO_LOCK_MEDIA;
  3077. break;
  3078. case HRESULT_FROM_WIN32( ERROR_UNABLE_TO_UNLOAD_MEDIA ):
  3079. hr = MVR_E_UNABLE_TO_UNLOAD_MEDIA;
  3080. break;
  3081. case HRESULT_FROM_WIN32( ERROR_WRITE_PROTECT ):
  3082. hr = MVR_E_WRITE_PROTECT;
  3083. break;
  3084. case HRESULT_FROM_WIN32( ERROR_CRC ):
  3085. // This is may indicate that the drive needs cleaning.
  3086. //
  3087. // 8505: This code returned for SpaceFilemarks or SpaceEOD operation
  3088. // for which no EOD marker exist on tape. This happens when
  3089. // after power cycling device during writes.
  3090. // Verfied by bmd on 3/25/98 using new, bulk erased, and used tape.
  3091. // Look for new error ERROR_NOT_FOUND to replace ERROR_CRC when
  3092. // there's a misssing EOD marker.
  3093. //
  3094. // DLT: See 8500 notes.
  3095. //
  3096. hr = MVR_E_CRC;
  3097. m_ValidLabel = FALSE;
  3098. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3099. break;
  3100. case HRESULT_FROM_WIN32( ERROR_DEVICE_REQUIRES_CLEANING ):
  3101. // This happens on I/O errors that that driver believes may be fixed
  3102. // by cleaning the drive heads.
  3103. hr = MVR_E_DEVICE_REQUIRES_CLEANING;
  3104. m_ValidLabel = FALSE;
  3105. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3106. break;
  3107. case HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION ):
  3108. // This happens when the CreateFile fails because the device is in use by some other app.
  3109. hr = MVR_E_SHARING_VIOLATION;
  3110. m_ValidLabel = FALSE;
  3111. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3112. break;
  3113. case HRESULT_FROM_WIN32( ERROR_IO_DEVICE ):
  3114. // This happens when the device is turned off during I/O, for example.
  3115. hr = MVR_E_ERROR_IO_DEVICE;
  3116. m_ValidLabel = FALSE;
  3117. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3118. break;
  3119. case HRESULT_FROM_WIN32( ERROR_DEVICE_NOT_CONNECTED ):
  3120. // This happens when the device is turned off.
  3121. hr = MVR_E_ERROR_DEVICE_NOT_CONNECTED;
  3122. m_ValidLabel = FALSE;
  3123. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3124. break;
  3125. case HRESULT_FROM_WIN32( ERROR_SEM_TIMEOUT ):
  3126. // This happens when the SCSI command does not return within the timeout period. A system error is logged for the SCSI controler (adapter).
  3127. hr = MVR_E_ERROR_DEVICE_NOT_CONNECTED;
  3128. break;
  3129. case HRESULT_FROM_WIN32( ERROR_NOT_READY ):
  3130. // This happens when the device is coming ready (i.e. after a bus reset).
  3131. hr = MVR_E_ERROR_NOT_READY;
  3132. m_ValidLabel = FALSE;
  3133. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3134. break;
  3135. case HRESULT_FROM_WIN32( ERROR_NOT_FOUND ):
  3136. // See 8500 notes under ERROR_CRC
  3137. hr = MVR_S_NO_DATA_DETECTED;
  3138. break;
  3139. default:
  3140. WsbThrow(hrToMap);
  3141. }
  3142. } WsbCatchAndDo(hr,
  3143. WsbLogEvent(MVR_MESSAGE_UNKNOWN_DEVICE_ERROR, 0, NULL, pAction, WsbHrAsString(hr), NULL);
  3144. hr = E_ABORT;
  3145. );
  3146. WsbTraceOut(OLESTR("CNtTapeIo::MapTapeError"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  3147. return hr;
  3148. }