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.

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