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.

981 lines
29 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. omlog.c
  5. Abstract:
  6. logging routines for the object log stream
  7. this code was jumpstarted from the clusrtl logging code. Most notably, it
  8. is UTF-8 encoded which allows full Unicode without the cost of writing
  9. 16b. for each character.
  10. remaining issues to solve: proper truncation of log file based on current
  11. starting session. We'd like to remember as many sessions as possible but
  12. since I've chosen UTF-8, I can't jump to the middle of the file and start
  13. looking around. One possibility strategy is using an alternate NTFS stream
  14. to record the starting offsets of sessions. If that stream didn't exist or
  15. we're on a FAT FS, then we'll continue with the current strategy.
  16. Author:
  17. Charlie Wickham (charlwi) 07-May-2001
  18. Environment:
  19. User Mode
  20. Revision History:
  21. --*/
  22. #include "omp.h"
  23. //
  24. // when this sequence is at the beginning of the file, it indicates that the
  25. // file is UTF8 encoded
  26. //
  27. #define UTF8_BOM "\x0EF\x0BB\x0BF"
  28. //
  29. // Private Data
  30. //
  31. DWORD OmpLogFileLimit;
  32. DWORD OmpCurrentSessionStart;
  33. BOOL OmpLogToFile = FALSE;
  34. HANDLE OmpLogFileHandle = NULL;
  35. DWORD OmpProcessId;
  36. DWORD OmpCurrentSessionOffset;
  37. PCLRTL_WORK_QUEUE OmpLoggerWorkQueue;
  38. //
  39. // structure used to pass formatted buffers to work queue routine
  40. //
  41. typedef struct _OM_LOG_BUFFER_DESC {
  42. DWORD TimeBytes;
  43. DWORD MsgBytes;
  44. PCHAR TimeBuffer;
  45. PCHAR MsgBuffer;
  46. } OM_LOG_BUFFER_DESC, *POM_LOG_BUFFER_DESC;
  47. #define MAX_NUMBER_LENGTH 20
  48. // Specify maximum file size ( DWORD / 1MB )
  49. #define MAX_FILE_SIZE ( 0xFFFFF000 / ( 1024 * 1024 ) )
  50. DWORD OmpLogFileLimit = ( 1 * 1024 * 1024 ); // 1 MB default
  51. DWORD OmpLogFileLoWater = 0;
  52. //
  53. // internal functions
  54. //
  55. DWORD
  56. OmpTruncateFile(
  57. IN HANDLE FileHandle,
  58. IN DWORD FileSize,
  59. IN LPDWORD LastPosition
  60. )
  61. /*++
  62. Routine Description:
  63. Truncate a file by copying the portion starting at LastPosition and ending
  64. at EOF to the front of the file and setting the file's EOF pointer to the
  65. end of the new chunk. We always keep the current session even that means
  66. growing larger than the file limit.
  67. For now, we have no good way of finding all the sessions within the file,
  68. so if the file must be truncated, we whack it back to the beginning of the
  69. current session. If time permits, I'll add something more intelligent
  70. later on.
  71. Arguments:
  72. FileHandle - File handle.
  73. FileSize - Current End of File.
  74. LastPosition - On input, specifies the starting position in the file from
  75. which the copy begins. On output, it is set to the new EOF
  76. Return Value:
  77. New end of file.
  78. --*/
  79. {
  80. //
  81. // The following buffer size should never be more than 1/4 the size of the
  82. // file.
  83. //
  84. #define BUFFER_SIZE ( 64 * 1024 )
  85. DWORD bytesLeft;
  86. DWORD endPosition = sizeof( UTF8_BOM ) - 1;
  87. DWORD bufferSize;
  88. DWORD bytesRead;
  89. DWORD bytesWritten;
  90. DWORD fileSizeHigh = 0;
  91. DWORD readPosition;
  92. DWORD writePosition;
  93. PVOID dataBuffer;
  94. //
  95. // current session is already at beginning of file so bale now...
  96. //
  97. if ( OmpCurrentSessionOffset == sizeof( UTF8_BOM ) - 1) {
  98. return FileSize;
  99. }
  100. //
  101. // don't truncate the current session, i.e., always copy from the start of
  102. // the current session
  103. //
  104. if ( *LastPosition > OmpCurrentSessionOffset ) {
  105. *LastPosition = OmpCurrentSessionOffset;
  106. }
  107. if ( *LastPosition > FileSize ) {
  108. //
  109. // something's confused; the spot we're supposed to copy from is at or
  110. // past the current EOF. reset the entire file
  111. //
  112. goto error_exit;
  113. }
  114. dataBuffer = LocalAlloc( LMEM_FIXED, BUFFER_SIZE );
  115. if ( !dataBuffer ) {
  116. goto error_exit;
  117. }
  118. //
  119. // calc number of bytes to move
  120. //
  121. bytesLeft = FileSize - *LastPosition;
  122. endPosition = bytesLeft + sizeof( UTF8_BOM ) - 1;
  123. //
  124. // Point back to last position for reading.
  125. //
  126. readPosition = *LastPosition;
  127. writePosition = sizeof( UTF8_BOM ) - 1;
  128. while ( bytesLeft ) {
  129. if ( bytesLeft >= BUFFER_SIZE ) {
  130. bufferSize = BUFFER_SIZE;
  131. } else {
  132. bufferSize = bytesLeft;
  133. }
  134. bytesLeft -= bufferSize;
  135. SetFilePointer( FileHandle,
  136. readPosition,
  137. &fileSizeHigh,
  138. FILE_BEGIN );
  139. if ( ReadFile( FileHandle,
  140. dataBuffer,
  141. bufferSize,
  142. &bytesRead,
  143. NULL ) )
  144. {
  145. SetFilePointer( FileHandle,
  146. writePosition,
  147. &fileSizeHigh,
  148. FILE_BEGIN );
  149. WriteFile( FileHandle,
  150. dataBuffer,
  151. bytesRead,
  152. &bytesWritten,
  153. NULL );
  154. } else {
  155. endPosition = sizeof( UTF8_BOM ) - 1;
  156. break;
  157. }
  158. readPosition += bytesRead;
  159. writePosition += bytesWritten;
  160. }
  161. LocalFree( dataBuffer );
  162. //
  163. // for now, we only only one truncate by setting the current position to
  164. // the beginning of file.
  165. //
  166. OmpCurrentSessionOffset = sizeof( UTF8_BOM ) - 1;
  167. error_exit:
  168. //
  169. // Force end of file to get set.
  170. //
  171. SetFilePointer( FileHandle,
  172. endPosition,
  173. &fileSizeHigh,
  174. FILE_BEGIN );
  175. SetEndOfFile( FileHandle );
  176. *LastPosition = endPosition;
  177. return(endPosition);
  178. } // OmpTruncateFile
  179. VOID
  180. OmpLoggerWorkThread(
  181. IN PCLRTL_WORK_ITEM WorkItem,
  182. IN DWORD Status,
  183. IN DWORD BytesTransferred,
  184. IN ULONG_PTR IoContext
  185. )
  186. /*++
  187. Routine Description:
  188. work queue worker routine. actually does the write to the file.
  189. Arguments:
  190. standard ClRtl thread args; we only care about WorkItem
  191. Return Value:
  192. None
  193. --*/
  194. {
  195. DWORD fileSize;
  196. DWORD fileSizeHigh;
  197. DWORD tsBytesWritten;
  198. DWORD msgBytesWritten;
  199. POM_LOG_BUFFER_DESC bufDesc = (POM_LOG_BUFFER_DESC)(WorkItem->Context);
  200. fileSize = GetFileSize( OmpLogFileHandle, &fileSizeHigh );
  201. ASSERT( fileSizeHigh == 0 ); // We're only using DWORDs!
  202. if ( fileSize > OmpLogFileLimit ) {
  203. fileSize = OmpTruncateFile( OmpLogFileHandle, fileSize, &OmpLogFileLoWater );
  204. }
  205. SetFilePointer( OmpLogFileHandle,
  206. fileSize,
  207. &fileSizeHigh,
  208. FILE_BEGIN );
  209. WriteFile(OmpLogFileHandle,
  210. bufDesc->TimeBuffer,
  211. bufDesc->TimeBytes,
  212. &tsBytesWritten,
  213. NULL);
  214. WriteFile(OmpLogFileHandle,
  215. bufDesc->MsgBuffer,
  216. bufDesc->MsgBytes,
  217. &msgBytesWritten,
  218. NULL);
  219. //
  220. // if we haven't set the lo water mark, wait until the file size has
  221. // crossed the halfway mark and set it to the beginning of the line we
  222. // just wrote.
  223. //
  224. if ( OmpLogFileLoWater == 0 && (fileSize > (OmpLogFileLimit / 2)) ) {
  225. OmpLogFileLoWater = fileSize;
  226. ASSERT( OmpLogFileLoWater >= OmpCurrentSessionOffset );
  227. }
  228. } // OmpLoggerWorkThread
  229. VOID
  230. OmpLogPrint(
  231. LPWSTR FormatString,
  232. ...
  233. )
  234. /*++
  235. Routine Description:
  236. Prints a message to the object config log file.
  237. Arguments:
  238. FormatString - The initial message string to print.
  239. Any FormatMessage-compatible arguments to be inserted in the message
  240. before it is logged.
  241. Return Value:
  242. None.
  243. --*/
  244. {
  245. PWCHAR unicodeOutput = NULL;
  246. PCHAR timestampBuffer;
  247. DWORD timestampBytes;
  248. PCHAR utf8Buffer;
  249. DWORD utf8Bytes;
  250. PWCHAR unicodeBuffer;
  251. DWORD unicodeBytes;
  252. DWORD status = ERROR_SUCCESS;
  253. SYSTEMTIME Time;
  254. ULONG_PTR ArgArray[9];
  255. va_list ArgList;
  256. //
  257. // init the variable arg list
  258. //
  259. va_start(ArgList, FormatString);
  260. if ( !OmpLogToFile ) {
  261. va_end(ArgList);
  262. return;
  263. }
  264. GetSystemTime(&Time);
  265. ArgArray[0] = OmpProcessId;
  266. ArgArray[1] = GetCurrentThreadId();
  267. ArgArray[2] = Time.wYear;
  268. ArgArray[3] = Time.wMonth;
  269. ArgArray[4] = Time.wDay;
  270. ArgArray[5] = Time.wHour;
  271. ArgArray[6] = Time.wMinute;
  272. ArgArray[7] = Time.wSecond;
  273. ArgArray[8] = Time.wMilliseconds;
  274. //
  275. // we can get away with formatting it as ANSI since our data is all numbers
  276. //
  277. timestampBytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
  278. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  279. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  280. "%1!08lx!.%2!08lx!::%3!02d!/%4!02d!/%5!02d!-%6!02d!:%7!02d!:%8!02d!.%9!03d! ",
  281. 0,
  282. 0,
  283. (LPSTR)&timestampBuffer,
  284. 50,
  285. (va_list*)ArgArray);
  286. if ( timestampBytes == 0 ) {
  287. va_end(ArgList);
  288. // WmiTrace("Prefix format failed, %d: %!ARSTR!", GetLastError(), FormatString);
  289. return;
  290. }
  291. //
  292. // format the message in unicode
  293. //
  294. try {
  295. unicodeBytes = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  296. | FORMAT_MESSAGE_FROM_STRING,
  297. FormatString,
  298. 0,
  299. 0,
  300. (LPWSTR)&unicodeOutput,
  301. 512,
  302. &ArgList);
  303. }
  304. except ( EXCEPTION_EXECUTE_HANDLER ) {
  305. unicodeBytes = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  306. | FORMAT_MESSAGE_FROM_STRING
  307. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  308. L"LOGERROR(exception): Could not print message: %1!ws!",
  309. 0,
  310. 0,
  311. (LPWSTR)&unicodeOutput,
  312. 512,
  313. (va_list *) &FormatString );
  314. }
  315. va_end(ArgList);
  316. if (unicodeBytes != 0) {
  317. PCLRTL_WORK_ITEM workQItem;
  318. //
  319. // convert the output to UTF-8; first get the size to see if it will
  320. // fit in our stack buffer.
  321. //
  322. utf8Bytes = WideCharToMultiByte(CP_UTF8,
  323. 0, // dwFlags
  324. unicodeOutput,
  325. unicodeBytes,
  326. NULL,
  327. 0,
  328. NULL, // lpDefaultChar
  329. NULL); // lpUsedDefaultChar
  330. utf8Buffer = LocalAlloc( LMEM_FIXED, utf8Bytes );
  331. if ( utf8Buffer == NULL ) {
  332. status = ERROR_NOT_ENOUGH_MEMORY;
  333. goto error_exit;
  334. }
  335. utf8Bytes = WideCharToMultiByte(CP_UTF8,
  336. 0, // dwFlags
  337. unicodeOutput,
  338. unicodeBytes,
  339. utf8Buffer,
  340. utf8Bytes,
  341. NULL, // lpDefaultChar
  342. NULL); // lpUsedDefaultChar
  343. workQItem = (PCLRTL_WORK_ITEM)LocalAlloc(LMEM_FIXED,
  344. sizeof( CLRTL_WORK_ITEM ) + sizeof( OM_LOG_BUFFER_DESC ));
  345. if ( workQItem != NULL ) {
  346. POM_LOG_BUFFER_DESC bufDesc = (POM_LOG_BUFFER_DESC)(workQItem + 1);
  347. bufDesc->TimeBytes = timestampBytes;
  348. bufDesc->TimeBuffer = timestampBuffer;
  349. bufDesc->MsgBytes = utf8Bytes;
  350. bufDesc->MsgBuffer = utf8Buffer;
  351. ClRtlInitializeWorkItem( workQItem, OmpLoggerWorkThread, bufDesc );
  352. status = ClRtlPostItemWorkQueue( OmpLoggerWorkQueue, workQItem, 0, 0 );
  353. } else {
  354. status = ERROR_NOT_ENOUGH_MEMORY;
  355. goto error_exit;
  356. }
  357. // WmiTrace("%!level! %!ARSTR!", *(UCHAR*)&LogLevel, AnsiString.Buffer + timestampBytes);
  358. } else {
  359. // WmiTrace("Format returned 0 bytes: %!ARSTR!", FormatString);
  360. status = GetLastError();
  361. }
  362. error_exit:
  363. if ( unicodeOutput != NULL ) {
  364. LocalFree( unicodeOutput );
  365. }
  366. return;
  367. } // OmpLogPrint
  368. //
  369. // exported (within OM) functions
  370. //
  371. VOID
  372. OmpOpenObjectLog(
  373. VOID
  374. )
  375. /*++
  376. Routine Description:
  377. Use the clusterlog environment variable to open another file that contains
  378. object mgr name to ID mapping info. If the routine fails, the failure is
  379. logged in the cluster log but no logging will be done to the object log
  380. file.
  381. NOTE: access to the file is synchronized since this routine is assumed to
  382. be called only once by OmInit. Arguments:
  383. Arguments:
  384. None
  385. Return Value:
  386. None
  387. --*/
  388. {
  389. WCHAR logFileBuffer[MAX_PATH];
  390. LPWSTR logFileName = NULL;
  391. WCHAR objectLogExtension[] = L".oml";
  392. DWORD status = ERROR_SUCCESS;
  393. DWORD defaultLogSize = 1; // in MB
  394. DWORD envLength;
  395. DWORD logFileNameChars;
  396. WCHAR logFileSize[MAX_NUMBER_LENGTH];
  397. DWORD logSize;
  398. LPWSTR lpszBakFileName = NULL;
  399. DWORD fileSizeHigh = 0;
  400. DWORD fileSizeLow;
  401. DWORD bytesWritten;
  402. PWCHAR dot;
  403. UNICODE_STRING logFileString;
  404. SECURITY_ATTRIBUTES logFileSecurityAttr;
  405. PSECURITY_DESCRIPTOR logFileSecurityDesc;
  406. //
  407. // see if logging has been specified; get a buffer big enough that will
  408. // hold the object log name. If the supplied buffer to
  409. // GetEnvironmentVariable is too small, it will return a value that
  410. // includes the space for the trailing null, i.e., there is no need to add
  411. // one.
  412. //
  413. logFileNameChars = GetEnvironmentVariable(L"ClusterLog",
  414. logFileBuffer,
  415. RTL_NUMBER_OF( logFileBuffer ));
  416. if ( logFileNameChars > ( RTL_NUMBER_OF(logFileBuffer) + RTL_NUMBER_OF(objectLogExtension)) ) {
  417. //
  418. // allocate a larger buffer since our static one wasn't big enough
  419. //
  420. logFileName = LocalAlloc( LMEM_FIXED,
  421. (logFileNameChars + RTL_NUMBER_OF(objectLogExtension)) * sizeof( WCHAR ) );
  422. if ( logFileName == NULL ) {
  423. ClRtlLogPrint(LOG_UNUSUAL,
  424. "[OM] Unable to get memory for Object log filename buffer\n");
  425. return;
  426. }
  427. logFileNameChars = GetEnvironmentVariable(L"ClusterLog",
  428. logFileName,
  429. logFileNameChars);
  430. if ( logFileNameChars == 0 ) {
  431. ClRtlLogPrint(LOG_UNUSUAL,
  432. "[OM] Unable to read ClusterLog environment variable\n");
  433. goto error_exit;
  434. }
  435. } else if ( logFileNameChars != 0 ) {
  436. logFileName = logFileBuffer;
  437. }
  438. //
  439. // remove any trailing white space. go to the end of the string and scan
  440. // backwards; stop when we find the first non-white space char or we hit
  441. // the beginning of the buffer.
  442. //
  443. if ( logFileName != NULL ) {
  444. PWCHAR p = logFileName + logFileNameChars - 1;
  445. while ( iswspace( *p )) {
  446. *p = UNICODE_NULL;
  447. if ( p == logFileName ) {
  448. break;
  449. }
  450. --p;
  451. }
  452. //
  453. // make sure something useful is left
  454. //
  455. if ( wcslen( logFileName ) == 0 ) {
  456. if ( logFileName != logFileBuffer ) {
  457. LocalFree( logFileName );
  458. }
  459. logFileName = NULL;
  460. }
  461. }
  462. if ( logFileName == NULL ) {
  463. //
  464. // logging is turned off or we can't determine where to put the file.
  465. //
  466. goto error_exit;
  467. }
  468. //
  469. // Try to get a limit on the log file size. This number is the number of
  470. // MB.
  471. //
  472. envLength = GetEnvironmentVariable(L"ClusterLogSize",
  473. logFileSize,
  474. RTL_NUMBER_OF( logFileSize ));
  475. if ( envLength != 0 && envLength < MAX_NUMBER_LENGTH ) {
  476. RtlInitUnicodeString( &logFileString, logFileSize );
  477. status = RtlUnicodeStringToInteger( &logFileString,
  478. 10,
  479. &logSize );
  480. if ( NT_SUCCESS( status ) ) {
  481. OmpLogFileLimit = logSize;
  482. }
  483. } else {
  484. OmpLogFileLimit = defaultLogSize;
  485. }
  486. status = ERROR_SUCCESS;
  487. if ( OmpLogFileLimit == 0 ) {
  488. goto error_exit;
  489. }
  490. //
  491. // make the file size no bigger than one-eighth the size of the normal log
  492. // file but no less than 256KB
  493. //
  494. if ( OmpLogFileLimit > MAX_FILE_SIZE ) {
  495. OmpLogFileLimit = MAX_FILE_SIZE;
  496. }
  497. OmpLogFileLimit = ( OmpLogFileLimit * ( 1024 * 1024 )) / 8;
  498. if ( OmpLogFileLimit < ( 256 * 1024 )) {
  499. OmpLogFileLimit = 256 * 1024;
  500. }
  501. //
  502. // replace the extension with the object log extension; scanning backwards
  503. // from the end of the string, find either the first occurance of a slash
  504. // (fwd or back) or a dot or the front of the string.
  505. //
  506. dot = logFileName + logFileNameChars - 1;
  507. while ( dot != logFileName && *dot != L'.' && *dot != L'/' && *dot != L'\\' ) {
  508. --dot;
  509. }
  510. if ( dot == logFileName ) {
  511. //
  512. // no dots, no slashes; append extension to end
  513. //
  514. wcscat( logFileName + logFileNameChars, objectLogExtension );
  515. }
  516. else if ( *dot == L'/' || *dot == L'\\' ) {
  517. //
  518. // found a slash before a dot; append extension to end
  519. //
  520. wcscat( logFileName + logFileNameChars, objectLogExtension );
  521. }
  522. else if ( *dot == L'.' ) {
  523. //
  524. // found a dot before a slash; make sure that the extension isn't
  525. // already in use; if so don't log.
  526. //
  527. if ( ClRtlStrICmp( dot, objectLogExtension ) != 0 ) {
  528. wcscpy( dot, objectLogExtension );
  529. } else {
  530. goto error_exit;
  531. }
  532. } else {
  533. ClRtlLogPrint(LOG_UNUSUAL,
  534. "[OM] Couldn't determine where to append object log extension. Object logging turned off.\n");
  535. goto error_exit;
  536. }
  537. //
  538. // create a SD giving only local admins and localsystem full access. DACL
  539. // is set to protected (P) meaning it is not affected by inheritable ACEs
  540. // in the parent (cluster directory) object.
  541. //
  542. if ( !ConvertStringSecurityDescriptorToSecurityDescriptor(
  543. L"D:P(A;;FA;;;BA)(A;;FA;;;SY)",
  544. SDDL_REVISION_1,
  545. &logFileSecurityDesc,
  546. NULL
  547. )
  548. )
  549. {
  550. logFileSecurityDesc = NULL;
  551. }
  552. logFileSecurityAttr.nLength = sizeof( logFileSecurityAttr );
  553. logFileSecurityAttr.lpSecurityDescriptor = logFileSecurityDesc;
  554. logFileSecurityAttr.bInheritHandle = FALSE;
  555. OmpLogFileHandle = CreateFile(logFileName,
  556. GENERIC_READ | GENERIC_WRITE,
  557. FILE_SHARE_READ,
  558. &logFileSecurityAttr,
  559. OPEN_ALWAYS,
  560. 0,
  561. NULL );
  562. if ( OmpLogFileHandle == INVALID_HANDLE_VALUE ) {
  563. status = GetLastError();
  564. ClRtlLogPrint(LOG_UNUSUAL,
  565. "[OM] Open of object log file failed. Error %1!u!\n",
  566. status);
  567. goto error_exit;
  568. } else {
  569. //
  570. // write UTF-8 header to beginning of file and get the offset of the
  571. // EOF; we never want to reset the start of the file after this point.
  572. //
  573. WriteFile( OmpLogFileHandle, UTF8_BOM, sizeof( UTF8_BOM ) - 1, &bytesWritten, NULL );
  574. OmpCurrentSessionOffset = SetFilePointer( OmpLogFileHandle, 0, NULL, FILE_END );
  575. if ( OmpCurrentSessionOffset == INVALID_SET_FILE_POINTER ) {
  576. ClRtlLogPrint(LOG_UNUSUAL,
  577. "[OM] Unable to get object log end of file position. error %1!u!.\n",
  578. GetLastError());
  579. CloseHandle( OmpLogFileHandle );
  580. goto error_exit;
  581. }
  582. OmpLogToFile = TRUE;
  583. OmpProcessId = GetCurrentProcessId();
  584. //
  585. // determine the initial low water mark. We have 3 cases
  586. // we need to handle:
  587. // 1) log size is less than 1/2 limit
  588. // 2) log size is within limit but more than 1/2 limit
  589. // 3) log size is greater than limit
  590. //
  591. // case 1 requires nothing special; the low water mark will be updated
  592. // on the next log write.
  593. //
  594. // for case 2, we need to find the beginning of a line near 1/2 the
  595. // current limit. for case 3, the place to start looking is current
  596. // log size - 1/2 limit. In this case, the log will be truncated
  597. // before the first write occurs, so we need to take the last 1/2
  598. // limit bytes and copy them down to the front.
  599. //
  600. //
  601. // For now, set the low water mark to be the current offset. When it
  602. // is time to wrap, we'll lose everything but the current session.
  603. //
  604. // the problem is that we're dealing with UTF8 and we can't just jump
  605. // in the middle of the file and start looking around (we might hit
  606. // the 2nd byte of a DBCS sequence). For now, we'll leave
  607. // OmpLogFileLoWater set to zero. It will get updated when the 1/2 way
  608. // threshold is crossed.
  609. //
  610. OmpLogFileLoWater = OmpCurrentSessionOffset;
  611. #if 0
  612. fileSizeLow = GetFileSize( OmpLogFileHandle, &fileSizeHigh );
  613. if ( fileSizeLow < ( OmpLogFileLimit / 2 )) {
  614. //
  615. // case 1: leave low water at zero; it will be updated with next
  616. // log write
  617. //
  618. ;
  619. } else {
  620. #define LOGBUF_SIZE 1024
  621. CHAR buffer[LOGBUF_SIZE];
  622. LONG currentPosition;
  623. DWORD bytesRead;
  624. if ( fileSizeLow < OmpLogFileLimit ) {
  625. //
  626. // case 2; start looking at the 1/2 the current limit to find
  627. // the starting position
  628. //
  629. currentPosition = OmpLogFileLimit / 2;
  630. } else {
  631. //
  632. // case 3: start at current size minus 1/2 limit to find our
  633. // starting position.
  634. //
  635. currentPosition = fileSizeLow - ( OmpLogFileLimit / 2 );
  636. }
  637. //
  638. // backup from the initial file position, read in a block and look
  639. // for the start of a session. When we find one, backup to the
  640. // beginning of that line. Use that as the initial starting
  641. // position when we finally truncate the file.
  642. //
  643. OmpLogFileLoWater = 0;
  644. currentPosition -= LOGBUF_SIZE;
  645. SetFilePointer(OmpLogFileHandle,
  646. currentPosition,
  647. &fileSizeHigh,
  648. FILE_BEGIN);
  649. do {
  650. if ( ReadFile(OmpLogFileHandle,
  651. buffer,
  652. LOGBUF_SIZE - 1,
  653. &bytesRead,
  654. NULL ) )
  655. {
  656. PCHAR p = buffer;
  657. PCHAR newp;
  658. buffer[ bytesRead ] = NULL;
  659. while ( *p != 'S' && bytesRead-- != 0 ) {
  660. newp = CharNextExA( CP_UTF8, p, 0 );
  661. if ( newp == p ) {
  662. break;
  663. }
  664. p = newp;
  665. }
  666. if ( p != newp ) {
  667. if ( strchr( p, "START" )) {
  668. //
  669. // set pointer to beginning of line
  670. //
  671. p = currentLine;
  672. break;
  673. }
  674. } else {
  675. //
  676. // not found in this block; read in the next one
  677. //
  678. }
  679. }
  680. } while ( TRUE );
  681. if ( *p == '\n' ) {
  682. OmpLogFileLoWater = (DWORD)(currentPosition + ( p - buffer + 1 ));
  683. }
  684. if ( OmpLogFileLoWater == 0 ) {
  685. //
  686. // couldn't find any reasonable data. just set it to
  687. // initial current position.
  688. //
  689. OmpLogFileLoWater = currentPosition + LOGBUF_SIZE;
  690. }
  691. }
  692. #endif
  693. }
  694. LocalFree( logFileSecurityDesc );
  695. //
  696. // finally, create the threadq that will handle the IO to the file
  697. //
  698. OmpLoggerWorkQueue = ClRtlCreateWorkQueue( 1, THREAD_PRIORITY_BELOW_NORMAL );
  699. if ( OmpLoggerWorkQueue == NULL ) {
  700. CloseHandle( OmpLogFileHandle );
  701. ClRtlLogPrint(LOG_UNUSUAL,
  702. "[OM] Unable to logger work queue. error %1!u!.\n",
  703. GetLastError());
  704. }
  705. error_exit:
  706. if ( logFileName != logFileBuffer && logFileName != NULL ) {
  707. LocalFree( logFileName );
  708. }
  709. } // OmpOpenObjectLog
  710. VOID
  711. OmpLogStartRecord(
  712. VOID
  713. )
  714. /*++
  715. Routine Description:
  716. Description
  717. Arguments:
  718. None
  719. Return Value:
  720. None
  721. --*/
  722. {
  723. OSVERSIONINFOEXW version;
  724. BOOL success;
  725. PWCHAR suiteAbbrev;
  726. SYSTEMTIME localTime;
  727. GetLocalTime( &localTime );
  728. version.dwOSVersionInfoSize = sizeof(version);
  729. success = GetVersionExW((POSVERSIONINFOW)&version);
  730. if ( success ) {
  731. //
  732. // Log the System version number
  733. //
  734. if ( version.wSuiteMask & VER_SUITE_DATACENTER ) {
  735. suiteAbbrev = L"DTC";
  736. } else if ( version.wSuiteMask & VER_SUITE_ENTERPRISE ) {
  737. suiteAbbrev = L"ADS";
  738. } else if ( version.wSuiteMask & VER_SUITE_EMBEDDEDNT ) {
  739. suiteAbbrev = L"EMB";
  740. } else if ( version.wProductType & VER_NT_WORKSTATION ) {
  741. suiteAbbrev = L"WS";
  742. } else if ( version.wProductType & VER_NT_DOMAIN_CONTROLLER ) {
  743. suiteAbbrev = L"DC";
  744. } else if ( version.wProductType & VER_NT_SERVER ) {
  745. suiteAbbrev = L"SRV"; // otherwise - some non-descript Server
  746. } else {
  747. suiteAbbrev = L"";
  748. }
  749. OmpLogPrint(L"START %1!02d!/%2!02d!/%3!02d!-%4!02d!:%5!02d!:%6!02d!.%7!03d! %8!u! %9!u! "
  750. L"%10!u! %11!u! %12!u! %13!u! \"%14!ws!\" "
  751. L"%15!u! %16!u! %17!04X! (%18!ws!) %19!u!\n",
  752. localTime.wYear,
  753. localTime.wMonth,
  754. localTime.wDay,
  755. localTime.wHour,
  756. localTime.wMinute,
  757. localTime.wSecond,
  758. localTime.wMilliseconds,
  759. CLUSTER_GET_MAJOR_VERSION( CsMyHighestVersion ),
  760. CLUSTER_GET_MINOR_VERSION( CsMyHighestVersion ),
  761. version.dwMajorVersion, // param 10
  762. version.dwMinorVersion,
  763. version.dwBuildNumber,
  764. version.dwPlatformId,
  765. version.szCSDVersion,
  766. version.wServicePackMajor, // param 15
  767. version.wServicePackMinor,
  768. version.wSuiteMask,
  769. suiteAbbrev,
  770. version.wProductType);
  771. }
  772. } // OmpLogStartRecord
  773. VOID
  774. OmpLogStopRecord(
  775. VOID
  776. )
  777. /*++
  778. Routine Description:
  779. Description
  780. Arguments:
  781. None
  782. Return Value:
  783. None
  784. --*/
  785. {
  786. OmpLogPrint( L"STOP\n" );
  787. } // OmpLogStopRecord
  788. /* end omlog.c */