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

3752 lines
110 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. NtFileIo.cpp
  5. Abstract:
  6. CNtFileIo class
  7. Author:
  8. Brian Dodd [brian] 25-Nov-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "NtFileIo.h"
  13. #include "engine.h"
  14. #include "wsbfmt.h"
  15. #include "Mll.h"
  16. #include "ntmsapi.h"
  17. #include "aclapi.h"
  18. int CNtFileIo::s_InstanceCount = 0;
  19. ////////////////////////////////////////////////////////////////////////////////
  20. //
  21. // CComObjectRoot Implementation
  22. //
  23. #pragma optimize("g", off)
  24. STDMETHODIMP
  25. CNtFileIo::FinalConstruct(void)
  26. /*++
  27. Implements:
  28. CComObjectRoot::FinalConstruct
  29. --*/
  30. {
  31. HRESULT hr = S_OK;
  32. WsbTraceIn(OLESTR("CNtFileIo::FinalConstruct"), OLESTR(""));
  33. try {
  34. WsbAffirmHr(CComObjectRoot::FinalConstruct());
  35. (void) CoCreateGuid( &m_ObjectId );
  36. m_pSession = NULL;
  37. m_DataSetNumber = 0;
  38. m_hFile = INVALID_HANDLE_VALUE;
  39. m_DeviceName = MVR_UNDEFINED_STRING;
  40. m_Flags = 0;
  41. m_LastVolume = OLESTR("");
  42. m_LastPath = OLESTR("");
  43. m_ValidLabel = TRUE;
  44. m_StreamName = MVR_UNDEFINED_STRING;
  45. m_Mode = 0;
  46. m_StreamOffset.QuadPart = 0;
  47. m_StreamSize.QuadPart = 0;
  48. m_isLocalStream = FALSE;
  49. m_OriginalAttributes = 0;
  50. m_BlockSize = DefaultBlockSize;
  51. } WsbCatch(hr);
  52. s_InstanceCount++;
  53. WsbTraceAlways(OLESTR("CNtFileIo::s_InstanceCount += %d\n"), s_InstanceCount);
  54. WsbTraceOut(OLESTR("CNtFileIo::FinalConstruct"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  55. return hr;
  56. }
  57. STDMETHODIMP
  58. CNtFileIo::FinalRelease(void)
  59. /*++
  60. Implements:
  61. CComObjectRoot::FinalRelease
  62. --*/
  63. {
  64. HRESULT hr = S_OK;
  65. WsbTraceIn(OLESTR("CNtFileIo::FinalRelease"), OLESTR(""));
  66. try {
  67. (void) CloseStream(); // in case anything is left open
  68. CComObjectRoot::FinalRelease();
  69. } WsbCatch(hr);
  70. s_InstanceCount--;
  71. WsbTraceAlways(OLESTR("CNtFileIo::s_InstanceCount -= %d\n"), s_InstanceCount);
  72. WsbTraceOut(OLESTR("CNtFileIo::FinalRelease"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  73. return hr;
  74. }
  75. #pragma optimize("", on)
  76. HRESULT
  77. CNtFileIo::CompareTo(
  78. IN IUnknown *pCollectable,
  79. OUT SHORT *pResult)
  80. /*++
  81. Implements:
  82. CRmsComObject::CompareTo
  83. --*/
  84. {
  85. HRESULT hr = E_FAIL;
  86. SHORT result = 1;
  87. WsbTraceIn( OLESTR("CNtFileIo::CompareTo"), OLESTR("") );
  88. try {
  89. // Validate arguments - Okay if pResult is NULL
  90. WsbAssertPointer( pCollectable );
  91. // We need the IRmsComObject interface to get the value of the object.
  92. CComQIPtr<IDataMover, &IID_IDataMover> pObject = pCollectable;
  93. WsbAssertPointer( pObject );
  94. GUID objectId;
  95. // Get objectId.
  96. WsbAffirmHr( pObject->GetObjectId( &objectId ));
  97. if ( m_ObjectId == objectId ) {
  98. // Object IDs match
  99. hr = S_OK;
  100. result = 0;
  101. }
  102. else {
  103. hr = S_FALSE;
  104. result = 1;
  105. }
  106. }
  107. WsbCatch( hr );
  108. if ( SUCCEEDED(hr) && (0 != pResult) ){
  109. *pResult = result;
  110. }
  111. WsbTraceOut( OLESTR("CNtFileIo::CompareTo"),
  112. OLESTR("hr = <%ls>, result = <%ls>"),
  113. WsbHrAsString( hr ), WsbPtrToShortAsString( pResult ) );
  114. return hr;
  115. }
  116. HRESULT
  117. CNtFileIo::IsEqual(
  118. IUnknown* pObject
  119. )
  120. /*++
  121. Implements:
  122. IWsbCollectable::IsEqual().
  123. --*/
  124. {
  125. HRESULT hr = S_OK;
  126. WsbTraceIn(OLESTR("CNtFileIo::IsEqual"), OLESTR(""));
  127. hr = CompareTo(pObject, NULL);
  128. WsbTraceOut(OLESTR("CNtFileIo::IsEqual"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  129. return(hr);
  130. }
  131. ////////////////////////////////////////////////////////////////////////////////
  132. //
  133. // ISupportErrorInfo Implementation
  134. //
  135. STDMETHODIMP
  136. CNtFileIo::InterfaceSupportsErrorInfo(
  137. IN REFIID riid)
  138. /*++
  139. Implements:
  140. ISupportErrorInfo::InterfaceSupportsErrorInfo
  141. --*/
  142. {
  143. static const IID* arr[] =
  144. {
  145. &IID_IDataMover,
  146. &IID_IStream,
  147. };
  148. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  149. {
  150. if (InlineIsEqualGUID(*arr[i],riid))
  151. return S_OK;
  152. }
  153. return S_FALSE;
  154. }
  155. ////////////////////////////////////////////////////////////////////////////////
  156. //
  157. // IDataMover Implementation
  158. //
  159. STDMETHODIMP
  160. CNtFileIo::GetObjectId(
  161. OUT GUID *pObjectId)
  162. /*++
  163. Implements:
  164. IRmsComObject::GetObjectId
  165. --*/
  166. {
  167. HRESULT hr = S_OK;
  168. WsbTraceIn(OLESTR("CNtFileIo::GetObjectId"), OLESTR(""));
  169. UNREFERENCED_PARAMETER(pObjectId);
  170. try {
  171. WsbAssertPointer( pObjectId );
  172. *pObjectId = m_ObjectId;
  173. } WsbCatch(hr);
  174. WsbTraceOut(OLESTR("CNtFileIo::GetObjectId"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  175. return hr;
  176. }
  177. STDMETHODIMP
  178. CNtFileIo::BeginSession(
  179. IN BSTR remoteSessionName,
  180. IN BSTR remoteSessionDescription,
  181. IN SHORT remoteDataSet,
  182. IN DWORD options)
  183. /*++
  184. Implements:
  185. IDataMover::BeginSession
  186. Notes:
  187. Each Mover session is written as a single MTF file data set. To create a consistant
  188. MTF data set we copy the MediaLabel data and use it for the TAPE DBLK for
  189. each data set generated.
  190. --*/
  191. {
  192. HRESULT hr = S_OK;
  193. CComPtr<IStream> pStream;
  194. WsbTraceIn(OLESTR("CNtFileIo::BeginSession"), OLESTR("<%ls> <%ls> <%d> <0x%08x>"),
  195. remoteSessionName, remoteSessionDescription, remoteDataSet, options);
  196. try {
  197. if (!(options & MVR_SESSION_METADATA)) {
  198. WsbAssert(remoteDataSet > 0, MVR_E_INVALIDARG);
  199. }
  200. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  201. ULARGE_INTEGER nil = {0,0};
  202. CWsbBstrPtr label, tempLabel;
  203. const ULONG maxIdSize = 1024;
  204. BYTE identifier[maxIdSize];
  205. ULONG idSize;
  206. ULONG idType;
  207. DWORD mode;
  208. // We need to read the label and use this label for each dataset created.
  209. // One data set per session. One data set per remote file.
  210. WsbAffirmHr(ReadLabel(&label));
  211. tempLabel = label;
  212. WsbAssertHr(VerifyLabel(tempLabel));
  213. // Try recovery, that is look for an indication for an incomplete data-set remote files
  214. // We continue even if Recovery fails since each data-set is kept in a separate file
  215. // Note: This code should be protected with CS when we support multiple migration to the SAME media
  216. (void) DoRecovery ();
  217. // Create the remote stream used for the entire session.
  218. // Use given remote session name as the remote file name
  219. mode = MVR_MODE_WRITE;
  220. if (options & MVR_SESSION_METADATA) {
  221. mode |= MVR_FLAG_SAFE_STORAGE;
  222. }
  223. WsbAffirmHr(CreateRemoteStream(remoteSessionName, mode, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  224. WsbAssertPointer(pStream);
  225. // Create the Recovery indicator (avoid creating for safe-storage files)
  226. // Note: the Recovery indicator just indicates that a Recovery may be required
  227. if (! (mode & MVR_FLAG_SAFE_STORAGE)) {
  228. WsbAssert(m_StreamName != MVR_UNDEFINED_STRING, MVR_E_LOGIC_ERROR);
  229. WsbAffirmHr(CreateRecoveryIndicator(m_StreamName));
  230. }
  231. // Write the TAPE DBLK and filemark
  232. WsbAffirmHr(m_pSession->DoTapeDblk(label, maxIdSize, identifier, &idSize, &idType));
  233. m_DataSetNumber = remoteDataSet;
  234. // Convert session option type bits to MTFSessionType
  235. MTFSessionType type;
  236. switch (options & MVR_SESSION_TYPES) {
  237. case MVR_SESSION_TYPE_TRANSFER:
  238. type = MTFSessionTypeTransfer;
  239. break;
  240. case MVR_SESSION_TYPE_COPY:
  241. type = MTFSessionTypeCopy;
  242. break;
  243. case MVR_SESSION_TYPE_NORMAL:
  244. type = MTFSessionTypeNormal;
  245. break;
  246. case MVR_SESSION_TYPE_DIFFERENTIAL:
  247. type = MTFSessionTypeDifferential;
  248. break;
  249. case MVR_SESSION_TYPE_INCREMENTAL:
  250. type = MTFSessionTypeIncremental;
  251. break;
  252. case MVR_SESSION_TYPE_DAILY:
  253. type = MTFSessionTypeDaily;
  254. break;
  255. default:
  256. type = MTFSessionTypeCopy;
  257. break;
  258. }
  259. // Write the SSET DBLK
  260. WsbAffirmHr(m_pSession->DoSSETDblk(remoteSessionName, remoteSessionDescription, type, remoteDataSet));
  261. } WsbCatchAndDo(hr,
  262. if (pStream) {
  263. (void) CloseStream();
  264. }
  265. );
  266. WsbTraceOut(OLESTR("CNtFileIo::BeginSession"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  267. return hr;
  268. }
  269. STDMETHODIMP
  270. CNtFileIo::EndSession(void)
  271. /*++
  272. Implements:
  273. IDataMover::EndSession
  274. --*/
  275. {
  276. HRESULT hr = S_OK;
  277. WsbTraceIn(OLESTR("CNtFileIo::EndSession"), OLESTR(""));
  278. try {
  279. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  280. // Write the trailing filemark, ESET DBLK, and filemark
  281. WsbAffirmHr(m_pSession->DoEndOfDataSet(m_DataSetNumber));
  282. } WsbCatch(hr);
  283. (void) CloseStream();
  284. if (! (m_Mode & MVR_FLAG_SAFE_STORAGE)) {
  285. WsbAssert(m_StreamName != MVR_UNDEFINED_STRING, MVR_E_LOGIC_ERROR);
  286. (void) DeleteRecoveryIndicator(m_StreamName);
  287. }
  288. // If Safe Storage flag is indicated, copy the temporary backup file to the dataset file
  289. // We copy by delete & rename (instead of copy) so if the dataset file exists, it is consistent
  290. if ((m_Mode & MVR_FLAG_SAFE_STORAGE) && (m_Mode & MVR_MODE_WRITE || m_Mode & MVR_MODE_APPEND)) {
  291. CWsbBstrPtr datasetName;
  292. int nLen, nExtLen;
  293. DWORD dwStatus;
  294. // Build dataset name
  295. nLen = wcslen(m_StreamName);
  296. nExtLen = wcslen(MVR_SAFE_STORAGE_FILETYPE);
  297. WsbAffirmHr(datasetName.TakeFrom(NULL, nLen - nExtLen + wcslen(MVR_DATASET_FILETYPE) + 1));
  298. wcsncpy(datasetName, m_StreamName, nLen-nExtLen);
  299. wcscpy(&(datasetName[nLen-nExtLen]), MVR_DATASET_FILETYPE);
  300. // No need to flush bedore Copy since flush-buffers always follows writing FILEMARKs
  301. if (! DeleteFile(datasetName)) {
  302. // DeleteFile may fail with NOT_FOUND if the dataset file is created for the first time
  303. dwStatus = GetLastError();
  304. if (ERROR_FILE_NOT_FOUND != dwStatus) {
  305. WsbAffirmNoError(dwStatus);
  306. }
  307. }
  308. WsbAffirmStatus(MoveFile(m_StreamName, datasetName));
  309. }
  310. // Clear internal data (such that another Mover Session could be started)
  311. m_Flags = 0;
  312. m_LastVolume = OLESTR("");
  313. m_LastPath = OLESTR("");
  314. m_ValidLabel = TRUE;
  315. m_isLocalStream = FALSE;
  316. m_OriginalAttributes = 0;
  317. WsbTraceOut(OLESTR("CNtFileIo::EndSession"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  318. return hr;
  319. }
  320. STDMETHODIMP
  321. CNtFileIo::StoreData(
  322. IN BSTR localName,
  323. IN ULARGE_INTEGER localDataStart,
  324. IN ULARGE_INTEGER localDataSize,
  325. IN DWORD flags,
  326. OUT ULARGE_INTEGER* pRemoteDataSetStart,
  327. OUT ULARGE_INTEGER* pRemoteFileStart,
  328. OUT ULARGE_INTEGER* pRemoteFileSize,
  329. OUT ULARGE_INTEGER* pRemoteDataStart,
  330. OUT ULARGE_INTEGER* pRemoteDataSize,
  331. OUT DWORD* pRemoteVerificationType,
  332. OUT ULARGE_INTEGER* pRemoteVerificationData,
  333. OUT DWORD* pDatastreamCRCType,
  334. OUT ULARGE_INTEGER* pDatastreamCRC,
  335. OUT ULARGE_INTEGER* pUsn)
  336. /*++
  337. Implements:
  338. IDataMover::StoreData
  339. --*/
  340. {
  341. HRESULT hr = S_OK;
  342. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  343. HANDLE hFile = INVALID_HANDLE_VALUE;
  344. WsbTraceIn(OLESTR("CNtFileIo::StoreData"), OLESTR("<%ls> <%I64u> <%I64u> <0x%08x>"),
  345. WsbAbbreviatePath((WCHAR *) localName, 120), localDataStart.QuadPart, localDataSize.QuadPart, flags);
  346. WsbTraceAlways(OLESTR("CNtFileIo::StoreData - Begin\n"));
  347. try {
  348. MvrInjectError(L"Inject.CNtFileIo::StoreData.0");
  349. WsbAssertPointer(m_pSession);
  350. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  351. // Default is to perform non-case sensitive searches.
  352. // So knock down the posix flag.
  353. m_Flags &= ~MVR_FLAG_POSIX_SEMANTICS;
  354. // Default is to not commit after each file.
  355. // So knock down the commit flag.
  356. m_Flags &= ~MVR_FLAG_COMMIT_FILE;
  357. // Default is to write one DIRB containing all directory info
  358. // instead of writing a DIRB for each directory level.
  359. // So knock down the write parent dir info flag.
  360. m_Flags &= ~MVR_FLAG_WRITE_PARENT_DIR_INFO;
  361. m_Flags |= flags;
  362. m_Flags |= MVR_MODE_WRITE;
  363. // Unconditionally set the case sensitive flag for each file.
  364. // We allow this flag to be set on a per file basis
  365. WsbTrace(OLESTR("Posix Semantics Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_POSIX_SEMANTICS & m_Flags));
  366. WsbAffirmHr(m_pSession->SetUseCaseSensitiveSearch(MVR_FLAG_POSIX_SEMANTICS & m_Flags));
  367. // This tells the session object to pad to a block boundary and flush the device
  368. // after the file is written.
  369. WsbTrace(OLESTR("Commit Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_COMMIT_FILE & m_Flags));
  370. WsbAffirmHr(m_pSession->SetCommitFile(MVR_FLAG_COMMIT_FILE & m_Flags));
  371. WsbTrace(OLESTR("ParentDirInfo Flag: <%ls>\n"), WsbBoolAsString(MVR_FLAG_WRITE_PARENT_DIR_INFO & m_Flags));
  372. if ((MVR_FLAG_BACKUP_SEMANTICS & m_Flags) || (MVR_FLAG_HSM_SEMANTICS & m_Flags)) {
  373. // Compare the volume and path with the last ones written to tape.
  374. CWsbStringPtr pathname;
  375. WCHAR *end;
  376. LONG numChar;
  377. pathname = localName;
  378. // strip off the path and file name
  379. end = wcschr((WCHAR *)pathname, L'\\');
  380. WsbAssert(end != NULL, MVR_E_INVALIDARG);
  381. numChar =(LONG)(end - (WCHAR *)pathname + 1); // keep the trailing backslash
  382. WsbAssert(numChar > 0, E_UNEXPECTED);
  383. ((WCHAR *)pathname)[numChar] = L'\0';
  384. // We do a case sensitive search if using Posix semantics.
  385. WsbTrace(OLESTR("Comparing with last volume: <%ls>\n"), WsbAbbreviatePath((WCHAR *) m_LastVolume, 120));
  386. if ( ((MVR_FLAG_POSIX_SEMANTICS & ~m_Flags)) && (0 != _wcsicmp((WCHAR *) m_LastVolume, (WCHAR *) pathname)) ||
  387. ((MVR_FLAG_POSIX_SEMANTICS & m_Flags) && (0 != wcscmp((WCHAR *) m_LastVolume, (WCHAR *) pathname))) ) {
  388. // write the VOLB DBLK
  389. WsbAffirmHr(m_pSession->DoVolumeDblk(pathname));
  390. m_LastVolume = pathname;
  391. }
  392. pathname = localName;
  393. // strip off the file name
  394. end = wcsrchr((WCHAR *)pathname, L'\\');
  395. WsbAssert(end != NULL, MVR_E_INVALIDARG);
  396. numChar = (LONG)(end - (WCHAR *)pathname);
  397. WsbAssert(numChar > 0, E_UNEXPECTED);
  398. ((WCHAR *)pathname)[numChar] = L'\0';
  399. // pathname is now in the form "Volume{guid}\dir1\...\dirn"
  400. // or "<drive letter>:\dir1\...\dirn"
  401. /***
  402. m_Flags |= MVR_FLAG_WRITE_PARENT_DIR_INFO;
  403. ***/
  404. WsbTrace(OLESTR("Comparing with last path: <%ls>\n"), WsbAbbreviatePath((WCHAR *) m_LastPath, 120));
  405. // We do a case sensitive search if using Posix semantics.
  406. if ( ((MVR_FLAG_POSIX_SEMANTICS & ~m_Flags)) && (0 != _wcsicmp((WCHAR *) m_LastPath, (WCHAR *) pathname)) ||
  407. ((MVR_FLAG_POSIX_SEMANTICS & m_Flags) && (0 != wcscmp((WCHAR *) m_LastPath, (WCHAR *) pathname))) ) {
  408. if (MVR_FLAG_HSM_SEMANTICS & m_Flags) {
  409. // We're not supporting this anymore!
  410. WsbThrow(E_NOTIMPL);
  411. WCHAR szRoot[16];
  412. // We use a flat file structure for MVR_FLAG_HSM_SEMANTICS
  413. WsbAffirmHr(m_pSession->SetUseFlatFileStructure(TRUE));
  414. // do DIRB DBLKs for root
  415. wcscpy(szRoot, L"X:\\");
  416. szRoot[0] = localName[0];
  417. WsbAffirmHr(m_pSession->DoParentDirectories(szRoot));
  418. }
  419. else if (MVR_FLAG_WRITE_PARENT_DIR_INFO & m_Flags) {
  420. // do a DIRB DBLK for each directory level of the file(s) to be backed up.
  421. WsbAffirmHr(m_pSession->DoParentDirectories(pathname));
  422. m_LastPath = pathname;
  423. }
  424. else {
  425. // do one DIRB DBLK for the whole directory structure of the file(s) to be backed up.
  426. WIN32_FIND_DATAW obFindData;
  427. CWsbStringPtr tempPath;
  428. DWORD additionalSearchFlags = 0;
  429. additionalSearchFlags |= (m_Flags & MVR_FLAG_POSIX_SEMANTICS) ? FIND_FIRST_EX_CASE_SENSITIVE : 0;
  430. tempPath = pathname;
  431. tempPath.Prepend(OLESTR("\\\\?\\"));
  432. if (NULL == wcschr((WCHAR *)tempPath+4, L'\\'))
  433. {
  434. // no path (i.e. we're at the root)
  435. BY_HANDLE_FILE_INFORMATION obGetFileInfoData;
  436. memset(&obGetFileInfoData, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
  437. tempPath.Append(OLESTR("\\"));
  438. // ** WIN32 API Calls
  439. WsbAffirmHandle(hFile = CreateFile(tempPath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
  440. WsbAffirmStatus(GetFileInformationByHandle(hFile, &obGetFileInfoData));
  441. // copy info from GetFileInformationByHandle call (BY_HANDLE_FILE_INFORMATION struct)
  442. // .. into obFindData (WIN32_FIND_DATAW struct) for DoDirectoryDblk call.
  443. memset(&obFindData, 0, sizeof(WIN32_FIND_DATAW));
  444. obFindData.dwFileAttributes = obGetFileInfoData.dwFileAttributes;
  445. obFindData.ftCreationTime = obGetFileInfoData.ftCreationTime;
  446. obFindData.ftLastAccessTime = obGetFileInfoData.ftLastAccessTime;
  447. obFindData.ftLastWriteTime = obGetFileInfoData.ftLastWriteTime;
  448. }
  449. else {
  450. // ** WIN32 API Call - gets file info
  451. WsbAffirmHandle(hSearchHandle = FindFirstFileEx((WCHAR *) tempPath, FindExInfoStandard, &obFindData, FindExSearchLimitToDirectories, 0, additionalSearchFlags));
  452. }
  453. WsbAffirmHr(m_pSession->DoDirectoryDblk((WCHAR *) pathname, &obFindData));
  454. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  455. FindClose(hSearchHandle);
  456. hSearchHandle = INVALID_HANDLE_VALUE;
  457. }
  458. if (hFile != INVALID_HANDLE_VALUE) {
  459. CloseHandle(hFile);
  460. hFile = INVALID_HANDLE_VALUE;
  461. }
  462. m_LastPath = pathname;
  463. }
  464. }
  465. }
  466. // The following uses code to store multiple files, but the
  467. // RS Hints is only valid for the last file. With the current
  468. // implementation, the HSM engine sends one file request through
  469. // StoreData at a time. The caveat is that Posix is case
  470. // sensitive, and therefore files created in this fashion could
  471. // overload the same filename (ignoring case) with multiple files.
  472. WsbAffirmHr(m_pSession->DoDataSet(localName));
  473. *pRemoteDataSetStart = m_pSession->m_sHints.DataSetStart;
  474. *pRemoteFileStart = m_pSession->m_sHints.FileStart;
  475. *pRemoteFileSize = m_pSession->m_sHints.FileSize;
  476. *pRemoteDataStart = m_pSession->m_sHints.DataStart;
  477. *pRemoteDataSize = m_pSession->m_sHints.DataSize;
  478. *pRemoteVerificationType = m_pSession->m_sHints.VerificationType;
  479. *pRemoteVerificationData = m_pSession->m_sHints.VerificationData;
  480. *pDatastreamCRCType = m_pSession->m_sHints.DatastreamCRCType;
  481. *pDatastreamCRC = m_pSession->m_sHints.DatastreamCRC;
  482. *pUsn = m_pSession->m_sHints.FileUSN;
  483. } WsbCatchAndDo(hr,
  484. if (hSearchHandle != INVALID_HANDLE_VALUE) {
  485. FindClose(hSearchHandle);
  486. hSearchHandle = INVALID_HANDLE_VALUE;
  487. }
  488. if (hFile != INVALID_HANDLE_VALUE) {
  489. CloseHandle(hFile);
  490. hFile = INVALID_HANDLE_VALUE;
  491. }
  492. WsbLogEvent(MVR_MESSAGE_DATA_TRANSFER_ERROR, 0, NULL,
  493. WsbAbbreviatePath((WCHAR *) localName, 120), WsbHrAsString(hr), NULL);
  494. // All fatal device errors are converted to E_ABORT so the calling code
  495. // can detect this general class of problem.
  496. switch(hr) {
  497. case MVR_E_BUS_RESET:
  498. case MVR_E_MEDIA_CHANGED:
  499. case MVR_E_NO_MEDIA_IN_DRIVE:
  500. case MVR_E_DEVICE_REQUIRES_CLEANING:
  501. case MVR_E_SHARING_VIOLATION:
  502. case MVR_E_ERROR_IO_DEVICE:
  503. case MVR_E_ERROR_DEVICE_NOT_CONNECTED:
  504. case MVR_E_ERROR_NOT_READY:
  505. hr = E_ABORT;
  506. break;
  507. case MVR_E_INVALID_BLOCK_LENGTH:
  508. case MVR_E_WRITE_PROTECT:
  509. case MVR_E_CRC:
  510. hr = MVR_E_MEDIA_ABORT;
  511. break;
  512. default:
  513. break;
  514. }
  515. );
  516. WsbTraceAlways(OLESTR("CNtFileIo::StoreData - End\n"));
  517. WsbTraceOut(OLESTR("CNtFileIo::StoreData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  518. return hr;
  519. }
  520. STDMETHODIMP
  521. CNtFileIo::RecallData (
  522. IN BSTR /*localName*/,
  523. IN ULARGE_INTEGER /*localDataStart*/,
  524. IN ULARGE_INTEGER /*localDataSize*/,
  525. IN DWORD /*options*/,
  526. IN BSTR /*migrateFileName*/,
  527. IN ULARGE_INTEGER /*remoteDataSetStart*/,
  528. IN ULARGE_INTEGER /*remoteFileStart*/,
  529. IN ULARGE_INTEGER /*remoteFileSize*/,
  530. IN ULARGE_INTEGER /*remoteDataStart*/,
  531. IN ULARGE_INTEGER /*remoteDataSize*/,
  532. IN DWORD /*verificationType*/,
  533. IN ULARGE_INTEGER /*verificationData*/)
  534. /*++
  535. Implements:
  536. IDataMover::RecallData
  537. --*/
  538. {
  539. HRESULT hr = S_OK;
  540. WsbTraceIn(OLESTR("CNtFileIo::RecallData"), OLESTR(""));
  541. try {
  542. WsbThrow( E_NOTIMPL );
  543. } WsbCatch(hr);
  544. WsbTraceOut(OLESTR("CNtFileIo::RecallData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  545. return hr;
  546. }
  547. STDMETHODIMP
  548. CNtFileIo::FormatLabel(
  549. IN BSTR displayName,
  550. OUT BSTR* pLabel)
  551. /*++
  552. Implements:
  553. IDataMover::FormatLabel
  554. --*/
  555. {
  556. HRESULT hr = S_OK;
  557. WsbTraceIn(OLESTR("CNtFileIo::FormatLabel"), OLESTR("<%ls>"), displayName);
  558. try {
  559. WsbAssertPointer(pLabel);
  560. WsbAssertPointer(displayName);
  561. WsbAssert(wcslen((WCHAR *)displayName) > 0, E_INVALIDARG);
  562. WsbAssertPointer(m_pCartridge);
  563. // Media Label or Description
  564. CWsbBstrPtr label;
  565. // Tag
  566. label = OLESTR("MTF Media Label"); // Required text per MTF specification.
  567. // Version
  568. WsbAffirmHr(label.Append(OLESTR("|")));
  569. WsbAffirmHr(label.Append(WsbLongAsString(MTF_FORMAT_VER_MAJOR)));
  570. WsbAffirmHr(label.Append(OLESTR(".")));
  571. WsbAffirmHr(label.Append(WsbLongAsString(MTF_FORMAT_VER_MINOR)));
  572. // Vendor
  573. WsbAffirmHr(label.Append(OLESTR("|")));
  574. WsbAffirmHr(label.Append(REMOTE_STORAGE_MTF_VENDOR_NAME));
  575. // Vendor Product ID
  576. WsbAffirmHr(label.Append(OLESTR("|")));
  577. WsbAffirmHr(label.Append(REMOTE_STORAGE_MLL_SOFTWARE_NAME));
  578. // Creation Time Stamp
  579. WsbAffirmHr(label.Append(OLESTR("|")));
  580. WCHAR timeStamp[128];
  581. time_t lTime;
  582. time(&lTime);
  583. wcsftime(timeStamp, 128, L"%Y/%m/%d.%H:%M:%S", localtime(&lTime));
  584. WsbAffirmHr(label.Append(timeStamp));
  585. // Cartridge Label
  586. WsbAffirmHr(label.Append(OLESTR("|")));
  587. if (m_pCartridge) {
  588. // Use barcode if available
  589. CWsbBstrPtr barcode;
  590. if (S_OK == m_pCartridge->GetBarcode(&barcode)) {
  591. WsbAffirmHr(label.Append(barcode));
  592. }
  593. else {
  594. WsbAffirmHr(label.Append(displayName));
  595. }
  596. }
  597. else {
  598. WsbAffirmHr(label.Append(displayName));
  599. }
  600. // Side
  601. WsbAffirmHr(label.Append(OLESTR("|")));
  602. if (m_pCartridge) {
  603. // TODO: This is broken, we need to know if the cartridge is inverted?
  604. if (S_OK == m_pCartridge->IsTwoSided()) {
  605. WsbAffirmHr(label.Append(OLESTR("2")));
  606. }
  607. else {
  608. WsbAffirmHr(label.Append(OLESTR("1")));
  609. }
  610. }
  611. else {
  612. WsbAffirmHr(label.Append(OLESTR("1"))); // Default
  613. }
  614. // Media Id
  615. GUID cartId;
  616. WsbAffirmHr(label.Append(OLESTR("|")));
  617. if (m_pCartridge) {
  618. // Use cartridge Id
  619. if (S_OK == m_pCartridge->GetCartridgeId(&cartId)) {
  620. WsbAffirmHr(label.Append(WsbGuidAsString(cartId)));
  621. }
  622. else {
  623. WsbAffirmHr(label.Append(WsbGuidAsString(GUID_NULL)));
  624. }
  625. }
  626. else {
  627. WsbAffirmHr(label.Append(WsbGuidAsString(GUID_NULL)));
  628. }
  629. // Media Domain Id
  630. GUID mediaSetId;
  631. WsbAffirmHr(label.Append(OLESTR("|")));
  632. if (m_pCartridge) {
  633. // Use MediaSet Id
  634. if (S_OK == m_pCartridge->GetMediaSetId(&mediaSetId)) {
  635. WsbAffirmHr(label.Append(WsbGuidAsString(mediaSetId)));
  636. }
  637. else {
  638. WsbAffirmHr(label.Append(WsbGuidAsString(GUID_NULL)));
  639. }
  640. }
  641. else {
  642. WsbAffirmHr(label.Append(WsbGuidAsString(GUID_NULL)));
  643. }
  644. // Vendor Specific
  645. WsbAffirmHr(label.Append(OLESTR("|VS:DisplayName=")));
  646. WsbAffirmHr(label.Append(displayName));
  647. WsbAffirmHr(label.CopyToBstr(pLabel));
  648. } WsbCatch(hr);
  649. WsbTraceOut(OLESTR("CNtFileIo::FormatLabel"), OLESTR("hr = <%ls>, label = <%ls>"), WsbHrAsString(hr), *pLabel);
  650. return hr;
  651. }
  652. STDMETHODIMP
  653. CNtFileIo::WriteLabel(
  654. IN BSTR label)
  655. /*++
  656. Implements:
  657. IDataMover::WriteLabel
  658. --*/
  659. {
  660. CComPtr<IStream> pStream;
  661. HRESULT hr = S_OK;
  662. CWsbBstrPtr DirName;
  663. PSID pAdminSID = NULL;
  664. PSID pSystemSID = NULL;
  665. PACL pACL = NULL;
  666. PSECURITY_DESCRIPTOR pSD = NULL;
  667. #define REMOTE_DIR_NUM_ACE 2
  668. EXPLICIT_ACCESS ea[REMOTE_DIR_NUM_ACE];
  669. SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
  670. SECURITY_ATTRIBUTES sa;
  671. WsbTraceIn(OLESTR("CNtFileIo::WriteLabel"), OLESTR("<%ls>"), label);
  672. try {
  673. WsbAssertPointer(label);
  674. WsbAssert(wcslen((WCHAR *)label) > 0, E_INVALIDARG);
  675. WsbAssertPointer(m_pCartridge);
  676. const ULONG maxIdSize = 1024;
  677. BYTE identifier[maxIdSize];
  678. ULONG idSize;
  679. ULONG idType;
  680. ULARGE_INTEGER nil = {0,0};
  681. // WriteLabel should be the first access to the remote media.
  682. // Therefore, some media initialization is done here:
  683. // 1) Formatting the volume
  684. // 2) Creating RSS directory
  685. // (We may consider moving this initialization part to rms unit)
  686. // Initialize volume (format in case of Removable Disk)
  687. UINT type = GetDriveType(m_DeviceName);
  688. switch (type) {
  689. case DRIVE_REMOVABLE: {
  690. // Format the volume on the media
  691. WCHAR *driveName = 0;
  692. WsbAffirmHr(m_DeviceName.CopyTo(&driveName));
  693. // Remove trailing backslash from drive name
  694. int len = wcslen(driveName);
  695. WsbAffirm(len > 0, E_UNEXPECTED);
  696. if (driveName[len-1] == OLECHAR('\\')) {
  697. driveName[len-1] = OLECHAR('\0');
  698. }
  699. // If the volume is already formatted to NTFS, perform a quick format
  700. BOOLEAN bQuickFormat = FALSE;
  701. BOOLEAN bNoFS = FALSE;
  702. WCHAR fileSystemType[MAX_PATH];
  703. if (! GetVolumeInformation((WCHAR *)m_DeviceName, NULL, 0,
  704. NULL, NULL, NULL, fileSystemType, MAX_PATH) ) {
  705. DWORD status = GetLastError();
  706. if (ERROR_UNRECOGNIZED_VOLUME == status) {
  707. status = NO_ERROR;
  708. bNoFS = TRUE;
  709. }
  710. WsbAffirmNoError(status);
  711. }
  712. if ( (! bNoFS) && (0 == wcscmp(L"NTFS", fileSystemType)) ) {
  713. bQuickFormat = TRUE;
  714. WsbTrace(OLESTR("CNtFileIo::WriteLabel: Quick formatting %ls to NTFS\n"), driveName);
  715. } else {
  716. WsbTrace(OLESTR("CNtFileIo::WriteLabel: Full formatting %ls to NTFS\n"), driveName);
  717. }
  718. hr = FormatPartition(driveName, // drive name
  719. FSTYPE_NTFS, // format to NTFS
  720. MVR_VOLUME_LABEL, // colume label
  721. WSBFMT_ENABLE_VOLUME_COMPRESSION, // enable compression
  722. bQuickFormat, // Full or Quick format
  723. TRUE, // Force format
  724. 0); // Use default allocation size
  725. WsbTrace(OLESTR("CNtFileIo::WriteLabel: Finish formatting hr=<%ls>\n"), WsbHrAsString(hr));
  726. if (! SUCCEEDED(hr)) {
  727. WsbLogEvent(MVR_MESSAGE_MEDIA_FORMAT_FAILED, 0, NULL, driveName, WsbHrAsString(hr), NULL);
  728. WsbFree(driveName);
  729. WsbAffirmHr(hr);
  730. }
  731. WsbFree(driveName);
  732. break;
  733. }
  734. case DRIVE_FIXED:
  735. // Delete files from RS remote directory
  736. WsbAffirmHr(DeleteAllData());
  737. break;
  738. case DRIVE_CDROM:
  739. case DRIVE_UNKNOWN:
  740. case DRIVE_REMOTE:
  741. case DRIVE_RAMDISK:
  742. default:
  743. WsbAssertHr(E_UNEXPECTED);
  744. break;
  745. }
  746. // Prepare security attribute for admin only access:
  747. memset(ea, 0, sizeof(EXPLICIT_ACCESS) * REMOTE_DIR_NUM_ACE);
  748. // Create a SID for the local system account
  749. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthNT, 1,
  750. SECURITY_LOCAL_SYSTEM_RID,
  751. 0, 0, 0, 0, 0, 0, 0,
  752. &pSystemSID) );
  753. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  754. // The ACE allows the Administrators group full access to the directory
  755. ea[0].grfAccessPermissions = FILE_ALL_ACCESS;
  756. ea[0].grfAccessMode = SET_ACCESS;
  757. ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  758. ea[0].Trustee.pMultipleTrustee = NULL;
  759. ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  760. ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  761. ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
  762. ea[0].Trustee.ptstrName = (LPTSTR) pSystemSID;
  763. // Create a SID for the Administrators group.
  764. WsbAssertStatus( AllocateAndInitializeSid( &SIDAuthNT, 2,
  765. SECURITY_BUILTIN_DOMAIN_RID,
  766. DOMAIN_ALIAS_RID_ADMINS,
  767. 0, 0, 0, 0, 0, 0,
  768. &pAdminSID) );
  769. // Initialize an EXPLICIT_ACCESS structure for an ACE.
  770. // The ACE allows the Administrators group full access to the directory
  771. ea[1].grfAccessPermissions = FILE_ALL_ACCESS;
  772. ea[1].grfAccessMode = SET_ACCESS;
  773. ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  774. ea[1].Trustee.pMultipleTrustee = NULL;
  775. ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  776. ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  777. ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
  778. ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID;
  779. // Create a new ACL that contains the new ACEs.
  780. WsbAffirmNoError( SetEntriesInAcl(REMOTE_DIR_NUM_ACE, ea, NULL, &pACL));
  781. // Initialize a security descriptor.
  782. pSD = (PSECURITY_DESCRIPTOR) WsbAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
  783. WsbAffirmPointer(pSD);
  784. WsbAffirmStatus(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
  785. // Add the ACL to the security descriptor.
  786. WsbAffirmStatus(SetSecurityDescriptorDacl
  787. (pSD,
  788. TRUE, // fDaclPresent flag
  789. pACL,
  790. FALSE)); // not a default DACL
  791. // Initialize a security attributes structure.
  792. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  793. sa.lpSecurityDescriptor = pSD;
  794. sa.bInheritHandle = FALSE;
  795. // Create the RSS directory with Admin Only access
  796. WsbAffirmHr(GetRemotePath(&DirName));
  797. if (! CreateDirectory(DirName, &sa)) {
  798. DWORD status = GetLastError();
  799. if ((status == ERROR_ALREADY_EXISTS) || (status == ERROR_FILE_EXISTS)) {
  800. // Directory already exists on remote media - ignore it
  801. status = NO_ERROR;
  802. }
  803. WsbAffirmNoError(status);
  804. }
  805. // Create the remote stream. Use fixed named for the media label file
  806. WsbAffirmHr(CreateRemoteStream(MVR_LABEL_FILENAME, MVR_MODE_WRITE, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  807. WsbAssertPointer(pStream);
  808. // Write the TAPE DBLK and filemark
  809. WsbAssertPointer(m_pSession);
  810. WsbAffirmHr(m_pSession->DoTapeDblk(label, maxIdSize, identifier, &idSize, &idType));
  811. WsbAffirmHr(CloseStream());
  812. pStream = NULL;
  813. // Now verify the label
  814. CWsbBstrPtr tempLabel;
  815. WsbAffirmHr(ReadLabel(&tempLabel));
  816. WsbAffirmHr(VerifyLabel(tempLabel));
  817. // Now that the tape header is written, we update the cartridge info.
  818. if (m_pCartridge) {
  819. WsbAffirmHr(m_pCartridge->SetOnMediaLabel(label));
  820. WsbAffirmHr(m_pCartridge->SetBlockSize(m_BlockSize));
  821. // For files systems we ignore the TAPE DBLK identifier, and use file system info.
  822. NTMS_FILESYSTEM_INFO fsInfo;
  823. DWORD filenameLength;
  824. DWORD fileSystemFlags;
  825. WsbAffirmStatus(GetVolumeInformation( (WCHAR *)m_DeviceName, fsInfo.VolumeName, 64,
  826. &fsInfo.SerialNumber, &filenameLength, &fileSystemFlags, fsInfo.FileSystemType, 256));
  827. WsbAffirmHr(m_pCartridge->SetOnMediaIdentifier((BYTE *)&fsInfo, sizeof(NTMS_FILESYSTEM_INFO), RmsOnMediaIdentifierWIN32));
  828. }
  829. } WsbCatchAndDo(hr,
  830. if (pStream) {
  831. (void) CloseStream();
  832. }
  833. );
  834. // Cleanup security allocations
  835. if (pAdminSID)
  836. FreeSid(pAdminSID);
  837. if (pSystemSID)
  838. FreeSid(pSystemSID);
  839. if (pACL)
  840. LocalFree(pACL);
  841. if (pSD)
  842. WsbFree(pSD);
  843. WsbTraceOut(OLESTR("CNtFileIo::WriteLabel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  844. return hr;
  845. }
  846. STDMETHODIMP
  847. CNtFileIo::ReadLabel(
  848. IN OUT BSTR* pLabel)
  849. /*++
  850. Implements:
  851. IDataMover::ReadLabel
  852. --*/
  853. {
  854. HRESULT hr = S_OK;
  855. WsbTraceIn(OLESTR("CNtFileIo::ReadLabel"), OLESTR(""));
  856. CComPtr<IStream> pStream;
  857. try {
  858. WsbAssertPointer(pLabel);
  859. WsbAssert(m_BlockSize > 0, MVR_E_LOGIC_ERROR);
  860. // Read the MTF TAPE DBLK, and pull out the label.
  861. ULARGE_INTEGER nil = {0,0};
  862. // Create remote stream of copy
  863. WsbAffirmHr(CreateRemoteStream(MVR_LABEL_FILENAME, MVR_MODE_READ | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  864. WsbAssertPointer(pStream);
  865. // Read label
  866. CWsbStringPtr label;
  867. WsbAffirmHr(m_pSession->ReadTapeDblk(&label));
  868. WsbAffirmHr(CloseStream());
  869. pStream = NULL;
  870. WsbAffirmHr(label.CopyToBstr(pLabel));
  871. } WsbCatchAndDo(hr,
  872. if (pStream) {
  873. (void) CloseStream();
  874. }
  875. );
  876. WsbTraceOut(OLESTR("CNtFileIo::ReadLabel"), OLESTR("hr = <%ls>, label = <%ls>"), WsbHrAsString(hr), *pLabel);
  877. return hr;
  878. }
  879. STDMETHODIMP
  880. CNtFileIo::VerifyLabel(
  881. IN BSTR label)
  882. /*++
  883. Implements:
  884. IDataMover::VerifyLabel
  885. --*/
  886. {
  887. HRESULT hr = S_OK;
  888. WsbTraceIn(OLESTR("CNtFileIo::VerifyLabel"), OLESTR("<%ls>"), label);
  889. GUID mediaId[2];
  890. try {
  891. WsbAssertPointer(label);
  892. WsbAssert(wcslen((WCHAR *)label) > 0, E_INVALIDARG);
  893. WsbAssertPointer(m_pCartridge);
  894. //
  895. // To verify a label we assert that the on-media Id matches the cartridge Id.
  896. //
  897. // From the media label we obtain the on-media Id.
  898. //
  899. WCHAR delim[] = OLESTR("|");
  900. WCHAR *token;
  901. int index = 0;
  902. token = wcstok((WCHAR *)label, delim); // !!! This toasts the string !!!
  903. while( token != NULL ) {
  904. index++;
  905. switch ( index ) {
  906. case 1: // Tag
  907. case 2: // Version
  908. case 3: // Vendor
  909. case 4: // Vendor Product ID
  910. case 5: // Creation Time Stamp
  911. case 6: // Cartridge Label
  912. case 7: // Side
  913. break;
  914. case 8: // Media ID
  915. WsbGuidFromString(token, &mediaId[0]);
  916. break;
  917. case 9: // Media Domain ID
  918. default: // Vendor specific of the form: L"VS:Name=Value"
  919. break;
  920. }
  921. token = wcstok( NULL, delim );
  922. }
  923. if (m_pCartridge) {
  924. //
  925. // Now compare on-media Id taken from the label to the cartridge's object Id.
  926. //
  927. WsbAffirmHr(m_pCartridge->GetCartridgeId(&mediaId[1]));
  928. WsbAffirm(mediaId[0] == mediaId[1], MVR_E_UNEXPECTED_MEDIA_ID_DETECTED);
  929. }
  930. m_ValidLabel = TRUE;
  931. } WsbCatchAndDo(hr,
  932. m_ValidLabel = FALSE;
  933. CWsbBstrPtr name;
  934. CWsbBstrPtr desc;
  935. if ( m_pCartridge ) {
  936. m_pCartridge->GetName(&name);
  937. m_pCartridge->GetDescription(&desc);
  938. }
  939. WsbLogEvent(MVR_MESSAGE_ON_MEDIA_ID_VERIFY_FAILED, 2*sizeof(GUID), mediaId,
  940. (WCHAR *) name, (WCHAR *) desc, WsbHrAsString(hr), NULL);
  941. );
  942. WsbTraceOut(OLESTR("CNtFileIo::VerifyLabel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  943. return hr;
  944. }
  945. STDMETHODIMP
  946. CNtFileIo::GetDeviceName(
  947. OUT BSTR* pName)
  948. /*++
  949. Implements:
  950. IDataMover::GetDeviceName
  951. --*/
  952. {
  953. HRESULT hr = S_OK;
  954. try {
  955. WsbAssertPointer(pName);
  956. WsbAffirmHr(m_DeviceName.CopyToBstr(pName));
  957. } WsbCatch( hr );
  958. return hr;
  959. }
  960. STDMETHODIMP
  961. CNtFileIo::SetDeviceName(
  962. IN BSTR name,
  963. IN BSTR /*unused*/)
  964. /*++
  965. Implements:
  966. IDataMover::SetDeviceName
  967. --*/
  968. {
  969. HRESULT hr = S_OK;
  970. try {
  971. WsbAssertPointer(name);
  972. m_DeviceName = name;
  973. } WsbCatch(hr);
  974. return S_OK;
  975. }
  976. STDMETHODIMP
  977. CNtFileIo::GetLargestFreeSpace(
  978. OUT LONGLONG* pFreeSpace,
  979. OUT LONGLONG* pCapacity,
  980. IN ULONG defaultFreeSpaceLow,
  981. IN LONG defaultFreeSpaceHigh
  982. )
  983. /*++
  984. Implements:
  985. IDataMover::GetLargestFreeSpace
  986. --*/
  987. {
  988. HRESULT hr = S_OK;
  989. WsbTraceIn(OLESTR("CNtFileIo::GetLargestFreeSpace"), OLESTR(""));
  990. UNREFERENCED_PARAMETER(defaultFreeSpaceLow);
  991. UNREFERENCED_PARAMETER(defaultFreeSpaceHigh);
  992. LONGLONG capacity = MAXLONGLONG;
  993. LONGLONG remaining = MAXLONGLONG;
  994. try {
  995. // Note: Fot File I/O, we currentlym always go to the file system to query
  996. // for free space and capacity and avoid internal counting like in tape.
  997. // If we want to use internal counting (IRmsStorageInfo interface of m_pCartridge),
  998. // then we need to maintain it by calling IncrementBytesWritten when appropriate
  999. ULARGE_INTEGER freeSpaceForCaller;
  1000. ULARGE_INTEGER totalCapacity;
  1001. ULARGE_INTEGER totalFreeSpace;
  1002. capacity = MAXLONGLONG;
  1003. remaining = MAXLONGLONG;
  1004. try {
  1005. // WIN32 - get disk free space
  1006. WsbAffirmStatus(GetDiskFreeSpaceEx( m_DeviceName, &freeSpaceForCaller, &totalCapacity, &totalFreeSpace));
  1007. capacity = totalCapacity.QuadPart;
  1008. remaining = freeSpaceForCaller.QuadPart;
  1009. } WsbCatchAndDo(hr,
  1010. hr = MapFileError(hr);
  1011. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, WsbHrAsString(hr), NULL);
  1012. WsbThrow(hr);
  1013. );
  1014. } WsbCatch(hr);
  1015. // Fill in the return parameters
  1016. if ( pCapacity ) {
  1017. *pCapacity = capacity;
  1018. }
  1019. if ( pFreeSpace ) {
  1020. *pFreeSpace = remaining;
  1021. }
  1022. WsbTraceOut(OLESTR("CNtFileIo::GetLargestFreeSpace"), OLESTR("hr = <%ls>, free=%I64u, capacity=%I64u"), WsbHrAsString(hr), remaining, capacity);
  1023. return hr;
  1024. }
  1025. STDMETHODIMP
  1026. CNtFileIo::SetInitialOffset(
  1027. IN ULARGE_INTEGER initialOffset
  1028. )
  1029. /*++
  1030. Implements:
  1031. IDataMover::SetInitialOffset
  1032. Notes:
  1033. Set Initial stream offset (without explicitly seeking the stream to this offset)
  1034. --*/
  1035. {
  1036. HRESULT hr = S_OK;
  1037. WsbTraceIn(OLESTR("CNtFileIo::SetInitialOffset"), OLESTR(""));
  1038. m_StreamOffset.QuadPart = initialOffset.QuadPart;
  1039. WsbTraceOut(OLESTR("CNtFileIo::SetInitialOffset"), OLESTR("hr = <%ls> offset = %I64u"), WsbHrAsString(hr), initialOffset.QuadPart);
  1040. return hr;
  1041. }
  1042. STDMETHODIMP
  1043. CNtFileIo::GetCartridge(
  1044. OUT IRmsCartridge** ptr
  1045. )
  1046. /*++
  1047. Implements:
  1048. IDataMover::GetCartridge
  1049. --*/
  1050. {
  1051. HRESULT hr = S_OK;
  1052. try {
  1053. WsbAssertPointer( ptr );
  1054. *ptr = m_pCartridge;
  1055. m_pCartridge->AddRef();
  1056. } WsbCatch( hr );
  1057. return hr;
  1058. }
  1059. STDMETHODIMP
  1060. CNtFileIo::SetCartridge(
  1061. IN IRmsCartridge* ptr
  1062. )
  1063. /*++
  1064. Implements:
  1065. IDataMover::SetCartridge
  1066. --*/
  1067. {
  1068. HRESULT hr = S_OK;
  1069. try {
  1070. WsbAssertPointer( ptr );
  1071. if ( m_pCartridge )
  1072. m_pCartridge = 0;
  1073. m_pCartridge = ptr;
  1074. } WsbCatch( hr );
  1075. return hr;
  1076. }
  1077. STDMETHODIMP
  1078. CNtFileIo::Cancel(void)
  1079. /*++
  1080. Implements:
  1081. IDataMover::Cancel
  1082. --*/
  1083. {
  1084. HRESULT hr = S_OK;
  1085. WsbTraceIn(OLESTR("CNtFileIo::Cancel"), OLESTR(""));
  1086. try {
  1087. (void) Revert();
  1088. (void) CloseStream();
  1089. } WsbCatch(hr);
  1090. WsbTraceOut(OLESTR("CNtFileIo::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1091. return hr;
  1092. }
  1093. STDMETHODIMP
  1094. CNtFileIo::CreateLocalStream(
  1095. IN BSTR name,
  1096. IN DWORD mode,
  1097. OUT IStream** ppStream)
  1098. /*++
  1099. Implements:
  1100. IDataMover::CreateLocalStream
  1101. --*/
  1102. {
  1103. HRESULT hr = S_OK;
  1104. WsbTraceIn(OLESTR("CNtFileIo::CreateLocalStream"), OLESTR(""));
  1105. try {
  1106. WsbAffirmPointer( ppStream );
  1107. WsbAffirm( mode & MVR_MODE_WRITE, E_UNEXPECTED ); // Only Recall or Restore supported this way.
  1108. FILE_BASIC_INFORMATION basicInformation;
  1109. IO_STATUS_BLOCK IoStatusBlock;
  1110. m_Mode = mode;
  1111. m_StreamName = name;
  1112. m_isLocalStream = TRUE;
  1113. m_StreamOffset.QuadPart = 0;
  1114. m_StreamSize.QuadPart = 0;
  1115. m_OriginalAttributes = GetFileAttributes(name);
  1116. if ( 0xffffffff == m_OriginalAttributes ) {
  1117. WsbAssertNoError(GetLastError());
  1118. } else if ( m_OriginalAttributes & FILE_ATTRIBUTE_READONLY ) {
  1119. //
  1120. // Set it to read/write
  1121. //
  1122. WsbAssertStatus(SetFileAttributes(m_StreamName, m_OriginalAttributes & ~FILE_ATTRIBUTE_READONLY));
  1123. }
  1124. DWORD posixFlag = (m_Mode & MVR_FLAG_POSIX_SEMANTICS) ? FILE_FLAG_POSIX_SEMANTICS : 0;
  1125. if ( m_Mode & MVR_FLAG_HSM_SEMANTICS ) {
  1126. //
  1127. // Recall - File must already exits!
  1128. //
  1129. WsbAffirmHandle(m_hFile = CreateFile(m_StreamName,
  1130. GENERIC_WRITE,
  1131. 0,
  1132. NULL,
  1133. OPEN_EXISTING,
  1134. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | posixFlag,
  1135. NULL));
  1136. //
  1137. // Mark the USN source for this handle (So content indexing knows there is no real change)
  1138. //
  1139. WsbAffirmHr(WsbMarkUsnSource(m_hFile, m_DeviceName));
  1140. } else {
  1141. //
  1142. // Restore
  1143. //
  1144. WsbAffirmHandle(m_hFile = CreateFile(m_StreamName,
  1145. GENERIC_WRITE,
  1146. 0,
  1147. NULL,
  1148. CREATE_ALWAYS,
  1149. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | posixFlag,
  1150. NULL));
  1151. }
  1152. //
  1153. // Set the time flags so that when we close the handle the
  1154. // times are not updated on the file and the FileAttributes
  1155. // indicate the file is offline
  1156. //
  1157. WsbAffirmNtStatus(NtQueryInformationFile(m_hFile,
  1158. &IoStatusBlock,
  1159. (PVOID)&basicInformation,
  1160. sizeof(basicInformation),
  1161. FileBasicInformation));
  1162. basicInformation.CreationTime.QuadPart = -1;
  1163. basicInformation.LastAccessTime.QuadPart = -1;
  1164. basicInformation.LastWriteTime.QuadPart = -1;
  1165. basicInformation.ChangeTime.QuadPart = -1;
  1166. WsbAffirmNtStatus(NtSetInformationFile(m_hFile,
  1167. &IoStatusBlock,
  1168. (PVOID)&basicInformation,
  1169. sizeof(basicInformation),
  1170. FileBasicInformation));
  1171. WsbAssertHrOk(((IUnknown*) (IDataMover*) this)->QueryInterface(IID_IStream, (void **) ppStream));
  1172. } WsbCatch(hr);
  1173. WsbTraceOut(OLESTR("CNtFileIo::CreateLocalStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1174. return hr;
  1175. }
  1176. STDMETHODIMP
  1177. CNtFileIo::CreateRemoteStream(
  1178. IN BSTR name,
  1179. IN DWORD mode,
  1180. IN BSTR remoteSessionName,
  1181. IN BSTR remoteSessionDescription,
  1182. IN ULARGE_INTEGER remoteDataSetStart,
  1183. IN ULARGE_INTEGER remoteFileStart,
  1184. IN ULARGE_INTEGER remoteFileSize,
  1185. IN ULARGE_INTEGER remoteDataStart,
  1186. IN ULARGE_INTEGER remoteDataSize,
  1187. IN DWORD remoteVerificationType,
  1188. IN ULARGE_INTEGER remoteVerificationData,
  1189. OUT IStream** ppStream)
  1190. /*++
  1191. Implements:
  1192. IDataMover::CreateRemoteStream
  1193. --*/
  1194. {
  1195. UNREFERENCED_PARAMETER(remoteSessionName);
  1196. UNREFERENCED_PARAMETER(remoteSessionDescription);
  1197. HRESULT hr = S_OK;
  1198. WsbTraceIn(OLESTR("CNtFileIo::CreateRemoteStream"), OLESTR(""));
  1199. try {
  1200. WsbAffirmPointer( ppStream );
  1201. m_Mode = mode;
  1202. WsbAffirmHr(GetRemotePath(&m_StreamName));
  1203. // Use given name as file-name here, use remoteSessionName only if name is NULL
  1204. if (name && (0 < wcslen((WCHAR *)name))) {
  1205. WsbAffirmHr(m_StreamName.Append(name));
  1206. } else {
  1207. WsbAffirmHr(m_StreamName.Append(remoteSessionName));
  1208. }
  1209. // Add file extension
  1210. // Note: In case of safe storage, we write to a temporary file.
  1211. // After a successful store, we rename the temporary file to the real file name
  1212. if ((m_Mode & MVR_FLAG_SAFE_STORAGE) && (m_Mode & MVR_MODE_WRITE || m_Mode & MVR_MODE_APPEND)) {
  1213. WsbAffirmHr(m_StreamName.Append(MVR_SAFE_STORAGE_FILETYPE));
  1214. } else {
  1215. WsbAffirmHr(m_StreamName.Append(MVR_DATASET_FILETYPE));
  1216. }
  1217. m_StreamOffset.QuadPart = 0;
  1218. m_StreamSize.QuadPart = remoteDataSize.QuadPart;
  1219. WsbTrace(OLESTR("CNtFileIo::CreateRemoteStream: Creating <%ls>\n"), (WCHAR *)m_StreamName);
  1220. if (m_Mode & MVR_FLAG_HSM_SEMANTICS || m_Mode & MVR_MODE_READ) {
  1221. //
  1222. // File must already exists!
  1223. //
  1224. DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
  1225. if (m_Mode & MVR_FLAG_NO_CACHING) {
  1226. dwFlags |= FILE_FLAG_NO_BUFFERING;
  1227. }
  1228. WsbAffirmHandle(m_hFile = CreateFile(m_StreamName,
  1229. GENERIC_READ,
  1230. FILE_SHARE_READ,
  1231. NULL,
  1232. OPEN_EXISTING,
  1233. dwFlags,
  1234. NULL));
  1235. } else if (m_Mode & MVR_MODE_RECOVER) {
  1236. //
  1237. // Open for R/W an already existsing file
  1238. //
  1239. WsbAffirmHandle(m_hFile = CreateFile(m_StreamName,
  1240. GENERIC_READ | GENERIC_WRITE,
  1241. FILE_SHARE_READ,
  1242. NULL,
  1243. OPEN_EXISTING,
  1244. FILE_ATTRIBUTE_NORMAL, // cannot use FILE_FLAG_NO_BUFFERING here !!
  1245. NULL));
  1246. } else {
  1247. //
  1248. // Create Data Set or Media Label
  1249. //
  1250. WsbAffirmHandle(m_hFile = CreateFile(m_StreamName,
  1251. GENERIC_READ | GENERIC_WRITE,
  1252. FILE_SHARE_READ,
  1253. NULL,
  1254. CREATE_ALWAYS,
  1255. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
  1256. NULL));
  1257. }
  1258. // Create and initialize an MTF Session object
  1259. CComPtr<IStream> pStream;
  1260. WsbAssertHrOk(((IUnknown*) (IDataMover*) this)->QueryInterface( IID_IStream, (void **) &pStream));
  1261. WsbAssert(NULL == m_pSession, MVR_E_LOGIC_ERROR);
  1262. m_pSession = new CMTFSession();
  1263. WsbAssertPointer(m_pSession);
  1264. m_pSession->m_pStream = pStream;
  1265. m_pSession->m_sHints.DataSetStart.QuadPart = remoteDataSetStart.QuadPart;
  1266. m_pSession->m_sHints.FileStart.QuadPart = remoteFileStart.QuadPart;
  1267. m_pSession->m_sHints.FileSize.QuadPart = remoteFileSize.QuadPart;
  1268. m_pSession->m_sHints.DataStart.QuadPart = remoteDataStart.QuadPart;
  1269. m_pSession->m_sHints.DataSize.QuadPart = remoteDataSize.QuadPart;
  1270. m_pSession->m_sHints.VerificationType = remoteVerificationType;
  1271. m_pSession->m_sHints.VerificationData.QuadPart = remoteVerificationData.QuadPart;
  1272. // Set block size according to device sector size
  1273. // (On FS-based media, the sector size is fixed, therefore we ignore the cached value in the cartridge record)
  1274. DWORD dummy1, dummy2, dummy3;
  1275. WsbAffirmStatus(GetDiskFreeSpace(m_DeviceName, &dummy1, &m_BlockSize, &dummy2, &dummy3));
  1276. WsbAssert((m_BlockSize % 512) == 0, E_UNEXPECTED);
  1277. WsbTrace( OLESTR("Setting Block Size to %d bytes/block.\n"), m_BlockSize);
  1278. // Set the Block Size used for the session.
  1279. WsbAffirmHr(m_pSession->SetBlockSize(m_BlockSize));
  1280. // Set the Block Size used for the session.
  1281. WsbAffirmHr(m_pSession->SetUseSoftFilemarks(TRUE));
  1282. if (m_Mode & MVR_MODE_APPEND) {
  1283. // Sets the current position to the end of data.
  1284. LARGE_INTEGER zero = {0,0};
  1285. WsbAffirmHr(pStream->Seek(zero, STREAM_SEEK_END, NULL));
  1286. }
  1287. *ppStream = pStream;
  1288. pStream->AddRef();
  1289. } WsbCatchAndDo(hr,
  1290. (void) CloseStream();
  1291. );
  1292. WsbTraceOut(OLESTR("CNtFileIo::CreateRemoteStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1293. return hr;
  1294. }
  1295. STDMETHODIMP
  1296. CNtFileIo::CloseStream(void)
  1297. /*++
  1298. Implements:
  1299. IDataMover::CloseStream
  1300. --*/
  1301. {
  1302. HRESULT hr = S_OK;
  1303. WsbTraceIn(OLESTR("CNtFileIo::CloseStream"), OLESTR(""));
  1304. try {
  1305. if (m_hFile != INVALID_HANDLE_VALUE) {
  1306. CloseHandle(m_hFile);
  1307. m_hFile = INVALID_HANDLE_VALUE;
  1308. }
  1309. if (m_isLocalStream) {
  1310. if (m_OriginalAttributes & FILE_ATTRIBUTE_READONLY) {
  1311. //
  1312. // Set it back to read only
  1313. WsbAssertStatus(SetFileAttributesW(m_StreamName, m_OriginalAttributes));
  1314. }
  1315. }
  1316. if (m_pSession) {
  1317. delete m_pSession;
  1318. m_pSession = NULL;
  1319. }
  1320. } WsbCatch(hr);
  1321. WsbTraceOut(OLESTR("CNtFileIo::CloseStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1322. return hr;
  1323. }
  1324. STDMETHODIMP
  1325. CNtFileIo::Duplicate(
  1326. IN IDataMover* pDestination,
  1327. IN DWORD options,
  1328. OUT ULARGE_INTEGER* pBytesCopied,
  1329. OUT ULARGE_INTEGER* pBytesReclaimed)
  1330. /*++
  1331. Implements:
  1332. IDataMover::Duplicate
  1333. Notes:
  1334. 1) The method uses an internal copy method instead of CopyFile since CopyFile makes wrong assumptions on
  1335. whether a copy is feasible based on the file-size and target volume size (ignores compression factor for example).
  1336. 2) It is assumed that for RSS data-set files, only the unnamed data stream should be copied.
  1337. Otherwise, the internal copy method that Duplicate calls for each file needs to be changed.
  1338. 3) The method uses the MVR_RECOVERY_FILETYPE files to mark (on the copy-media) a file that is
  1339. in the middle of copy. In case of a crash, the next time the function runs it will identify
  1340. such a case and delete the partial file.
  1341. --*/
  1342. {
  1343. ULARGE_INTEGER bytesCopied = {0,0};
  1344. ULARGE_INTEGER bytesReclaimed = {0,0};
  1345. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  1346. HRESULT hr = S_OK;
  1347. WsbTraceIn(OLESTR("CNtFileIo::Duplicate"), OLESTR(""));
  1348. try {
  1349. CWsbBstrPtr dirName;
  1350. CWsbBstrPtr copyDirName;
  1351. CWsbStringPtr nameSpace;
  1352. CWsbStringPtr nameSpacePrefix;
  1353. CWsbStringPtr originalFile;
  1354. CWsbStringPtr copyFile;
  1355. CWsbStringPtr specificFile;
  1356. BOOL bRefresh;
  1357. WIN32_FIND_DATA findData;
  1358. BOOL bMoreFiles = TRUE;
  1359. bRefresh = (options & MVR_DUPLICATE_REFRESH) ? TRUE : FALSE;
  1360. // Check if recovery is needed on the master media before duplicating the media
  1361. // We continue even if Recovery fails
  1362. (void) DoRecovery ();
  1363. // Get remote path of original and copy
  1364. WsbAffirmHr(GetRemotePath(&dirName));
  1365. WsbAffirmHr(pDestination->GetDeviceName(&copyDirName));
  1366. WsbAffirmHr(copyDirName.Append(MVR_RSDATA_PATH));
  1367. // Traverse directory (traverse only MTF files)
  1368. nameSpacePrefix = dirName;
  1369. WsbAffirmHr(nameSpacePrefix.Prepend(OLESTR("\\\\?\\")));
  1370. WsbAffirmHr(nameSpacePrefix.Append(OLESTR("*")));
  1371. nameSpace = nameSpacePrefix;
  1372. WsbAffirmHr(nameSpace.Append(MVR_DATASET_FILETYPE));
  1373. hSearchHandle = FindFirstFile((WCHAR *) nameSpace, &findData);
  1374. // Copy only non-existing data-set (BAG) files
  1375. while ((INVALID_HANDLE_VALUE != hSearchHandle) && bMoreFiles) {
  1376. if ( (0 == (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) &&
  1377. (0 != wcsncmp(findData.cFileName, MVR_LABEL_FILENAME, wcslen(MVR_LABEL_FILENAME))) ) {
  1378. originalFile = dirName;
  1379. WsbAffirmHr(originalFile.Append(findData.cFileName));
  1380. copyFile = copyDirName;
  1381. WsbAffirmHr(copyFile.Append(findData.cFileName));
  1382. // Test for an incomplete copy from a previous session
  1383. WsbAffirmHr(TestRecoveryIndicatorAndDeleteFile(copyFile));
  1384. // Create a recovery indicator file for crash consistency on the copy media
  1385. WsbAffirmHr(CreateRecoveryIndicator(copyFile));
  1386. // Copy
  1387. hr = InternalCopyFile(originalFile, copyFile, (! bRefresh));
  1388. // Delete the recovery indicator file
  1389. (void) DeleteRecoveryIndicator(copyFile);
  1390. if (! SUCCEEDED(hr)) {
  1391. if ( (! bRefresh) &&
  1392. ((HRESULT_CODE(hr) == ERROR_ALREADY_EXISTS) || (HRESULT_CODE(hr) == ERROR_FILE_EXISTS)) ) {
  1393. // File already exists on remote media - ignore it
  1394. hr = S_OK;
  1395. }
  1396. WsbAffirmHr(hr);
  1397. } else {
  1398. // Increase counter only if a file is really copied
  1399. bytesCopied.HighPart += findData.nFileSizeHigh;
  1400. bytesCopied.LowPart += findData.nFileSizeLow;
  1401. }
  1402. }
  1403. bMoreFiles = FindNextFile(hSearchHandle, &findData);
  1404. }
  1405. if (INVALID_HANDLE_VALUE != hSearchHandle) {
  1406. FindClose(hSearchHandle);
  1407. hSearchHandle = INVALID_HANDLE_VALUE;
  1408. }
  1409. // Copy safe-storage backup files (if exist, usually they don't)
  1410. bMoreFiles = TRUE;
  1411. nameSpace = nameSpacePrefix;
  1412. WsbAffirmHr(nameSpace.Append(MVR_SAFE_STORAGE_FILETYPE));
  1413. hSearchHandle = FindFirstFile((WCHAR *) nameSpace, &findData);
  1414. while ((INVALID_HANDLE_VALUE != hSearchHandle) && bMoreFiles) {
  1415. if ( (0 == (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) ) {
  1416. originalFile = dirName;
  1417. WsbAffirmHr(originalFile.Append(findData.cFileName));
  1418. copyFile = copyDirName;
  1419. WsbAffirmHr(copyFile.Append(findData.cFileName));
  1420. WsbAffirmHr(InternalCopyFile(originalFile, copyFile, FALSE));
  1421. }
  1422. bMoreFiles = FindNextFile(hSearchHandle, &findData);
  1423. }
  1424. // Copy specific files (currently, only HSM metadata file)
  1425. specificFile = HSM_METADATA_NAME;
  1426. WsbAffirmHr(specificFile.Append(MVR_DATASET_FILETYPE));
  1427. originalFile = dirName;
  1428. WsbAffirmHr(originalFile.Append(specificFile));
  1429. copyFile = copyDirName;
  1430. WsbAffirmHr(copyFile.Append(specificFile));
  1431. hr = InternalCopyFile(originalFile, copyFile, FALSE);
  1432. if (! SUCCEEDED(hr)) {
  1433. if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND) {
  1434. // Original file may not exist
  1435. hr = S_OK;
  1436. }
  1437. WsbAffirmHr(hr);
  1438. }
  1439. } WsbCatch(hr);
  1440. if (INVALID_HANDLE_VALUE != hSearchHandle) {
  1441. FindClose(hSearchHandle);
  1442. hSearchHandle = INVALID_HANDLE_VALUE;
  1443. }
  1444. // Set output params
  1445. if ( pBytesCopied ) {
  1446. pBytesCopied->QuadPart = bytesCopied.QuadPart;
  1447. }
  1448. if ( pBytesReclaimed ) {
  1449. pBytesReclaimed->QuadPart = bytesReclaimed.QuadPart;
  1450. }
  1451. WsbTraceOut(OLESTR("CNtFileIo::Duplicate"), OLESTR("hr = <%ls>, bytesCopied=%I64u, bytesReclaimed=%I64u"),
  1452. WsbHrAsString(hr), bytesCopied.QuadPart, bytesReclaimed.QuadPart);
  1453. return hr;
  1454. }
  1455. STDMETHODIMP
  1456. CNtFileIo::FlushBuffers(void)
  1457. /*++
  1458. Implements:
  1459. IDataMover::FlushBuffers
  1460. --*/
  1461. {
  1462. HRESULT hr = S_OK;
  1463. WsbTraceIn(OLESTR("CNtFileIo::FlushBuffers"), OLESTR(""));
  1464. try {
  1465. // Pad to the next physical block boundary and flush the filesystem buffer.
  1466. // Note: The session object calls Commit which flush the data
  1467. WsbAffirmHr(m_pSession->ExtendLastPadToNextPBA());
  1468. } WsbCatch(hr);
  1469. WsbTraceOut(OLESTR("CNtFileIo::FlushBuffers"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1470. return hr;
  1471. }
  1472. STDMETHODIMP
  1473. CNtFileIo::Recover(OUT BOOL *pDeleteFile)
  1474. /*++
  1475. Implements:
  1476. IDataMover::Recover
  1477. Notes:
  1478. Recovery is done by:
  1479. 1. Verifying existence of initial blocks
  1480. 2. Skip to data sets (FILE DNLKs)
  1481. 3. If a data set is incomplete - delete it and write FILEMARK+ESET+FILEMARK
  1482. 4. If FILEMARK is found, all the data is there, just verify and complete the FILEMARK+ESET+FILEMARK
  1483. --*/
  1484. {
  1485. HRESULT hr = S_OK;
  1486. *pDeleteFile = FALSE;
  1487. WsbTraceIn(OLESTR("CNtFileIo::Recover"), OLESTR(""));
  1488. try {
  1489. USHORT nDataSetNumber = 0;
  1490. BOOL bForceEset = FALSE;
  1491. // Check first part of the file
  1492. hr = m_pSession->SkipOverTapeDblk();
  1493. if (hr == S_OK) {
  1494. hr = m_pSession->SkipOverSSETDblk(&nDataSetNumber);
  1495. }
  1496. if (hr == S_OK) {
  1497. hr = m_pSession->SkipToDataSet();
  1498. }
  1499. if (hr == S_OK) {
  1500. hr = m_pSession->SkipOverDataSet();
  1501. }
  1502. if (hr == MVR_E_NOT_FOUND) {
  1503. // File is consistent but no remote data was written or first data written was cut
  1504. // Therefore, indicate that file can be deleted altogether and exit
  1505. *pDeleteFile = TRUE;
  1506. hr = S_OK;
  1507. WsbThrow(hr);
  1508. } else {
  1509. // Verify no other unexpected error
  1510. WsbAffirmHr(hr);
  1511. }
  1512. // Skip over data sets until they are done or we find a problem
  1513. while (TRUE) {
  1514. hr = m_pSession->SkipToDataSet();
  1515. if (hr == S_OK) {
  1516. hr = m_pSession->SkipOverDataSet();
  1517. if (hr != S_OK) {
  1518. bForceEset = TRUE;
  1519. break;
  1520. }
  1521. // No more data sets
  1522. } else {
  1523. // force re-marking end-of-set unless end-of-set was detected
  1524. if (hr != MVR_S_SETMARK_DETECTED) {
  1525. bForceEset = TRUE;
  1526. }
  1527. break;
  1528. }
  1529. }
  1530. // Whatever the error is, since we collected at least one legal data set (one
  1531. // complete migrated file), continueby terminating the file properly
  1532. // TEMPORARY: in case of an 'inconsistent' error should we ignore, terminate, log event
  1533. hr = S_OK;
  1534. // Handle end of set
  1535. if (! bForceEset) {
  1536. // Verify that end-of-data-set is complete
  1537. hr = m_pSession->SkipOverEndOfDataSet();
  1538. if (hr != S_OK) {
  1539. bForceEset = TRUE;
  1540. hr = S_OK;
  1541. }
  1542. }
  1543. if (bForceEset) {
  1544. // End-of-set is missing or incomplete
  1545. WsbAffirmHr(m_pSession->PrepareForEndOfDataSet());
  1546. WsbAffirmHr(m_pSession->DoEndOfDataSet(nDataSetNumber));
  1547. WsbAffirmStatus(SetEndOfFile(m_hFile));
  1548. }
  1549. } WsbCatch(hr);
  1550. WsbTraceOut(OLESTR("CNtFileIo::Recover"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1551. return hr;
  1552. }
  1553. ////////////////////////////////////////////////////////////////////////////////
  1554. //
  1555. // IStream Implementation
  1556. //
  1557. STDMETHODIMP
  1558. CNtFileIo::Read(
  1559. OUT void *pv,
  1560. IN ULONG cb,
  1561. OUT ULONG *pcbRead)
  1562. /*++
  1563. Implements:
  1564. IStream::Read
  1565. --*/
  1566. {
  1567. HRESULT hr = S_OK;
  1568. WsbTraceIn(OLESTR("CNtFileIo::Read"), OLESTR("Bytes Requested = %u, offset = %I64u, mode = 0x%08x"), cb, m_StreamOffset.QuadPart, m_Mode);
  1569. ULONG bytesRead = 0;
  1570. ULONG bytesToRead = 0;
  1571. try {
  1572. WsbAssert(pv != 0, STG_E_INVALIDPOINTER);
  1573. WsbAssert(FALSE == m_isLocalStream, E_UNEXPECTED);
  1574. //
  1575. // Read data from disk
  1576. //
  1577. LARGE_INTEGER loc = {0,0};
  1578. if ( MVR_MODE_UNFORMATTED & m_Mode ) {
  1579. //
  1580. // Set location according to current stream offset
  1581. // (m_StreamOffset represents here the absolute location to read from)
  1582. //
  1583. loc.QuadPart = m_StreamOffset.QuadPart;
  1584. bytesToRead = cb;
  1585. }
  1586. else if ( MVR_FLAG_HSM_SEMANTICS & m_Mode ) {
  1587. //
  1588. // Set location according to session parameters
  1589. // (m_StreamOffset represents here an offset into the actual stream-to-read)
  1590. //
  1591. loc.QuadPart = ( m_pSession->m_sHints.DataSetStart.QuadPart +
  1592. m_pSession->m_sHints.FileStart.QuadPart +
  1593. m_pSession->m_sHints.DataStart.QuadPart +
  1594. m_StreamOffset.QuadPart );
  1595. bytesToRead = cb;
  1596. }
  1597. else {
  1598. WsbThrow( E_UNEXPECTED );
  1599. }
  1600. //
  1601. // Set Position
  1602. //
  1603. WsbAffirmHr(SetPosition(loc.QuadPart));
  1604. hr = ReadBuffer((BYTE *) pv, cb, &bytesRead);
  1605. if ( FAILED(hr) ) {
  1606. WsbThrow(hr)
  1607. }
  1608. else {
  1609. switch (hr) {
  1610. case MVR_S_FILEMARK_DETECTED:
  1611. case MVR_S_SETMARK_DETECTED:
  1612. m_StreamOffset.QuadPart += (unsigned _int64) m_BlockSize;
  1613. break;
  1614. }
  1615. }
  1616. m_StreamOffset.QuadPart += bytesRead;
  1617. if ( pcbRead ) {
  1618. *pcbRead = bytesRead;
  1619. }
  1620. } WsbCatch(hr);
  1621. WsbTraceOut(OLESTR("CNtFileIo::Read"), OLESTR("hr = <%ls> bytes Read = %u, new offset = %I64u"), WsbHrAsString(hr), bytesRead, m_StreamOffset.QuadPart);
  1622. return hr;
  1623. }
  1624. STDMETHODIMP
  1625. CNtFileIo::Write(
  1626. IN void const *pv,
  1627. IN ULONG cb,
  1628. OUT ULONG *pcbWritten)
  1629. /*++
  1630. Implements:
  1631. IStream::Write
  1632. --*/
  1633. {
  1634. HRESULT hr = S_OK;
  1635. WsbTraceIn(OLESTR("CNtFileIo::Write"), OLESTR("Bytes Requested = %u, offset = %I64u, mode = 0x%08x"),
  1636. cb, m_StreamOffset.QuadPart, m_Mode);
  1637. ULONG bytesWritten = 0;
  1638. try {
  1639. WsbAssert(pv != 0, STG_E_INVALIDPOINTER);
  1640. // Consistency Check
  1641. // UINT64 pos = m_StreamOffset.QuadPart / m_BlockSize;;
  1642. // WsbAffirmHr(EnsurePosition(pos));
  1643. // UINT64 curPos;
  1644. // WsbAffirmHr(GetPosition(&curPos));
  1645. // WsbAssert(curPos == m_StreamOffset.QuadPart / m_BlockSize, E_UNEXPECTED);
  1646. WsbAffirmHr(WriteBuffer((BYTE *) pv, cb, &bytesWritten));
  1647. if (pcbWritten) {
  1648. *pcbWritten = bytesWritten;
  1649. }
  1650. m_StreamOffset.QuadPart += bytesWritten;
  1651. } WsbCatch(hr);
  1652. WsbTraceOut(OLESTR("CNtFileIo::Write"), OLESTR("hr = <%ls>, bytesWritten=%u"), WsbHrAsString(hr), bytesWritten);
  1653. return hr;
  1654. }
  1655. STDMETHODIMP
  1656. CNtFileIo::Seek(
  1657. IN LARGE_INTEGER dlibMove,
  1658. IN DWORD dwOrigin,
  1659. OUT ULARGE_INTEGER *plibNewPosition)
  1660. /*++
  1661. Implements:
  1662. IStream::Seek
  1663. --*/
  1664. {
  1665. HRESULT hr = S_OK;
  1666. WsbTraceIn(OLESTR("CNtFileIo::Seek"), OLESTR("<%I64d> <%d>"), dlibMove.QuadPart, dwOrigin);
  1667. ULARGE_INTEGER newPosition;
  1668. try {
  1669. newPosition.QuadPart = dlibMove.QuadPart;
  1670. //
  1671. // Note: Somewhere it is written that FILE_BEGIN is always and
  1672. // forever same as STREAM_SEEK_CUR, etc.
  1673. //
  1674. switch ( (STREAM_SEEK)dwOrigin ) {
  1675. case STREAM_SEEK_SET:
  1676. newPosition.LowPart = SetFilePointer(m_hFile, dlibMove.LowPart, (long *)&newPosition.HighPart, FILE_BEGIN);
  1677. if (INVALID_SET_FILE_POINTER == newPosition.LowPart) {
  1678. WsbAffirmNoError(GetLastError());
  1679. }
  1680. m_StreamOffset.QuadPart = dlibMove.QuadPart;
  1681. break;
  1682. case STREAM_SEEK_CUR:
  1683. newPosition.LowPart = SetFilePointer(m_hFile, dlibMove.LowPart, (long *)&newPosition.HighPart, FILE_CURRENT);
  1684. if (INVALID_SET_FILE_POINTER == newPosition.LowPart) {
  1685. WsbAffirmNoError(GetLastError());
  1686. }
  1687. m_StreamOffset.QuadPart += dlibMove.QuadPart;
  1688. break;
  1689. case STREAM_SEEK_END:
  1690. WsbAssert(0 == dlibMove.QuadPart, STG_E_INVALIDPARAMETER);
  1691. newPosition.LowPart = SetFilePointer(m_hFile, 0, (long *)&newPosition.HighPart, FILE_END);
  1692. if (INVALID_SET_FILE_POINTER == newPosition.LowPart) {
  1693. WsbAffirmNoError(GetLastError());
  1694. }
  1695. m_StreamOffset = newPosition;
  1696. break;
  1697. default:
  1698. WsbThrow(STG_E_INVALIDFUNCTION);
  1699. }
  1700. WsbAssert(newPosition.QuadPart == m_StreamOffset.QuadPart, MVR_E_LOGIC_ERROR);
  1701. if (plibNewPosition) {
  1702. plibNewPosition->QuadPart = newPosition.QuadPart;
  1703. }
  1704. } WsbCatch(hr);
  1705. WsbTraceOut(OLESTR("CNtFileIo::Seek"), OLESTR("hr = <%ls>, newPosition=%I64u"), WsbHrAsString(hr), newPosition.QuadPart);
  1706. return hr;
  1707. }
  1708. STDMETHODIMP
  1709. CNtFileIo::SetSize(
  1710. IN ULARGE_INTEGER /*libNewSize*/)
  1711. /*++
  1712. Implements:
  1713. IStream::SetSize
  1714. --*/
  1715. {
  1716. HRESULT hr = S_OK;
  1717. WsbTraceIn(OLESTR("CNtFileIo::SetSize"), OLESTR(""));
  1718. try {
  1719. WsbThrow(E_NOTIMPL);
  1720. } WsbCatch(hr);
  1721. WsbTraceOut(OLESTR("CNtFileIo::SetSize"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1722. return hr;
  1723. }
  1724. STDMETHODIMP
  1725. CNtFileIo::CopyTo(
  1726. IN IStream *pstm,
  1727. IN ULARGE_INTEGER cb,
  1728. OUT ULARGE_INTEGER *pcbRead,
  1729. OUT ULARGE_INTEGER *pcbWritten)
  1730. /*++
  1731. Implements:
  1732. IStream::CopyTo
  1733. Note:
  1734. A lot of the code that is implemented for Tape I/O in the Read method, is
  1735. implemented here in CopyTo, the method that alloacte the I/O buffer.
  1736. Otherwise, we would have to alloacte an internal buffer in Read and perform
  1737. double copy. In File I/O we want to avoid this for better performance.
  1738. --*/
  1739. {
  1740. HRESULT hr = S_OK;
  1741. WsbTraceIn(OLESTR("CNtFileIo::CopyTo"), OLESTR("<%I64u>"), cb.QuadPart);
  1742. ULARGE_INTEGER totalBytesRead = {0,0};
  1743. ULARGE_INTEGER totalBytesWritten = {0,0};
  1744. BYTE *pBuffer = NULL;
  1745. BYTE *pRealBuffer = NULL;
  1746. try {
  1747. WsbAssert(pstm != 0, STG_E_INVALIDPOINTER);
  1748. WsbAssert(m_BlockSize > 0, MVR_E_LOGIC_ERROR);
  1749. ULONG defaultBufferSize = DefaultMinBufferSize;
  1750. DWORD size;
  1751. OLECHAR tmpString[256];
  1752. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_BUFFER_SIZE, tmpString, 256, &size))) {
  1753. // Get the value.
  1754. LONG val = wcstol(tmpString, NULL, 10);
  1755. if (val > 0) {
  1756. defaultBufferSize = val;
  1757. }
  1758. }
  1759. ULONG bufferSize;
  1760. ULONG nBlocks = defaultBufferSize/m_BlockSize;
  1761. nBlocks = (nBlocks < 2) ? 2 : nBlocks;
  1762. bufferSize = nBlocks * m_BlockSize;
  1763. // Allocate buffer and make sure its virtual address is aligned with block size
  1764. pRealBuffer = (BYTE *) WsbAlloc(bufferSize+m_BlockSize);
  1765. if (pRealBuffer) {
  1766. if ((ULONG_PTR)pRealBuffer % m_BlockSize) {
  1767. pBuffer = pRealBuffer - ((ULONG_PTR)pRealBuffer % m_BlockSize) + m_BlockSize;
  1768. } else {
  1769. pBuffer = pRealBuffer;
  1770. }
  1771. } else {
  1772. pBuffer = NULL;
  1773. }
  1774. WsbAffirmPointer(pBuffer);
  1775. memset(pBuffer, 0, bufferSize);
  1776. ULONG bytesToRead;
  1777. ULONG bytesRead;
  1778. ULONG bytesWritten;
  1779. ULONG bytesToSkip;
  1780. ULONG bytesToCut;
  1781. ULARGE_INTEGER bytesToCopy;
  1782. bytesToCopy.QuadPart = cb.QuadPart;
  1783. while ((bytesToCopy.QuadPart > 0) && (S_OK == hr)) {
  1784. bytesToRead = 0;
  1785. bytesRead = 0;
  1786. bytesWritten = 0;
  1787. bytesToSkip = 0;
  1788. bytesToCut = 0;
  1789. if ((m_Mode & MVR_FLAG_NO_CACHING) ||
  1790. (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType )) {
  1791. // Must read additional data for alignment and/or CRC check
  1792. ULARGE_INTEGER loc = {0,0};
  1793. ULONG tempMode;
  1794. ULARGE_INTEGER offsetIntoFile;
  1795. // Set absoulte offset to read from
  1796. if ( MVR_VERIFICATION_TYPE_NONE == m_pSession->m_sHints.VerificationType ) {
  1797. // No verification - no stream header
  1798. loc.QuadPart = ( m_pSession->m_sHints.DataSetStart.QuadPart +
  1799. m_pSession->m_sHints.FileStart.QuadPart +
  1800. m_pSession->m_sHints.DataStart.QuadPart +
  1801. m_StreamOffset.QuadPart );
  1802. } else if (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType ) {
  1803. // Currently, we don't support CRC checking if you don't read from the beginning of the stream
  1804. WsbAssert(m_StreamOffset.QuadPart == 0, MVR_E_INVALIDARG);
  1805. // Position to the stream header and crc it first.
  1806. loc.QuadPart = (m_pSession->m_sHints.DataSetStart.QuadPart +
  1807. m_pSession->m_sHints.FileStart.QuadPart +
  1808. m_pSession->m_sHints.DataStart.QuadPart -
  1809. sizeof(MTF_STREAM_INFO));
  1810. bytesToSkip += sizeof(MTF_STREAM_INFO);
  1811. } else {
  1812. WsbThrow( E_UNEXPECTED );
  1813. }
  1814. // Set absolute place to read from, how many bytes to read and
  1815. // how many bytes for skipping to the actual data
  1816. offsetIntoFile.QuadPart = m_StreamOffset.QuadPart;
  1817. m_StreamOffset.QuadPart = loc.QuadPart - (loc.QuadPart % m_BlockSize);
  1818. bytesToSkip += (ULONG)(loc.QuadPart % m_BlockSize);
  1819. if (bytesToCopy.QuadPart > bufferSize) {
  1820. bytesToRead = bufferSize;
  1821. } else {
  1822. bytesToRead = bytesToCopy.LowPart;
  1823. bytesToRead += bytesToSkip;
  1824. bytesToRead = (bytesToRead < bufferSize) ? bytesToRead : bufferSize;
  1825. }
  1826. if (bytesToRead % m_BlockSize) {
  1827. // Expected only when reading the last chunk
  1828. bytesToCut = m_BlockSize - (bytesToRead % m_BlockSize);
  1829. bytesToRead = bytesToRead - (bytesToRead % m_BlockSize) + m_BlockSize;
  1830. }
  1831. // Read the aligned data in an 'unformated' Read
  1832. tempMode = m_Mode;
  1833. m_Mode |= MVR_MODE_UNFORMATTED;
  1834. hr = Read(pBuffer, bytesToRead, &bytesRead);
  1835. m_Mode = tempMode;
  1836. m_StreamOffset.QuadPart = offsetIntoFile.QuadPart;
  1837. if (FAILED(hr)) {
  1838. WsbThrow(hr);
  1839. }
  1840. if (MVR_VERIFICATION_TYPE_HEADER_CRC == m_pSession->m_sHints.VerificationType ) {
  1841. // Peform the CRC check
  1842. // If for some unexpected reason not enough bytes are read, we skip the CRC check
  1843. if (bytesToSkip <= bytesRead) {
  1844. MTF_STREAM_INFO sSTREAM;
  1845. CMTFApi::MTF_ReadStreamHeader(&sSTREAM, &(pBuffer[bytesToSkip-sizeof(MTF_STREAM_INFO)]));
  1846. try {
  1847. // Make sure it is the correct type of header
  1848. WsbAffirm((0 == memcmp(sSTREAM.acStreamId, MTF_STANDARD_DATA_STREAM, 4)), MVR_E_UNEXPECTED_DATA);
  1849. // Verify the stream header checksum
  1850. WsbAffirm((m_pSession->m_sHints.VerificationData.QuadPart == sSTREAM.uCheckSum), MVR_E_UNEXPECTED_DATA);
  1851. } catch (HRESULT catchHr) {
  1852. hr = catchHr;
  1853. // Log a detailed error
  1854. // Give as attached data the beginning of the buffer which usually contains the FILE DBLK + Stream Info
  1855. CWsbBstrPtr name;
  1856. CWsbBstrPtr desc;
  1857. if (m_pCartridge) {
  1858. m_pCartridge->GetName(&name);
  1859. m_pCartridge->GetDescription(&desc);
  1860. }
  1861. WCHAR location[32];
  1862. WCHAR offset[16];
  1863. WCHAR mark[8];
  1864. WCHAR found[16];
  1865. swprintf(found, L"0x%04x", sSTREAM.uCheckSum);
  1866. swprintf(location, L"%I64u", m_StreamOffset.QuadPart);
  1867. swprintf(offset, L"%lu", bytesToSkip - sizeof(MTF_STREAM_INFO));
  1868. swprintf(mark, L"0");
  1869. WsbLogEvent(MVR_MESSAGE_UNEXPECTED_DATA,
  1870. bytesToSkip, pBuffer,
  1871. found, (WCHAR *)name, (WCHAR *)desc,
  1872. location, offset, mark, NULL);
  1873. WsbThrow(hr);
  1874. }
  1875. }
  1876. // CRC check is done only once
  1877. m_pSession->m_sHints.VerificationType = MVR_VERIFICATION_TYPE_NONE;
  1878. }
  1879. // Set file offset, handle unexpected cases where bytesRead<bytesToRead
  1880. if (bytesToCut) {
  1881. if ((bytesToRead - bytesRead) < bytesToCut) {
  1882. bytesToCut = bytesToCut - (bytesToRead - bytesRead);
  1883. } else {
  1884. bytesToCut = 0;
  1885. }
  1886. }
  1887. if (bytesRead > bytesToSkip) {
  1888. m_StreamOffset.QuadPart += (bytesRead - (bytesToSkip+bytesToCut));
  1889. }
  1890. } else {
  1891. // May read only actual data (no alignments) - let default Read to do its job
  1892. bytesToRead = (bytesToCopy.QuadPart < bufferSize) ? bytesToCopy.LowPart : bufferSize;
  1893. hr = Read(pBuffer, bytesToRead, &bytesRead);
  1894. if (FAILED(hr)) {
  1895. WsbThrow(hr);
  1896. }
  1897. }
  1898. // Write the data in the output stream and calculate totals
  1899. if (bytesRead > (bytesToSkip+bytesToCut)) {
  1900. totalBytesRead.QuadPart += (bytesRead - (bytesToSkip+bytesToCut));
  1901. WsbAffirmHrOk(pstm->Write(pBuffer+bytesToSkip, bytesRead - (bytesToSkip+bytesToCut), &bytesWritten));
  1902. totalBytesWritten.QuadPart += bytesWritten;
  1903. bytesToCopy.QuadPart -= (bytesRead - (bytesToSkip+bytesToCut));
  1904. }
  1905. }
  1906. if (pcbRead) {
  1907. pcbRead->QuadPart = totalBytesRead.QuadPart;
  1908. }
  1909. if (pcbWritten) {
  1910. pcbWritten->QuadPart = totalBytesWritten.QuadPart;
  1911. }
  1912. } WsbCatch(hr);
  1913. if (pRealBuffer) {
  1914. WsbFree(pRealBuffer);
  1915. pRealBuffer = NULL;
  1916. pBuffer = NULL;
  1917. }
  1918. WsbTraceOut(OLESTR("CNtFileIo::CopyTo"), OLESTR("hr = <%ls>, bytesRead=%I64u, bytesWritten=%I64u"),
  1919. WsbHrAsString(hr), totalBytesRead.QuadPart, totalBytesWritten.QuadPart);
  1920. return hr;
  1921. }
  1922. STDMETHODIMP
  1923. CNtFileIo::Commit(
  1924. IN DWORD grfCommitFlags)
  1925. /*++
  1926. Implements:
  1927. IStream::Commit
  1928. --*/
  1929. {
  1930. HRESULT hr = S_OK;
  1931. WsbTraceIn(OLESTR("CNtFileIo::Commit"), OLESTR(""));
  1932. try {
  1933. if (STGC_DEFAULT == grfCommitFlags) {
  1934. WsbAssertStatus(FlushFileBuffers(m_hFile));
  1935. }
  1936. else {
  1937. WsbThrow(E_NOTIMPL);
  1938. }
  1939. } WsbCatch(hr);
  1940. WsbTraceOut(OLESTR("CNtFileIo::Commit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1941. return hr;
  1942. }
  1943. STDMETHODIMP
  1944. CNtFileIo::Revert(void)
  1945. /*++
  1946. Implements:
  1947. IStream::Revert
  1948. --*/
  1949. {
  1950. HRESULT hr = S_OK;
  1951. WsbTraceIn(OLESTR("CNtFileIo::Revert"), OLESTR(""));
  1952. try {
  1953. // TEMPORARY: Setting the mode to 0 currently doesn't prevent any write
  1954. // which is ongoing. We need to re-visit this issue
  1955. m_Mode = 0;
  1956. } WsbCatch(hr);
  1957. WsbTraceOut(OLESTR("CNtFileIo::Revert"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1958. return hr;
  1959. }
  1960. STDMETHODIMP
  1961. CNtFileIo::LockRegion(
  1962. IN ULARGE_INTEGER /*libOffset*/,
  1963. IN ULARGE_INTEGER /*cb*/,
  1964. IN DWORD /*dwLockType*/)
  1965. /*++
  1966. Implements:
  1967. IStream::LockRegion
  1968. --*/
  1969. {
  1970. HRESULT hr = S_OK;
  1971. WsbTraceIn(OLESTR("CNtFileIo::LockRegion"), OLESTR(""));
  1972. try {
  1973. WsbThrow(E_NOTIMPL);
  1974. } WsbCatch(hr);
  1975. WsbTraceOut(OLESTR("CNtFileIo::LockRegion"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1976. return hr;
  1977. }
  1978. STDMETHODIMP
  1979. CNtFileIo::UnlockRegion(
  1980. IN ULARGE_INTEGER /*libOffset*/,
  1981. IN ULARGE_INTEGER /*cb*/,
  1982. IN DWORD /*dwLockType*/)
  1983. /*++
  1984. Implements:
  1985. IStream::UnlockRegion
  1986. --*/
  1987. {
  1988. HRESULT hr = S_OK;
  1989. WsbTraceIn(OLESTR("CNtFileIo::UnlockRegion"), OLESTR(""));
  1990. try {
  1991. WsbThrow(E_NOTIMPL);
  1992. } WsbCatch(hr);
  1993. WsbTraceOut(OLESTR("CNtFileIo::UnlockRegion"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1994. return hr;
  1995. }
  1996. STDMETHODIMP
  1997. CNtFileIo::Stat(
  1998. OUT STATSTG * /*pstatstg*/,
  1999. IN DWORD /*grfStatFlag*/)
  2000. /*++
  2001. Implements:
  2002. IStream::Stat
  2003. --*/
  2004. {
  2005. HRESULT hr = S_OK;
  2006. WsbTraceIn(OLESTR("CNtFileIo::Stat"), OLESTR(""));
  2007. try {
  2008. WsbThrow(E_NOTIMPL);
  2009. } WsbCatch(hr);
  2010. WsbTraceOut(OLESTR("CNtFileIo::Stat"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2011. return hr;
  2012. }
  2013. STDMETHODIMP
  2014. CNtFileIo::Clone(
  2015. OUT IStream ** /*ppstm*/)
  2016. /*++
  2017. Implements:
  2018. IStream::Clone
  2019. --*/
  2020. {
  2021. HRESULT hr = S_OK;
  2022. WsbTraceIn(OLESTR("CNtFileIo::Clone"), OLESTR(""));
  2023. try {
  2024. WsbThrow(E_NOTIMPL);
  2025. } WsbCatch(hr);
  2026. WsbTraceOut(OLESTR("CNtFileIo::Clone"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2027. return hr;
  2028. }
  2029. ////////////////////////////////////////////////////////////////////////////////
  2030. //
  2031. // Local Methods
  2032. //
  2033. HRESULT
  2034. CNtFileIo::WriteBuffer(
  2035. IN BYTE *pBuffer,
  2036. IN ULONG nBytesToWrite,
  2037. OUT ULONG *pBytesWritten)
  2038. /*++
  2039. Routine Description:
  2040. Used to write all MTF data. Guarantees full blocks are written.
  2041. Arguments:
  2042. pBuffer - Data buffer.
  2043. nBytesToWrite - number of bytes to write in buffer.
  2044. pBytesWritten - Bytes written.
  2045. Return Value:
  2046. S_OK - Success.
  2047. --*/
  2048. {
  2049. HRESULT hr = S_OK;
  2050. try {
  2051. if (!m_isLocalStream) {
  2052. // Must have a valid label!
  2053. WsbAffirm(TRUE == m_ValidLabel, E_ABORT);
  2054. // Making sure that we are writting only full blocks
  2055. WsbAssert(!(nBytesToWrite % m_BlockSize), MVR_E_LOGIC_ERROR);
  2056. }
  2057. try {
  2058. // ** WIN32 Tape API Call - write the data
  2059. WsbAffirmStatus(WriteFile(m_hFile, pBuffer, nBytesToWrite, pBytesWritten, 0));
  2060. } WsbCatchAndDo(hr,
  2061. hr = MapFileError(hr);
  2062. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, WsbHrAsString(hr), NULL);
  2063. );
  2064. if (!m_isLocalStream) {
  2065. // Making sure that we have written only full blocks
  2066. WsbAssert(!(*pBytesWritten % m_BlockSize), E_UNEXPECTED);
  2067. }
  2068. } WsbCatch(hr);
  2069. return hr;
  2070. }
  2071. HRESULT
  2072. CNtFileIo::ReadBuffer (
  2073. IN BYTE *pBuffer,
  2074. IN ULONG nBytesToRead,
  2075. OUT ULONG *pBytesRead)
  2076. /*++
  2077. Routine Description:
  2078. Used to read all MTF data. Guarantees full blocks are read.
  2079. Arguments:
  2080. pBuffer - Data buffer.
  2081. nBytesToRead - number of bytes to read into buffer.
  2082. pBytesRead - Bytes read.
  2083. Return Value:
  2084. S_OK - Success.
  2085. --*/
  2086. {
  2087. HRESULT hr = S_OK;
  2088. try {
  2089. // For FileSystem I/O restrictions on reading only full blocks depends on how
  2090. // the file is opened. Therefore, we don't enforce it here.
  2091. try {
  2092. // ** WIN32 Tape API Call - read the data
  2093. WsbAffirmStatus(ReadFile(m_hFile, pBuffer, nBytesToRead, pBytesRead, 0));
  2094. } WsbCatchAndDo(hr,
  2095. hr = MapFileError(hr);
  2096. if ( FAILED(hr) ) {
  2097. WsbLogEvent(MVR_MESSAGE_DEVICE_ERROR, 0, NULL, WsbHrAsString(hr), NULL);
  2098. WsbThrow(hr);
  2099. }
  2100. );
  2101. } WsbCatch(hr);
  2102. return hr;
  2103. }
  2104. HRESULT
  2105. CNtFileIo::GetPosition(
  2106. OUT UINT64 *pPosition)
  2107. /*++
  2108. Routine Description:
  2109. Returns the current physical block address relative the current partition.
  2110. Arguments:
  2111. pPostion - Receives the current physical block address.
  2112. Return Value:
  2113. S_OK - Success.
  2114. --*/
  2115. {
  2116. HRESULT hr = S_OK;
  2117. WsbTraceIn(OLESTR("CNtFileIo::GetPosition"), OLESTR(""));
  2118. try {
  2119. WsbThrow(E_NOTIMPL);
  2120. } WsbCatch(hr);
  2121. WsbTraceOut(OLESTR("CNtFileIo::GetPosition"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), *pPosition);
  2122. return hr;
  2123. }
  2124. HRESULT
  2125. CNtFileIo::SetPosition(
  2126. IN UINT64 position)
  2127. /*++
  2128. Routine Description:
  2129. Mover to the specified physical block address relative the current partition.
  2130. Arguments:
  2131. postion - The physical block address to position to.
  2132. Return Value:
  2133. S_OK - Success.
  2134. --*/
  2135. {
  2136. HRESULT hr = S_OK;
  2137. WsbTraceIn(OLESTR("CNtFileIo::SetPosition"), OLESTR("<%I64u>"), position);
  2138. ULARGE_INTEGER newPosition;
  2139. try {
  2140. newPosition.QuadPart = position;
  2141. newPosition.LowPart = SetFilePointer(m_hFile, newPosition.LowPart, (long *)&newPosition.HighPart, FILE_BEGIN);
  2142. if (INVALID_SET_FILE_POINTER == newPosition.LowPart) {
  2143. WsbAffirmNoError(GetLastError());
  2144. }
  2145. } WsbCatch(hr);
  2146. WsbTraceOut(OLESTR("CNtFileIo::SetPosition"), OLESTR("hr = <%ls>, pos=%I64u"), WsbHrAsString(hr), newPosition.QuadPart);
  2147. return hr;
  2148. }
  2149. HRESULT
  2150. CNtFileIo::EnsurePosition(
  2151. IN UINT64 position)
  2152. /*++
  2153. Routine Description:
  2154. Checks that the tape is positioned at the specified current physical block
  2155. address relative to the current partition. If it is not an attempt is made
  2156. to recover to the specified position.
  2157. Arguments:
  2158. postion - The physical block address to verify.
  2159. Return Value:
  2160. S_OK - Success.
  2161. --*/
  2162. {
  2163. HRESULT hr = S_OK;
  2164. WsbTraceIn(OLESTR("CNtFileIo::EnsurePosition"), OLESTR("<%I64u>"), position);
  2165. try {
  2166. WsbThrow(E_NOTIMPL);
  2167. } WsbCatch(hr);
  2168. WsbTraceOut(OLESTR("CNtFileIo::EnsurePosition"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2169. return hr;
  2170. }
  2171. HRESULT
  2172. CNtFileIo::GetRemotePath(
  2173. OUT BSTR *pDestinationString)
  2174. {
  2175. HRESULT hr = S_OK;
  2176. WsbTraceIn(OLESTR("CNtFileIo::GetRemotePath"), OLESTR(""));
  2177. try {
  2178. CWsbBstrPtr tmpString;
  2179. tmpString = m_DeviceName;
  2180. WsbAffirmHr(tmpString.Append(MVR_RSDATA_PATH));
  2181. WsbTrace(OLESTR("RemotePath is <%ls>\n"), (WCHAR *) tmpString);
  2182. // Hand over the string
  2183. WsbAffirmHr(tmpString.CopyToBstr(pDestinationString));
  2184. } WsbCatch(hr);
  2185. WsbTraceOut(OLESTR("CNtFileIo::GetRemotePath"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2186. return hr;
  2187. }
  2188. HRESULT
  2189. CNtFileIo::DoRecovery(void)
  2190. {
  2191. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  2192. HRESULT hr = S_OK;
  2193. WsbTraceIn(OLESTR("CNtFileIo::DoRecovery"), OLESTR(""));
  2194. try {
  2195. CWsbBstrPtr dirName;
  2196. CWsbStringPtr nameSpace;
  2197. CWsbStringPtr recoveredFile;
  2198. WIN32_FIND_DATA findData;
  2199. BOOL bMoreFiles = TRUE;
  2200. // Traverse remote directory for Recovery Indicator files
  2201. WsbAffirmHr(GetRemotePath(&dirName));
  2202. nameSpace = dirName;
  2203. WsbAffirmHr(nameSpace.Append(OLESTR("*")));
  2204. WsbAffirmHr(nameSpace.Append(MVR_RECOVERY_FILETYPE));
  2205. nameSpace.Prepend(OLESTR("\\\\?\\"));
  2206. hSearchHandle = FindFirstFile((WCHAR *) nameSpace, &findData);
  2207. while ((INVALID_HANDLE_VALUE != hSearchHandle) && bMoreFiles) {
  2208. CComPtr<IDataMover> pMover;
  2209. CComPtr<IStream> pStream;
  2210. CWsbBstrPtr recoveryName;
  2211. ULARGE_INTEGER nil = {0,0};
  2212. int nLen, nExtLen;
  2213. BOOL bDeleteFile = FALSE;
  2214. CWsbBstrPtr name;
  2215. CWsbBstrPtr desc;
  2216. // Prepare file name to recover
  2217. nLen = wcslen(findData.cFileName);
  2218. nExtLen = wcslen(MVR_RECOVERY_FILETYPE);
  2219. WsbAffirmHr(recoveryName.TakeFrom(NULL, nLen - nExtLen + 1));
  2220. wcsncpy(recoveryName, findData.cFileName, nLen-nExtLen);
  2221. recoveryName[nLen-nExtLen] = NULL;
  2222. // Recover - a failure to recover in file doesn't stop from trying to recover others
  2223. try {
  2224. if ( m_pCartridge ) {
  2225. m_pCartridge->GetName(&name);
  2226. m_pCartridge->GetDescription(&desc);
  2227. }
  2228. WsbLogEvent(MVR_MESSAGE_INCOMPLETE_DATA_SET_DETECTED, 0, NULL,
  2229. (WCHAR *)recoveryName, (WCHAR *) name, (WCHAR *) desc, NULL);
  2230. // Create and initializa a data mover
  2231. WsbAssertHr(CoCreateInstance(CLSID_CNtFileIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)&pMover));
  2232. WsbAffirmHr(pMover->SetDeviceName(m_DeviceName));
  2233. WsbAffirmHr(pMover->SetCartridge(m_pCartridge));
  2234. // Create the stream for Recovery
  2235. WsbAffirmHr(pMover->CreateRemoteStream(recoveryName, MVR_MODE_RECOVER | MVR_MODE_UNFORMATTED, L"",L"",nil,nil,nil,nil,nil,0,nil, &pStream));
  2236. // Perform the actual recovery over the file
  2237. WsbAffirmHr(pMover->Recover(&bDeleteFile));
  2238. (void) pMover->CloseStream();
  2239. pStream = NULL;
  2240. if (bDeleteFile) {
  2241. // Delete the remote file itself
  2242. recoveredFile = dirName;
  2243. WsbAffirmHr(recoveredFile.Append(recoveryName));
  2244. WsbAffirmHr(recoveredFile.Append(MVR_DATASET_FILETYPE));
  2245. WsbTrace(OLESTR("CNtFileIo::DoRecovery: Nothing to recover in <%ls> - Deleting file!\n"), (WCHAR *)recoveredFile);
  2246. WsbAffirmStatus(DeleteFile(recoveredFile));
  2247. }
  2248. WsbLogEvent(MVR_MESSAGE_DATA_SET_RECOVERED, 0, NULL, NULL);
  2249. } WsbCatchAndDo (hr,
  2250. if (pStream) {
  2251. (void) pMover->CloseStream();
  2252. pStream = NULL;
  2253. }
  2254. WsbLogEvent(MVR_MESSAGE_DATA_SET_NOT_RECOVERABLE, 0, NULL, WsbHrAsString(hr), NULL);
  2255. hr = S_OK;
  2256. );
  2257. // Create (for deleting) full name of indicator file
  2258. recoveredFile = dirName;
  2259. WsbAffirmHr(recoveredFile.Append(findData.cFileName));
  2260. // Get next file
  2261. bMoreFiles = FindNextFile(hSearchHandle, &findData);
  2262. // Delete indicator file (independent of the recovery result)
  2263. WsbAffirmStatus(DeleteFile(recoveredFile));
  2264. }
  2265. } WsbCatch(hr);
  2266. if (INVALID_HANDLE_VALUE != hSearchHandle) {
  2267. FindClose(hSearchHandle);
  2268. }
  2269. WsbTraceOut(OLESTR("CNtFileIo::DoRecovery"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2270. return hr;
  2271. }
  2272. HRESULT
  2273. CNtFileIo::CreateRecoveryIndicator(IN WCHAR *pFileName)
  2274. /*++
  2275. Implements:
  2276. CNtFileIo::CreateRecoveryIndicator
  2277. Notes:
  2278. The method assumes that the input file name ends with MVR_DATASET_FILETYPE !!
  2279. Otherwise, it fails with E_UNEXPECTED
  2280. --*/
  2281. {
  2282. HRESULT hr = S_OK;
  2283. WsbTraceIn(OLESTR("CNtFileIo::CreateRecoveryIndicator"), OLESTR(""));
  2284. try {
  2285. CWsbStringPtr recoveryName;
  2286. int nLen, nExtLen;
  2287. HANDLE hFile;
  2288. // Generate file name
  2289. nLen = wcslen(pFileName);
  2290. nExtLen = wcslen(MVR_DATASET_FILETYPE);
  2291. WsbAssert(nLen > nExtLen, E_UNEXPECTED);
  2292. WsbAssert(0 == wcscmp(&(pFileName[nLen-nExtLen]), MVR_DATASET_FILETYPE), E_UNEXPECTED);
  2293. WsbAffirmHr(recoveryName.TakeFrom(NULL, nLen - nExtLen + wcslen(MVR_RECOVERY_FILETYPE) + 1));
  2294. wcsncpy(recoveryName, pFileName, nLen-nExtLen);
  2295. wcscpy(&(recoveryName[nLen-nExtLen]), MVR_RECOVERY_FILETYPE);
  2296. //Create and immediately close the file
  2297. WsbAffirmHandle(hFile = CreateFile(recoveryName,
  2298. GENERIC_READ,
  2299. FILE_SHARE_READ,
  2300. NULL,
  2301. CREATE_ALWAYS,
  2302. FILE_ATTRIBUTE_HIDDEN,
  2303. NULL));
  2304. CloseHandle(hFile);
  2305. } WsbCatch(hr);
  2306. WsbTraceOut(OLESTR("CNtFileIo::CreateRecoveryIndicator"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2307. return hr;
  2308. }
  2309. HRESULT
  2310. CNtFileIo::DeleteRecoveryIndicator(IN WCHAR *pFileName)
  2311. /*++
  2312. Implements:
  2313. CNtFileIo::DeleteRecoveryIndicator
  2314. Notes:
  2315. The method assumes that the input file name ends with MVR_DATASET_FILETYPE !!
  2316. Otherwise, it fails with E_UNEXPECTED
  2317. --*/
  2318. {
  2319. HRESULT hr = S_OK;
  2320. WsbTraceIn(OLESTR("CNtFileIo::DeleteRecoveryIndicator"), OLESTR(""));
  2321. try {
  2322. CWsbStringPtr recoveryName;
  2323. int nLen, nExtLen;
  2324. // Generate file name
  2325. nLen = wcslen(pFileName);
  2326. nExtLen = wcslen(MVR_DATASET_FILETYPE);
  2327. WsbAssert(nLen > nExtLen, E_UNEXPECTED);
  2328. WsbAssert(0 == wcscmp(&(pFileName[nLen-nExtLen]), MVR_DATASET_FILETYPE), E_UNEXPECTED);
  2329. WsbAffirmHr(recoveryName.TakeFrom(NULL, nLen - nExtLen + wcslen(MVR_RECOVERY_FILETYPE) + 1));
  2330. wcsncpy(recoveryName, pFileName, nLen-nExtLen);
  2331. wcscpy(&(recoveryName[nLen-nExtLen]), MVR_RECOVERY_FILETYPE);
  2332. //Delete the indicator file
  2333. WsbAffirmStatus(DeleteFile(recoveryName));
  2334. } WsbCatch(hr);
  2335. WsbTraceOut(OLESTR("CNtFileIo::DeleteRecoveryIndicator"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2336. return hr;
  2337. }
  2338. HRESULT
  2339. CNtFileIo::TestRecoveryIndicatorAndDeleteFile(IN WCHAR *pFileName)
  2340. /*++
  2341. Implements:
  2342. CNtFileIo::TestRecoveryIndicatorAndDeleteFile
  2343. Notes:
  2344. The method assumes that the input file name ends with MVR_DATASET_FILETYPE !!
  2345. Otherwise, it fails with E_UNEXPECTED
  2346. The method:
  2347. 1) Test if the recovery indicator for the given file exists
  2348. 2) If so, it deletes the file
  2349. 3) Then, it deleted the recovery indicator
  2350. Returns:
  2351. S_OK - If found a recovery indicator and deleted successfully
  2352. S_FALSE - If didn't find a recovery indicator
  2353. --*/
  2354. {
  2355. HRESULT hr = S_FALSE;
  2356. WsbTraceIn(OLESTR("CNtFileIo::TestRecoveryIndicatorAndDeleteFile"), OLESTR(""));
  2357. try {
  2358. CWsbStringPtr recoveryName;
  2359. int nLen, nExtLen;
  2360. // Generate recovery-indicator file name
  2361. nLen = wcslen(pFileName);
  2362. nExtLen = wcslen(MVR_DATASET_FILETYPE);
  2363. WsbAssert(nLen > nExtLen, E_UNEXPECTED);
  2364. WsbAssert(0 == wcscmp(&(pFileName[nLen-nExtLen]), MVR_DATASET_FILETYPE), E_UNEXPECTED);
  2365. WsbAffirmHr(recoveryName.TakeFrom(NULL, nLen - nExtLen + wcslen(MVR_RECOVERY_FILETYPE) + 1));
  2366. wcsncpy(recoveryName, pFileName, nLen-nExtLen);
  2367. wcscpy(&(recoveryName[nLen-nExtLen]), MVR_RECOVERY_FILETYPE);
  2368. // Test recovery indicator file existance
  2369. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  2370. WIN32_FIND_DATA findData;
  2371. hSearchHandle = FindFirstFile(recoveryName, &findData);
  2372. if (INVALID_HANDLE_VALUE != hSearchHandle) {
  2373. FindClose(hSearchHandle);
  2374. hr = S_OK;
  2375. WsbTrace(OLESTR("CNtFileIo::TestRecoveryIndicator... : Found recovery indicator. Therefore, deleting <%ls>\n"),
  2376. pFileName);
  2377. //Delete the target file itself
  2378. WsbAffirmStatus(DeleteFile(pFileName));
  2379. //Delete the indicator file
  2380. WsbAffirmStatus(DeleteFile(recoveryName));
  2381. }
  2382. } WsbCatch(hr);
  2383. WsbTraceOut(OLESTR("CNtFileIo::TestRecoveryIndicatorAndDeleteFile"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2384. return hr;
  2385. }
  2386. HRESULT
  2387. CNtFileIo::DeleteAllData(void)
  2388. {
  2389. HRESULT hr = S_OK;
  2390. HANDLE hSearchHandle = INVALID_HANDLE_VALUE;
  2391. WsbTraceIn(OLESTR("CNtFileIo::DeleteAllData"), OLESTR(""));
  2392. try {
  2393. CWsbStringPtr nameSpace;
  2394. CWsbStringPtr pathname;
  2395. WIN32_FIND_DATAW obFindData;
  2396. BOOL bMoreFiles;
  2397. CWsbBstrPtr remotePath;
  2398. WsbAffirmHr(GetRemotePath(&remotePath));
  2399. nameSpace = remotePath;
  2400. nameSpace.Append(OLESTR("*.*"));
  2401. nameSpace.Prepend(OLESTR("\\\\?\\"));
  2402. hSearchHandle = FindFirstFileEx((WCHAR *) nameSpace, FindExInfoStandard, &obFindData, FindExSearchNameMatch, 0, 0);
  2403. for (bMoreFiles = TRUE;
  2404. hSearchHandle != INVALID_HANDLE_VALUE && bMoreFiles;
  2405. bMoreFiles = FindNextFileW(hSearchHandle, &obFindData)) {
  2406. if ((obFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  2407. // use the remotePath to get the pathname, then append the filename
  2408. pathname = remotePath;
  2409. pathname.Prepend(OLESTR("\\\\?\\"));
  2410. pathname.Append(obFindData.cFileName);
  2411. WsbAffirmStatus(DeleteFile((WCHAR *)pathname));
  2412. }
  2413. }
  2414. } WsbCatch(hr);
  2415. // close search handle after processing all the files
  2416. if (INVALID_HANDLE_VALUE != hSearchHandle) {
  2417. FindClose(hSearchHandle);
  2418. hSearchHandle = INVALID_HANDLE_VALUE;
  2419. }
  2420. WsbTraceOut(OLESTR("CNtFileIo::DeleteAllData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2421. return hr;
  2422. }
  2423. HRESULT
  2424. CNtFileIo::FormatDrive(
  2425. IN BSTR label)
  2426. /*++
  2427. Routine Description:
  2428. Formats a unit of media.
  2429. Arguments:
  2430. label - The formatted label returned from FormatLabel().
  2431. Return Value:
  2432. S_OK - Success.
  2433. E_ABORT - Operation aborted.
  2434. --*/
  2435. {
  2436. HRESULT hr = S_OK;
  2437. WsbTraceIn(OLESTR("CNtFileIo::FormatDrive"), OLESTR("<%ls>"), (WCHAR *)label);
  2438. PROCESS_INFORMATION exeInfo;
  2439. STARTUPINFO startupInfo;
  2440. memset(&startupInfo, 0, sizeof(startupInfo));
  2441. startupInfo.cb = sizeof( startupInfo );
  2442. startupInfo.wShowWindow = SW_HIDE;
  2443. startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  2444. try {
  2445. //
  2446. // Get volumeLabel for the FS from the label parameter
  2447. //
  2448. CWsbBstrPtr volumeLabel = MVR_UNDEFINED_STRING;
  2449. CWsbBstrPtr tempLabel = label;
  2450. WCHAR delim[] = OLESTR("|");
  2451. WCHAR *token;
  2452. int index=0;
  2453. token = wcstok( (WCHAR *)tempLabel, delim );
  2454. while( token != NULL ) {
  2455. index++;
  2456. switch ( index ) {
  2457. case 1: // Tag
  2458. case 2: // Version
  2459. case 3: // Vendor
  2460. case 4: // Vendor Product ID
  2461. case 5: // Creation Time Stamp
  2462. case 6: // Cartridge Label
  2463. case 7: // Side
  2464. case 8: // Media ID
  2465. case 9: // Media Domain ID
  2466. default: // Vendor specific of the form L"VS:Name=Value"
  2467. {
  2468. WCHAR *name = NULL;
  2469. int nameLen = 0;
  2470. // DisplayName
  2471. name = L"VS:DisplayName=";
  2472. nameLen = wcslen(name);
  2473. if( 0 == wcsncmp(token, name, nameLen) ) {
  2474. volumeLabel = &token[nameLen];
  2475. }
  2476. }
  2477. break;
  2478. }
  2479. token = wcstok( NULL, delim );
  2480. }
  2481. // Build the format command with options:
  2482. // "Format d: /fs:ntfs /force /q /x /v:ROOT_D > Null:"
  2483. OLECHAR drive[256];
  2484. (void) wcsncpy((WCHAR *)drive, (WCHAR *)m_DeviceName, 2);
  2485. drive[2] = '\0'; // TODO: Fix for no drive letter support
  2486. // NOTE: It's possible that the format command isn't where we
  2487. // think it is. The following registry entry allows
  2488. // an override.
  2489. CWsbBstrPtr formatCmd = RMS_DEFAULT_FORMAT_COMMAND;
  2490. DWORD size;
  2491. OLECHAR tmpString[256];
  2492. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FORMAT_COMMAND, tmpString, 256, &size))) {
  2493. // Get the value.
  2494. formatCmd = tmpString;
  2495. }
  2496. WsbTrace(OLESTR("Using command: <%ls>.\n"), (WCHAR *)formatCmd);
  2497. WsbAffirmHr(formatCmd.Append(L" "));
  2498. WsbAffirmHr(formatCmd.Append(drive));
  2499. CWsbBstrPtr commandLine = formatCmd;
  2500. CWsbBstrPtr formatOpts = RMS_DEFAULT_FORMAT_OPTIONS;
  2501. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FORMAT_OPTIONS, tmpString, 256, &size))) {
  2502. // Get the value.
  2503. formatOpts = tmpString;
  2504. }
  2505. WsbTrace(OLESTR("Using options: <%ls>.\n"), (WCHAR *)formatOpts);
  2506. DWORD formatWaitTime = RMS_DEFAULT_FORMAT_WAIT_TIME;
  2507. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FORMAT_WAIT_TIME, tmpString, 256, &size))) {
  2508. // Get the value.
  2509. formatWaitTime = wcstol(tmpString, NULL, 10);
  2510. }
  2511. WsbTrace(OLESTR("Using wait time: %d.\n"), formatWaitTime);
  2512. int retry = 0;
  2513. do {
  2514. try {
  2515. WsbAffirm(0 == wcslen((WCHAR *)formatOpts), E_UNEXPECTED);
  2516. WsbAffirmHr(commandLine.Append(L" "));
  2517. WsbAffirmHr(commandLine.Append(formatOpts));
  2518. WsbAffirmHr(commandLine.Append(L" /v:"));
  2519. WsbAffirmHr(commandLine.Append(volumeLabel));
  2520. WsbAffirmHr(commandLine.Append(L" > Null:"));
  2521. WsbTrace(OLESTR("Using command: <%ls> to format media.\n"), (WCHAR *)commandLine);
  2522. WsbAffirmStatus(CreateProcess(0, (WCHAR *)commandLine, 0, 0, FALSE, 0, 0, 0, &startupInfo, &exeInfo));
  2523. WsbAffirmStatus(WAIT_FAILED != WaitForSingleObject(exeInfo.hProcess, 20*60*1000));
  2524. break;
  2525. } WsbCatchAndDo(hr,
  2526. retry++;
  2527. commandLine = formatCmd;
  2528. if (retry == 1) {
  2529. formatOpts = RMS_DEFAULT_FORMAT_OPTIONS_ALT1;
  2530. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FORMAT_OPTIONS_ALT1, tmpString, 256, &size))) {
  2531. // Get the value.
  2532. formatOpts = tmpString;
  2533. }
  2534. }
  2535. else if (retry == 2) {
  2536. formatOpts = RMS_DEFAULT_FORMAT_OPTIONS_ALT2;
  2537. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_FORMAT_OPTIONS_ALT2, tmpString, 256, &size))) {
  2538. // Get the value.
  2539. formatOpts = tmpString;
  2540. }
  2541. }
  2542. else {
  2543. WsbThrow(hr);
  2544. }
  2545. WsbTrace(OLESTR("Retrying with otions: <%ls>.\n"), (WCHAR *)formatOpts);
  2546. );
  2547. } while (retry < 3);
  2548. } WsbCatch(hr);
  2549. if (FAILED(hr)) {
  2550. hr = E_ABORT;
  2551. }
  2552. WsbTraceOut(OLESTR("CNtFileIo::FormatDrive"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2553. return hr;
  2554. }
  2555. HRESULT
  2556. CNtFileIo::MapFileError(
  2557. IN HRESULT hrToMap)
  2558. /*++
  2559. Routine Description:
  2560. Maps a WIN32 file error, specified as an HRESULT, to a MVR error.
  2561. Arguments:
  2562. hrToMap - WIN32 file error to map.
  2563. Return Value:
  2564. S_OK - Success.
  2565. MVR_E_BEGINNING_OF_MEDIA - The beginning of the tape or a partition was encountered.
  2566. MVR_E_BUS_RESET - The I/O bus was reset.
  2567. MVR_E_END_OF_MEDIA - The physical end of the tape has been reached.
  2568. MVR_S_FILEMARK_DETECTED - A tape access reached a filemark.
  2569. MVR_S_SETMARK_DETECTED - A tape access reached the end of a set of files.
  2570. MVR_S_NO_DATA_DETECTED - No more data is on the tape.
  2571. MVR_E_PARTITION_FAILURE - Tape could not be partitioned.
  2572. MVR_E_INVALID_BLOCK_LENGTH - When accessing a new tape of a multivolume partition, the current blocksize is incorrect.
  2573. MVR_E_DEVICE_NOT_PARTITIONED - Tape partition information could not be found when loading a tape.
  2574. MVR_E_MEDIA_CHANGED - The media in the drive may have changed.
  2575. MVR_E_NO_MEDIA_IN_DRIVE - No media in drive.
  2576. MVR_E_UNABLE_TO_LOCK_MEDIA - Unable to lock the media eject mechanism.
  2577. MVR_E_UNABLE_TO_UNLOAD_MEDIA - Unable to unload the media.
  2578. MVR_E_WRITE_PROTECT - The media is write protected.
  2579. MVR_E_CRC - Data error (cyclic redundancy check).
  2580. MVR_E_SHARING_VIOLATION - The process cannot access the file because it is being used by another process.
  2581. MVR_E_ERROR_IO_DEVICE - The request could not be performed because of an I/O device error. - Unknown error.
  2582. MVE_E_ERROR_DEVICE_NOT_CONNECTED - The device is not connected.
  2583. MVR_E_DISK_FULL - There is insufficient disk space to complete the operation.
  2584. E_ABORT - Unknown error, abort.
  2585. --*/
  2586. {
  2587. HRESULT hr = S_OK;
  2588. WsbTraceIn(OLESTR("CNtFileIo::MapFileError"), OLESTR("<%ls>"), WsbHrAsString(hrToMap));
  2589. try {
  2590. // The valid label flag is knocked down when the media may have changed
  2591. // or device parameters (i.e. block size) may have been reset.
  2592. switch ( hrToMap ) {
  2593. case S_OK:
  2594. break;
  2595. case HRESULT_FROM_WIN32( ERROR_BEGINNING_OF_MEDIA ):
  2596. hr = MVR_E_BEGINNING_OF_MEDIA;
  2597. break;
  2598. case HRESULT_FROM_WIN32( ERROR_BUS_RESET ):
  2599. hr = MVR_E_BUS_RESET;
  2600. m_ValidLabel = FALSE;
  2601. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, WsbHrAsString(hr), NULL);
  2602. break;
  2603. case HRESULT_FROM_WIN32( ERROR_END_OF_MEDIA ):
  2604. hr = MVR_E_END_OF_MEDIA;
  2605. break;
  2606. case HRESULT_FROM_WIN32( ERROR_FILEMARK_DETECTED ): // Maps to Success
  2607. hr = MVR_S_FILEMARK_DETECTED;
  2608. break;
  2609. case HRESULT_FROM_WIN32( ERROR_SETMARK_DETECTED ): // Maps to Success
  2610. hr = MVR_S_SETMARK_DETECTED;
  2611. break;
  2612. case HRESULT_FROM_WIN32( ERROR_NO_DATA_DETECTED ): // Maps to Success
  2613. // EOD
  2614. // This happens on SpaceFilemarks() past end of data.
  2615. hr = MVR_S_NO_DATA_DETECTED;
  2616. break;
  2617. case HRESULT_FROM_WIN32( ERROR_PARTITION_FAILURE ):
  2618. hr = MVR_E_PARTITION_FAILURE;
  2619. break;
  2620. case HRESULT_FROM_WIN32( ERROR_INVALID_BLOCK_LENGTH ):
  2621. hr = MVR_E_INVALID_BLOCK_LENGTH;
  2622. break;
  2623. case HRESULT_FROM_WIN32( ERROR_DEVICE_NOT_PARTITIONED ):
  2624. hr = MVR_E_DEVICE_NOT_PARTITIONED;
  2625. break;
  2626. case HRESULT_FROM_WIN32( ERROR_MEDIA_CHANGED ):
  2627. hr = MVR_E_MEDIA_CHANGED;
  2628. m_ValidLabel = FALSE;
  2629. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, WsbHrAsString(hr), NULL);
  2630. break;
  2631. case HRESULT_FROM_WIN32( ERROR_NO_MEDIA_IN_DRIVE ):
  2632. hr = MVR_E_NO_MEDIA_IN_DRIVE;
  2633. m_ValidLabel = FALSE;
  2634. WsbLogEvent(MVR_MESSAGE_MEDIA_NOT_VALID, 0, NULL, WsbHrAsString(hr), NULL);
  2635. break;
  2636. case HRESULT_FROM_WIN32( ERROR_UNABLE_TO_LOCK_MEDIA ):
  2637. hr = MVR_E_UNABLE_TO_LOCK_MEDIA;
  2638. break;
  2639. case HRESULT_FROM_WIN32( ERROR_UNABLE_TO_UNLOAD_MEDIA ):
  2640. hr = MVR_E_UNABLE_TO_UNLOAD_MEDIA;
  2641. break;
  2642. case HRESULT_FROM_WIN32( ERROR_WRITE_PROTECT ):
  2643. hr = MVR_E_WRITE_PROTECT;
  2644. break;
  2645. case HRESULT_FROM_WIN32( ERROR_CRC ):
  2646. // This is may indicate that the drive needs cleaning.
  2647. hr = MVR_E_CRC;
  2648. break;
  2649. case HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION ):
  2650. // This happens when the CreateFile fails because the device is in use by some other app.
  2651. hr = MVR_E_SHARING_VIOLATION;
  2652. break;
  2653. case HRESULT_FROM_WIN32( ERROR_IO_DEVICE ):
  2654. // This happens when the device is turned off during I/O, for example.
  2655. hr = MVR_E_ERROR_IO_DEVICE;
  2656. break;
  2657. case HRESULT_FROM_WIN32( ERROR_DEVICE_NOT_CONNECTED ):
  2658. // This happens when the device is turned off.
  2659. hr = MVR_E_ERROR_DEVICE_NOT_CONNECTED;
  2660. break;
  2661. case HRESULT_FROM_WIN32( ERROR_SEM_TIMEOUT ):
  2662. // This happens when the SCSI command does not return within the timeout period. A system error is logged for the SCSI controler (adapter).
  2663. hr = MVR_E_ERROR_DEVICE_NOT_CONNECTED;
  2664. break;
  2665. case HRESULT_FROM_WIN32( ERROR_DISK_FULL ):
  2666. // There is not enough space on the disk.
  2667. hr = MVR_E_DISK_FULL;
  2668. break;
  2669. case HRESULT_FROM_WIN32( ERROR_UNRECOGNIZED_VOLUME ):
  2670. // This happens when the volume is not formatted to any file system
  2671. hr = MVR_E_UNRECOGNIZED_VOLUME;
  2672. break;
  2673. case HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE ):
  2674. // This happens after a Cancel() operation.
  2675. hr = E_ABORT;
  2676. break;
  2677. default:
  2678. WsbThrow(hrToMap);
  2679. }
  2680. } WsbCatchAndDo(hr,
  2681. WsbLogEvent(MVR_MESSAGE_UNKNOWN_DEVICE_ERROR, 0, NULL, WsbHrAsString(hr), NULL);
  2682. hr = E_ABORT;
  2683. );
  2684. WsbTraceOut(OLESTR("CNtFileIo::MapFileError"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2685. return hr;
  2686. }
  2687. HRESULT
  2688. CNtFileIo::InternalCopyFile(
  2689. IN WCHAR *pOriginalFileName,
  2690. IN WCHAR *pCopyFileName,
  2691. IN BOOL bFailIfExists)
  2692. /*++
  2693. Implements:
  2694. CNtFileIo::InternalCopyFile
  2695. Notes:
  2696. 1) The method copies only the unnamed data stream using Read/Write.
  2697. Currently this is sufficient for RSS .bkf files on a media, however, if we ever use
  2698. other-than-default file characteristics like named streams, per-file security attributes,
  2699. special file attributes, etc. - then we should consider using BackupRead & BackupWrite
  2700. for implementing the internal-copy
  2701. 2) If caller ask for bFailIfExists=TRUE, then the method returns HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)
  2702. 3) In case of a failure half way through, the method deletes the partial file
  2703. --*/
  2704. {
  2705. HRESULT hr = S_OK;
  2706. HANDLE hOriginal = INVALID_HANDLE_VALUE;
  2707. HANDLE hCopy = INVALID_HANDLE_VALUE;
  2708. BYTE *pBuffer = NULL;
  2709. WsbTraceIn(OLESTR("CNtFileIo::InternalCopyFile"), OLESTR(""));
  2710. try {
  2711. // Create file on the Original media with no write-sharing - upper level should ensure
  2712. // that nobody opens the file for write while a copy-media is going on
  2713. WsbAffirmHandle(hOriginal = CreateFile(pOriginalFileName,
  2714. GENERIC_READ,
  2715. FILE_SHARE_READ,
  2716. NULL,
  2717. OPEN_EXISTING,
  2718. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  2719. NULL));
  2720. // Create the file on the Copy media with no sharing at all. Create-disposition
  2721. // depends on caller request
  2722. // Exisitng file would generate ERROR_FILE_EXISTS that should be handled by the caller
  2723. DWORD dwCreationDisposition;
  2724. dwCreationDisposition = bFailIfExists ? CREATE_NEW : CREATE_ALWAYS;
  2725. WsbAffirmHandle(hCopy = CreateFile(pCopyFileName,
  2726. GENERIC_WRITE,
  2727. 0, // no sharing
  2728. NULL,
  2729. dwCreationDisposition,
  2730. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  2731. NULL));
  2732. // Allocate a buffer for the media copy
  2733. ULONG defaultBufferSize = RMS_DEFAULT_BUFFER_SIZE;
  2734. DWORD size;
  2735. OLECHAR tmpString[256];
  2736. if (SUCCEEDED(WsbGetRegistryValueString(NULL, RMS_REGISTRY_STRING, RMS_PARAMETER_COPY_BUFFER_SIZE, tmpString, 256, &size))) {
  2737. // Get the value.
  2738. LONG val = wcstol(tmpString, NULL, 10);
  2739. if (val > 0) {
  2740. defaultBufferSize = val;
  2741. }
  2742. }
  2743. pBuffer = (BYTE *)WsbAlloc(defaultBufferSize);
  2744. WsbAffirmAlloc(pBuffer);
  2745. // Read and write in chunks
  2746. // Synchronous ReadFile should signal eof by returning zero bytes read
  2747. BOOL done = FALSE;
  2748. DWORD dwBytesToRead = defaultBufferSize;
  2749. DWORD dwBytesRead, dwBytesWritten;
  2750. while (! done) {
  2751. WsbAffirmStatus(ReadFile(hOriginal, pBuffer, dwBytesToRead, &dwBytesRead, NULL));
  2752. if (dwBytesRead == 0) {
  2753. // eof
  2754. done = TRUE;
  2755. } else {
  2756. // Write to copy-file
  2757. WsbAffirmStatus(WriteFile(hCopy, pBuffer, dwBytesRead, &dwBytesWritten, NULL));
  2758. if (dwBytesWritten != dwBytesRead) {
  2759. // Fail the copy
  2760. WsbTraceAlways(OLESTR("CNtFileIo::InternalCopyFile: writing to copy-file is not completed to-write=%lu, written=%lu - Aborting!\n"),
  2761. dwBytesRead, dwBytesWritten);
  2762. WsbThrow(E_FAIL);
  2763. }
  2764. }
  2765. }
  2766. // Flush to media
  2767. WsbAffirmStatus(FlushFileBuffers(hCopy));
  2768. } WsbCatch(hr);
  2769. // Close original file
  2770. if (INVALID_HANDLE_VALUE != hOriginal) {
  2771. CloseHandle(hOriginal);
  2772. hOriginal = INVALID_HANDLE_VALUE;
  2773. }
  2774. // Close copy file
  2775. if (INVALID_HANDLE_VALUE != hCopy) {
  2776. if (! CloseHandle(hCopy)) {
  2777. DWORD dwErr = GetLastError();
  2778. WsbTrace(OLESTR("CNtFileIo::InternalCopyFile: CloseHandle for copy-file failed with error=%lu\n"), dwErr);
  2779. // Set hr only if there was a success so far...
  2780. if (SUCCEEDED(hr)) {
  2781. hr = HRESULT_FROM_WIN32(dwErr);
  2782. }
  2783. }
  2784. hCopy = INVALID_HANDLE_VALUE;
  2785. // Delete copy file on any error, including close errors
  2786. if (! SUCCEEDED(hr)) {
  2787. WsbTrace(OLESTR("CNtFileIo::InternalCopyFile: Deleting copy-file <%s> due to an error during the copy\n"),
  2788. pCopyFileName);
  2789. if (! DeleteFile(pCopyFileName)) {
  2790. DWORD dwErr = GetLastError();
  2791. WsbTrace(OLESTR("CNtFileIo::InternalCopyFile: Failed to delete copy-file, DeleteFile error=%lu\n"), dwErr);
  2792. }
  2793. }
  2794. }
  2795. if (pBuffer) {
  2796. WsbFree(pBuffer);
  2797. pBuffer = NULL;
  2798. }
  2799. WsbTraceOut(OLESTR("CNtFileIo::InternalCopyFile"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2800. return hr;
  2801. }