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.
1060 lines
22 KiB
1060 lines
22 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// logfile.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class LogFile.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ias.h"
|
|
#include "logfile.h"
|
|
#include <climits>
|
|
#include <new>
|
|
#include "iasevent.h"
|
|
#include "iastrace.h"
|
|
#include "iasutil.h"
|
|
#include "mprlog.h"
|
|
|
|
inline StringSentry::StringSentry(wchar_t* p) throw ()
|
|
: sz(p)
|
|
{
|
|
}
|
|
|
|
|
|
inline StringSentry::~StringSentry() throw ()
|
|
{
|
|
delete[] sz;
|
|
}
|
|
|
|
|
|
inline const wchar_t* StringSentry::Get() const throw ()
|
|
{
|
|
return sz;
|
|
}
|
|
|
|
|
|
inline bool StringSentry::IsNull() const throw ()
|
|
{
|
|
return sz == 0;
|
|
}
|
|
|
|
|
|
inline StringSentry::operator const wchar_t*() const throw ()
|
|
{
|
|
return sz;
|
|
}
|
|
|
|
|
|
inline StringSentry::operator wchar_t*() throw ()
|
|
{
|
|
return sz;
|
|
}
|
|
|
|
|
|
inline void StringSentry::Swap(StringSentry& other) throw ()
|
|
{
|
|
wchar_t* temp = sz;
|
|
sz = other.sz;
|
|
other.sz = temp;
|
|
}
|
|
|
|
|
|
inline StringSentry& StringSentry::operator=(wchar_t* p) throw ()
|
|
{
|
|
if (sz != p)
|
|
{
|
|
delete[] sz;
|
|
sz = p;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
LogFile::LogFile() throw ()
|
|
: deleteIfFull(true),
|
|
period(IAS_LOGGING_UNLIMITED_SIZE),
|
|
seqNum(0),
|
|
file(INVALID_HANDLE_VALUE),
|
|
firstDayOfWeek(0),
|
|
iasEventSource(RegisterEventSourceW(0, L"IAS")),
|
|
rasEventSource(RegisterEventSourceW(0, L"RemoteAccess"))
|
|
{
|
|
maxSize.QuadPart = _UI64_MAX;
|
|
|
|
wchar_t buffer[4];
|
|
if (GetLocaleInfo(
|
|
LOCALE_SYSTEM_DEFAULT,
|
|
LOCALE_IFIRSTDAYOFWEEK,
|
|
buffer,
|
|
sizeof(buffer)/sizeof(wchar_t)
|
|
))
|
|
{
|
|
// The locale info calls Monday day zero, while SYSTEMTIME calls
|
|
// Sunday day zero.
|
|
firstDayOfWeek = (1 + static_cast<DWORD>(_wtoi(buffer))) % 7;
|
|
}
|
|
}
|
|
|
|
|
|
LogFile::~LogFile() throw ()
|
|
{
|
|
Close();
|
|
|
|
if (iasEventSource != 0)
|
|
{
|
|
DeregisterEventSource(iasEventSource);
|
|
}
|
|
|
|
if (rasEventSource != 0)
|
|
{
|
|
DeregisterEventSource(rasEventSource);
|
|
}
|
|
}
|
|
|
|
|
|
void LogFile::SetDeleteIfFull(bool newVal) throw ()
|
|
{
|
|
Lock();
|
|
|
|
deleteIfFull = newVal;
|
|
|
|
Unlock();
|
|
|
|
IASTracePrintf("LogFile.DeleteIfFull = %s", (newVal ? "true" : "false"));
|
|
}
|
|
|
|
|
|
DWORD LogFile::SetDirectory(const wchar_t* newVal) throw ()
|
|
{
|
|
if (newVal == 0)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// How big is the expanded directory string?
|
|
DWORD len = ExpandEnvironmentStringsW(
|
|
newVal,
|
|
0,
|
|
0
|
|
);
|
|
if (len == 0)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
// Allocate memory to hold the new directory and expand any variables.
|
|
StringSentry newDirectory(new (std::nothrow) wchar_t[len]);
|
|
if (newDirectory.IsNull())
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
len = ExpandEnvironmentStringsW(
|
|
newVal,
|
|
newDirectory,
|
|
len
|
|
);
|
|
if (len == 0)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
// Does it end in a backlash ?
|
|
if ((len > 1) && (newDirectory[len - 2] == L'\\'))
|
|
{
|
|
// Null out the backslash.
|
|
newDirectory[len - 2] = L'\0';
|
|
}
|
|
|
|
Lock();
|
|
|
|
DWORD error = NO_ERROR;
|
|
|
|
// Is this a new directory?
|
|
if (directory.IsNull() || (wcscmp(newDirectory, directory) != 0))
|
|
{
|
|
// Save the new value.
|
|
directory.Swap(newDirectory);
|
|
|
|
// Close the old file.
|
|
Close();
|
|
|
|
// Rescan the sequence number.
|
|
error = UpdateSequence();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
IASTracePrintf("LogFile.Directory = %S", directory.Get());
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
void LogFile::SetMaxSize(const ULONGLONG& newVal) throw ()
|
|
{
|
|
Lock();
|
|
|
|
maxSize.QuadPart = newVal;
|
|
|
|
Unlock();
|
|
|
|
IASTracePrintf(
|
|
"LogFile.MaxSize = 0x%08X%08X",
|
|
maxSize.HighPart,
|
|
maxSize.LowPart
|
|
);
|
|
}
|
|
|
|
|
|
DWORD LogFile::SetPeriod(NEW_LOG_FILE_FREQUENCY newVal) throw ()
|
|
{
|
|
DWORD error = NO_ERROR;
|
|
|
|
Lock();
|
|
|
|
if (newVal != period)
|
|
{
|
|
// A new period means a new filename.
|
|
Close();
|
|
|
|
period = newVal;
|
|
|
|
if (!directory.IsNull())
|
|
{
|
|
error = UpdateSequence();
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
IASTracePrintf("LogFile.Period = %u", newVal);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
bool LogFile::Write(
|
|
IASPROTOCOL protocol,
|
|
const SYSTEMTIME& st,
|
|
const BYTE* buf,
|
|
DWORD buflen,
|
|
bool allowRetry
|
|
) throw ()
|
|
{
|
|
Lock();
|
|
|
|
// Save the currently cached file handle (may be null or stale).
|
|
HANDLE cached = file;
|
|
|
|
// Get the correct handle for the write.
|
|
CheckFileHandle(protocol, st, buflen);
|
|
|
|
bool success = false;
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD error;
|
|
do
|
|
{
|
|
DWORD bytesWritten;
|
|
if (WriteFile(file, buf, buflen, &bytesWritten, 0))
|
|
{
|
|
currentSize.QuadPart += buflen;
|
|
success = true;
|
|
error = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
error = GetLastError();
|
|
IASTracePrintf("WriteFile failed; error = %lu", error);
|
|
}
|
|
}
|
|
while ((error == ERROR_DISK_FULL) && DeleteOldestFile(protocol, st));
|
|
|
|
if ((error != NO_ERROR) && (error != ERROR_DISK_FULL))
|
|
{
|
|
// If we used a cached handle and allowRetry, then try again.
|
|
bool retry = (cached == file) && allowRetry;
|
|
|
|
// Prevent others from using the bad handle.
|
|
Close();
|
|
|
|
// Now that we've closed the bad handle try again.
|
|
if (retry)
|
|
{
|
|
// Set allowRetry to false to prevent an infinite recursion.
|
|
success = Write(protocol, st, buf, buflen, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
void LogFile::Close() throw ()
|
|
{
|
|
Lock();
|
|
|
|
if (file != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(file);
|
|
file = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
void LogFile::CheckFileHandle(
|
|
IASPROTOCOL protocol,
|
|
const SYSTEMTIME& st,
|
|
DWORD buflen
|
|
) throw ()
|
|
{
|
|
// Do we have a valid handle?
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
{
|
|
OpenFile(protocol, st);
|
|
}
|
|
|
|
// Have we reached the next period?
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_DAILY:
|
|
{
|
|
if ((st.wDay != whenOpened.wDay) ||
|
|
(st.wMonth != whenOpened.wMonth) ||
|
|
(st.wYear != whenOpened.wYear))
|
|
{
|
|
OpenFile(protocol, st);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_WEEKLY:
|
|
{
|
|
if ((GetWeekOfMonth(st) != weekOpened) ||
|
|
(st.wMonth != whenOpened.wMonth) ||
|
|
(st.wYear != whenOpened.wYear))
|
|
{
|
|
OpenFile(protocol, st);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
if ((st.wMonth != whenOpened.wMonth) ||
|
|
(st.wYear != whenOpened.wYear))
|
|
{
|
|
OpenFile(protocol, st);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
{
|
|
while ((currentSize.QuadPart + buflen) > maxSize.QuadPart)
|
|
{
|
|
++seqNum;
|
|
OpenFile(protocol, st);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
HANDLE LogFile::CreateDirectoryAndFile() throw ()
|
|
{
|
|
if (filename.IsNull())
|
|
{
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// Open the file if it exists or else create a new one.
|
|
HANDLE newFile = CreateFileW(
|
|
filename,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
0,
|
|
OPEN_ALWAYS,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
0
|
|
);
|
|
if (newFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
return newFile;
|
|
}
|
|
|
|
if (GetLastError() != ERROR_PATH_NOT_FOUND)
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// If the path is just a drive letter, there's nothing we can do.
|
|
size_t len = wcslen(directory);
|
|
if ((len != 0) && (directory[len - 1] == L':'))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// Otherwise, let's try to create the directory.
|
|
if (!CreateDirectoryW(directory, NULL))
|
|
{
|
|
IASTracePrintf(
|
|
"CreateDirectoryW(%S) failed; error = %lu",
|
|
directory.Get(),
|
|
GetLastError()
|
|
);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// Then try again to create the file.
|
|
newFile = CreateFileW(
|
|
filename,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
0,
|
|
OPEN_ALWAYS,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
0
|
|
);
|
|
if (newFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
IASTracePrintf(
|
|
"CreateFileW(%S) failed; error = %lu",
|
|
filename.Get(),
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
return newFile;
|
|
}
|
|
|
|
|
|
bool LogFile::DeleteOldestFile(
|
|
IASPROTOCOL protocol,
|
|
const SYSTEMTIME& st
|
|
) throw ()
|
|
{
|
|
if (!deleteIfFull ||
|
|
(period == IAS_LOGGING_UNLIMITED_SIZE) ||
|
|
directory.IsNull() ||
|
|
filename.IsNull())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool success = false;
|
|
|
|
// Find the lowest (oldest) file number.
|
|
unsigned int number;
|
|
DWORD error = FindFileNumber(st, true, number);
|
|
switch (error)
|
|
{
|
|
case NO_ERROR:
|
|
{
|
|
// Convert the file number to a file name.
|
|
StringSentry oldfile(FormatFileName(number));
|
|
if (oldfile.IsNull())
|
|
{
|
|
ReportOldFileDeleteError(protocol, L"", ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else if (_wcsicmp(oldfile, filename) == 0)
|
|
{
|
|
// Oldest file is the current file.
|
|
ReportOldFileNotFound(protocol);
|
|
}
|
|
else if (DeleteFileW(oldfile))
|
|
{
|
|
ReportOldFileDeleted(protocol, oldfile);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
ReportOldFileDeleteError(protocol, oldfile, GetLastError());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
{
|
|
ReportOldFileNotFound(protocol);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ReportOldFileDeleteError(protocol, L"", error);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
unsigned int LogFile::ExtendFileNumber(
|
|
const SYSTEMTIME& st,
|
|
unsigned int narrow
|
|
) const throw ()
|
|
{
|
|
unsigned int wide = narrow;
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_DAILY:
|
|
case IAS_LOGGING_WEEKLY:
|
|
{
|
|
unsigned int century = st.wYear / 100;
|
|
if (GetFileNumber(st) >= narrow)
|
|
{
|
|
wide += century * 1000000;
|
|
}
|
|
else
|
|
{
|
|
// We assume that log files are never from the future, so this file
|
|
// must be from the previous century.
|
|
wide += (century - 1) * 1000000;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
unsigned int century = st.wYear / 100;
|
|
if (GetFileNumber(st) >= narrow)
|
|
{
|
|
wide += century * 10000;
|
|
}
|
|
else
|
|
{
|
|
// We assume that log files are never from the future, so this file
|
|
// must be from the previous century.
|
|
wide += (century - 1) * 10000;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return wide;
|
|
}
|
|
|
|
|
|
DWORD LogFile::FindFileNumber(
|
|
const SYSTEMTIME& st,
|
|
bool findLowest,
|
|
unsigned int& result
|
|
) const throw ()
|
|
{
|
|
// Can't call this function until after the directory's been initialized.
|
|
if (directory.IsNull())
|
|
{
|
|
return ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
// The search filter passed to FindFirstFileW.
|
|
StringSentry filter(
|
|
ias_makewcs(
|
|
directory.Get(),
|
|
L"\\",
|
|
GetFileNameFilter(),
|
|
0
|
|
)
|
|
);
|
|
if (filter.IsNull())
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// Format string used for extracting the numeric portion of the filename.
|
|
const wchar_t* format = GetFileNameFormat();
|
|
|
|
WIN32_FIND_DATAW findData;
|
|
HANDLE hFind = FindFirstFileW(filter, &findData);
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
// Stores the best extended result found so far.
|
|
unsigned int bestWideMatch = findLowest ? UINT_MAX : 0;
|
|
// Stores the narrow version of bestWideMatch.
|
|
unsigned int bestNarrowMatch = UINT_MAX;
|
|
|
|
// Iterate through all the files that match the filter.
|
|
do
|
|
{
|
|
// Extract the numeric portion and test its validity.
|
|
unsigned int narrow;
|
|
if (swscanf(findData.cFileName, format, &narrow) == 1)
|
|
{
|
|
if (IsValidFileNumber(wcslen(findData.cFileName), narrow))
|
|
{
|
|
// Extend the file number to include the century.
|
|
unsigned int wide = ExtendFileNumber(st, narrow);
|
|
|
|
// Update bestMatch as appropriate.
|
|
if (wide < bestWideMatch)
|
|
{
|
|
if (findLowest)
|
|
{
|
|
bestWideMatch = wide;
|
|
bestNarrowMatch = narrow;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!findLowest)
|
|
{
|
|
bestWideMatch = wide;
|
|
bestNarrowMatch = narrow;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (FindNextFileW(hFind, &findData));
|
|
|
|
FindClose(hFind);
|
|
|
|
// Did we find a valid file?
|
|
if (bestNarrowMatch == UINT_MAX)
|
|
{
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
// We found a valid file, so return the result.
|
|
result = bestNarrowMatch;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
wchar_t* LogFile::FormatFileName(unsigned int number) const throw ()
|
|
{
|
|
// Longest filename is iaslog4294967295.log
|
|
wchar_t buffer[21];
|
|
swprintf(buffer, GetFileNameFormat(), number);
|
|
return ias_makewcs(directory.Get(), L"\\", buffer, 0);
|
|
}
|
|
|
|
|
|
const wchar_t* LogFile::GetFileNameFilter() const throw ()
|
|
{
|
|
const wchar_t* filter;
|
|
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
{
|
|
filter = L"iaslog*.log";
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_DAILY:
|
|
case IAS_LOGGING_WEEKLY:
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
filter = L"IN*.log";
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
default:
|
|
{
|
|
filter = L"iaslog.log";
|
|
break;
|
|
}
|
|
}
|
|
|
|
return filter;
|
|
}
|
|
|
|
|
|
const wchar_t* LogFile::GetFileNameFormat() const throw ()
|
|
{
|
|
const wchar_t* format;
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
{
|
|
format = L"iaslog%u.log";
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_DAILY:
|
|
case IAS_LOGGING_WEEKLY:
|
|
{
|
|
format = L"IN%06u.log";
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
format = L"IN%04u.log";
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
default:
|
|
{
|
|
format = L"iaslog.log";
|
|
break;
|
|
}
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
|
|
unsigned int LogFile::GetFileNumber(const SYSTEMTIME& st) const throw ()
|
|
{
|
|
unsigned int number;
|
|
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
{
|
|
number = seqNum;
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_DAILY:
|
|
{
|
|
number = ((st.wYear % 100) * 10000) + (st.wMonth * 100) + st.wDay;
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_WEEKLY:
|
|
{
|
|
number = ((st.wYear % 100) * 10000) + (st.wMonth * 100) +
|
|
GetWeekOfMonth(st);
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
number = ((st.wYear % 100) * 100) + st.wMonth;
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
default:
|
|
{
|
|
number = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return number;
|
|
}
|
|
|
|
|
|
DWORD LogFile::GetWeekOfMonth(const SYSTEMTIME& st) const throw ()
|
|
{
|
|
DWORD dom = st.wDay - 1;
|
|
DWORD wom = 1 + dom / 7;
|
|
|
|
if ((dom % 7) > ((st.wDayOfWeek + 7 - firstDayOfWeek) % 7))
|
|
{
|
|
++wom;
|
|
}
|
|
|
|
return wom;
|
|
}
|
|
|
|
|
|
bool LogFile::IsValidFileNumber(size_t len, unsigned int num) const throw ()
|
|
{
|
|
bool valid;
|
|
|
|
switch (period)
|
|
{
|
|
case IAS_LOGGING_DAILY:
|
|
{
|
|
// INyymmdd.log
|
|
unsigned int day = num % 100;
|
|
unsigned int month = (num / 100) % 100;
|
|
|
|
valid = (len == 12) &&
|
|
(day >= 1) && (day <= 31) &&
|
|
(month >= 1) && (month <= 12);
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_WEEKLY:
|
|
{
|
|
// INyymmww.log
|
|
unsigned int week = num % 100;
|
|
unsigned int month = (num / 100) % 100;
|
|
|
|
valid = (len == 12) &&
|
|
(week >= 1) && (week <= 5) &&
|
|
(month >= 1) && (month <= 12);
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_MONTHLY:
|
|
{
|
|
// INyymm.log
|
|
unsigned int month = num % 100;
|
|
|
|
valid = (len == 10) && (month >= 1) && (month <= 12);
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_WHEN_FILE_SIZE_REACHES:
|
|
{
|
|
// iaslogN.log
|
|
valid = (len > 10);
|
|
break;
|
|
}
|
|
|
|
case IAS_LOGGING_UNLIMITED_SIZE:
|
|
default:
|
|
{
|
|
// Doesn't contain a number, so never valid.
|
|
valid = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
void LogFile::OpenFile(IASPROTOCOL protocol, const SYSTEMTIME& st) throw ()
|
|
{
|
|
// Save the time when the file was opened.
|
|
whenOpened = st;
|
|
weekOpened = GetWeekOfMonth(st);
|
|
|
|
// Assume the currentSize is zero until we successfully open a file.
|
|
currentSize.QuadPart = 0;
|
|
|
|
// Close the exisisting file.
|
|
Close();
|
|
|
|
filename = FormatFileName(GetFileNumber(st));
|
|
if (!filename.IsNull())
|
|
{
|
|
HANDLE newFile;
|
|
do
|
|
{
|
|
newFile = CreateDirectoryAndFile();
|
|
}
|
|
while ((newFile == INVALID_HANDLE_VALUE) &&
|
|
(GetLastError() == ERROR_DISK_FULL) &&
|
|
DeleteOldestFile(protocol, st));
|
|
|
|
if (newFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
file = newFile;
|
|
|
|
// Get the size of the file.
|
|
currentSize.LowPart = GetFileSize(file, ¤tSize.HighPart);
|
|
if ((currentSize.LowPart == 0xFFFFFFFF) &&
|
|
(GetLastError() != NO_ERROR))
|
|
{
|
|
Close();
|
|
}
|
|
else
|
|
{
|
|
// Start writing new information at the end of the file.
|
|
SetFilePointer(file, 0, 0, FILE_END);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD LogFile::UpdateSequence() throw ()
|
|
{
|
|
if (period != IAS_LOGGING_WHEN_FILE_SIZE_REACHES)
|
|
{
|
|
seqNum = 0;
|
|
}
|
|
else
|
|
{
|
|
// SYSTEMTIME is ignored for sized files, so we can simply pass an
|
|
// unitialized struct.
|
|
SYSTEMTIME st;
|
|
DWORD error = FindFileNumber(st, false, seqNum);
|
|
switch (error)
|
|
{
|
|
case NO_ERROR:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
{
|
|
seqNum = 0;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return error;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
void LogFile::ReportOldFileDeleteError(
|
|
IASPROTOCOL protocol,
|
|
const wchar_t* oldfile,
|
|
DWORD error
|
|
) const throw ()
|
|
{
|
|
HANDLE eventLog;
|
|
DWORD eventId;
|
|
switch (protocol)
|
|
{
|
|
case IAS_PROTOCOL_RADIUS:
|
|
{
|
|
eventLog = iasEventSource;
|
|
eventId = ACCT_E_OLD_LOG_DELETE_ERROR;
|
|
break;
|
|
}
|
|
|
|
case IAS_PROTOCOL_RAS:
|
|
{
|
|
eventLog = rasEventSource;
|
|
eventId = ROUTERLOG_OLD_LOG_DELETE_ERROR;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
ReportEventW(
|
|
eventLog,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
eventId,
|
|
0,
|
|
1,
|
|
sizeof(error),
|
|
&oldfile,
|
|
&error
|
|
);
|
|
}
|
|
|
|
|
|
void LogFile::ReportOldFileDeleted(
|
|
IASPROTOCOL protocol,
|
|
const wchar_t* oldfile
|
|
) const throw ()
|
|
{
|
|
HANDLE eventLog;
|
|
DWORD eventId;
|
|
switch (protocol)
|
|
{
|
|
case IAS_PROTOCOL_RADIUS:
|
|
{
|
|
eventLog = iasEventSource;
|
|
eventId = ACCT_S_OLD_LOG_DELETED;
|
|
break;
|
|
}
|
|
|
|
case IAS_PROTOCOL_RAS:
|
|
{
|
|
eventLog = rasEventSource;
|
|
eventId = ROUTERLOG_OLD_LOG_DELETED;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
ReportEventW(
|
|
eventLog,
|
|
EVENTLOG_SUCCESS,
|
|
0,
|
|
eventId,
|
|
0,
|
|
1,
|
|
0,
|
|
&oldfile,
|
|
0
|
|
);
|
|
}
|
|
|
|
|
|
void LogFile::ReportOldFileNotFound(
|
|
IASPROTOCOL protocol
|
|
) const throw ()
|
|
{
|
|
HANDLE eventLog;
|
|
DWORD eventId;
|
|
switch (protocol)
|
|
{
|
|
case IAS_PROTOCOL_RADIUS:
|
|
{
|
|
eventLog = iasEventSource;
|
|
eventId = ACCT_I_OLD_LOG_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
case IAS_PROTOCOL_RAS:
|
|
{
|
|
eventLog = rasEventSource;
|
|
eventId = ROUTERLOG_OLD_LOG_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
ReportEventW(
|
|
eventLog,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
0,
|
|
eventId,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
}
|