Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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