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.

1283 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. filectl.cxx
  5. Abstract:
  6. OLE control to handle file logging object
  7. Author:
  8. Terence Kwan ( terryk ) 18-Sep-1996
  9. Project:
  10. IIS Logging 3.0
  11. --*/
  12. #include "precomp.hxx"
  13. #include "initguid.h"
  14. #include <ilogobj.hxx>
  15. #include "filectl.hxx"
  16. #include <issched.hxx>
  17. #include <atlimpl.cpp>
  18. #define LOG_FILE_SLOP 512
  19. //
  20. // tick minute.
  21. //
  22. #define TICK_MINUTE (60 * 1000)
  23. //************************************************************************************
  24. VOID
  25. LogWriteEvent(
  26. IN LPCSTR InstanceName,
  27. IN BOOL fResume
  28. );
  29. //
  30. // globals
  31. //
  32. LPEVENT_LOG g_eventLog = NULL;
  33. CLogFileCtrl::CLogFileCtrl(
  34. VOID
  35. )
  36. :
  37. m_fFirstLog ( TRUE),
  38. m_pLogFile ( NULL),
  39. m_fDiskFullShutdown ( FALSE),
  40. m_fUsingCustomHeaders ( FALSE),
  41. m_sequence ( 1),
  42. m_TickResumeOpen ( 0),
  43. m_strLogFileName ( ),
  44. m_dwSchedulerCookie ( 0),
  45. m_fInTerminate ( FALSE)
  46. /*++
  47. Routine Description:
  48. Contructor for the log file control
  49. Arguments:
  50. Return Value:
  51. --*/
  52. {
  53. //
  54. // initialize all the internal variable
  55. //
  56. ZeroMemory( &m_stCurrentFile, sizeof( m_stCurrentFile));
  57. INITIALIZE_CRITICAL_SECTION( &m_csLock );
  58. }
  59. //************************************************************************************
  60. // CLogFileCtrl::~CLogFileCtrl - Destructor
  61. CLogFileCtrl::~CLogFileCtrl()
  62. /*++
  63. Routine Description:
  64. destructor for the log file control
  65. Arguments:
  66. Return Value:
  67. --*/
  68. {
  69. TerminateLog();
  70. DeleteCriticalSection( &m_csLock );
  71. }
  72. //************************************************************************************
  73. STDMETHODIMP
  74. CLogFileCtrl::InitializeLog(
  75. LPCSTR szInstanceName,
  76. LPCSTR pszMetabasePath,
  77. CHAR* pvIMDCOM )
  78. /*++
  79. Routine Description:
  80. Initialize log
  81. Arguments:
  82. cbSize - size of the service name
  83. RegKey - service name
  84. dwInstanceOf - instance number
  85. Return Value:
  86. --*/
  87. {
  88. //
  89. // get the default parameters
  90. //
  91. m_strInstanceName.Copy(szInstanceName);
  92. m_strMetabasePath.Copy(pszMetabasePath);
  93. m_pvIMDCOM = (LPVOID)pvIMDCOM;
  94. //
  95. // get the registry value
  96. //
  97. (VOID)GetRegParameters(
  98. pszMetabasePath,
  99. pvIMDCOM );
  100. return 0;
  101. }
  102. //************************************************************************************
  103. STDMETHODIMP
  104. CLogFileCtrl::TerminateLog(
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. clean up the log
  110. Arguments:
  111. Return Value:
  112. --*/
  113. {
  114. Lock( );
  115. m_fInTerminate = TRUE;
  116. if ( m_pLogFile!=NULL) {
  117. m_pLogFile->CloseFile( );
  118. delete m_pLogFile;
  119. m_pLogFile = NULL;
  120. }
  121. if (m_dwSchedulerCookie)
  122. {
  123. RemoveWorkItem(m_dwSchedulerCookie);
  124. }
  125. m_dwSchedulerCookie = 0;
  126. m_fInTerminate = FALSE;
  127. Unlock( );
  128. return(TRUE);
  129. }
  130. //************************************************************************************
  131. STDMETHODIMP
  132. CLogFileCtrl::LogInformation(
  133. IInetLogInformation * ppvDataObj
  134. )
  135. /*++
  136. Routine Description:
  137. log information
  138. Arguments:
  139. ppvDataObj - COM Logging object
  140. Return Value:
  141. --*/
  142. {
  143. SYSTEMTIME stNow;
  144. CHAR tmpBuf[512];
  145. DWORD dwSize = sizeof(tmpBuf);
  146. PCHAR pBuf = tmpBuf;
  147. DWORD err;
  148. retry:
  149. err = NO_ERROR;
  150. if ( FormatLogBuffer(ppvDataObj,
  151. pBuf,
  152. &dwSize,
  153. &stNow // time is returned
  154. )
  155. )
  156. {
  157. WriteLogInformation(stNow, pBuf, dwSize, FALSE, FALSE);
  158. }
  159. else
  160. {
  161. err = GetLastError();
  162. IIS_PRINTF((buff,"FormatLogBuffer failed with %d\n",GetLastError()));
  163. if ( (err == ERROR_INSUFFICIENT_BUFFER) &&
  164. ( pBuf == tmpBuf ) &&
  165. (dwSize <= MAX_LOG_RECORD_LEN) )
  166. {
  167. pBuf = (PCHAR)LocalAlloc( 0, dwSize );
  168. if ( pBuf != NULL )
  169. {
  170. goto retry;
  171. }
  172. }
  173. }
  174. if ( (pBuf != tmpBuf) && (pBuf != NULL) )
  175. {
  176. LocalFree( pBuf );
  177. }
  178. return(0);
  179. } // LogInformation
  180. //************************************************************************************
  181. STDMETHODIMP
  182. CLogFileCtrl::GetConfig( DWORD, BYTE * log)
  183. /*++
  184. Routine Description:
  185. get configuration information
  186. Arguments:
  187. cbSize - size of the data structure
  188. log - log configuration data structure
  189. Return Value:
  190. --*/
  191. {
  192. InternalGetConfig( (PINETLOG_CONFIGURATIONA)log );
  193. return(0L);
  194. }
  195. //************************************************************************************
  196. STDMETHODIMP
  197. CLogFileCtrl::QueryExtraLoggingFields(
  198. IN PDWORD pcbSize,
  199. PCHAR pszFieldsList
  200. )
  201. /*++
  202. Routine Description:
  203. get configuration information
  204. Arguments:
  205. cbSize - size of the data structure
  206. log - log configuration data structure
  207. Return Value:
  208. --*/
  209. {
  210. InternalGetExtraLoggingFields( pcbSize, pszFieldsList );
  211. return(0L);
  212. }
  213. //************************************************************************************
  214. STDMETHODIMP
  215. CLogFileCtrl::LogCustomInformation(
  216. IN DWORD,
  217. IN PCUSTOM_LOG_DATA,
  218. IN LPSTR
  219. )
  220. {
  221. return(0L);
  222. }
  223. //************************************************************************************
  224. void
  225. CLogFileCtrl::InternalGetExtraLoggingFields(
  226. PDWORD pcbSize,
  227. TCHAR *pszFieldsList
  228. )
  229. {
  230. pszFieldsList[0]=_T('\0');
  231. pszFieldsList[1]=_T('\0');
  232. *pcbSize = 2;
  233. }
  234. //************************************************************************************
  235. VOID
  236. CLogFileCtrl::InternalGetConfig(
  237. IN PINETLOG_CONFIGURATIONA pLogConfig
  238. )
  239. /*++
  240. Routine Description:
  241. internal; get configuration information function.
  242. Arguments:
  243. log - log configuration data structure
  244. Return Value:
  245. --*/
  246. {
  247. pLogConfig->inetLogType = INET_LOG_TO_FILE;
  248. strcpy(
  249. pLogConfig->u.logFile.rgchLogFileDirectory,
  250. QueryLogFileDirectory()
  251. );
  252. pLogConfig->u.logFile.cbSizeForTruncation = QuerySizeForTruncation();
  253. pLogConfig->u.logFile.ilPeriod = QueryPeriod();
  254. pLogConfig->u.logFile.ilFormat = QueryLogFormat();
  255. }
  256. //************************************************************************************
  257. STDMETHODIMP
  258. CLogFileCtrl::SetConfig(
  259. DWORD,
  260. BYTE * log
  261. )
  262. /*++
  263. Routine Description:
  264. set the log configuration information
  265. Arguments:
  266. cbSize - size of the configuration data structure
  267. log - log information
  268. Return Value:
  269. --*/
  270. {
  271. //
  272. // write the configuration information to the registry
  273. //
  274. PINETLOG_CONFIGURATIONA pLogConfig = (PINETLOG_CONFIGURATIONA)log;
  275. SetSizeForTruncation( pLogConfig->u.logFile.cbSizeForTruncation );
  276. SetPeriod( pLogConfig->u.logFile.ilPeriod );
  277. SetLogFileDirectory( pLogConfig->u.logFile.rgchLogFileDirectory );
  278. return(0L);
  279. } // CLogFileCtrl::SetConfig
  280. //************************************************************************************
  281. DWORD
  282. CLogFileCtrl::GetRegParameters(
  283. IN LPCSTR pszRegKey,
  284. IN LPVOID
  285. )
  286. /*++
  287. Routine Description:
  288. get the registry value
  289. Arguments:
  290. strRegKey - registry key
  291. Return Value:
  292. --*/
  293. {
  294. DWORD err = NO_ERROR;
  295. MB mb( (IMDCOM*) m_pvIMDCOM );
  296. DWORD dwSize;
  297. CHAR szTmp[MAX_PATH+1];
  298. DWORD cbTmp = sizeof(szTmp);
  299. CHAR buf[MAX_PATH+1];
  300. DWORD dwPeriod;
  301. if ( !mb.Open("") ) {
  302. err = GetLastError();
  303. return(err);
  304. }
  305. //
  306. // Get log file period
  307. //
  308. if ( mb.GetDword(
  309. pszRegKey,
  310. MD_LOGFILE_PERIOD,
  311. IIS_MD_UT_SERVER,
  312. &dwPeriod ) )
  313. {
  314. //
  315. // Make sure it is within bounds
  316. //
  317. if ( dwPeriod > INET_LOG_PERIOD_HOURLY )
  318. {
  319. IIS_PRINTF((buff,"Invalid log period %d, set to %d\n",
  320. dwPeriod, DEFAULT_LOG_FILE_PERIOD));
  321. dwPeriod = DEFAULT_LOG_FILE_PERIOD;
  322. }
  323. }
  324. else
  325. {
  326. dwPeriod = DEFAULT_LOG_FILE_PERIOD;
  327. }
  328. SetPeriod( dwPeriod );
  329. //
  330. // Get truncate size
  331. //
  332. if ( dwPeriod == INET_LOG_PERIOD_NONE )
  333. {
  334. SetSizeForTruncation ( DEFAULT_LOG_FILE_TRUNCATE_SIZE );
  335. if ( mb.GetDword( pszRegKey,
  336. MD_LOGFILE_TRUNCATE_SIZE,
  337. IIS_MD_UT_SERVER,
  338. &dwSize ) )
  339. {
  340. if ( dwSize < MIN_FILE_TRUNCATION_SIZE )
  341. {
  342. dwSize = MIN_FILE_TRUNCATION_SIZE;
  343. IIS_PRINTF((buff,
  344. "Setting truncation size to %d\n", dwSize));
  345. }
  346. SetSizeForTruncation( dwSize );
  347. }
  348. }
  349. else
  350. {
  351. SetSizeForTruncation( NO_FILE_TRUNCATION );
  352. }
  353. //
  354. // Get directory
  355. //
  356. if ( !mb.GetExpandString(
  357. pszRegKey,
  358. MD_LOGFILE_DIRECTORY,
  359. IIS_MD_UT_SERVER,
  360. szTmp,
  361. &cbTmp ) )
  362. {
  363. lstrcpy(szTmp,
  364. DEFAULT_LOG_FILE_DIRECTORY_NT );
  365. }
  366. mb.Close();
  367. ExpandEnvironmentStrings( szTmp, buf, MAX_PATH+1 );
  368. SetLogFileDirectory( buf );
  369. return(err);
  370. } // CLogFileCtrl::GetRegParameters
  371. //************************************************************************************
  372. BOOL
  373. CLogFileCtrl::OpenLogFile(
  374. IN PSYSTEMTIME pst
  375. )
  376. /*++
  377. Routine Description:
  378. internal routine to open file.
  379. Arguments:
  380. Return Value:
  381. --*/
  382. {
  383. BOOL fReturn = TRUE;
  384. BOOL bRet = FALSE;
  385. HANDLE hToken = NULL;
  386. DWORD dwError = NO_ERROR;
  387. CHAR rgchPath[ MAX_PATH + 1 + 32];
  388. if ( m_pLogFile != NULL) {
  389. //
  390. // already a log file is open. return silently
  391. //
  392. IIS_PRINTF( ( buff,
  393. " Log File %s is already open ( %p)\n",
  394. m_strLogFileName.QueryStr(), m_pLogFile));
  395. } else {
  396. //
  397. // If this the first time we opened, get the file name
  398. //
  399. if ( m_fFirstLog || (QueryPeriod() != INET_LOG_PERIOD_NONE) ) {
  400. m_fFirstLog = FALSE;
  401. FormNewLogFileName( pst );
  402. }
  403. //
  404. // Append log file name to path to form the path of file to be opened.
  405. //
  406. if ( (m_strLogFileName.QueryCCH() +
  407. m_strLogFileDirectory.QueryCCH() >= MAX_PATH) ||
  408. (m_strLogFileDirectory.QueryCCH() < 3) ) {
  409. fReturn = FALSE;
  410. if ( (g_eventLog != NULL) && !m_fDiskFullShutdown) {
  411. const CHAR* tmpString[1];
  412. tmpString[0] = rgchPath;
  413. g_eventLog->LogEvent(
  414. LOG_EVENT_CREATE_DIR_ERROR,
  415. 1,
  416. tmpString,
  417. ERROR_BAD_PATHNAME );
  418. }
  419. SetLastError( ERROR_BAD_PATHNAME );
  420. goto exit;
  421. }
  422. lstrcpy( rgchPath, QueryLogFileDirectory());
  423. // if ( rgchPath[strlen(rgchPath)-1] != '\\' ) {
  424. if ( *CharPrev(rgchPath, rgchPath + strlen(rgchPath)) != '\\' ) {
  425. lstrcat( rgchPath, "\\");
  426. }
  427. lstrcat( rgchPath, QueryInstanceName() );
  428. //
  429. // There is a small chance that this function could be called (indirectly)
  430. // from an INPROC ISAPI completion thread (HSE_REQ_DONE). In this case
  431. // the thread token is the impersonated user and may not have permissions
  432. // to open the log file (especially if the user is the IUSR_ account).
  433. // To be paranoid, let's revert to LOCAL_SYSTEM anyways before opening.
  434. //
  435. if ( OpenThreadToken( GetCurrentThread(),
  436. TOKEN_ALL_ACCESS,
  437. FALSE,
  438. &hToken ) )
  439. {
  440. DBG_ASSERT( hToken != NULL );
  441. RevertToSelf();
  442. }
  443. // Allow logging to mapped drives
  444. bRet = IISCreateDirectory( rgchPath, TRUE );
  445. dwError = GetLastError();
  446. if ( hToken != NULL )
  447. {
  448. SetThreadToken( NULL, hToken );
  449. SetLastError( dwError );
  450. }
  451. if ( !bRet ) {
  452. if ( (g_eventLog != NULL) && !m_fDiskFullShutdown) {
  453. const CHAR* tmpString[1];
  454. tmpString[0] = rgchPath;
  455. g_eventLog->LogEvent(
  456. LOG_EVENT_CREATE_DIR_ERROR,
  457. 1,
  458. tmpString,
  459. GetLastError()
  460. );
  461. }
  462. IIS_PRINTF((buff,"IISCreateDir[%s] error %d\n",
  463. rgchPath, GetLastError()));
  464. fReturn = FALSE;
  465. goto exit;
  466. }
  467. lstrcat( rgchPath, "\\");
  468. lstrcat( rgchPath, m_strLogFileName.QueryStr());
  469. m_pLogFile = new ILOG_FILE( );
  470. if (m_pLogFile != NULL) {
  471. if ( m_pLogFile->Open(
  472. rgchPath,
  473. QuerySizeForTruncation(),
  474. !m_fDiskFullShutdown
  475. ) ) {
  476. m_pLogFile->QueryFileSize(&m_cbTotalWritten);
  477. } else {
  478. delete m_pLogFile;
  479. m_pLogFile = NULL;
  480. fReturn = FALSE;
  481. }
  482. } else {
  483. IIS_PRINTF((buff,"Unable to allocate ILOG_FILE[err %d]\n",
  484. GetLastError()));
  485. fReturn = FALSE;
  486. }
  487. }
  488. exit:
  489. return ( fReturn);
  490. } // CLogFileCtrl::OpenLogFile
  491. //************************************************************************************
  492. BOOL
  493. CLogFileCtrl::WriteLogDirectives(
  494. IN DWORD Sludge
  495. )
  496. /*++
  497. Routine Description:
  498. virtual function for the sub class to log directives to the file.
  499. Arguments:
  500. Sludge - number of additional bytes that needs to be written
  501. together with the directives
  502. Return Value:
  503. TRUE, ok
  504. FALSE, not enough space to write.
  505. --*/
  506. {
  507. //
  508. // if we will overflow, open another file
  509. //
  510. if ( IsFileOverFlowForCB( Sludge ) ) {
  511. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  512. DBGPRINTF((DBG_CONTEXT,
  513. "Unable to write directive\n"));
  514. return(FALSE);
  515. }
  516. return TRUE;
  517. } // CLogFileCtrl::WriteLogDirectives
  518. //************************************************************************************
  519. BOOL
  520. CLogFileCtrl::WriteCustomLogDirectives(
  521. IN DWORD
  522. )
  523. {
  524. return TRUE;
  525. }
  526. //************************************************************************************
  527. VOID
  528. CLogFileCtrl::I_FormNewLogFileName(
  529. IN LPSYSTEMTIME pstNow,
  530. IN LPCSTR LogNamePrefix
  531. )
  532. {
  533. CHAR tmpBuf[MAX_PATH+1];
  534. WORD wYear = ( pstNow->wYear % 100); // retain just last 2 digits.
  535. switch ( QueryPeriod( ) ) {
  536. case INET_LOG_PERIOD_HOURLY:
  537. wsprintf( tmpBuf, "%.2s%02.2u%02u%02u%02u.%s",
  538. LogNamePrefix,
  539. wYear,
  540. pstNow->wMonth,
  541. pstNow->wDay,
  542. pstNow->wHour,
  543. DEFAULT_LOG_FILE_EXTENSION);
  544. break;
  545. case INET_LOG_PERIOD_DAILY:
  546. wsprintf( tmpBuf, "%.2s%02.2u%02u%02u.%s",
  547. LogNamePrefix,
  548. wYear,
  549. pstNow->wMonth,
  550. pstNow->wDay,
  551. DEFAULT_LOG_FILE_EXTENSION);
  552. break;
  553. case INET_LOG_PERIOD_WEEKLY:
  554. wsprintf( tmpBuf, "%.2s%02.2u%02u%02u.%s",
  555. LogNamePrefix,
  556. wYear,
  557. pstNow->wMonth,
  558. WeekOfMonth(pstNow),
  559. DEFAULT_LOG_FILE_EXTENSION);
  560. break;
  561. case INET_LOG_PERIOD_MONTHLY:
  562. wsprintf( tmpBuf, "%.2s%02u%02u.%s",
  563. LogNamePrefix,
  564. wYear,
  565. pstNow->wMonth,
  566. DEFAULT_LOG_FILE_EXTENSION);
  567. break;
  568. case INET_LOG_PERIOD_NONE:
  569. default:
  570. wsprintf(tmpBuf, "%.6s%u.%s",
  571. LogNamePrefix,
  572. m_sequence,
  573. DEFAULT_LOG_FILE_EXTENSION);
  574. m_sequence++;
  575. break;
  576. } // switch()
  577. m_strLogFileName.Copy(tmpBuf);
  578. return;
  579. }
  580. //************************************************************************************
  581. VOID
  582. CLogFileCtrl::SetLogFileDirectory(
  583. IN LPCSTR pszDir
  584. )
  585. {
  586. STR tmpStr;
  587. HANDLE hFile;
  588. WIN32_FIND_DATA findData;
  589. DWORD maxFileSize = 0;
  590. m_strLogFileDirectory.Copy(pszDir);
  591. //
  592. // if period is not none, then return
  593. //
  594. if ( QueryPeriod() != INET_LOG_PERIOD_NONE ) {
  595. return;
  596. }
  597. //
  598. // Get the starting sequence number
  599. //
  600. m_sequence = 1;
  601. //
  602. // Append instance name and the pattern.
  603. // should look like c:\winnt\system32\logfiles\w3svc1\inetsv*.log
  604. //
  605. tmpStr.Copy(pszDir);
  606. // if ( pszDir[tmpStr.QueryCCH()-1] != '\\' ) {
  607. if ( *CharPrev(pszDir, pszDir + tmpStr.QueryCCH()) != '\\' ) {
  608. tmpStr.Append("\\");
  609. }
  610. tmpStr.Append( QueryInstanceName() );
  611. tmpStr.Append( "\\" );
  612. tmpStr.Append( QueryNoPeriodPattern() );
  613. hFile = FindFirstFile( tmpStr.QueryStr(), &findData );
  614. if ( hFile == INVALID_HANDLE_VALUE ) {
  615. return;
  616. }
  617. do {
  618. PCHAR ptr;
  619. DWORD sequence = 1;
  620. ptr = strchr(findData.cFileName, '.');
  621. if (ptr != NULL ) {
  622. *ptr = '\0';
  623. ptr = findData.cFileName;
  624. while ( *ptr != '\0' ) {
  625. if ( isdigit((UCHAR)(*ptr)) ) {
  626. sequence = atoi( ptr );
  627. break;
  628. }
  629. ptr++;
  630. }
  631. if ( sequence > m_sequence ) {
  632. maxFileSize = findData.nFileSizeLow;
  633. m_sequence = sequence;
  634. DBGPRINTF((DBG_CONTEXT,
  635. "Sequence start is %d[%d]\n", sequence, maxFileSize));
  636. }
  637. }
  638. } while ( FindNextFile( hFile, &findData ) );
  639. FindClose(hFile);
  640. if ( (maxFileSize+LOG_FILE_SLOP) > QuerySizeForTruncation() ) {
  641. m_sequence++;
  642. }
  643. return;
  644. } // SetLogFileDirectory
  645. //************************************************************************************
  646. VOID
  647. CLogFileCtrl::WriteLogInformation(
  648. IN SYSTEMTIME& stNow,
  649. IN PCHAR pBuf,
  650. IN DWORD dwSize,
  651. IN BOOL fCustom,
  652. IN BOOL fResetHeaders
  653. )
  654. /*++
  655. Routine Description:
  656. write log line to file
  657. Arguments:
  658. stNow Present Time
  659. fResetHeaders TRUE -> Reset headers, FALSE -> Don't reset headers
  660. pBuf Pointer to Log Line
  661. dwSize Number of characters in pBuf
  662. fCustom TRUE -> Using custom logging, FALSE -> normal logging
  663. Return Value:
  664. --*/
  665. {
  666. BOOL fOpenNewFile;
  667. DWORD err = NO_ERROR;
  668. DWORD tickCount = 0;
  669. Lock ( );
  670. if ( m_pLogFile != NULL )
  671. {
  672. if ( QueryPeriod() == INET_LOG_PERIOD_DAILY )
  673. {
  674. fOpenNewFile = (m_stCurrentFile.wDay != stNow.wDay) ||
  675. (m_stCurrentFile.wMonth != stNow.wMonth);
  676. }
  677. else
  678. {
  679. fOpenNewFile = IsBeginningOfNewPeriod( QueryPeriod(),
  680. &m_stCurrentFile,
  681. &stNow) ||
  682. IsFileOverFlowForCB( dwSize);
  683. //
  684. // Reset headers if day is over. Used for weekly or unlimited files.
  685. //
  686. if ( !fOpenNewFile && !fResetHeaders)
  687. {
  688. fResetHeaders = (m_stCurrentFile.wDay != stNow.wDay) ||
  689. (m_stCurrentFile.wMonth != stNow.wMonth);
  690. }
  691. }
  692. }
  693. else
  694. {
  695. fOpenNewFile = TRUE;
  696. }
  697. if (fOpenNewFile )
  698. {
  699. //
  700. // open a file only after every minute when we hit disk full
  701. //
  702. if ( m_TickResumeOpen != 0 )
  703. {
  704. tickCount = GetTickCount( );
  705. if ( (tickCount < m_TickResumeOpen) ||
  706. ((tickCount + TICK_MINUTE) < tickCount ) ) // The Tick counter is about to wrap.
  707. {
  708. goto exit_tick;
  709. }
  710. }
  711. retry_open:
  712. //
  713. // Close existing log
  714. //
  715. TerminateLog();
  716. //
  717. // Open new log file
  718. //
  719. if ( OpenLogFile( &stNow ) )
  720. {
  721. //
  722. // Schedule Callback for closing log file and set flag for writing directives.
  723. //
  724. ScheduleCallback(stNow);
  725. fResetHeaders = TRUE;
  726. }
  727. else
  728. {
  729. err = GetLastError();
  730. //
  731. // The file is already bigger than the truncate size
  732. // try another one.
  733. //
  734. if ( err == ERROR_INSUFFICIENT_BUFFER )
  735. {
  736. FormNewLogFileName( &stNow );
  737. err = NO_ERROR;
  738. goto retry_open;
  739. }
  740. goto exit;
  741. }
  742. }
  743. //
  744. // Reset Headers if needed
  745. //
  746. if ((fResetHeaders) || (fCustom != m_fUsingCustomHeaders))
  747. {
  748. BOOL fSucceeded;
  749. if (fCustom)
  750. {
  751. m_fUsingCustomHeaders = TRUE;
  752. fSucceeded = WriteCustomLogDirectives(dwSize);
  753. }
  754. else
  755. {
  756. m_fUsingCustomHeaders = FALSE;
  757. fSucceeded = WriteLogDirectives(dwSize);
  758. }
  759. if (!fSucceeded)
  760. {
  761. err = GetLastError( );
  762. if ( err == ERROR_INSUFFICIENT_BUFFER )
  763. {
  764. FormNewLogFileName( &stNow );
  765. err = NO_ERROR;
  766. goto retry_open;
  767. }
  768. TerminateLog();
  769. goto exit;
  770. }
  771. //
  772. // record the time of opening of this new file
  773. //
  774. m_stCurrentFile = stNow;
  775. }
  776. //
  777. // write it to the buffer
  778. //
  779. if ( m_pLogFile->Write(pBuf, dwSize) )
  780. {
  781. IncrementBytesWritten(dwSize);
  782. //
  783. // If this had been shutdown, log event for reactivation
  784. //
  785. if ( m_fDiskFullShutdown )
  786. {
  787. m_fDiskFullShutdown = FALSE;
  788. m_TickResumeOpen = 0;
  789. LogWriteEvent( QueryInstanceName(), TRUE );
  790. }
  791. }
  792. else
  793. {
  794. err = GetLastError();
  795. TerminateLog( );
  796. }
  797. exit:
  798. if ( err == ERROR_DISK_FULL )
  799. {
  800. if ( !m_fDiskFullShutdown )
  801. {
  802. m_fDiskFullShutdown = TRUE;
  803. LogWriteEvent( QueryInstanceName(), FALSE );
  804. }
  805. m_TickResumeOpen = GetTickCount();
  806. m_TickResumeOpen += TICK_MINUTE;
  807. }
  808. exit_tick:
  809. Unlock( );
  810. } // LogInformation
  811. //************************************************************************************
  812. DWORD
  813. CLogFileCtrl::ScheduleCallback(SYSTEMTIME& stNow)
  814. {
  815. DWORD dwTimeRemaining = 0;
  816. switch (m_dwPeriod)
  817. {
  818. case INET_LOG_PERIOD_HOURLY:
  819. dwTimeRemaining = 60*60 -
  820. (stNow.wMinute*60 +
  821. stNow.wSecond);
  822. break;
  823. case INET_LOG_PERIOD_DAILY:
  824. dwTimeRemaining = 24*60*60 -
  825. (stNow.wHour*60*60 +
  826. stNow.wMinute*60 +
  827. stNow.wSecond);
  828. break;
  829. case INET_LOG_PERIOD_WEEKLY:
  830. dwTimeRemaining = 7*24*60*60 -
  831. (stNow.wDayOfWeek*24*60*60 +
  832. stNow.wHour*60*60 +
  833. stNow.wMinute*60 +
  834. stNow.wSecond);
  835. break;
  836. case INET_LOG_PERIOD_MONTHLY:
  837. DWORD dwNumDays = 31;
  838. if ( (4 == stNow.wMonth) || // April
  839. (6 == stNow.wMonth) || // June
  840. (9 == stNow.wMonth) || // September
  841. (11 == stNow.wMonth) // November
  842. )
  843. {
  844. dwNumDays = 30;
  845. }
  846. if (2 == stNow.wMonth) // February
  847. {
  848. if ((stNow.wYear % 4 == 0 && stNow.wYear % 100 != 0) || stNow.wYear % 400 == 0)
  849. {
  850. //
  851. // leap year.
  852. //
  853. dwNumDays = 29;
  854. }
  855. else
  856. {
  857. dwNumDays = 28;
  858. }
  859. }
  860. dwTimeRemaining = dwNumDays*24*60*60 -
  861. (stNow.wDay*24*60*60 +
  862. stNow.wHour*60*60 +
  863. stNow.wMinute*60 +
  864. stNow.wSecond);
  865. break;
  866. }
  867. //
  868. // Convert remaining time to millisecs
  869. //
  870. dwTimeRemaining = dwTimeRemaining*1000 - stNow.wMilliseconds;
  871. if (dwTimeRemaining)
  872. {
  873. m_dwSchedulerCookie = ScheduleWorkItem(
  874. LoggingSchedulerCallback,
  875. this,
  876. dwTimeRemaining,
  877. FALSE);
  878. }
  879. return(m_dwSchedulerCookie);
  880. }
  881. //************************************************************************************
  882. CHAR * SkipWhite( CHAR * pch )
  883. {
  884. while ( ISWHITEA( *pch ) )
  885. {
  886. pch++;
  887. }
  888. return pch;
  889. }
  890. //************************************************************************************
  891. DWORD
  892. FastDwToA(
  893. CHAR* pBuf,
  894. DWORD dwV
  895. )
  896. /*++
  897. Routine Description:
  898. Convert DWORD to ascii (decimal )
  899. returns length ( w/o trailing '\0' )
  900. Arguments:
  901. pBuf - buffer where to store converted value
  902. dwV - value to convert
  903. Return Value:
  904. length of ascii string
  905. --*/
  906. {
  907. DWORD v;
  908. if ( dwV < 10 ) {
  909. pBuf[0] = (CHAR)('0'+dwV);
  910. pBuf[1] = '\0';
  911. return 1;
  912. } else if ( dwV < 100 ) {
  913. pBuf[0] = (CHAR)((dwV/10) + '0');
  914. pBuf[1] = (CHAR)((dwV%10) + '0');
  915. pBuf[2] = '\0';
  916. return 2;
  917. } else if ( dwV < 1000 ) {
  918. pBuf[0] = (CHAR)((v=dwV/100) + '0');
  919. dwV -= v * 100;
  920. pBuf[1] = (CHAR)((dwV/10) + '0');
  921. pBuf[2] = (CHAR)((dwV%10) + '0');
  922. pBuf[3] = '\0';
  923. return 3;
  924. } else if ( dwV < 10000 ) {
  925. pBuf[0] = (CHAR)((v=dwV/1000) + '0');
  926. dwV -= v * 1000;
  927. pBuf[1] = (CHAR)((v=dwV/100) + '0');
  928. dwV -= v * 100;
  929. pBuf[2] = (CHAR)((dwV/10) + '0');
  930. pBuf[3] = (CHAR)((dwV%10) + '0');
  931. pBuf[4] = '\0';
  932. return 4;
  933. }
  934. _ultoa(dwV, pBuf, 10);
  935. return (DWORD)strlen(pBuf);
  936. } // FastDwToA
  937. //************************************************************************************
  938. VOID
  939. LogWriteEvent(
  940. IN LPCSTR InstanceName,
  941. IN BOOL fResume
  942. )
  943. {
  944. if ( g_eventLog != NULL ) {
  945. const CHAR* tmpString[1];
  946. tmpString[0] = InstanceName;
  947. g_eventLog->LogEvent(
  948. fResume ?
  949. LOG_EVENT_RESUME_LOGGING :
  950. LOG_EVENT_DISK_FULL_SHUTDOWN,
  951. 1,
  952. tmpString,
  953. 0);
  954. }
  955. return;
  956. } // LogWriteEvent
  957. //************************************************************************************
  958. VOID WINAPI LoggingSchedulerCallback( PVOID pContext)
  959. {
  960. CLogFileCtrl *pLog = (CLogFileCtrl *) pContext;
  961. //
  962. // There is a possibility of deadlock if another thread is inside TerminateLog
  963. // stuck in RemoveWorkItem, waiting for this callback thread to complete. To
  964. // prevent that we use the synchronization flag - m_fInTerminate.
  965. //
  966. pLog->m_dwSchedulerCookie = 0;
  967. if (!pLog->m_fInTerminate)
  968. {
  969. pLog->TerminateLog();
  970. }
  971. }
  972. //************************************************************************************