1054 lines
28 KiB
C
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);
|
|
}
|
|
|