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.

378 lines
11 KiB

  1. #include "shellprv.h"
  2. #include "filefldr.h"
  3. #include "recdocs.h"
  4. #include "ids.h"
  5. #include "mtpt.h"
  6. class CFileSysEnum : public IEnumIDList
  7. {
  8. public:
  9. // IUnknown
  10. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  11. STDMETHOD_(ULONG,AddRef)();
  12. STDMETHOD_(ULONG,Release)();
  13. // IEnumIDList
  14. STDMETHOD(Next)(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  15. STDMETHOD(Skip)(ULONG celt);
  16. STDMETHOD(Reset)();
  17. STDMETHOD(Clone)(IEnumIDList **ppenum);
  18. CFileSysEnum(CFSFolder *pfsf, HWND hwnd, DWORD grfFlags);
  19. HRESULT Init();
  20. private:
  21. ~CFileSysEnum();
  22. BOOL _FindNextFile();
  23. void _HideFiles(); // operates on _fd data
  24. LONG _cRef;
  25. CFSFolder *_pfsf;
  26. DWORD _grfFlags;
  27. HWND _hwnd;
  28. HANDLE _hfind;
  29. TCHAR _szFolder[MAX_PATH];
  30. BOOL _fMoreToEnum;
  31. WIN32_FIND_DATA _fd;
  32. int _cHiddenFiles;
  33. ULONGLONG _cbSize;
  34. IMruDataList *_pmruRecent;
  35. int _iIndexMRU;
  36. BOOL _fShowSuperHidden;
  37. BOOL _fIsRootDrive;
  38. BOOL _fIsCDFS;
  39. };
  40. CFileSysEnum::CFileSysEnum(CFSFolder *pfsf, HWND hwnd, DWORD grfFlags) :
  41. _cRef(1), _pfsf(pfsf), _hwnd(hwnd), _grfFlags(grfFlags), _hfind(INVALID_HANDLE_VALUE)
  42. {
  43. _fShowSuperHidden = ShowSuperHidden();
  44. _pfsf->AddRef();
  45. }
  46. CFileSysEnum::~CFileSysEnum()
  47. {
  48. if (_hfind != INVALID_HANDLE_VALUE)
  49. {
  50. // this handle can be the find file or MRU list in the case of RECENTDOCSDIR
  51. ATOMICRELEASE(_pmruRecent);
  52. FindClose(_hfind);
  53. _hfind = INVALID_HANDLE_VALUE;
  54. }
  55. _pfsf->Release();
  56. }
  57. HRESULT CFileSysEnum::Init()
  58. {
  59. TCHAR szPath[MAX_PATH];
  60. HRESULT hr = _pfsf->_GetPath(_szFolder, ARRAYSIZE(_szFolder));
  61. if (SUCCEEDED(hr) && !PathIsUNC(_szFolder))
  62. {
  63. TCHAR szRoot[] = TEXT("A:\\");
  64. _fIsRootDrive = PathIsRoot(_szFolder);
  65. // For mapped net drives, register a change
  66. // notify alias for the corresponding UNC path.
  67. szRoot[0] = _szFolder[0];
  68. if (DRIVE_REMOTE == GetDriveType(szRoot))
  69. {
  70. MountPoint_RegisterChangeNotifyAlias(DRIVEID(_szFolder));
  71. }
  72. TCHAR szFileSystem[6];
  73. _fIsCDFS = (DRIVE_CDROM == GetDriveType(szRoot)) &&
  74. GetVolumeInformation(szRoot, NULL, 0, NULL, NULL, NULL, szFileSystem, ARRAYSIZE(szFileSystem)) &&
  75. (StrCmpI(L"CDFS", szFileSystem) == 0);
  76. }
  77. if (SUCCEEDED(hr) &&
  78. PathCombine(szPath, _szFolder, c_szStarDotStar))
  79. {
  80. // let name mapper see the path/PIDL pair (for UNC root mapping)
  81. // skip the My Net Places entry when passing it to NPTRegisterNameToPidlTranslation.
  82. LPCITEMIDLIST pidlToMap = _pfsf->_pidlTarget ? _pfsf->_pidlTarget:_pfsf->_pidl;
  83. if (IsIDListInNameSpace(pidlToMap, &CLSID_NetworkPlaces))
  84. {
  85. NPTRegisterNameToPidlTranslation(_szFolder, _ILNext(pidlToMap));
  86. }
  87. if (_grfFlags == SHCONTF_FOLDERS)
  88. {
  89. // use mask to only find folders, mask is in the hi byte of dwFileAttributes
  90. // algorithm: (((attrib_on_disk & mask) ^ mask) == 0)
  91. // signature to tell SHFindFirstFileRetry() to use the attribs specified
  92. _fd.dwFileAttributes = (FILE_ATTRIBUTE_DIRECTORY << 8) |
  93. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY;
  94. _fd.dwReserved0 = 0x56504347;
  95. }
  96. hr = SHFindFirstFileRetry(_hwnd, NULL, szPath, &_fd, &_hfind, SHPPFW_NONE);
  97. if (SUCCEEDED(hr))
  98. {
  99. _HideFiles();
  100. ASSERT(hr == S_OK ? (_hfind != INVALID_HANDLE_VALUE) : TRUE);
  101. _fMoreToEnum = (hr == S_OK);
  102. if (!(_grfFlags & SHCONTF_INCLUDEHIDDEN))
  103. {
  104. if (_pfsf->_IsCSIDL(CSIDL_RECENT))
  105. {
  106. CreateRecentMRUList(&_pmruRecent);
  107. }
  108. }
  109. hr = S_OK; // convert S_FALSE to S_OK to match ::EnumObjects() returns
  110. }
  111. }
  112. else if (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
  113. {
  114. // Tracking target doesn't exist; return an empty enumerator
  115. _fMoreToEnum = FALSE;
  116. hr = S_OK;
  117. }
  118. else
  119. {
  120. // _GetPathForItem & PathCombine() fail when path is too long
  121. if (_hwnd)
  122. {
  123. ShellMessageBox(HINST_THISDLL, _hwnd, MAKEINTRESOURCE(IDS_ENUMERR_PATHTOOLONG),
  124. NULL, MB_OK | MB_ICONHAND);
  125. }
  126. // This error value tells callers that we have already displayed error UI so skip
  127. // displaying errors.
  128. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  129. }
  130. return hr;
  131. }
  132. STDMETHODIMP CFileSysEnum::QueryInterface(REFIID riid, void **ppv)
  133. {
  134. static const QITAB qit[] = {
  135. QITABENT(CFileSysEnum, IEnumIDList), // IID_IEnumIDList
  136. { 0 },
  137. };
  138. return QISearch(this, qit, riid, ppv);
  139. }
  140. STDMETHODIMP_(ULONG) CFileSysEnum::AddRef()
  141. {
  142. return InterlockedIncrement(&_cRef);
  143. }
  144. STDMETHODIMP_(ULONG) CFileSysEnum::Release()
  145. {
  146. ASSERT( 0 != _cRef );
  147. ULONG cRef = InterlockedDecrement(&_cRef);
  148. if ( 0 == cRef )
  149. {
  150. delete this;
  151. }
  152. return cRef;
  153. }
  154. const LPCWSTR c_rgFilesToHideInRoot[] =
  155. {
  156. L"AUTOEXEC.BAT", // case sensitive
  157. L"CONFIG.SYS",
  158. L"COMMAND.COM"
  159. };
  160. const LPCWSTR c_rgFilesToHideOnCDFS[] =
  161. {
  162. L"thumbs.db",
  163. L"desktop.ini"
  164. };
  165. void CFileSysEnum::_HideFiles()
  166. {
  167. // only do this if HIDDEN and SYSTEM attributes are not set on the file
  168. // (we assume if the file has these bits these files are setup properly)
  169. if (0 == (_fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)))
  170. {
  171. // only do this for root drives
  172. if (_fIsRootDrive)
  173. {
  174. for (int i = 0; i < ARRAYSIZE(c_rgFilesToHideInRoot); i++)
  175. {
  176. // case sensitive to make it faster
  177. if (0 == StrCmpC(c_rgFilesToHideInRoot[i], _fd.cFileName))
  178. {
  179. _fd.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
  180. break;
  181. }
  182. }
  183. }
  184. // only do this if we're on a normal CD filesystem
  185. if (_fIsCDFS)
  186. {
  187. for (int i = 0; i < ARRAYSIZE(c_rgFilesToHideOnCDFS); i++)
  188. {
  189. // dont share code from above since these can be upper or lower
  190. if (0 == StrCmpI(c_rgFilesToHideOnCDFS[i], _fd.cFileName))
  191. {
  192. _fd.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
  193. break;
  194. }
  195. }
  196. }
  197. }
  198. }
  199. BOOL CFileSysEnum::_FindNextFile()
  200. {
  201. BOOL fMoreToEnum = FALSE;
  202. if (_pmruRecent)
  203. {
  204. LPITEMIDLIST pidl;
  205. while (SUCCEEDED(RecentDocs_Enum(_pmruRecent, _iIndexMRU, &pidl)))
  206. {
  207. // confirm that the item stil exists in the file system, fill in the _fd data
  208. TCHAR szPath[MAX_PATH];
  209. HANDLE h;
  210. _pfsf->_GetPathForItem(_pfsf->_IsValidID(pidl), szPath, ARRAYSIZE(szPath));
  211. ILFree(pidl);
  212. h = FindFirstFile(szPath, &_fd);
  213. if (h != INVALID_HANDLE_VALUE)
  214. {
  215. fMoreToEnum = TRUE;
  216. _iIndexMRU++;
  217. FindClose(h);
  218. break;
  219. }
  220. else
  221. {
  222. //
  223. // WARNING - if the list is corrupt we torch it - ZekeL 19-JUN-98
  224. // we could do some special stuff, i guess, to weed out the bad
  225. // items, but it seems simpler to just blow it away.
  226. // the only reason this should happen is if somebody
  227. // has been mushing around with RECENT directory directly,
  228. // which they shouldnt do since it is hidden...
  229. //
  230. // kill this invalid entry, and then try the same index again...
  231. _pmruRecent->Delete(_iIndexMRU);
  232. }
  233. }
  234. }
  235. else
  236. {
  237. fMoreToEnum = FindNextFile(_hfind, &_fd);
  238. _HideFiles();
  239. }
  240. return fMoreToEnum;
  241. }
  242. STDMETHODIMP CFileSysEnum::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  243. {
  244. HRESULT hr;
  245. for (; _fMoreToEnum; _fMoreToEnum = _FindNextFile())
  246. {
  247. if (_fMoreToEnum == (BOOL)42)
  248. continue; // we already processed the current item, skip it now
  249. if (PathIsDotOrDotDot(_fd.cFileName))
  250. continue;
  251. if (!(_grfFlags & SHCONTF_STORAGE))
  252. {
  253. if (_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  254. {
  255. if (!(_grfFlags & SHCONTF_FOLDERS))
  256. continue; // item is folder but client does not want folders
  257. }
  258. else if (!(_grfFlags & SHCONTF_NONFOLDERS))
  259. continue; // item is file, but client only wants folders
  260. // skip hidden and system things unconditionally, don't even count them
  261. if (!_fShowSuperHidden && IS_SYSTEM_HIDDEN(_fd.dwFileAttributes))
  262. continue;
  263. }
  264. _cbSize += MAKELONGLONG(_fd.nFileSizeLow, _fd.nFileSizeHigh);
  265. if (!(_grfFlags & (SHCONTF_INCLUDEHIDDEN | SHCONTF_STORAGE)) &&
  266. (_fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
  267. {
  268. _cHiddenFiles++;
  269. continue;
  270. }
  271. break;
  272. }
  273. if (_fMoreToEnum)
  274. {
  275. hr = _pfsf->_CreateIDList(&_fd, NULL, ppidl);
  276. _fMoreToEnum = (BOOL)42; // we have processed the current item, skip it next time
  277. }
  278. else
  279. {
  280. *ppidl = NULL;
  281. hr = S_FALSE; // no more items
  282. // completed the enum, stash some items back into the folder
  283. // PERF ??: we could QueryService for the view callback at this point and
  284. // poke these in directly there instead of pushing these into the folder
  285. _pfsf->_cHiddenFiles = _cHiddenFiles;
  286. _pfsf->_cbSize = _cbSize;
  287. }
  288. if (pceltFetched)
  289. *pceltFetched = (hr == S_OK) ? 1 : 0;
  290. return hr;
  291. }
  292. STDMETHODIMP CFileSysEnum::Skip(ULONG celt)
  293. {
  294. return E_NOTIMPL;
  295. }
  296. STDMETHODIMP CFileSysEnum::Reset()
  297. {
  298. return S_OK;
  299. }
  300. STDMETHODIMP CFileSysEnum::Clone(IEnumIDList **ppenum)
  301. {
  302. *ppenum = NULL;
  303. return E_NOTIMPL;
  304. }
  305. STDAPI CFSFolder_CreateEnum(CFSFolder *pfsf, HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  306. {
  307. HRESULT hr;
  308. CFileSysEnum *penum = new CFileSysEnum(pfsf, hwnd, grfFlags);
  309. if (penum)
  310. {
  311. hr = penum->Init();
  312. if (SUCCEEDED(hr))
  313. hr = penum->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  314. penum->Release();
  315. }
  316. else
  317. {
  318. hr = E_OUTOFMEMORY;
  319. *ppenum = NULL;
  320. }
  321. return hr;
  322. }