Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3443 lines
112 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. MTFSessn.cpp
  5. Abstract:
  6. CMTFSession class
  7. Author:
  8. Brian Dodd [brian] 25-Nov-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "engine.h"
  13. #include "MTFSessn.h"
  14. //
  15. // !!!!! VERY IMPORTANT !!!!!
  16. //
  17. // WIN32_STREAM_ID_SIZE -- Size of WIN32_STREAM_ID (20) != sizeof(WIN32_STREAM_ID) (24)
  18. // due to WIN32_STREAM_ID being a variable sized structure --
  19. // See below.
  20. #define WIN32_STREAM_ID_SIZE 20
  21. /*****************************************************************************
  22. DETAIL DESCRIPTION
  23. OVERVIEW
  24. ========
  25. This class uses MTF API calls to create a data set. A data set
  26. is created by writing a series of DBLKs which may optionally be followed by
  27. data streams.
  28. For each DBLK, the MTF API defines a corresponding xxxx_DBLK_INFO struct
  29. which is filled in by the client. This can be done field by field or by
  30. using an MTF API function which automatically fills in the structure with
  31. default information.
  32. The xxxx_DBLK_INFO structs are then passed to MTF_WriteXXXXDblk functions which
  33. use the information in the struct to format a buffer, which can then be written
  34. to the data set, using the Stream I/O Write function.
  35. DATA SET FORMAT
  36. ===============
  37. A data set is created by writing DBLKs and Streams in the following order:
  38. TAPE DBLK -- describes the media
  39. FILEMARK
  40. SSET DBLK -- start of set describing the data set
  41. VOLB DBLK -- describs the volume being stored
  42. for each directory and parent directory
  43. DIRB DBLK -- one for each directory/sub-directory, starting with the root
  44. STREAM -- may contain security info for the directory
  45. for each file to backup
  46. FILE DBLK -- one for each file, followed by one or more streams, describing
  47. STREAM security info, as well as the file data streams themselves
  48. STREAM
  49. FILEMARK
  50. ESET DBLK -- indicates the end of the data set
  51. FILEMARK -- terminates the data set
  52. FUNCTIONS OVERVIEW
  53. ==================
  54. The MTF session maintains various information about the data set being created.
  55. This member data is then used by the following routines.
  56. InitCommonHeader() -- Initializes the common header which is used in
  57. all DBLKS is stored
  58. DoTapeDblk() -- writes the TAPE DBLK
  59. DoSSETDblk() -- writes the SSET DBLK
  60. DoVolumeDblk() -- writes the VOLB DBLK
  61. DoParentDirectories() -- writes DIRB DBLKs and Streams for the directory
  62. to backed up and each of its parent directories
  63. DoDirectoryDblk() -- writes a single DIRB DBLK and associated security
  64. stream
  65. DoDataSet() -- writes FILE and DIRB DBLKs and associated data
  66. streams for everything in the directory.
  67. Recurses for sub-directories
  68. DoFileDblk() -- writes a FILE DBLK
  69. DoDataStream() -- writes data stream(s) associated with a file or
  70. directory
  71. DoEndOfDataSet() -- writes ESET DBLK and surrounding FILEMARKS
  72. NOTES AND WARNINGS
  73. ==================
  74. o Directory names are stored in DIRB DBLKs as "DIR\SUBDIR1\...\SUBDIRn\"
  75. (no vol, and with a trailing \) where as filenames are stored in
  76. FILE DBLKS just as "FILENAME.EXT"
  77. o In DIRB's, the backslashes between directory names are covnerted to L'\0'!!!!!
  78. (the mtf api takes care of this -- give it names with slashes!!!!)
  79. o All strings are assumed to be WCHAR by the MTF API
  80. o We assume here that __uint64 is supported by the compiler.
  81. *****************************************************************************/
  82. static USHORT iCountMTFs = 0; // Count of existing objects
  83. CMTFSession::CMTFSession(void)
  84. {
  85. WsbTraceIn(OLESTR("CMTFSession::CMTFSession"), OLESTR(""));
  86. // public
  87. m_pStream = NULL;
  88. memset(&m_sHints, 0, sizeof(MVR_REMOTESTORAGE_HINTS));
  89. // private
  90. m_nCurrentBlockId = 0;
  91. m_nDirectoryId = 0;
  92. m_nFileId = 0;
  93. m_nFormatLogicalAddress = 0;
  94. m_nPhysicalBlockAddress = 0;
  95. m_nBlockSize = 0;
  96. m_pSoftFilemarks = NULL;
  97. memset (&m_sHeaderInfo, 0, sizeof(MTF_DBLK_HDR_INFO));
  98. memset (&m_sSetInfo, 0, sizeof(MTF_DBLK_SSET_INFO));
  99. memset (&m_sVolInfo, 0, sizeof(MTF_DBLK_VOLB_INFO));
  100. m_pBuffer = NULL;
  101. m_pRealBuffer = NULL;
  102. m_nBufUsed = 0;
  103. m_nBufSize = 0;
  104. m_nStartOfPad = 0;
  105. m_bUseFlatFileStructure = FALSE;
  106. m_bUseSoftFilemarks = FALSE;
  107. m_bUseCaseSensitiveSearch = FALSE;
  108. m_bCommitFile = FALSE;
  109. m_bSetInitialized = FALSE;
  110. memset (&m_SaveBasicInformation, 0, sizeof(FILE_BASIC_INFORMATION));
  111. m_pvReadContext = NULL;
  112. // Create an MTFApi object
  113. m_pMTFApi = new CMTFApi;
  114. iCountMTFs++;
  115. WsbTraceOut(OLESTR("CMTFSession::CMTFSession"),OLESTR("Count is <%d>"), iCountMTFs);
  116. }
  117. CMTFSession::~CMTFSession(void)
  118. {
  119. WsbTraceIn(OLESTR("CMTFSession::~CMTFSession"), OLESTR(""));
  120. if (m_pMTFApi) {
  121. delete m_pMTFApi;
  122. m_pMTFApi = NULL;
  123. }
  124. if (m_pSoftFilemarks) {
  125. WsbFree(m_pSoftFilemarks);
  126. m_pSoftFilemarks = NULL;
  127. }
  128. if (m_pRealBuffer) {
  129. WsbFree(m_pRealBuffer);
  130. m_pBuffer = NULL;
  131. m_pRealBuffer = NULL;
  132. }
  133. iCountMTFs--;
  134. WsbTraceOut(OLESTR("CMTFSession::~CMTFSession"),OLESTR("Count is <%d>"), iCountMTFs);
  135. }
  136. ////////////////////////////////////////////////////////////////////////////////
  137. //
  138. // Local Methods
  139. //
  140. HRESULT
  141. CMTFSession::SetBlockSize(
  142. UINT32 blockSize)
  143. /*++
  144. Routine Description:
  145. Defines the physical block size for the session. This is used for various PBA calculations.
  146. The value should only be set once per session.
  147. Arguments:
  148. blockSize - The new block size for the session.
  149. Return Value:
  150. S_OK - Success.
  151. --*/
  152. {
  153. HRESULT hr = S_OK;
  154. WsbTraceIn(OLESTR("CMTFSession::SetBlockSize"), OLESTR("<%d>"), blockSize);
  155. ULONG bufferSize = 0;
  156. try {
  157. WsbAssert(blockSize > 0, E_INVALIDARG);
  158. WsbAssert(!(blockSize % 512), E_INVALIDARG);
  159. m_nBlockSize = blockSize;
  160. // **MTF API CALL**
  161. // The MTF API needs to know the alignment factor!!!!!!!
  162. //
  163. WsbAssert(m_pMTFApi != NULL, E_OUTOFMEMORY);
  164. if (!(blockSize % 1024)) {
  165. m_pMTFApi->MTF_SetAlignmentFactor((UINT16) 1024);
  166. }
  167. else {
  168. // We already checked that the block size is a multiple of 512....
  169. m_pMTFApi->MTF_SetAlignmentFactor((UINT16) 512);
  170. }
  171. ULONG defaultBufferSize = RMS_DEFAULT_BUFFER_SIZE;
  172. DWORD size;
  173. OLECHAR tmpString[256];
  174. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_BUFFER_SIZE, tmpString, 256, &size))) {
  175. // Get the value.
  176. LONG val = wcstol(tmpString, NULL, 10);
  177. if (val > 0) {
  178. defaultBufferSize = val;
  179. }
  180. }
  181. ULONG nBlocks = defaultBufferSize/m_nBlockSize;
  182. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  183. bufferSize = nBlocks * m_nBlockSize;
  184. // Make sure we work with a virtual address aligned with sector size
  185. m_pRealBuffer = (BYTE *)WsbAlloc(bufferSize+m_nBlockSize);
  186. if (m_pRealBuffer) {
  187. if ((ULONG_PTR)m_pRealBuffer % m_nBlockSize) {
  188. m_pBuffer = m_pRealBuffer - ((ULONG_PTR)m_pRealBuffer % m_nBlockSize) + m_nBlockSize;
  189. } else {
  190. m_pBuffer = m_pRealBuffer;
  191. }
  192. } else {
  193. m_pBuffer = NULL;
  194. }
  195. WsbTrace(OLESTR("CMTFSession::SetBlockSize: Real Buffer Ptr = %I64X , Use Buffer Ptr = %I64X\n"),
  196. (UINT64)m_pRealBuffer, (UINT64)m_pBuffer);
  197. if (m_pBuffer) {
  198. m_nBufSize = bufferSize;
  199. m_nBufUsed = 0;
  200. }
  201. else {
  202. m_nBufSize = 0;
  203. m_nBufUsed = bufferSize;
  204. }
  205. WsbAssertPointer(m_pBuffer);
  206. WsbTraceAlways( OLESTR("Using buffer size of %d bytes for data transfers.\n"), bufferSize);
  207. } WsbCatch(hr);
  208. WsbTraceOut(OLESTR("CMTFSession::SetBlockSize"), OLESTR("hr = <%ls>, Alignment = %d, BufferSize = %d"), WsbHrAsString(hr), m_pMTFApi->MTF_GetAlignmentFactor(), bufferSize);
  209. return hr;
  210. }
  211. HRESULT
  212. CMTFSession::SetUseFlatFileStructure(
  213. BOOL val)
  214. /*++
  215. Routine Description:
  216. Unconditionally sets the session flags to the value specified.
  217. Arguments:
  218. val - The new value for the UseFlatFileStructure flag.
  219. Return Value:
  220. S_OK - Success.
  221. --*/
  222. {
  223. m_bUseFlatFileStructure = val;
  224. return S_OK;
  225. }
  226. HRESULT
  227. CMTFSession::SetUseCaseSensitiveSearch(
  228. BOOL val)
  229. /*++
  230. Routine Description:
  231. Unconditionally sets the session flag to the value specified.
  232. Arguments:
  233. val - The new value for the CaseSensitiveSearch flag.
  234. Return Value:
  235. S_OK - Success.
  236. --*/
  237. {
  238. m_bUseCaseSensitiveSearch = val;
  239. return S_OK;
  240. }
  241. HRESULT
  242. CMTFSession::SetCommitFile(
  243. BOOL val)
  244. /*++
  245. Routine Description:
  246. Unconditionally sets the session flag to the value specified.
  247. Arguments:
  248. val - The new value for the CommitFile flag.
  249. Return Value:
  250. S_OK - Success.
  251. --*/
  252. {
  253. m_bCommitFile = val;
  254. return S_OK;
  255. }
  256. HRESULT
  257. CMTFSession::SetUseSoftFilemarks(
  258. BOOL val)
  259. /*++
  260. Routine Description:
  261. Unconditionally sets the session flags to the value specified.
  262. Arguments:
  263. val - The new value for the UseSoftFilemarks flag.
  264. Return Value:
  265. S_OK - Success.
  266. --*/
  267. {
  268. HRESULT hr = S_OK;
  269. try {
  270. m_bUseSoftFilemarks = val;
  271. if (TRUE == m_bUseSoftFilemarks) {
  272. WsbAssert(NULL == m_pSoftFilemarks, E_UNEXPECTED);
  273. // Make sure the block size was initialized.
  274. WsbAssert(m_nBlockSize > 0, E_UNEXPECTED);
  275. // Allocate a block of memory for the soft filemark array
  276. m_pSoftFilemarks = (MTF_DBLK_SFMB_INFO *) WsbAlloc(m_nBlockSize);
  277. WsbAffirmPointer(m_pSoftFilemarks);
  278. memset(m_pSoftFilemarks, 0 , m_nBlockSize);
  279. // **MTF API CALL**
  280. m_pSoftFilemarks->uNumberOfFilemarkEntries = m_pMTFApi->MTF_GetMaxSoftFilemarkEntries(m_nBlockSize);
  281. WsbAssert(m_pSoftFilemarks->uNumberOfFilemarkEntries > 0, E_UNEXPECTED);
  282. }
  283. else {
  284. if (m_pSoftFilemarks) {
  285. WsbFree(m_pSoftFilemarks);
  286. m_pSoftFilemarks = NULL;
  287. }
  288. }
  289. } WsbCatch(hr);
  290. return hr;
  291. }
  292. HRESULT
  293. CMTFSession::InitCommonHeader(void)
  294. /*++
  295. Routine Description:
  296. Sets up the common header.
  297. m_sHeaderInfo is set for unicode, NT & no block
  298. attributes
  299. Arguments:
  300. None.
  301. Return Value:
  302. S_OK - Success.
  303. --*/
  304. {
  305. // Init Common header
  306. // **MTF API CALL**
  307. m_pMTFApi->MTF_SetDblkHdrDefaults(&m_sHeaderInfo);
  308. m_sHeaderInfo.uBlockAttributes = 0;
  309. m_sHeaderInfo.uOSID = MTF_OSID_DOS; // MTF_OSID_NT or MTF_OSID_DOS
  310. m_sHeaderInfo.uStringType = MTF_STRING_UNICODE_STR;
  311. return S_OK;
  312. }
  313. HRESULT
  314. CMTFSession::DoTapeDblk(
  315. IN WCHAR *szLabel,
  316. IN ULONG maxIdSize,
  317. IN OUT BYTE *pIdentifier,
  318. IN OUT ULONG *pIdSize,
  319. IN OUT ULONG *pIdType)
  320. /*++
  321. Routine Description:
  322. Formats and Writes a TAPE DBLK. TAPE DBLK and
  323. FILEMARK are written to beginning of tape, disk, or file.
  324. Arguments:
  325. szLabel - The media label.
  326. Return Value:
  327. S_OK - Success.
  328. --*/
  329. {
  330. HRESULT hr = S_OK;
  331. WsbTraceIn(OLESTR("CMTFSession::DoTapeDblk"), OLESTR("<%ls>"), szLabel);
  332. try {
  333. MvrInjectError(L"Inject.CMTFSession::DoTapeDblk.0");
  334. WsbAssertPointer(m_pBuffer);
  335. if ( maxIdSize > 0 ) {
  336. WsbAssertPointer( pIdentifier );
  337. WsbAssertPointer( pIdSize );
  338. WsbAssertPointer( pIdType );
  339. }
  340. MTF_DBLK_TAPE_INFO sTapeInfo; // **MTF API STRUCT ** -- info for TAPE
  341. (void) InitCommonHeader();
  342. // **MTF API CALL**
  343. // First set defaults for the info struct
  344. //
  345. // Note: Tthis sets the alignment factor to that set previously by
  346. // MTF_SetAlignmentFactor()
  347. m_pMTFApi->MTF_SetTAPEDefaults(&sTapeInfo);
  348. // Set the values of the MTF_DBLK_TAPE_INFO struct to suit our application
  349. // Set SFMB size, this should be used during restoration on media types that use SFM
  350. sTapeInfo.uSoftFilemarkBlockSize = (UINT16)(m_nBlockSize / 512);
  351. // The family id should be a unique value for each piece of media. Although not
  352. // guaranteed to be unique, the time function should provide something close enough.
  353. time_t tTime;
  354. sTapeInfo.uTapeFamilyId = (unsigned int) time(&tTime);
  355. sTapeInfo.uTapeAttributes |= MTF_TAPE_MEDIA_LABEL;
  356. if (TRUE == m_bUseSoftFilemarks) {
  357. sTapeInfo.uTapeAttributes |= MTF_TAPE_SOFT_FILEMARK;
  358. }
  359. sTapeInfo.uTapeSequenceNumber = 1;
  360. sTapeInfo.szTapeDescription = szLabel;
  361. sTapeInfo.uSoftwareVendorId = REMOTE_STORAGE_MTF_VENDOR_ID;
  362. //
  363. // Get remaining information from the label
  364. //
  365. CWsbBstrPtr tempLabel = szLabel;
  366. WCHAR delim[] = OLESTR("|");
  367. WCHAR *token;
  368. int index=0;
  369. token = wcstok( (WCHAR *)tempLabel, delim );
  370. while( token != NULL ) {
  371. index++;
  372. switch ( index ) {
  373. case 1: // Tag
  374. case 2: // Version
  375. case 3: // Vendor
  376. break;
  377. case 4: // Vendor Product ID
  378. sTapeInfo.szSoftwareName = token;
  379. break;
  380. case 5: // Creation Time Stamp
  381. {
  382. int iYear, iMonth, iDay, iHour, iMinute, iSecond;
  383. swscanf( token, L"%d/%d/%d.%d:%d:%d", &iYear, &iMonth, &iDay, &iHour, &iMinute, &iSecond );
  384. // **MTF API CALL**
  385. sTapeInfo.sTapeDate = m_pMTFApi->MTF_CreateDateTime( iYear, iMonth, iDay, iHour, iMinute, iSecond );
  386. }
  387. break;
  388. case 6: // Cartridge Label
  389. sTapeInfo.szTapeName = token;
  390. break;
  391. case 7: // Side
  392. case 8: // Media ID
  393. case 9: // Media Domain ID
  394. default: // Vendor specific of the form L"VS:Name=Value"
  395. break;
  396. }
  397. token = wcstok( NULL, delim );
  398. }
  399. // These are zero for the tape dblk
  400. m_sHeaderInfo.uControlBlockId = 0;
  401. m_sHeaderInfo.uFormatLogicalAddress = 0;
  402. WsbTrace(OLESTR("Writing Tape Header (TAPE)\n"));
  403. // Sets the current position to beginning of data.
  404. WsbAffirmHr(SpaceToBOD());
  405. // **MTF API CALL**
  406. // Provide the MTF_DBLK_HDR_INFO and MTF_DBLK_TAPE_INFO structs to this
  407. // function. The result is an MTF formatted TAPE DBLK in m_pBuffer.
  408. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  409. WsbAssertNoError(m_pMTFApi->MTF_WriteTAPEDblk(&m_sHeaderInfo, &sTapeInfo, m_pBuffer, m_nBufSize, &m_nBufUsed));
  410. WsbTrace(OLESTR("Tape Header uses %lu of %lu bytes\n"), (ULONG)m_nBufUsed, (ULONG)m_nBufSize);
  411. // Save the on media identifier
  412. if (maxIdSize > 0) {
  413. *pIdSize = (maxIdSize > (ULONG)m_nBufUsed) ? (ULONG)m_nBufUsed : maxIdSize;
  414. *pIdType = (LONG) RmsOnMediaIdentifierMTF;
  415. memcpy(pIdentifier, m_pBuffer, *pIdSize);
  416. }
  417. WsbAffirmHr(PadToNextPBA());
  418. // Write a filemark. This will flush the device buffer.
  419. WsbAffirmHr(WriteFilemarks(1));
  420. } WsbCatch(hr);
  421. WsbTraceOut(OLESTR("CMTFSession::DoTapeDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  422. return hr;
  423. }
  424. HRESULT
  425. CMTFSession::DoSSETDblk(
  426. IN WCHAR *szSessionName,
  427. IN WCHAR *szSessionDescription,
  428. IN MTFSessionType type,
  429. IN USHORT nDataSetNumber)
  430. /*++
  431. Routine Description:
  432. Formats and Writes a SSET DBLK. The SSET is the first DBLK written
  433. to a data set.
  434. Arguments:
  435. szSessionName - Session name.
  436. szSessionDescription - Session description that is displayed by the Backup program
  437. type - Specifies the data set type: Transfer, copy , normal, differential,
  438. incremental, daily, etc.
  439. nDataSetNumber - The data set number.
  440. Return Value:
  441. S_OK - Success.
  442. --*/
  443. {
  444. HRESULT hr = S_OK;
  445. WsbTraceIn(OLESTR("CMTFSession::DoSSETDblk"), OLESTR("<%ls> <%ls> <%d> <%d>"), szSessionName, szSessionDescription, type, nDataSetNumber);
  446. try {
  447. MvrInjectError(L"Inject.CMTFSession::DoSSETDblk.0");
  448. WsbAssertPointer(m_pBuffer);
  449. UINT64 curPos;
  450. size_t nBufUsed = 0;
  451. // Reset Control Block info.
  452. m_nCurrentBlockId = 0;
  453. m_nDirectoryId = 0;
  454. m_nFileId = 0;
  455. (void) InitCommonHeader();
  456. // Init SSET block
  457. // **MTF API CALL**
  458. m_pMTFApi->MTF_SetSSETDefaults(&m_sSetInfo);
  459. m_bSetInitialized = TRUE;
  460. //
  461. // Find out our account information
  462. //
  463. CWsbStringPtr accountName;
  464. WsbAffirmHr(WsbGetServiceInfo(APPID_RemoteStorageEngine, NULL, &accountName));
  465. //
  466. // Set the values of the MTF_DBLK_SSET_INFO struct...
  467. //
  468. // First select the type of data set we are creating.
  469. switch (type) {
  470. case MTFSessionTypeTransfer:
  471. m_sSetInfo.uSSETAttributes = MTF_SSET_TRANSFER;
  472. break;
  473. case MTFSessionTypeCopy:
  474. m_sSetInfo.uSSETAttributes = MTF_SSET_COPY;
  475. break;
  476. case MTFSessionTypeNormal:
  477. m_sSetInfo.uSSETAttributes = MTF_SSET_NORMAL;
  478. break;
  479. case MTFSessionTypeDifferential:
  480. m_sSetInfo.uSSETAttributes = MTF_SSET_DIFFERENTIAL;
  481. break;
  482. case MTFSessionTypeIncremental:
  483. m_sSetInfo.uSSETAttributes = MTF_SSET_INCREMENTAL;
  484. break;
  485. case MTFSessionTypeDaily:
  486. m_sSetInfo.uSSETAttributes = MTF_SSET_DAILY;
  487. break;
  488. default:
  489. WsbThrow(E_INVALIDARG);
  490. break;
  491. }
  492. m_sSetInfo.uDataSetNumber = nDataSetNumber;
  493. m_sSetInfo.uSoftwareVendorId = REMOTE_STORAGE_MTF_VENDOR_ID;
  494. m_sSetInfo.szDataSetName = szSessionName;
  495. m_sSetInfo.szDataSetDescription = szSessionDescription;
  496. m_sSetInfo.szUserName = accountName;
  497. WsbAffirmHr(GetCurrentPBA(&curPos)); // utility fn below
  498. m_sSetInfo.uPhysicalBlockAddress = curPos;
  499. m_sSetInfo.uPhysicalBlockAddress += 1 ; // MTF is one based, devices are zero based.
  500. m_sSetInfo.uSoftwareVerMjr = REMOTE_STORAGE_MTF_SOFTWARE_VERSION_MJ;
  501. m_sSetInfo.uSoftwareVerMnr = REMOTE_STORAGE_MTF_SOFTWARE_VERSION_MN;
  502. // Save the PBA for the data set
  503. m_nPhysicalBlockAddress = m_sSetInfo.uPhysicalBlockAddress -1;
  504. WsbAssert(m_nPhysicalBlockAddress > 0, E_UNEXPECTED); // Someting went wrong!
  505. m_nFormatLogicalAddress = 0;
  506. // The Control Block ID field is used for error recovery. The
  507. // Control Block ID value for an SSET DBLK should be zero. All
  508. // subsequent DBLKs within the Data Set will have a Control Block
  509. // ID one greater than the previous DBLK�s Control Block ID.
  510. // Values for this field are only defined for DBLKs within a Data
  511. // Set from the SSET to the last DBLK occurring prior to the ESET.
  512. WsbAssert(0 == m_nCurrentBlockId, E_UNEXPECTED);
  513. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  514. // Increment them here after for every dblk we write
  515. m_sHeaderInfo.uFormatLogicalAddress = 0;
  516. WsbTrace(OLESTR("Writing Start of Set (SSET) @ PBA %I64u\n"), m_nPhysicalBlockAddress);
  517. // **MTF API CALL** --
  518. // Provide the MTF_DBLK_HDR_INFO and MTF_DBLK_SSET_INFO structs to
  519. // this function. The result is an MTF formatted SSET DBLK in m_pBuffer.
  520. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  521. WsbAssertNoError(m_pMTFApi->MTF_WriteSSETDblk(&m_sHeaderInfo, &m_sSetInfo, m_pBuffer, m_nBufSize, &m_nBufUsed));
  522. // We pass in FALSE to make sure we don't actually touch tape. The SSET is the
  523. // first DBLK written in the data set so we have plenty of transfer buffer for
  524. // the DBLKs to follow.
  525. //
  526. // This routine is called when the application starts a new data set, but
  527. // we don't wan't to fail if we're going to get device errors, that will come
  528. // later.
  529. WsbAffirmHr(PadToNextFLA(FALSE));
  530. m_sHints.DataSetStart.QuadPart = m_nPhysicalBlockAddress * m_nBlockSize;
  531. } WsbCatch(hr);
  532. WsbTraceOut(OLESTR("CMTFSession::DoSSETDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  533. return hr;
  534. }
  535. HRESULT
  536. CMTFSession::DoVolumeDblk(
  537. IN WCHAR *szPath)
  538. /*++
  539. Routine Description:
  540. Formats and Writes a VOLB DBLK.
  541. Arguments:
  542. szPath - Full pathname containing name of volume.
  543. Return Value:
  544. S_OK - Success.
  545. --*/
  546. {
  547. HRESULT hr = S_OK;
  548. WsbTraceIn(OLESTR("CMTFSession::DoVolumeDblk"), OLESTR("<%ls>"), WsbAbbreviatePath(szPath, 120));
  549. try {
  550. MvrInjectError(L"Inject.CMTFSession::DoVolumeDblk.0");
  551. WsbAssertPointer(m_pBuffer);
  552. WsbAssertPointer(szPath);
  553. CWsbStringPtr szVolume;
  554. size_t nMoreBufUsed;
  555. szVolume = szPath;
  556. WsbAffirm(0 != (WCHAR *)szVolume, E_OUTOFMEMORY);
  557. WsbAssert(m_nBlockSize > 0, MVR_E_LOGIC_ERROR);
  558. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  559. // It won't be if we are having problems writing to tape.
  560. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  561. WsbAffirm(0 == (m_nBufUsed % uAlignmentFactor), E_ABORT);
  562. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  563. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  564. WsbTrace(OLESTR("%ls (VOLB) @ FLA %I64u (%I64u, %I64u)\n"), WsbAbbreviatePath(szPath, 120),
  565. fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  566. // **MTF API CALL**
  567. // Sets the MTF_VOLB_DBLK_INFO struct using Win32 GetVolumeInformation data
  568. m_pMTFApi->MTF_SetVOLBForDevice(&m_sVolInfo, szVolume);
  569. // Increment the blockid and alignment index values that we keep in
  570. // our common block header structure.
  571. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  572. m_sHeaderInfo.uFormatLogicalAddress = fla;
  573. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  574. // **MTF API CALL**
  575. // Provide the MTF_DBLK_HDR_INFO and MTF_DBLK_VOLB_INFO structs to
  576. // this function. The result is an MTF formatted VOLB DBLK in m_pBuffer.
  577. nMoreBufUsed = 0;
  578. WsbAssertNoError(m_pMTFApi->MTF_WriteVOLBDblk(&m_sHeaderInfo, &m_sVolInfo, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  579. m_nBufUsed += nMoreBufUsed;
  580. // Output VOLB to the data set.
  581. WsbAffirmHr(PadToNextFLA(TRUE));
  582. } WsbCatch(hr);
  583. WsbTraceOut(OLESTR("CMTFSession::DoVolumeDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  584. return hr;
  585. }
  586. HRESULT
  587. CMTFSession::DoParentDirectories(
  588. IN WCHAR *szPath)
  589. /*++
  590. Routine Description:
  591. Formats and writes the parent DIRB Dblks for the given pathname.
  592. Arguments:
  593. szPath - Full pathname of directory.
  594. Return Value:
  595. S_OK - Success.
  596. Note:
  597. In order for both stickyName and driveLetter-colon path formats to work properly, both with and
  598. without writing separate DIRBs for the parent directories,
  599. THE EXISTENCE AND PLACEMENT OF THE PATH MANIPULATION CODE (APPEND/PREPEND, ETC.) IS CRUCIAL!!!
  600. --*/
  601. {
  602. HRESULT hr = S_OK;
  603. WsbTraceIn(OLESTR("CMTFSession::DoParentDirectories"), OLESTR("<%ls>"), WsbAbbreviatePath(szPath, 120));
  604. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  605. try {
  606. MvrInjectError(L"Inject.CMTFSession::DoParentDirectories.0");
  607. WsbAssertPointer( szPath );
  608. WIN32_FIND_DATAW obFindData;
  609. CWsbStringPtr path;
  610. CWsbStringPtr nameSpace;
  611. WCHAR *szDirs;
  612. WCHAR *token;
  613. DWORD additionalSearchFlags = 0;
  614. additionalSearchFlags |= (m_bUseCaseSensitiveSearch) ? FIND_FIRST_EX_CASE_SENSITIVE : 0;
  615. nameSpace = szPath;
  616. nameSpace.GiveTo(&szDirs);
  617. // First we need to do a DIRB dblk for the root directory
  618. nameSpace = wcstok(szDirs, OLESTR("\\")); // pop off "Volume{......}" or "driveLetter:"
  619. WsbAffirmHr(nameSpace.Append(OLESTR("\\")));
  620. // ** WIN32 API Call - gets directory info for the root directory
  621. // For the root directory only, we need to call GetFileInformationByHandle instead of
  622. // ..FindFirstFileEx. FindFirst doesn't return root dir info since the root has no parent
  623. path = nameSpace;
  624. WsbAffirmHr(path.Prepend(OLESTR("\\\\?\\")));
  625. WsbAffirm(0 != (WCHAR *)path, E_OUTOFMEMORY);
  626. BY_HANDLE_FILE_INFORMATION obGetFileInfoData;
  627. memset(&obGetFileInfoData, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
  628. WsbAffirmHandle(hSearchHandle = CreateFile(path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
  629. WsbAffirmStatus(GetFileInformationByHandle(hSearchHandle, &obGetFileInfoData));
  630. FindClose(hSearchHandle);
  631. hSearchHandle = INVALID_HANDLE_VALUE;
  632. // At time of this writing CreateTime for root dir is bogus. (bills 10/20/98).
  633. WsbTrace(OLESTR("Create Time = <%ls>\n"), WsbFiletimeAsString(FALSE, obGetFileInfoData.ftCreationTime));
  634. WsbTrace(OLESTR("Last Access Time = <%ls>\n"), WsbFiletimeAsString(FALSE, obGetFileInfoData.ftLastAccessTime));
  635. WsbTrace(OLESTR("Last Write Time = <%ls>\n"), WsbFiletimeAsString(FALSE, obGetFileInfoData.ftLastWriteTime));
  636. // copy info from GetFileInformationByHandle call (BY_HANDLE_FILE_INFORMATION struct)
  637. // .. into obFindData (WIN32_FIND_DATAW struct) for DoDirectoryDblk call.
  638. memset(&obFindData, 0, sizeof(WIN32_FIND_DATAW));
  639. obFindData.dwFileAttributes = obGetFileInfoData.dwFileAttributes;
  640. obFindData.ftCreationTime = obGetFileInfoData.ftCreationTime;
  641. obFindData.ftLastAccessTime = obGetFileInfoData.ftLastAccessTime;
  642. obFindData.ftLastWriteTime = obGetFileInfoData.ftLastWriteTime;
  643. WsbAffirmHr(DoDirectoryDblk(nameSpace, &obFindData));
  644. // Now do the same for each succeeding directory in the path using strtok
  645. token = wcstok(0, OLESTR("\\")); // pop off first subdir
  646. for ( ; token; token = wcstok(0, OLESTR("\\"))) {
  647. nameSpace.Append(token);
  648. path = nameSpace;
  649. path.Prepend(OLESTR("\\\\?\\"));
  650. WsbAssertHandle(hSearchHandle = FindFirstFileEx((WCHAR *) path, FindExInfoStandard, &obFindData, FindExSearchLimitToDirectories, 0, additionalSearchFlags));
  651. if ( obFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  652. nameSpace.Append(OLESTR("\\")); // add in \ to dir
  653. WsbAffirmHr(DoDirectoryDblk((WCHAR *) nameSpace, &obFindData));
  654. }
  655. FindClose(hSearchHandle);
  656. hSearchHandle = INVALID_HANDLE_VALUE;
  657. }
  658. nameSpace.TakeFrom(szDirs, 0); // cleanup
  659. } WsbCatch(hr);
  660. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  661. FindClose(hSearchHandle);
  662. }
  663. WsbTraceOut(OLESTR("CMTFSession::DoParentDirectories"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  664. return hr;
  665. }
  666. HRESULT
  667. CMTFSession::DoDataSet(
  668. IN WCHAR *szPath)
  669. /*++
  670. Routine Description:
  671. Recurses through all the items contained in the directory
  672. specified by path and backs them up calling DoFileDblk and
  673. DoDirectoryDblk
  674. Arguments:
  675. szPath - Full pathname of directory.
  676. Return Value:
  677. S_OK - Success.
  678. MVR_E_NOT_FOUND - Object not found.
  679. --*/
  680. {
  681. HRESULT hr = MVR_E_NOT_FOUND;
  682. WsbTraceIn(OLESTR("CMTFSession::DoDataSet"), OLESTR("<%ls>"), WsbAbbreviatePath(szPath, 120));
  683. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  684. try {
  685. MvrInjectError(L"Inject.CMTFSession::DoDataSet.0");
  686. WsbAssertPointer( szPath );
  687. WIN32_FIND_DATAW obFindData;
  688. BOOL bMoreFiles;
  689. CWsbStringPtr nameSpace;
  690. CWsbStringPtr pathname;
  691. // check if the specification is for file(s): nameSpace = c:\dir\test*.* or c:\dir\test1.tst
  692. nameSpace = szPath;
  693. WsbAffirmHr(nameSpace.Prepend(OLESTR("\\\\?\\")));
  694. DWORD additionalSearchFlags = 0;
  695. additionalSearchFlags |= (m_bUseCaseSensitiveSearch) ? FIND_FIRST_EX_CASE_SENSITIVE : 0;
  696. WsbAssertHandle(hSearchHandle = FindFirstFileEx((WCHAR *) nameSpace, FindExInfoStandard, &obFindData, FindExSearchNameMatch, 0, additionalSearchFlags));
  697. for (bMoreFiles = TRUE;
  698. hSearchHandle != INVALID_HANDLE_VALUE && bMoreFiles;
  699. bMoreFiles = FindNextFileW(hSearchHandle, &obFindData)) {
  700. // Skip all directories
  701. if ((obFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { // Not a dir
  702. CWsbStringPtr path;
  703. WCHAR *end;
  704. LONG numChar;
  705. // use the szPath to get the pathname, then append the filename
  706. pathname = szPath;
  707. WsbAffirm(0 != (WCHAR *)pathname, E_OUTOFMEMORY);
  708. end = wcsrchr((WCHAR *)pathname, L'\\');
  709. WsbAssert(end != NULL, MVR_E_INVALIDARG);
  710. numChar = (LONG)(end - (WCHAR *)pathname + 1);
  711. WsbAssert(numChar > 0, E_UNEXPECTED);
  712. WsbAffirmHr(path.Alloc(numChar + MAX_PATH));
  713. wcsncpy((WCHAR *)path, (WCHAR *)pathname, numChar);
  714. ((WCHAR *)path)[numChar] = L'\0';
  715. path.Append(obFindData.cFileName);
  716. WsbAffirmHr(hr = DoFileDblk((WCHAR *)path, &obFindData));
  717. }
  718. }
  719. // close search handle after processing all the files
  720. FindClose(hSearchHandle);
  721. hSearchHandle = INVALID_HANDLE_VALUE;
  722. // process all files for this directory: nameSpace = c:\dir
  723. nameSpace = szPath;
  724. nameSpace.Append(OLESTR("\\*.*"));
  725. nameSpace.Prepend(OLESTR("\\\\?\\"));
  726. hSearchHandle = FindFirstFileEx((WCHAR *) nameSpace, FindExInfoStandard, &obFindData, FindExSearchNameMatch, 0, additionalSearchFlags);
  727. for (bMoreFiles = TRUE;
  728. hSearchHandle != INVALID_HANDLE_VALUE && bMoreFiles;
  729. bMoreFiles = FindNextFileW(hSearchHandle, &obFindData)) {
  730. if ((obFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  731. // use the szPath to get the pathname, then append the filename
  732. pathname = szPath;
  733. pathname.Append(OLESTR("\\"));
  734. pathname.Append(obFindData.cFileName);
  735. WsbAffirmHr(hr = DoFileDblk((WCHAR *)pathname, &obFindData));
  736. }
  737. }
  738. // close search handle after processing all the files
  739. FindClose(hSearchHandle);
  740. hSearchHandle = INVALID_HANDLE_VALUE;
  741. // process all directories in this directory: nameSpace = c:\dir
  742. nameSpace = szPath;
  743. nameSpace.Append(OLESTR("\\*.*"));
  744. nameSpace.Prepend(OLESTR("\\\\?\\"));
  745. hSearchHandle = FindFirstFileEx((WCHAR *) nameSpace, FindExInfoStandard, &obFindData, FindExSearchNameMatch, 0, additionalSearchFlags);
  746. for (bMoreFiles = TRUE;
  747. hSearchHandle != INVALID_HANDLE_VALUE && bMoreFiles;
  748. bMoreFiles = FindNextFileW(hSearchHandle, &obFindData)) {
  749. // Recursively handle any directories other than . and ..
  750. if (((obFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) &&
  751. (wcscmp(obFindData.cFileName, OLESTR(".")) != 0) &&
  752. (wcscmp(obFindData.cFileName, OLESTR("..")) != 0)) {
  753. // append the directory name to pathname
  754. pathname = szPath;
  755. pathname.Append(OLESTR("\\"));
  756. pathname.Append(obFindData.cFileName);
  757. pathname.Append(OLESTR("\\"));
  758. WsbAffirmHr(hr = DoDirectoryDblk((WCHAR *) pathname, &obFindData));
  759. // append the directory name to pathname and process
  760. pathname = szPath;
  761. pathname.Append(OLESTR("\\"));
  762. pathname.Append(obFindData.cFileName);
  763. WsbAffirmHr(DoDataSet((WCHAR *) pathname));
  764. }
  765. }
  766. } WsbCatch(hr);
  767. // close search handle after processing all the directories
  768. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  769. FindClose(hSearchHandle);
  770. }
  771. WsbTraceOut(OLESTR("CMTFSession::DoDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  772. return hr;
  773. }
  774. HRESULT
  775. CMTFSession::DoDirectoryDblk(
  776. IN WCHAR *szPath,
  777. IN WIN32_FIND_DATAW *pFindData)
  778. /*++
  779. Routine Description:
  780. Writes out a DIRB DBLK and calls DoStream to write out
  781. associated stream data.
  782. Arguments:
  783. szPath - Full pathname of directory.
  784. pFindData - WIN32 information about the directiory.
  785. Return Value:
  786. S_OK - Success.
  787. Note:
  788. In order for both stickyName and driveLetter-colon path formats to work properly, both with and
  789. without writing separate DIRBs for the parent directories,
  790. THE EXISTENCE AND PLACEMENT OF THE PATH MANIPULATION CODE (APPEND/PREPEND, ETC.) IS CRUCIAL!!!
  791. --*/
  792. {
  793. HRESULT hr = S_OK;
  794. WsbTraceIn(OLESTR("CMTFSession::DoDirectoryDblk"), OLESTR(""));
  795. HANDLE hStream = INVALID_HANDLE_VALUE;
  796. try {
  797. MvrInjectError(L"Inject.CMTFSession::DoDirectoryDblk.0");
  798. WsbAssertPointer(m_pBuffer);
  799. WsbAssertPointer(szPath);
  800. MTF_DBLK_DIRB_INFO sDIRB; // **MTF API STRUCT ** -- info for DIRB
  801. PWCHAR pSlash;
  802. size_t nMoreBufUsed;
  803. WCHAR *end;
  804. WsbAssert(m_nBlockSize > 0, MVR_E_LOGIC_ERROR);
  805. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  806. // It won't be if we are having problems writing to tape.
  807. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  808. WsbAffirm(0 == (m_nBufUsed % uAlignmentFactor), E_ABORT);
  809. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  810. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  811. WsbTrace(OLESTR("%ls (DIRB) @ FLA %I64u (%I64u, %I64u)\n"), WsbAbbreviatePath(szPath, 120),
  812. fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  813. CWsbStringPtr path = szPath;
  814. // tack on trailing backslash if not already there
  815. end = wcsrchr((WCHAR *)path, L'\0');
  816. WsbAssert(end != NULL, MVR_E_INVALIDARG); // Something went wrong!
  817. if(*(end-1) != L'\\') {
  818. path.Append(OLESTR("\\"));
  819. }
  820. // Get a handle to the directory. If this fails we need to skip everything else.
  821. WsbAffirmHr(OpenStream(path, &hStream));
  822. // **MTF API CALL**
  823. // automatically fill in the MTF_DIRB_DBLK_INFO structure using
  824. // information in the pFindData structure
  825. //
  826. // if we are getting something in the form of "C:\",
  827. // then we want to send the name along as just "\"
  828. // otherwise
  829. // we want to send the full path, but omit the volume ("C:\")
  830. // thus the "+3"
  831. pSlash = wcschr(path, L'\\');
  832. WsbAssert(pSlash != NULL, MVR_E_INVALIDARG); // Something went wrong!
  833. pSlash++; // Look for the second one
  834. pSlash = wcschr(pSlash, L'\\');
  835. if (NULL == pSlash) {
  836. // It's just the volume name and nothing more
  837. m_pMTFApi->MTF_SetDIRBFromFindData(&sDIRB, OLESTR("\\"), pFindData);
  838. }
  839. else {
  840. pSlash = wcschr(path, L'\\'); // point to first backslash (beginning of path)
  841. m_pMTFApi->MTF_SetDIRBFromFindData(&sDIRB, pSlash + 1, pFindData);
  842. }
  843. // Check if we need to set the Backup Date field for the DIRB
  844. if (m_sSetInfo.uSSETAttributes & MTF_SSET_NORMAL) {
  845. time_t tTime;
  846. time(&tTime);
  847. sDIRB.sBackupDate = m_pMTFApi->MTF_CreateDateTimeFromTM(gmtime(&tTime));
  848. }
  849. // make sure to mark and update the directory id as well as the
  850. // control block id and alignment is already correct
  851. sDIRB.uDirectoryId = ++m_nDirectoryId;
  852. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  853. m_sHeaderInfo.uFormatLogicalAddress = fla;
  854. // Add in OS Specific data
  855. MTF_DIRB_OS_NT_0 sOSNT;
  856. switch ( m_sHeaderInfo.uOSID ) {
  857. case MTF_OSID_NT:
  858. sOSNT.uDirectoryAttributes = sDIRB.uDirectoryAttributes;
  859. m_sHeaderInfo.pvOSData = &sOSNT;
  860. m_sHeaderInfo.uOSDataSize = sizeof(sOSNT);
  861. break;
  862. default:
  863. break;
  864. }
  865. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  866. // **MTF API CALL**
  867. // provide the MTF_DBLK_HDR_INFO and MTF_DBLK_DIRB_INFO structs
  868. // to this function. The result is an MTF formatted DIRB DBLK in
  869. // m_pBuffer.
  870. nMoreBufUsed = 0;
  871. WsbAssertNoError(m_pMTFApi->MTF_WriteDIRBDblk(&m_sHeaderInfo, &sDIRB, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  872. m_nBufUsed += nMoreBufUsed;
  873. // **MTF API CALL**
  874. // output the name stream, if required.
  875. if ( sDIRB.uDirectoryAttributes & MTF_DIRB_PATH_IN_STREAM ) {
  876. nMoreBufUsed = 0;
  877. if ( m_sVolInfo.uVolumeAttributes & MTF_VOLB_DEV_DRIVE ) {
  878. WsbAssertNoError(m_pMTFApi->MTF_WriteNameStream(MTF_PATH_NAME_STREAM, szPath + 3, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  879. m_nBufUsed += nMoreBufUsed;
  880. }
  881. else if ( m_sVolInfo.uVolumeAttributes & MTF_VOLB_DEV_OS_SPEC ) {
  882. if ( 0 == _wcsnicmp( m_sVolInfo.szDeviceName, OLESTR("Volume{"), 7 )) {
  883. WsbAssertNoError(m_pMTFApi->MTF_WriteNameStream(MTF_PATH_NAME_STREAM, szPath + 45, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  884. m_nBufUsed += nMoreBufUsed;
  885. }
  886. else {
  887. // unrecognized operating system specific format
  888. WsbThrow(MVR_E_INVALIDARG);
  889. }
  890. }
  891. else {
  892. // UNC path - unsupported
  893. WsbThrow(MVR_E_INVALIDARG);
  894. }
  895. }
  896. // Now, instead of padding this out, we call this funciton to write
  897. // out the stream which will write out the current contents of the
  898. // buffer as well. When this call returns, the current contents of
  899. // the buffer as well as the associated data stream will have been
  900. // written to media.
  901. // Note: Data may still remain in the device buffer, or the
  902. // local m_pBuffer if the file doesn't pad to a block
  903. // boundary, and the device buffer is not flushed.
  904. WsbAffirmHr(DoDataStream(hStream));
  905. } WsbCatch(hr);
  906. if (INVALID_HANDLE_VALUE != hStream) {
  907. CloseStream(hStream);
  908. hStream = INVALID_HANDLE_VALUE;
  909. }
  910. WsbTraceOut(OLESTR("CMTFSession::DoDirectoryDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  911. return hr;
  912. }
  913. HRESULT
  914. CMTFSession::DoFileDblk(
  915. IN WCHAR *szPath,
  916. IN WIN32_FIND_DATAW *pFindData)
  917. /*++
  918. Routine Description:
  919. Writes out a FILE DBLK and calls DoStream to write out
  920. associated stream data
  921. Arguments:
  922. szPath - Full pathname of file.
  923. pFindData - WIN32 information about the file.
  924. Return Value:
  925. S_OK - Success.
  926. --*/
  927. {
  928. HRESULT hr = S_OK;
  929. WsbTraceIn(OLESTR("CMTFSession::DoFileDblk"), OLESTR(""));
  930. HANDLE hStream = INVALID_HANDLE_VALUE;
  931. try {
  932. MvrInjectError(L"Inject.CMTFSession::DoFileDblk.0");
  933. WsbAssertPointer(m_pBuffer);
  934. WsbAssertPointer(szPath);
  935. MTF_DBLK_FILE_INFO sFILE; // **MTF API STRUCT ** -- info for FILE
  936. size_t nMoreBufUsed;
  937. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  938. WsbAssert(m_nBlockSize > 0, MVR_E_LOGIC_ERROR);
  939. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  940. // It won't be if we are having problems writing to tape.
  941. WsbAffirm(0 == (m_nBufUsed % uAlignmentFactor), E_ABORT);
  942. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  943. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  944. WsbTrace(OLESTR("%ls (FILE) @ FLA %I64u (%I64u, %I64u)\n"), WsbAbbreviatePath(szPath, 120),
  945. fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  946. // Get a handle to the directory. If this fails we need to skip everything else.
  947. WsbAffirmHr(OpenStream(szPath, &hStream));
  948. // Initialize the hints set for each file.
  949. m_sHints.FileStart.QuadPart = fla * uAlignmentFactor;
  950. m_sHints.FileSize.QuadPart = 0;
  951. m_sHints.DataStart.QuadPart = 0;
  952. m_sHints.DataSize.QuadPart = 0;
  953. m_sHints.VerificationType = MVR_VERIFICATION_TYPE_NONE;
  954. m_sHints.VerificationData.QuadPart = 0;
  955. m_sHints.DatastreamCRCType = WSB_CRC_CALC_NONE;
  956. m_sHints.DatastreamCRC.QuadPart = 0;
  957. m_sHints.FileUSN.QuadPart = 0;
  958. if (m_bUseFlatFileStructure) {
  959. // For HSM we rename the file to it's logical address
  960. swprintf( pFindData->cFileName, L"%08x", fla );
  961. }
  962. // **MTF API CALL**
  963. // automatically fill in the MTF_FILE_DBLK_INFO structure using
  964. // information in the pFindData structure
  965. m_pMTFApi->MTF_SetFILEFromFindData(&sFILE, pFindData);
  966. // Check if we need to set the Backup Date field for the FILE DBLK
  967. if ((m_sSetInfo.uSSETAttributes & MTF_SSET_NORMAL)
  968. |(m_sSetInfo.uSSETAttributes & MTF_SSET_DIFFERENTIAL)
  969. |(m_sSetInfo.uSSETAttributes & MTF_SSET_INCREMENTAL)
  970. |(m_sSetInfo.uSSETAttributes & MTF_SSET_DAILY)){
  971. time_t tTime;
  972. time(&tTime);
  973. sFILE.sBackupDate = m_pMTFApi->MTF_CreateDateTimeFromTM(gmtime(&tTime));
  974. }
  975. // make sure to mark and update the file id as well as the control
  976. // block id and alignment is already correct
  977. sFILE.uDirectoryId = m_nDirectoryId;
  978. sFILE.uFileId = ++m_nFileId;
  979. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  980. m_sHeaderInfo.uFormatLogicalAddress = fla;
  981. // Add in OS Specific data
  982. MTF_FILE_OS_NT_0 sOSNT;
  983. switch ( m_sHeaderInfo.uOSID ) {
  984. case MTF_OSID_NT:
  985. sOSNT.uFileAttributes = sFILE.uFileAttributes;
  986. sOSNT.uShortNameOffset = 0;
  987. sOSNT.uShortNameSize = 0;
  988. sOSNT.lLink = 0;
  989. sOSNT.uReserved = 0;
  990. m_sHeaderInfo.pvOSData = &sOSNT;
  991. m_sHeaderInfo.uOSDataSize = sizeof(sOSNT);
  992. break;
  993. default:
  994. break;
  995. }
  996. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  997. // **MTF API CALL**
  998. // Provide the MTF_DBLK_HDR_INFO and MTF_DBLK_FILE_INFO structs
  999. // to this function. The result is an MTF formatted FILE DBLK in
  1000. // m_pBuffer.
  1001. nMoreBufUsed = 0;
  1002. WsbAssertNoError(m_pMTFApi->MTF_WriteFILEDblk(&m_sHeaderInfo, &sFILE, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  1003. m_nBufUsed += nMoreBufUsed;
  1004. // Like the directory, instead of padding this out, we call this
  1005. // funciton to write out the stream which will write out the current
  1006. // contents of the buffer as well. When this call returns, the
  1007. // current contents of the buffer as well as the associated data
  1008. // stream will have been written to media.
  1009. // Note: Data may still remain in the device buffer, or the
  1010. // local m_pBuffer if the file doesn't pad to a block
  1011. // boundary, and the device buffer is not flushed.
  1012. hr = DoDataStream(hStream);
  1013. if ( hr != S_OK) {
  1014. // unable to copy the file to target media.
  1015. WsbTraceAlways( OLESTR("Unable to store file %ls. reason = %s\n"), WsbAbbreviatePath(szPath, 120), WsbHrAsString(hr));
  1016. WsbThrow(hr);
  1017. }
  1018. else {
  1019. // Make sure we are alinged with a FLA (i.e. the last stream was properly padded).
  1020. WsbAssert(0 == (m_nBufUsed % uAlignmentFactor), MVR_E_LOGIC_ERROR);
  1021. m_sHints.FileSize.QuadPart =
  1022. m_nFormatLogicalAddress * uAlignmentFactor + m_nBufUsed - m_sHints.FileStart.QuadPart;
  1023. }
  1024. } WsbCatch(hr);
  1025. if (INVALID_HANDLE_VALUE != hStream) {
  1026. CloseStream(hStream);
  1027. hStream = INVALID_HANDLE_VALUE;
  1028. }
  1029. WsbTraceOut(OLESTR("CMTFSession::DoFileDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1030. return hr;
  1031. }
  1032. HRESULT
  1033. CMTFSession::OpenStream(
  1034. IN WCHAR *szPath,
  1035. OUT HANDLE *pStreamHandle)
  1036. /*++
  1037. Routine Description:
  1038. Opens the file to backup in "backup read" mode, and returns
  1039. stream handle for the file specified.
  1040. Arguments:
  1041. szPath - Full pathname of file.
  1042. hStream - Returned stream handle.
  1043. Return Value:
  1044. S_OK - Success.
  1045. --*/
  1046. {
  1047. HRESULT hr = S_OK;
  1048. WsbTraceIn(OLESTR("CMTFSession::OpenStream"), OLESTR("<%ls>"), WsbAbbreviatePath(szPath, 120));
  1049. HANDLE hStream = INVALID_HANDLE_VALUE;
  1050. try {
  1051. MvrInjectError(L"Inject.CMTFSession::OpenStream.0");
  1052. WsbAssertPointer(szPath);
  1053. WsbAssertPointer(pStreamHandle);
  1054. *pStreamHandle = INVALID_HANDLE_VALUE;
  1055. FILE_BASIC_INFORMATION basicInformation;
  1056. IO_STATUS_BLOCK IoStatusBlock;
  1057. NTSTATUS ccode;
  1058. // ** WIN32 File API Call - open the file for backup read. This can be more involved if
  1059. // the app needs to be run by someone without the proper authority to
  1060. // backup certain files....
  1061. // We also ask for GENERIC_WRITE so we can set the attributes to prevent the
  1062. // modification of dates.
  1063. DWORD posixFlag = (m_bUseCaseSensitiveSearch) ? FILE_FLAG_POSIX_SEMANTICS : 0;
  1064. CWsbStringPtr name = szPath;
  1065. WsbAffirmHr(name.Prepend(OLESTR("\\\\?\\")));
  1066. WsbAffirm(0 != (WCHAR *)name, E_OUTOFMEMORY);
  1067. WsbAffirmHandle(hStream = CreateFileW((WCHAR *) name,
  1068. GENERIC_READ | FILE_WRITE_ATTRIBUTES,
  1069. FILE_SHARE_READ,
  1070. NULL,
  1071. OPEN_EXISTING,
  1072. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | posixFlag,
  1073. NULL));
  1074. //
  1075. // Prevent modification of file dates
  1076. //
  1077. // ** NT System Call - query for file information
  1078. WsbAffirmNtStatus(NtQueryInformationFile(hStream, &IoStatusBlock, (PVOID)&basicInformation,
  1079. sizeof( basicInformation ), FileBasicInformation));
  1080. m_SaveBasicInformation = basicInformation;
  1081. basicInformation.CreationTime.QuadPart = -1;
  1082. basicInformation.LastAccessTime.QuadPart = -1;
  1083. basicInformation.LastWriteTime.QuadPart = -1;
  1084. basicInformation.ChangeTime.QuadPart = -1;
  1085. // ** NT System Call - set file information
  1086. WsbAffirmNtStatus(ccode = NtSetInformationFile( hStream, &IoStatusBlock, (PVOID)&basicInformation,
  1087. sizeof( basicInformation ), FileBasicInformation));
  1088. if (pStreamHandle) {
  1089. *pStreamHandle = hStream;
  1090. }
  1091. } WsbCatchAndDo(hr,
  1092. if (INVALID_HANDLE_VALUE != hStream) {
  1093. CloseHandle( hStream );
  1094. hStream = INVALID_HANDLE_VALUE;
  1095. }
  1096. );
  1097. WsbTraceOut(OLESTR("CMTFSession::OpenStream"), OLESTR("hr = <%ls>, handle = <0x%08x>"), WsbHrAsString(hr), hStream);
  1098. return hr;
  1099. }
  1100. HRESULT
  1101. CMTFSession::CloseStream(
  1102. IN HANDLE hStream)
  1103. /*++
  1104. Routine Description:
  1105. Close stream handle and performs cleanup.
  1106. Arguments:
  1107. hStream - Stream handle to close
  1108. Return Value:
  1109. S_OK - Success.
  1110. --*/
  1111. {
  1112. HRESULT hr = S_OK;
  1113. WsbTraceIn(OLESTR("CMTFSession::CloseStream"), OLESTR("<0x%08x>"), hStream);
  1114. try {
  1115. if (INVALID_HANDLE_VALUE != hStream) {
  1116. //
  1117. // Cleanup from a partial backup read. We're setting bAbort=TRUE
  1118. // to free resources used by BackupRead()
  1119. //
  1120. if (m_pvReadContext) {
  1121. (void) BackupRead(hStream, NULL, 0, NULL, TRUE, FALSE, &m_pvReadContext);
  1122. m_pvReadContext = NULL;
  1123. }
  1124. (void) CloseHandle( hStream );
  1125. hStream = INVALID_HANDLE_VALUE;
  1126. }
  1127. } WsbCatch(hr);
  1128. WsbTraceOut(OLESTR("CMTFSession::CloseStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1129. return hr;
  1130. }
  1131. HRESULT
  1132. CMTFSession::DoDataStream(
  1133. IN HANDLE hStream)
  1134. /*++
  1135. Routine Description:
  1136. Uses WIN32 BackupRead to read streams associated with a file
  1137. and then write them out to the data set. BackupRead opens a
  1138. file and successively reads data streams from that file.
  1139. Each data stream is preceeded by a WIN32_STREAM_ID struct.
  1140. Arguments:
  1141. hStream - File handle.
  1142. Return Value:
  1143. S_OK - Success.
  1144. Algorithm:
  1145. - with buffer, current_buf_position do:
  1146. - while there are more streams loop
  1147. - read next stream header using BackupRead
  1148. - exit loop when no next stream
  1149. - use stream header to append format MTF STREAM HEADER to buffer
  1150. - flush as much of buffer as possible to the data set.
  1151. - while entire stream not read loop
  1152. - read as much of current stream as possible into remainder
  1153. of buffer
  1154. - flush as much of buffer as possible to the data set.
  1155. - end loop this stream not read
  1156. - end loop more streams
  1157. - flush as much of the buffer to the data set
  1158. - pad buffer out to next alignment factor
  1159. - flush as much of the buffer to the data set
  1160. --*/
  1161. {
  1162. HRESULT hr = S_OK;
  1163. WsbTraceIn(OLESTR("CMTFSession::DoDataStream"), OLESTR("<0x%08x>"), hStream);
  1164. try {
  1165. MvrInjectError(L"Inject.CMTFSession::DoDataStream.0");
  1166. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1167. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  1168. WsbTrace(OLESTR("CMTFSession::DoDataStream - Start: FLA = %I64u\n"), fla);
  1169. WIN32_STREAM_ID sStreamHeader; // comes back from Win32 BackupRead
  1170. ULONG nThisRead; // number of bytes to read
  1171. ULONG nBytesRead; // number of bytes read
  1172. UINT64 nStreamBytesToRead; // total number bytes that we need to read
  1173. UINT64 nStreamBytesRead; // total number bytes that have been read
  1174. USHORT nStreamCount = 0; // current stream number
  1175. MTF_STREAM_INFO sSTREAM;
  1176. size_t nMoreBufUsed;
  1177. BOOL bReadStatus = FALSE;
  1178. // Prepare to calculate the CRC for the unnamed datastream
  1179. BYTE* pCurrent;
  1180. BYTE* pStart;
  1181. ULONG datastreamCRC;
  1182. BOOL doDatastreamCRC;
  1183. memset(&sStreamHeader, 0, sizeof(WIN32_STREAM_ID));
  1184. INITIALIZE_CRC(datastreamCRC);
  1185. WsbTrace(OLESTR("CMTFSession::DoDataStream initialzed CRC is <%lu> for <0x%08x>\n"),
  1186. datastreamCRC, hStream);
  1187. m_sHints.DatastreamCRCType = WSB_CRC_CALC_NONE;
  1188. WsbTrace(OLESTR("CMTFSession::DoDataStream - Start While\n"));
  1189. while(1) {
  1190. // We want to do a CRC on the unnamed datastream
  1191. doDatastreamCRC = FALSE;
  1192. nBytesRead = 0;
  1193. try {
  1194. MvrInjectError(L"Inject.CMTFSession::DoDataStream.BackupRead.1.0");
  1195. // ** WIN32 File API Call - Backup read returns the file as a sequence of streams each
  1196. // preceed by a WIN32_STREAM_ID struct. Note that this structure is a
  1197. // variable size -- depending on the length of the name of the stream.
  1198. // In any case, we are guaranteed at least 20 bytes of it
  1199. // (WIN32_STREAM_ID_SIZE)
  1200. nStreamCount++;
  1201. WsbAffirmStatus(BackupRead(hStream,
  1202. (BYTE *) &sStreamHeader,
  1203. WIN32_STREAM_ID_SIZE,
  1204. &nBytesRead,
  1205. FALSE,
  1206. TRUE,
  1207. &m_pvReadContext));
  1208. MvrInjectError(L"Inject.CMTFSession::DoDataStream.BackupRead.1.1");
  1209. } catch (HRESULT catchHr) {
  1210. //
  1211. // CORRUPT FILE PROCESSING for stream header
  1212. //
  1213. hr = catchHr;
  1214. WsbLogEvent(MVR_E_ERROR_IO_DEVICE, 0, NULL, WsbHrAsString(hr), NULL);
  1215. // Write SPAD
  1216. WsbAffirmHr(PadToNextFLA(TRUE));
  1217. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  1218. // It won't be if we are having problems writing to tape.
  1219. WsbAssert(0 == (m_nBufUsed % uAlignmentFactor), MVR_E_LOGIC_ERROR);
  1220. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  1221. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  1222. WsbTrace(OLESTR("%ls (CFIL) @ FLA %I64u (%I64u, %I64u)\n"), fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  1223. // Write a corrupt file (CFIL) DBLK
  1224. MTF_DBLK_CFIL_INFO sCFILInfo;
  1225. m_pMTFApi->MTF_SetCFILDefaults( &sCFILInfo );
  1226. sCFILInfo.uCorruptStreamNumber = nStreamCount;
  1227. sCFILInfo.uStreamOffset = 0;
  1228. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  1229. m_sHeaderInfo.uFormatLogicalAddress = fla;
  1230. WsbAssertNoError(m_pMTFApi->MTF_WriteCFILDblk(&m_sHeaderInfo, &sCFILInfo, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  1231. m_nBufUsed += nMoreBufUsed;
  1232. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1233. WsbThrow(hr);
  1234. };
  1235. if (nBytesRead < WIN32_STREAM_ID_SIZE)
  1236. break;
  1237. // **MTF API CALL**
  1238. // now use the info in the stream header to fill in an mtf stream
  1239. // header using the mtf call then write the resulting info to the
  1240. // buffer.
  1241. // BMD Note: special conditional code added on third arg for named data streams
  1242. m_pMTFApi->MTF_SetSTREAMFromStreamId( &sSTREAM,
  1243. &sStreamHeader,
  1244. (sStreamHeader.dwStreamNameSize) ? sStreamHeader.dwStreamNameSize + 4 : 0 );
  1245. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1246. // **MTF API CALL**
  1247. // Write out the stream header.
  1248. nMoreBufUsed = 0;
  1249. WsbAssertNoError(m_pMTFApi->MTF_WriteStreamHeader(&sSTREAM, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  1250. m_nBufUsed += nMoreBufUsed;
  1251. // BMD Note: we need to put the size of the stream name in the MTF stream
  1252. // right after the header. We'll write the name itself as part of the stream.
  1253. //
  1254. // ?? Should this be in MTF_WriteStreamHeader ??
  1255. if ( sStreamHeader.dwStreamNameSize ) {
  1256. *(DWORD UNALIGNED *)(m_pBuffer + m_nBufUsed) = sStreamHeader.dwStreamNameSize;
  1257. m_nBufUsed += sizeof( DWORD );
  1258. }
  1259. // Save away the "STAN" stream start byte address, and size.
  1260. // This is the one we recall.
  1261. if ( 0 == memcmp( sSTREAM.acStreamId, "STAN", 4 ) ) {
  1262. // This is an unnamed data stream, so there's no stream name.
  1263. m_sHints.VerificationData.QuadPart = sSTREAM.uCheckSum;
  1264. m_sHints.VerificationType = MVR_VERIFICATION_TYPE_HEADER_CRC;
  1265. m_sHints.DataStart.QuadPart = m_nFormatLogicalAddress * uAlignmentFactor + m_nBufUsed - m_sHints.FileStart.QuadPart;
  1266. m_sHints.DataSize.QuadPart = sSTREAM.uStreamLength;
  1267. doDatastreamCRC = TRUE;
  1268. m_sHints.DatastreamCRCType = WSB_CRC_CALC_MICROSOFT_32;
  1269. }
  1270. // the above stream should always fit...
  1271. WsbAssert(m_nBufUsed < m_nBufSize, MVR_E_LOGIC_ERROR);
  1272. // try to flush as many BLOCK SIZE chunks out of the buffer as possible
  1273. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1274. // now, while there is more data in the stream, read the rest of
  1275. // the stream, or how ever much will fit into the buffer
  1276. nStreamBytesToRead = m_pMTFApi->MTF_CreateUINT64(sStreamHeader.Size.LowPart, sStreamHeader.Size.HighPart)
  1277. + sStreamHeader.dwStreamNameSize;
  1278. nStreamBytesRead = 0;
  1279. WsbTrace(OLESTR("CMTFSession::DoDataStream - Start Do\n"));
  1280. do
  1281. {
  1282. nThisRead = 0;
  1283. // we read as many bytes as will fit into our buffer, up to
  1284. // the end of the stream min doesn't work well here...
  1285. if (nStreamBytesToRead < (m_nBufSize - m_nBufUsed))
  1286. nThisRead = (ULONG) nStreamBytesToRead;
  1287. else
  1288. nThisRead = (ULONG)(m_nBufSize - m_nBufUsed);
  1289. try {
  1290. MvrInjectError(L"Inject.CMTFSession::DoDataStream.BackupRead.2.0");
  1291. // ** WIN32 File API Call - read nThisRead bytes, bail out if the read failed or
  1292. // no bytes were read (assume done)
  1293. bReadStatus = FALSE;
  1294. bReadStatus = BackupRead(hStream,
  1295. m_pBuffer + m_nBufUsed,
  1296. nThisRead,
  1297. &nBytesRead,
  1298. FALSE,
  1299. TRUE,
  1300. &m_pvReadContext);
  1301. nStreamBytesRead += nBytesRead;
  1302. WsbAffirmStatus(bReadStatus);
  1303. MvrInjectError(L"Inject.CMTFSession::DoDataStream.BackupRead.2.1");
  1304. } catch (HRESULT catchHr) {
  1305. //
  1306. // CORRUPT FILE PROCESSING for stream data
  1307. //
  1308. hr = catchHr;
  1309. WsbLogEvent(MVR_E_ERROR_IO_DEVICE, 0, NULL, WsbHrAsString(hr), NULL);
  1310. // Go to the last good byte
  1311. m_nBufUsed += nBytesRead;
  1312. // Pad to fill up size of file
  1313. while( nStreamBytesRead < nStreamBytesToRead ) {
  1314. for( ; (m_nBufUsed < m_nBufSize) && (nStreamBytesRead < nStreamBytesToRead); ++m_nBufUsed, ++nStreamBytesRead ) {
  1315. m_pBuffer[m_nBufUsed] = 0;
  1316. }
  1317. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1318. }
  1319. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1320. // Align on 4-byte boundary
  1321. for( ; m_nBufUsed % 4; ++m_nBufUsed ){
  1322. m_pBuffer[m_nBufUsed] = 0;
  1323. }
  1324. // Write SPAD
  1325. WsbAffirmHr(PadToNextFLA(TRUE));
  1326. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  1327. // It won't be if we are having problems writing to tape.
  1328. WsbAssert(0 == (m_nBufUsed % uAlignmentFactor), MVR_E_LOGIC_ERROR);
  1329. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  1330. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  1331. WsbTrace(OLESTR("%ls (CFIL) @ FLA %I64u (%I64u, %I64u)\n"), fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  1332. // Write a corrupt file (CFIL) DBLK
  1333. MTF_DBLK_CFIL_INFO sCFILInfo;
  1334. m_pMTFApi->MTF_SetCFILDefaults( &sCFILInfo );
  1335. sCFILInfo.uCorruptStreamNumber = nStreamCount;
  1336. sCFILInfo.uStreamOffset = nStreamBytesRead;
  1337. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  1338. m_sHeaderInfo.uFormatLogicalAddress = fla;
  1339. WsbAssertNoError(m_pMTFApi->MTF_WriteCFILDblk(&m_sHeaderInfo, &sCFILInfo, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  1340. m_nBufUsed += nMoreBufUsed;
  1341. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1342. WsbThrow(hr);
  1343. };
  1344. if (nBytesRead == 0)
  1345. break;
  1346. nStreamBytesToRead -= nBytesRead;
  1347. pStart = m_pBuffer + m_nBufUsed;
  1348. m_nBufUsed += nBytesRead;
  1349. HRESULT hrCRC = S_OK;
  1350. if (TRUE == doDatastreamCRC ) {
  1351. for (pCurrent = pStart; (pCurrent < (pStart + nBytesRead)) && (S_OK == hr); pCurrent++) {
  1352. hrCRC = WsbCRCReadFile(pCurrent, &datastreamCRC);
  1353. if (S_OK != hrCRC) {
  1354. WsbThrow(MVR_E_CANT_CALC_DATASTREAM_CRC);
  1355. }
  1356. }
  1357. }
  1358. // At this point we've got stuff in the buffer that might need
  1359. // to be flushed so, try to do that
  1360. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1361. } while (nStreamBytesToRead > 0);
  1362. WsbTrace(OLESTR("CMTFSession::DoDataStream - End Do\n"));
  1363. // Okay. At this point we're done with the stream. As much as
  1364. // possible was actually written out to the data set by FlushBuffer, but
  1365. // some probably still remains in the buffer. It will get flushed
  1366. // later on... At this point we need to align on a four byte
  1367. // boundary. Once we do this, we can start all over again with
  1368. // the next stream (if none, then we bail out of this loop)
  1369. for( ; m_nBufUsed % 4; ++m_nBufUsed )
  1370. m_pBuffer[m_nBufUsed] = 0;
  1371. }
  1372. WsbTrace(OLESTR("CMTFSession::DoDataStream - End While\n"));
  1373. // Finish off the unnamed datastream CRC stuff
  1374. FINIALIZE_CRC(datastreamCRC);
  1375. WsbTrace(OLESTR("CMTFSession::DoDataStream finalized CRC is <%lu>\n"), datastreamCRC);
  1376. if (WSB_CRC_CALC_NONE != m_sHints.DatastreamCRCType) {
  1377. // We have a CRC that we want to save in the hints.
  1378. m_sHints.DatastreamCRC.QuadPart = datastreamCRC;
  1379. }
  1380. IO_STATUS_BLOCK IoStatusBlock;
  1381. NTSTATUS ccode;
  1382. // ** NT System Call - set file information
  1383. // This call fixes the access time that can be changed by the BackupRead call above
  1384. // When BackupRead is fixed this line should be removed. RAID 121023.
  1385. //
  1386. // IMPORTANT NOTE: This changes the USN, and must be done before we save the USN.
  1387. //
  1388. // TODO: See if we still need this
  1389. HRESULT infoHr = S_OK;
  1390. try {
  1391. WsbAffirmNtStatus(ccode = NtSetInformationFile( hStream, &IoStatusBlock, (PVOID)&m_SaveBasicInformation,
  1392. sizeof( m_SaveBasicInformation ), FileBasicInformation));
  1393. } WsbCatch(infoHr);
  1394. // Get the USN of the file before we close it
  1395. //
  1396. // Before we close the file, get the USN
  1397. //
  1398. LONGLONG lUsn;
  1399. if (S_OK == WsbGetUsnFromFileHandle(hStream, TRUE, &lUsn)) {
  1400. m_sHints.FileUSN.QuadPart = lUsn;
  1401. } else {
  1402. // If we can't get the USN, then just set it to 0
  1403. // which is invalid. Don't stop things.
  1404. m_sHints.FileUSN.QuadPart = 0;
  1405. }
  1406. // Now, were done with all of the streams. If there is data left
  1407. // in the buffer, we need to pad out to the next alignment block boundary and
  1408. // flush the buffer.
  1409. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1410. if (m_bCommitFile) {
  1411. WsbTrace(OLESTR("CMTFSession::DoDataStream - Commit\n"));
  1412. // Pad and Flush to next physical block
  1413. WsbAffirmHr(PadToNextPBA());
  1414. // Now flush the device buffer.
  1415. WsbAffirmNoError(WriteFilemarks(0));
  1416. }
  1417. else {
  1418. // Pad and Flush to next format logical block
  1419. WsbAffirmHr(PadToNextFLA(TRUE));
  1420. }
  1421. // Make sure we are aligned with a FLA (i.e. the last DBLK/stream was properly padded).
  1422. WsbAssert(0 == (m_nBufUsed % uAlignmentFactor), MVR_E_LOGIC_ERROR);
  1423. fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  1424. WsbTrace(OLESTR("CMTFSession::DoDataStream - End: FLA = %I64u\n"), fla);\
  1425. } WsbCatch(hr);
  1426. WsbTraceOut(OLESTR("CMTFSession::DoDataStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1427. return hr;
  1428. }
  1429. HRESULT
  1430. CMTFSession::DoEndOfDataSet(
  1431. IN USHORT nDataSetNumber)
  1432. /*++
  1433. Routine Description:
  1434. Formats and Writes an ESET DBLK. The end of data set sequence
  1435. starts with a filemark (which terminates the file data), followed
  1436. by an ESET, then a final filemark.
  1437. Arguments:
  1438. nDataSetNumber - The data set number. Used only in error recover. Otherwise
  1439. The original data set number is used.
  1440. Return Value:
  1441. S_OK - Success.
  1442. --*/
  1443. {
  1444. HRESULT hr = S_OK;
  1445. WsbTraceIn(OLESTR("CMTFSession::DoEndOfDataSet"), OLESTR("<%d>"), nDataSetNumber);
  1446. try {
  1447. MvrInjectError(L"Inject.CMTFSession::DoEndOfDataSet.0");
  1448. WsbAssertPointer(m_pBuffer);
  1449. MTF_DBLK_ESET_INFO sESET; // **MTF API STRUCT ** -- info for ESET
  1450. size_t nMoreBufUsed;
  1451. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1452. WsbAssert(m_nBlockSize > 0, MVR_E_LOGIC_ERROR);
  1453. //
  1454. // We can enter this routine in error recovery mode if
  1455. // we need to write out an ESET at the end of a previously
  1456. // written data set. In this case the Initialization flag
  1457. // will be FALSE.
  1458. //
  1459. if (! m_bSetInitialized) {
  1460. // This block of code is special to error recovery.
  1461. (void) InitCommonHeader();
  1462. // Since we use the Init SSET block to retrieve ESET info
  1463. // we need to initialize it.
  1464. // **MTF API CALL**
  1465. m_pMTFApi->MTF_SetSSETDefaults(&m_sSetInfo);
  1466. // Reset the set attributes and DataSetNumber.
  1467. m_sSetInfo.uSSETAttributes = 0; // TODO: This should match the original set attribute
  1468. m_sSetInfo.uDataSetNumber = nDataSetNumber;
  1469. // Can't be anyting in the buffer if we are only writing
  1470. // out the ESET.
  1471. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  1472. }
  1473. if (m_nBufUsed > 0) {
  1474. // Write out an ESPB if we have something in the buffer. This conditional covers
  1475. // the error recovery case where a missing ESET is detected. In this case we
  1476. // don't have enough info to write an ESBP, and were already on a physical block
  1477. // boundary, so we skip the ESPB.
  1478. // Make sure we are aligned with a FLA (i.e. the last DBLK was properly padded).
  1479. // It won't be if we are having problems writing to tape.
  1480. WsbAffirm(0 == (m_nBufUsed % uAlignmentFactor), E_ABORT);
  1481. UINT64 fla = m_nFormatLogicalAddress + m_nBufUsed/uAlignmentFactor;
  1482. UINT64 pba = m_nPhysicalBlockAddress + (fla*uAlignmentFactor/m_nBlockSize);
  1483. WsbTrace(OLESTR("Writing End of Set Pad (ESPB) @ FLA %I64u (%I64u, %I64u)\n"),
  1484. fla, pba, fla % (m_nBlockSize/uAlignmentFactor));
  1485. // TODO: Not sure all the error cases are handled, here. What if we
  1486. // end the set before completing the last I/O transfer. May need
  1487. // to add code to write out CFIL.
  1488. // Increment the BlockId and alignment index values that we keep in
  1489. // our common block header structure.
  1490. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  1491. m_sHeaderInfo.uFormatLogicalAddress = fla;
  1492. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  1493. // **MTF API CALL**
  1494. // Write ESPB to pad the backup set to a phyical block boundary.
  1495. nMoreBufUsed = 0;
  1496. WsbAssertNoError(m_pMTFApi->MTF_WriteESPBDblk(&m_sHeaderInfo, m_pBuffer+m_nBufUsed, m_nBufSize-m_nBufUsed, &nMoreBufUsed));
  1497. m_nBufUsed += nMoreBufUsed;
  1498. // Write out the ESPB DBLK and SPAD.
  1499. WsbAffirmHr(PadToNextPBA());
  1500. }
  1501. // Write a filemark to begin the end of data set sequence. This will flush the device buffer.
  1502. WsbAffirmHr(WriteFilemarks(1));
  1503. // **MTF API CALL**
  1504. // First set defaults for the info struct
  1505. m_pMTFApi->MTF_SetESETDefaults(&sESET);
  1506. sESET.uESETAttributes = m_sSetInfo.uSSETAttributes;
  1507. sESET.uDataSetNumber = m_sSetInfo.uDataSetNumber;
  1508. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  1509. m_sHeaderInfo.uFormatLogicalAddress = 0;
  1510. UINT64 curPos = 0;
  1511. WsbAffirmHr(GetCurrentPBA(&curPos)); // From the stream I/O model
  1512. WsbTrace(OLESTR("Writing End of Set (ESET) @ PBA %I64u\n"), curPos);
  1513. // **MTF API CALL**
  1514. // Provide the MTF_DBLK_HDR_INFO and MTF_DBLK_SSET_INFO structs to
  1515. // this function. The result is an MTF formatted SSET DBLK in m_pBuffer.
  1516. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  1517. WsbAssertNoError(m_pMTFApi->MTF_WriteESETDblk(&m_sHeaderInfo, &sESET, m_pBuffer, m_nBufSize, &m_nBufUsed));
  1518. // Write out the ESET DBLK and SPAD.
  1519. WsbAffirmHr(PadToNextPBA());
  1520. // NOTE: The PadToNextPBA() is a placeholder.
  1521. // The On Media Catalog would be generated and written after the ESET DBLK and SPAD.
  1522. // If we ever implement a catalog, we need to change the previous PadToNextPBA() to
  1523. // PadToNextPLA();
  1524. // Write a filemark. This will flush the device buffer.
  1525. WsbAffirmHr(WriteFilemarks(1));
  1526. } WsbCatch(hr);
  1527. WsbTraceOut(OLESTR("CMTFSession::DoEndOfDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1528. return hr;
  1529. }
  1530. HRESULT
  1531. CMTFSession::ExtendLastPadToNextPBA(void)
  1532. /*++
  1533. Routine Description:
  1534. Re-writes the last SPAD in the transfer buffer to align with
  1535. the next physical block boundary. This routine shoud only be
  1536. used before flushing the device buffer to guarantee data is written
  1537. to the physical device.
  1538. Arguments:
  1539. None.
  1540. Return Value:
  1541. S_OK - Success.
  1542. Comments:
  1543. !!! Not for CMTFSession internal use !!!
  1544. --*/
  1545. {
  1546. HRESULT hr = S_OK;
  1547. WsbTraceIn(OLESTR("CMTFSession::ExtendLastPadToNextPBA"), OLESTR(""));
  1548. try {
  1549. MvrInjectError(L"Inject.CMTFSession::ExtendLastPadToNextPBA.0");
  1550. WsbAssertPointer(m_pBuffer);
  1551. //
  1552. // The start of the SPAD could be in last part of a previous
  1553. // block that was flushed. In this case the transfer buffer
  1554. // contains the remaning portion of the SPAD, and the
  1555. // SPAD cannot be extended so we simply return.
  1556. //
  1557. // If we hit EOM while in the middle of a file transfer, the
  1558. // last thing in the transfer buffer won't be a SPAD. No SPAD
  1559. // is indicated by m_nStartOfPad == 0.
  1560. //
  1561. if ((m_nBufUsed > 0) && (m_nStartOfPad > 0) && (m_nStartOfPad < m_nBufUsed)) {
  1562. MTF_STREAM_INFO sSTREAM;
  1563. // Verify that there's an SPAD within the valid part of the buffer.
  1564. // Make sure our last pad pointer is at an SPAD.
  1565. WsbAffirmNoError(m_pMTFApi->MTF_ReadStreamHeader(&sSTREAM, &m_pBuffer[m_nStartOfPad]));
  1566. WsbAssert((0 == memcmp(sSTREAM.acStreamId, "SPAD", 4)), MVR_E_LOGIC_ERROR);
  1567. // Now, make sure we aren't going to overwrite anything other than a trailing SPAD.
  1568. WsbAssert(m_nBufUsed == (m_nStartOfPad + sizeof(MTF_STREAM_INFO) + sSTREAM.uStreamLength), MVR_E_LOGIC_ERROR);
  1569. // Reset the amount of buffer used to the start of the current SPAD
  1570. // in preparation for overwrite of SPAD to a physical block boundary.
  1571. m_nBufUsed = m_nStartOfPad;
  1572. WsbAffirmHr(PadToNextPBA());
  1573. }
  1574. // Flush the device buffer.
  1575. WsbAffirmHr(WriteFilemarks(0));
  1576. } WsbCatch(hr);
  1577. WsbTraceOut(OLESTR("CMTFSession::ExtendLastPadToNextPBA"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1578. return hr;
  1579. }
  1580. /***
  1581. Note:
  1582. "Skip" methods used for Recovery assume that you may read FLA size blocks
  1583. rather than PBA size block. Therefore, they muse be used only for files opened
  1584. without the FILE_FLAG_NO_BUFFERING flag.
  1585. If we come to the point where we must read only sector-size blocks, then some
  1586. of this code should be enhanced!
  1587. ***/
  1588. HRESULT
  1589. CMTFSession::SkipOverTapeDblk(void)
  1590. /*++
  1591. Routine Description:
  1592. Skips over a TAPE DBLK and the following FILEMARK.
  1593. Expects to find a full or partial TAPE DBLK but no other data.
  1594. Arguments:
  1595. None.
  1596. Return Value:
  1597. S_OK - Success.
  1598. MVR_E_NOT_FOUND - Block is missing or cut in the middle
  1599. --*/
  1600. {
  1601. HRESULT hr = S_OK;
  1602. WsbTraceIn(OLESTR("CMTFSession::SkipOverTapeDblk"), OLESTR(""));
  1603. try {
  1604. ULONG bytesRead = 0;
  1605. ULONG bytesToRead = m_nBlockSize;
  1606. UINT64 fileMarkPos;
  1607. // Read TAPE DBLK
  1608. WsbAffirmHr(SetCurrentPBA(0));
  1609. WsbAffirmHr(ReadFromDataSet (m_pBuffer, bytesToRead, &bytesRead));
  1610. if (bytesRead < bytesToRead) {
  1611. // incomplete block
  1612. WsbThrow(MVR_E_NOT_FOUND);
  1613. }
  1614. // Check block
  1615. MTF_DBLK_HDR_INFO sHdrInfo;
  1616. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1617. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_TAPE, 4), MVR_E_UNKNOWN_MEDIA);
  1618. // Next block should be a FILEMARK
  1619. WsbAffirmHr(GetCurrentPBA(&fileMarkPos));
  1620. bytesRead = 0;
  1621. WsbAffirmHr(ReadFromDataSet (m_pBuffer, bytesToRead, &bytesRead));
  1622. if (bytesRead < bytesToRead) {
  1623. // incomplete block
  1624. WsbThrow(MVR_E_NOT_FOUND);
  1625. }
  1626. // Check block
  1627. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1628. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_SFMB, 4), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1629. // Keep Soft File Marks array updated
  1630. if (TRUE == m_bUseSoftFilemarks) {
  1631. m_pMTFApi->MTF_InsertSoftFilemark(m_pSoftFilemarks, (UINT32)fileMarkPos);
  1632. }
  1633. } WsbCatch(hr);
  1634. WsbTraceOut(OLESTR("CMTFSession::SkipOverTapeDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1635. return hr;
  1636. }
  1637. HRESULT
  1638. CMTFSession::SkipOverSSETDblk(OUT USHORT* pDataSetNumber)
  1639. /*++
  1640. Routine Description:
  1641. Skips over a SSET DBLK
  1642. Expects to find a full or partial SSET DBLK but no other data.
  1643. Arguments:
  1644. pDataSetNumber - Data set number taken from the skipped block
  1645. Return Value:
  1646. S_OK - Success.
  1647. MVR_E_NOT_FOUND - Block is missing or cut in the middle
  1648. --*/
  1649. {
  1650. HRESULT hr = S_OK;
  1651. LARGE_INTEGER startBlockPosition = {0,0};
  1652. LARGE_INTEGER currentBlockPosition = {0,0};
  1653. WsbTraceIn(OLESTR("CMTFSession::SkipOverSSETDblk"), OLESTR(""));
  1654. try {
  1655. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1656. ULONG bytesRead = 0;
  1657. ULONG bytesToRead = uAlignmentFactor;
  1658. LARGE_INTEGER zero = {0,0};
  1659. m_nFormatLogicalAddress = 0;
  1660. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&startBlockPosition));
  1661. // Read SSET DBLK
  1662. WsbAffirmHr(m_pStream->Read(m_pBuffer, bytesToRead, &bytesRead));
  1663. if (bytesRead < bytesToRead) {
  1664. // incomplete block
  1665. WsbThrow(MVR_E_NOT_FOUND);
  1666. }
  1667. // Check block and get set number
  1668. MTF_DBLK_HDR_INFO sHdrInfo;
  1669. MTF_DBLK_SSET_INFO sSsetInfo;
  1670. m_pMTFApi->MTF_ReadSSETDblk(&sHdrInfo, &sSsetInfo, m_pBuffer);
  1671. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_SSET, 4), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1672. *pDataSetNumber = m_sSetInfo.uDataSetNumber;
  1673. // Skip over rest of the block
  1674. WsbAffirmHr(SkipOverStreams(startBlockPosition.QuadPart + sHdrInfo.uOffsetToFirstStream));
  1675. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&currentBlockPosition));
  1676. m_nFormatLogicalAddress += (currentBlockPosition.QuadPart - startBlockPosition.QuadPart) / uAlignmentFactor;
  1677. } WsbCatchAndDo(hr,
  1678. // Seek back to the beginning of the block
  1679. (void) m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL);
  1680. );
  1681. WsbTraceOut(OLESTR("CMTFSession::SkipOverSSETDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1682. return hr;
  1683. }
  1684. HRESULT
  1685. CMTFSession::SkipToDataSet(void)
  1686. /*++
  1687. Routine Description:
  1688. Skips to the beginning of the next FILE DBLK
  1689. Expects to find 0 to n other blocks such as DIRB DBLK.
  1690. In case of a partial last block, stream pointer is set to the beginning of the partial block
  1691. Arguments:
  1692. None.
  1693. Return Value:
  1694. S_OK - Success.
  1695. MVR_S_SETMARK_DETECTED - No more data sets (i.e. end-of-data-set detected)
  1696. MVR_E_NOT_FOUND - Block is missing or cut in the middle
  1697. --*/
  1698. {
  1699. HRESULT hr = S_OK;
  1700. LARGE_INTEGER startBlockPosition = {0,0};
  1701. LARGE_INTEGER currentBlockPosition = {0,0};
  1702. BOOL bIdRead = FALSE;
  1703. WsbTraceIn(OLESTR("CMTFSession::SkipToDataSet"), OLESTR(""));
  1704. try {
  1705. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1706. ULONG bytesRead = 0;
  1707. ULONG bytesToRead = uAlignmentFactor;
  1708. LARGE_INTEGER zero = {0,0};
  1709. while (TRUE) {
  1710. bIdRead = FALSE;
  1711. // keep current position, before block starts
  1712. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&startBlockPosition));
  1713. // Read block header
  1714. WsbAffirmHr(m_pStream->Read(m_pBuffer, bytesToRead, &bytesRead));
  1715. if (bytesRead < bytesToRead) {
  1716. // incomplete block
  1717. WsbThrow(MVR_E_NOT_FOUND);
  1718. }
  1719. // Check block
  1720. MTF_DBLK_HDR_INFO sHdrInfo;
  1721. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1722. m_nFormatLogicalAddress = sHdrInfo.uFormatLogicalAddress;
  1723. m_nCurrentBlockId = sHdrInfo.uControlBlockId + 1;
  1724. bIdRead = TRUE;
  1725. if ((0 == memcmp(sHdrInfo.acBlockType, MTF_ID_VOLB, 4)) ||
  1726. (0 == memcmp(sHdrInfo.acBlockType, MTF_ID_DIRB, 4))) {
  1727. // Just skip following streams
  1728. WsbAffirmHr(SkipOverStreams(startBlockPosition.QuadPart + sHdrInfo.uOffsetToFirstStream));
  1729. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&currentBlockPosition));
  1730. m_nFormatLogicalAddress += (currentBlockPosition.QuadPart - startBlockPosition.QuadPart) / uAlignmentFactor;
  1731. } else if (0 == memcmp(sHdrInfo.acBlockType, MTF_ID_FILE, 4)) {
  1732. WsbAffirmHr(m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL));
  1733. break;
  1734. } else if (0 == memcmp(sHdrInfo.acBlockType, MTF_ID_SFMB, 4)) {
  1735. // end of data-set reached, no ESPB block, must be alligned with PBA
  1736. WsbAffirmHr(m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL));
  1737. WsbAssert(0 == (startBlockPosition.QuadPart % m_nBlockSize), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1738. hr = MVR_S_SETMARK_DETECTED;
  1739. break;
  1740. } else if (0 == memcmp(sHdrInfo.acBlockType, MTF_ID_ESPB, 4)) {
  1741. // last block in data-set found. Make sure it is complete
  1742. WsbAffirmHr(SkipOverStreams(startBlockPosition.QuadPart + sHdrInfo.uOffsetToFirstStream));
  1743. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&currentBlockPosition));
  1744. WsbAssert(0 == (currentBlockPosition.QuadPart % m_nBlockSize), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1745. m_nFormatLogicalAddress += (currentBlockPosition.QuadPart - startBlockPosition.QuadPart) / uAlignmentFactor;
  1746. hr = MVR_S_SETMARK_DETECTED;
  1747. break;
  1748. } else {
  1749. // unexpected data
  1750. WsbThrow(MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1751. }
  1752. }
  1753. } WsbCatchAndDo(hr,
  1754. // Seek back to the end of the last complete & valid block
  1755. (void) m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL);
  1756. if (bIdRead) {
  1757. m_nCurrentBlockId--;
  1758. }
  1759. );
  1760. WsbTraceOut(OLESTR("CMTFSession::SkipToDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1761. return hr;
  1762. }
  1763. HRESULT
  1764. CMTFSession::SkipOverDataSet(void)
  1765. /*++
  1766. Routine Description:
  1767. Skips over one FILE DBLK, including all of its data streams
  1768. Expects to find a FILE DBLK.
  1769. In case of a partial block, stream pointer is set back to the beginning of the block
  1770. Arguments:
  1771. None.
  1772. Return Value:
  1773. S_OK - Success.
  1774. MVR_E_NOT_FOUND - Block is missing or cut in the middle
  1775. --*/
  1776. {
  1777. HRESULT hr = S_OK;
  1778. LARGE_INTEGER startBlockPosition = {0,0};
  1779. LARGE_INTEGER currentBlockPosition = {0,0};
  1780. WsbTraceIn(OLESTR("CMTFSession::SkipOverDataSet"), OLESTR(""));
  1781. try {
  1782. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1783. ULONG bytesRead = 0;
  1784. ULONG bytesToRead = uAlignmentFactor;
  1785. LARGE_INTEGER zero = {0,0};
  1786. // keep current position, before block starts
  1787. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&startBlockPosition));
  1788. // Read block header
  1789. WsbAffirmHr(m_pStream->Read(m_pBuffer, bytesToRead, &bytesRead));
  1790. if (bytesRead < bytesToRead) {
  1791. // incomplete block
  1792. WsbThrow(MVR_E_NOT_FOUND);
  1793. }
  1794. // Check block
  1795. MTF_DBLK_HDR_INFO sHdrInfo;
  1796. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1797. if (0 == memcmp(sHdrInfo.acBlockType, MTF_ID_FILE, 4)) {
  1798. WsbAffirmHr(SkipOverStreams(startBlockPosition.QuadPart + sHdrInfo.uOffsetToFirstStream));
  1799. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&currentBlockPosition));
  1800. m_nFormatLogicalAddress += (currentBlockPosition.QuadPart - startBlockPosition.QuadPart) / uAlignmentFactor;
  1801. } else {
  1802. // unexpected data
  1803. WsbThrow(MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1804. }
  1805. } WsbCatchAndDo(hr,
  1806. // Seek back to the beginning of the block
  1807. (void) m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL);
  1808. m_nCurrentBlockId--;
  1809. );
  1810. WsbTraceOut(OLESTR("CMTFSession::SkipOverDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1811. return hr;
  1812. }
  1813. HRESULT
  1814. CMTFSession::SkipOverEndOfDataSet(void)
  1815. /*++
  1816. Routine Description:
  1817. Skips over one the sequence FILEMARK + ESET DBLK + FILEMARK
  1818. Expects to find a FILE MARK, even if ESPB exists, it should have been already skipped.
  1819. In case of a partial sequence, stream pointer is set back to the beginning of the sequence
  1820. Arguments:
  1821. None.
  1822. Return Value:
  1823. S_OK - Success. (It really means that the file is valid & complete)
  1824. MVR_E_NOT_FOUND - Sequence is missing or cut in the middle
  1825. --*/
  1826. {
  1827. HRESULT hr = S_OK;
  1828. LARGE_INTEGER startBlockPosition = {0,0};
  1829. UINT64 nFormatLogicalAddress = m_nFormatLogicalAddress;
  1830. WsbTraceIn(OLESTR("CMTFSession::SkipOverEndOfDataSet"), OLESTR(""));
  1831. try {
  1832. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1833. ULONG bytesRead = 0;
  1834. ULONG bytesToRead = m_nBlockSize;
  1835. LARGE_INTEGER zero = {0,0};
  1836. // keep current position, before block starts
  1837. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&startBlockPosition));
  1838. // Read block header
  1839. m_nFormatLogicalAddress = startBlockPosition.QuadPart / uAlignmentFactor;
  1840. WsbAffirmHr(ReadFromDataSet (m_pBuffer, bytesToRead, &bytesRead));
  1841. if (bytesRead < bytesToRead) {
  1842. // incomplete block
  1843. WsbThrow(MVR_E_NOT_FOUND);
  1844. }
  1845. // Check block, must be a FILE MARK
  1846. MTF_DBLK_HDR_INFO sHdrInfo;
  1847. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1848. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_SFMB, 4), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1849. // Read next block
  1850. bytesRead = 0;
  1851. WsbAffirmHr(ReadFromDataSet (m_pBuffer, bytesToRead, &bytesRead));
  1852. if (bytesRead < bytesToRead) {
  1853. // incomplete block
  1854. WsbThrow(MVR_E_NOT_FOUND);
  1855. }
  1856. // Check block, must be a ESET DBLK
  1857. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1858. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_ESET, 4), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1859. // Read next block
  1860. bytesRead = 0;
  1861. WsbAffirmHr(ReadFromDataSet (m_pBuffer, bytesToRead, &bytesRead));
  1862. if (bytesRead < bytesToRead) {
  1863. // incomplete block
  1864. WsbThrow(MVR_E_NOT_FOUND);
  1865. }
  1866. // Check block, must be a FILEMARK
  1867. m_pMTFApi->MTF_DBLK_HDR_INFO_ReadFromBuffer(&sHdrInfo, m_pBuffer);
  1868. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_SFMB, 4), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1869. } WsbCatchAndDo(hr,
  1870. // Seek back to the beginning of the block
  1871. (void) m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL);
  1872. m_nFormatLogicalAddress = nFormatLogicalAddress;
  1873. );
  1874. WsbTraceOut(OLESTR("CMTFSession::SkipOverEndOfDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1875. return hr;
  1876. }
  1877. HRESULT
  1878. CMTFSession::PrepareForEndOfDataSet(void)
  1879. /*++
  1880. Routine Description:
  1881. Write an ESPB block in case that last complete fla is NOT aligned with pba
  1882. File position should be aligned with pba after the method ends
  1883. Arguments:
  1884. None.
  1885. Return Value:
  1886. S_OK - Success.
  1887. --*/
  1888. {
  1889. HRESULT hr = S_OK;
  1890. LARGE_INTEGER startBlockPosition = {0,0};
  1891. LARGE_INTEGER zero = {0,0};
  1892. UINT64 nRemainder;
  1893. UINT64 nFormatLogicalAddress = m_nFormatLogicalAddress;
  1894. WsbTraceIn(OLESTR("CMTFSession::PrepareForEndOfDataSet"), OLESTR(""));
  1895. try {
  1896. // ESPB block should be written only if:
  1897. // 1. Physical Block size is larger than MTF Logical Block size
  1898. // 2. Current location is not aligned with pba (it already must be aligned with fla)
  1899. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1900. if (m_nBlockSize != uAlignmentFactor) {
  1901. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&startBlockPosition));
  1902. nRemainder = startBlockPosition.QuadPart % m_nBlockSize;
  1903. if (0 != nRemainder) {
  1904. size_t nSizeUsed = 0;
  1905. size_t nBufUsed = 0;
  1906. ULONG bytesWritten = 0;
  1907. ULONG bytesToWrite;
  1908. WsbTrace(OLESTR("Writing ESPB for Recovery, completing a remainder of %I64u bytes (%I64u fla) to pba\n"),
  1909. nRemainder, (nRemainder / uAlignmentFactor));
  1910. (void) InitCommonHeader();
  1911. m_sHeaderInfo.uControlBlockId = m_nCurrentBlockId++;
  1912. m_sHeaderInfo.uFormatLogicalAddress = m_nFormatLogicalAddress;
  1913. // **MTF API CALL**
  1914. WsbAssertNoError(m_pMTFApi->MTF_WriteESPBDblk(&m_sHeaderInfo, m_pBuffer+m_nBufUsed, m_nBufSize, &nSizeUsed));
  1915. WsbAssertNoError(m_pMTFApi->MTF_PadToNextPhysicalBlockBoundary(m_pBuffer, m_nBlockSize, nSizeUsed, m_nBufSize, &nBufUsed));
  1916. // Write data and flush
  1917. bytesToWrite = (ULONG)(m_nBlockSize - nRemainder);
  1918. WsbAffirmHr(m_pStream->Write(m_pBuffer, bytesToWrite, &bytesWritten));
  1919. WsbAffirm((bytesWritten == bytesToWrite), E_FAIL);
  1920. WsbAffirmHr(m_pStream->Commit(0)); // Flush the device buffers
  1921. m_nFormatLogicalAddress += bytesWritten / uAlignmentFactor;
  1922. }
  1923. }
  1924. } WsbCatchAndDo(hr,
  1925. // Seek back to the beginning of the block
  1926. (void) m_pStream->Seek(startBlockPosition, STREAM_SEEK_SET, NULL);
  1927. m_nCurrentBlockId--;
  1928. );
  1929. WsbTraceOut(OLESTR("CMTFSession::PrepareForEndOfDataSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1930. return hr;
  1931. }
  1932. HRESULT
  1933. CMTFSession::SkipOverStreams(IN UINT64 uOffsetToFirstStream)
  1934. /*++
  1935. Routine Description:
  1936. Skips over all streams of current block
  1937. Expects to find a SPAD stream as the last one (if data is not truncated)
  1938. Arguments:
  1939. uOffsetToFirstStream - Offset to the beginning of the first stream (absolute position)
  1940. Return Value:
  1941. S_OK - Success.
  1942. MVR_E_NOT_FOUND - Stream is missing or cut in the middle
  1943. --*/
  1944. {
  1945. HRESULT hr = S_OK;
  1946. LARGE_INTEGER startStreamPosition = {0,0};
  1947. WsbTraceIn(OLESTR("CMTFSession::SkipOverStreams"), OLESTR(""));
  1948. try {
  1949. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  1950. ULONG bytesRead = 0;
  1951. ULONG bytesToRead = (ULONG)sizeof(MTF_STREAM_INFO);
  1952. UINT64 uStreamLength;
  1953. LARGE_INTEGER skipToPosition = {0,0};
  1954. LARGE_INTEGER endPosition = {0,0};
  1955. LARGE_INTEGER zero = {0,0};
  1956. BOOL bMoreStreams = TRUE;
  1957. // Keep end position
  1958. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_END, (ULARGE_INTEGER *)&endPosition));
  1959. // Seek to begining of first stream
  1960. skipToPosition.QuadPart = uOffsetToFirstStream;
  1961. WsbAffirmHr(m_pStream->Seek(skipToPosition, STREAM_SEEK_SET, NULL));
  1962. while (bMoreStreams) {
  1963. // keep current position, before stream starts
  1964. startStreamPosition.QuadPart = skipToPosition.QuadPart;
  1965. // Read stream header
  1966. WsbAffirmHr(m_pStream->Read(m_pBuffer, bytesToRead, &bytesRead));
  1967. if (bytesRead < bytesToRead) {
  1968. // incomplete stream
  1969. WsbThrow(MVR_E_NOT_FOUND);
  1970. }
  1971. MTF_STREAM_INFO sHdrInfo;
  1972. m_pMTFApi->MTF_ReadStreamHeader(&sHdrInfo, m_pBuffer);
  1973. if (0 == memcmp(sHdrInfo.acStreamId, MTF_PAD_STREAM, 4)) {
  1974. bMoreStreams = FALSE;
  1975. }
  1976. // Skip to the next stream
  1977. uStreamLength = sHdrInfo.uStreamLength + sizeof(MTF_STREAM_INFO);
  1978. if (uStreamLength % 4) {
  1979. uStreamLength = uStreamLength - (uStreamLength % 4) + 4;
  1980. }
  1981. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&skipToPosition));
  1982. skipToPosition.QuadPart = skipToPosition.QuadPart + uStreamLength - bytesToRead;
  1983. if (skipToPosition.QuadPart > endPosition.QuadPart) {
  1984. // incomplete block
  1985. WsbThrow(MVR_E_NOT_FOUND);
  1986. }
  1987. WsbAffirmHr(m_pStream->Seek(skipToPosition, STREAM_SEEK_SET, NULL));
  1988. }
  1989. // If we got here, SPAD was found and skipped hence we must be FLA alligned
  1990. WsbAssert(0 == (skipToPosition.QuadPart % uAlignmentFactor), MVR_E_INCONSISTENT_MEDIA_LAYOUT);
  1991. } WsbCatchAndDo(hr,
  1992. // Seek back to the end of the last complete & valid stream
  1993. (void) m_pStream->Seek(startStreamPosition, STREAM_SEEK_SET, NULL);
  1994. );
  1995. WsbTraceOut(OLESTR("CMTFSession::SkipOverStreams"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1996. return hr;
  1997. }
  1998. HRESULT
  1999. CMTFSession::PadToNextPBA(void)
  2000. /*++
  2001. Routine Description:
  2002. Writes an SPAD to the transfer buffer upto the next physical block boundary.
  2003. Arguments:
  2004. None.
  2005. Return Value:
  2006. S_OK - Success.
  2007. --*/
  2008. {
  2009. HRESULT hr = S_OK;
  2010. WsbTraceIn(OLESTR("CMTFSession::PadToNextPBA"), OLESTR(""));
  2011. try {
  2012. MvrInjectError(L"Inject.CMTFSession::PadToNextPBA.0");
  2013. WsbAssertPointer(m_pBuffer);
  2014. // **MTF API CALL **
  2015. // Write an SPAD out to the next physical block boundary.
  2016. WsbAssertNoError(m_pMTFApi->MTF_PadToNextPhysicalBlockBoundary(m_pBuffer, m_nBlockSize, m_nBufUsed, m_nBufSize, &m_nBufUsed));
  2017. // At this point our buffer should be padded out to
  2018. // the next physical block boundary, which means it is
  2019. // ready to be written in its entirety to the target
  2020. // media.
  2021. // Write out the data and SPAD stream.
  2022. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  2023. // Everything in the buffer should be written out when
  2024. // the buffer is aligned on a physical block boundary.
  2025. WsbAssert(0 == m_nBufUsed, E_UNEXPECTED);
  2026. } WsbCatch(hr);
  2027. WsbTraceOut(OLESTR("CMTFSession::PadToNextPBA"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2028. return hr;
  2029. }
  2030. HRESULT
  2031. CMTFSession::PadToNextFLA(
  2032. BOOL flush)
  2033. /*++
  2034. Routine Description:
  2035. Writes an SPAD to the transfer buffer upto format logical block boundary.
  2036. Arguments:
  2037. flush - if TRUE, the transfer buffer is flushed.
  2038. Return Value:
  2039. S_OK - Success.
  2040. --*/
  2041. {
  2042. HRESULT hr = S_OK;
  2043. WsbTraceIn(OLESTR("CMTFSession::PadToNextFLA"), OLESTR("<%ls>"), WsbBoolAsString(flush));
  2044. try {
  2045. MvrInjectError(L"Inject.CMTFSession::PadToNextFLA.0");
  2046. WsbAssertPointer(m_pBuffer);
  2047. size_t startOfPad;
  2048. // **MTF API CALL **
  2049. // Write an SPAD out to the next alignment block boundary.
  2050. startOfPad = m_nBufUsed;
  2051. WsbAssertNoError(m_pMTFApi->MTF_PadToNextAlignmentFactor(m_pBuffer, m_nBufUsed, m_nBufSize, &m_nBufUsed));
  2052. if (flush) {
  2053. // Write out data and SPAD stream.
  2054. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  2055. }
  2056. // Reset the location of the last SPAD within the buffer.
  2057. // Note: The value is only valid of m_nStartOfPad < m_nBufUsed.
  2058. m_nStartOfPad = (m_nBufUsed > 0) ? startOfPad % m_nBlockSize : 0;
  2059. } WsbCatch(hr);
  2060. WsbTraceOut(OLESTR("CMTFSession::PadToNextFLA"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2061. return hr;
  2062. }
  2063. HRESULT
  2064. CMTFSession::WriteToDataSet(
  2065. IN BYTE *pBuffer,
  2066. IN ULONG nBytesToWrite,
  2067. OUT ULONG *pBytesWritten)
  2068. /*++
  2069. Routine Description:
  2070. Used to write all MTF data.
  2071. Format Logical Address is updated to the current offset.
  2072. Arguments:
  2073. pBuffer - Data buffer.
  2074. nBytesToWrite - number of bytes to write in buffer.
  2075. pBytesWritten - Bytes written.
  2076. Return Value:
  2077. S_OK - Success.
  2078. --*/
  2079. {
  2080. HRESULT hr = S_OK;
  2081. try {
  2082. MvrInjectError(L"Inject.CMTFSession::WriteToDataSet.0");
  2083. WsbAssertPointer(m_pStream);
  2084. WsbAssertPointer(pBuffer);
  2085. WsbAssertPointer(pBytesWritten);
  2086. *pBytesWritten = 0;
  2087. // Make sure that we are asked to write only full blocks
  2088. WsbAssert(!(nBytesToWrite % m_nBlockSize), MVR_E_LOGIC_ERROR);
  2089. try {
  2090. WsbAffirmHr(m_pStream->Write(pBuffer, nBytesToWrite, pBytesWritten));
  2091. } WsbCatch(hr);
  2092. // Making sure that we are writing only full blocks
  2093. if (*pBytesWritten != nBytesToWrite) {
  2094. WsbTraceAlways(OLESTR("Asked to write %lu bytes but wrote only %lu bytes. Write hr = <%ls>\n"),
  2095. nBytesToWrite, *pBytesWritten, WsbHrAsString(hr));
  2096. if (SUCCEEDED(hr)) {
  2097. // Write "succeeded" buy didn't write all the bytes (full disk scenario):
  2098. // Shouldn't happen since caller is expected to verify that there's enough free space in advance.
  2099. hr = E_FAIL;
  2100. }
  2101. }
  2102. // Update the total number of alignment factors
  2103. m_nFormatLogicalAddress += *pBytesWritten / (m_pMTFApi->MTF_GetAlignmentFactor());
  2104. } WsbCatch(hr);
  2105. return hr;
  2106. }
  2107. HRESULT
  2108. CMTFSession::ReadFromDataSet (
  2109. IN BYTE *pBuffer,
  2110. IN ULONG nBytesToRead,
  2111. OUT ULONG *pBytesRead)
  2112. /*++
  2113. Routine Description:
  2114. Used to read all MTF data.
  2115. Format Logical Address is updated to the current offset.
  2116. Arguments:
  2117. pBuffer - Data buffer.
  2118. nBytesToRead - number of bytes to read into buffer.
  2119. pBytesRead - Bytes read.
  2120. Return Value:
  2121. S_OK - Success.
  2122. --*/
  2123. {
  2124. HRESULT hr = S_OK;
  2125. try {
  2126. MvrInjectError(L"Inject.CMTFSession::ReadFromDataSet.0");
  2127. WsbAssertPointer(m_pStream);
  2128. WsbAssertPointer(pBuffer);
  2129. WsbAssertPointer(pBytesRead);
  2130. // We need to set hr. MVR_S_FILEMARK_DETECTED, MVR_S_SETMARK_DETECTED are Okay.
  2131. hr = m_pStream->Read(pBuffer, nBytesToRead, pBytesRead);
  2132. // update the total number of alignment factors
  2133. m_nFormatLogicalAddress += *pBytesRead / (m_pMTFApi->MTF_GetAlignmentFactor());
  2134. // Now test hr
  2135. WsbAffirmHr(hr);
  2136. // Make sure that we read only full blocks
  2137. WsbAssert(!(*pBytesRead % m_nBlockSize), MVR_E_LOGIC_ERROR);
  2138. } WsbCatch(hr);
  2139. return hr;
  2140. }
  2141. HRESULT
  2142. CMTFSession::FlushBuffer(
  2143. IN BYTE *pBuffer,
  2144. IN OUT size_t *pBufPosition)
  2145. /*++
  2146. Routine Description:
  2147. Writes as much of the buffer as possible out to the device.
  2148. Any remaining data not written out is moved to the front of
  2149. the buffer, and *pBufPosition is updated accordingly
  2150. Arguments:
  2151. pBuffer - Data buffer.
  2152. pBufPosition - Number of bytes to write in buffer. On output
  2153. holds the number of bytes still in the buffer.
  2154. Return Value:
  2155. S_OK - Success.
  2156. --*/
  2157. {
  2158. HRESULT hr = S_OK;
  2159. ULONG uPosition = (ULONG)(*pBufPosition);
  2160. try {
  2161. MvrInjectError(L"Inject.CMTFSession::FlushBuffer.0");
  2162. // If the buffer has more than a physical block of bytes in it, dump as many as
  2163. // possible to the device, then move the remaining data to the head of the buffer
  2164. if (uPosition >= m_nBlockSize) {
  2165. ULONG nBlocksToWrite;
  2166. ULONG nBytesWritten = 0;
  2167. // Determine the number of physical blocks to write
  2168. nBlocksToWrite = uPosition / m_nBlockSize;
  2169. try {
  2170. // Write the data to the data set
  2171. WsbAffirmHr(WriteToDataSet(pBuffer, nBlocksToWrite * m_nBlockSize, &nBytesWritten));
  2172. } WsbCatch(hr);
  2173. // Adjust the buffer position and slide the unwritten data down in the buffer
  2174. WsbAssert(uPosition >= nBytesWritten, E_UNEXPECTED);
  2175. uPosition -= nBytesWritten;
  2176. memmove(pBuffer, pBuffer + nBytesWritten, uPosition);
  2177. // Invalidate the pad start location after any flush. This is reset in PadToNextFLA().
  2178. m_nStartOfPad = 0;
  2179. }
  2180. } WsbCatch(hr);
  2181. // Set output
  2182. *pBufPosition = (size_t)uPosition;
  2183. return hr;
  2184. }
  2185. HRESULT
  2186. CMTFSession::WriteFilemarks(
  2187. IN ULONG nCount)
  2188. /*++
  2189. Routine Description:
  2190. Writes count filemarks at the current location.
  2191. Arguments:
  2192. nCount - Number of Filemarks to write.
  2193. Return Value:
  2194. S_OK - Success.
  2195. --*/
  2196. {
  2197. HRESULT hr = S_OK;
  2198. WsbTraceIn(OLESTR("CMTFSession::WriteFilemarks"), OLESTR("<%u>"), nCount);
  2199. try {
  2200. MvrInjectError(L"Inject.CMTFSession::WriteFilemarks.0");
  2201. WsbAssertPointer(m_pStream);
  2202. WsbAssertPointer(m_pBuffer);
  2203. UINT16 uAlignmentFactor = m_pMTFApi->MTF_GetAlignmentFactor();
  2204. if ( nCount > 0) {
  2205. // Can't write a filemark with data still in the transfer buffer if nCount > 0!
  2206. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  2207. UINT64 pba = 0;
  2208. UINT64 curPos = 0;
  2209. WsbAffirmHr(GetCurrentPBA(&curPos)); // From the stream I/O model
  2210. if ( m_nPhysicalBlockAddress > 0 ) {
  2211. // Make sure the FLA aligns with a PBA!
  2212. WsbAssert(0 == (m_nFormatLogicalAddress*uAlignmentFactor) % m_nBlockSize, MVR_E_LOGIC_ERROR);
  2213. // Provided there's nothing in the transfer buffer, this is an accurate calc.
  2214. pba = m_nPhysicalBlockAddress + ((m_nFormatLogicalAddress*uAlignmentFactor)/m_nBlockSize);
  2215. // Make sure we are where we think we are.
  2216. WsbAssert(curPos == pba, MVR_E_LOGIC_ERROR);
  2217. }
  2218. else {
  2219. //
  2220. // We skip the consistency check for the case were we're writing filemarks
  2221. // through the session model and m_nPhysicalBlockAddress is uninitialzed.
  2222. // This happens we we are writing an ESET sequence in dataset recovery code.
  2223. //
  2224. pba = curPos;
  2225. }
  2226. if (TRUE == m_bUseSoftFilemarks) {
  2227. LONG n = nCount;
  2228. if (n > 0) {
  2229. UINT32 pba32 = (UINT32) pba;
  2230. // Soft Filemark support only handles 2^32 * 1 KByte media (16 TBytes using 1 KByte logical Blocks)
  2231. // Some day this won't be enough... and we'll know!
  2232. WsbAssert((UINT64)pba32 == pba, E_UNEXPECTED);
  2233. // One last check... Can't write out more filemarks, at one time, than can be stored in
  2234. // the filemark table.
  2235. WsbAssert(nCount < m_pSoftFilemarks->uNumberOfFilemarkEntries, E_UNEXPECTED);
  2236. while(n-- > 0) {
  2237. // **MTF API CALL**
  2238. m_pMTFApi->MTF_InsertSoftFilemark(m_pSoftFilemarks, pba32++);
  2239. // **MTF API CALL**
  2240. WsbAssertNoError(m_pMTFApi->MTF_WriteSFMBDblk(&m_sHeaderInfo, m_pSoftFilemarks, m_pBuffer, m_nBufSize, &m_nBufUsed));
  2241. // Write out the SFMB DBLK.
  2242. WsbAffirmHr(FlushBuffer(m_pBuffer, &m_nBufUsed));
  2243. // Everything should be written to media after a filemark!
  2244. WsbAssert(0 == m_nBufUsed, MVR_E_LOGIC_ERROR);
  2245. // PBA counter should never roll over!
  2246. WsbAssert(pba32 > 0, E_UNEXPECTED);
  2247. };
  2248. }
  2249. WsbAffirmHr(m_pStream->Commit(0)); // Flush the device buffers
  2250. // NOTE: The total number of alignment factors is updated via FlushBuffer(),
  2251. // so we don't need to do it here.
  2252. }
  2253. else {
  2254. // We use the IStream::Commit interface to write out the filemark.
  2255. // This is not a perfect match in that the nCount parameter is supposed to
  2256. // be a commit flag, not filemark count. Zero flushes device buffers
  2257. // without writing a filemark.
  2258. WsbAffirmHr(m_pStream->Commit(nCount));
  2259. // update the total number of alignment factors
  2260. m_nFormatLogicalAddress += (nCount * m_nBlockSize) / uAlignmentFactor;
  2261. }
  2262. }
  2263. else {
  2264. // 0 == nCount implies flush device buffers.
  2265. //
  2266. // We skip all consistency checks since it is
  2267. // is always safe to flush device buffers.
  2268. //
  2269. WsbAffirmHr(m_pStream->Commit(0)); // Flush the device buffers
  2270. }
  2271. } WsbCatch(hr);
  2272. WsbTraceOut(OLESTR("CMTFSession::WriteFilemarks"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2273. return hr;
  2274. }
  2275. HRESULT
  2276. CMTFSession::GetCurrentPBA(
  2277. OUT UINT64 *pPosition)
  2278. /*++
  2279. Routine Description:
  2280. Returns the current physical block address relative the current partition.
  2281. Arguments:
  2282. pPostion - Receives the current physical block address.
  2283. Return Value:
  2284. S_OK - Success.
  2285. --*/
  2286. {
  2287. HRESULT hr = S_OK;
  2288. WsbTraceIn(OLESTR("CMTFSession::GetCurrentPBA"), OLESTR(""));
  2289. ULARGE_INTEGER position = {0xffffffff,0xffffffff};
  2290. try {
  2291. MvrInjectError(L"Inject.CMTFSession::GetCurrentPBA.0");
  2292. WsbAssertPointer(m_pStream);
  2293. WsbAssertPointer(pPosition);
  2294. LARGE_INTEGER zero = {0,0};
  2295. // Gets the current position.
  2296. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_CUR, &position));
  2297. position.QuadPart = position.QuadPart / m_nBlockSize;
  2298. *pPosition = position.QuadPart;
  2299. } WsbCatch(hr);
  2300. WsbTraceOut(OLESTR("CMTFSession::GetCurrentPBA"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), position);
  2301. return hr;
  2302. }
  2303. HRESULT
  2304. CMTFSession::SetCurrentPBA(
  2305. IN UINT64 position)
  2306. /*++
  2307. Routine Description:
  2308. Returns the current physical block address relative the current partition.
  2309. Arguments:
  2310. postion - The physical block address to position to.
  2311. Return Value:
  2312. S_OK - Success.
  2313. --*/
  2314. {
  2315. HRESULT hr = S_OK;
  2316. WsbTraceIn(OLESTR("CMTFSession::SetCurrentPBA"), OLESTR("<%I64u>"), position);
  2317. try {
  2318. WsbAssertPointer(m_pStream);
  2319. LARGE_INTEGER seekTo;
  2320. seekTo.QuadPart = position * m_nBlockSize;
  2321. // Move to the specified position.
  2322. WsbAffirmHr(m_pStream->Seek(seekTo, STREAM_SEEK_SET, NULL));
  2323. m_nPhysicalBlockAddress = position;
  2324. } WsbCatch(hr);
  2325. WsbTraceOut(OLESTR("CMTFSession::SetCurrentPBA"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), m_nPhysicalBlockAddress);
  2326. return hr;
  2327. }
  2328. HRESULT
  2329. CMTFSession::SpaceToEOD(void)
  2330. /*++
  2331. Routine Description:
  2332. Positions the media to the end of data of the current partition.
  2333. Arguments:
  2334. None.
  2335. Return Value:
  2336. S_OK - Success.
  2337. --*/
  2338. {
  2339. HRESULT hr = S_OK;
  2340. WsbTraceIn(OLESTR("CMTFSession::SpaceToEOD"), OLESTR(""));
  2341. UINT64 curPos = 0xffffffffffffffff;
  2342. try {
  2343. MvrInjectError(L"Inject.CMTFSession::SpaceToEOD.0");
  2344. WsbAssertPointer(m_pStream);
  2345. LARGE_INTEGER zero = {0,0};
  2346. // Sets the current position to the end of data.
  2347. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_END, NULL));
  2348. WsbAffirmHr(GetCurrentPBA(&curPos));
  2349. m_nPhysicalBlockAddress = curPos;
  2350. } WsbCatch(hr);
  2351. WsbTraceOut(OLESTR("CMTFSession::SpaceToEOD"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2352. return hr;
  2353. }
  2354. HRESULT
  2355. CMTFSession::SpaceToBOD(void)
  2356. /*++
  2357. Routine Description:
  2358. Posotions the media to the beginnning of the current partition.
  2359. Arguments:
  2360. None.
  2361. Return Value:
  2362. S_OK - Success.
  2363. --*/
  2364. {
  2365. HRESULT hr = S_OK;
  2366. WsbTraceIn(OLESTR("CMTFSession::SpaceToBOD"), OLESTR(""));
  2367. UINT64 curPos = 0xffffffffffffffff;
  2368. try {
  2369. MvrInjectError(L"Inject.CMTFSession::SpaceToBOD.0");
  2370. WsbAssertPointer(m_pStream);
  2371. LARGE_INTEGER zero = {0,0};
  2372. // Sets the current position to the beginning of data.
  2373. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_SET, NULL));
  2374. WsbAffirmHr(GetCurrentPBA(&curPos));
  2375. m_nPhysicalBlockAddress = curPos;
  2376. } WsbCatch(hr);
  2377. WsbTraceOut(OLESTR("CMTFSession::SpaceToBOD"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), curPos);
  2378. return hr;
  2379. }
  2380. HRESULT
  2381. CMTFSession::ReadTapeDblk(OUT WCHAR **pszLabel)
  2382. /*++
  2383. Routine Description:
  2384. Skips over a SSET DBLK
  2385. Expects to find a full or partial SSET DBLK but no other data.
  2386. Arguments:
  2387. pszLabel - Pointer to a buffer to hold the RSS tape label.
  2388. Reallocated as necessary
  2389. Return Value:
  2390. S_OK - Success.
  2391. MVR_E_UNKNOWN_MEDIA - No TAPE DBLK or not RSS TAPE
  2392. --*/
  2393. {
  2394. HRESULT hr = S_OK;
  2395. ULONG bytesRead = 0;
  2396. WsbTraceIn(OLESTR("CMTFSession::ReadTapeDblk"), OLESTR(""));
  2397. try {
  2398. ULARGE_INTEGER position = {0,0};
  2399. LARGE_INTEGER zero = {0,0};
  2400. // The MTF labels are < 1024 bytes. We need to read 1024 bytes + the filemark
  2401. // (1 block), 3x the min block size covers all cases.
  2402. // The MTFSession work buffer is at least 2 blocks
  2403. ULONG nBlocks = (3*512)/m_nBlockSize;
  2404. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  2405. ULONG bytesToRead = nBlocks * m_nBlockSize;
  2406. WsbAssertPointer(m_pBuffer);
  2407. memset(m_pBuffer, 0, bytesToRead);
  2408. // Sets the current position to the beginning of data.
  2409. WsbAffirmHr(m_pStream->Seek(zero, STREAM_SEEK_SET, &position));
  2410. // Read upto first Filemark.
  2411. WsbAffirmHr(m_pStream->Read(m_pBuffer, bytesToRead, &bytesRead));
  2412. MTF_DBLK_HDR_INFO sHdrInfo;
  2413. MTF_DBLK_TAPE_INFO sTapeInfo;
  2414. m_pMTFApi->MTF_ReadTAPEDblk(&sHdrInfo, &sTapeInfo, m_pBuffer);
  2415. // Is this a MTF Tape?
  2416. WsbAffirm(0 == memcmp(sHdrInfo.acBlockType, MTF_ID_TAPE, 4), MVR_E_UNKNOWN_MEDIA);
  2417. // Now try to identify it as one of ours,
  2418. // using the following criteria:
  2419. // 1) It has a UNICODE tape name and tape description and software name.
  2420. // 2) It has our Vendor Id (accept both old Win2K id and current id).
  2421. WsbAffirm(sHdrInfo.uStringType == MTF_STRING_UNICODE_STR, MVR_E_UNKNOWN_MEDIA);
  2422. WsbAffirm(sTapeInfo.szTapeName, MVR_E_UNKNOWN_MEDIA);
  2423. WsbAffirm(sTapeInfo.szTapeDescription, MVR_E_UNKNOWN_MEDIA);
  2424. WsbAffirm(sTapeInfo.szSoftwareName, MVR_E_UNKNOWN_MEDIA);
  2425. WsbAffirm((REMOTE_STORAGE_MTF_VENDOR_ID == sTapeInfo.uSoftwareVendorId) ||
  2426. (REMOTE_STORAGE_WIN2K_MTF_VENDOR_ID == sTapeInfo.uSoftwareVendorId),
  2427. MVR_E_UNKNOWN_MEDIA);
  2428. CWsbStringPtr label = sTapeInfo.szTapeDescription;
  2429. *pszLabel = NULL;
  2430. WsbAffirmHr(label.CopyTo(pszLabel));
  2431. } WsbCatchAndDo(hr,
  2432. // Trace the illegal buffer where the RSS TAPE DBLK should reside
  2433. if (m_pBuffer) {
  2434. WsbTraceBuffer(bytesRead, m_pBuffer);
  2435. }
  2436. );
  2437. WsbTraceOut(OLESTR("CMTFSession::ReadTapeDblk"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2438. return hr;
  2439. }