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.

747 lines
15 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1998 **/
  4. /**********************************************************************/
  5. /*
  6. fileinfo.cxx
  7. This module contains the methods for TS_OPEN_FILE_INFO
  8. FILE HISTORY:
  9. MCourage 09-Dec-1997 Created
  10. */
  11. #include <tsunami.hxx>
  12. #include "tsunamip.hxx"
  13. #include <iistypes.hxx>
  14. #include <acache.hxx>
  15. #include <imd.h>
  16. #include <mb.hxx>
  17. #include "string.h"
  18. #include <uspud.h>
  19. #include "filecach.hxx"
  20. #include "filehash.hxx"
  21. #include "tlcach.h"
  22. #include "etagmb.h"
  23. GENERIC_MAPPING g_gmFile = {
  24. FILE_GENERIC_READ,
  25. FILE_GENERIC_WRITE,
  26. FILE_GENERIC_EXECUTE,
  27. FILE_ALL_ACCESS
  28. };
  29. ALLOC_CACHE_HANDLER * TS_OPEN_FILE_INFO::sm_pachFileInfos;
  30. CRITICAL_SECTION TS_OPEN_FILE_INFO::sm_cs;
  31. TS_OPEN_FILE_INFO::TS_OPEN_FILE_INFO()
  32. : m_Signature(TS_FILE_INFO_SIGNATURE),
  33. m_hFile(INVALID_HANDLE_VALUE),
  34. m_hCopyFile(INVALID_HANDLE_VALUE),
  35. m_pFileBuffer(0),
  36. m_hUser(INVALID_HANDLE_VALUE),
  37. m_cbSecDescMaxSize(0),
  38. m_pSecurityDescriptor(m_abSecDesc),
  39. m_fSecurityDescriptor(FALSE),
  40. m_cchHttpInfo(0),
  41. m_cchETag(0),
  42. m_ETagIsWeak(TRUE),
  43. m_bIsCached(FALSE),
  44. m_state(FI_UNINITIALIZED),
  45. m_lRefCount(0),
  46. m_dwIORefCount(0),
  47. m_TTL(1),
  48. m_FileAttributes(0xFFFFFFFF),
  49. m_pvContext( NULL ),
  50. m_pfnFreeRoutine( NULL )
  51. {
  52. m_FileKey.m_cbFileName = 0;
  53. m_FileKey.m_pszFileName = NULL;
  54. }
  55. BOOL
  56. TS_OPEN_FILE_INFO::SetContext(
  57. PVOID pvContext,
  58. PCONTEXT_FREE_ROUTINE pfnFreeRoutine
  59. )
  60. /*++
  61. Routine Description
  62. Used by external components (SSI) to set an opaque context and a
  63. free routine to be called when freeing the context. This allows SSI
  64. to associate the SSI parsed template with actual TS_OPEN_FILE_INFO
  65. Arguments
  66. None.
  67. Return
  68. TRUE if the context was set. FALSE if there was already a context.
  69. --*/
  70. {
  71. BOOL fRet;
  72. Lock();
  73. if ( m_pvContext != NULL )
  74. {
  75. fRet = FALSE;
  76. }
  77. else
  78. {
  79. m_pvContext = pvContext;
  80. m_pfnFreeRoutine = pfnFreeRoutine;
  81. fRet = TRUE;
  82. }
  83. Unlock();
  84. return fRet;
  85. }
  86. PVOID
  87. TS_OPEN_FILE_INFO::QueryContext(
  88. VOID
  89. ) const
  90. /*++
  91. Routine Description
  92. Returns the context associated with the TS_OPEN_FILE_INFO
  93. Arguments
  94. None.
  95. Return
  96. Pointer to context
  97. --*/
  98. {
  99. PVOID pvContext;
  100. Lock();
  101. pvContext = m_pvContext;
  102. Unlock();
  103. return pvContext;
  104. }
  105. VOID
  106. TS_OPEN_FILE_INFO::FreeContext(
  107. VOID
  108. )
  109. /*++
  110. Routine Description
  111. Frees the opaque context by calling the free routine
  112. Arguments
  113. None.
  114. Return
  115. None
  116. --*/
  117. {
  118. Lock();
  119. if ( m_pvContext )
  120. {
  121. if ( m_pfnFreeRoutine )
  122. {
  123. __try
  124. {
  125. m_pfnFreeRoutine( m_pvContext );
  126. }
  127. __finally
  128. {
  129. m_pvContext = NULL;
  130. }
  131. }
  132. else
  133. {
  134. DBG_ASSERT( FALSE );
  135. }
  136. }
  137. Unlock();
  138. }
  139. BOOL
  140. FileFlushFilterContext(
  141. TS_OPEN_FILE_INFO *pOpenFile,
  142. PVOID pv
  143. )
  144. /*++
  145. Routine Description
  146. Filter used by FilteredFlushFileCache to select those TS_OPEN_FILE_INFO
  147. objects which have a context. This routine will actually do the freeing
  148. and will return FALSE. This is done to prevent premature flushing of
  149. the cache when SSI shuts down.
  150. Arguments
  151. pOpenFile - TS_OPEN_FILE_INFO object
  152. pv - Unused context
  153. Return
  154. Always returns FALSE
  155. --*/
  156. {
  157. DBG_ASSERT( pOpenFile );
  158. pOpenFile->FreeContext();
  159. DBG_ASSERT( !pOpenFile->QueryContext() );
  160. return FALSE;
  161. }
  162. VOID
  163. TsFlushFilesWithContext(
  164. VOID
  165. )
  166. /*++
  167. Routine Description
  168. Exported routine used by SSI to free all opaque contexts. This is called
  169. before SSINC.DLL is unloaded to prevent AVs in context free
  170. Arguments
  171. None
  172. Return
  173. None
  174. --*/
  175. {
  176. FilteredFlushFileCache( FileFlushFilterContext, NULL );
  177. }
  178. BOOL
  179. TS_OPEN_FILE_INFO::SetFileName(const CHAR * pszFileName)
  180. {
  181. DBG_ASSERT( pszFileName );
  182. DBG_ASSERT( pszFileName[0] );
  183. m_FileKey.m_cbFileName = strlen(pszFileName);
  184. if (m_FileKey.m_cbFileName < TS_DEFAULT_PATH_SIZE) {
  185. //
  186. // It fits in our fixed size buffer
  187. //
  188. m_FileKey.m_pszFileName = m_FileKey.m_achFileNameBuf;
  189. } else {
  190. //
  191. // we need a bigger buffer
  192. //
  193. m_FileKey.m_pszFileName = new CHAR[m_FileKey.m_cbFileName + 1];
  194. }
  195. if (NULL != m_FileKey.m_pszFileName) {
  196. memcpy(m_FileKey.m_pszFileName, pszFileName, m_FileKey.m_cbFileName + 1);
  197. } else {
  198. m_FileKey.m_cbFileName = 0;
  199. }
  200. return (0 != m_FileKey.m_cbFileName);
  201. }
  202. TS_OPEN_FILE_INFO::~TS_OPEN_FILE_INFO( VOID)
  203. {
  204. DBG_ASSERT( 0 == m_lRefCount );
  205. DBG_ASSERT( 0 == m_dwIORefCount );
  206. DBG_ASSERT( CheckSignature() );
  207. m_Signature = TS_FREE_FILE_INFO_SIGNATURE;
  208. if (m_FileKey.m_pszFileName
  209. && (m_FileKey.m_achFileNameBuf != m_FileKey.m_pszFileName)) {
  210. delete [] m_FileKey.m_pszFileName;
  211. }
  212. if (m_pFileBuffer) {
  213. DWORD dwError;
  214. dwError = ReleaseFromMemoryCache(
  215. m_pFileBuffer,
  216. m_nFileSizeLow
  217. );
  218. DBG_ASSERT(dwError == ERROR_SUCCESS);
  219. }
  220. if (m_pSecurityDescriptor
  221. && (m_pSecurityDescriptor != m_abSecDesc)) {
  222. FREE(m_pSecurityDescriptor);
  223. }
  224. if (m_pvContext)
  225. {
  226. FreeContext();
  227. }
  228. }
  229. BOOL
  230. TS_OPEN_FILE_INFO::AccessCheck(
  231. IN HANDLE hUser,
  232. IN BOOL bCache
  233. )
  234. {
  235. DBG_ASSERT(hUser != INVALID_HANDLE_VALUE);
  236. //
  237. // If it's the same user that last opened the file
  238. // then we know we have access.
  239. //
  240. if (hUser == m_hUser) {
  241. TraceCheckpointEx(TS_MAGIC_ACCESS_CHECK, (PVOID)hUser, (PVOID)(LONG_PTR)0xffffffff);
  242. return TRUE;
  243. }
  244. //
  245. // If we've got a security descriptor we can check
  246. // against that, otherwise fail the check.
  247. //
  248. BYTE psFile[SIZE_PRIVILEGE_SET];
  249. DWORD dwPS;
  250. DWORD dwGrantedAccess;
  251. BOOL fAccess;
  252. dwPS = sizeof(psFile);
  253. ((PRIVILEGE_SET*)&psFile)->PrivilegeCount = 0;
  254. if (m_fSecurityDescriptor
  255. && ::AccessCheck(m_pSecurityDescriptor,
  256. hUser,
  257. FILE_GENERIC_READ,
  258. &g_gmFile,
  259. (PRIVILEGE_SET*)psFile,
  260. &dwPS,
  261. &dwGrantedAccess,
  262. &fAccess) ) {
  263. if (fAccess && bCache) {
  264. m_hUser = hUser;
  265. }
  266. TraceCheckpointEx(TS_MAGIC_ACCESS_CHECK, (PVOID)hUser, (PVOID) (ULONG_PTR) fAccess);
  267. return fAccess;
  268. } else {
  269. return FALSE;
  270. }
  271. }
  272. VOID
  273. TS_OPEN_FILE_INFO::SetFileInfo(
  274. HANDLE hFile,
  275. HANDLE hUser,
  276. PSECURITY_DESCRIPTOR pSecDesc,
  277. DWORD dwSecDescSize
  278. )
  279. {
  280. BY_HANDLE_FILE_INFORMATION FileInfo;
  281. //
  282. // Fetch file information
  283. //
  284. BOOL fReturn;
  285. fReturn = GetFileInformationByHandle(
  286. hFile,
  287. &FileInfo
  288. );
  289. m_FileAttributes = FileInfo.dwFileAttributes;
  290. m_nFileSizeLow = FileInfo.nFileSizeLow;
  291. m_nFileSizeHigh = FileInfo.nFileSizeHigh;
  292. m_ftLastWriteTime = (__int64)*(__int64 *) &FileInfo.ftLastWriteTime;
  293. //
  294. // Handle common info
  295. //
  296. SetFileInfoHelper(hFile, hUser, pSecDesc, dwSecDescSize);
  297. }
  298. VOID
  299. TS_OPEN_FILE_INFO::SetFileInfo(
  300. PBYTE pFileBuff,
  301. HANDLE hCopyFile,
  302. HANDLE hFile,
  303. HANDLE hUser,
  304. PSECURITY_DESCRIPTOR pSecDesc,
  305. DWORD dwSecDescSize,
  306. PSPUD_FILE_INFORMATION pFileInfo
  307. )
  308. {
  309. //
  310. // Save SPUD specific parameters
  311. //
  312. m_FileAttributes = pFileInfo->BasicInformation.FileAttributes;
  313. m_nFileSizeLow = pFileInfo->StandardInformation.EndOfFile.LowPart;
  314. m_nFileSizeHigh = pFileInfo->StandardInformation.EndOfFile.HighPart;
  315. m_ftLastWriteTime = (__int64)*(__int64 *) &pFileInfo->BasicInformation.LastWriteTime;
  316. //
  317. // Save file buffer
  318. //
  319. m_pFileBuffer = pFileBuff;
  320. m_hCopyFile = hCopyFile;
  321. //
  322. // Handle common info
  323. //
  324. SetFileInfoHelper(hFile, hUser, pSecDesc, dwSecDescSize);
  325. }
  326. VOID
  327. TS_OPEN_FILE_INFO::SetFileInfoHelper(
  328. HANDLE hFile,
  329. HANDLE hUser,
  330. PSECURITY_DESCRIPTOR pSecDesc,
  331. DWORD dwSecDescSize
  332. )
  333. {
  334. //
  335. // Save away the given parameters
  336. //
  337. m_hFile = hFile;
  338. m_hUser = hUser;
  339. m_pSecurityDescriptor = pSecDesc;
  340. m_cbSecDescMaxSize = dwSecDescSize;
  341. if (dwSecDescSize)
  342. m_fSecurityDescriptor = TRUE;
  343. //
  344. // Generate some other file attributes
  345. //
  346. DWORD dwChangeNumber = ETagChangeNumber::GetChangeNumber();
  347. BOOL fReturn = TRUE;
  348. *((__int64 *)&m_CastratedLastWriteTime)
  349. = (*((__int64 *)&m_ftLastWriteTime) / 10000000)
  350. * 10000000;
  351. //
  352. // Make the ETag
  353. //
  354. m_ETagIsWeak = TRUE;
  355. m_cchETag = FORMAT_ETAG(m_achETag, *(FILETIME*) &m_ftLastWriteTime,
  356. dwChangeNumber);
  357. //
  358. // Make the ETag strong if possible
  359. //
  360. MakeStrongETag();
  361. //
  362. // Turn off the hidden attribute if this is a root directory listing
  363. // (root some times has the bit set for no apparent reason)
  364. //
  365. if ( m_FileAttributes & FILE_ATTRIBUTE_HIDDEN )
  366. {
  367. CHAR * pszFileName = m_FileKey.m_pszFileName;
  368. if ( m_FileKey.m_cbFileName >= 2 )
  369. {
  370. if ( pszFileName[ 1 ] == ':' )
  371. {
  372. if ( ( pszFileName[ 2 ] == '\0' ) ||
  373. ( pszFileName[ 2 ] == '\\' && pszFileName[ 3 ] == '\0' ) )
  374. {
  375. //
  376. // This looks like a local root. Mask out the bit
  377. //
  378. m_FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
  379. }
  380. }
  381. }
  382. }
  383. }
  384. VOID
  385. TS_OPEN_FILE_INFO::CloseHandle(
  386. void
  387. )
  388. {
  389. HANDLE hFile;
  390. PBYTE pFileBuffer;
  391. BOOL bClose = FALSE;
  392. BOOL bRelease = FALSE;
  393. DWORD dwError;
  394. Lock();
  395. ASSERT( DisableTsunamiCaching
  396. || (m_state == FI_FLUSHED)
  397. || (m_bIsCached == FALSE) );
  398. ASSERT( m_dwIORefCount == 0 );
  399. m_state = FI_CLOSED;
  400. if (m_pFileBuffer) {
  401. pFileBuffer = m_pFileBuffer;
  402. m_pFileBuffer = NULL;
  403. bRelease = TRUE;
  404. }
  405. if (m_hFile != INVALID_HANDLE_VALUE) {
  406. hFile = m_hFile;
  407. m_hFile = INVALID_HANDLE_VALUE;
  408. bClose = TRUE;
  409. }
  410. DBG_ASSERT(m_hCopyFile == INVALID_HANDLE_VALUE);
  411. Unlock();
  412. if (bRelease) {
  413. TraceCheckpointEx(TS_MAGIC_CLOSE, pFileBuffer, (PVOID) 1);
  414. dwError = ReleaseFromMemoryCache(
  415. pFileBuffer,
  416. m_nFileSizeLow
  417. );
  418. DBG_ASSERT(dwError == ERROR_SUCCESS);
  419. }
  420. if (bClose) {
  421. TraceCheckpointEx(TS_MAGIC_CLOSE, hFile, 0);
  422. ::CloseHandle(hFile);
  423. }
  424. }
  425. INT
  426. FormatETag(
  427. PCHAR pszBuffer,
  428. const FILETIME& rft,
  429. DWORD mdchange)
  430. {
  431. PCHAR psz = pszBuffer;
  432. PBYTE pbTime = (PBYTE) &rft;
  433. const char szHex[] = "0123456789abcdef";
  434. *psz++ = '\"';
  435. for (int i = 0; i < 8; i++)
  436. {
  437. BYTE b = *pbTime++;
  438. BYTE bH = b >> 4;
  439. if (bH != 0)
  440. *psz++ = szHex[bH];
  441. *psz++ = szHex[b & 0xF];
  442. }
  443. *psz++ = ':';
  444. psz += strlen(_itoa((DWORD) mdchange, psz, 16));
  445. *psz++ = '\"';
  446. *psz = '\0';
  447. return (INT)(psz - pszBuffer);
  448. }
  449. VOID
  450. TS_OPEN_FILE_INFO::MakeStrongETag(
  451. VOID
  452. )
  453. /*++
  454. Routine Description
  455. Try and make an ETag 'strong'. To do this we see if the difference
  456. between now and the last modified date is greater than our strong ETag
  457. delta - if so, we mark the ETag strong.
  458. Arguments
  459. None.
  460. Returns
  461. Nothing.
  462. --*/
  463. {
  464. FILETIME ftNow;
  465. SYSTEMTIME stNow;
  466. __int64 iNow, iFileTime;
  467. if ( m_pFileBuffer ||
  468. m_hFile != INVALID_HANDLE_VALUE ) {
  469. ::GetSystemTimeAsFileTime(&ftNow);
  470. iNow = (__int64)*(__int64 *)&ftNow;
  471. iFileTime = (__int64)*(__int64 *)&m_ftLastWriteTime;
  472. if ((iNow - iFileTime) > STRONG_ETAG_DELTA )
  473. {
  474. m_ETagIsWeak = FALSE;
  475. }
  476. }
  477. }
  478. BOOL
  479. TS_OPEN_FILE_INFO::SetHttpInfo(
  480. IN PSTR pszInfo,
  481. IN INT InfoLength
  482. )
  483. /*++
  484. Routine Description
  485. Set the "Last-Modified:" header field in the file structure.
  486. Arguments
  487. pszDate - pointer to the header value to save
  488. InfoLength - length of the header value to save
  489. Returns
  490. TRUE if information was cached,
  491. FALSE if not cached
  492. --*/
  493. {
  494. if ( !m_ETagIsWeak && InfoLength < sizeof(m_achHttpInfo)-1 ) {
  495. CopyMemory( m_achHttpInfo, pszInfo, InfoLength+1 );
  496. //
  497. // this MUST be set after updating the array,
  498. // as this is checked to know if the array content is valid.
  499. //
  500. m_cchHttpInfo = InfoLength;
  501. return TRUE;
  502. }
  503. return FALSE;
  504. } // TS_OPEN_FILE_INFO::SetHttpInfo
  505. /*
  506. * Static members
  507. */
  508. BOOL
  509. TS_OPEN_FILE_INFO::Initialize(
  510. DWORD dwMaxFiles
  511. )
  512. {
  513. ALLOC_CACHE_CONFIGURATION acConfig = { 1, dwMaxFiles, sizeof(TS_OPEN_FILE_INFO)};
  514. if ( NULL != sm_pachFileInfos) {
  515. // already initialized
  516. return ( TRUE);
  517. }
  518. sm_pachFileInfos = new ALLOC_CACHE_HANDLER( "FileInfos",
  519. &acConfig);
  520. if ( sm_pachFileInfos ) {
  521. INITIALIZE_CRITICAL_SECTION(&sm_cs);
  522. }
  523. return ( NULL != sm_pachFileInfos);
  524. }
  525. VOID
  526. TS_OPEN_FILE_INFO::Cleanup(
  527. VOID
  528. )
  529. {
  530. if ( NULL != sm_pachFileInfos) {
  531. delete sm_pachFileInfos;
  532. sm_pachFileInfos = NULL;
  533. DeleteCriticalSection(&sm_cs);
  534. }
  535. }
  536. VOID
  537. TS_OPEN_FILE_INFO::Lock(
  538. VOID
  539. )
  540. {
  541. EnterCriticalSection(&sm_cs);
  542. }
  543. VOID
  544. TS_OPEN_FILE_INFO::Unlock(
  545. VOID
  546. )
  547. {
  548. LeaveCriticalSection(&sm_cs);
  549. }
  550. VOID *
  551. TS_OPEN_FILE_INFO::operator new( size_t s)
  552. {
  553. DBG_ASSERT( s == sizeof( TS_OPEN_FILE_INFO));
  554. // allocate from allocation cache.
  555. DBG_ASSERT( NULL != sm_pachFileInfos);
  556. return (sm_pachFileInfos->Alloc());
  557. }
  558. VOID
  559. TS_OPEN_FILE_INFO::operator delete( void * pOpenFile)
  560. {
  561. DBG_ASSERT( NULL != pOpenFile);
  562. // free to the allocation pool
  563. DBG_ASSERT( NULL != sm_pachFileInfos);
  564. DBG_REQUIRE( sm_pachFileInfos->Free(pOpenFile));
  565. return;
  566. }
  567. //
  568. // fileopen.cxx
  569. //