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

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