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.

731 lines
22 KiB

  1. #include "precomp.h"
  2. #include <stdio.h>
  3. #include <io.h>
  4. #include <wbemutil.h>
  5. #include <GroupsForUser.h>
  6. #include <ArrTempl.h>
  7. #include <GenUtils.h>
  8. #include <ErrorObj.h>
  9. #include "logfile.h"
  10. #include <sync.h>
  11. #include <statsync.h>
  12. #include <errno.h>
  13. #include <strsafe.h>
  14. #define LOGFILE_PROPNAME_FILENAME L"Filename"
  15. #define LOGFILE_PROPNAME_TEXT L"Text"
  16. #define LOGFILE_PROPNAME_MAX_SIZE L"MaximumFileSize"
  17. #define LOGFILE_PROPNAME_IS_UNICODE L"IsUnicode"
  18. const char ByteOrderMark[2] = {'\xFF','\xFE'};
  19. CStaticCritSec fileLock;
  20. HRESULT STDMETHODCALLTYPE CLogFileConsumer::XProvider::FindConsumer(
  21. IWbemClassObject* pLogicalConsumer,
  22. IWbemUnboundObjectSink** ppConsumer)
  23. {
  24. // Create a new sink
  25. // =================
  26. CLogFileSink* pSink = new CLogFileSink(m_pObject->m_pControl);
  27. if (!pSink)
  28. return WBEM_E_OUT_OF_MEMORY;
  29. // Initialize it
  30. // =============
  31. HRESULT hres = pSink->Initialize(pLogicalConsumer);
  32. if(FAILED(hres))
  33. {
  34. delete pSink;
  35. *ppConsumer = NULL;
  36. return hres;
  37. }
  38. // return it
  39. else return pSink->QueryInterface(IID_IWbemUnboundObjectSink,
  40. (void**)ppConsumer);
  41. }
  42. HRESULT STDMETHODCALLTYPE CLogFileConsumer::XInit::Initialize(
  43. LPWSTR, LONG, LPWSTR, LPWSTR, IWbemServices*, IWbemContext*,
  44. IWbemProviderInitSink* pSink)
  45. {
  46. pSink->SetStatus(0, 0);
  47. return 0;
  48. }
  49. void* CLogFileConsumer::GetInterface(REFIID riid)
  50. {
  51. if(riid == IID_IWbemEventConsumerProvider)
  52. return &m_XProvider;
  53. else if(riid == IID_IWbemProviderInit)
  54. return &m_XInit;
  55. else return NULL;
  56. }
  57. CLogFileSink::~CLogFileSink()
  58. {
  59. if(m_hFile != INVALID_HANDLE_VALUE)
  60. CloseHandle(m_hFile);
  61. if (m_pErrorObj)
  62. m_pErrorObj->Release();
  63. }
  64. // determine whether file needs to be backed up
  65. // returns false if we are not expected to back up file
  66. bool CLogFileSink::IsFileTooBig(UINT64 maxFileSize, HANDLE hFile)
  67. {
  68. bool bRet = false;
  69. // zero is interpreted to mean 'Let it grow without bounds'
  70. if (maxFileSize > 0)
  71. {
  72. LARGE_INTEGER size;
  73. if (GetFileSizeEx(hFile, &size))
  74. bRet = size.QuadPart > maxFileSize;
  75. }
  76. return bRet;
  77. }
  78. bool CLogFileSink::IsFileTooBig(UINT64 maxFileSize, WString& fileName)
  79. {
  80. bool bRet = false;
  81. // zero is interpreted to mean 'Let it grow without bounds'
  82. if (maxFileSize > 0)
  83. {
  84. struct _wfinddatai64_t foundData;
  85. __int64 handle;
  86. handle = _wfindfirsti64( (wchar_t *)fileName, &foundData);
  87. if (handle != -1l)
  88. {
  89. bRet = foundData.size >= maxFileSize;
  90. _findclose(handle);
  91. }
  92. }
  93. return bRet;
  94. }
  95. bool CLogFileSink::GetNumericExtension(WCHAR* pName, int& foundNumber)
  96. {
  97. WCHAR foundExtension[_MAX_EXT];
  98. _wsplitpath(pName, NULL, NULL, NULL, foundExtension);
  99. return (swscanf(foundExtension, L".%d", &foundNumber) == 1);
  100. }
  101. // makes backup of file
  102. // file must be closed when this is called
  103. HRESULT CLogFileSink::ArchiveFile(WString& fullName)
  104. {
  105. // first, let's make sure the dang file actually exists...
  106. struct _wfinddatai64_t foundData;
  107. __int64 findHandle;
  108. if ((findHandle = _wfindfirsti64( fullName, &foundData)) == -1i64)
  109. {
  110. if (GetLastError() == ENOENT)
  111. return WBEM_S_NO_ERROR;
  112. else
  113. return WBEM_E_FAILED;
  114. }
  115. else
  116. _findclose(findHandle);
  117. WCHAR drive[_MAX_DRIVE];
  118. WCHAR dir[_MAX_DIR];
  119. WCHAR fname[_MAX_FNAME];
  120. WCHAR ext[_MAX_EXT];
  121. // warning: reused, it'll be the mask for the lookup
  122. // then it'll be the new file name.
  123. WCHAR pathBuf[MAX_PATH +1];
  124. _wsplitpath( (const wchar_t *)fullName, drive, dir, fname, ext );
  125. bool bItEightDotThree = (wcslen(fname) <= 8) && (wcslen(ext) <= 4);
  126. // eightdot three file names are backed up to name.###
  127. // NON eight dotthree are backed up to name.ext.###
  128. // build mask for lookup
  129. StringCchCopyW(pathBuf, MAX_PATH+1, drive);
  130. StringCchCatW(pathBuf, MAX_PATH+1, dir);
  131. StringCchCatW(pathBuf, MAX_PATH+1, fname);
  132. if (!bItEightDotThree)
  133. {
  134. // there's a possibility that the filename would be too long
  135. // if we appended four chars. Will trunc if needed
  136. if ((wcslen(pathBuf) + wcslen(ext) + 4) > MAX_PATH)
  137. {
  138. // see if we can get away with just dropping the ext
  139. if ((wcslen(pathBuf) + 4) > MAX_PATH)
  140. pathBuf[MAX_PATH -4] = L'\0';
  141. }
  142. else
  143. // everything fits, no trunc needed
  144. StringCchCatW(pathBuf, MAX_PATH+1, ext);
  145. }
  146. // and the dotstar goes on the end, no matter what.
  147. StringCchCatW(pathBuf, MAX_PATH+1, L".*");
  148. // pathbuf is now the proper mask to lookup stuff.
  149. int biggestOne = 0;
  150. bool foundOne = false;
  151. bool foundOnes[1000];
  152. // keep track of which ones we found
  153. // just in case we have to go back & find a hole
  154. // using 1000 so I don't have to convert all the time.
  155. ZeroMemory(foundOnes, sizeof(bool) * 1000);
  156. if ((findHandle = _wfindfirsti64( pathBuf, &foundData)) != -1i64)
  157. {
  158. int latestOne;
  159. if (foundOne = GetNumericExtension(foundData.name, latestOne))
  160. {
  161. if (latestOne <= 999)
  162. {
  163. foundOnes[latestOne] = true;
  164. if (latestOne > biggestOne)
  165. biggestOne = latestOne;
  166. }
  167. }
  168. while (0 == _wfindnexti64(findHandle, &foundData))
  169. {
  170. if (GetNumericExtension(foundData.name, latestOne) && (latestOne <= 999))
  171. {
  172. foundOne = true;
  173. foundOnes[latestOne] = true;
  174. if (latestOne > biggestOne)
  175. biggestOne = latestOne;
  176. }
  177. }
  178. _findclose(findHandle);
  179. }
  180. int newExt = -1;
  181. if (foundOne)
  182. if (biggestOne < 999)
  183. newExt = biggestOne + 1;
  184. else
  185. {
  186. newExt = -1;
  187. // see if there's a hole somewhere
  188. for (int i = 1; i <= 999; i++)
  189. if (!foundOnes[i])
  190. {
  191. newExt = i;
  192. break;
  193. }
  194. }
  195. WCHAR *pTok;
  196. pTok = wcschr(pathBuf, L'*');
  197. // "can't happen" - the asterisk is added approximately 60 lines up
  198. // however, we'll go ahead & do the check - will make PREFIX happy if nothing else.
  199. if (!pTok)
  200. return WBEM_E_CRITICAL_ERROR;
  201. if (newExt != -1)
  202. {
  203. // calc how much buffer we have past the end of pTok...
  204. int nTokStrLen = MAX_PATH - (pTok - pathBuf) -1;
  205. // construct new name
  206. // we want to replace the * with ###
  207. StringCchPrintf(pTok, nTokStrLen, L"%03d", newExt);
  208. //swprintf(pTok, L"%03d", newExt);
  209. }
  210. else
  211. // okay, we'll hammer an old file
  212. {
  213. // calc how much buffer we have past the end of pTok...
  214. int nTokStrLen = MAX_PATH - (pTok - pathBuf) -1;
  215. StringCchCopy(pTok, nTokStrLen, L"001");
  216. _wremove(pathBuf);
  217. }
  218. HRESULT hr = WBEM_S_NO_ERROR;
  219. BOOL bRet;
  220. //int retval = _wrename(fullName, pathBuf);
  221. {
  222. bRet = MoveFile(fullName, pathBuf);
  223. }
  224. if (!bRet)
  225. {
  226. DWORD err = GetLastError();
  227. m_pErrorObj->ReportError(L"MoveFile", fullName, NULL, err, true);
  228. ERRORTRACE((LOG_ESS, "MoveFile failed 0x%08X\n", err));
  229. hr = WBEM_E_FAILED;
  230. }
  231. return hr;
  232. }
  233. // determines whether file is too large, archives old if needed
  234. // use this function rather than accessing the file pointer directly
  235. HRESULT CLogFileSink::GetFileHandle(HANDLE& handle)
  236. {
  237. CInCritSec lockMe(&fileLock);
  238. // assume the worst
  239. HRESULT hr = WBEM_E_FAILED;
  240. handle = INVALID_HANDLE_VALUE;
  241. // check for whether we have to archive file
  242. // (use handle if open, else use filename)
  243. if (m_hFile != INVALID_HANDLE_VALUE)
  244. {
  245. if (IsFileTooBig(m_maxFileSize, m_hFile))
  246. {
  247. // two possibilities: we have ahold of logfile.log OR we've got logfile.001
  248. CloseHandle(m_hFile);
  249. m_hFile = INVALID_HANDLE_VALUE;
  250. hr = WBEM_S_NO_ERROR;
  251. if (IsFileTooBig(m_maxFileSize, m_wsFile))
  252. hr = ArchiveFile(m_wsFile);
  253. if (FAILED(hr))
  254. return hr;
  255. }
  256. }
  257. else
  258. {
  259. if (IsFileTooBig(m_maxFileSize, m_wsFile))
  260. {
  261. hr = ArchiveFile(m_wsFile);
  262. if (FAILED(hr))
  263. return hr;
  264. }
  265. }
  266. if (m_hFile != INVALID_HANDLE_VALUE)
  267. {
  268. // got a good file, we're good to go
  269. handle = m_hFile;
  270. hr = WBEM_S_NO_ERROR;
  271. }
  272. else
  273. {
  274. // Open the file
  275. // we'll try opening an existing file first
  276. m_hFile = CreateFile(m_wsFile, GENERIC_READ | GENERIC_WRITE,
  277. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  278. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  279. if(m_hFile != INVALID_HANDLE_VALUE)
  280. {
  281. if (FILE_TYPE_DISK != GetFileType(m_hFile))
  282. {
  283. CloseHandle(m_hFile);
  284. m_hFile = INVALID_HANDLE_VALUE;
  285. m_pErrorObj->ReportError(L"CreateFile", m_wsFile, NULL, WBEM_E_ACCESS_DENIED, false);
  286. return WBEM_E_ACCESS_DENIED;
  287. }
  288. // now, take a looksee and determine whether the existing file is unicode
  289. // *regardless* of what the flag says
  290. char readbuf[2] = {'\0','\0'};
  291. DWORD bytesRead;
  292. // if (fread(&readbuf, sizeof(WCHAR), 1, m_pFile) > 0)
  293. if (ReadFile(m_hFile, &readbuf, sizeof(WCHAR), &bytesRead, NULL) &&
  294. (bytesRead == sizeof(WCHAR)))
  295. {
  296. // only interesting cases are those where the flag
  297. // doesn't match what's in the file...
  298. if ((readbuf[0] == ByteOrderMark[0]) && (readbuf[1] == ByteOrderMark[1])
  299. && !m_bUnicode)
  300. m_bUnicode = true;
  301. else if (((readbuf[0] != ByteOrderMark[0]) || (readbuf[1] != ByteOrderMark[1])) && m_bUnicode)
  302. m_bUnicode = false;
  303. }
  304. // line up at the end of the file
  305. SetFilePointer(m_hFile, 0,0, FILE_END);
  306. handle = m_hFile;
  307. hr = WBEM_S_NO_ERROR;
  308. }
  309. else
  310. {
  311. // ahhh - it wasn't there, for whatever reason.
  312. m_hFile = CreateFile(m_wsFile, GENERIC_READ | GENERIC_WRITE,
  313. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  314. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  315. if (m_hFile != INVALID_HANDLE_VALUE)
  316. {
  317. if (FILE_TYPE_DISK != GetFileType(m_hFile))
  318. {
  319. CloseHandle(m_hFile);
  320. m_hFile = INVALID_HANDLE_VALUE;
  321. m_pErrorObj->ReportError(L"CreateFile", m_wsFile, NULL, WBEM_E_ACCESS_DENIED, false);
  322. return WBEM_E_ACCESS_DENIED;
  323. }
  324. DWORD bytesWryt;
  325. if (m_bUnicode)
  326. {
  327. if (0 == WriteFile(m_hFile, (LPCVOID)ByteOrderMark, 2, &bytesWryt, NULL))
  328. ERRORTRACE((LOG_ESS, "Failed to write byte order mark to log file 0x%08X\n", GetLastError()));
  329. }
  330. handle = m_hFile;
  331. hr = WBEM_S_NO_ERROR;
  332. }
  333. else
  334. {
  335. DWORD dwError = GetLastError();
  336. m_pErrorObj->ReportError(L"CreateFile", m_wsFile, NULL, dwError, true);
  337. ERRORTRACE((LOG_ESS, "Unable to open log file %S, [0x%X]\n", (LPWSTR)m_wsFile, dwError));
  338. }
  339. }
  340. }
  341. return hr;
  342. }
  343. // initialize members, do security check.
  344. // a tidier programmer would probably move the security check to a separate function
  345. HRESULT CLogFileSink::Initialize(IWbemClassObject* pLogicalConsumer)
  346. {
  347. // this is actually a pointer to a static object
  348. // if it fails, something is Very, Very Wrong.
  349. m_pErrorObj = ErrorObj::GetErrorObj();
  350. if (!m_pErrorObj)
  351. return WBEM_E_CRITICAL_ERROR;
  352. // Get the information
  353. // ===================
  354. HRESULT hres;
  355. VARIANT v;
  356. VariantInit(&v);
  357. hres = pLogicalConsumer->Get(LOGFILE_PROPNAME_FILENAME, 0, &v, NULL, NULL);
  358. if (FAILED(hres) || (V_VT(&v) != VT_BSTR) || (v.bstrVal == NULL))
  359. {
  360. VariantClear(&v);
  361. return WBEM_E_INVALID_PARAMETER;
  362. }
  363. size_t length;
  364. length = wcslen(v.bstrVal);
  365. if ((length > MAX_PATH) || (length == 0))
  366. {
  367. VariantClear(&v);
  368. return WBEM_E_INVALID_PARAMETER;
  369. }
  370. m_wsFile = V_BSTR(&v);
  371. // check for disallowed filenames
  372. VariantClear(&v);
  373. m_wsFile.StripWs(WString::leading);
  374. if (m_wsFile.Length() == 0)
  375. return WBEM_E_INVALID_PARAMETER;
  376. // UNC global file names: no-no.
  377. if (wcsstr(m_wsFile, L"\\\\.")
  378. ||
  379. wcsstr(m_wsFile, L"//.")
  380. ||
  381. wcsstr(m_wsFile, L"\\\\??")
  382. ||
  383. wcsstr(m_wsFile, L"//??"))
  384. {
  385. m_pErrorObj->ReportError(L"CLogFileSink::Initialize", m_wsFile, L"Filename", WBEM_E_ACCESS_DENIED, true);
  386. return WBEM_E_ACCESS_DENIED;
  387. }
  388. hres = pLogicalConsumer->Get(LOGFILE_PROPNAME_TEXT, 0, &v, NULL, NULL);
  389. if(FAILED(hres) || V_VT(&v) != VT_BSTR)
  390. {
  391. VariantClear(&v);
  392. return WBEM_E_INVALID_PARAMETER;
  393. }
  394. m_Template.SetTemplate(V_BSTR(&v));
  395. VariantClear(&v);
  396. hres = pLogicalConsumer->Get(LOGFILE_PROPNAME_IS_UNICODE, 0, &v, NULL, NULL);
  397. if(FAILED(hres))
  398. return WBEM_E_INVALID_PARAMETER;
  399. else if (V_VT(&v) == VT_BOOL)
  400. m_bUnicode = v.boolVal == VARIANT_TRUE;
  401. else if (V_VT(&v) == VT_NULL)
  402. m_bUnicode = false;
  403. else
  404. return WBEM_E_INVALID_PARAMETER;
  405. VariantClear(&v);
  406. hres = pLogicalConsumer->Get(LOGFILE_PROPNAME_MAX_SIZE, 0, &v, NULL, NULL);
  407. if (FAILED(hres))
  408. return WBEM_E_INVALID_PARAMETER;
  409. else if (V_VT(&v) == VT_BSTR)
  410. {
  411. if (!ReadUI64(V_BSTR(&v), m_maxFileSize))
  412. return WBEM_E_INVALID_PARAMETER;
  413. }
  414. else if (V_VT(&v) == VT_NULL)
  415. m_maxFileSize = 65535;
  416. else
  417. return WBEM_E_INVALID_PARAMETER;
  418. VariantClear(&v);
  419. // Determine whether user has rights to file
  420. // =========================================
  421. // first determine who is our creator...
  422. hres = pLogicalConsumer->Get(L"CreatorSid", 0, &v,
  423. NULL, NULL);
  424. if (SUCCEEDED(hres))
  425. {
  426. HRESULT hDebug = WBEM_E_FAILED;
  427. long ubound = 0;
  428. PSID pSidCreator = NULL;
  429. PVOID pVoid = NULL;
  430. hDebug = SafeArrayGetUBound(V_ARRAY(&v), 1, &ubound);
  431. if(FAILED(hDebug)) return hDebug;
  432. hDebug = SafeArrayAccessData(V_ARRAY(&v), &pVoid);
  433. if(FAILED(hDebug)) return hDebug;
  434. pSidCreator = new BYTE[ubound +1];
  435. if (pSidCreator)
  436. memcpy(pSidCreator, pVoid, ubound + 1);
  437. else
  438. {
  439. VariantClear(&v);
  440. SafeArrayUnaccessData(V_ARRAY(&v));
  441. return WBEM_E_OUT_OF_MEMORY;
  442. }
  443. CDeleteMe<BYTE> deleteTheCreator((BYTE*)pSidCreator);
  444. SafeArrayUnaccessData(V_ARRAY(&v));
  445. VariantClear(&v);
  446. BOOL bIsSystem;
  447. // check to see if the creator is The System
  448. {
  449. PSID pSidSystem;
  450. SID_IDENTIFIER_AUTHORITY sa = SECURITY_NT_AUTHORITY;
  451. if (AllocateAndInitializeSid(&sa, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &pSidSystem))
  452. {
  453. bIsSystem = EqualSid(pSidCreator, pSidSystem);
  454. FreeSid(pSidSystem);
  455. }
  456. else
  457. return WBEM_E_FAILED;
  458. }
  459. if (bIsSystem)
  460. // creator is local system, let him in.
  461. hres = WBEM_S_NO_ERROR;
  462. else
  463. {
  464. DWORD dwSize;
  465. WString fNameForCheck = m_wsFile;
  466. // call once to see how big a buffer we might need
  467. GetFileSecurityW(fNameForCheck, DACL_SECURITY_INFORMATION, NULL, 0, &dwSize);
  468. DWORD dwErr = GetLastError();
  469. if (dwErr == ERROR_INVALID_NAME)
  470. {
  471. m_pErrorObj->ReportError(L"GetFileSecurity", (WCHAR*)fNameForCheck, NULL, dwErr, true);
  472. return WBEM_E_INVALID_PARAMETER;
  473. }
  474. else if (dwErr == ERROR_FILE_NOT_FOUND)
  475. // no file - see if directory exists
  476. {
  477. WCHAR drive[_MAX_DRIVE];
  478. WCHAR dir[_MAX_DIR];
  479. _wsplitpath( m_wsFile,drive, dir, NULL, NULL);
  480. WCHAR path[MAX_PATH];
  481. StringCchCopy(path, MAX_PATH, drive);
  482. StringCchCat(path, MAX_PATH, dir);
  483. fNameForCheck = path;
  484. GetFileSecurityW(fNameForCheck, DACL_SECURITY_INFORMATION, NULL, 0, &dwSize);
  485. dwErr = GetLastError();
  486. }
  487. // we don't bother trying to create the directory.
  488. if ((dwErr == ERROR_FILE_NOT_FOUND) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_INVALID_NAME))
  489. {
  490. m_pErrorObj->ReportError(L"GetFileSecurity", m_wsFile, NULL, dwErr, true);
  491. return WBEM_E_INVALID_PARAMETER;
  492. }
  493. if (dwErr != ERROR_INSUFFICIENT_BUFFER)
  494. return WBEM_E_FAILED;
  495. PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) new BYTE[dwSize];
  496. if (!psd)
  497. return WBEM_E_OUT_OF_MEMORY;
  498. CDeleteMe<BYTE> delSD((BYTE *)psd);
  499. PACL pDacl = NULL;
  500. BOOL bDaclPresent, bDaclDefaulted;
  501. // retrieve file's security, if any
  502. if (GetFileSecurityW(fNameForCheck, DACL_SECURITY_INFORMATION, psd, dwSize, &dwSize) &&
  503. GetSecurityDescriptorDacl(psd, &bDaclPresent, &pDacl, &bDaclDefaulted))
  504. {
  505. if (bDaclPresent && pDacl)
  506. {
  507. DWORD accessMask;
  508. if (S_OK == GetAccessMask(pSidCreator, pDacl, &accessMask))
  509. {
  510. DWORD rightAccess = FILE_WRITE_DATA;
  511. if (accessMask & rightAccess)
  512. hres = WBEM_S_NO_ERROR;
  513. else
  514. hres = WBEM_E_ACCESS_DENIED;
  515. }
  516. else
  517. return WBEM_E_ACCESS_DENIED;
  518. }
  519. }
  520. else
  521. return WBEM_E_FAILED;
  522. }
  523. }
  524. return hres;
  525. }
  526. HRESULT STDMETHODCALLTYPE CLogFileSink::XSink::IndicateToConsumer(
  527. IWbemClassObject* pLogicalConsumer, long lNumObjects,
  528. IWbemClassObject** apObjects)
  529. {
  530. for(int i = 0; i < lNumObjects; i++)
  531. {
  532. // Apply the template to the event
  533. // ===============================
  534. BSTR strText = m_pObject->m_Template.Apply(apObjects[i]);
  535. if(strText == NULL)
  536. strText = SysAllocString(L"invalid log entry");
  537. if (strText == NULL)
  538. return WBEM_E_OUT_OF_MEMORY;
  539. CSysFreeMe freeString(strText);
  540. HANDLE hFile = INVALID_HANDLE_VALUE;
  541. HRESULT hr = m_pObject->GetFileHandle(hFile);
  542. if (SUCCEEDED(hr))
  543. {
  544. if (m_pObject->m_bUnicode)
  545. {
  546. CInCritSec lockMe(&fileLock);
  547. WCHAR EOL[] = L"\r\n";
  548. // make sure we're at the end, in case of multiple writers
  549. SetFilePointer(hFile, 0,0, FILE_END);
  550. DWORD bitzwritz;
  551. if (!WriteFile(hFile, strText, wcslen(strText) *2, &bitzwritz, NULL) ||
  552. !WriteFile(hFile, EOL, wcslen(EOL) *2, &bitzwritz, NULL))
  553. {
  554. DWORD dwErr = GetLastError();
  555. m_pObject->m_pErrorObj->ReportError(L"WriteFile", strText, NULL, dwErr, true);
  556. ERRORTRACE((LOG_ESS, "LOGFILE: Failed to write to file, 0x%08X\n", dwErr));
  557. return WBEM_E_FAILED;
  558. }
  559. }
  560. else
  561. {
  562. // convert to mbcs
  563. char* pStr = new char[wcslen(strText) *2 +1];
  564. if (!pStr)
  565. return WBEM_E_OUT_OF_MEMORY;
  566. // else...
  567. CDeleteMe<char> delStr(pStr);
  568. if (0 == WideCharToMultiByte(CP_THREAD_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, strText, -1, pStr, wcslen(strText) *2 +1, NULL, NULL))
  569. {
  570. ERRORTRACE((LOG_ESS, "LOGFILE: Unable to convert \"%S\" to MBCS, failing\n", strText));
  571. return WBEM_E_FAILED;
  572. }
  573. else
  574. {
  575. CInCritSec lockMe(&fileLock);
  576. char EOL[] = "\r\n";
  577. // make sure we're at the end, in case of multiple writers
  578. SetFilePointer(hFile, 0,0, FILE_END);
  579. DWORD bitzwritz;
  580. if (!WriteFile(hFile, pStr, strlen(pStr), &bitzwritz, NULL) ||
  581. !WriteFile(hFile, EOL, strlen(EOL), &bitzwritz, NULL))
  582. {
  583. DWORD dwErr = GetLastError();
  584. m_pObject->m_pErrorObj->ReportError(L"WriteFile", strText, NULL, dwErr, true);
  585. ERRORTRACE((LOG_ESS, "LOGFILE: Failed to write to file, 0x%08X\n", dwErr));
  586. return WBEM_E_FAILED;
  587. }
  588. }
  589. }
  590. }
  591. else
  592. return hr;
  593. }
  594. return S_OK;
  595. }
  596. void* CLogFileSink::GetInterface(REFIID riid)
  597. {
  598. if(riid == IID_IWbemUnboundObjectSink)
  599. return &m_XSink;
  600. else return NULL;
  601. }