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.

1471 lines
39 KiB

  1. // Storage.cpp -- Implementation of class CStorage
  2. #include "stdafx.h"
  3. DEBUGDEF(LONG CStorage:: CImpIStorage::s_cInCriticalSection = 0)
  4. DEBUGDEF(LONG CFSStorage::CImpIFSStorage::s_cInCriticalSection = 0)
  5. HRESULT STDMETHODCALLTYPE CopyStorage(IStorage *pStgDest, IStorage *pStgSrc,
  6. BOOL fCopyStorages, BOOL fCopyStreams
  7. )
  8. {
  9. HRESULT hr = NO_ERROR;
  10. IEnumSTATSTG *pEnumStatStg = NULL;
  11. hr = pStgSrc->EnumElements(0, NULL, 0, &pEnumStatStg);
  12. if (hr != S_OK) return hr;
  13. typedef struct _NameList
  14. {
  15. struct _NameList *pNextName;
  16. const WCHAR *pStorageName;
  17. } NameList, *PNameList;
  18. NameList *pNLHead = NULL;
  19. const WCHAR *pwcsItem = NULL;
  20. for (; ;)
  21. {
  22. STATSTG statstg;
  23. ULONG cElts;
  24. hr = pEnumStatStg->Next(1, &statstg, &cElts);
  25. if (hr == S_FALSE) break;
  26. if (hr == S_OK && cElts != 1)
  27. hr = STG_E_UNKNOWN;
  28. if (hr != S_OK) break;
  29. IStream *pStrmDest = NULL,
  30. *pStrmSrc = NULL;
  31. pwcsItem = (const WCHAR *) statstg.pwcsName;
  32. switch(statstg.type)
  33. {
  34. case STGTY_STORAGE:
  35. if (!fCopyStorages) break;
  36. {
  37. PNameList pNL = New NameList;
  38. pNL->pNextName = pNLHead;
  39. pNL->pStorageName = pwcsItem;
  40. pwcsItem = NULL;
  41. pNLHead = pNL;
  42. }
  43. break;
  44. case STGTY_STREAM:
  45. if (!fCopyStreams) break;
  46. hr = pStgDest->CreateStream(pwcsItem,
  47. STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  48. | STGM_CREATE,
  49. 0, 0, &pStrmDest
  50. );
  51. if (hr != S_OK) break;
  52. hr = pStgSrc->OpenStream(pwcsItem, NULL, STGM_READ | STGM_SHARE_DENY_NONE,
  53. 0, &pStrmSrc
  54. );
  55. if (hr != S_OK) break;
  56. hr = pStrmSrc->CopyTo(pStrmDest, statstg.cbSize, NULL, NULL);
  57. break;
  58. case STGTY_LOCKBYTES:
  59. case STGTY_PROPERTY:
  60. default:
  61. hr = STG_E_UNKNOWN;
  62. break;
  63. }
  64. if (pwcsItem)
  65. {
  66. OLEHeap()->Free((void *) pwcsItem);
  67. pwcsItem = NULL;
  68. }
  69. if (pStrmDest)
  70. {
  71. pStrmDest->Release();
  72. pStrmDest = NULL;
  73. }
  74. if (pStrmSrc)
  75. {
  76. pStrmSrc->Release();
  77. pStrmSrc = NULL;
  78. }
  79. if (hr != S_OK) break;
  80. }
  81. pEnumStatStg->Release();
  82. pEnumStatStg = NULL;
  83. RonM_ASSERT(hr != S_OK);
  84. if (hr == S_FALSE)
  85. hr = S_OK;
  86. for (;;)
  87. {
  88. PNameList pNL = pNLHead;
  89. if (!pNL) break;
  90. pNLHead = pNL->pNextName;
  91. if (hr == S_OK)
  92. {
  93. IStorage *pStgChildDest = NULL,
  94. *pStgChildSrc = NULL;
  95. hr = pStgDest->CreateStorage(pNL->pStorageName,
  96. STGM_READWRITE | STGM_SHARE_EXCLUSIVE
  97. | STGM_CREATE,
  98. 0, 0, &pStgChildDest
  99. );
  100. if (hr == S_OK)
  101. hr = pStgSrc->OpenStorage(pNL->pStorageName, NULL,
  102. STGM_READ | STGM_SHARE_DENY_NONE,
  103. NULL, 0, &pStgChildSrc
  104. );
  105. if (hr == S_OK)
  106. hr = CopyStorage(pStgChildDest, pStgChildSrc, fCopyStorages, fCopyStreams);
  107. if (pStgChildDest)
  108. pStgChildDest->Release();
  109. if (pStgChildSrc)
  110. pStgChildSrc->Release();
  111. }
  112. OLEHeap()->Free((void *) pNL->pStorageName);
  113. delete pNL;
  114. }
  115. return hr;
  116. }
  117. HRESULT __stdcall CStorage::OpenStorage(IUnknown *pUnkOuter,
  118. IITFileSystem *pITFS,
  119. PathInfo *pPathInfo,
  120. DWORD grfMode,
  121. IStorageITEx **ppStg
  122. )
  123. {
  124. CStorage *pstg = New CStorage(pUnkOuter);
  125. return FinishSetup(pstg? pstg->m_ImpIStorage.InitOpenStorage(pITFS, pPathInfo, grfMode)
  126. : STG_E_INSUFFICIENTMEMORY,
  127. pstg, IID_IStorageITEx, (PPVOID) ppStg
  128. );
  129. }
  130. CStorage::CImpIStorage::CImpIStorage(CStorage *pBackObj, IUnknown *pUnkOuter)
  131. : IIT_IStorageITEx(pBackObj, pUnkOuter, this->m_PathInfo.awszStreamPath)
  132. {
  133. m_pITFS = NULL;
  134. m_grfMode = 0;
  135. m_fWritable = FALSE;
  136. ZeroMemory(&m_PathInfo, sizeof m_PathInfo);
  137. }
  138. HRESULT __stdcall CStorage::CImpIStorage::InitOpenStorage
  139. (IITFileSystem *pITFS, PathInfo *pPathInfo, DWORD grfMode)
  140. {
  141. pITFS->AddRef();
  142. m_pITFS = pITFS;
  143. m_PathInfo = *pPathInfo;
  144. m_grfMode = grfMode;
  145. m_fWritable = S_OK == m_pITFS->IsWriteable();
  146. m_pITFS->ConnectStorage(this);
  147. return NO_ERROR;
  148. }
  149. CStorage::CImpIStorage::~CImpIStorage(void)
  150. {
  151. if (ActiveMark())
  152. MarkInactive();
  153. if (m_PathInfo.awszStreamPath[0] != L'/')
  154. m_pITFS->FSObjectReleased();
  155. m_pITFS->Release();
  156. }
  157. // IUnknown methods:
  158. STDMETHODIMP_(ULONG) CStorage::CImpIStorage::Release(void)
  159. {
  160. // The actual work for the Release function is done by
  161. // CImpITUnknown::Release() and ~CImpIStorage.
  162. //
  163. // We bracket that work as a critical section active storages
  164. // are kept in a linked list. A release operation may remove
  165. // this storage from that list, and we need to guard against
  166. // having someone find a reference to this storage just before
  167. // we destroy it.
  168. CSyncWith sw(g_csITFS);
  169. ULONG ulCnt = CImpITUnknown::Release();
  170. return ulCnt;
  171. }
  172. // IStorage methods:
  173. HRESULT __stdcall CStorage::CImpIStorage::CreateStream(
  174. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  175. /* [in] */ DWORD grfMode,
  176. /* [in] */ DWORD reserved1,
  177. /* [in] */ DWORD reserved2,
  178. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  179. {
  180. WCHAR awszNewBasePath[MAX_PATH];
  181. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
  182. if (SUCCEEDED(hr))
  183. hr = m_pITFS->CreateStream(NULL, awszNewBasePath, grfMode, (IStreamITEx **) ppstm);
  184. return hr;
  185. }
  186. /* [local] */ HRESULT __stdcall CStorage::CImpIStorage::OpenStream(
  187. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  188. /* [unique][in] */ void __RPC_FAR *reserved1,
  189. /* [in] */ DWORD grfMode,
  190. /* [in] */ DWORD reserved2,
  191. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  192. {
  193. return OpenStreamITEx(pwcsName, reserved1, grfMode, reserved2, (IStreamITEx **)ppstm);
  194. }
  195. HRESULT __stdcall CStorage::CImpIStorage::CreateStorage(
  196. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  197. /* [in] */ DWORD grfMode,
  198. /* [in] */ DWORD dwStgFmt,
  199. /* [in] */ DWORD reserved2,
  200. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  201. {
  202. WCHAR awszNewBasePath[MAX_PATH];
  203. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
  204. if (SUCCEEDED(hr))
  205. hr = m_pITFS->CreateStorage(NULL, awszNewBasePath, grfMode, (IStorageITEx **) ppstg);
  206. RonM_ASSERT(IsUnlocked(g_csITFS));
  207. return hr;
  208. }
  209. HRESULT __stdcall CStorage::CImpIStorage::OpenStorage(
  210. /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
  211. /* [unique][in] */ IStorage __RPC_FAR *pstgPriority,
  212. /* [in] */ DWORD grfMode,
  213. /* [unique][in] */ SNB snbExclude,
  214. /* [in] */ DWORD reserved,
  215. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  216. {
  217. WCHAR awszNewBasePath[MAX_PATH];
  218. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
  219. if (SUCCEEDED(hr))
  220. hr = m_pITFS->OpenStorage(NULL, awszNewBasePath, grfMode, (IStorageITEx **) ppstg);
  221. RonM_ASSERT(IsUnlocked(g_csITFS));
  222. return hr;
  223. }
  224. BOOL CStorage::ValidStreamName(const WCHAR *pwcsName)
  225. {
  226. UINT cwcName = wcsLen(pwcsName);
  227. if (!cwcName)
  228. return FALSE;
  229. for (; cwcName--; )
  230. {
  231. WCHAR wc = *pwcsName++;
  232. if (wc < 0x20 || wc == L'<'
  233. || wc == L'>'
  234. || wc == L':'
  235. || wc == L'"'
  236. || wc == L'|'
  237. || wc == L'/'
  238. || wc == L'\\'
  239. )
  240. return FALSE;
  241. }
  242. return TRUE;
  243. }
  244. HRESULT __stdcall ResolvePath(PWCHAR pwcFullPath, const WCHAR *pwcBasePath,
  245. const WCHAR *pwcRelativePath,
  246. BOOL fStoragePath
  247. )
  248. {
  249. if (pwcBasePath[0] != 0)
  250. wcsCpy(pwcFullPath, pwcBasePath);
  251. else
  252. if ( (pwcRelativePath[0] == L'/' || pwcRelativePath[0] == L'\\')
  253. && (pwcRelativePath[1] == L'/' || pwcRelativePath[1] == L'\\')
  254. )
  255. {
  256. // This is a UNC path. We expect the syntax pattern //ServerName/
  257. wcsCpy(pwcFullPath, L"//");
  258. pwcRelativePath += 2;
  259. PWCHAR pwcDest = pwcFullPath + 2;
  260. // The code below copies across the server name.
  261. for (;;)
  262. {
  263. WCHAR wc = *pwcRelativePath++;
  264. if (wc == L'\\')
  265. wc = L'/';
  266. if (wc < 0x20 || wc == L'<'
  267. || wc == L'>'
  268. || wc == L':'
  269. || wc == L'"'
  270. || wc == L'|'
  271. )
  272. return STG_E_INVALIDNAME; // Invalid path character
  273. if (pwcDest - pwcFullPath > MAX_PATH - 2)
  274. return STG_E_INVALIDNAME;
  275. *pwcDest++ = wc;
  276. // The code below rejects server names "." and ".."
  277. if (wc == L'/')
  278. {
  279. if (pwcDest[-2] == L'.')
  280. if ( pwcDest[-3] == L'/'
  281. || (pwcDest[-3] == L'.' && pwcDest[-4] == L'/')
  282. ) return STG_E_INVALIDNAME;
  283. break;
  284. }
  285. }
  286. *pwcDest= 0;
  287. }
  288. else
  289. if ( pwcRelativePath[0]
  290. && Is_WC_Letter(pwcRelativePath[0])
  291. && pwcRelativePath[1] == L':'
  292. && (pwcRelativePath[2] == L'/' || pwcRelativePath[2] == L'\\')
  293. )
  294. {
  295. pwcFullPath[0] = pwcRelativePath[0];
  296. pwcFullPath[1] = L':';
  297. pwcFullPath[2] = L'/';
  298. pwcFullPath[3] = 0;
  299. pwcRelativePath += 3;
  300. }
  301. else
  302. {
  303. char aszCurrentDir[MAX_PATH];
  304. UINT cch = GetCurrentDirectory(MAX_PATH, aszCurrentDir);
  305. if (!cch)
  306. return CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  307. UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
  308. aszCurrentDir, lstrlenA(aszCurrentDir) + 1,
  309. pwcFullPath, MAX_PATH
  310. );
  311. if (!cwc || cwc == MAX_PATH)
  312. return STG_E_INVALIDNAME;
  313. RonM_ASSERT(cwc >= 2 && pwcFullPath[cwc - 2] != L'/'
  314. && pwcFullPath[cwc - 2] != L'\\');
  315. pwcFullPath[cwc - 1] = L'/';
  316. pwcFullPath[cwc ] = 0;
  317. PWCHAR pwc = pwcFullPath + --cwc;
  318. for (; cwc--; )
  319. {
  320. WCHAR wc = *--pwc;
  321. if (wc == L'\\')
  322. *pwc = L'/';
  323. }
  324. }
  325. RonM_ASSERT(pwcFullPath[0] != 0);
  326. PWCHAR pwcBase = pwcFullPath;
  327. if ( (pwcBase[0] == L'/' && pwcBase[1] == L'/')
  328. || (pwcBase[0] == L':' && pwcBase[1] == L':')
  329. )
  330. for (pwcBase += 2; L'/' != *pwcBase++; )
  331. RonM_ASSERT(pwcBase[-1]);
  332. else
  333. if (Is_WC_Letter(pwcBase[0]) && pwcBase[1] == L':' && pwcBase[2] == L'/')
  334. pwcBase += 3;
  335. else pwcBase++;
  336. RonM_ASSERT(pwcBase[-1] == L'/');
  337. WCHAR wcFirst = *pwcRelativePath;
  338. if (wcFirst == L'/' || wcFirst == L'\\')
  339. {
  340. if (*pwcFullPath == L':')
  341. return STG_E_INVALIDNAME;
  342. *pwcBase = 0;
  343. ++pwcRelativePath;
  344. }
  345. PWCHAR pwcNext= pwcFullPath + wcsLen(pwcFullPath);
  346. for (;;)
  347. {
  348. WCHAR wc= *pwcRelativePath++;
  349. if (wc == L'\\')
  350. wc = L'/';
  351. if (!wc || wc == L'/')
  352. {
  353. RonM_ASSERT(pwcNext >= pwcBase); // We start with at least "/" and
  354. // never go shorter than that.
  355. WCHAR wcLast = pwcNext[-1];
  356. if (wcLast == L'/')
  357. {
  358. if (!wc)
  359. break;
  360. else return STG_E_INVALIDNAME; // Empty storage name
  361. }
  362. if (wcLast == L'.')
  363. {
  364. RonM_ASSERT(pwcNext > pwcBase); // Must be at least "/."
  365. WCHAR wcNextToLast= pwcNext[-2];
  366. if (wcNextToLast == L'/')
  367. {
  368. // We've found the pattern "<prefix>/./" which we convert to
  369. // "<prefix>/".
  370. pwcNext--;
  371. continue;
  372. }
  373. if (wcNextToLast == L'.')
  374. {
  375. RonM_ASSERT(pwcNext > pwcBase + 1); // Must be at least "/.."
  376. if (pwcNext[-3] == L'/')
  377. {
  378. // We've found the pattern "<prefix>/<StorageName>/../"
  379. // which we convert to "<prefix>/".
  380. // We don't allow this for paths beginning with ":".
  381. // Those are system paths. For example --
  382. //
  383. // ::Transform/{200EAF82-9006-11d0-9E15-00A0C922E6EC}/InstanceData/
  384. if (*pwcFullPath == L':')
  385. return STG_E_INVALIDNAME;
  386. // We must verify that we don't have "/../"
  387. if (pwcNext == pwcBase + 2) // Can't back up beyond root!
  388. return STG_E_INVALIDNAME;
  389. for (pwcNext-= 4; *pwcNext != L'/'; pwcNext--);
  390. ++pwcNext;
  391. continue;
  392. }
  393. }
  394. }
  395. if (wc || fStoragePath) // Trailing null adds a "/" only when we're
  396. *pwcNext++ = L'/'; // constructing a directory path.
  397. if (pwcNext - pwcFullPath >= MAX_PATH)
  398. return STG_E_INVALIDNAME; // BugBug: Really should be "path too long".
  399. if (!wc)
  400. break;
  401. else continue;
  402. }
  403. if (wc < 0x20 || wc == L'<'
  404. || wc == L'>'
  405. || wc == L':'
  406. || wc == L'"'
  407. || wc == L'|'
  408. )
  409. return STG_E_INVALIDNAME; // Invalid path character
  410. *pwcNext++ = wc;
  411. if (pwcNext - pwcFullPath >= MAX_PATH)
  412. return STG_E_INVALIDNAME; // BugBug: Really should be "path too long".
  413. }
  414. RonM_ASSERT(pwcNext > pwcFullPath);
  415. if (!fStoragePath && pwcNext[-1] == L'/')
  416. return STG_E_INVALIDNAME; // BugBug: Really should be "Not a valid stream name"
  417. *pwcNext= 0;
  418. return NOERROR;
  419. }
  420. HRESULT STGCopyTo(IStorage *pStgSrc, DWORD ciidExclude, const IID __RPC_FAR *rgiidExclude,
  421. SNB snbExclude, IStorage __RPC_FAR *pstgDest
  422. )
  423. {
  424. if (snbExclude)
  425. return STG_E_UNIMPLEMENTEDFUNCTION;
  426. BOOL fCopyStorages = TRUE,
  427. fCopyStreams = TRUE;
  428. for (; ciidExclude--; rgiidExclude++)
  429. {
  430. if (*rgiidExclude == IID_IStorage)
  431. fCopyStorages = FALSE;
  432. if (*rgiidExclude == IID_IStream)
  433. fCopyStreams = FALSE;
  434. }
  435. return CopyStorage(pstgDest, pStgSrc, fCopyStorages, fCopyStreams);
  436. }
  437. HRESULT __stdcall CStorage::CImpIStorage::CopyTo(
  438. /* [in] */ DWORD ciidExclude,
  439. /* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude,
  440. /* [unique][in] */ SNB snbExclude,
  441. /* [unique][in] */ IStorage __RPC_FAR *pstgDest)
  442. {
  443. return STGCopyTo((IStorage *) this, ciidExclude, rgiidExclude, snbExclude, pstgDest);
  444. }
  445. HRESULT __stdcall CStorage::CImpIStorage::MoveElementTo(
  446. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  447. /* [unique][in] */ IStorage __RPC_FAR *pstgDest,
  448. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName,
  449. /* [in] */ DWORD grfFlags)
  450. {
  451. RonM_ASSERT(FALSE); // To catch unexpected uses of this interface...
  452. return E_NOTIMPL;
  453. }
  454. HRESULT __stdcall CStorage::CImpIStorage::Commit(
  455. /* [in] */ DWORD grfCommitFlags)
  456. {
  457. return S_OK;
  458. }
  459. HRESULT __stdcall CStorage::CImpIStorage::Revert( void)
  460. {
  461. RonM_ASSERT(FALSE); // To catch unexpected uses of this interface...
  462. return E_NOTIMPL;
  463. }
  464. HRESULT __stdcall CStorage::CImpIStorage::EnumElements
  465. (DWORD reserved1, void __RPC_FAR *reserved2,
  466. DWORD reserved3,
  467. IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum
  468. )
  469. {
  470. return CEnumStorage::NewEnumStorage(NULL, m_pITFS, &m_PathInfo, ppenum);
  471. }
  472. HRESULT __stdcall CStorage::CImpIStorage::DestroyElement(
  473. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName)
  474. {
  475. WCHAR awszNewBasePath[MAX_PATH];
  476. // The call to ResolvePath combines pwcsName with the base path string
  477. // associated with this storage. It will also force a trailing L'/' character.
  478. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, TRUE);
  479. if (SUCCEEDED(hr))
  480. {
  481. UINT cwc = lstrlenW(awszNewBasePath);
  482. // Now we're going to delete the trailing '/' character to meet
  483. // the needs of the DeleteItem method.
  484. RonM_ASSERT(cwc > 0);
  485. RonM_ASSERT(awszNewBasePath[cwc-1] == L'/');
  486. awszNewBasePath[cwc-1] = 0;
  487. hr = m_pITFS->DeleteItem(awszNewBasePath);
  488. }
  489. return hr;
  490. }
  491. HRESULT __stdcall CStorage::CImpIStorage::RenameElement(
  492. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName,
  493. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName)
  494. {
  495. WCHAR awszOldBasePath[MAX_PATH];
  496. WCHAR awszNewBasePath[MAX_PATH];
  497. // The calls to ResolvePath combine pwcsOldName and pwcsNewName with the base path string
  498. // associated with this storage. It will also force a trailing L'/' character.
  499. HRESULT hr = ResolvePath(awszOldBasePath, m_PathInfo.awszStreamPath, pwcsOldName, TRUE);
  500. if (SUCCEEDED(hr))
  501. hr = ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsNewName, TRUE);
  502. if (SUCCEEDED(hr))
  503. {
  504. // Now we're going to delete the trailing '/' characters to meet
  505. // the needs of the RenameItem method.
  506. UINT cwc = lstrlenW(awszOldBasePath);
  507. RonM_ASSERT(cwc > 0);
  508. RonM_ASSERT(awszOldBasePath[cwc-1] == L'/');
  509. awszOldBasePath[cwc-1] = 0;
  510. cwc = lstrlenW(awszNewBasePath);
  511. RonM_ASSERT(cwc > 0);
  512. RonM_ASSERT(awszNewBasePath[cwc-1] == L'/');
  513. awszNewBasePath[cwc-1] = 0;
  514. hr = m_pITFS->RenameItem(awszOldBasePath, awszNewBasePath);
  515. }
  516. return hr;
  517. }
  518. HRESULT __stdcall CStorage::CImpIStorage::SetElementTimes(
  519. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  520. /* [in] */ const FILETIME __RPC_FAR *pctime,
  521. /* [in] */ const FILETIME __RPC_FAR *patime,
  522. /* [in] */ const FILETIME __RPC_FAR *pmtime)
  523. {
  524. if ( m_PathInfo.cwcStreamPath != 1
  525. && m_PathInfo.awszStreamPath[0] != L'/'
  526. && S_OK != m_pITFS->SetITFSTimes(pctime, patime, pmtime)
  527. )
  528. return NO_ERROR;
  529. return STG_E_UNIMPLEMENTEDFUNCTION;
  530. }
  531. HRESULT __stdcall CStorage::CImpIStorage::SetClass(
  532. /* [in] */ REFCLSID clsid)
  533. {
  534. m_PathInfo.clsidStorage = clsid;
  535. return m_pITFS->UpdatePathInfo(&m_PathInfo);
  536. }
  537. HRESULT __stdcall CStorage::CImpIStorage::SetStateBits(
  538. /* [in] */ DWORD grfStateBits,
  539. /* [in] */ DWORD grfMask)
  540. {
  541. m_PathInfo.uStateBits = (m_PathInfo.uStateBits & ~grfMask) | grfStateBits;
  542. return m_pITFS->UpdatePathInfo(&m_PathInfo);
  543. }
  544. HRESULT __stdcall CStorage::CImpIStorage::Stat(
  545. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  546. /* [in] */ DWORD grfStatFlag)
  547. {
  548. pstatstg->type = STGTY_STORAGE;
  549. pstatstg->cbSize.LowPart = 0;
  550. pstatstg->cbSize.HighPart = 0;
  551. pstatstg->grfMode = m_grfMode;
  552. pstatstg->grfLocksSupported = 0;
  553. pstatstg->clsid = m_PathInfo.clsidStorage;
  554. pstatstg->grfStateBits = m_PathInfo.uStateBits;
  555. pstatstg->reserved = 0;
  556. if ( m_PathInfo.cwcStreamPath != 1
  557. || m_PathInfo.awszStreamPath[0] != L'/'
  558. || S_OK != m_pITFS->GetITFSTimes(&(pstatstg->ctime),
  559. &(pstatstg->atime),
  560. &(pstatstg->mtime)
  561. )
  562. )
  563. {
  564. pstatstg->mtime.dwLowDateTime = 0;
  565. pstatstg->ctime.dwLowDateTime = 0;
  566. pstatstg->atime.dwLowDateTime = 0;
  567. pstatstg->mtime.dwHighDateTime = 0;
  568. pstatstg->ctime.dwHighDateTime = 0;
  569. pstatstg->atime.dwHighDateTime = 0;
  570. }
  571. if (grfStatFlag == STATFLAG_NONAME)
  572. pstatstg->pwcsName = NULL;
  573. else
  574. {
  575. UINT cb = sizeof(WCHAR) * (m_PathInfo.cwcStreamPath + 1);
  576. pstatstg->pwcsName = PWCHAR(OLEHeap()->Alloc(cb));
  577. if (!pstatstg->pwcsName)
  578. return STG_E_INSUFFICIENTMEMORY;
  579. CopyMemory(pstatstg->pwcsName, m_PathInfo.awszStreamPath, cb);
  580. }
  581. return NO_ERROR;
  582. }
  583. HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::GetCheckSum(ULARGE_INTEGER *puli)
  584. {
  585. RonM_ASSERT(FALSE);
  586. return E_NOTIMPL;
  587. }
  588. HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::CreateStreamITEx
  589. (const WCHAR * pwcsName, const WCHAR *pwcsDataSpaceName,
  590. DWORD grfMode, DWORD reserved1, DWORD reserved2,
  591. IStreamITEx ** ppstm
  592. )
  593. {
  594. WCHAR awszNewBasePath[MAX_PATH];
  595. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
  596. if (SUCCEEDED(hr))
  597. hr = m_pITFS->CreateStream(NULL, awszNewBasePath, pwcsDataSpaceName, grfMode, ppstm);
  598. return hr;
  599. }
  600. HRESULT STDMETHODCALLTYPE CStorage::CImpIStorage::OpenStreamITEx
  601. (const OLECHAR * pwcsName, void * reserved1, DWORD grfMode,
  602. DWORD reserved2, IStreamITEx ** ppstm
  603. )
  604. {
  605. WCHAR awszNewBasePath[MAX_PATH];
  606. HRESULT hr= ResolvePath(awszNewBasePath, m_PathInfo.awszStreamPath, pwcsName, FALSE);
  607. if (SUCCEEDED(hr))
  608. hr = m_pITFS->OpenStream(NULL, awszNewBasePath, grfMode, ppstm);
  609. return hr;
  610. }
  611. HRESULT __stdcall CFSStorage::CreateStorage
  612. (IUnknown *pUnkOuter, const WCHAR *pwcsPath, DWORD grfMode,
  613. IStorage **ppStg
  614. )
  615. {
  616. CSyncWith sw(g_csITFS);
  617. IStorage *pStorage = (IStorage *) CImpIFSStorage::FindStorage(pwcsPath, grfMode);
  618. if (pStorage)
  619. {
  620. pStorage->Release();
  621. return STG_E_INUSE;
  622. }
  623. CFSStorage *pstg = New CFSStorage(pUnkOuter);
  624. return FinishSetup(pstg? pstg->m_ImpIFSStorage.InitCreateStorage(pwcsPath, grfMode)
  625. : STG_E_INSUFFICIENTMEMORY,
  626. pstg, IID_IStorage, (PPVOID) ppStg
  627. );
  628. }
  629. HRESULT __stdcall CFSStorage::OpenStorage
  630. (IUnknown *pUnkOuter, const WCHAR *pwcsPath, DWORD grfMode,
  631. IStorage **ppStg
  632. )
  633. {
  634. CSyncWith sw(g_csITFS);
  635. IStorage *pStorage = CImpIFSStorage::FindStorage(pwcsPath, grfMode);
  636. if (pStorage)
  637. {
  638. *ppStg = pStorage;
  639. return NO_ERROR;
  640. }
  641. CFSStorage *pstg = New CFSStorage(pUnkOuter);
  642. return FinishSetup(pstg? pstg->m_ImpIFSStorage.InitOpenStorage(pwcsPath, grfMode)
  643. : STG_E_INSUFFICIENTMEMORY,
  644. pstg, IID_IStorage, (PPVOID) ppStg
  645. );
  646. }
  647. CFSStorage::CImpIFSStorage::CImpIFSStorage(CFSStorage *pBackObj, IUnknown *punkOuter)
  648. : IIT_IStorage(pBackObj, punkOuter, this->m_awcsPath)
  649. {
  650. m_awcsPath[0] = 0;
  651. m_CP = GetACP();
  652. }
  653. CFSStorage::CImpIFSStorage::~CImpIFSStorage(void)
  654. {
  655. if (ActiveMark())
  656. MarkInactive();
  657. }
  658. IStorage *CFSStorage::CImpIFSStorage::FindStorage(const WCHAR * pwszFileName, DWORD grfMode)
  659. {
  660. for (CImpITUnknown *pStg = g_pImpIFSStorageList;
  661. pStg;
  662. pStg = pStg->NextObject()
  663. )
  664. if (((CImpIFSStorage *)pStg)->IsNamed(pwszFileName))
  665. {
  666. pStg->AddRef();
  667. return (IStorage *) pStg;
  668. }
  669. return NULL;
  670. }
  671. HRESULT __stdcall BuildMultiBytePath(UINT codepage, PCHAR pszPath, PWCHAR pwcsPath)
  672. {
  673. UINT cb = WideCharToMultiByte(codepage, WC_COMPOSITECHECK, pwcsPath,
  674. wcsLen(pwcsPath) + 1, pszPath, MAX_PATH * 2,
  675. NULL, NULL
  676. );
  677. if (cb == 0)
  678. {
  679. UINT uLastError = GetLastError();
  680. switch(uLastError)
  681. {
  682. case ERROR_INSUFFICIENT_BUFFER:
  683. case ERROR_INVALID_FLAGS:
  684. case ERROR_INVALID_PARAMETER:
  685. return STG_E_INVALIDPARAMETER;
  686. default:
  687. return STG_E_UNKNOWN;
  688. }
  689. }
  690. return NO_ERROR;
  691. }
  692. HRESULT __stdcall CFSStorage::CImpIFSStorage::InitCreateStorage(const WCHAR *pwcsPath, DWORD grfMode)
  693. {
  694. HRESULT hr = ResolvePath(m_awcsPath, m_awcsPath, pwcsPath, TRUE);
  695. if (!SUCCEEDED(hr))
  696. return hr;
  697. char achFullPath[MAX_PATH * 2];
  698. hr = BuildMultiBytePath(m_CP, achFullPath, m_awcsPath);
  699. if (!SUCCEEDED(hr))
  700. return hr;
  701. if (CreateDirectory(achFullPath, NULL))
  702. hr = NO_ERROR;
  703. else
  704. hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  705. if (hr == S_OK)
  706. MarkActive(g_pImpIFSStorageList);
  707. return hr;
  708. }
  709. HRESULT __stdcall CFSStorage::CImpIFSStorage::InitOpenStorage (const WCHAR *pwcsPath, DWORD grfMode)
  710. {
  711. HRESULT hr = ResolvePath(m_awcsPath, m_awcsPath, pwcsPath, TRUE);
  712. if (!SUCCEEDED(hr))
  713. return hr;
  714. char achFullPath[MAX_PATH * 2];
  715. hr = BuildMultiBytePath(m_CP, achFullPath, m_awcsPath);
  716. if (!SUCCEEDED(hr))
  717. return hr;
  718. WIN32_FIND_DATA fd;
  719. HANDLE hFind = FindFirstFile(achFullPath, &fd);
  720. if (hFind == INVALID_HANDLE_VALUE)
  721. return CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  722. FindClose(hFind);
  723. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  724. {
  725. MarkActive(g_pImpIFSStorageList);
  726. return NO_ERROR;
  727. }
  728. else
  729. return STG_E_INVALIDNAME;
  730. }
  731. // IUnknown methods:
  732. STDMETHODIMP_(ULONG) CFSStorage::CImpIFSStorage::Release(void)
  733. {
  734. // The actual work for the Release function is done by
  735. // CImpITUnknown::Release() and ~CImpIStorage.
  736. //
  737. // We bracket that work as a critical section active storages
  738. // are kept in a linked list. A release operation may remove
  739. // this storage from that list, and we need to guard against
  740. // having someone find a reference to this storage just before
  741. // we destroy it.
  742. CSyncWith sw(g_csITFS);
  743. ULONG ulCnt = CImpITUnknown::Release();
  744. return ulCnt;
  745. }
  746. // IStorage methods:
  747. HRESULT __stdcall CFSStorage::CImpIFSStorage::CreateStream(
  748. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  749. /* [in] */ DWORD grfMode,
  750. /* [in] */ DWORD reserved1,
  751. /* [in] */ DWORD reserved2,
  752. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  753. {
  754. WCHAR awcsStreamPath[MAX_PATH];
  755. wcsCpy(awcsStreamPath, m_awcsPath);
  756. HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, FALSE);
  757. if (!SUCCEEDED(hr))
  758. return hr;
  759. ILockBytes *pLKB = NULL;
  760. hr = CFSLockBytes::Create(NULL, awcsStreamPath, grfMode, &pLKB);
  761. if (hr == S_OK)
  762. {
  763. hr = CStream::OpenStream(NULL, pLKB, grfMode, (IStreamITEx **) ppstm);
  764. if (hr != S_OK)
  765. pLKB->Release();
  766. }
  767. RonM_ASSERT(IsUnlocked(g_csITFS));
  768. return hr;
  769. }
  770. /* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::OpenStream(
  771. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  772. /* [unique][in] */ void __RPC_FAR *reserved1,
  773. /* [in] */ DWORD grfMode,
  774. /* [in] */ DWORD reserved2,
  775. /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm)
  776. {
  777. WCHAR awcsStreamPath[MAX_PATH];
  778. wcsCpy(awcsStreamPath, m_awcsPath);
  779. HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, FALSE);
  780. if (!SUCCEEDED(hr))
  781. return hr;
  782. ILockBytes *pLKB = NULL;
  783. hr = CFSLockBytes::Open(NULL, awcsStreamPath, grfMode, &pLKB);
  784. if (hr == S_OK)
  785. {
  786. hr = CStream::OpenStream(NULL, pLKB, grfMode, (IStreamITEx **) ppstm);
  787. if (hr != S_OK)
  788. pLKB->Release();
  789. }
  790. RonM_ASSERT(IsUnlocked(g_csITFS));
  791. return hr;
  792. }
  793. HRESULT __stdcall CFSStorage::CImpIFSStorage::CreateStorage(
  794. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  795. /* [in] */ DWORD grfMode,
  796. /* [in] */ DWORD dwStgFmt,
  797. /* [in] */ DWORD reserved2,
  798. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  799. {
  800. WCHAR awcsStreamPath[MAX_PATH];
  801. wcsCpy(awcsStreamPath, m_awcsPath);
  802. HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, TRUE);
  803. if (!SUCCEEDED(hr))
  804. return hr;
  805. hr = CFSStorage::CreateStorage(NULL, (const WCHAR *)awcsStreamPath, grfMode, ppstg);
  806. RonM_ASSERT(IsUnlocked(g_csITFS));
  807. return hr;
  808. }
  809. HRESULT __stdcall CFSStorage::CImpIFSStorage::OpenStorage(
  810. /* [string][unique][in] */ const OLECHAR __RPC_FAR *pwcsName,
  811. /* [unique][in] */ IStorage __RPC_FAR *pstgPriority,
  812. /* [in] */ DWORD grfMode,
  813. /* [unique][in] */ SNB snbExclude,
  814. /* [in] */ DWORD reserved,
  815. /* [out] */ IStorage __RPC_FAR *__RPC_FAR *ppstg)
  816. {
  817. WCHAR awcsStreamPath[MAX_PATH];
  818. wcsCpy(awcsStreamPath, m_awcsPath);
  819. HRESULT hr = ResolvePath(awcsStreamPath, m_awcsPath, pwcsName, TRUE);
  820. if (!SUCCEEDED(hr))
  821. return hr;
  822. hr = CFSStorage::OpenStorage(NULL, (const WCHAR *)awcsStreamPath, grfMode, ppstg);
  823. RonM_ASSERT(IsUnlocked(g_csITFS));
  824. return hr;
  825. }
  826. HRESULT __stdcall CFSStorage::CImpIFSStorage::CopyTo(
  827. /* [in] */ DWORD ciidExclude,
  828. /* [size_is][unique][in] */ const IID __RPC_FAR *rgiidExclude,
  829. /* [unique][in] */ SNB snbExclude,
  830. /* [unique][in] */ IStorage __RPC_FAR *pstgDest)
  831. {
  832. return STGCopyTo((IStorage *) this, ciidExclude, rgiidExclude, snbExclude, pstgDest);
  833. }
  834. HRESULT __stdcall CFSStorage::CImpIFSStorage::MoveElementTo(
  835. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  836. /* [unique][in] */ IStorage __RPC_FAR *pstgDest,
  837. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName,
  838. /* [in] */ DWORD grfFlags)
  839. {
  840. RonM_ASSERT(FALSE);
  841. return E_NOTIMPL;
  842. }
  843. HRESULT __stdcall CFSStorage::CImpIFSStorage::Commit(
  844. /* [in] */ DWORD grfCommitFlags)
  845. {
  846. return NO_ERROR;
  847. }
  848. HRESULT __stdcall CFSStorage::CImpIFSStorage::Revert( void)
  849. {
  850. RonM_ASSERT(FALSE);
  851. return E_NOTIMPL;
  852. }
  853. /* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::EnumElements(
  854. /* [in] */ DWORD reserved1,
  855. /* [size_is][unique][in] */ void __RPC_FAR *reserved2,
  856. /* [in] */ DWORD reserved3,
  857. /* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
  858. {
  859. return CFSEnumStorage::NewEnumStorage(NULL, (CONST WCHAR *) m_awcsPath, ppenum);
  860. }
  861. HRESULT __stdcall CFSStorage::CImpIFSStorage::DestroyElement(
  862. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName)
  863. {
  864. RonM_ASSERT(FALSE);
  865. return E_NOTIMPL;
  866. }
  867. HRESULT __stdcall CFSStorage::CImpIFSStorage::RenameElement(
  868. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsOldName,
  869. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsNewName)
  870. {
  871. RonM_ASSERT(FALSE);
  872. return E_NOTIMPL;
  873. }
  874. HRESULT __stdcall CFSStorage::CImpIFSStorage::SetElementTimes(
  875. /* [string][in] */ const OLECHAR __RPC_FAR *pwcsName,
  876. /* [in] */ const FILETIME __RPC_FAR *pctime,
  877. /* [in] */ const FILETIME __RPC_FAR *patime,
  878. /* [in] */ const FILETIME __RPC_FAR *pmtime)
  879. {
  880. RonM_ASSERT(FALSE);
  881. return E_NOTIMPL;
  882. }
  883. HRESULT __stdcall CFSStorage::CImpIFSStorage::SetClass(
  884. /* [in] */ REFCLSID clsid)
  885. {
  886. RonM_ASSERT(FALSE);
  887. return E_NOTIMPL;
  888. }
  889. HRESULT __stdcall CFSStorage::CImpIFSStorage::SetStateBits(
  890. /* [in] */ DWORD grfStateBits,
  891. /* [in] */ DWORD grfMask)
  892. {
  893. RonM_ASSERT(FALSE);
  894. return E_NOTIMPL;
  895. }
  896. HRESULT __stdcall CFSStorage::CImpIFSStorage::Stat(
  897. /* [out] */ STATSTG __RPC_FAR *pstatstg,
  898. /* [in] */ DWORD grfStatFlag)
  899. {
  900. RonM_ASSERT(FALSE);
  901. return E_NOTIMPL;
  902. }
  903. HRESULT CFSStorage::CImpIFSStorage::CFSEnumStorage::NewEnumStorage
  904. (IUnknown *pUnkOuter, CONST WCHAR *pwcsPath, IEnumSTATSTG **ppEnumSTATSTG)
  905. {
  906. CFSEnumStorage *pEnumContainer = New CFSEnumStorage(pUnkOuter);
  907. return FinishSetup(pEnumContainer? pEnumContainer->m_ImpIEnumStorage.Initial(pwcsPath)
  908. : STG_E_INSUFFICIENTMEMORY,
  909. pEnumContainer, IID_IEnumSTATSTG, (PPVOID) ppEnumSTATSTG
  910. );
  911. }
  912. CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::CImpIEnumStorage
  913. (CFSEnumStorage *pBackObj, IUnknown *punkOuter)
  914. : IITEnumSTATSTG(pBackObj, punkOuter)
  915. {
  916. m_State = Before;
  917. m_hEnum = INVALID_HANDLE_VALUE;
  918. }
  919. CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::~CImpIEnumStorage(void)
  920. {
  921. if (m_hEnum != INVALID_HANDLE_VALUE)
  922. FindClose(m_hEnum);
  923. }
  924. HRESULT CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Initial(CONST WCHAR *pwcsPath)
  925. {
  926. RonM_ASSERT(m_State == Before);
  927. RonM_ASSERT(m_hEnum == INVALID_HANDLE_VALUE);
  928. UINT cwc = lstrlenW(pwcsPath);
  929. if (!cwc || pwcsPath[cwc-1] != L'/' || cwc + 1 >= MAX_PATH)
  930. return STG_E_INVALIDNAME;
  931. wcsCpy(m_awszBasePath, pwcsPath);
  932. wcsCat(m_awszBasePath, L"*");
  933. return NO_ERROR;
  934. }
  935. // IEnumSTATSTG methods:
  936. /* [local] */ HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Next
  937. (
  938. /* [in] */ ULONG celt,
  939. /* [in] */ STATSTG __RPC_FAR *rgelt,
  940. /* [out] */ ULONG __RPC_FAR *pceltFetched)
  941. {
  942. HRESULT hr = S_OK;
  943. UINT celtFetched = 0;
  944. for (; celt--; rgelt++)
  945. {
  946. hr = NextEntry();
  947. if (hr != S_OK) break;
  948. WCHAR awcsBuffer[MAX_PATH];
  949. UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED,
  950. m_w32fd.cFileName, lstrlen(m_w32fd.cFileName) + 1,
  951. awcsBuffer, MAX_PATH
  952. );
  953. if (!cwc)
  954. {
  955. hr = STG_E_UNKNOWN;
  956. break;
  957. }
  958. PWCHAR pwcDest = PWCHAR(OLEHeap()->Alloc(cwc * sizeof(WCHAR)));
  959. if (!pwcDest)
  960. {
  961. hr = STG_E_INSUFFICIENTMEMORY;
  962. break;
  963. }
  964. CopyMemory(pwcDest, awcsBuffer, cwc * sizeof(WCHAR));
  965. BOOL fStorage = (m_w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  966. rgelt->pwcsName = pwcDest; pwcDest = NULL;
  967. rgelt->type = fStorage? STGTY_STORAGE : STGTY_STREAM;
  968. rgelt->cbSize.LowPart = m_w32fd.nFileSizeLow;
  969. rgelt->cbSize.HighPart = m_w32fd.nFileSizeHigh;
  970. rgelt->mtime.dwLowDateTime = m_w32fd.ftLastWriteTime.dwLowDateTime;
  971. rgelt->mtime.dwHighDateTime = m_w32fd.ftLastWriteTime.dwHighDateTime;
  972. rgelt->ctime.dwLowDateTime = m_w32fd.ftCreationTime.dwLowDateTime;
  973. rgelt->ctime.dwHighDateTime = m_w32fd.ftCreationTime.dwHighDateTime;
  974. rgelt->atime.dwLowDateTime = m_w32fd.ftLastAccessTime.dwLowDateTime;
  975. rgelt->atime.dwHighDateTime = m_w32fd.ftLastAccessTime.dwHighDateTime;
  976. rgelt->grfMode = 0;
  977. rgelt->grfLocksSupported = 0;
  978. rgelt->clsid = CLSID_NULL;
  979. rgelt->grfStateBits = 0;
  980. rgelt->reserved = 0;
  981. celtFetched++;
  982. }
  983. if (pceltFetched)
  984. *pceltFetched = celtFetched;
  985. return hr;
  986. }
  987. HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Skip(ULONG celt)
  988. {
  989. HRESULT hr = S_OK;
  990. for (; celt--; )
  991. {
  992. hr = NextEntry();
  993. if (hr != S_OK) break;
  994. }
  995. return hr;
  996. }
  997. HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Reset( void)
  998. {
  999. if (m_hEnum != INVALID_HANDLE_VALUE)
  1000. {
  1001. FindClose(m_hEnum);
  1002. m_hEnum = INVALID_HANDLE_VALUE;
  1003. }
  1004. m_State = Before;
  1005. return NO_ERROR;
  1006. }
  1007. HRESULT __stdcall CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::Clone
  1008. (
  1009. /* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum)
  1010. {
  1011. RonM_ASSERT(FALSE);
  1012. return E_NOTIMPL;
  1013. }
  1014. HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::GetNextEntryInSeq
  1015. (ULONG celt, PathInfo *rgelt, ULONG *pceltFetched)
  1016. {
  1017. RonM_ASSERT(FALSE);
  1018. return E_NOTIMPL;
  1019. }
  1020. HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::GetFirstEntryInSeq
  1021. (PathInfo *rgelt)
  1022. {
  1023. RonM_ASSERT(FALSE);
  1024. return E_NOTIMPL;
  1025. }
  1026. HRESULT STDMETHODCALLTYPE CFSStorage::CImpIFSStorage::CFSEnumStorage::CImpIEnumStorage::NextEntry()
  1027. {
  1028. HRESULT hr = S_OK;
  1029. switch(m_State)
  1030. {
  1031. case Before:
  1032. {
  1033. char aszBuffer[MAX_PATH * 2];
  1034. UINT cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK | WC_DEFAULTCHAR,
  1035. m_awszBasePath, lstrlenW(m_awszBasePath) + 1,
  1036. aszBuffer, MAX_PATH * 2, NULL, NULL
  1037. );
  1038. if (!cb) return STG_E_UNKNOWN;
  1039. m_hEnum = FindFirstFile(aszBuffer, &m_w32fd);
  1040. if (m_hEnum == INVALID_HANDLE_VALUE)
  1041. return STG_E_INVALIDNAME;
  1042. m_State = During;
  1043. // For the Win32 file system the first two entries returned by
  1044. // FindFirstFile/FindNextFile will always be "." and "..". So we
  1045. // must skip over those items.
  1046. RonM_ASSERT(!lstrcmp(m_w32fd.cFileName, "."));
  1047. NextEntry();
  1048. RonM_ASSERT(!lstrcmp(m_w32fd.cFileName, ".."));
  1049. return NextEntry(); // To get the first real enumeration name.
  1050. }
  1051. case During:
  1052. RonM_ASSERT(m_hEnum != INVALID_HANDLE_VALUE);
  1053. if (FindNextFile(m_hEnum, &m_w32fd))
  1054. return NO_ERROR;
  1055. if (GetLastError() == ERROR_NO_MORE_FILES)
  1056. {
  1057. m_State = After;
  1058. return S_FALSE;
  1059. }
  1060. case After:
  1061. return S_FALSE;
  1062. default:
  1063. return STG_E_UNKNOWN;
  1064. }
  1065. }