windows-nt/Source/XPSP1/NT/base/pnp/setupapi/filelog.c
2020-09-26 16:20:57 +08:00

1054 lines
28 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
filelog.c
Abstract:
Routines for logging files in copy logs.
Author:
Ted Miller (tedm) 14-Jun-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Define name of system log file and various strings used
// within it.
//
PCTSTR SystemLogFileName = TEXT("repair\\setup.log");
PCTSTR NtFileSectionName = TEXT("Files.WinNT");
//
// Define structure used internally to represent a file log file.
//
typedef struct _SETUP_FILE_LOG {
PCTSTR FileName;
BOOL QueryOnly;
BOOL SystemLog;
} SETUP_FILE_LOG, *PSETUP_FILE_LOG;
#ifdef UNICODE
//
// ANSI version
//
HSPFILELOG
SetupInitializeFileLogA(
IN PCSTR LogFileName, OPTIONAL
IN DWORD Flags
)
{
PWSTR p;
DWORD d;
HSPFILELOG h;
if(LogFileName) {
d = pSetupCaptureAndConvertAnsiArg(LogFileName,&p);
if(d != NO_ERROR) {
SetLastError(d);
return(INVALID_HANDLE_VALUE);
}
} else {
p = NULL;
}
h = SetupInitializeFileLogW(p,Flags);
d = GetLastError();
if(p) {
MyFree(p);
}
SetLastError(d);
return(h);
}
#else
//
// Unicode stub
//
HSPFILELOG
SetupInitializeFileLogW(
IN PCWSTR LogFileName, OPTIONAL
IN DWORD Flags
)
{
UNREFERENCED_PARAMETER(LogFileName);
UNREFERENCED_PARAMETER(Flags);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(INVALID_HANDLE_VALUE);
}
#endif
HSPFILELOG
SetupInitializeFileLog(
IN PCTSTR LogFileName, OPTIONAL
IN DWORD Flags
)
/*++
Routine Description:
Initialize a file for logging or query. The caller may specify that he
wishes to use the system log, which is where the system tracks which
files are installed as part of Windows NT; or the caller may specify
any other random file to be used as a log.
If the user specifies the system log not for query only, the function fails
unless the user is administrator. However this only guarantees security
on the log when the system is installed on a drive with a filesystem that
supports ACLs; the log is simply a file and anyone can access it unless
setup can secure it via ACLs.
Arguments:
LogFileName - if specified, supplies the filename of the file to be used
as the log file. Must be specified if Flags does not include
SPFILELOG_SYSTEMLOG. Must not be specified if Flags includes
SPFILELOG_SYSTEMLOG.
Flags - supplies a combination of the following values:
SPFILELOG_SYSTEMLOG - use the Windows NT system file log, which is used
to track what files are installed as part of Windows NT. The user must
be administrator to specify this option unless SPFILELOG_QUERYONLY
is specified, and LogFileName must not be specified. May not be specified
in combination with SPFILELOG_FORCENEW.
SPFILELOG_FORCENEW - if the log file exists, it will be overwritten.
If the log file exists and this flag is not specified then additional
files are added to the existing log. May not be specified in combination
with SPFILELOG_SYSTEMLOG.
SPFILELOG_QUERYONLY - open the log file for querying only. The user
Return Value:
Handle to file log or INVALID_HANDLE_VALUE if the function fails;
extended error info is available via GetLastError() in this case.
--*/
{
TCHAR SysLogFileName[MAX_PATH];
PCTSTR FileName;
PSETUP_FILE_LOG FileLog;
DWORD Err;
HANDLE hFile;
//
// Validate args.
//
Err = ERROR_INVALID_PARAMETER;
if(Flags & SPFILELOG_SYSTEMLOG) {
if((Flags & SPFILELOG_FORCENEW) || LogFileName) {
goto clean0;
}
//
// User must be administrator to gain write access to system log.
//
if(!(Flags & SPFILELOG_QUERYONLY) && !pSetupIsUserAdmin()) {
Err = ERROR_ACCESS_DENIED;
goto clean0;
}
//
// uses actual windows directory instead of hydra remapped
//
lstrcpyn(SysLogFileName,WindowsDirectory,MAX_PATH);
pSetupConcatenatePaths(SysLogFileName,SystemLogFileName,MAX_PATH,NULL);
FileName = SysLogFileName;
} else {
if(LogFileName) {
if(!lstrcpyn(SysLogFileName,LogFileName,MAX_PATH)) {
//
// lstrcpyn faulted, LogFileName must be bad
//
Err = ERROR_INVALID_PARAMETER;
goto clean0;
}
FileName = SysLogFileName;
} else {
goto clean0;
}
}
//
// Allocate a log file structure.
//
Err = ERROR_NOT_ENOUGH_MEMORY;
if(FileLog = MyMalloc(sizeof(SETUP_FILE_LOG))) {
FileLog->FileName = DuplicateString(FileName);
if(!FileLog->FileName) {
goto clean1;
}
} else {
goto clean0;
}
FileLog->QueryOnly = ((Flags & SPFILELOG_QUERYONLY) != 0);
FileLog->SystemLog = ((Flags & SPFILELOG_SYSTEMLOG) != 0);
//
// See if the file exists.
//
if(FileExists(FileName,NULL)) {
//
// If it's the system log, take ownership of the file.
//
if(FileLog->SystemLog) {
Err = TakeOwnershipOfFile(FileName);
if(Err != NO_ERROR) {
goto clean2;
}
}
//
// Set attribute to normal. This ensures we can delete/open/create the file
// as appropriate below.
//
if(!SetFileAttributes(FileName,FILE_ATTRIBUTE_NORMAL)) {
Err = GetLastError();
goto clean2;
}
//
// Delete the file now if the caller specified the force_new flag.
//
if((Flags & SPFILELOG_FORCENEW) && !DeleteFile(FileName)) {
Err = GetLastError();
goto clean2;
}
}
//
// Make sure we can open/create the file by attempting to do that now.
//
hFile = CreateFile(
FileName,
GENERIC_READ | (FileLog->QueryOnly ? 0 : GENERIC_WRITE),
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS, // Open if exists, create if not
FILE_ATTRIBUTE_NORMAL,
NULL
);
if(hFile == INVALID_HANDLE_VALUE) {
Err = GetLastError();
goto clean2;
}
CloseHandle(hFile);
return((HSPFILELOG)FileLog);
clean2:
MyFree(FileLog->FileName);
clean1:
MyFree(FileLog);
clean0:
SetLastError(Err);
return(INVALID_HANDLE_VALUE);
}
BOOL
SetupTerminateFileLog(
IN HSPFILELOG FileLogHandle
)
/*++
Routine Description:
Releases resources associated with a file log.
Arguments:
FileLogHandle - supplies the handle to the file log, as returned
by SetupInitializeLogFile.
Return Value:
Boolean value indicating outcome. If FALSE, the caller can use
GetLastError() to get extended error info.
--*/
{
PSETUP_FILE_LOG FileLog;
DWORD Err;
FileLog = (PSETUP_FILE_LOG)FileLogHandle;
Err = NO_ERROR;
try {
MyFree(FileLog->FileName);
MyFree(FileLog);
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
SetLastError(Err);
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
SetupLogFileA(
IN HSPFILELOG FileLogHandle,
IN PCSTR LogSectionName, OPTIONAL
IN PCSTR SourceFilename,
IN PCSTR TargetFilename,
IN DWORD Checksum, OPTIONAL
IN PCSTR DiskTagfile, OPTIONAL
IN PCSTR DiskDescription, OPTIONAL
IN PCSTR OtherInfo, OPTIONAL
IN DWORD Flags
)
{
PWSTR logsectionname = NULL;
PWSTR sourcefilename = NULL;
PWSTR targetfilename = NULL;
PWSTR disktagfile = NULL;
PWSTR diskdescription = NULL;
PWSTR otherinfo = NULL;
DWORD d;
BOOL b;
if(LogSectionName) {
d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
} else {
d = NO_ERROR;
}
if(d == NO_ERROR) {
d = pSetupCaptureAndConvertAnsiArg(SourceFilename,&sourcefilename);
}
if(d == NO_ERROR) {
d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
}
if((d == NO_ERROR) && DiskTagfile) {
d = pSetupCaptureAndConvertAnsiArg(DiskTagfile,&disktagfile);
}
if((d == NO_ERROR) && DiskDescription) {
d = pSetupCaptureAndConvertAnsiArg(DiskDescription,&diskdescription);
}
if((d == NO_ERROR) && OtherInfo) {
d = pSetupCaptureAndConvertAnsiArg(OtherInfo,&otherinfo);
}
if(d == NO_ERROR) {
b = SetupLogFileW(
FileLogHandle,
logsectionname,
sourcefilename,
targetfilename,
Checksum,
disktagfile,
diskdescription,
otherinfo,
Flags
);
d = GetLastError();
} else {
b = FALSE;
}
if(logsectionname) {
MyFree(logsectionname);
}
if(sourcefilename) {
MyFree(sourcefilename);
}
if(targetfilename) {
MyFree(targetfilename);
}
if(disktagfile) {
MyFree(disktagfile);
}
if(diskdescription) {
MyFree(diskdescription);
}
if(otherinfo) {
MyFree(otherinfo);
}
SetLastError(d);
return(b);
}
#else
//
// Unicode stub
//
BOOL
SetupLogFileW(
IN HSPFILELOG FileLogHandle,
IN PCWSTR LogSectionName, OPTIONAL
IN PCWSTR SourceFilename,
IN PCWSTR TargetFilename,
IN DWORD Checksum, OPTIONAL
IN PCWSTR DiskTagfile, OPTIONAL
IN PCWSTR DiskDescription, OPTIONAL
IN PCWSTR OtherInfo, OPTIONAL
IN DWORD Flags
)
{
UNREFERENCED_PARAMETER(FileLogHandle);
UNREFERENCED_PARAMETER(LogSectionName);
UNREFERENCED_PARAMETER(SourceFilename);
UNREFERENCED_PARAMETER(TargetFilename);
UNREFERENCED_PARAMETER(Checksum);
UNREFERENCED_PARAMETER(DiskTagfile);
UNREFERENCED_PARAMETER(DiskDescription);
UNREFERENCED_PARAMETER(OtherInfo);
UNREFERENCED_PARAMETER(Flags);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
SetupLogFile(
IN HSPFILELOG FileLogHandle,
IN PCTSTR LogSectionName, OPTIONAL
IN PCTSTR SourceFilename,
IN PCTSTR TargetFilename,
IN DWORD Checksum, OPTIONAL
IN PCTSTR DiskTagfile, OPTIONAL
IN PCTSTR DiskDescription, OPTIONAL
IN PCTSTR OtherInfo, OPTIONAL
IN DWORD Flags
)
/*++
Routine Description:
Logs a file into a file log.
Arguments:
FileLogHandle - supplies the handle to the file log, as returned
by SetupInitializeLogFile(). The caller must not have passed
SPFILELOG_QUERYONLY when the log file was opened/initialized.
LogSectionName - required if SPFILELOG_SYSTEMLOG was not passed when
the file log was opened/initialized; optional otherwise.
Supplies the name for a logical grouping of files within the log.
SourceFilename - supplies the name of the file as it exists on the
source media from which it was installed. This name should be in
whatever format is meaningful to the caller.
TargetFilename - supplies the name of the file as it exists on the
Target. This name should be in whatever format is meaningful to
the caller.
Checksum - supplies a 32-bit checksum value. Required for the system log.
DiskTagfile - Gives the tagfile for the media from which the file
was installed. Required for the system log if SPFILELOG_OEMFILE
is specified. Ignored for the system log if SPFILELOG_OEMFILE is
not specified.
DiskDescription - Gives the human-readable description for the media
from which the file was installed. Required for the system log if
SPFILELOG_OEMFILE is specified. Ignored for the system log if
SPFILELOG_OEMFILE is not specified.
OtherInfo - supplies additional information to be associated with the
file.
Flags - may supply SPFILELOG_OEMFILE, which is meaningful only for
the system log and indicates that the file is not an MS-supplied file.
Can be used to convert an existing file's entry such as when an oem
overwrites an MS-supplied system file.
Return Value:
Boolean value indicating outcome. If FALSE, the caller can use
GetLastError() to get extended error info.
--*/
{
PSETUP_FILE_LOG FileLog;
DWORD Err;
BOOL b;
TCHAR LineToWrite[512];
TCHAR sourceFilename[MAX_PATH];
PTSTR p,Directory;
FileLog = (PSETUP_FILE_LOG)FileLogHandle;
try {
//
// Validate params. Handle must be for non-queryonly.
// If for the system log and oem file is specified,
// caller must have passed disk tagfile and description.
// There's really no way to validate the checksum because
// 0 is a perfectly valid one.
// If not the system log, caller must have passed a section name.
//
if(FileLog->QueryOnly
|| ( FileLog->SystemLog
&& (Flags & SPFILELOG_OEMFILE)
&& (!DiskTagfile || !DiskDescription))
|| (!FileLog->SystemLog && !LogSectionName))
{
Err = ERROR_INVALID_PARAMETER;
} else {
//
// Use default section if not specified.
//
if(!LogSectionName) {
MYASSERT(FileLog->SystemLog);
LogSectionName = NtFileSectionName;
}
//
// IF THIS LOGIC IS CHANGED BE SURE TO CHANGE
// SetupQueryFileLog() AS WELL!
//
// Split up the source filename into filename and
// directory if appropriate.
//
lstrcpyn(sourceFilename,SourceFilename,MAX_PATH);
if(FileLog->SystemLog && (Flags & SPFILELOG_OEMFILE)) {
if(p = _tcsrchr(sourceFilename,TEXT('\\'))) {
*p++ = 0;
Directory = p;
} else {
Directory = TEXT("\\");
}
} else {
Directory = TEXT("");
}
_sntprintf(
LineToWrite,
sizeof(LineToWrite)/sizeof(LineToWrite[0]),
TEXT("%s,%x,%s,%s,\"%s\""),
sourceFilename,
Checksum,
Directory,
DiskTagfile ? DiskTagfile : TEXT(""),
DiskDescription ? DiskDescription : TEXT("")
);
b = WritePrivateProfileString(
LogSectionName,
TargetFilename,
LineToWrite,
FileLog->FileName
);
Err = b ? NO_ERROR : GetLastError();
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
SetLastError(Err);
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
SetupRemoveFileLogEntryA(
IN HSPFILELOG FileLogHandle,
IN PCSTR LogSectionName, OPTIONAL
IN PCSTR TargetFilename OPTIONAL
)
{
PWSTR logsectionname,targetfilename;
DWORD d;
BOOL b;
if(LogSectionName) {
d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
if(d != NO_ERROR) {
SetLastError(d);
return(FALSE);
}
} else {
logsectionname = NULL;
}
if(TargetFilename) {
d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
if(d != NO_ERROR) {
if(logsectionname) {
MyFree(logsectionname);
}
SetLastError(d);
return(FALSE);
}
} else {
targetfilename = NULL;
}
b = SetupRemoveFileLogEntryW(FileLogHandle,logsectionname,targetfilename);
d = GetLastError();
if(logsectionname) {
MyFree(logsectionname);
}
if(targetfilename) {
MyFree(targetfilename);
}
SetLastError(d);
return(b);
}
#else
//
// Unicode stub
//
BOOL
SetupRemoveFileLogEntryW(
IN HSPFILELOG FileLogHandle,
IN PCWSTR LogSectionName, OPTIONAL
IN PCWSTR TargetFilename OPTIONAL
)
{
UNREFERENCED_PARAMETER(FileLogHandle);
UNREFERENCED_PARAMETER(LogSectionName);
UNREFERENCED_PARAMETER(TargetFilename);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
SetupRemoveFileLogEntry(
IN HSPFILELOG FileLogHandle,
IN PCTSTR LogSectionName, OPTIONAL
IN PCTSTR TargetFilename OPTIONAL
)
/*++
Routine Description:
Removes an entry or section from a file log.
Arguments:
FileLogHandle - supplies the handle to the file log, as returned
by SetupInitializeLogFile(). The caller must not have passed
SPFILELOG_QUERYONLY when the log file was opened/initialized.
LogSectionName - Supplies the name for a logical grouping of files
within the log. Required for non-system logs; optional for the
system log.
TargetFilename - supplies the name of the file as it exists on the
Target. This name should be in whatever format is meaningful to
the caller. If not specified, the entire section specified by
LogSectionName is removed. Removing the main section for NT files
is not allowed.
Return Value:
Boolean value indicating outcome. If FALSE, the caller can use
GetLastError() to get extended error info.
--*/
{
DWORD Err;
PSETUP_FILE_LOG FileLog;
BOOL b;
FileLog = (PSETUP_FILE_LOG)FileLogHandle;
try {
Err = NO_ERROR;
if(FileLog->QueryOnly) {
Err = ERROR_INVALID_PARAMETER;
} else {
if(!LogSectionName) {
if(FileLog->SystemLog) {
LogSectionName = NtFileSectionName;
} else {
Err = ERROR_INVALID_PARAMETER;
}
}
//
// Diallow removing the main nt files section.
//
if((Err == NO_ERROR)
&& FileLog->SystemLog
&& !TargetFilename
&& !lstrcmpi(LogSectionName,NtFileSectionName))
{
Err = ERROR_INVALID_PARAMETER;
}
}
if(Err == NO_ERROR) {
b = WritePrivateProfileString(LogSectionName,TargetFilename,NULL,FileLog->FileName);
Err = b ? NO_ERROR : GetLastError();
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
return(Err == NO_ERROR);
}
#ifdef UNICODE
//
// ANSI version
//
BOOL
SetupQueryFileLogA(
IN HSPFILELOG FileLogHandle,
IN PCSTR LogSectionName, OPTIONAL
IN PCSTR TargetFilename,
IN SetupFileLogInfo DesiredInfo,
OUT PSTR DataOut, OPTIONAL
IN DWORD ReturnBufferSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
PWSTR logsectionname;
PWSTR targetfilename;
PWSTR unicodeBuffer = NULL;
DWORD unicodeSize = 2048;
PSTR ansidata;
DWORD requiredsize;
DWORD d;
BOOL b;
d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
if(d != NO_ERROR) {
SetLastError(d);
return(FALSE);
}
if(LogSectionName) {
d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
if(d != NO_ERROR) {
MyFree(targetfilename);
SetLastError(d);
return(FALSE);
}
} else {
logsectionname = NULL;
}
unicodeBuffer = MyMalloc(unicodeSize*sizeof(WCHAR));
if(!unicodeBuffer) {
if(targetfilename) {
MyFree(targetfilename);
}
if(logsectionname) {
MyFree(logsectionname);
}
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
b = SetupQueryFileLogW(
FileLogHandle,
logsectionname,
targetfilename,
DesiredInfo,
unicodeBuffer,
unicodeSize,
&requiredsize
);
d = GetLastError();
if(b) {
d = NO_ERROR;
if(ansidata = pSetupUnicodeToAnsi(unicodeBuffer)) {
requiredsize = lstrlenA(ansidata)+1;
if(RequiredSize) {
try {
*RequiredSize = requiredsize;
} except(EXCEPTION_EXECUTE_HANDLER) {
b = FALSE;
d = ERROR_INVALID_PARAMETER;
}
}
if(b && DataOut) {
if(ReturnBufferSize >= requiredsize) {
if(!lstrcpyA(DataOut,ansidata)) {
//
// lstrcpy faulted, ReturnBuffer must be invalid
//
d = ERROR_INVALID_PARAMETER;
b = FALSE;
}
} else {
d = ERROR_INSUFFICIENT_BUFFER;
b = FALSE;
}
}
MyFree(ansidata);
} else {
b = FALSE;
d = ERROR_NOT_ENOUGH_MEMORY;
}
}
MyFree(targetfilename);
if(logsectionname) {
MyFree(logsectionname);
}
if(unicodeBuffer) {
MyFree(unicodeBuffer);
}
SetLastError(d);
return(b);
}
#else
//
// Unicode stub
//
BOOL
SetupQueryFileLogW(
IN HSPFILELOG FileLogHandle,
IN PCWSTR LogSectionName, OPTIONAL
IN PCWSTR TargetFilename,
IN SetupFileLogInfo DesiredInfo,
OUT PWSTR DataOut, OPTIONAL
IN DWORD ReturnBufferSize,
OUT PDWORD RequiredSize OPTIONAL
)
{
UNREFERENCED_PARAMETER(FileLogHandle);
UNREFERENCED_PARAMETER(LogSectionName);
UNREFERENCED_PARAMETER(TargetFilename);
UNREFERENCED_PARAMETER(DesiredInfo);
UNREFERENCED_PARAMETER(DataOut);
UNREFERENCED_PARAMETER(ReturnBufferSize);
UNREFERENCED_PARAMETER(RequiredSize);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
}
#endif
BOOL
SetupQueryFileLog(
IN HSPFILELOG FileLogHandle,
IN PCTSTR LogSectionName, OPTIONAL
IN PCTSTR TargetFilename,
IN SetupFileLogInfo DesiredInfo,
OUT PTSTR DataOut, OPTIONAL
IN DWORD ReturnBufferSize,
OUT PDWORD RequiredSize OPTIONAL
)
/*++
Routine Description:
Returns information from a setup file log.
Arguments:
FileLogHandle - supplies handle to open file log, as returned by
SetupInitializeFileLog().
LogSectionName - required for non-system logs; if not specified
for the system log a default is supplied. Supplies the name
for a logical grouping within the log that is meaningful
to the caller.
TargetFilename - supplies name of file for which log information
is desired.
DesiredInfo - supplies an ordinal indicating what information
is desired about the file.
DataOut - If specified, points to a buffer that receives the
requested information for the file. Note that not all info
is provided for every file; an error is not returned if an entry
for the file exists in the log but is empty.
ReturnBufferSize - supplies size of the buffer (in chars) pointed to
by DataOut. If the buffer is too small and DataOut is specified,
no data is stored and the function returns FALSE. If DataOut is
not specified this value is ignored.
RequiredSize - receives the number of characters (including the
terminating nul) required to hold the result.
Return Value:
Boolean value indicating result. If FALSE, extended error info is
available from GetLastError().
--*/
{
DWORD Err;
PSETUP_FILE_LOG FileLog;
BOOL b;
TCHAR ProfileValue[2*MAX_PATH];
INT n;
DWORD d;
PTCHAR Field,End,Info;
UINT InfoLength;
BOOL Quoted;
FileLog = (PSETUP_FILE_LOG)FileLogHandle;
try {
//
// Validate arguments.
// Section name must be supplied for non-system log.
//
if((!FileLog->SystemLog && !LogSectionName)
|| (DesiredInfo >= SetupFileLogMax) || !TargetFilename) {
Err = ERROR_INVALID_PARAMETER;
} else {
if(!LogSectionName) {
MYASSERT(FileLog->SystemLog);
LogSectionName = NtFileSectionName;
}
//
// Query the log file via profile API.
//
d = GetPrivateProfileString(
LogSectionName,
TargetFilename,
TEXT(""),
ProfileValue,
sizeof(ProfileValue)/sizeof(ProfileValue[0]),
FileLog->FileName
);
if(d) {
//
// We want to retreive the Nth item in the value we just
// retreived, where N is based on what the caller wants.
// This routine assumes that the SetupFileLogInfo enum is
// in the same order as items appear in a line in the log!
//
Field = ProfileValue;
n = 0;
nextfield:
//
// Find the end of the current field, which is
// the first comma, or the end of the value.
// Skip leading spaces.
//
while(*Field == TEXT(' ')) {
Field++;
}
End = Field;
Quoted = FALSE;
while(*End) {
if(*End == TEXT('\"')) {
Quoted = !Quoted;
} else {
if(!Quoted && *End == TEXT(',')) {
//
// Got the end of the field.
//
break;
}
}
End++;
}
//
// At this point, Field points to the start of the field
// and End points at the character that terminated it.
//
if(n == DesiredInfo) {
Info = Field;
InfoLength = (UINT)(End-Field);
//
// Compensate for trailing space.
//
while (*--End == TEXT(' ')) {
InfoLength--;
}
} else {
//
// Skip trailing spaces and the comma, if any.
//
while(*End == ' ') {
End++;
}
if(*End == ',') {
//
// More fields exist.
//
Field = End+1;
n++;
goto nextfield;
} else {
//
// Item doesn't exist.
//
Info = TEXT("");
InfoLength = 0;
}
}
if(RequiredSize) {
*RequiredSize = InfoLength+1;
}
Err = NO_ERROR;
if(DataOut) {
if(ReturnBufferSize > InfoLength) {
lstrcpyn(DataOut,Info,InfoLength+1);
} else {
Err = ERROR_INSUFFICIENT_BUFFER;
}
}
} else {
Err = ERROR_FILE_NOT_FOUND;
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
}
SetLastError(Err);
return(Err == NO_ERROR);
}