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.

511 lines
14 KiB

  1. // Copyright (C) 1997 Microsoft Corporation. All rights reserved.
  2. #include "stdafx.h"
  3. // to avoid linker error related to undefined GUIDs
  4. #include "initguid.h"
  5. #include "fs.h"
  6. #pragma data_seg(".text", "CODE")
  7. static const WCHAR txtwUncompressed[] = L"uncompressed";
  8. #pragma data_seg()
  9. // returns poinder inside pszPath string that points to file name
  10. // for example in "d:\Tshooter\http\lan.chm\lan.htm" it points
  11. // to "lan.htm"
  12. LPCSTR FindFilePortion(LPCSTR pszPath)
  13. {
  14. int index =0;
  15. CString path(pszPath);
  16. if (-1 == (index = path.ReverseFind(_T('\\'))))
  17. {
  18. if (-1 == (index = path.ReverseFind(_T('/'))))
  19. index = 0;
  20. else
  21. index += sizeof(_T('/'));
  22. }
  23. else
  24. index += sizeof(_T('\\'));
  25. return pszPath + index;
  26. }
  27. CFileSystem::CFileSystem()
  28. {
  29. m_pITStorage = NULL;
  30. m_pStorage = NULL;
  31. m_szPathName[0] = 0;
  32. }
  33. CFileSystem::~CFileSystem()
  34. {
  35. ReleaseObjPtr(m_pStorage);
  36. ReleaseObjPtr(m_pITStorage);
  37. }
  38. HRESULT CFileSystem::Init(void)
  39. {
  40. if (! m_pITStorage) {
  41. IClassFactory* pICFITStorage;
  42. HRESULT hr = CoGetClassObject(CLSID_ITStorage, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **) &pICFITStorage);
  43. if (!SUCCEEDED(hr))
  44. return hr;
  45. hr = pICFITStorage->CreateInstance(NULL, IID_ITStorage,(void **) &m_pITStorage);
  46. ReleaseObjPtr( pICFITStorage );
  47. if (!SUCCEEDED(hr))
  48. return hr;
  49. }
  50. return S_OK;
  51. }
  52. typedef struct tagITSControlData
  53. {
  54. UINT cdwFollowing; // Must be 6 or 13
  55. DWORD cdwITFS_Control; // Must be 5
  56. DWORD dwMagicITS; // Must be MAGIC_ITSFS_CONTROL (see below)
  57. DWORD dwVersionITS; // Must be 1
  58. DWORD cbDirectoryBlock; // Size in bytes of directory blocks (Default is 8192)
  59. DWORD cMinCacheEntries; // Least upper bound on the number of directory blocks
  60. // which we'll cache in memory. (Default is 20)
  61. DWORD fFlags; // Control bit flags (see below).
  62. // Default value is fDefaultIsCompression.
  63. UINT cdwControlData; // Must be 6
  64. DWORD dwLZXMagic; // Must be LZX_MAGIC (see below)
  65. DWORD dwVersion; // Must be 2
  66. DWORD dwMulResetBlock; // Number of blocks between compression resets. (Default: 4)
  67. DWORD dwMulWindowSize; // Maximum number of blocks kept in data history (Default: 4)
  68. DWORD dwMulSecondPartition; // Granularity in blocks of sliding history(Default: 2)
  69. DWORD dwOptions; // Option flags (Default: fOptimizeCodeStreams)
  70. } ITCD;
  71. HRESULT CFileSystem::Create( PCSTR pszPathName )
  72. {
  73. HRESULT hr;
  74. ITCD itcd;
  75. if (! m_pITStorage || m_pStorage )
  76. return E_FAIL;
  77. itcd.cdwFollowing = 13;
  78. itcd.cdwITFS_Control = 5;
  79. itcd.dwMagicITS = MAGIC_ITSFS_CONTROL;
  80. itcd.dwVersionITS = 1;
  81. itcd.cbDirectoryBlock = 4096; // default = 8192
  82. itcd.cMinCacheEntries = 10; // default = 20
  83. itcd.fFlags = 1; // 0 == Uncompressed, 1 == Compressed.
  84. itcd.cdwControlData = 6;
  85. itcd.dwLZXMagic = LZX_MAGIC;
  86. itcd.dwVersion = 2;
  87. itcd.dwMulResetBlock = 2; // Default = 4
  88. itcd.dwMulWindowSize = 2; // Default = 4
  89. itcd.dwMulSecondPartition = 1; // Default = 2
  90. itcd.dwOptions = 0; // Default = fOptimizeCodeStreams
  91. m_pITStorage->SetControlData(PITS_Control_Data(&itcd));
  92. WCHAR wsz[MAX_PATH];
  93. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  94. hr = m_pITStorage->StgCreateDocfile( (LPCWSTR) wsz, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &m_pStorage);
  95. if (!SUCCEEDED(hr)) {
  96. return hr;
  97. }
  98. strcpy( (LPSTR) m_szPathName, pszPathName );
  99. return S_OK;
  100. }
  101. // NOTE: The below function is required for the ITIR full-text indexer to
  102. // initialize. I'm working to find out why this is and what impact
  103. // the below has on the file system.
  104. //
  105. HRESULT CFileSystem::CreateUncompressed( PCSTR pszPathName )
  106. {
  107. HRESULT hr;
  108. ITCD itcd;
  109. if (! m_pITStorage || m_pStorage )
  110. return E_FAIL;
  111. itcd.cdwFollowing = 6;
  112. itcd.cdwITFS_Control = 5;
  113. itcd.dwMagicITS = MAGIC_ITSFS_CONTROL;
  114. itcd.dwVersionITS = 1;
  115. itcd.cbDirectoryBlock = 8192; // default = 8192
  116. itcd.cMinCacheEntries = 20; // default = 20
  117. itcd.fFlags = 0; // 0 == Uncompressed, 1 == Compressed.
  118. m_pITStorage->SetControlData(PITS_Control_Data(&itcd));
  119. WCHAR wsz[MAX_PATH];
  120. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  121. hr = m_pITStorage->StgCreateDocfile( (LPCWSTR) wsz, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &m_pStorage);
  122. if (!SUCCEEDED(hr)) {
  123. return hr;
  124. }
  125. strcpy( (LPSTR) m_szPathName, pszPathName );
  126. return S_OK;
  127. }
  128. HRESULT CFileSystem::Open(PCSTR pszPathName, DWORD dwAccess)
  129. {
  130. HRESULT hr = S_OK;
  131. if (! m_pITStorage || m_pStorage )
  132. return E_FAIL;
  133. // force access modes
  134. if( (dwAccess & STGM_WRITE) || (dwAccess & STGM_READWRITE) ) {
  135. dwAccess &= ~STGM_WRITE;
  136. dwAccess |= STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  137. }
  138. else
  139. dwAccess |= STGM_SHARE_DENY_WRITE;
  140. WCHAR wsz[MAX_PATH];
  141. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  142. hr = m_pITStorage->StgOpenStorage( (LPCWSTR) wsz, NULL, dwAccess, NULL, 0, &m_pStorage);
  143. if (!SUCCEEDED(hr)) {
  144. return hr;
  145. }
  146. strcpy( (LPSTR) m_szPathName, pszPathName );
  147. return hr;
  148. }
  149. HRESULT CFileSystem::Compact(LPCSTR pszPathName)
  150. {
  151. WCHAR wszPathName[MAX_PATH];
  152. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, wszPathName, sizeof(wszPathName));
  153. m_pITStorage->Compact(wszPathName, COMPACT_DATA_AND_PATH);
  154. return S_OK;
  155. }
  156. HRESULT CFileSystem::Close()
  157. {
  158. ReleaseObjPtr(m_pStorage);
  159. return S_OK;
  160. }
  161. //////////////////////////////////////////////////////////////////////////////////////////////
  162. //
  163. // Here are a set of "sub" file I/O calls.
  164. //
  165. //
  166. CSubFileSystem::CSubFileSystem(CFileSystem* pFS)
  167. {
  168. m_pFS = pFS;
  169. m_pStorage = NULL;
  170. m_pStream = NULL;
  171. m_szPathName[0] = 0;
  172. }
  173. CSubFileSystem::~CSubFileSystem()
  174. {
  175. if ( m_pStorage && (m_pStorage != m_pFS->m_pStorage) )
  176. ReleaseObjPtr(m_pStorage);
  177. ReleaseObjPtr(m_pStream);
  178. }
  179. HRESULT CSubFileSystem::CreateSub(PCSTR pszPathName)
  180. {
  181. PCSTR pszFilePortion;
  182. HRESULT hr;
  183. if ( m_pStorage || m_pStream )
  184. return E_FAIL;
  185. if ((pszFilePortion = FindFilePortion(pszPathName)) && pszFilePortion > pszPathName)
  186. {
  187. CHAR szPath[MAX_PATH];
  188. strcpy( szPath, pszPathName );
  189. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  190. WCHAR wszStorage[MAX_PATH];
  191. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  192. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &m_pStorage);
  193. if (!SUCCEEDED(hr) || !m_pStorage) // storage didn't exist, so create it
  194. hr = m_pFS->m_pStorage->CreateStorage(wszStorage, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStorage);
  195. if (!SUCCEEDED(hr))
  196. {
  197. return hr;
  198. }
  199. }
  200. else // no folder, so store the file in the root
  201. {
  202. m_pStorage = m_pFS->m_pStorage;
  203. pszFilePortion = pszPathName;
  204. }
  205. WCHAR wszStream[MAX_PATH];
  206. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  207. hr = m_pStorage->CreateStream(wszStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStream);
  208. if (!SUCCEEDED(hr))
  209. {
  210. if (m_pStorage != m_pFS->m_pStorage)
  211. ReleaseObjPtr(m_pStorage);
  212. return hr;
  213. }
  214. // Needed for delete.
  215. strcpy( m_szPathName, pszFilePortion );
  216. return S_OK;
  217. }
  218. HRESULT CSubFileSystem::CreateUncompressedSub(PCSTR pszPathName)
  219. {
  220. PCSTR pszFilePortion;
  221. HRESULT hr;
  222. IStorageITEx* pIStorageEx;
  223. if ( m_pStorage || m_pStream )
  224. return E_FAIL;
  225. if ((pszFilePortion = FindFilePortion(pszPathName)) && pszFilePortion > pszPathName)
  226. {
  227. CHAR szPath[MAX_PATH];
  228. strcpy( szPath, pszPathName );
  229. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  230. WCHAR wszStorage[MAX_PATH];
  231. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  232. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &m_pStorage);
  233. if (!SUCCEEDED(hr) || !m_pStorage) // storage didn't exist, so create it
  234. hr = m_pFS->m_pStorage->CreateStorage(wszStorage, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStorage);
  235. if (!SUCCEEDED(hr))
  236. {
  237. return hr;
  238. }
  239. }
  240. else // no folder, so store the file in the root
  241. {
  242. m_pStorage = m_pFS->m_pStorage;
  243. pszFilePortion = pszPathName;
  244. }
  245. if ( !(SUCCEEDED(hr = m_pStorage->QueryInterface(IID_IStorageITEx, (void**)&pIStorageEx))) )
  246. pIStorageEx = (IStorageITEx*)m_pStorage; // BUGBUG the QI call above should work!
  247. WCHAR wszStream[MAX_PATH];
  248. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  249. hr = pIStorageEx->CreateStreamITEx(wszStream, txtwUncompressed, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, (IStreamITEx**)&m_pStream);
  250. ReleaseObjPtr(pIStorageEx);
  251. if (!SUCCEEDED(hr))
  252. {
  253. if (m_pStorage != m_pFS->m_pStorage)
  254. ReleaseObjPtr(m_pStorage);
  255. return hr;
  256. }
  257. // Needed for delete.
  258. strcpy( m_szPathName, pszFilePortion );
  259. return S_OK;
  260. }
  261. HRESULT CSubFileSystem::CreateSystemFile(PCSTR pszPathName)
  262. {
  263. m_pStorage = m_pFS->m_pStorage;
  264. WCHAR wszStream[MAX_PATH];
  265. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wszStream, MAX_PATH);
  266. HRESULT hr = m_pStorage->CreateStream(wszStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStream);
  267. if (!SUCCEEDED(hr))
  268. {
  269. return hr;
  270. }
  271. // Needed for delete.
  272. strcpy( m_szPathName, pszPathName );
  273. return S_OK;
  274. }
  275. HRESULT CSubFileSystem::CreateUncompressedSystemFile(PCSTR pszPathName)
  276. {
  277. IStorageITEx* pIStorageEx;
  278. HRESULT hr;
  279. m_pStorage = m_pFS->m_pStorage;
  280. if ( !(SUCCEEDED(hr = m_pStorage->QueryInterface(IID_IStorageITEx, (void**)&pIStorageEx))) )
  281. pIStorageEx = (IStorageITEx*)m_pStorage; // BUGBUG the QI call above should work!
  282. WCHAR wszStream[MAX_PATH];
  283. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wszStream, MAX_PATH);
  284. hr = pIStorageEx->CreateStreamITEx(wszStream, txtwUncompressed, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, (IStreamITEx**)&m_pStream);
  285. ReleaseObjPtr(pIStorageEx);
  286. if (!SUCCEEDED(hr))
  287. {
  288. return hr;
  289. }
  290. // Needed for delete.
  291. strcpy( m_szPathName, pszPathName );
  292. return S_OK;
  293. }
  294. HRESULT CSubFileSystem::OpenSub(PCSTR pszPathName, DWORD dwAccess)
  295. {
  296. PCSTR pszFilePortion;
  297. HRESULT hr;
  298. if ( m_pStorage || m_pStream )
  299. return E_FAIL;
  300. // force access modes
  301. if( (dwAccess & STGM_WRITE) || (dwAccess & STGM_READWRITE) ) {
  302. dwAccess &= ~STGM_WRITE;
  303. dwAccess |= STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  304. }
  305. else
  306. dwAccess |= STGM_SHARE_DENY_WRITE;
  307. if ((pszFilePortion = FindFilePortion(pszPathName)) &&
  308. pszFilePortion > pszPathName + 2) // +2 to support / && ./
  309. {
  310. CHAR szPath[MAX_PATH];
  311. strcpy( szPath, pszPathName );
  312. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  313. WCHAR wszStorage[MAX_PATH];
  314. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  315. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, dwAccess, NULL, 0, &m_pStorage);
  316. if (!SUCCEEDED(hr))
  317. {
  318. return hr;
  319. }
  320. }
  321. else // no folder, so store the file in the root
  322. {
  323. m_pStorage = m_pFS->m_pStorage ? m_pFS->m_pStorage : m_pFS->m_pStorage;
  324. pszFilePortion = pszPathName;
  325. }
  326. WCHAR wszStream[MAX_PATH];
  327. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  328. hr = m_pStorage->OpenStream(wszStream, NULL, dwAccess, 0, &m_pStream);
  329. if (!SUCCEEDED(hr))
  330. {
  331. if (m_pStorage != m_pFS->m_pStorage)
  332. ReleaseObjPtr(m_pStorage);
  333. return hr;
  334. }
  335. // Needed for delete.
  336. strcpy( m_szPathName, pszFilePortion );
  337. return S_OK;
  338. }
  339. ULONG CSubFileSystem::WriteSub(const void* pData, int cb)
  340. {
  341. if ( !m_pStorage || !m_pStream )
  342. return (ULONG) -1;
  343. ULONG cbWritten;
  344. HRESULT hr = m_pStream->Write(pData, cb, &cbWritten);
  345. if (!SUCCEEDED(hr) || (cbWritten != (ULONG)cb) )
  346. {
  347. return (ULONG) -1;
  348. }
  349. // REVIEW: 30-May-1997 [ralphw] Why are we returning this? We fail if
  350. // we don't write cb bytes.
  351. return cbWritten;
  352. }
  353. /*
  354. * iOrigin:
  355. * 0 = Seek from beginning.
  356. * 1 = Seek from current.
  357. * 2 = Seek from end.
  358. */
  359. ULONG CSubFileSystem::SeekSub(int cb, int iOrigin)
  360. {
  361. LARGE_INTEGER liCount = {0,0};
  362. ULARGE_INTEGER liNewPos;
  363. if ( !m_pStorage || !m_pStream )
  364. return (ULONG) -1;
  365. liCount.LowPart = cb;
  366. HRESULT hr = m_pStream->Seek(liCount, iOrigin, &liNewPos);
  367. if (!SUCCEEDED(hr) )
  368. {
  369. return (ULONG) -1;
  370. }
  371. return liNewPos.LowPart;
  372. }
  373. //
  374. // Pre-allocate the size of the stream.
  375. //
  376. HRESULT CSubFileSystem::SetSize(unsigned uSize)
  377. {
  378. ULARGE_INTEGER liSize = {0,0};
  379. HRESULT hr;
  380. if ( !m_pStorage || !m_pStream )
  381. return E_FAIL;
  382. liSize.LowPart = uSize;
  383. hr = m_pStream->SetSize(liSize);
  384. if (!SUCCEEDED(hr) )
  385. {
  386. return (ULONG) -1;
  387. }
  388. return hr;
  389. }
  390. //
  391. // Delete substorage.
  392. //
  393. HRESULT
  394. CSubFileSystem::DeleteSub()
  395. {
  396. if (m_pStorage)
  397. {
  398. if (m_pStream)
  399. {
  400. // Release the stream.
  401. ReleaseObjPtr(m_pStream) ;
  402. }
  403. // Now delete the storage.
  404. WCHAR element[MAX_PATH];
  405. MultiByteToWideChar(CP_ACP, 0, m_szPathName, -1, (PWSTR) element, MAX_PATH);
  406. HRESULT hr = m_pStorage->DestroyElement(element) ;
  407. if (SUCCEEDED(hr))
  408. {
  409. // Get back to the constructor state.
  410. if ( m_pStorage && (m_pStorage != m_pFS->m_pStorage) )
  411. {
  412. ReleaseObjPtr(m_pStorage);
  413. }
  414. return S_OK ;
  415. }
  416. }
  417. return S_OK ;
  418. }