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

443 lines
13 KiB

  1. #include "sfstorage.h"
  2. class CSFStorageEnum : public IEnumSTATSTG
  3. {
  4. public:
  5. // IUnknown
  6. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  7. STDMETHOD_(ULONG, AddRef)();
  8. STDMETHOD_(ULONG, Release)();
  9. // IEnumSTATSTG
  10. STDMETHOD(Skip)(ULONG celt)
  11. { return E_NOTIMPL; };
  12. STDMETHOD(Clone)(IEnumSTATSTG **ppenum)
  13. { return E_NOTIMPL; };
  14. STDMETHOD(Next)(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched);
  15. STDMETHOD(Reset)();
  16. protected:
  17. CSFStorageEnum(CSFStorage* psfstg);
  18. ~CSFStorageEnum();
  19. private:
  20. LONG _cRef;
  21. CSFStorage *_psfstg;
  22. IEnumIDList *_peidl;
  23. HRESULT _PidlToSTATSTG(LPCITEMIDLIST pidl, STATSTG *pstatstg);
  24. friend CSFStorage;
  25. };
  26. CSFStorageEnum::CSFStorageEnum(CSFStorage *psfstg) :
  27. _cRef(1)
  28. {
  29. _psfstg = psfstg;
  30. _psfstg->AddRef();
  31. DllAddRef();
  32. }
  33. CSFStorageEnum::~CSFStorageEnum()
  34. {
  35. _psfstg->Release();
  36. ATOMICRELEASE(_peidl);
  37. DllRelease();
  38. }
  39. STDMETHODIMP_(ULONG) CSFStorageEnum::AddRef()
  40. {
  41. return InterlockedIncrement(&_cRef);
  42. }
  43. STDMETHODIMP_(ULONG) CSFStorageEnum::Release()
  44. {
  45. ASSERT( 0 != _cRef );
  46. ULONG cRef = InterlockedDecrement(&_cRef);
  47. if ( 0 == cRef )
  48. {
  49. delete this;
  50. }
  51. return cRef;
  52. }
  53. STDMETHODIMP CSFStorageEnum::QueryInterface(REFIID riid, void **ppv)
  54. {
  55. static const QITAB qit[] = {
  56. QITABENT(CSFStorageEnum, IEnumSTATSTG), // IEnumSTATSTG
  57. { 0 },
  58. };
  59. return QISearch(this, qit, riid, ppv);
  60. }
  61. HRESULT CSFStorageEnum::_PidlToSTATSTG(LPCITEMIDLIST pidl, STATSTG *pstatstg)
  62. {
  63. ZeroMemory(pstatstg, sizeof(*pstatstg)); // per COM conventions
  64. VARIANT var;
  65. VariantInit(&var);
  66. HRESULT hr = _psfstg->GetDetailsEx(pidl, &SCID_FINDDATA, &var);
  67. if (SUCCEEDED(hr))
  68. {
  69. WIN32_FIND_DATAW wfd;
  70. if (VariantToBuffer(&var, &wfd, sizeof(wfd)))
  71. {
  72. pstatstg->atime = wfd.ftLastAccessTime;
  73. pstatstg->ctime = wfd.ftCreationTime;
  74. pstatstg->mtime = wfd.ftLastWriteTime;
  75. pstatstg->cbSize.HighPart = wfd.nFileSizeHigh;
  76. pstatstg->cbSize.LowPart = wfd.nFileSizeLow;
  77. pstatstg->type = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? STGTY_STORAGE : STGTY_STREAM;
  78. hr = SHStrDupW(wfd.cFileName, &pstatstg->pwcsName);
  79. }
  80. VariantClear(&var);
  81. }
  82. return hr;
  83. }
  84. STDMETHODIMP CSFStorageEnum::Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
  85. {
  86. ASSERT((celt != 1) ? (pceltFetched != NULL) : TRUE);
  87. HRESULT hr = S_OK;
  88. if (!_peidl)
  89. {
  90. hr = _psfstg->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &_peidl);
  91. }
  92. if (S_OK == hr)
  93. {
  94. hr = E_OUTOFMEMORY;
  95. LPITEMIDLIST *apidl = new LPITEMIDLIST[celt];
  96. if (apidl)
  97. {
  98. ULONG celtFetched;
  99. hr = _peidl->Next(celt, apidl, &celtFetched);
  100. if (SUCCEEDED(hr))
  101. {
  102. ULONG celtConverted = 0;
  103. ULONG i;
  104. for (i = 0; i < celtFetched; i++)
  105. {
  106. if (SUCCEEDED(_PidlToSTATSTG(apidl[i], &rgelt[celtConverted])))
  107. {
  108. celtConverted++;
  109. }
  110. }
  111. hr = (celtConverted == celt) ? S_OK : S_FALSE;
  112. if (pceltFetched)
  113. {
  114. *pceltFetched = celtConverted;
  115. }
  116. for (i = 0; i < celtFetched; i++)
  117. {
  118. ILFree(apidl[i]);
  119. }
  120. }
  121. delete apidl;
  122. }
  123. }
  124. return hr;
  125. }
  126. STDMETHODIMP CSFStorageEnum::Reset()
  127. {
  128. HRESULT hr = S_OK;
  129. if (_peidl)
  130. {
  131. hr = _peidl->Reset();
  132. }
  133. return hr;
  134. }
  135. HRESULT CSFStorage::_ParseAndVerify(LPCWSTR pwszName, LPBC pbc, LPITEMIDLIST *ppidl)
  136. {
  137. *ppidl = NULL;
  138. LPITEMIDLIST pidl;
  139. HRESULT hr = ParseDisplayName(NULL, pbc, (LPWSTR) pwszName, NULL, &pidl, NULL);
  140. if (SUCCEEDED(hr))
  141. {
  142. // must be single-level
  143. if (ILFindLastID(pidl) != pidl)
  144. {
  145. hr = E_FAIL;
  146. ILFree(pidl);
  147. }
  148. else
  149. {
  150. *ppidl = pidl;
  151. }
  152. }
  153. return hr;
  154. }
  155. HRESULT CSFStorage::_BindByName(LPCWSTR pwszName, LPBC pbcParse, DWORD grfMode, REFIID riid, void **ppv)
  156. {
  157. *ppv = NULL;
  158. LPITEMIDLIST pidl;
  159. HRESULT hr = _ParseAndVerify(pwszName, pbcParse, &pidl);
  160. if (SUCCEEDED(hr))
  161. {
  162. IBindCtx *pbc;
  163. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  164. if (SUCCEEDED(hr))
  165. {
  166. hr = BindToObject(pidl, pbc, riid, ppv);
  167. pbc->Release();
  168. }
  169. ILFree(pidl);
  170. }
  171. return hr;
  172. }
  173. STDMETHODIMP CSFStorage::Commit(DWORD grfCommitFlags)
  174. {
  175. return S_OK;
  176. }
  177. STDMETHODIMP CSFStorage::Revert()
  178. {
  179. return E_NOTIMPL;
  180. }
  181. STDMETHODIMP CSFStorage::SetClass(REFCLSID clsid)
  182. {
  183. return E_NOTIMPL;
  184. }
  185. STDMETHODIMP CSFStorage::SetStateBits(DWORD grfStateBits, DWORD grfMask)
  186. {
  187. return E_NOTIMPL;
  188. }
  189. STDMETHODIMP CSFStorage::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  190. {
  191. // we can at least get the name to use in STATSTG.
  192. ZeroMemory(pstatstg, sizeof(*pstatstg));
  193. LPITEMIDLIST pidl;
  194. HRESULT hr = SHGetIDListFromUnk(SAFECAST(this, IShellFolder2*), &pidl);
  195. if (SUCCEEDED(hr))
  196. {
  197. LPCITEMIDLIST pidlLast;
  198. IShellFolder *psf;
  199. hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  200. if (SUCCEEDED(hr))
  201. {
  202. TCHAR szName[MAX_PATH];
  203. hr = DisplayNameOf(psf, pidlLast, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  204. if (SUCCEEDED(hr))
  205. {
  206. // don't know what mode we were bound with, STGM_READ is good enough.
  207. pstatstg->grfMode = STGM_READ;
  208. if (!(grfStatFlag & STATFLAG_NONAME))
  209. {
  210. hr = SHStrDup(szName, &pstatstg->pwcsName);
  211. }
  212. }
  213. psf->Release();
  214. }
  215. ILFree(pidl);
  216. }
  217. return hr;
  218. }
  219. STDMETHODIMP CSFStorage::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
  220. {
  221. HRESULT hr;
  222. CSFStorageEnum *penum = new CSFStorageEnum(this);
  223. if (penum)
  224. {
  225. *ppenum = (IEnumSTATSTG *) penum;
  226. hr = S_OK;
  227. }
  228. else
  229. {
  230. *ppenum = NULL;
  231. hr = E_OUTOFMEMORY;
  232. }
  233. return hr;
  234. }
  235. STDMETHODIMP CSFStorage::OpenStream(LPCWSTR pszRel, VOID *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
  236. {
  237. HRESULT hr = _BindByName(pszRel, NULL, grfMode, IID_PPV_ARG(IStream, ppstm));
  238. return MapWin32ErrorToSTG(hr);
  239. }
  240. STDMETHODIMP CSFStorage::OpenStorage(LPCWSTR pszRel, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
  241. {
  242. HRESULT hr = _BindByName(pszRel, NULL, grfMode, IID_PPV_ARG(IStorage, ppstg));
  243. return MapWin32ErrorToSTG(hr);
  244. }
  245. STDMETHODIMP CSFStorage::DestroyElement(LPCWSTR pszRel)
  246. {
  247. LPITEMIDLIST pidl;
  248. HRESULT hr = _ParseAndVerify(pszRel, NULL, &pidl);
  249. if (SUCCEEDED(hr))
  250. {
  251. hr = _DeleteItemByIDList(pidl);
  252. ILFree(pidl);
  253. }
  254. return hr;
  255. }
  256. STDMETHODIMP CSFStorage::RenameElement(LPCWSTR pwcsOldName, LPCWSTR pwcsNewName)
  257. {
  258. LPITEMIDLIST pidl;
  259. HRESULT hr = _ParseAndVerify(pwcsOldName, NULL, &pidl);
  260. if (SUCCEEDED(hr))
  261. {
  262. // ISSUE: this might put up UI
  263. hr = SetNameOf(NULL, pidl, pwcsNewName, SHGDN_FORPARSING, NULL);
  264. ILFree(pidl);
  265. }
  266. return hr;
  267. }
  268. STDMETHODIMP CSFStorage::SetElementTimes(LPCWSTR pszRel, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
  269. {
  270. // could have another virtual function here for the subclass to implement,
  271. // but nobody ever calls this function anyway.
  272. return E_NOTIMPL;
  273. }
  274. STDMETHODIMP CSFStorage::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
  275. {
  276. // TODO filefldr doesnt implement this so apparently nobody needs it yet
  277. return E_NOTIMPL;
  278. }
  279. STDMETHODIMP CSFStorage::MoveElementTo(LPCWSTR pszRel, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  280. {
  281. return StgMoveElementTo(SAFECAST(this, IShellFolder *), SAFECAST(this, IStorage *), pszRel, pstgDest, pwcsNewName, grfFlags);
  282. }
  283. HRESULT CSFStorage::_CreateHelper(LPCWSTR pwcsName, DWORD grfMode, REFIID riid, void **ppv)
  284. {
  285. *ppv = NULL;
  286. HRESULT hr = S_OK;
  287. LPITEMIDLIST pidlTemp;
  288. if (!(grfMode & STGM_CREATE) && SUCCEEDED(_ParseAndVerify(pwcsName, NULL, &pidlTemp)))
  289. {
  290. ILFree(pidlTemp);
  291. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  292. }
  293. if (SUCCEEDED(hr))
  294. {
  295. IBindCtx *pbcParse;
  296. hr = BindCtx_CreateWithMode(STGM_CREATE, &pbcParse);
  297. if (SUCCEEDED(hr))
  298. {
  299. LPITEMIDLIST pidl;
  300. hr = _ParseAndVerify(pwcsName, pbcParse, &pidl);
  301. if (SUCCEEDED(hr))
  302. {
  303. hr = _StgCreate(pidl, grfMode, riid, ppv);
  304. ILFree(pidl);
  305. }
  306. pbcParse->Release();
  307. }
  308. }
  309. return MapWin32ErrorToSTG(hr);
  310. }
  311. STDMETHODIMP CSFStorage::CreateStream(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStream **ppstm)
  312. {
  313. return _CreateHelper(pwcsName, grfMode, IID_PPV_ARG(IStream, ppstm));
  314. }
  315. STDMETHODIMP CSFStorage::CreateStorage(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStorage **ppstg)
  316. {
  317. return _CreateHelper(pwcsName, grfMode, IID_PPV_ARG(IStorage, ppstg));
  318. }
  319. // factored out of filefldr.cpp
  320. HRESULT StgMoveElementTo(IShellFolder *psf, IStorage *pstgSrc, LPCWSTR pwcsName, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  321. {
  322. if ((grfFlags != STGMOVE_MOVE) && (grfFlags != STGMOVE_COPY))
  323. return E_INVALIDARG;
  324. // Get the IDList for the source stream's file
  325. LPITEMIDLIST pidl;
  326. HRESULT hr = psf->ParseDisplayName(NULL, NULL, (LPWSTR) pwcsName, NULL, &pidl, NULL);
  327. if (SUCCEEDED(hr))
  328. {
  329. // Bind to the source file as an IStream
  330. IStream *pstmSrc;
  331. hr = psf->BindToObject(pidl, NULL, IID_PPV_ARG(IStream, &pstmSrc));
  332. if (SUCCEEDED(hr))
  333. {
  334. // Create the destination stream
  335. IStream *pstmDst;
  336. hr = pstgDest->CreateStream(pwcsNewName, STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, NULL, &pstmDst);
  337. if (SUCCEEDED(hr))
  338. {
  339. ULARGE_INTEGER ulMax = {-1, -1}; // whole thing
  340. hr = pstmSrc->CopyTo(pstmDst, ulMax, NULL, NULL);
  341. // If all went well this is a move (not a copy), remove the source
  342. if (SUCCEEDED(hr))
  343. {
  344. hr = pstmDst->Commit(STGC_DEFAULT);
  345. if (SUCCEEDED(hr) && (grfFlags == STGMOVE_MOVE))
  346. hr = pstgSrc->DestroyElement(pwcsName);
  347. }
  348. pstmDst->Release();
  349. }
  350. pstmSrc->Release();
  351. }
  352. else
  353. {
  354. IStorage *pstgSrc;
  355. hr = psf->BindToObject(pidl, NULL, IID_PPV_ARG(IStorage, &pstgSrc));
  356. if (SUCCEEDED(hr))
  357. {
  358. IStorage *pstgDst;
  359. hr = pstgDest->CreateStorage(pwcsNewName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, NULL, &pstgDst);
  360. if (SUCCEEDED(hr))
  361. {
  362. IEnumSTATSTG *penum;
  363. if (S_OK == pstgSrc->EnumElements(0, NULL, 0, &penum))
  364. {
  365. STATSTG stat;
  366. while (S_OK == penum->Next(1, &stat, NULL))
  367. {
  368. hr = pstgSrc->MoveElementTo(stat.pwcsName, pstgDst, stat.pwcsName, grfFlags);
  369. if (SUCCEEDED(hr))
  370. hr = pstgDst->Commit(STGC_DEFAULT);
  371. CoTaskMemFree(stat.pwcsName);
  372. if (FAILED(hr))
  373. break;
  374. }
  375. penum->Release();
  376. }
  377. if (SUCCEEDED(hr))
  378. hr = pstgDst->Commit(STGC_DEFAULT);
  379. pstgDst->Release();
  380. }
  381. pstgSrc->Release();
  382. }
  383. }
  384. ILFree(pidl);
  385. }
  386. return hr;
  387. }