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.

687 lines
17 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. ilogfile.cxx
  5. Abstract:
  6. This module defines helper functions for File logging
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 21-FEb-1996
  9. --*/
  10. #include "precomp.hxx"
  11. #define BLOCK_INC_SIZE 1
  12. #if !defined(STATUS_DISK_FULL)
  13. #define STATUS_DISK_FULL 0xC000007FL
  14. #endif
  15. ILOG_FILE::ILOG_FILE(
  16. VOID
  17. )
  18. /*++
  19. This function constructs a new File object used for handling
  20. log files.
  21. The reference count is used to count the number of owners
  22. of this object. It starts off with 1.
  23. the ILOG_FILE::OpenFileForAppend() function
  24. inrements refcount when a new owner is given this object
  25. the ILOG_FILE::CloseFile() function
  26. derements refcount when an owner relinquishes the object
  27. --*/
  28. :
  29. m_hFile ( INVALID_HANDLE_VALUE),
  30. m_pvBuffer ( NULL),
  31. m_cbBufferUsed ( 0),
  32. m_hMemFile ( NULL),
  33. m_nGranules ( 0),
  34. m_strFileName ( )
  35. {
  36. SYSTEM_INFO sysInfo;
  37. m_qwFilePos.QuadPart = 0;
  38. m_mapSize.QuadPart = 0;
  39. GetSystemInfo(&sysInfo);
  40. m_dwAllocationGranularity = sysInfo.dwAllocationGranularity;
  41. if ( m_dwAllocationGranularity == 0 ) {
  42. m_dwAllocationGranularity = 0x10000;
  43. }
  44. } // ILOG_FILE::ILOG_FILE()
  45. ILOG_FILE::~ILOG_FILE(VOID)
  46. /*++
  47. This function cleans up state maintained within the object -
  48. freeing up the memory and closing file handle.
  49. It then destroys all state information maintained.
  50. The reference count should be zero, indicating this object is no more in use.
  51. --*/
  52. {
  53. CloseFile();
  54. return;
  55. } // ILOG_FILE::~ILOG_FILE()
  56. BOOL
  57. ILOG_FILE::ExpandMapping(
  58. VOID
  59. )
  60. {
  61. m_mapSize.QuadPart = m_mapSize.QuadPart + (ULONGLONG)(BLOCK_INC_SIZE * m_dwAllocationGranularity);
  62. /*
  63. //
  64. // This check is removed as now condition isn't true becuase we are not limited by 32 bit
  65. // truncation size
  66. //
  67. if ( (newMapSize.QuadPart < m_mapSize.QuadPart) || (m_mapSize.QuadPart > m_qwTruncateSize.QuadPart) ) {
  68. IIS_PRINTF((buff,"Cannot expand mapping. "
  69. "New size %d will exceed truncation size %d\n",
  70. newMapSize, m_qwTruncateSize));
  71. SetLastError( ERROR_DISK_FULL );
  72. return(FALSE);
  73. }
  74. */
  75. //
  76. // Destroy the old and create a new mapping
  77. //
  78. DestroyMapping( );
  79. return(CreateMapping( ));
  80. } // ExpandMapping
  81. BOOL
  82. ILOG_FILE::CreateMapping(
  83. VOID
  84. )
  85. {
  86. //
  87. // find the next file mapping window
  88. //
  89. ULARGE_INTEGER qwStart;
  90. ULARGE_INTEGER qwTmp;
  91. DWORD dwSize;
  92. //DWORD dwSize;
  93. qwStart.QuadPart = m_qwFilePos.QuadPart;
  94. qwStart.LowPart = qwStart.LowPart - (qwStart.LowPart % m_dwAllocationGranularity);
  95. m_hMemFile = CreateFileMapping(
  96. m_hFile,
  97. NULL,
  98. PAGE_READWRITE,
  99. m_mapSize.HighPart,
  100. m_mapSize.LowPart,
  101. NULL ) ;
  102. if ( m_hMemFile == NULL ) {
  103. #if 0
  104. IIS_PRINTF((buff,"Error %d in CreateFileMapping[%s][size = %d]\n",
  105. GetLastError(), m_strFileName.QueryStr(),
  106. m_mapSize ));
  107. #endif
  108. SetLastError( ERROR_DISK_FULL );
  109. return(FALSE);
  110. }
  111. qwTmp.QuadPart = m_mapSize.QuadPart - qwStart.QuadPart;
  112. dwSize = qwTmp.LowPart;
  113. qwTmp.QuadPart = m_qwFilePos.QuadPart - qwStart.QuadPart;
  114. m_cbBufferUsed = qwTmp.LowPart;
  115. m_pvBuffer = MapViewOfFile(
  116. m_hMemFile,
  117. FILE_MAP_ALL_ACCESS,
  118. qwStart.HighPart,
  119. qwStart.LowPart,
  120. dwSize
  121. );
  122. if ( m_pvBuffer == NULL ) {
  123. IIS_PRINTF((buff,"Error %d in MapViewOfFile[%s][%d:%d,%d]\n",
  124. GetLastError(), m_strFileName.QueryStr(),
  125. qwStart.HighPart,qwStart.LowPart, dwSize ));
  126. DestroyMapping();
  127. return(FALSE);
  128. }
  129. return(TRUE);
  130. } // CreateMapping
  131. BOOL
  132. ILOG_FILE::Write(
  133. IN PCHAR pvData,
  134. IN DWORD cbData
  135. )
  136. /*++
  137. This function writes the data present in the input buffer of specified
  138. length to the file.
  139. For performance reasons, the function actually buffers data in the
  140. internal buffers of ILOG_FILE object. Such buffered data is flushed
  141. to disk later on when buffer (chain) is full or when
  142. a flush call is made from a scheduled flush.
  143. Arguments:
  144. pvData pointer to buffer containing data to be written
  145. cbData count of characters of data to be written.
  146. Returns:
  147. TRUE on success and FALSE if there is any error.
  148. --*/
  149. {
  150. ULARGE_INTEGER oldFilePos;
  151. ULARGE_INTEGER newFilePos;
  152. BOOL fReturn = TRUE;
  153. if ( m_hMemFile == NULL ) {
  154. SetLastError( ERROR_INVALID_PARAMETER);
  155. return ( FALSE);
  156. }
  157. //
  158. // Bug 110351: Need try-except blocks around CopyMemory for dealing
  159. // with compressed files
  160. //
  161. oldFilePos.QuadPart = m_qwFilePos.QuadPart;
  162. newFilePos.QuadPart = m_qwFilePos.QuadPart + (ULONGLONG)cbData;
  163. //
  164. // copy part of the data to the end of the buffer
  165. //
  166. if (newFilePos.QuadPart > m_mapSize.QuadPart ) {
  167. ULARGE_INTEGER qwSpace;
  168. DWORD dwSpace;
  169. qwSpace.QuadPart = m_mapSize.QuadPart - m_qwFilePos.QuadPart;
  170. dwSpace = qwSpace.LowPart;
  171. __try
  172. {
  173. CopyMemory(
  174. (LPBYTE)m_pvBuffer + m_cbBufferUsed,
  175. (PVOID)pvData,
  176. dwSpace
  177. );
  178. }
  179. __except( ( _exception_code() == STATUS_IN_PAGE_ERROR ||
  180. _exception_code() == STATUS_DISK_FULL ) ?
  181. EXCEPTION_EXECUTE_HANDLER :
  182. EXCEPTION_CONTINUE_SEARCH )
  183. {
  184. SetLastError( _exception_code() );
  185. goto error_exit;
  186. }
  187. cbData -= dwSpace;
  188. pvData += dwSpace;
  189. m_cbBufferUsed += dwSpace;
  190. m_qwFilePos.QuadPart = m_qwFilePos.QuadPart + qwSpace.QuadPart;
  191. if ( !ExpandMapping( ) )
  192. {
  193. DWORD err = GetLastError();
  194. SetLastError(err);
  195. goto error_exit;
  196. }
  197. }
  198. __try
  199. {
  200. CopyMemory(
  201. (LPBYTE)m_pvBuffer + m_cbBufferUsed,
  202. pvData,
  203. cbData
  204. );
  205. }
  206. __except(( _exception_code() == STATUS_IN_PAGE_ERROR ||
  207. _exception_code() == STATUS_DISK_FULL ) ?
  208. EXCEPTION_EXECUTE_HANDLER :
  209. EXCEPTION_CONTINUE_SEARCH )
  210. {
  211. SetLastError( _exception_code() );
  212. goto error_exit;
  213. }
  214. m_cbBufferUsed += cbData;
  215. m_qwFilePos.QuadPart = m_qwFilePos.QuadPart + (ULONGLONG)cbData;
  216. return ( fReturn);
  217. error_exit:
  218. m_qwFilePos.QuadPart = oldFilePos.QuadPart;
  219. CloseFile( );
  220. return(FALSE);
  221. } // ILOG_FILE::Write()
  222. BOOL
  223. ILOG_FILE::Open(
  224. IN LPCSTR pszFileName,
  225. IN DWORD dwTruncationSize,
  226. IN BOOL fLogEvent
  227. )
  228. /*++
  229. This function opens up a new file for appending data.
  230. This function automatically sets the file pointer to be
  231. at the end of file to just enable append to file.
  232. This function should be called after locking this object
  233. Arguments:
  234. pszFileName - name of the file to open
  235. dwTruncationSize
  236. fLogEvent - Produce an event log if Open fails.
  237. Returns:
  238. TRUE on success and FALSE if there is any failure.
  239. --*/
  240. {
  241. BOOL fRet;
  242. HANDLE hToken = NULL;
  243. if ( dwTruncationSize < MIN_FILE_TRUNCATION_SIZE ) {
  244. dwTruncationSize = MIN_FILE_TRUNCATION_SIZE;
  245. }
  246. m_qwTruncateSize.HighPart = 0;
  247. m_qwTruncateSize.LowPart = dwTruncationSize;
  248. m_nGranules = BLOCK_INC_SIZE;
  249. m_mapSize.QuadPart = UInt32x32To64(m_nGranules,m_dwAllocationGranularity);
  250. m_strFileName.Copy(pszFileName);
  251. //
  252. // There is a small chance that this function could be called (indirectly)
  253. // from an INPROC ISAPI completion thread (HSE_REQ_DONE). In this case
  254. // the thread token is the impersonated user and may not have permissions
  255. // to open the log file (especially if the user is the IUSR_ account).
  256. // To be paranoid, let's revert to LOCAL_SYSTEM anyways before opening.
  257. //
  258. if ( OpenThreadToken( GetCurrentThread(),
  259. TOKEN_ALL_ACCESS,
  260. FALSE,
  261. &hToken ) )
  262. {
  263. DBG_ASSERT( hToken != NULL );
  264. RevertToSelf();
  265. }
  266. fRet = OpenFile( pszFileName, fLogEvent);
  267. if ( hToken != NULL )
  268. {
  269. SetThreadToken( NULL, hToken );
  270. }
  271. return fRet;
  272. } // ILOG_FILE::Open
  273. BOOL
  274. ILOG_FILE::OpenFile(
  275. IN LPCSTR pszFileName,
  276. IN BOOL fLogEvent
  277. )
  278. {
  279. ULARGE_INTEGER qwTmp;
  280. DWORD err = NO_ERROR;
  281. m_qwFilePos.QuadPart = 0;
  282. m_pvBuffer = NULL;
  283. m_cbBufferUsed = 0;
  284. //
  285. // 1. Create a new file -- open a file if it already exists
  286. //
  287. m_hFile = CreateFile(pszFileName,
  288. GENERIC_WRITE | GENERIC_READ,
  289. FILE_SHARE_WRITE | FILE_SHARE_READ,
  290. NULL, // security attributes
  291. OPEN_ALWAYS,
  292. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  293. NULL); // template file handle
  294. if ( m_hFile == INVALID_HANDLE_VALUE ) {
  295. err = GetLastError();
  296. if ( (g_eventLog != NULL) && fLogEvent) {
  297. const CHAR* tmpString[1];
  298. tmpString[0] = pszFileName;
  299. g_eventLog->LogEvent(
  300. LOG_EVENT_CREATE_FILE_ERROR,
  301. 1,
  302. tmpString,
  303. err
  304. );
  305. }
  306. IIS_PRINTF((buff,"CreateFile[%s] error %d\n",
  307. pszFileName, err));
  308. SetLastError(err);
  309. return(FALSE);
  310. }
  311. //
  312. // 2. Set the file pointer at the end of the file (append mode)
  313. //
  314. if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
  315. if ( !PositionToEOF( &m_qwFilePos ) ) {
  316. err = GetLastError();
  317. goto error_exit;
  318. }
  319. qwTmp.HighPart = 0;
  320. qwTmp.LowPart = BLOCK_INC_SIZE * m_dwAllocationGranularity;
  321. while ( m_qwFilePos.QuadPart >= m_mapSize.QuadPart ) {
  322. m_mapSize.QuadPart = m_mapSize.QuadPart + qwTmp.QuadPart;
  323. m_nGranules += BLOCK_INC_SIZE;
  324. }
  325. /*
  326. // not anymore a problem for 64b file possition offsets
  327. if ( m_mapSize.QuadPart >= m_qwTruncateSize.QuadPart ) {
  328. IIS_PRINTF((buff,"[OpenFile] Truncate size[%d] exceeded[%d]\n",
  329. m_qwTruncateSize, m_mapSize));
  330. err = ERROR_INSUFFICIENT_BUFFER;
  331. goto error_exit;
  332. }
  333. */
  334. }
  335. if ( !CreateMapping( ) ) {
  336. err = GetLastError();
  337. goto error_exit;
  338. }
  339. return ( TRUE );
  340. error_exit:
  341. CloseFile( );
  342. SetLastError(err);
  343. return(FALSE);
  344. } // ILOG_FILE::OpenFile()
  345. BOOL
  346. ILOG_FILE::PositionToEOF(
  347. ULARGE_INTEGER *pFilePos
  348. )
  349. /*++
  350. Determine where to begin append operation
  351. This function should be called after locking this object
  352. Arguments:
  353. pFilePos - updated with position where to begin append if success
  354. Returns:
  355. TRUE on success and FALSE if there is any failure.
  356. --*/
  357. {
  358. ULARGE_INTEGER qwFileSize;
  359. ULARGE_INTEGER qwFilePos;
  360. BOOL fReturn = FALSE;
  361. DWORD dwRet;
  362. //
  363. // If file size multiple of BLOCK_INC_SIZE * m_dwAllocationGranularity
  364. // then it is likely that file has not been closed properly.
  365. // If this is the case we need to get the position of the last
  366. // zero char in the file and start logging there.
  367. //
  368. qwFileSize.QuadPart = 0;
  369. qwFileSize.LowPart = GetFileSize( m_hFile,&qwFileSize.HighPart);
  370. if (qwFileSize.LowPart != FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
  371. {
  372. if ( (qwFileSize.LowPart == 0) ||
  373. (qwFileSize.LowPart % m_dwAllocationGranularity) != 0 )
  374. {
  375. qwFilePos.QuadPart = 0;
  376. dwRet = SetFilePointer(m_hFile,
  377. qwFilePos.LowPart,
  378. (PLONG)(&qwFilePos.HighPart),
  379. FILE_END);
  380. if (dwRet != FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
  381. {
  382. pFilePos->QuadPart = qwFileSize.QuadPart;
  383. return TRUE;
  384. }
  385. else
  386. {
  387. IIS_PRINTF((buff,"SetFilePointer[END] failed %d\n",
  388. GetLastError()));
  389. return(FALSE);
  390. }
  391. }
  392. else
  393. {
  394. //
  395. // find last zero char in file
  396. //
  397. ULARGE_INTEGER lLow;
  398. ULARGE_INTEGER lHigh;
  399. ULARGE_INTEGER lLast;
  400. ULARGE_INTEGER lMiddle;
  401. CHAR ch;
  402. DWORD dwRead;
  403. lLow.QuadPart = 0;
  404. lHigh.QuadPart = qwFileSize.QuadPart - 1;
  405. lLast.QuadPart = qwFileSize.QuadPart;
  406. fReturn = TRUE;
  407. while ( lLow.QuadPart <= lHigh.QuadPart ) {
  408. lMiddle.QuadPart = lLow.QuadPart + (lHigh.QuadPart - lLow.QuadPart) / 2;
  409. dwRet = SetFilePointer( m_hFile,
  410. lMiddle.LowPart,
  411. (PLONG)(&lMiddle.HighPart),
  412. FILE_BEGIN);
  413. if (dwRet==FILE_SIZE_LOW_MAX && GetLastError()!=NO_ERROR)
  414. {
  415. fReturn = FALSE;
  416. break;
  417. }
  418. if ( ReadFile( m_hFile, &ch, 1, &dwRead, NULL ) ) {
  419. if ( ch == '\0' ) {
  420. lHigh.QuadPart = lMiddle.QuadPart - 1;
  421. lLast.QuadPart = lMiddle.QuadPart;
  422. } else {
  423. lLow.QuadPart = lMiddle.QuadPart + 1;
  424. }
  425. } else {
  426. fReturn = FALSE;
  427. break;
  428. }
  429. }
  430. if ( fReturn ) {
  431. IIS_PRINTF((buff,"[ilogfile.cxx], set log pos:%I64u\n",
  432. lLast.QuadPart ));
  433. dwRet = SetFilePointer( m_hFile,
  434. lLast.LowPart,
  435. (PLONG)(&lLast.HighPart),
  436. FILE_BEGIN );
  437. if (dwRet!=FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
  438. {
  439. pFilePos->QuadPart = lLast.QuadPart;
  440. } else
  441. {
  442. fReturn = FALSE;
  443. }
  444. }
  445. }
  446. } else {
  447. IIS_PRINTF((buff,"GetFilePosition failed with %d\n",
  448. GetLastError()));
  449. }
  450. return fReturn;
  451. }
  452. BOOL
  453. ILOG_FILE::CloseFile(VOID)
  454. /*++
  455. This function closes the open file. It flushes out file data
  456. before closing the file.
  457. This function should be called after locking this object
  458. Arguments:
  459. None
  460. Returns:
  461. TRUE on success and FALSE if there is any failure.
  462. --*/
  463. {
  464. DWORD dwRet;
  465. DestroyMapping( );
  466. if ( m_hFile != INVALID_HANDLE_VALUE) {
  467. //
  468. // set the pointer to the end of file
  469. //
  470. dwRet = SetFilePointer( m_hFile,
  471. m_qwFilePos.LowPart,
  472. (PLONG)(&m_qwFilePos.HighPart),
  473. FILE_BEGIN);
  474. if ( dwRet==FILE_SIZE_LOW_MAX && GetLastError()!=NO_ERROR )
  475. {
  476. IIS_PRINTF((buff,"SetFilePointer[Pos = %I64u] failed with %d\n",
  477. m_qwFilePos.QuadPart, GetLastError()));
  478. }
  479. SetEndOfFile( m_hFile );
  480. CloseHandle( m_hFile);
  481. m_hFile = INVALID_HANDLE_VALUE; // store the invalid handle
  482. }
  483. return (TRUE);
  484. } // ILOG_FILE::CloseFile()
  485. VOID
  486. ILOG_FILE::DestroyMapping(
  487. VOID
  488. )
  489. /*++
  490. This function closes the open file. It flushes out file data
  491. before closing the file.
  492. This function should be called after locking this object
  493. Arguments:
  494. None
  495. Returns:
  496. TRUE on success and FALSE if there is any failure.
  497. --*/
  498. {
  499. /* NKJ -- why do we need to flush?
  500. if ( m_hFile != INVALID_HANDLE_VALUE) {
  501. FlushFileBuffers( m_hFile);
  502. }
  503. */
  504. if ( m_pvBuffer != NULL ) {
  505. /* FlushViewOfFile( m_pvBuffer, 0 ); * NKJ */
  506. UnmapViewOfFile( m_pvBuffer );
  507. m_pvBuffer = NULL;
  508. }
  509. if (m_hMemFile!=NULL) {
  510. CloseHandle( m_hMemFile );
  511. m_hMemFile = NULL;
  512. }
  513. return;
  514. } // ILOG_FILE::DestroyMapping