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.
 
 
 
 
 
 

2559 lines
68 KiB

/*****************************************************************************/
/*
/* Copyright (c) 2001 Microsoft Corporation, All Rights Reserved /
/*
/*****************************************************************************/
#include "precomp.h"
#include "WMI_FilePrivateProfile.h"
#define STOP_AT_SECTION 1
#define STOP_AT_KEYWORD 2
#define STOP_AT_NONSECTION 3
#define BYTE_ORDER_MARK 0xFEFF
#define REVERSE_BYTE_ORDER_MARK 0xFFFE
ULONG LockFileKey = 1;
DWORD
APIENTRY
WMI_FILE_GetPrivateProfileStringW(
LPCWSTR lpAppName,
LPCWSTR lpKeyName,
LPCWSTR lpDefault,
LPWSTR lpReturnedString,
DWORD nSize,
LPCWSTR lpFileName
)
{
NTSTATUS Status;
ULONG n;
if (lpDefault == NULL) {
lpDefault = L"";
}
n = nSize;
Status = CWMI_FILE_IniFile::ReadWriteIniFile(FALSE, // WriteOperation
FALSE, // SectionOperation
lpFileName,
lpAppName,
lpKeyName,
lpReturnedString,
&n
);
if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_OVERFLOW) {
if (NT_SUCCESS( Status )) {
SetLastError( NO_ERROR );
n--;
} else
if (!lpAppName || !lpKeyName) {
if (nSize >= 2) {
n = nSize - 2;
lpReturnedString[ n+1 ] = UNICODE_NULL;
} else {
n = 0;
}
} else {
if (nSize >= 1) {
n = nSize - 1;
} else {
n = 0;
}
}
} else {
n = wcslen( lpDefault );
while (n > 0 && lpDefault[n-1] == L' ') {
n -= 1;
}
if (n >= nSize) {
n = nSize;
}
wcsncpy( lpReturnedString, lpDefault, n );
}
if (n < nSize) {
lpReturnedString[ n ] = UNICODE_NULL;
} else
if (nSize > 0) {
lpReturnedString[ nSize-1 ] = UNICODE_NULL;
}
return( n );
}
UINT
APIENTRY
WMI_FILE_GetPrivateProfileIntW(
LPCWSTR lpAppName,
LPCWSTR lpKeyName,
INT nDefault,
LPCWSTR lpFileName
)
{
NTSTATUS Status;
ULONG ReturnValue;
WCHAR ValueBuffer[ 256 ];
UNICODE_STRING Value;
ANSI_STRING AnsiString;
ULONG cb;
ReturnValue = 0;
cb = WMI_FILE_GetPrivateProfileStringW(lpAppName,
lpKeyName,
NULL,
ValueBuffer,
sizeof( ValueBuffer ) / sizeof( WCHAR ),
lpFileName
);
if (cb == 0)
{
ReturnValue = nDefault;
}
else
{
Value.Buffer = ValueBuffer;
Value.Length = (USHORT)(cb * sizeof( WCHAR ));
Value.MaximumLength = (USHORT)((cb + 1) * sizeof( WCHAR ));
Status = RtlUnicodeStringToAnsiString( &AnsiString,
&Value,
TRUE
);
if (NT_SUCCESS( Status ))
{
Status = RtlCharToInteger( AnsiString.Buffer, 0, &ReturnValue );
RtlFreeAnsiString( &AnsiString );
}
if (!NT_SUCCESS( Status ))
{
SetLastError( Status );
}
else
{
SetLastError( NO_ERROR );
}
}
return ReturnValue;
}
BOOL
APIENTRY
WMI_FILE_WritePrivateProfileStringW(
LPCWSTR lpAppName,
LPCWSTR lpKeyName,
LPCWSTR lpString,
LPCWSTR lpFileName
)
{
NTSTATUS Status;
Status = CWMI_FILE_IniFile::ReadWriteIniFile(TRUE, // WriteOperation
FALSE, // SectionOperation
lpFileName,
lpAppName,
lpKeyName,
(LPWSTR)(lpKeyName == NULL ? NULL : lpString),
NULL
);
if (NT_SUCCESS( Status )) {
return( TRUE );
} else {
if (Status == STATUS_INVALID_IMAGE_FORMAT) {
SetLastError( ERROR_INVALID_DATA );
} else {
SetLastError( Status );
}
return( FALSE );
}
}
DWORD
APIENTRY
WMI_FILE_GetPrivateProfileSectionW(
LPCWSTR lpAppName,
LPWSTR lpReturnedString,
DWORD nSize,
LPCWSTR lpFileName
)
{
NTSTATUS Status;
ULONG n;
n = nSize;
Status = CWMI_FILE_IniFile::ReadWriteIniFile(FALSE, // WriteOperation
TRUE, // SectionOperation
lpFileName,
lpAppName,
NULL,
lpReturnedString,
&n
);
if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_OVERFLOW) {
if (NT_SUCCESS( Status )) {
SetLastError( NO_ERROR );
n--;
} else
if (nSize >= 2) {
n = nSize - 2;
lpReturnedString[ n+1 ] = UNICODE_NULL;
} else {
n = 0;
}
} else {
if (Status == STATUS_INVALID_IMAGE_FORMAT) {
SetLastError( ERROR_INVALID_DATA );
} else {
SetLastError( Status );
}
n = 0;
}
if (n < nSize) {
lpReturnedString[ n ] = UNICODE_NULL;
} else
if (nSize > 0) {
lpReturnedString[ nSize-1 ] = UNICODE_NULL;
}
return( n );
}
BOOL
APIENTRY
WMI_FILE_WritePrivateProfileSectionW(
LPCWSTR lpAppName,
LPCWSTR lpString,
LPCWSTR lpFileName
)
{
NTSTATUS Status;
Status = CWMI_FILE_IniFile::ReadWriteIniFile(TRUE, // WriteOperation
TRUE, // SectionOperation
lpFileName,
lpAppName,
NULL,
(LPWSTR)lpString,
NULL
);
if (NT_SUCCESS( Status ))
{
return( TRUE );
}
else
{
if (Status == STATUS_INVALID_IMAGE_FORMAT)
{
SetLastError( ERROR_INVALID_DATA );
}
else
{
SetLastError( Status );
}
return( FALSE );
}
}
CWMI_FILE_IniFileObject::CWMI_FILE_IniFileObject()
{
m_EnvironmentUpdateCount = 0;
m_FileHandle = INVALID_HANDLE_VALUE;
m_WriteAccess = FALSE;
m_UnicodeFile = FALSE;
m_LockedFile = FALSE;
m_EndOfFile = 0;
m_BaseAddress = NULL;
m_CommitSize = 0;
m_RegionSize = 0;
m_UpdateOffset = 0;
m_UpdateEndOffset = 0;
m_DirectoryInformationLength = 0;
}
CWMI_FILE_IniFileObject::~CWMI_FILE_IniFileObject()
{
if ((m_FileHandle != INVALID_HANDLE_VALUE) && (m_FileHandle != NULL))
{
NtClose(m_FileHandle);
m_FileHandle = INVALID_HANDLE_VALUE;
}
}
CWMI_FILE_IniFile::CWMI_FILE_IniFile()
{
RtlInitAnsiString( &m_VariableName, NULL );
RtlInitUnicodeString( &m_VariableNameU, NULL );
RtlInitAnsiString( &m_ApplicationName, NULL );
RtlInitUnicodeString( &m_ApplicationNameU, NULL );
m_Operation = Enum_ReadKeyValueOp;
m_IsWriteOperation = FALSE;
m_FileName = NULL;
m_IsMultiValueStrings = FALSE;
m_ValueBuffer = NULL;
m_ValueLength = 0;
m_ValueBufferU = NULL;
m_ValueLengthU = 0;
m_ResultChars = 0;
m_ResultMaxChars = 0;
m_ResultBufferU = NULL;
m_TextCurrent = NULL;
m_TextStart = NULL;
m_TextEnd = NULL;
}
CWMI_FILE_IniFile::~CWMI_FILE_IniFile()
{
if (m_VariableName.Buffer)
{
delete [] m_VariableName.Buffer;
m_VariableName.Buffer = NULL;
}
if (m_ApplicationName.Buffer)
{
delete [] m_ApplicationName.Buffer;
m_ApplicationName.Buffer = NULL;
}
if (m_ValueBuffer)
{
delete [] m_ValueBuffer;
m_ValueBuffer = NULL;
}
}
NTSTATUS CWMI_FILE_IniFile::ReadWriteIniFile(
IN BOOL WriteOperation,
IN BOOL SectionOperation,
IN LPCWSTR FileName,
IN LPCWSTR ApplicationName,
IN LPCWSTR VariableName,
IN OUT LPWSTR VariableValue,
IN OUT PULONG VariableValueLength
)
{
NTSTATUS Status = STATUS_SUCCESS;
BOOL MultiValueStrings = FALSE;;
INIFILE_OPERATION Operation;
if (SectionOperation) {
VariableName = NULL;
}
MultiValueStrings = FALSE;
if (WriteOperation)
{
if (ApplicationName)
{
if (VariableName)
{
if (VariableValue)
{
Operation = Enum_WriteKeyValueOp;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
if (VariableValue)
{
Operation = Enum_WriteSectionOp;
MultiValueStrings = TRUE;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
else
{
if (ApplicationName)
{
if (!ARGUMENT_PRESENT( VariableValue ))
{
Status = STATUS_INVALID_PARAMETER;
}
else
{
if (VariableName)
{
Operation = Enum_ReadKeyValueOp;
}
else
{
if (SectionOperation)
{
Operation = Enum_ReadSectionOp;
MultiValueStrings = TRUE;
}
else
{
Operation = Enum_ReadKeyNamesOp;
MultiValueStrings = TRUE;
}
}
}
}
else
{
if ( ! ( SectionOperation || !ARGUMENT_PRESENT( VariableValue ) ) )
{
Operation = Enum_ReadSectionNamesOp;
MultiValueStrings = TRUE;
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
}
}
if (NT_SUCCESS( Status ))
{
CWMI_FILE_IniFile myIni;
Status = myIni.CaptureIniFileParameters(Operation,
WriteOperation,
MultiValueStrings,
FileName,
ApplicationName,
VariableName,
VariableValue,
VariableValueLength
);
if (NT_SUCCESS( Status ))
{
Status = myIni.ReadWriteIniFileOnDisk();
if (NT_SUCCESS( Status ))
{
if (myIni.m_Operation == Enum_ReadSectionNamesOp ||
myIni.m_Operation == Enum_ReadKeyNamesOp ||
myIni.m_Operation == Enum_ReadSectionOp )
{
myIni.AppendNullToResultBuffer();
}
}
if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_OVERFLOW)
{
if (!myIni.m_IsWriteOperation)
{
if (ARGUMENT_PRESENT( VariableValueLength ))
{
*VariableValueLength = myIni.m_ResultChars;
}
}
}
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::CaptureIniFileParameters(
INIFILE_OPERATION a_Operation,
BOOL a_WriteOperation,
BOOL a_MultiValueStrings,
LPCWSTR a_FileName,
LPCWSTR a_ApplicationName,
LPCWSTR a_VariableName,
LPWSTR a_VariableValue,
PULONG a_ResultMaxChars
)
{
NTSTATUS Status = STATUS_SUCCESS;
m_Operation = a_Operation;
m_IsWriteOperation = a_WriteOperation;
m_IsMultiValueStrings = a_MultiValueStrings;
if (a_FileName)
{
m_FileName = a_FileName;
}
if (a_ApplicationName)
{
RtlInitUnicodeString(&m_ApplicationNameU, a_ApplicationName);
}
if (a_VariableName)
{
RtlInitUnicodeString(&m_VariableNameU, a_VariableName);
}
ULONG uVariableValueLength = 0;
if (a_VariableValue )
{
if (!a_ResultMaxChars)
{
if (!a_MultiValueStrings)
{
uVariableValueLength = wcslen( a_VariableValue );
}
else
{
LPWSTR p = a_VariableValue;
while (*p)
{
while (*p++)
{
}
}
uVariableValueLength = (ULONG)(p - a_VariableValue);
}
}
if (m_IsWriteOperation)
{
m_ValueBufferU = a_VariableValue;
m_ValueLengthU = uVariableValueLength * sizeof( WCHAR );
m_ValueBuffer = NULL;
m_ValueLength = 0;
}
else
{
if (a_ResultMaxChars)
{
m_ResultMaxChars = *a_ResultMaxChars;
}
m_ResultChars = 0;
m_ResultBufferU = a_VariableValue;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::OpenIniFileOnDisk()
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING FullFileName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER ByteOffset;
LARGE_INTEGER Length;
m_IniFile.m_WriteAccess = m_IsWriteOperation;
RtlInitUnicodeString(&FullFileName, NULL);
if (!RtlDosPathNameToNtPathName_U( m_FileName,
&FullFileName,
NULL,
NULL
)
)
{
return STATUS_OBJECT_PATH_NOT_FOUND;
}
try
{
InitializeObjectAttributes( &ObjectAttributes,
&FullFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
if (m_IniFile.m_WriteAccess)
{
Status = NtCreateFile( &m_IniFile.m_FileHandle,
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT |
FILE_NON_DIRECTORY_FILE,
NULL,
0
);
}
else
{
Status = NtOpenFile( &m_IniFile.m_FileHandle,
SYNCHRONIZE | GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT |
FILE_NON_DIRECTORY_FILE
);
}
}
catch(...)
{
RtlFreeUnicodeString(&FullFileName);
RtlInitUnicodeString(&FullFileName, NULL);
throw;
}
RtlFreeUnicodeString( &FullFileName );
RtlInitUnicodeString(&FullFileName, NULL);
if (NT_SUCCESS( Status ))
{
ByteOffset.QuadPart = 0;
Length.QuadPart = -1;
Status = NtLockFile( m_IniFile.m_FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ByteOffset,
&Length,
LockFileKey,
FALSE,
(BOOLEAN)m_IniFile.m_WriteAccess
);
if (NT_SUCCESS( Status ))
{
m_IniFile.m_LockedFile = TRUE;
}
if (NT_SUCCESS( Status ))
{
Status = NtQueryInformationFile( m_IniFile.m_FileHandle,
&IoStatusBlock,
&m_IniFile.m_StandardInformation,
sizeof( m_IniFile.m_StandardInformation ),
FileStandardInformation
);
if (Status == STATUS_BUFFER_OVERFLOW)
{
Status = STATUS_SUCCESS;
}
}
}
if (!NT_SUCCESS( Status ))
{
if ((m_IniFile.m_FileHandle != INVALID_HANDLE_VALUE) && (m_IniFile.m_FileHandle != NULL))
{
if (m_IniFile.m_LockedFile)
{
m_IniFile.m_LockedFile = FALSE;
ByteOffset.QuadPart = 0;
Length.QuadPart = -1;
NtUnlockFile( m_IniFile.m_FileHandle,
&IoStatusBlock,
&ByteOffset,
&Length,
LockFileKey
);
}
NtClose( m_IniFile.m_FileHandle );
m_IniFile.m_FileHandle = INVALID_HANDLE_VALUE;
}
return Status;
}
else
{
m_IniFile.m_EndOfFile = m_IniFile.m_StandardInformation.EndOfFile.LowPart;
m_IniFile.m_CommitSize = m_IniFile.m_EndOfFile + (4 * (m_IniFile.m_UnicodeFile ? sizeof( WCHAR ) : 1));
m_IniFile.m_RegionSize = m_IniFile.m_CommitSize + 0x100000; // Room for 256KB of growth
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&m_IniFile.m_BaseAddress,
0,
&m_IniFile.m_RegionSize,
MEM_RESERVE,
PAGE_READWRITE
);
if (NT_SUCCESS( Status ))
{
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&m_IniFile.m_BaseAddress,
0,
&m_IniFile.m_CommitSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (NT_SUCCESS( Status )) {
Status = NtReadFile( m_IniFile.m_FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
m_IniFile.m_BaseAddress,
m_IniFile.m_EndOfFile,
NULL,
&LockFileKey
);
if (NT_SUCCESS( Status ) && IoStatusBlock.Information != m_IniFile.m_EndOfFile) {
Status = STATUS_END_OF_FILE;
}
}
}
}
if (NT_SUCCESS( Status ))
{
// We would like to check the possibility of IS_TEXT_UNICODE_DBCS_LEADBYTE.
INT iResult = ~0x0;
m_IniFile.m_UpdateOffset = 0xFFFFFFFF;
m_IniFile.m_UpdateEndOffset = 0;
m_IniFile.m_UnicodeFile = RtlIsTextUnicode( m_IniFile.m_BaseAddress, m_IniFile.m_EndOfFile, (PULONG)&iResult );
if (m_IniFile.m_UnicodeFile)
{
LPWSTR Src = (LPWSTR)((PCHAR)m_IniFile.m_BaseAddress + m_IniFile.m_EndOfFile);
while (Src > (LPWSTR)m_IniFile.m_BaseAddress && Src[ -1 ] <= L' ')
{
if (Src[-1] == L'\r' || Src[-1] == L'\n')
{
break;
}
m_IniFile.m_EndOfFile -= sizeof( WCHAR );
Src -= 1;
}
Src = (LPWSTR)((PCHAR)m_IniFile.m_BaseAddress + m_IniFile.m_EndOfFile);
if (Src > (LPWSTR)m_IniFile.m_BaseAddress)
{
if (Src[-1] != L'\n')
{
*Src++ = L'\r';
*Src++ = L'\n';
m_IniFile.m_UpdateOffset = m_IniFile.m_EndOfFile;
m_IniFile.m_UpdateEndOffset = m_IniFile.m_UpdateOffset + 2 * sizeof( WCHAR );
m_IniFile.m_EndOfFile = m_IniFile.m_UpdateEndOffset;
}
}
}
else
{
LPBYTE Src = (PBYTE)((PCHAR)m_IniFile.m_BaseAddress + m_IniFile.m_EndOfFile);
while (Src > (PBYTE)m_IniFile.m_BaseAddress && Src[ -1 ] <= ' ')
{
if (Src[-1] == '\r' || Src[-1] == '\n') {
break;
}
m_IniFile.m_EndOfFile -= 1;
Src -= 1;
}
Src = (PBYTE)((PCHAR)m_IniFile.m_BaseAddress + m_IniFile.m_EndOfFile);
if (Src > (PBYTE)m_IniFile.m_BaseAddress)
{
if (Src[-1] != '\n') {
*Src++ = '\r';
*Src++ = '\n';
m_IniFile.m_UpdateOffset = m_IniFile.m_EndOfFile;
m_IniFile.m_UpdateEndOffset = m_IniFile.m_UpdateOffset + 2;
m_IniFile.m_EndOfFile = m_IniFile.m_UpdateEndOffset;
}
}
}
}
else
{
if ((m_IniFile.m_FileHandle != INVALID_HANDLE_VALUE) && (m_IniFile.m_FileHandle != NULL))
{
if (m_IniFile.m_LockedFile)
{
m_IniFile.m_LockedFile = FALSE;
ByteOffset.QuadPart = 0;
Length.QuadPart = -1;
NtUnlockFile( m_IniFile.m_FileHandle,
&IoStatusBlock,
&ByteOffset,
&Length,
LockFileKey
);
}
NtClose( m_IniFile.m_FileHandle );
m_IniFile.m_FileHandle = INVALID_HANDLE_VALUE;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::ReadWriteIniFileOnDisk()
{
NTSTATUS Status;
ULONG PartialResultChars = 0;
if (!m_IsWriteOperation) {
PartialResultChars = m_ResultChars;
}
Status = OpenIniFileOnDisk();
if (NT_SUCCESS( Status ))
{
try
{
m_TextEnd = (PCHAR)m_IniFile.m_BaseAddress + m_IniFile.m_EndOfFile;
m_TextCurrent = m_IniFile.m_BaseAddress;
if (m_IniFile.m_UnicodeFile &&
((*(PWCHAR)m_TextCurrent == BYTE_ORDER_MARK) ||
(*(PWCHAR)m_TextCurrent == REVERSE_BYTE_ORDER_MARK)))
{
// Skip past the BOM.
PWCHAR foo = (PWCHAR)m_TextCurrent;
foo++;
m_TextCurrent = (PVOID)foo;
}
if ( m_Operation == Enum_ReadSectionNamesOp )
{
Status = ReadSectionNames();
}
else if (m_Operation == Enum_ReadKeyValueOp)
{
Status = ReadKeywordValue();
}
else if (m_Operation == Enum_ReadKeyNamesOp)
{
Status = ReadKeywordNames();
}
else if (m_Operation == Enum_ReadSectionOp)
{
Status = ReadSection();
}
else if (m_Operation == Enum_WriteKeyValueOp)
{
Status = WriteKeywordValue(NULL );
}
else if (m_Operation == Enum_WriteSectionOp)
{
Status = WriteSection();
}
else
{
Status = STATUS_INVALID_PARAMETER;
}
NTSTATUS CloseStatus;
CloseStatus = CloseIniFileOnDisk();
if (NT_SUCCESS( Status ))
{
Status = CloseStatus;
}
}
catch (...)
{
NTSTATUS CloseStatus;
CloseStatus = CloseIniFileOnDisk();
if (NT_SUCCESS( Status ))
{
Status = CloseStatus;
}
}
}
if (Status == STATUS_OBJECT_NAME_NOT_FOUND &&
!m_IsWriteOperation &&
PartialResultChars != 0
)
{
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::CloseIniFileOnDisk()
{
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS CloseStatus = STATUS_SUCCESS;
IO_STATUS_BLOCK IoStatusBlock;
ULONG UpdateLength = 0;
LARGE_INTEGER ByteOffset;
LARGE_INTEGER Length;
if ((m_IniFile.m_FileHandle != INVALID_HANDLE_VALUE) && (m_IniFile.m_FileHandle != NULL))
{
if (m_IniFile.m_BaseAddress != NULL)
{
if (m_IniFile.m_UpdateOffset != 0xFFFFFFFF && m_IniFile.m_WriteAccess)
{
ByteOffset.HighPart = 0;
ByteOffset.LowPart = m_IniFile.m_UpdateOffset;
UpdateLength = m_IniFile.m_UpdateEndOffset - m_IniFile.m_UpdateOffset;
Status = NtWriteFile( m_IniFile.m_FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PCHAR)(m_IniFile.m_BaseAddress) + m_IniFile.m_UpdateOffset,
UpdateLength,
&ByteOffset,
&LockFileKey
);
if (NT_SUCCESS( Status ))
{
if (IoStatusBlock.Information != UpdateLength)
{
Status = STATUS_DISK_FULL;
}
else
{
Length.QuadPart = m_IniFile.m_EndOfFile;
Status = NtSetInformationFile( m_IniFile.m_FileHandle,
&IoStatusBlock,
&Length,
sizeof( Length ),
FileEndOfFileInformation
);
}
}
}
NtFreeVirtualMemory( NtCurrentProcess(),
&m_IniFile.m_BaseAddress,
&m_IniFile.m_RegionSize,
MEM_RELEASE
);
m_IniFile.m_BaseAddress = NULL;
m_IniFile.m_CommitSize = 0;
m_IniFile.m_RegionSize = 0;
}
if (m_IniFile.m_LockedFile)
{
m_IniFile.m_LockedFile = FALSE;
ByteOffset.QuadPart = 0;
Length.QuadPart = -1;
NtUnlockFile( m_IniFile.m_FileHandle,
&IoStatusBlock,
&ByteOffset,
&Length,
LockFileKey
);
}
CloseStatus = NtClose( m_IniFile.m_FileHandle );
m_IniFile.m_FileHandle = INVALID_HANDLE_VALUE;
if (NT_SUCCESS( Status ))
{
Status = CloseStatus;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::ReadSectionNames()
{
NTSTATUS Status;
Status = STATUS_SUCCESS;
while (NT_SUCCESS( Status ))
{
Status = AdvanceTextPointer( STOP_AT_SECTION );
if (Status == STATUS_MORE_ENTRIES) {
Status = AppendStringToResultBuffer(m_AnsiSectionName,
m_UnicodeSectionName,
TRUE
);
}
else
{
if (Status == STATUS_NO_MORE_ENTRIES)
{
Status = STATUS_SUCCESS;
}
break;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::ReadKeywordNames()
{
NTSTATUS Status;
Status = FindSection();
while (NT_SUCCESS( Status ))
{
Status = AdvanceTextPointer( STOP_AT_KEYWORD );
if (Status == STATUS_MORE_ENTRIES)
{
Status = AppendStringToResultBuffer( m_AnsiKeywordName,
m_UnicodeKeywordName,
TRUE
);
}
else
{
if (Status == STATUS_NO_MORE_ENTRIES)
{
Status = STATUS_SUCCESS;
}
break;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::ReadKeywordValue()
{
NTSTATUS Status = FindSection();
if (!NT_SUCCESS( Status ))
{
return Status;
}
Status = FindKeyword();
if (!NT_SUCCESS( Status ))
{
return Status;
}
if (m_IniFile.m_UnicodeFile)
{
LPWSTR Src = (LPWSTR)m_UnicodeKeywordValue->Buffer;
while (*Src <= L' ' && m_UnicodeKeywordValue->Length)
{
Src += 1;
m_UnicodeKeywordValue->Buffer = Src;
m_UnicodeKeywordValue->Length -= sizeof( WCHAR );
m_UnicodeKeywordValue->MaximumLength -= sizeof( WCHAR );
}
if (m_UnicodeKeywordValue->Length >= (2 * sizeof( WCHAR )) &&
(Src[ 0 ] == Src[ (m_UnicodeKeywordValue->Length - sizeof( WCHAR )) / sizeof( WCHAR ) ]) &&
(Src[ 0 ] == L'"' || Src[ 0 ] == L'\'')
) {
m_UnicodeKeywordValue->Buffer += 1;
m_UnicodeKeywordValue->Length -= (2 * sizeof( WCHAR ));
m_UnicodeKeywordValue->MaximumLength -= (2 * sizeof( WCHAR ));
}
}
else
{
PBYTE Src;
Src = (PBYTE)m_AnsiKeywordValue->Buffer;
while (*Src <= ' ' && m_AnsiKeywordValue->Length) {
Src += 1;
m_AnsiKeywordValue->Buffer = (PCHAR)Src;
m_AnsiKeywordValue->Length -= sizeof( UCHAR );
m_AnsiKeywordValue->MaximumLength -= sizeof( UCHAR );
}
if (m_AnsiKeywordValue->Length >= (2 * sizeof( UCHAR )) &&
(Src[ 0 ] == Src[ (m_AnsiKeywordValue->Length - sizeof( UCHAR )) / sizeof( UCHAR ) ]) &&
(Src[ 0 ] == '"' || Src[ 0 ] == '\'')
) {
m_AnsiKeywordValue->Buffer += 1;
m_AnsiKeywordValue->Length -= (2 * sizeof( UCHAR ));
m_AnsiKeywordValue->MaximumLength -= (2 * sizeof( UCHAR ));
}
}
return AppendStringToResultBuffer(m_AnsiKeywordValue,
m_UnicodeKeywordValue,
TRUE
);
}
NTSTATUS CWMI_FILE_IniFile::ReadSection()
{
NTSTATUS Status;
Status = FindSection();
if (!NT_SUCCESS( Status )) {
return Status;
}
while (TRUE) {
Status = AdvanceTextPointer( STOP_AT_NONSECTION );
if (Status == STATUS_MORE_ENTRIES) {
if (m_AnsiKeywordName || m_UnicodeKeywordName) {
Status = AppendStringToResultBuffer(m_AnsiKeywordName,
m_UnicodeKeywordName,
FALSE
);
if (!NT_SUCCESS( Status )) {
return Status;
}
Status = AppendBufferToResultBuffer(NULL,
L"=",
1,
FALSE
);
if (!NT_SUCCESS( Status )) {
return Status;
}
}
if (m_IniFile.m_UnicodeFile) {
LPWSTR Src;
Src = (LPWSTR)m_UnicodeKeywordValue->Buffer;
while (*Src <= L' ' && m_UnicodeKeywordValue->Length) {
Src += 1;
m_UnicodeKeywordValue->Buffer = Src;
m_UnicodeKeywordValue->Length -= sizeof( WCHAR );
m_UnicodeKeywordValue->MaximumLength -= sizeof( WCHAR );
}
} else {
PBYTE Src;
Src = (PBYTE)m_AnsiKeywordValue->Buffer;
while (*Src <= ' ' && m_AnsiKeywordValue->Length) {
Src += 1;
m_AnsiKeywordValue->Buffer = (PCHAR)Src;
m_AnsiKeywordValue->Length -= sizeof( UCHAR );
m_AnsiKeywordValue->MaximumLength -= sizeof( UCHAR );
}
}
Status = AppendStringToResultBuffer(m_AnsiKeywordValue,
m_UnicodeKeywordValue,
TRUE
);
if (!NT_SUCCESS( Status )) {
return Status;
}
} else {
if (Status == STATUS_NO_MORE_ENTRIES) {
Status = STATUS_SUCCESS;
}
break;
}
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::FindSection()
{
NTSTATUS Status;
PANSI_STRING AnsiSectionName;
PUNICODE_STRING UnicodeSectionName;
while (TRUE)
{
Status = AdvanceTextPointer(STOP_AT_SECTION );
if (Status == STATUS_MORE_ENTRIES)
{
if (m_AnsiSectionName)
{
// Ansi ini file -- get the ansi parm
if (!GetApplicationName(&AnsiSectionName, NULL ))
{
return STATUS_INVALID_PARAMETER;
}
}
else
{
// we just need the unicode section name...
if (!GetApplicationName(NULL, &UnicodeSectionName ))
{
return STATUS_INVALID_PARAMETER;
}
}
if (m_AnsiSectionName == NULL)
{
if (RtlEqualUnicodeString( UnicodeSectionName,
m_UnicodeSectionName,
TRUE
)
)
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_MORE_ENTRIES;
}
}
else
{
if (RtlEqualString( AnsiSectionName, m_AnsiSectionName, TRUE ))
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_MORE_ENTRIES;
}
}
if (Status != STATUS_MORE_ENTRIES)
{
return Status;
}
}
else
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
}
}
NTSTATUS CWMI_FILE_IniFile::FindKeyword()
{
NTSTATUS Status = STATUS_SUCCESS;
PANSI_STRING AnsiKeywordName;
PUNICODE_STRING UnicodeKeywordName;
while (TRUE) {
Status = AdvanceTextPointer(STOP_AT_KEYWORD);
if (Status == STATUS_MORE_ENTRIES) {
// Here's the deal. We don't want to compare in Unicode
// unless both the ini and the input parm are Unicode,
// because we want to avoid the round-trip problem (we
// lose data when we convert Unicode -> Ansi (on disk) ->
// Unicode; since we don't get back the original Unicode
// string, lookups of previously stored data fail -- bug
// 426754). So if both are Unicode, great! -- use Unicode.
// Otherwise, use ansi for everything.
if (m_AnsiKeywordName) {
// Ansi ini file -- get the ansi parm
if (!GetVariableName(&AnsiKeywordName, NULL )) {
return STATUS_INVALID_PARAMETER;
}
} else {
//great, get the Unicode parm.
if (!GetVariableName(NULL, &UnicodeKeywordName )) {
return STATUS_INVALID_PARAMETER;
}
}
if (m_AnsiKeywordName == NULL) {
if (RtlEqualUnicodeString( UnicodeKeywordName,
m_UnicodeKeywordName,
TRUE
)
) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_MORE_ENTRIES;
}
} else {
if (RtlEqualString( AnsiKeywordName, m_AnsiKeywordName, TRUE )) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_MORE_ENTRIES;
}
}
if (Status != STATUS_MORE_ENTRIES) {
return Status;
}
} else {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
}
}
NTSTATUS CWMI_FILE_IniFile::AdvanceTextPointer( IN ULONG StopAt )
{
BOOL AllowNoEquals = FALSE;
if (StopAt == STOP_AT_NONSECTION)
{
StopAt = STOP_AT_KEYWORD;
AllowNoEquals = TRUE;
}
if (m_IniFile.m_UnicodeFile)
{
LPWSTR Name, EndOfName, Value, EndOfValue;
#undef INI_TEXT
#define INI_TEXT(quote) L##quote
LPWSTR Src = (LPWSTR)m_TextCurrent;
LPWSTR EndOfFile = (LPWSTR)m_TextEnd;
while (Src < EndOfFile)
{
//
// Find first non-blank character on a line. Skip blank lines
//
while (Src < EndOfFile && *Src <= INI_TEXT(' '))
{
Src++;
}
if (Src >= EndOfFile)
{
m_TextCurrent = Src;
break;
}
LPWSTR EndOfLine = Src;
LPWSTR EqualSign = NULL;
m_TextStart = Src;
while (EndOfLine < EndOfFile)
{
if (EqualSign == NULL && *EndOfLine == INI_TEXT('='))
{
EqualSign = ++EndOfLine;
}
else if (*EndOfLine == INI_TEXT('\r') || *EndOfLine == INI_TEXT('\n'))
{
if (*EndOfLine == INI_TEXT('\r'))
{
EndOfLine++;
}
if (*EndOfLine == INI_TEXT('\n'))
{
EndOfLine++;
}
break;
}
else
{
EndOfLine++;
}
}
if (*Src != INI_TEXT(';'))
{
if (*Src == INI_TEXT('['))
{
Name = Src + 1;
while (Name < EndOfLine && *Name <= INI_TEXT(' '))
{
Name++;
}
EndOfName = Name;
while (EndOfName < EndOfLine && *EndOfName != INI_TEXT(']'))
{
EndOfName++;
}
while (EndOfName > Name && EndOfName[ -1 ] <= INI_TEXT(' '))
{
EndOfName--;
}
m_SectionNameU.Buffer = Name;
m_SectionNameU.Length = (USHORT)((PCHAR)EndOfName - (PCHAR)Name);
m_SectionNameU.MaximumLength = m_SectionNameU.Length;
m_AnsiSectionName = NULL;
m_UnicodeSectionName = &m_SectionNameU;
if (StopAt == STOP_AT_SECTION)
{
m_TextCurrent = EndOfLine;
return STATUS_MORE_ENTRIES;
}
else if (StopAt == STOP_AT_KEYWORD)
{
return STATUS_NO_MORE_ENTRIES;
}
}
else if (AllowNoEquals || (EqualSign != NULL) )
{
if (EqualSign != NULL)
{
Name = Src;
EndOfName = EqualSign - 1;
while (EndOfName > Name && EndOfName[ -1 ] <= INI_TEXT(' '))
{
EndOfName--;
}
m_KeywordNameU.Buffer = Name;
m_KeywordNameU.Length = (USHORT)((PCHAR)EndOfName - (PCHAR)Name);
m_KeywordNameU.MaximumLength = m_KeywordNameU.Length;
m_AnsiKeywordName = NULL;
m_UnicodeKeywordName = &m_KeywordNameU;
Value = EqualSign;
}
else
{
Value = Src;
m_AnsiKeywordName = NULL;
m_UnicodeKeywordName = NULL;
}
EndOfValue = EndOfLine;
while (EndOfValue > Value && EndOfValue[ -1 ] <= INI_TEXT(' '))
{
EndOfValue--;
}
m_KeywordValueU.Buffer = Value;
m_KeywordValueU.Length = (USHORT)((PCHAR)EndOfValue - (PCHAR)Value);
m_KeywordValueU.MaximumLength = m_KeywordValueU.Length;
m_AnsiKeywordValue = NULL;
m_UnicodeKeywordValue = &m_KeywordValueU;
if (StopAt == STOP_AT_KEYWORD)
{
m_TextCurrent = EndOfLine;
return STATUS_MORE_ENTRIES;
}
}
}
Src = EndOfLine;
}
}
else
{
PBYTE Src, EndOfLine, EqualSign, EndOfFile;
PBYTE Name, EndOfName, Value, EndOfValue;
#undef INI_TEXT
#define INI_TEXT(quote) quote
Src = (PBYTE)m_TextCurrent;
EndOfFile = (PBYTE)m_TextEnd;
while (Src < EndOfFile)
{
//
// Find first non-blank character on a line. Skip blank lines
//
while (Src < EndOfFile && *Src <= INI_TEXT(' '))
{
Src++;
}
if (Src >= EndOfFile)
{
m_TextCurrent = Src;
break;
}
EndOfLine = Src;
EqualSign = NULL;
m_TextStart = Src;
while (EndOfLine < EndOfFile)
{
if (EqualSign == NULL && *EndOfLine == INI_TEXT('='))
{
EqualSign = ++EndOfLine;
}
else if (*EndOfLine == INI_TEXT('\r') || *EndOfLine == INI_TEXT('\n'))
{
if (*EndOfLine == INI_TEXT('\r'))
{
EndOfLine++;
}
if (*EndOfLine == INI_TEXT('\n')) {
EndOfLine++;
}
break;
}
else
{
EndOfLine++;
}
}
if (*Src != INI_TEXT(';'))
{
if (*Src == INI_TEXT('['))
{
Name = Src + 1;
while (Name < EndOfLine && *Name <= INI_TEXT(' '))
{
Name++;
}
EndOfName = Name;
while (EndOfName < EndOfLine)
{
if (*EndOfName == INI_TEXT(']'))
{
break;
}
if (IsDBCSLeadByte(*EndOfName))
{
EndOfName++;
}
EndOfName++;
}
while (EndOfName > Name && EndOfName[ -1 ] <= INI_TEXT(' '))
{
EndOfName--;
}
m_SectionName.Buffer = (PCHAR)Name;
m_SectionName.Length = (USHORT)((PCHAR)EndOfName - (PCHAR)Name);
m_SectionName.MaximumLength = m_SectionName.Length;
m_AnsiSectionName = &m_SectionName;
m_UnicodeSectionName = NULL;
if (StopAt == STOP_AT_SECTION)
{
m_TextCurrent = EndOfLine;
return STATUS_MORE_ENTRIES;
}
else if (StopAt == STOP_AT_KEYWORD)
{
return STATUS_NO_MORE_ENTRIES;
}
}
else if (AllowNoEquals || (EqualSign != NULL))
{
if (EqualSign != NULL)
{
Name = Src;
EndOfName = EqualSign - 1;
while (EndOfName > Name && EndOfName[ -1 ] <= INI_TEXT(' '))
{
EndOfName--;
}
m_KeywordName.Buffer = (PCHAR)Name;
m_KeywordName.Length = (USHORT)((PCHAR)EndOfName - (PCHAR)Name);
m_KeywordName.MaximumLength = m_KeywordName.Length;
m_AnsiKeywordName = &m_KeywordName;
m_UnicodeKeywordName = NULL;
Value = EqualSign;
}
else
{
Value = Src;
m_AnsiKeywordName = NULL;
m_UnicodeKeywordName = NULL;
}
EndOfValue = EndOfLine;
while (EndOfValue > Value && EndOfValue[ -1 ] <= INI_TEXT(' '))
{
EndOfValue--;
}
m_KeywordValue.Buffer = (PCHAR)Value;
m_KeywordValue.Length = (USHORT)((PCHAR)EndOfValue - (PCHAR)Value);
m_KeywordValue.MaximumLength = m_KeywordValue.Length;
m_AnsiKeywordValue = &m_KeywordValue;
m_UnicodeKeywordValue = NULL;
if (StopAt == STOP_AT_KEYWORD)
{
m_TextCurrent = EndOfLine;
return STATUS_MORE_ENTRIES;
}
}
}
Src = EndOfLine;
}
}
return STATUS_NO_MORE_ENTRIES;
}
BOOL CWMI_FILE_IniFile::GetApplicationName(
OUT PANSI_STRING *ApplicationName OPTIONAL,
OUT PUNICODE_STRING *ApplicationNameU OPTIONAL
)
{
NTSTATUS Status;
if (ApplicationName)
{
if (m_ApplicationName.Length == 0)
{
m_ApplicationName.Buffer = new char[(m_ApplicationNameU.Length * sizeof(WORD)) + 1]; //MBCS strings
m_ApplicationName.MaximumLength = (m_ApplicationNameU.Length * sizeof(WORD)) + 1;
Status = RtlUnicodeStringToAnsiString( &m_ApplicationName, &m_ApplicationNameU, FALSE );
if (!NT_SUCCESS( Status ))
{
return FALSE;
}
}
*ApplicationName = &m_ApplicationName;
return TRUE;
}
if (ApplicationNameU)
{
if (m_ApplicationNameU.Length == 0)
{
return FALSE;
}
*ApplicationNameU = &m_ApplicationNameU;
return TRUE;
}
return FALSE;
}
BOOL CWMI_FILE_IniFile::GetVariableName(
OUT PANSI_STRING *VariableName OPTIONAL,
OUT PUNICODE_STRING *VariableNameU OPTIONAL
)
{
NTSTATUS Status;
if (ARGUMENT_PRESENT( VariableName ))
{
if (m_VariableName.Length == 0)
{
m_VariableName.Buffer = new char[(m_VariableNameU.Length * sizeof(WORD)) + 1]; //MBCS strings
m_VariableName.MaximumLength = (m_VariableNameU.Length * sizeof(WORD)) + 1;
Status = RtlUnicodeStringToAnsiString( &m_VariableName, &m_VariableNameU, FALSE );
if (!NT_SUCCESS( Status ))
{
return FALSE;
}
}
*VariableName = &m_VariableName;
return TRUE;
}
if (ARGUMENT_PRESENT( VariableNameU ))
{
if (m_VariableNameU.Length == 0)
{
return FALSE;
}
*VariableNameU = &m_VariableNameU;
return TRUE;
}
return FALSE;
}
BOOL CWMI_FILE_IniFile::GetVariableValue(
OUT PBYTE *VariableValue OPTIONAL,
OUT LPWSTR *VariableValueU OPTIONAL,
OUT PULONG VariableValueLength
)
{
NTSTATUS Status;
ULONG Index;
if (VariableValue)
{
if (m_ValueLength == 0)
{
if (m_ValueBufferU == NULL || m_ValueLengthU == 0)
{
*VariableValue = NULL;
*VariableValueLength = sizeof ( UCHAR );
return TRUE;
}
m_ValueBuffer = new char[m_ValueLengthU + 1]; //DBCS
m_ValueLength = m_ValueLengthU;
Status = RtlUnicodeToMultiByteN( (PCHAR)m_ValueBuffer,
m_ValueLength,
&Index,
m_ValueBufferU,
m_ValueLengthU
);
if (!NT_SUCCESS( Status ))
{
return FALSE;
}
// Set real converted size
m_ValueLength = Index;
m_ValueBuffer[ Index ] = '\0'; // Null terminate converted value
}
else
{
Index = m_ValueLength;
}
*VariableValue = (PBYTE)m_ValueBuffer;
*VariableValueLength = Index + 1;
return TRUE;
}
if (VariableValueU)
{
if (m_ValueLengthU == 0)
{
if (m_ValueBuffer == NULL || m_ValueLength == 0)
{
*VariableValueU = NULL;
*VariableValueLength = sizeof ( WCHAR );
return TRUE;
}
else
{
return FALSE;
}
}
else
{
Index = m_ValueLengthU / sizeof( WCHAR );
}
*VariableValueU = m_ValueBufferU;
*VariableValueLength = (Index + 1) * sizeof( WCHAR );
return TRUE;
}
return FALSE;
}
NTSTATUS CWMI_FILE_IniFile::AppendStringToResultBuffer(
IN PANSI_STRING String OPTIONAL,
IN PUNICODE_STRING StringU OPTIONAL,
IN BOOL IncludeNull
)
{
if (String)
{
if (StringU)
{
return STATUS_INVALID_PARAMETER;
}
else
{
return AppendBufferToResultBuffer((PBYTE)String->Buffer,
NULL,
String->Length,
IncludeNull
);
}
}
else if (StringU)
{
if (String)
{
return STATUS_INVALID_PARAMETER;
}
else
{
return AppendBufferToResultBuffer(NULL,
StringU->Buffer,
StringU->Length / sizeof( WCHAR ),
IncludeNull
);
}
}
else
{
return STATUS_INVALID_PARAMETER;
}
}
NTSTATUS CWMI_FILE_IniFile::AppendBufferToResultBuffer(
IN PBYTE Buffer OPTIONAL,
IN LPWSTR BufferU OPTIONAL,
IN ULONG Chars,
IN BOOL IncludeNull
)
{
NTSTATUS Status, OverflowStatus;
ULONG Index;
OverflowStatus = STATUS_SUCCESS;
if (Buffer)
{
if (BufferU)
{
return STATUS_INVALID_PARAMETER;
}
else
{
ULONG CharsMbcs = Chars;
//
// In this point, Chars does not contains proper value for Unicode.
// because. Chars was computed based on DBCS string length,
// This is correct, sources string is DBCS, then
// if the source is not DBCS. we just adjust it here.
//
Status = RtlMultiByteToUnicodeSize(&Chars,(PCSTR)Buffer,Chars);
if (!NT_SUCCESS( Status ))
{
return Status;
}
Chars /= sizeof(WCHAR);
if (m_ResultChars + Chars >= m_ResultMaxChars)
{
OverflowStatus = STATUS_BUFFER_OVERFLOW;
Chars = m_ResultMaxChars - m_ResultChars;
if (Chars) {
Chars -= 1;
}
}
if (Chars)
{
Status = RtlMultiByteToUnicodeN( (PWSTR)(m_ResultBufferU + m_ResultChars),
Chars * sizeof( WCHAR ),
&Index,
(PCSTR)Buffer,
CharsMbcs
);
if (!NT_SUCCESS( Status ))
{
return Status;
}
m_ResultChars += Chars;
}
}
}
else if (BufferU)
{
if (Buffer)
{
return STATUS_INVALID_PARAMETER;
}
else
{
ULONG CharsUnicode = Chars;
if (m_ResultChars + Chars >= m_ResultMaxChars)
{
OverflowStatus = STATUS_BUFFER_OVERFLOW;
Chars = m_ResultMaxChars - m_ResultChars;
if (Chars)
{
Chars -= 1;
}
}
if (Chars)
{
memcpy( (LPVOID)(m_ResultBufferU + m_ResultChars), BufferU, Chars * sizeof( WCHAR ) );
m_ResultChars += Chars;
}
}
}
if (IncludeNull)
{
if (m_ResultChars + 1 >= m_ResultMaxChars)
{
return STATUS_BUFFER_OVERFLOW;
}
m_ResultBufferU[ m_ResultChars ] = L'\0';
m_ResultChars += 1;
}
return OverflowStatus;
}
NTSTATUS CWMI_FILE_IniFile::WriteKeywordValue(
IN PUNICODE_STRING VariableName OPTIONAL
)
{
NTSTATUS Status;
BOOL InsertSectionName;
BOOL InsertKeywordName;
ULONG InsertAmount, n;
PANSI_STRING AnsiSectionName;
PANSI_STRING AnsiKeywordName;
PUNICODE_STRING UnicodeSectionName;
PUNICODE_STRING UnicodeKeywordName;
PBYTE AnsiKeywordValue;
LPWSTR UnicodeKeywordValue;
ULONG ValueLength;
ULONG DeleteLength;
PVOID AddressInFile;
InsertAmount = 0;
Status = FindSection( );
if (!NT_SUCCESS( Status ))
{
AddressInFile = m_TextEnd;
if (m_IniFile.m_UnicodeFile)
{
if (!GetApplicationName(NULL, &UnicodeSectionName ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of [SectionName]\r\n
//
InsertAmount += (1 + 1 + 2) * sizeof( WCHAR );
InsertAmount += UnicodeSectionName->Length;
}
else
{
if (!GetApplicationName(&AnsiSectionName, NULL ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of [SectionName]\r\n
//
InsertAmount += (1 + 1 + 2) * sizeof( UCHAR );
InsertAmount += AnsiSectionName->Length;
}
InsertSectionName = TRUE;
}
else
{
InsertSectionName = FALSE;
Status = FindKeyword( );
}
if (!NT_SUCCESS( Status ))
{
if (!InsertSectionName)
{
AddressInFile = m_TextCurrent;
}
if (m_IniFile.m_UnicodeFile)
{
if (!GetVariableName(NULL, &UnicodeKeywordName ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of Keyword=\r\n
//
InsertAmount += (1 + 2) * sizeof( WCHAR );
InsertAmount += UnicodeKeywordName->Length;
}
else
{
if (!GetVariableName(&AnsiKeywordName, NULL ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of Keyword=\r\n
//
InsertAmount += (1 + 2) * sizeof( UCHAR );
InsertAmount += AnsiKeywordName->Length;
}
InsertKeywordName = TRUE;
}
else
{
if (m_IniFile.m_UnicodeFile)
{
AddressInFile = m_UnicodeKeywordValue->Buffer;
}
else
{
AddressInFile = m_AnsiKeywordValue->Buffer;
}
InsertKeywordName = FALSE;
}
if (m_IniFile.m_UnicodeFile)
{
if (!GetVariableValue( NULL, &UnicodeKeywordValue, &ValueLength ))
{
return STATUS_INVALID_PARAMETER;
}
ValueLength -= sizeof( WCHAR );
if (InsertAmount == 0)
{
return ModifyMappedFile(m_UnicodeKeywordValue->Buffer,
m_UnicodeKeywordValue->Length,
UnicodeKeywordValue,
ValueLength
);
}
//
// Add in size of value
//
InsertAmount += ValueLength;
}
else
{
if (!GetVariableValue(&AnsiKeywordValue, NULL, &ValueLength ))
{
return STATUS_INVALID_PARAMETER;
}
ValueLength -= sizeof( UCHAR );
if (InsertAmount == 0)
{
return ModifyMappedFile(m_AnsiKeywordValue->Buffer,
m_AnsiKeywordValue->Length,
AnsiKeywordValue,
ValueLength
);
}
//
// Add in size of value
//
InsertAmount += ValueLength;
}
PVOID InsertBuffer = NULL;
InsertBuffer = (PVOID) new BYTE[InsertAmount + sizeof( L'\0' )];
try
{
if (m_IniFile.m_UnicodeFile)
{
LPWSTR Src, Dst;
Dst = (LPWSTR)InsertBuffer;
if (InsertSectionName)
{
*Dst++ = L'[';
Src = UnicodeSectionName->Buffer;
n = UnicodeSectionName->Length / sizeof( WCHAR );
while (n--)
{
*Dst++ = *Src++;
}
*Dst++ = L']';
*Dst++ = L'\r';
*Dst++ = L'\n';
}
if (InsertKeywordName)
{
Src = UnicodeKeywordName->Buffer;
n = UnicodeKeywordName->Length / sizeof( WCHAR );
while (n--)
{
*Dst++ = *Src++;
}
*Dst++ = L'=';
}
Src = UnicodeKeywordValue;
n = ValueLength / sizeof( WCHAR );
while (n--)
{
*Dst++ = *Src++;
}
if (InsertKeywordName)
{
*Dst++ = L'\r';
*Dst++ = L'\n';
}
}
else
{
PBYTE Src, Dst;
Dst = (PBYTE)InsertBuffer;
if (InsertSectionName)
{
*Dst++ = '[';
Src = (PBYTE)AnsiSectionName->Buffer;
n = AnsiSectionName->Length;
while (n--)
{
*Dst++ = *Src++;
}
*Dst++ = ']';
*Dst++ = '\r';
*Dst++ = '\n';
}
if (InsertKeywordName)
{
Src = (PBYTE)AnsiKeywordName->Buffer;
n = AnsiKeywordName->Length;
while (n--)
{
*Dst++ = *Src++;
}
*Dst++ = '=';
}
Src = AnsiKeywordValue;
n = ValueLength;
while (n--)
{
*Dst++ = *Src++;
}
if (InsertKeywordName)
{
*Dst++ = '\r';
*Dst++ = '\n';
}
}
Status = ModifyMappedFile(AddressInFile,
0,
InsertBuffer,
InsertAmount
);
delete [] ((BYTE*) InsertBuffer);
InsertBuffer = NULL;
}
catch(...)
{
if (InsertBuffer)
{
delete [] ((BYTE*) InsertBuffer);
InsertBuffer = NULL;
}
throw;
}
return Status;
}
NTSTATUS CWMI_FILE_IniFile::ModifyMappedFile(
IN PVOID AddressInFile,
IN ULONG SizeToRemove,
IN PVOID InsertBuffer,
IN ULONG InsertAmount
)
{
NTSTATUS Status;
ULONG NewEndOfFile, UpdateOffset, UpdateLength;
NewEndOfFile = m_IniFile.m_EndOfFile - SizeToRemove + InsertAmount;
if (NewEndOfFile > m_IniFile.m_CommitSize)
{
if (NewEndOfFile > m_IniFile.m_RegionSize)
{
return STATUS_BUFFER_OVERFLOW;
}
m_IniFile.m_CommitSize = NewEndOfFile;
Status = NtAllocateVirtualMemory( NtCurrentProcess(),
&m_IniFile.m_BaseAddress,
0,
&m_IniFile.m_CommitSize,
MEM_COMMIT,
PAGE_READWRITE
);
if (!NT_SUCCESS( Status )) {
return Status;
}
m_IniFile.m_EndOfFile = NewEndOfFile;
}
UpdateOffset = (ULONG)((PCHAR)AddressInFile - (PCHAR)(m_IniFile.m_BaseAddress)),
UpdateLength = (ULONG)((PCHAR)m_TextEnd - (PCHAR)AddressInFile) + InsertAmount - SizeToRemove;
//
// Are we deleting more than we are inserting?
//
if (SizeToRemove > InsertAmount)
{
//
// Yes copy over insert string.
//
RtlMoveMemory( AddressInFile, InsertBuffer, InsertAmount );
//
// Delete remaining text after insertion string by moving it
// up
//
RtlMoveMemory( (PCHAR)AddressInFile + InsertAmount,
(PCHAR)AddressInFile + SizeToRemove,
UpdateLength - InsertAmount
);
}
else if (InsertAmount > 0)
{
//
// Are we deleting less than we are inserting?
//
if (SizeToRemove < InsertAmount)
{
//
// Move text down to make room for insertion
//
RtlMoveMemory( (PCHAR)AddressInFile + InsertAmount - SizeToRemove,
(PCHAR)AddressInFile,
UpdateLength - InsertAmount + SizeToRemove
);
}
else
{
//
// Deleting and inserting same amount, update just that text as
// no shifting was done.
//
UpdateLength = InsertAmount;
}
//
// Copy over insert string
//
RtlMoveMemory( AddressInFile, InsertBuffer, InsertAmount );
}
else
{
//
// Nothing to change, as InsertAmount and SizeToRemove are zero
//
return STATUS_SUCCESS;
}
if (m_IniFile.m_EndOfFile != NewEndOfFile)
{
m_IniFile.m_EndOfFile = NewEndOfFile;
}
if (UpdateOffset < m_IniFile.m_UpdateOffset)
{
m_IniFile.m_UpdateOffset = UpdateOffset;
}
if ((UpdateOffset + UpdateLength) > m_IniFile.m_UpdateEndOffset)
{
m_IniFile.m_UpdateEndOffset = UpdateOffset + UpdateLength;
}
return STATUS_SUCCESS;
}
NTSTATUS CWMI_FILE_IniFile::WriteSection()
{
NTSTATUS Status;
BOOLEAN InsertSectionName;
ULONG InsertAmount, n;
PANSI_STRING AnsiSectionName;
PUNICODE_STRING UnicodeSectionName;
PBYTE AnsiKeywordValue, s;
PWSTR UnicodeKeywordValue, w;
ULONG ValueLength, SizeToRemove;
PVOID AddressInFile;
InsertAmount = 0;
Status = FindSection();
if (!NT_SUCCESS( Status ))
{
AddressInFile = m_TextEnd;
if (m_IniFile.m_UnicodeFile)
{
if (!GetApplicationName(NULL, &UnicodeSectionName ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of [SectionName]\r\n
//
InsertAmount += (1 + 1 + 2) * sizeof( WCHAR );
InsertAmount += UnicodeSectionName->Length;
}
else
{
if (!GetApplicationName(&AnsiSectionName, NULL ))
{
return STATUS_INVALID_PARAMETER;
}
//
// Add in size of [SectionName]\r\n
//
InsertAmount += (1 + 1 + 2) * sizeof( UCHAR );
InsertAmount += AnsiSectionName->Length;
}
InsertSectionName = TRUE;
SizeToRemove = 0;
}
else
{
AddressInFile = m_TextCurrent;
while (TRUE)
{
//
// For delete operations need to iterate all lines in section,
// not just those that have an = on them. Otherwise sections like
// [foo]
// a
// b = c
// d
//
// don't get deleted properly.
//
Status = AdvanceTextPointer(STOP_AT_KEYWORD);
if (Status == STATUS_MORE_ENTRIES)
{
}
else if (Status == STATUS_NO_MORE_ENTRIES)
{
SizeToRemove = (ULONG)((PCHAR)m_TextCurrent - (PCHAR)AddressInFile);
break;
}
else
{
return Status;
}
}
InsertSectionName = FALSE;
}
if (m_IniFile.m_UnicodeFile)
{
if (!GetVariableValue(NULL, &UnicodeKeywordValue, &ValueLength ))
{
return STATUS_INVALID_PARAMETER;
}
ValueLength -= sizeof( WCHAR );
//
// Add in size of value, + \r\n for each line
//
w = UnicodeKeywordValue;
InsertAmount += ValueLength;
while (w && *w)
{
while (*w++)
{
}
InsertAmount += (2-1) * sizeof( WCHAR ); // Subtract out NULL byte already in ValueLength
}
}
else
{
if (!GetVariableValue(&AnsiKeywordValue, NULL, &ValueLength ))
{
return STATUS_INVALID_PARAMETER;
}
ValueLength -= sizeof( UCHAR );
//
// Add in size of value, + \r\n for each line
//
s = AnsiKeywordValue;
InsertAmount += ValueLength;
while (s && *s)
{
while (*s++)
{
}
InsertAmount += 2 - 1; // Subtract out NULL byte already in ValueLength
}
}
PVOID InsertBuffer = NULL;
InsertBuffer = (PVOID) new BYTE[InsertAmount + sizeof( L'\0' )];
try
{
if (m_IniFile.m_UnicodeFile)
{
PWSTR Src, Dst;
Dst = (PWSTR)InsertBuffer;
if (InsertSectionName)
{
*Dst++ = L'[';
Src = UnicodeSectionName->Buffer;
n = UnicodeSectionName->Length / sizeof( WCHAR );
while (n--)
{
*Dst++ = *Src++;
}
*Dst++ = L']';
*Dst++ = L'\r';
*Dst++ = L'\n';
}
Src = UnicodeKeywordValue;
while (*Src)
{
while (*Dst = *Src++)
{
Dst += 1;
}
*Dst++ = L'\r';
*Dst++ = L'\n';
}
}
else
{
PBYTE Src, Dst;
Dst = (PBYTE)InsertBuffer;
if (InsertSectionName) {
*Dst++ = '[';
Src = (PBYTE)AnsiSectionName->Buffer;
n = AnsiSectionName->Length;
while (n--) {
*Dst++ = *Src++;
}
*Dst++ = ']';
*Dst++ = '\r';
*Dst++ = '\n';
}
Src = AnsiKeywordValue;
while (*Src)
{
while (*Dst = *Src++)
{
Dst += 1;
}
*Dst++ = '\r';
*Dst++ = '\n';
}
}
Status = ModifyMappedFile(AddressInFile,
SizeToRemove,
InsertBuffer,
InsertAmount
);
delete [] ((BYTE*) InsertBuffer);
InsertBuffer = NULL;
}
catch(...)
{
if (InsertBuffer)
{
delete [] ((BYTE*) InsertBuffer);
InsertBuffer = NULL;
}
throw;
}
return Status;
}