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

572 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. filestream.cpp
  5. Abstract:
  6. Implementation of IStream over a win32 file.
  7. Author:
  8. Michael J. Grier (MGrier) 23-Feb-2000
  9. Revision History:
  10. --*/
  11. #include "stdinc.h"
  12. #include <windows.h>
  13. #include "sxsp.h"
  14. #include "filestream.h"
  15. #include "SxsExceptionHandling.h"
  16. CFileStreamBase::CFileStreamBase() : m_cRef(0), m_hFile(INVALID_HANDLE_VALUE), m_grfMode(0)
  17. {
  18. }
  19. CFileStreamBase::~CFileStreamBase()
  20. {
  21. ASSERT_NTC(m_cRef == 0);
  22. if (m_hFile != INVALID_HANDLE_VALUE)
  23. {
  24. CSxsPreserveLastError ple;
  25. if ((m_grfMode & STGM_WRITE) == STGM_WRITE)
  26. ::FlushFileBuffers(m_hFile);
  27. ::CloseHandle(m_hFile);
  28. ple.Restore();
  29. }
  30. }
  31. BOOL
  32. CFileStreamBase::OpenForWrite(
  33. PCWSTR pszPath,
  34. DWORD dwShareMode,
  35. DWORD dwCreationDisposition,
  36. DWORD dwFlagsAndAttributes
  37. )
  38. {
  39. BOOL fSuccess = FALSE;
  40. FN_TRACE_WIN32(fSuccess);
  41. PARAMETER_CHECK(pszPath != NULL);
  42. INTERNAL_ERROR_CHECK(m_hFile == INVALID_HANDLE_VALUE);
  43. IFW32INVALIDHANDLE_ORIGINATE_AND_EXIT(
  44. m_hFile = ::CreateFileW(
  45. pszPath,
  46. GENERIC_WRITE,
  47. dwShareMode,
  48. NULL,
  49. dwCreationDisposition, // default value is CREATE_ALWAYS
  50. dwFlagsAndAttributes,
  51. NULL));
  52. m_grfMode = STGM_WRITE | STGM_CREATE;
  53. FN_EPILOG
  54. }
  55. BOOL
  56. CFileStreamBase::OpenForRead(
  57. PCWSTR pszPath,
  58. const CImpersonationData &ImpersonationData,
  59. DWORD dwShareMode,
  60. DWORD dwCreationDisposition,
  61. DWORD dwFlagsAndAttributes
  62. )
  63. {
  64. DWORD dwWin32Error;
  65. return
  66. this->OpenForRead(
  67. pszPath,
  68. ImpersonationData,
  69. dwShareMode,
  70. dwCreationDisposition,
  71. dwFlagsAndAttributes,
  72. dwWin32Error,
  73. 0);
  74. }
  75. BOOL
  76. CFileStreamBase::OpenForRead(
  77. PCWSTR pszPath,
  78. const CImpersonationData &ImpersonationData,
  79. DWORD dwShareMode,
  80. DWORD dwCreationDisposition,
  81. DWORD dwFlagsAndAttributes,
  82. DWORD &rdwLastError,
  83. SIZE_T cExceptionalLastErrors,
  84. ...
  85. )
  86. {
  87. BOOL fSuccess = FALSE;
  88. FN_TRACE_WIN32(fSuccess);
  89. DWORD dwLastError = ERROR_INTERNAL_ERROR;
  90. CImpersonate impersonate(ImpersonationData);
  91. rdwLastError = ERROR_SUCCESS;
  92. PARAMETER_CHECK(pszPath != NULL);
  93. INTERNAL_ERROR_CHECK(m_hFile == INVALID_HANDLE_VALUE);
  94. IFW32FALSE_EXIT(impersonate.Impersonate());
  95. ::FusionpSetLastWin32Error(ERROR_SUCCESS);
  96. m_hFile = ::CreateFileW(
  97. pszPath,
  98. GENERIC_READ,
  99. dwShareMode,
  100. NULL,
  101. dwCreationDisposition,
  102. dwFlagsAndAttributes,
  103. NULL);
  104. dwLastError = ::FusionpGetLastWin32Error();
  105. IFW32FALSE_EXIT(impersonate.Unimpersonate());
  106. m_grfMode = STGM_READ;
  107. if (m_hFile == INVALID_HANDLE_VALUE)
  108. {
  109. va_list ap;
  110. SIZE_T i = 0;
  111. if (dwLastError == ERROR_SUCCESS)
  112. {
  113. //
  114. // CreateFile always set lasterror to be 0 for an unexisted file even OPEN_EXISTING
  115. // for GENERIC_READ, Fusion expect ERROR_FILE_NOT_FOUND in this case for some reason
  116. //
  117. ::FusionpSetLastWin32Error(ERROR_FILE_NOT_FOUND);
  118. dwLastError = ERROR_FILE_NOT_FOUND; // reset lLastError
  119. }
  120. va_start(ap, cExceptionalLastErrors);
  121. for (i=0; i<cExceptionalLastErrors; i++)
  122. {
  123. if (dwLastError == va_arg(ap, DWORD))
  124. {
  125. rdwLastError = dwLastError;
  126. break;
  127. }
  128. }
  129. va_end(ap);
  130. if (i == cExceptionalLastErrors) // This gets the cExceptionalLastErrors == 0 case too.
  131. {
  132. ::FusionpDbgPrintEx(
  133. FUSION_DBG_LEVEL_ERROR,
  134. "SXS.DLL: %s(%ls) gave error %ld\n",
  135. __FUNCTION__,
  136. pszPath,
  137. dwLastError);
  138. ORIGINATE_WIN32_FAILURE_AND_EXIT(CreateFileW, dwLastError);
  139. }
  140. }
  141. FN_EPILOG
  142. }
  143. BOOL
  144. CFileStreamBase::Close()
  145. {
  146. BOOL fSuccess = FALSE;
  147. FN_TRACE_WIN32(fSuccess);
  148. if (m_hFile != INVALID_HANDLE_VALUE)
  149. {
  150. if ((m_grfMode & STGM_WRITE) == STGM_WRITE)
  151. {
  152. if (!::FlushFileBuffers(m_hFile))
  153. {
  154. ::FusionpDbgPrintEx(
  155. FUSION_DBG_LEVEL_ERROR,
  156. "SXS.DLL: %s - Error flushing file handle %p; win32 error = %ld\n", __FUNCTION__, m_hFile, ::FusionpGetLastWin32Error());
  157. CSxsPreserveLastError ple;
  158. ::CloseHandle(m_hFile);
  159. ple.Restore();
  160. m_hFile = INVALID_HANDLE_VALUE;
  161. goto Exit;
  162. }
  163. }
  164. if (!::CloseHandle(m_hFile))
  165. {
  166. ::FusionpDbgPrintEx(
  167. FUSION_DBG_LEVEL_ERROR,
  168. "SXS.DLL: Error closing file handle %p; ::FusionpGetLastWin32Error() = %d\n", m_hFile, ::FusionpGetLastWin32Error());
  169. m_hFile = INVALID_HANDLE_VALUE;
  170. goto Exit;
  171. }
  172. m_hFile = INVALID_HANDLE_VALUE;
  173. }
  174. fSuccess = TRUE;
  175. Exit:
  176. return fSuccess;
  177. }
  178. ULONG
  179. CFileStreamBase::AddRef()
  180. {
  181. ULONG ulResult = 0;
  182. FN_TRACE_ADDREF(CFileStreamBase, ulResult);
  183. ulResult = ::InterlockedIncrement((LONG *) &m_cRef);
  184. return ulResult;
  185. }
  186. ULONG
  187. CFileStreamBase::Release()
  188. {
  189. ULONG ulRefCount = 0;
  190. FN_TRACE_RELEASE(CFileStreamBase, ulRefCount);
  191. ulRefCount = ::InterlockedDecrement((LONG *) &m_cRef);
  192. if (ulRefCount == 0)
  193. this->OnRefCountZero();
  194. return ulRefCount;
  195. }
  196. HRESULT
  197. CFileStreamBase::QueryInterface(
  198. REFIID riid,
  199. PVOID *ppvObj
  200. )
  201. {
  202. HRESULT hr = NOERROR;
  203. FN_TRACE_HR(hr);
  204. IUnknown *pIUnknown = NULL;
  205. if (ppvObj != NULL)
  206. *ppvObj = NULL;
  207. if (ppvObj == NULL)
  208. {
  209. hr = E_POINTER;
  210. goto Exit;
  211. }
  212. if ((riid == IID_IUnknown) ||
  213. (riid == IID_ISequentialStream) ||
  214. (riid == IID_IStream))
  215. pIUnknown = static_cast<IStream *>(this);
  216. if (pIUnknown == NULL)
  217. {
  218. hr = E_NOINTERFACE;
  219. goto Exit;
  220. }
  221. pIUnknown->AddRef();
  222. *ppvObj = pIUnknown;
  223. hr = NOERROR;
  224. Exit:
  225. return hr;
  226. }
  227. HRESULT
  228. CFileStreamBase::Read(
  229. void *pv,
  230. ULONG cb,
  231. ULONG *pcbRead
  232. )
  233. {
  234. HRESULT hr = NOERROR;
  235. FN_TRACE_HR(hr);
  236. ULONG cbRead = 0;
  237. if (pcbRead != NULL)
  238. *pcbRead = 0;
  239. INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
  240. IFW32FALSE_ORIGINATE_AND_EXIT(::ReadFile(m_hFile, pv, cb, &cbRead, NULL));
  241. ::FusionpDbgPrintEx(
  242. FUSION_DBG_LEVEL_VERBOSE,
  243. "SXS.DLL: CFileStreamBase::Read() got %d bytes from file.\n", cbRead);
  244. if (cbRead == 0)
  245. hr = S_FALSE;
  246. else
  247. hr = NOERROR;
  248. if (pcbRead != NULL)
  249. *pcbRead = cbRead;
  250. Exit:
  251. return hr;
  252. }
  253. HRESULT
  254. CFileStreamBase::Write(
  255. void const *pv,
  256. ULONG cb,
  257. ULONG *pcbWritten
  258. )
  259. {
  260. HRESULT hr = NOERROR;
  261. FN_TRACE_HR(hr);
  262. ULONG cbWritten = 0;
  263. if (pcbWritten != NULL)
  264. *pcbWritten = 0;
  265. INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
  266. if (!::WriteFile(m_hFile, pv, cb, &cbWritten, NULL))
  267. {
  268. ::FusionpDbgPrintEx(
  269. FUSION_DBG_LEVEL_ERROR,
  270. "SXS.DLL: CFileStreamBase::Write() calling ::WriteFile() failed; ::FusionpGetLastWin32Error() = %d\n", ::FusionpGetLastWin32Error());
  271. hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
  272. goto Exit;
  273. }
  274. ::FusionpDbgPrintEx(
  275. FUSION_DBG_LEVEL_VERBOSE,
  276. "SXS.DLL: CFileStreamBase::Write() got %d bytes from file.\n", cbWritten);
  277. if (cbWritten == 0)
  278. hr = S_FALSE;
  279. else
  280. hr = NOERROR;
  281. if (pcbWritten != NULL)
  282. *pcbWritten = cbWritten;
  283. Exit:
  284. return hr;
  285. }
  286. HRESULT
  287. CFileStreamBase::Seek(
  288. LARGE_INTEGER dlibMove,
  289. DWORD dwOrigin,
  290. ULARGE_INTEGER *plibNewPosition
  291. )
  292. {
  293. HRESULT hr = NOERROR;
  294. FN_TRACE_HR(hr);
  295. DWORD dwWin32Origin = 0;
  296. INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
  297. switch (dwOrigin)
  298. {
  299. default:
  300. hr = E_INVALIDARG;
  301. goto Exit;
  302. case STREAM_SEEK_SET:
  303. dwWin32Origin = FILE_BEGIN;
  304. break;
  305. case STREAM_SEEK_CUR:
  306. dwWin32Origin = FILE_CURRENT;
  307. break;
  308. case STREAM_SEEK_END:
  309. dwWin32Origin = FILE_END;
  310. break;
  311. }
  312. if (!::SetFilePointerEx(
  313. m_hFile,
  314. dlibMove,
  315. (LARGE_INTEGER *) plibNewPosition,
  316. dwWin32Origin))
  317. {
  318. hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
  319. goto Exit;
  320. }
  321. hr = NOERROR;
  322. Exit:
  323. return hr;
  324. }
  325. HRESULT
  326. CFileStreamBase::SetSize(
  327. ULARGE_INTEGER libNewSize
  328. )
  329. {
  330. ::FusionpDbgPrintEx(
  331. FUSION_DBG_LEVEL_ERROR,
  332. "SXS.DLL: Entered CFileStreamBase::SetSize() !!! NOT IMPLEMENTED !!!\n");
  333. UNUSED(libNewSize);
  334. return E_NOTIMPL;
  335. }
  336. HRESULT
  337. CFileStreamBase::CopyTo(
  338. IStream *pstm,
  339. ULARGE_INTEGER cb,
  340. ULARGE_INTEGER *pcbRead,
  341. ULARGE_INTEGER *pcbWritten
  342. )
  343. {
  344. ::FusionpDbgPrintEx(
  345. FUSION_DBG_LEVEL_ERROR,
  346. "SXS.DLL: Entered CFileStreamBase::CopyTo() !!! NOT IMPLEMENTED !!!\n");
  347. if (pcbRead != NULL)
  348. pcbRead->QuadPart = 0;
  349. if (pcbWritten != NULL)
  350. pcbWritten->QuadPart = 0;
  351. return E_NOTIMPL;
  352. }
  353. HRESULT
  354. CFileStreamBase::Commit(
  355. DWORD grfCommitFlags
  356. )
  357. {
  358. HRESULT hr = NOERROR;
  359. ::FusionpDbgPrintEx(
  360. FUSION_DBG_LEVEL_INFO,
  361. "SXS.DLL: Entered CFileStreamBase::Commit()\n");
  362. if (grfCommitFlags != 0)
  363. return E_INVALIDARG;
  364. if ( !Close())
  365. hr = HRESULT_FROM_WIN32 (::FusionpGetLastWin32Error());
  366. if (!SUCCEEDED(hr))
  367. ::FusionpDbgPrintEx(
  368. FUSION_DBG_LEVEL_ERROR,
  369. "SXS.DLL: %s() failed; ::FusionpGetLastWin32Error() = %d\n", __FUNCTION__, ::FusionpGetLastWin32Error());
  370. else
  371. ::FusionpDbgPrintEx(
  372. FUSION_DBG_LEVEL_INFO,
  373. "SXS.DLL: Leaving %s()\n", __FUNCTION__);
  374. return hr ;
  375. }
  376. HRESULT
  377. CFileStreamBase::Revert()
  378. {
  379. ::FusionpDbgPrintEx(
  380. FUSION_DBG_LEVEL_ERROR,
  381. "SXS.DLL: Entered CFileStreamBase::Revert() !!! NOT IMPLEMENTED !!!\n");
  382. return E_NOTIMPL;
  383. }
  384. HRESULT
  385. CFileStreamBase::LockRegion(
  386. ULARGE_INTEGER libOffset,
  387. ULARGE_INTEGER cb,
  388. DWORD dwLockType
  389. )
  390. {
  391. ::FusionpDbgPrintEx(
  392. FUSION_DBG_LEVEL_ERROR,
  393. "SXS.DLL: Entered CFileStreamBase::LockRegion() !!! NOT IMPLEMENTED !!!\n");
  394. UNUSED(libOffset);
  395. UNUSED(cb);
  396. UNUSED(dwLockType);
  397. return E_NOTIMPL;
  398. }
  399. HRESULT
  400. CFileStreamBase::UnlockRegion(
  401. ULARGE_INTEGER libOffset,
  402. ULARGE_INTEGER cb,
  403. DWORD dwLockType
  404. )
  405. {
  406. ::FusionpDbgPrintEx(
  407. FUSION_DBG_LEVEL_ERROR,
  408. "SXS.DLL: Entered CFileStreamBase::UnlockRegion() !!! NOT IMPLEMENTED !!!\n");
  409. UNUSED(libOffset);
  410. UNUSED(cb);
  411. UNUSED(dwLockType);
  412. return E_NOTIMPL;
  413. }
  414. HRESULT
  415. CFileStreamBase::Stat(
  416. STATSTG *pstatstg,
  417. DWORD grfStatFlag
  418. )
  419. {
  420. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR);
  421. FN_TRACE_HR(hr);
  422. BY_HANDLE_FILE_INFORMATION bhfi;
  423. if (pstatstg != NULL)
  424. memset(pstatstg, 0, sizeof(*pstatstg));
  425. PARAMETER_CHECK(((grfStatFlag & ~(STATFLAG_NONAME)) == 0));
  426. PARAMETER_CHECK(pstatstg != NULL);
  427. if (!(grfStatFlag & STATFLAG_NONAME))
  428. {
  429. ::FusionpDbgPrintEx(
  430. FUSION_DBG_LEVEL_ERROR,
  431. "SXS.DLL: %s() does not handle STATFLAG_NONE; returning E_NOTIMPL.\n", __FUNCTION__);
  432. hr = E_NOTIMPL;
  433. goto Exit;
  434. }
  435. INTERNAL_ERROR_CHECK(m_hFile != INVALID_HANDLE_VALUE);
  436. IFW32FALSE_ORIGINATE_AND_EXIT(::GetFileInformationByHandle(m_hFile, &bhfi));
  437. pstatstg->pwcsName = NULL;
  438. pstatstg->type = STGTY_STREAM;
  439. pstatstg->cbSize.LowPart = bhfi.nFileSizeLow;
  440. pstatstg->cbSize.HighPart = bhfi.nFileSizeHigh;
  441. pstatstg->mtime = bhfi.ftLastWriteTime;
  442. pstatstg->ctime = bhfi.ftCreationTime;
  443. pstatstg->atime = bhfi.ftLastAccessTime;
  444. pstatstg->grfMode = m_grfMode;
  445. pstatstg->grfLocksSupported = LOCK_WRITE;
  446. pstatstg->clsid = GUID_NULL;
  447. pstatstg->grfStateBits = 0;
  448. pstatstg->reserved = 0;
  449. hr = NOERROR;
  450. Exit:
  451. return hr;
  452. }
  453. HRESULT
  454. CFileStreamBase::Clone(
  455. IStream **ppIStream
  456. )
  457. {
  458. ::FusionpDbgPrintEx(
  459. FUSION_DBG_LEVEL_ERROR,
  460. "SXS.DLL: Entered CFileStreamBase::Clone() !!! NOT IMPLEMENTED !!!\n");
  461. if (ppIStream != NULL)
  462. *ppIStream = NULL;
  463. return E_NOTIMPL;
  464. }