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.

1594 lines
43 KiB

  1. // LockBytes.cpp -- Implementation for class CFSLockBytes
  2. #include "StdAfx.h"
  3. typedef PITransformInstance * PPITI;
  4. DEBUGDEF(LONG CFSLockBytes::CImpILockBytes::s_cInCriticalSection) // = 0)
  5. DEBUGDEF(LONG CSegmentLockBytes::CImpILockBytes::s_cInCriticalSection) // = 0)
  6. DEBUGDEF(LONG CTransformedLockBytes::CImpILockBytes::s_cInCriticalSection) // = 0)
  7. HRESULT IITLockBytes::CopyLockBytes
  8. (ILockBytes *pilbSrc, CULINT ullBaseSrc, CULINT ullLimitSrc,
  9. ILockBytes *pilbDest, CULINT ullBaseDest
  10. )
  11. {
  12. CULINT ullLimitDest;
  13. ullLimitDest = ullBaseDest + (ullLimitSrc - ullBaseSrc);
  14. if (ullLimitDest.NonZero() && ullLimitDest < ullBaseDest)
  15. return STG_E_MEDIUMFULL;
  16. PBYTE pbBuffer = PBYTE(_alloca(CB_COPY_BUFFER));
  17. if (!pbBuffer)
  18. return STG_E_INSUFFICIENTMEMORY;
  19. for (; (ullLimitSrc.NonZero()? ullBaseSrc < ullLimitSrc : ullBaseSrc.NonZero()); )
  20. {
  21. CULINT ullLimit;
  22. ullLimit = ullBaseSrc + CB_COPY_BUFFER;
  23. UINT cb = (ullLimit <= ullLimitSrc)? CB_COPY_BUFFER
  24. : (ullLimitSrc - ullBaseSrc).Uli().LowPart;
  25. ULONG cbRead;
  26. HRESULT hr= pilbSrc->ReadAt(ullBaseSrc.Uli(), pbBuffer, cb, &cbRead);
  27. if (!SUCCEEDED(hr))
  28. return hr;
  29. if (cb != cbRead)
  30. return STG_E_READFAULT;
  31. ULONG cbWritten;
  32. hr= pilbDest->WriteAt(ullBaseDest.Uli(), pbBuffer, cb, &cbWritten);
  33. if (!SUCCEEDED(hr))
  34. return hr;
  35. if (cb != cbWritten)
  36. return STG_E_WRITEFAULT;
  37. ullBaseSrc += cb;
  38. ullBaseDest += cb;
  39. }
  40. return NO_ERROR;
  41. }
  42. ILockBytes *STDMETHODCALLTYPE FindMatchingLockBytes(const WCHAR *pwcsPath, CImpITUnknown *pLkb)
  43. {
  44. for (; pLkb; pLkb = pLkb->NextObject())
  45. if (((IITLockBytes *)pLkb)->IsNamed(pwcsPath))
  46. {
  47. pLkb->AddRef();
  48. return (ILockBytes *) pLkb;
  49. }
  50. return NULL;
  51. }
  52. HRESULT CFSLockBytes::Create(IUnknown *punkOuter, const WCHAR * pwszFileName,
  53. DWORD grfMode, ILockBytes **pplkb
  54. )
  55. {
  56. CFSLockBytes *pfslkb = New CFSLockBytes(punkOuter);
  57. return FinishSetup(pfslkb? pfslkb->m_ImpILockBytes.InitCreateLockBytesOnFS
  58. (pwszFileName, grfMode)
  59. : STG_E_INSUFFICIENTMEMORY,
  60. pfslkb,IID_ILockBytes , (PPVOID) pplkb
  61. );
  62. }
  63. HRESULT CFSLockBytes::CreateTemp(IUnknown *punkOuter, ILockBytes **pplkb)
  64. {
  65. char szTempPath[MAX_PATH];
  66. DWORD cbPath= GetTempPath(MAX_PATH, szTempPath);
  67. if (!cbPath)
  68. lstrcpyA(szTempPath, ".\\");
  69. char szPrefix[4] = "IMT"; // BugBug! May need to make this a random string.
  70. char szFullPath[MAX_PATH];
  71. if (!GetTempFileName(szTempPath, szPrefix, 0, szFullPath))
  72. return CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  73. WCHAR wszFullPath[MAX_PATH];
  74. UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, szFullPath,
  75. 1 + lstrlenA(szFullPath), wszFullPath, MAX_PATH
  76. );
  77. if (!cwc)
  78. return GetLastError();
  79. return Open(punkOuter, wszFullPath, STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  80. | STGM_DELETEONRELEASE,
  81. pplkb
  82. );
  83. }
  84. HRESULT CFSLockBytes::Open(IUnknown *punkOuter, const WCHAR * pwszFileName,
  85. DWORD grfMode, ILockBytes **pplkb
  86. )
  87. {
  88. ILockBytes *pLockBytes = NULL;
  89. if (!punkOuter)
  90. {
  91. pLockBytes = CFSLockBytes::CImpILockBytes::FindFSLockBytes(pwszFileName);
  92. if (pLockBytes)
  93. {
  94. *pplkb = pLockBytes;
  95. return NO_ERROR;
  96. }
  97. }
  98. CFSLockBytes *pfslkb = New CFSLockBytes(punkOuter);
  99. return FinishSetup(pfslkb? pfslkb->m_ImpILockBytes.InitOpenLockBytesOnFS
  100. (pwszFileName, grfMode)
  101. : STG_E_INSUFFICIENTMEMORY,
  102. pfslkb, IID_ILockBytes, (PPVOID) pplkb
  103. );
  104. }
  105. CFSLockBytes::CImpILockBytes::CImpILockBytes
  106. (CFSLockBytes *pBackObj, IUnknown *punkOuter)
  107. : IITLockBytes(pBackObj, punkOuter, this->m_awszFileName)
  108. {
  109. m_hFile = NULL;
  110. m_fFlushed = TRUE;
  111. m_grfMode = 0;
  112. m_cwcFileName = 0;
  113. m_awszFileName[0] = 0;
  114. }
  115. CFSLockBytes::CImpILockBytes::~CImpILockBytes(void)
  116. {
  117. CSyncWith sw(g_csITFS);
  118. if (m_hFile)
  119. {
  120. // RonM_ASSERT(m_fFlushed);
  121. // The above assert is here because we want to avoid
  122. // relying on the release operation to flush out pending
  123. // disk I/O. The reason is that neither the destructor
  124. // nor the Release function can return an error code.
  125. // Thus you'd never know whether the flush succeeded.
  126. if (!m_fFlushed)
  127. Flush();
  128. if (ActiveMark())
  129. MarkInactive();
  130. // if (m_grfMode & STGM_DELETE_ON_RELEASE)
  131. // ...
  132. CloseHandle(m_hFile);
  133. }
  134. }
  135. // Initialing routines:
  136. #define INVALID_MODE 0xFFFFFFFF
  137. DWORD adwAccessModes[4] = { GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE, INVALID_MODE };
  138. DWORD adwShareModes[8] = { INVALID_MODE, 0, FILE_SHARE_READ, FILE_SHARE_WRITE,
  139. FILE_SHARE_READ | FILE_SHARE_WRITE,
  140. INVALID_MODE, INVALID_MODE, INVALID_MODE
  141. };
  142. // The tables adwFileCreateErrors and adwSTGMappedErrors define a mapping from the
  143. // Win32 file system errors to the STG_E_xxx errors.
  144. // BugBug: Can we do this by simple bit fiddling?
  145. static LONG adwFileCreateErrors[] =
  146. {
  147. ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_TOO_MANY_OPEN_FILES,
  148. ERROR_ACCESS_DENIED, ERROR_INVALID_HANDLE, ERROR_NOT_ENOUGH_MEMORY,
  149. ERROR_OUTOFMEMORY, ERROR_INVALID_DRIVE, ERROR_NO_MORE_FILES,
  150. ERROR_WRITE_PROTECT, ERROR_BAD_UNIT, ERROR_CRC,
  151. ERROR_SEEK, ERROR_WRITE_FAULT, ERROR_READ_FAULT,
  152. ERROR_SHARING_VIOLATION, ERROR_LOCK_VIOLATION, ERROR_FILE_EXISTS,
  153. ERROR_INVALID_PARAMETER, ERROR_DISK_FULL, ERROR_NOACCESS,
  154. ERROR_INVALID_USER_BUFFER, ERROR_ALREADY_EXISTS, ERROR_INVALID_NAME
  155. };
  156. static LONG adwSTGMappedErrors[] =
  157. {
  158. STG_E_FILENOTFOUND, STG_E_PATHNOTFOUND, STG_E_TOOMANYOPENFILES,
  159. STG_E_ACCESSDENIED, STG_E_INVALIDHANDLE, STG_E_INSUFFICIENTMEMORY,
  160. STG_E_INSUFFICIENTMEMORY, STG_E_PATHNOTFOUND, STG_E_NOMOREFILES,
  161. STG_E_DISKISWRITEPROTECTED, STG_E_PATHNOTFOUND, STG_E_READFAULT,
  162. STG_E_SEEKERROR, STG_E_WRITEFAULT, STG_E_READFAULT,
  163. STG_E_SHAREVIOLATION, STG_E_LOCKVIOLATION, STG_E_FILEALREADYEXISTS,
  164. STG_E_INVALIDPARAMETER, STG_E_MEDIUMFULL, STG_E_INVALIDPOINTER,
  165. STG_E_INVALIDPOINTER, STG_E_FILEALREADYEXISTS, STG_E_PATHNOTFOUND
  166. };
  167. DWORD CFSLockBytes::CImpILockBytes::STGErrorFromFSError(DWORD fsError)
  168. {
  169. // This routine maps Win32 file system errors into STG_E_xxxx errors.
  170. UINT cErrs = sizeof(adwFileCreateErrors) / sizeof(DWORD);
  171. RonM_ASSERT(cErrs == sizeof(adwSTGMappedErrors)/sizeof(DWORD));
  172. DWORD *pdw = (DWORD *) adwFileCreateErrors;
  173. for (; cErrs--; pdw++)
  174. {
  175. DWORD dw = *pdw;
  176. if (dw == fsError)
  177. return (DWORD) adwSTGMappedErrors[pdw - (DWORD *) adwFileCreateErrors];
  178. }
  179. RonM_ASSERT(FALSE); // We're supposed to map all errors!
  180. return STG_E_UNKNOWN; // For when we don't find a match.
  181. }
  182. HRESULT CFSLockBytes::CImpILockBytes::InitCreateLockBytesOnFS
  183. (const WCHAR * pwszFileName,
  184. DWORD grfMode
  185. )
  186. {
  187. return OpenOrCreateLockBytesOnFS(pwszFileName, grfMode, TRUE);
  188. }
  189. HRESULT CFSLockBytes::CImpILockBytes::OpenOrCreateLockBytesOnFS
  190. (const WCHAR * pwszFileName,
  191. DWORD grfMode,
  192. BOOL fCreate
  193. )
  194. {
  195. RonM_ASSERT(!m_hFile);
  196. if (grfMode & STGM_TRANSACTED)
  197. return STG_E_UNIMPLEMENTEDFUNCTION;
  198. // The following assert verifies that RW_ACCESS_MASK is correct.
  199. RonM_ASSERT(STGM_READ == 0 && STGM_WRITE == 1 && STGM_READWRITE == 2);
  200. DWORD dwAccessMode = adwAccessModes[grfMode & RW_ACCESS_MASK];
  201. if (dwAccessMode == INVALID_MODE)
  202. return STG_E_INVALIDFLAG;
  203. // The following ASSERT verifies that SHARE_MASK and SHARE_BIT_SHIFT are correct.
  204. RonM_ASSERT( STGM_SHARE_DENY_NONE == 0x40
  205. && STGM_SHARE_DENY_READ == 0x30
  206. && STGM_SHARE_DENY_WRITE == 0x20
  207. && STGM_SHARE_EXCLUSIVE == 0x10
  208. );
  209. DWORD dwShareMode = adwShareModes[(grfMode & SHARE_MASK) >> SHARE_BIT_SHIFT];
  210. if (dwShareMode == INVALID_MODE)
  211. dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; // default is STGM_SHARE_DENY_NONE
  212. // return STG_E_INVALIDFLAG;
  213. m_grfMode = grfMode;
  214. char aszFileName[MAX_PATH+1];
  215. INT cwc= wcsLen(pwszFileName);
  216. if (cwc >= MAX_PATH)
  217. return STG_E_INVALIDNAME;
  218. INT cb = WideCharToMultiByte(CP_USER_DEFAULT(), WC_COMPOSITECHECK | WC_SEPCHARS,
  219. pwszFileName, cwc+1,aszFileName, MAX_PATH, NULL, NULL);
  220. if (!cb)
  221. return STG_E_INVALIDNAME;
  222. DWORD dwCreationMode = fCreate? (grfMode & STGM_CREATE)? CREATE_ALWAYS : CREATE_NEW
  223. : OPEN_EXISTING;
  224. m_hFile = CreateFile(aszFileName, dwAccessMode, dwShareMode, NULL, dwCreationMode,
  225. (grfMode & STGM_DELETEONRELEASE)? FILE_FLAG_DELETE_ON_CLOSE
  226. : FILE_ATTRIBUTE_NORMAL,
  227. NULL
  228. );
  229. if (m_hFile == INVALID_HANDLE_VALUE)
  230. return STGErrorFromFSError(GetLastError());
  231. CopyMemory(m_awszFileName, pwszFileName, sizeof(WCHAR) * (cwc + 1));
  232. m_cwcFileName = cwc;
  233. MarkActive(g_pFSLockBytesFirstActive);
  234. return NO_ERROR;
  235. }
  236. HRESULT CFSLockBytes::CImpILockBytes::InitOpenLockBytesOnFS
  237. (const WCHAR * pwszFileName,
  238. DWORD grfMode
  239. )
  240. {
  241. return OpenOrCreateLockBytesOnFS(pwszFileName, grfMode, FALSE);
  242. }
  243. // ILockBytes methods:
  244. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::ReadAt(
  245. /* [in] */ ULARGE_INTEGER ulOffset,
  246. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  247. /* [in] */ ULONG cb,
  248. /* [out] */ ULONG __RPC_FAR *pcbRead)
  249. {
  250. /*
  251. This routine reads data synchronously. This means that multiple accesses
  252. to the file from different threads are forced into a strict sequence with no
  253. overlap. This could be a serious bottleneck in a multi-threaded environment.
  254. We can relax this constraint by using multiple read threads in Win95 or
  255. overlapped I/O in WinNT.
  256. */
  257. RonM_ASSERT(m_hFile);
  258. CSyncWith sw(g_csITFS);
  259. UINT ulResult = SetFilePointer(m_hFile, ulOffset.LowPart, (LONG *) &(ulOffset.HighPart), FILE_BEGIN);
  260. if (ulResult == UINT(~0))
  261. {
  262. DWORD dwErr= GetLastError();
  263. if (dwErr != NO_ERROR)
  264. return STGErrorFromFSError(dwErr);
  265. }
  266. ULONG cbRead = 0;
  267. BOOL fSucceeded = ReadFile(m_hFile, pv, cb, &cbRead, NULL);
  268. if (pcbRead)
  269. *pcbRead = cbRead;
  270. if (fSucceeded)
  271. return NO_ERROR;
  272. DWORD dwErr= GetLastError();
  273. RonM_ASSERT(cb);
  274. if (dwErr == ERROR_HANDLE_EOF)
  275. return (!cbRead)? S_FALSE : S_OK;
  276. return STGErrorFromFSError(dwErr);
  277. }
  278. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::WriteAt(
  279. /* [in] */ ULARGE_INTEGER ulOffset,
  280. /* [size_is][in] */ const void __RPC_FAR *pv,
  281. /* [in] */ ULONG cb,
  282. /* [out] */ ULONG __RPC_FAR *pcbWritten)
  283. {
  284. RonM_ASSERT(m_hFile);
  285. m_fFlushed = FALSE;
  286. /*
  287. This routine writes data synchronously. This means that multiple accesses
  288. to the file from different threads are forced into a strict sequence with no
  289. overlap. This could be a serious bottleneck in a multi-threaded environment.
  290. We can relax this constraint by using multiple read threads in Win95 or
  291. overlapped I/O in WinNT.
  292. */
  293. CSyncWith sw(g_csITFS);
  294. DWORD ulResult = SetFilePointer(m_hFile, ulOffset.LowPart, (LONG *) &(ulOffset.HighPart), FILE_BEGIN);
  295. if (ulResult == UINT(~0))
  296. {
  297. DWORD dwErr= GetLastError();
  298. if (dwErr != NO_ERROR)
  299. return STGErrorFromFSError(dwErr);
  300. }
  301. ULONG cbWritten = 0;
  302. BOOL fSucceeded = WriteFile(m_hFile, pv, cb, &cbWritten, NULL);
  303. if (pcbWritten)
  304. *pcbWritten = cbWritten;
  305. if (fSucceeded)
  306. return NO_ERROR;
  307. return STGErrorFromFSError(GetLastError());
  308. }
  309. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::Flush( void)
  310. {
  311. RonM_ASSERT(m_hFile);
  312. CSyncWith sw(g_csITFS);
  313. BOOL fSucceeded = FlushFileBuffers(m_hFile);
  314. HRESULT hr;
  315. if (fSucceeded)
  316. {
  317. m_fFlushed = TRUE;
  318. hr = NO_ERROR;
  319. }
  320. else hr = STGErrorFromFSError(GetLastError());
  321. return hr;
  322. }
  323. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::SetSize(
  324. /* [in] */ ULARGE_INTEGER cb)
  325. {
  326. RonM_ASSERT(m_hFile);
  327. m_fFlushed = FALSE; // Is this necessary?
  328. CSyncWith sw(g_csITFS);
  329. DWORD dwDistLow= SetFilePointer(m_hFile, cb.LowPart, (LONG *) &(cb.HighPart),
  330. FILE_BEGIN
  331. );
  332. if (!~dwDistLow) // Seek operation failed
  333. return STGErrorFromFSError(GetLastError());
  334. BOOL fSucceeded= SetEndOfFile(m_hFile);
  335. if (fSucceeded)
  336. return NO_ERROR;
  337. return STGErrorFromFSError(GetLastError());
  338. }
  339. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::LockRegion(
  340. /* [in] */ ULARGE_INTEGER libOffset,
  341. /* [in] */ ULARGE_INTEGER cb,
  342. /* [in] */ DWORD dwLockType)
  343. {
  344. RonM_ASSERT(m_hFile);
  345. if (dwLockType != LOCK_EXCLUSIVE)
  346. return STG_E_UNIMPLEMENTEDFUNCTION;
  347. if (LockFile(m_hFile, libOffset.LowPart, libOffset.HighPart,
  348. cb.LowPart, cb.HighPart
  349. )
  350. )
  351. return NO_ERROR;
  352. return STGErrorFromFSError(GetLastError());
  353. }
  354. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::UnlockRegion(
  355. /* [in] */ ULARGE_INTEGER libOffset,
  356. /* [in] */ ULARGE_INTEGER cb,
  357. /* [in] */ DWORD dwLockType)
  358. {
  359. RonM_ASSERT(m_hFile);
  360. if (dwLockType != LOCK_EXCLUSIVE)
  361. return STG_E_UNIMPLEMENTEDFUNCTION;
  362. if (UnlockFile(m_hFile, libOffset.LowPart, libOffset.HighPart,
  363. cb.LowPart, cb.HighPart
  364. )
  365. )
  366. return NO_ERROR;
  367. return STGErrorFromFSError(GetLastError());
  368. }
  369. HRESULT STDMETHODCALLTYPE CFSLockBytes::CImpILockBytes::Stat(
  370. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  371. /* [in] */ DWORD grfStatFlag)
  372. {
  373. RonM_ASSERT(m_hFile);
  374. pstatstg->cbSize.LowPart = GetFileSize(m_hFile, &(pstatstg->cbSize.HighPart));
  375. DWORD dwErr= GetLastError();
  376. if (pstatstg->cbSize.LowPart == 0xFFFFFFFF && dwErr != NO_ERROR)
  377. return STGErrorFromFSError(dwErr);
  378. if (!GetFileTime(m_hFile, &(pstatstg->ctime), &(pstatstg->atime), &(pstatstg->mtime)))
  379. return STGErrorFromFSError(GetLastError());
  380. pstatstg->type = STGTY_LOCKBYTES;
  381. pstatstg->grfMode = m_grfMode;
  382. pstatstg->grfLocksSupported = LOCK_EXCLUSIVE;
  383. pstatstg->clsid = CLSID_NULL;
  384. pstatstg->grfStateBits = 0;
  385. pstatstg->reserved = 0;
  386. // The code for setting pstatstg->pwcsName must go last because we don't want
  387. // to allocate memory for the name and then report an error. If we did, our
  388. // caller would not realize that they needed to deallocate that name memory.
  389. if (grfStatFlag == STATFLAG_DEFAULT)
  390. {
  391. PWCHAR pwcName= PWCHAR(OLEHeap()->Alloc(sizeof(WCHAR) * (m_cwcFileName+1)));
  392. if (!pwcName)
  393. return STG_E_INSUFFICIENTMEMORY;
  394. CopyMemory(pwcName, m_awszFileName, sizeof(WCHAR) * (m_cwcFileName+1));
  395. pstatstg->pwcsName= pwcName;
  396. }
  397. else pstatstg->pwcsName = NULL;
  398. return NO_ERROR;
  399. }
  400. ILockBytes *CFSLockBytes::CImpILockBytes::FindFSLockBytes(const WCHAR * pwszFileName)
  401. {
  402. CSyncWith sw(g_csITFS);
  403. return FindMatchingLockBytes(pwszFileName, (CImpITUnknown *) g_pFSLockBytesFirstActive);
  404. }
  405. HRESULT __stdcall CFSLockBytes::CImpILockBytes::SetTimes
  406. (FILETIME const * pctime,
  407. FILETIME const * patime,
  408. FILETIME const * pmtime
  409. )
  410. {
  411. BOOL fSuccess = SetFileTime(m_hFile, pctime, patime, pmtime);
  412. if (fSuccess)
  413. return NO_ERROR;
  414. return STGErrorFromFSError(GetLastError());
  415. }
  416. CSegmentLockBytes::CImpILockBytes::CImpILockBytes
  417. (CSegmentLockBytes *pBackObj, IUnknown *punkOuter)
  418. : IITLockBytes(pBackObj, punkOuter, m_PathInfo.awszStreamPath)
  419. {
  420. m_fFlushed = TRUE;
  421. m_pITFS = NULL;
  422. m_plbMedium = NULL;
  423. m_plbTemp = NULL;
  424. m_plbLockMgr = NULL;
  425. ZeroMemory(&m_PathInfo, sizeof(m_PathInfo));
  426. }
  427. CSegmentLockBytes::CImpILockBytes::~CImpILockBytes(void)
  428. {
  429. CSyncWith sw(g_csITFS);
  430. if (m_plbMedium)
  431. {
  432. // RonM_ASSERT(m_fFlushed);
  433. // The above assert is here because we want to avoid
  434. // relying on the release operation to flush out pending
  435. // disk I/O. The reason is that neither the destructor
  436. // nor the Release function can return an error code.
  437. // Thus you'd never know whether the flush succeeded.
  438. if (!m_fFlushed)
  439. Flush();
  440. if (m_PathInfo.cUnrecordedChanges)
  441. m_pITFS->UpdatePathInfo(&m_PathInfo);
  442. if (m_plbTemp) // Should have been discarded by Flush.
  443. m_plbTemp->Release(); // However this can happen if we're low on disk space.
  444. if (m_plbLockMgr) // Will exit if we've had a LockRegion call.
  445. m_plbLockMgr->Release();
  446. MarkInactive(); // Take this LockBytes out of the active chain.
  447. RonM_ASSERT(m_pITFS); // Because we've got m_plbMedium.
  448. if (m_PathInfo.awszStreamPath[0] != L'/')
  449. m_pITFS->FSObjectReleased();
  450. m_plbMedium->Release();
  451. m_pITFS ->Release();
  452. }
  453. else
  454. {
  455. RonM_ASSERT(!m_pITFS);
  456. RonM_ASSERT(!m_plbTemp); // Won't exist if we don't have a lockbyte medium.
  457. RonM_ASSERT(!m_plbLockMgr); // Won't exist if we don't have a lockbyte medium.
  458. }
  459. }
  460. HRESULT CSegmentLockBytes::OpenSegment
  461. (IUnknown *punkOuter, IITFileSystem *pITFS, ILockBytes *pLKBMedium,
  462. PathInfo *pPI, ILockBytes **pplkb
  463. )
  464. {
  465. CSegmentLockBytes *pSegLKB = New CSegmentLockBytes(punkOuter);
  466. return FinishSetup(pSegLKB? pSegLKB->m_ImpILockBytes.InitOpenSegment
  467. (pITFS, pLKBMedium, pPI)
  468. : STG_E_INSUFFICIENTMEMORY,
  469. pSegLKB, IID_ILockBytes, (PPVOID) pplkb
  470. );
  471. }
  472. HRESULT CSegmentLockBytes::CImpILockBytes::InitOpenSegment
  473. (IITFileSystem *pITFS, ILockBytes *pLKBMedium, PathInfo *pPI)
  474. {
  475. m_pITFS = pITFS;
  476. m_plbMedium = pLKBMedium;
  477. m_PathInfo = *pPI;
  478. #if 0
  479. m_grfMode = (m_pITFS->IsWriteable())? STGM_READWRITE | STGM_SHARE_DENY_NONE
  480. : STGM_READ | STGM_SHARE_DENY_NONE;
  481. #endif // 0
  482. m_pITFS ->AddRef();
  483. m_plbMedium->AddRef();
  484. m_pITFS->ConnectLockBytes(this);
  485. return NO_ERROR;
  486. }
  487. // ILockBytes methods:
  488. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::ReadAt(
  489. /* [in] */ ULARGE_INTEGER ulOffset,
  490. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  491. /* [in] */ ULONG cb,
  492. /* [out] */ ULONG __RPC_FAR *pcbRead)
  493. {
  494. RonM_ASSERT(m_plbMedium);
  495. // Since a particular segmented lockbyte may be shared among
  496. // several different stream objects with varying grfMode settings,
  497. // we don't validate read access permission at runtime. Instead
  498. // lockbyte segments are always opened with the maximum permissions
  499. // available for the medium, and we rely on the client stream object
  500. // not to ask us to violate the available medium permissions.
  501. #if 0
  502. RonM_ASSERT( (m_grfMode & RW_ACCESS_MASK) == STGM_READ
  503. || (m_grfMode & RW_ACCESS_MASK) == STGM_READWRITE
  504. );
  505. // #else
  506. if ( (m_grfMode & RW_ACCESS_MASK) != STGM_READ
  507. && (m_grfMode & RW_ACCESS_MASK) != STGM_READWRITE
  508. )
  509. return STG_E_INVALID_FLAG;
  510. #endif
  511. if (!cb)
  512. {
  513. if (pcbRead)
  514. *pcbRead = 0;
  515. return NO_ERROR;
  516. }
  517. /*
  518. The rest of the code runs in a critical section because a concurrent
  519. write operation could move the data into a temporary lockbytes object,
  520. or it could change the segment boundaries.
  521. */
  522. CSyncWith sw(g_csITFS);
  523. HRESULT hr = NO_ERROR;
  524. if (m_plbTemp)
  525. return m_plbTemp->ReadAt(ulOffset, pv, cb, pcbRead);
  526. CULINT ullBase, ullLimit;
  527. ullBase = m_PathInfo.ullcbOffset + ulOffset;
  528. ullLimit = ullBase + cb;
  529. CULINT ullLimitSegment = m_PathInfo.ullcbOffset + m_PathInfo.ullcbData;
  530. if (ullBase > ullLimitSegment) // Beyond the end of the segment?
  531. {
  532. if (pcbRead)
  533. *pcbRead = 0;
  534. return S_FALSE;
  535. }
  536. BOOL fEOS = FALSE;
  537. if ( ullLimit < ullBase // Wrapped at 2**64 bytes?
  538. || ullLimit > ullLimitSegment // Trying to read past end of segment?
  539. )
  540. {
  541. fEOS = TRUE;
  542. ullLimit = ullLimitSegment;
  543. }
  544. ULONG cbRead = 0;
  545. hr= m_plbMedium->ReadAt(ullBase.Uli(), pv, (ullLimit - ullBase).Uli().LowPart,
  546. &cbRead
  547. );
  548. if (pcbRead)
  549. *pcbRead = cbRead;
  550. RonM_ASSERT(cb);
  551. if (fEOS && hr == NO_ERROR && !cbRead)
  552. hr = S_FALSE;
  553. return hr;
  554. }
  555. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::WriteAt(
  556. /* [in] */ ULARGE_INTEGER ulOffset,
  557. /* [size_is][in] */ const void __RPC_FAR *pv,
  558. /* [in] */ ULONG cb,
  559. /* [out] */ ULONG __RPC_FAR *pcbWritten)
  560. {
  561. RonM_ASSERT(m_plbMedium);
  562. // Since a particular segmented lockbyte may be shared among
  563. // several different stream objects with varying grfMode settings,
  564. // we don't validate write access permission at runtime. Instead
  565. // lockbyte segments are always opened with the maximum permissions
  566. // available for the medium, and we rely on the client stream object
  567. // not to ask us to violate the available medium permissions.
  568. #if 0
  569. RonM_ASSERT( (m_grfMode & RW_ACCESS_MASK) == STGM_WRITE
  570. || (m_grfMode & RW_ACCESS_MASK) == STGM_READWRITE
  571. );
  572. // #else
  573. if ( (m_grfMode & RW_ACCESS_MASK) != STGM_WRITE
  574. && (m_grfMode & RW_ACCESS_MASK) != STGM_READWRITE
  575. )
  576. return STG_E_INVALID_FLAG;
  577. #endif
  578. if (!cb)
  579. {
  580. if (pcbWritten)
  581. *pcbWritten = 0;
  582. return NO_ERROR;
  583. }
  584. /*
  585. The rest of the code runs in a critical section. That's necessary because a
  586. particular write operation may change the underlying medium from a lockbyte
  587. segment to a temporary lockbyte object or it may do a realloc which changes
  588. the segment boundaries.
  589. */
  590. CSyncWith sw(g_csITFS);
  591. HRESULT hr = NO_ERROR;
  592. hr = m_pITFS->CountWrites();
  593. if (m_plbTemp)
  594. return m_plbTemp->WriteAt(ulOffset, pv, cb, pcbWritten);
  595. CULINT ullBase, ullLimit;
  596. ullBase = m_PathInfo.ullcbOffset + ulOffset;
  597. ullLimit = ullBase + cb;
  598. CULINT ullLimitSegment = m_PathInfo.ullcbOffset + m_PathInfo.ullcbData;
  599. // The assert below verifies that the segment doesn't wrap around
  600. // through the beginning of the 64-bit address space.
  601. RonM_ASSERT( m_PathInfo.ullcbOffset <= ullLimitSegment
  602. || !(ullLimitSegment.NonZero())
  603. );
  604. if ( ullBase < m_PathInfo.ullcbOffset
  605. || (ullBase > ullLimit && ullLimit.NonZero())
  606. )
  607. {
  608. // The write would wrap around.
  609. // This is very unlikely -- at least for the next few years.
  610. if (pcbWritten)
  611. *pcbWritten = 0;
  612. return STG_E_WRITEFAULT;
  613. }
  614. m_fFlushed = FALSE; // Because we know we're going to write something.
  615. // Here we check to see if the write is completely contained within
  616. // the segment.
  617. if ( m_PathInfo.ullcbData.NonZero()
  618. && ullBase >= m_PathInfo.ullcbOffset
  619. && (ullLimitSegment.NonZero()? ullLimit <= ullLimitSegment
  620. : ( ullLimit > m_PathInfo.ullcbOffset
  621. || !ullLimit.NonZero()
  622. )
  623. )
  624. )
  625. return m_plbMedium->WriteAt(ullBase.Uli(), pv, cb, pcbWritten);
  626. // The write doesn't fit in the segment.
  627. // Let's see if we can reallocate the segment without moving it.
  628. //
  629. // Note that we pass in pointers to both the segment base and the segment limit.
  630. // You might think that we don't need to pass in the base since the storage
  631. // manager already knows where the segment is located. However when the segment's
  632. // size is zero, it really doesn't have a location. So we let the storage manager
  633. // put it at the end of the medium. This takes care of the case where several
  634. // lockbyte segments are created and then they are written in some random order.
  635. CULINT ullcbNew;
  636. ullcbNew = ullLimit - m_PathInfo.ullcbOffset;
  637. hr = m_pITFS->ReallocInPlace(&m_PathInfo, ullcbNew);
  638. if (hr == S_OK)
  639. {
  640. ullBase = m_PathInfo.ullcbOffset + ulOffset;
  641. return m_plbMedium->WriteAt(ullBase.Uli(), pv, cb, pcbWritten);
  642. }
  643. // We couldn't do an in-place reallocation.
  644. //
  645. // So we move the data into a temporary ILockbytes object
  646. // and then do the write operation there.
  647. hr= CFSLockBytes::CreateTemp(NULL, &m_plbTemp);
  648. if (!SUCCEEDED(hr))
  649. return hr;
  650. ((IITLockBytes *) m_plbTemp)->Container()->MarkSecondary();
  651. hr = IITLockBytes::CopyLockBytes(m_plbMedium, m_PathInfo.ullcbOffset, ullLimitSegment,
  652. m_plbTemp, 0
  653. );
  654. if (!SUCCEEDED(hr))
  655. {
  656. m_plbTemp->Release();
  657. m_plbTemp = NULL;
  658. return hr;
  659. }
  660. hr = m_pITFS->ReallocInPlace(&m_PathInfo, 0);
  661. RonM_ASSERT(SUCCEEDED(hr)); // In place shrinking should always work!
  662. if (!SUCCEEDED(hr))
  663. return hr;
  664. return m_plbTemp->WriteAt(ulOffset, pv, cb, pcbWritten);
  665. }
  666. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::Flush( void)
  667. {
  668. RonM_ASSERT(m_plbMedium);
  669. CSyncWith sw(g_csITFS);
  670. HRESULT hr = NO_ERROR;
  671. if (m_fFlushed)
  672. return hr;
  673. if (m_plbTemp)
  674. {
  675. // At some point we moved the data into a temporary file. That's
  676. // usually because we needed to write beyond the segment boundaries.
  677. // Now we must move the data back into the lockbyte medium.
  678. // First we must reallocate the segment to the current data size
  679. STATSTG statstg;
  680. hr = m_plbTemp->Stat(&statstg, STATFLAG_NONAME);
  681. if (!SUCCEEDED(hr))
  682. return hr;
  683. hr = m_pITFS->ReallocEntry(&m_PathInfo, CULINT(statstg.cbSize), FALSE);
  684. if (!SUCCEEDED(hr))
  685. return hr;
  686. // Then we must copy the data back into the lockbyte medium.
  687. hr = IITLockBytes::CopyLockBytes(m_plbTemp, CULINT(0), CULINT(statstg.cbSize),
  688. m_plbMedium, m_PathInfo.ullcbOffset
  689. );
  690. if (!SUCCEEDED(hr))
  691. return hr;
  692. // At this point we don't need the temporary lockbyte any more.
  693. // At least not until the next append operation...
  694. m_plbTemp->Release();
  695. m_plbTemp = NULL;
  696. }
  697. hr = m_plbMedium->Flush(); // Flush in-memory data to disk.
  698. m_fFlushed = TRUE;
  699. return hr;
  700. }
  701. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::SetSize(
  702. /* [in] */ ULARGE_INTEGER cb)
  703. {
  704. RonM_ASSERT(m_plbMedium);
  705. CSyncWith sw(g_csITFS);
  706. HRESULT hr = NO_ERROR;
  707. if (m_PathInfo.ullcbData == CULINT(cb))
  708. return hr;
  709. m_fFlushed = FALSE;
  710. if (m_plbTemp)
  711. hr = m_plbTemp->SetSize(cb);
  712. else
  713. {
  714. hr = m_pITFS->ReallocInPlace(&m_PathInfo, CULINT(cb));
  715. if (hr != S_OK)
  716. {
  717. // Couldn't grow the segment in place. So now we must move the data
  718. // into a temp lockbyte object. We know it's a grow operation and not
  719. // a shrinkage because the storage manager can always do an in-place
  720. // shrink operation.
  721. hr = CFSLockBytes::CreateTemp(NULL, &m_plbTemp);
  722. if (SUCCEEDED(hr))
  723. {
  724. CULINT ullLimitSegment = m_PathInfo.ullcbOffset + m_PathInfo.ullcbData;
  725. hr = m_plbTemp->SetSize(cb);
  726. if (SUCCEEDED(hr))
  727. hr = IITLockBytes::CopyLockBytes
  728. (m_plbMedium, m_PathInfo.ullcbOffset,
  729. ullLimitSegment, m_plbTemp, 0
  730. );
  731. if (!SUCCEEDED(hr))
  732. {
  733. m_plbTemp->Release();
  734. m_plbTemp = NULL;
  735. }
  736. }
  737. }
  738. }
  739. return hr;
  740. }
  741. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::LockRegion(
  742. /* [in] */ ULARGE_INTEGER libOffset,
  743. /* [in] */ ULARGE_INTEGER cb,
  744. /* [in] */ DWORD dwLockType)
  745. {
  746. RonM_ASSERT(m_plbMedium);
  747. /*
  748. LockRegion operations on lockbyte segments are little tricky because
  749. the data may exist in two places -- *m_plbMedium and *m_plbTemp.
  750. You might think we could just keep compare the lock span against the
  751. boundaries of the segment to determine which underlying lockbyte object
  752. should do the lock operation. In many situations that would work correctly.
  753. However if a Flush operation occurs when we have a temporary lockbytes object
  754. active, the segment boundaries will change. In addition the temporary
  755. object will be discarded.
  756. The solution then is to always use a third temporary lockbytes object
  757. to handle lock/unlock operations. Hence the need for m_plbLockMgr.
  758. */
  759. CSyncWith sw(g_csITFS);
  760. HRESULT hr = NO_ERROR;
  761. if (!m_plbLockMgr)
  762. {
  763. hr = CFSLockBytes::CreateTemp(NULL, &m_plbLockMgr);
  764. if (!SUCCEEDED(hr))
  765. return hr;
  766. }
  767. hr = m_plbLockMgr->LockRegion(libOffset, cb, dwLockType);
  768. return hr;
  769. }
  770. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::UnlockRegion(
  771. /* [in] */ ULARGE_INTEGER libOffset,
  772. /* [in] */ ULARGE_INTEGER cb,
  773. /* [in] */ DWORD dwLockType)
  774. {
  775. RonM_ASSERT(m_plbMedium);
  776. CSyncWith sw(g_csITFS);
  777. HRESULT hr = NO_ERROR;
  778. if (!m_plbLockMgr)
  779. hr = STG_E_LOCKVIOLATION;
  780. else hr = m_plbLockMgr->UnlockRegion(libOffset, cb, dwLockType);
  781. return hr;
  782. }
  783. HRESULT STDMETHODCALLTYPE CSegmentLockBytes::CImpILockBytes::Stat(
  784. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  785. /* [in] */ DWORD grfStatFlag)
  786. {
  787. RonM_ASSERT(m_plbMedium);
  788. CSyncWith sw(g_csITFS);
  789. HRESULT hr = NO_ERROR;
  790. hr= m_plbMedium->Stat(pstatstg, STATFLAG_NONAME);
  791. if (SUCCEEDED(hr))
  792. {
  793. if (m_plbTemp)
  794. {
  795. STATSTG statstgTmp;
  796. hr= m_plbTemp->Stat(&statstgTmp, STATFLAG_NONAME);
  797. if (SUCCEEDED(hr))
  798. pstatstg->cbSize = statstgTmp.cbSize;
  799. }
  800. else pstatstg->cbSize = m_PathInfo.ullcbData.Uli();
  801. if (grfStatFlag != STATFLAG_NONAME)
  802. {
  803. UINT cb = sizeof(WCHAR) * (m_PathInfo.cwcStreamPath + 1);
  804. pstatstg->pwcsName = PWCHAR(OLEHeap()->Alloc(cb));
  805. if (pstatstg->pwcsName)
  806. CopyMemory(pstatstg->pwcsName, m_PathInfo.awszStreamPath, cb);
  807. else hr = STG_E_INSUFFICIENTMEMORY;
  808. }
  809. }
  810. return hr;
  811. }
  812. TransformDescriptor::TransformDescriptor()
  813. {
  814. iSpace = ~0;
  815. pLockBytesChain = NULL;
  816. cTransformLayers = 0;
  817. apTransformInstance = NULL;
  818. }
  819. TransformDescriptor::~TransformDescriptor()
  820. {
  821. RonM_ASSERT(cs.LockCount() == 0);
  822. if (apTransformInstance)
  823. delete [] (PPITI)apTransformInstance;
  824. }
  825. TransformDescriptor *TransformDescriptor::Create(UINT iDataSpace, UINT cLayers)
  826. {
  827. TransformDescriptor *pTD = New TransformDescriptor();
  828. if (pTD)
  829. {
  830. pTD->cTransformLayers = cLayers;
  831. pTD->apTransformInstance = (PITransformInstance *)(New PPITI[cLayers]);
  832. if (pTD->apTransformInstance)
  833. ZeroMemory(pTD->apTransformInstance, cLayers * sizeof(PPITI));
  834. else
  835. {
  836. delete pTD; pTD = NULL;
  837. }
  838. }
  839. return pTD;
  840. }
  841. HRESULT CTransformedLockBytes::Open(IUnknown *punkOuter, PathInfo *pPathInfo,
  842. TransformDescriptor *pTransformDescriptor,
  843. IITFileSystem *pITFS,
  844. ILockBytes **ppLockBytes
  845. )
  846. {
  847. CSyncWith sw(g_csITFS);
  848. CTransformedLockBytes *pTLKB = New CTransformedLockBytes(punkOuter);
  849. return FinishSetup(pTLKB? pTLKB->m_ImpILockBytes.InitOpen
  850. (pPathInfo, pTransformDescriptor, pITFS)
  851. : STG_E_INSUFFICIENTMEMORY,
  852. pTLKB, IID_ILockBytes, (PPVOID) ppLockBytes
  853. );
  854. }
  855. // Constructor and Destructor:
  856. CTransformedLockBytes::CImpILockBytes::CImpILockBytes
  857. (CTransformedLockBytes *pBackObj, IUnknown *punkOuter)
  858. : IITLockBytes(pBackObj, punkOuter, m_PathInfo.awszStreamPath)
  859. {
  860. m_pTransformDescriptor = NULL;
  861. m_pTransformInstance = NULL;
  862. m_pITFS = NULL;
  863. m_plbLockMgr = NULL;
  864. m_fFlushed = TRUE;
  865. m_grfMode = 0;
  866. ZeroMemory(&m_PathInfo, sizeof(m_PathInfo));
  867. }
  868. CTransformedLockBytes::CImpILockBytes::~CImpILockBytes(void)
  869. {
  870. if (m_pTransformInstance)
  871. {
  872. if (!m_fFlushed)
  873. m_pTransformInstance->Flush();
  874. m_pTransformInstance->Release();
  875. if (m_plbLockMgr)
  876. m_plbLockMgr->Release();
  877. if (ActiveMark())
  878. MarkInactive();
  879. }
  880. if (m_pITFS)
  881. m_pITFS->Release();
  882. }
  883. // Initialing routines:
  884. HRESULT CTransformedLockBytes::CImpILockBytes::InitOpen(PathInfo *pPathInfo,
  885. TransformDescriptor *pTransformDescriptor,
  886. IITFileSystem *pITFS
  887. )
  888. {
  889. m_PathInfo = *pPathInfo;
  890. m_pTransformDescriptor = pTransformDescriptor;
  891. m_pTransformInstance = pTransformDescriptor->apTransformInstance[0];
  892. m_pITFS = pITFS;
  893. m_pTransformInstance->AddRef();
  894. m_pITFS ->AddRef();
  895. MarkActive(pTransformDescriptor->pLockBytesChain);
  896. return NO_ERROR;
  897. }
  898. ILockBytes *CTransformedLockBytes::CImpILockBytes::FindTransformedLockBytes
  899. (const WCHAR * pwszFileName,
  900. TransformDescriptor *pTransformDescriptor
  901. )
  902. {
  903. return FindMatchingLockBytes(pwszFileName, (CImpITUnknown *) pTransformDescriptor->pLockBytesChain);
  904. }
  905. // ILockBytes methods:
  906. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::ReadAt(
  907. /* [in] */ ULARGE_INTEGER ulOffset,
  908. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  909. /* [in] */ ULONG cb,
  910. /* [out] */ ULONG __RPC_FAR *pcbRead)
  911. {
  912. ImageSpan SpanInfo;
  913. SpanInfo.uliHandle = m_PathInfo.ullcbOffset.Uli();
  914. SpanInfo.uliSize = m_PathInfo.ullcbData .Uli();
  915. CSyncWith sw(m_pTransformDescriptor->cs);
  916. ULONG cbRead = 0;
  917. HRESULT hr = m_pTransformInstance->ReadAt(ulOffset, pv, cb, &cbRead, &SpanInfo);
  918. if (pcbRead)
  919. *pcbRead = cbRead;
  920. return hr;
  921. }
  922. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::WriteAt(
  923. /* [in] */ ULARGE_INTEGER ulOffset,
  924. /* [size_is][in] */ const void __RPC_FAR *pv,
  925. /* [in] */ ULONG cb,
  926. /* [out] */ ULONG __RPC_FAR *pcbWritten)
  927. {
  928. ImageSpan SpanInfo;
  929. SpanInfo.uliHandle = m_PathInfo.ullcbOffset.Uli();
  930. SpanInfo.uliSize = m_PathInfo.ullcbData .Uli();
  931. CSyncWith(m_pTransformDescriptor->cs);
  932. ULONG cbWritten = 0;
  933. HRESULT hr = m_pTransformInstance->WriteAt(ulOffset, pv, cb, &cbWritten, &SpanInfo);
  934. if (pcbWritten)
  935. *pcbWritten = cbWritten;
  936. if ( m_PathInfo.ullcbOffset != SpanInfo.uliHandle
  937. || m_PathInfo.ullcbData != SpanInfo.uliSize
  938. )
  939. {
  940. m_PathInfo.ullcbOffset = SpanInfo.uliHandle;
  941. m_PathInfo.ullcbData = SpanInfo.uliSize;
  942. CSyncWith sw(g_csITFS);
  943. HRESULT hr2 = m_pITFS->UpdatePathInfo(&m_PathInfo);
  944. if (!SUCCEEDED(hr2))
  945. return hr2;
  946. }
  947. return hr;
  948. }
  949. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::Flush( void)
  950. {
  951. CSyncWith sw(g_csITFS);
  952. HRESULT hr = m_pTransformInstance->Flush();
  953. return hr;
  954. }
  955. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::SetSize(
  956. /* [in] */ ULARGE_INTEGER cb)
  957. {
  958. return NO_ERROR;
  959. }
  960. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::LockRegion(
  961. /* [in] */ ULARGE_INTEGER libOffset,
  962. /* [in] */ ULARGE_INTEGER cb,
  963. /* [in] */ DWORD dwLockType)
  964. {
  965. CSyncWith sw(m_pTransformDescriptor->cs);
  966. HRESULT hr = NO_ERROR;
  967. if (!m_plbLockMgr)
  968. {
  969. hr = CFSLockBytes::CreateTemp(NULL, &m_plbLockMgr);
  970. if (!SUCCEEDED(hr))
  971. return hr;
  972. }
  973. return m_plbLockMgr->LockRegion(libOffset, cb, dwLockType);
  974. }
  975. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::UnlockRegion(
  976. /* [in] */ ULARGE_INTEGER libOffset,
  977. /* [in] */ ULARGE_INTEGER cb,
  978. /* [in] */ DWORD dwLockType)
  979. {
  980. CSyncWith(m_pTransformDescriptor->cs);
  981. HRESULT hr = NO_ERROR;
  982. if (!m_plbLockMgr)
  983. hr = STG_E_LOCKVIOLATION;
  984. else hr = m_plbLockMgr->UnlockRegion(libOffset, cb, dwLockType);
  985. return hr;
  986. }
  987. HRESULT STDMETHODCALLTYPE CTransformedLockBytes::CImpILockBytes::Stat(
  988. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  989. /* [in] */ DWORD grfStatFlag)
  990. {
  991. CSyncWith(m_pTransformDescriptor->cs);
  992. pstatstg->type = STGTY_LOCKBYTES;
  993. pstatstg->cbSize = m_PathInfo.ullcbData.Uli();
  994. pstatstg->grfMode = m_grfMode;
  995. pstatstg->grfLocksSupported = LOCK_EXCLUSIVE;
  996. pstatstg->clsid = CLSID_NULL;
  997. pstatstg->grfStateBits = 0;
  998. pstatstg->reserved = 0;
  999. pstatstg->mtime.dwLowDateTime = 0;
  1000. pstatstg->mtime.dwHighDateTime = 0;
  1001. pstatstg->ctime.dwLowDateTime = 0;
  1002. pstatstg->ctime.dwHighDateTime = 0;
  1003. pstatstg->atime.dwLowDateTime = 0;
  1004. pstatstg->atime.dwHighDateTime = 0;
  1005. HRESULT hr = NO_ERROR;
  1006. if (grfStatFlag != STATFLAG_NONAME)
  1007. {
  1008. UINT cb = sizeof(WCHAR) * (m_PathInfo.cwcStreamPath + 1);
  1009. pstatstg->pwcsName = PWCHAR(OLEHeap()->Alloc(cb));
  1010. if (pstatstg->pwcsName)
  1011. CopyMemory(pstatstg->pwcsName, m_PathInfo.awszStreamPath, cb);
  1012. else hr = STG_E_INSUFFICIENTMEMORY;
  1013. }
  1014. return hr;
  1015. }
  1016. CStrmLockBytes::CImpILockBytes::CImpILockBytes
  1017. (CStrmLockBytes *pBackObj, IUnknown *punkOuter)
  1018. : IITLockBytes(pBackObj, punkOuter, this->m_awszLkBName)
  1019. {
  1020. m_pStream = NULL;
  1021. }
  1022. CStrmLockBytes::CImpILockBytes::~CImpILockBytes(void)
  1023. {
  1024. if (m_pStream)
  1025. m_pStream->Release();
  1026. }
  1027. HRESULT CStrmLockBytes::OpenUrlStream
  1028. (const WCHAR *pwszURL, ILockBytes **pplkb)
  1029. {
  1030. CSyncWith sw(g_csITFS);
  1031. ILockBytes *pLkb = CStrmLockBytes::CImpILockBytes::FindStrmLockBytes(pwszURL);
  1032. if (pLkb)
  1033. {
  1034. *pplkb = pLkb;
  1035. return NO_ERROR;
  1036. }
  1037. CStrmLockBytes *pLkbStream = New CStrmLockBytes(NULL);
  1038. return FinishSetup(pLkbStream? pLkbStream->m_ImpILockBytes.InitUrlStream(pwszURL)
  1039. : STG_E_INSUFFICIENTMEMORY,
  1040. pLkbStream, IID_ILockBytes, (PPVOID) pplkb
  1041. );
  1042. }
  1043. HRESULT CStrmLockBytes::Create(IUnknown *punkOuter, IStream *pStrm, ILockBytes **pplkb)
  1044. {
  1045. CStrmLockBytes *pLkbStream = New CStrmLockBytes(punkOuter);
  1046. return FinishSetup(pLkbStream? pLkbStream->m_ImpILockBytes.Init(pStrm)
  1047. : STG_E_INSUFFICIENTMEMORY,
  1048. pLkbStream, IID_ILockBytes, (PPVOID) pplkb
  1049. );
  1050. }
  1051. // Initialing routines:
  1052. HRESULT CStrmLockBytes::CImpILockBytes::InitUrlStream(const WCHAR *pwszURL)
  1053. {
  1054. UINT cwc = wcsLen(pwszURL);
  1055. if (cwc >= MAX_PATH)
  1056. return STG_E_INVALIDNAME;
  1057. CopyMemory(m_awszLkBName, pwszURL, sizeof(WCHAR) * (cwc + 1));
  1058. IStream *pstrmRoot = NULL;
  1059. HRESULT hr = URLOpenBlockingStreamW(NULL, pwszURL, &pstrmRoot, 0, NULL);
  1060. if (!SUCCEEDED(hr)) return hr;
  1061. m_pStream = pstrmRoot; pstrmRoot = NULL;
  1062. MarkActive(g_pStrmLockBytesFirstActive);
  1063. return NO_ERROR;
  1064. }
  1065. HRESULT CStrmLockBytes::CImpILockBytes::Init(IStream *pStrm)
  1066. {
  1067. STATSTG statstg;
  1068. HRESULT hr = pStrm->Stat(&statstg, STATFLAG_DEFAULT);
  1069. if (!SUCCEEDED(hr)) return hr;
  1070. UINT cwc = wcsLen(statstg.pwcsName);
  1071. if (cwc >= MAX_PATH)
  1072. {
  1073. OLEHeap()->Free(statstg.pwcsName);
  1074. return STG_E_INVALIDNAME;
  1075. }
  1076. CopyMemory(m_awszLkBName, statstg.pwcsName, sizeof(WCHAR) * (cwc + 1));
  1077. OLEHeap()->Free(statstg.pwcsName);
  1078. m_pStream = pStrm;
  1079. m_pStream->AddRef();
  1080. MarkActive(g_pStrmLockBytesFirstActive);
  1081. return NO_ERROR;
  1082. }
  1083. // Search routine
  1084. ILockBytes *CStrmLockBytes::CImpILockBytes::FindStrmLockBytes(const WCHAR * pwszFileName)
  1085. {
  1086. return FindMatchingLockBytes(pwszFileName, (CImpITUnknown *) g_pStrmLockBytesFirstActive);
  1087. }
  1088. // ILockBytes methods:
  1089. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::ReadAt(
  1090. /* [in] */ ULARGE_INTEGER ulOffset,
  1091. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  1092. /* [in] */ ULONG cb,
  1093. /* [out] */ ULONG __RPC_FAR *pcbRead)
  1094. {
  1095. CSyncWith sw(m_cs);
  1096. HRESULT hr = m_pStream->Seek(*(LARGE_INTEGER *)&ulOffset, STREAM_SEEK_SET, NULL);
  1097. if (!SUCCEEDED(hr)) return hr;
  1098. hr = m_pStream->Read(pv, cb, pcbRead);
  1099. return hr;
  1100. }
  1101. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::WriteAt(
  1102. /* [in] */ ULARGE_INTEGER ulOffset,
  1103. /* [size_is][in] */ const void __RPC_FAR *pv,
  1104. /* [in] */ ULONG cb,
  1105. /* [out] */ ULONG __RPC_FAR *pcbWritten)
  1106. {
  1107. CSyncWith sw(m_cs);
  1108. HRESULT hr = m_pStream->Seek(*(LARGE_INTEGER *)&ulOffset, STREAM_SEEK_SET, NULL);
  1109. if (!SUCCEEDED(hr)) return hr;
  1110. hr = m_pStream->Write(pv, cb, pcbWritten);
  1111. return hr;
  1112. }
  1113. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::Flush( void)
  1114. {
  1115. return NO_ERROR;
  1116. }
  1117. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::SetSize(
  1118. /* [in] */ ULARGE_INTEGER cb)
  1119. {
  1120. return m_pStream->SetSize(cb);
  1121. }
  1122. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::LockRegion(
  1123. /* [in] */ ULARGE_INTEGER libOffset,
  1124. /* [in] */ ULARGE_INTEGER cb,
  1125. /* [in] */ DWORD dwLockType)
  1126. {
  1127. return m_pStream->LockRegion(libOffset, cb, dwLockType);
  1128. }
  1129. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::UnlockRegion(
  1130. /* [in] */ ULARGE_INTEGER libOffset,
  1131. /* [in] */ ULARGE_INTEGER cb,
  1132. /* [in] */ DWORD dwLockType)
  1133. {
  1134. return m_pStream->UnlockRegion(libOffset, cb, dwLockType);
  1135. }
  1136. HRESULT STDMETHODCALLTYPE CStrmLockBytes::CImpILockBytes::Stat(
  1137. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  1138. /* [in] */ DWORD grfStatFlag)
  1139. {
  1140. HRESULT hr = m_pStream->Stat(pstatstg, grfStatFlag);
  1141. if (SUCCEEDED(hr))
  1142. pstatstg->type = STGTY_LOCKBYTES;
  1143. return hr;
  1144. }