441 lines
12 KiB
C
441 lines
12 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
file.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the functions to save references to files for the
|
||
|
INSTALER program. Part of each reference is a handle to a backup copy
|
||
|
of a file if the reference is a write/delete/rename.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Steve Wood (stevewo) 22-Aug-1994
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "instaler.h"
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
CreateFileReference(
|
||
|
PWSTR Name,
|
||
|
BOOLEAN WriteAccess,
|
||
|
PFILE_REFERENCE *ReturnedReference
|
||
|
)
|
||
|
{
|
||
|
PFILE_REFERENCE p;
|
||
|
PWSTR BackupFileName;
|
||
|
WIN32_FIND_DATAW FindFileData;
|
||
|
HANDLE FindFileHandle;
|
||
|
|
||
|
*ReturnedReference = NULL;
|
||
|
p = FindFileReference( Name );
|
||
|
if (p != NULL) {
|
||
|
if (p->WriteAccess) {
|
||
|
*ReturnedReference = p;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
p = AllocMem( sizeof( *p ) );
|
||
|
if (p == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
InsertTailList( &FileReferenceListHead, &p->Entry );
|
||
|
NumberOfFileReferences += 1;
|
||
|
p->Name = Name;
|
||
|
}
|
||
|
|
||
|
BackupFileName = L"";
|
||
|
FindFileHandle = NULL;
|
||
|
if ((p->WriteAccess = WriteAccess) &&
|
||
|
(FindFileHandle = FindFirstFileW( p->Name, &FindFileData )) != INVALID_HANDLE_VALUE
|
||
|
) {
|
||
|
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||
|
p->DirectoryFile = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
p->BackupFileAttributes = FindFileData.dwFileAttributes;
|
||
|
p->BackupLastWriteTime = FindFileData.ftLastWriteTime;
|
||
|
p->BackupFileSize.LowPart = FindFileData.nFileSizeLow;
|
||
|
p->BackupFileSize.HighPart = FindFileData.nFileSizeHigh;
|
||
|
BackupFileName = CreateBackupFileName( &p->BackupFileUniqueId );
|
||
|
if (BackupFileName == NULL ||
|
||
|
!CopyFileW( Name, BackupFileName, TRUE )
|
||
|
) {
|
||
|
p->BackupFileUniqueId = 0xFFFF; // Backup failed.
|
||
|
DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), Name );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
p->Created = p->WriteAccess;
|
||
|
}
|
||
|
|
||
|
if (FindFileHandle != NULL) {
|
||
|
FindClose( FindFileHandle );
|
||
|
}
|
||
|
|
||
|
*ReturnedReference = p;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
CompleteFileReference(
|
||
|
PFILE_REFERENCE p,
|
||
|
BOOLEAN CallSuccessful,
|
||
|
BOOLEAN Deleted,
|
||
|
PFILE_REFERENCE RenameReference
|
||
|
)
|
||
|
{
|
||
|
DWORD dwFileAttributes;
|
||
|
|
||
|
if (!CallSuccessful) {
|
||
|
DestroyFileReference( p );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (RenameReference) {
|
||
|
if (RenameReference->Created) {
|
||
|
LogEvent( INSTALER_EVENT_RENAME_TEMP_FILE,
|
||
|
3,
|
||
|
RenameReference->DirectoryFile ? L"directory" : L"file",
|
||
|
RenameReference->Name,
|
||
|
p->Name
|
||
|
);
|
||
|
|
||
|
RenameReference->Name = p->Name;
|
||
|
DestroyFileReference( p );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
RenameReference->Deleted = TRUE;
|
||
|
|
||
|
LogEvent( INSTALER_EVENT_RENAME_FILE,
|
||
|
3,
|
||
|
RenameReference->DirectoryFile ? L"directory" : L"file",
|
||
|
RenameReference->Name,
|
||
|
p->Name
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
if (Deleted && p->Created) {
|
||
|
LogEvent( INSTALER_EVENT_DELETE_TEMP_FILE,
|
||
|
2,
|
||
|
p->DirectoryFile ? L"directory" : L"file",
|
||
|
p->Name
|
||
|
);
|
||
|
DestroyFileReference( p );
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
if (wcschr( p->Name, '\\' ) == NULL) {
|
||
|
//
|
||
|
// If no path separator, must be volume open. Treat
|
||
|
// as directory and dont touch file
|
||
|
//
|
||
|
p->DirectoryFile = TRUE;
|
||
|
}
|
||
|
else
|
||
|
if ((dwFileAttributes = GetFileAttributes( p->Name )) != 0xFFFFFFFF) {
|
||
|
p->DirectoryFile = (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||
|
}
|
||
|
|
||
|
if (Deleted) {
|
||
|
LogEvent( INSTALER_EVENT_DELETE_FILE,
|
||
|
2,
|
||
|
p->DirectoryFile ? L"directory" : L"file",
|
||
|
p->Name
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
if (p->WriteAccess) {
|
||
|
if (p->Created) {
|
||
|
LogEvent( INSTALER_EVENT_CREATE_FILE,
|
||
|
2,
|
||
|
p->DirectoryFile ? L"directory" : L"file",
|
||
|
p->Name
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
LogEvent( INSTALER_EVENT_WRITE_FILE,
|
||
|
2,
|
||
|
p->DirectoryFile ? L"directory" : L"file",
|
||
|
p->Name
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
LogEvent( INSTALER_EVENT_READ_FILE,
|
||
|
2,
|
||
|
p->DirectoryFile ? L"directory" : L"file",
|
||
|
p->Name
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p->Deleted = Deleted;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
DestroyFileReference(
|
||
|
PFILE_REFERENCE p
|
||
|
)
|
||
|
{
|
||
|
PWSTR BackupFileName;
|
||
|
|
||
|
if (!p->Created &&
|
||
|
(BackupFileName = FormatTempFileName( NULL, &p->BackupFileUniqueId ))
|
||
|
) {
|
||
|
DeleteFileW( BackupFileName );
|
||
|
}
|
||
|
|
||
|
if (p->DateModified || p->AttributesModified) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
RemoveEntryList( &p->Entry );
|
||
|
NumberOfFileReferences -= 1;
|
||
|
FreeMem( &p );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
PVOID
|
||
|
MapFileForRead(
|
||
|
PWSTR FileName,
|
||
|
PULONG FileSize
|
||
|
)
|
||
|
{
|
||
|
HANDLE FileHandle, MappingHandle;
|
||
|
PVOID FileData;
|
||
|
ULONG HighFileSize;
|
||
|
|
||
|
FileData = NULL;
|
||
|
FileHandle = CreateFileW( FileName,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
|
NULL,
|
||
|
OPEN_EXISTING,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
if (FileHandle != INVALID_HANDLE_VALUE) {
|
||
|
*FileSize = GetFileSize( FileHandle, &HighFileSize );
|
||
|
if (*FileSize == 0) {
|
||
|
CloseHandle( FileHandle );
|
||
|
return (PVOID)0xFFFFFFFF;
|
||
|
}
|
||
|
|
||
|
MappingHandle = CreateFileMappingW( FileHandle,
|
||
|
NULL,
|
||
|
PAGE_READONLY,
|
||
|
0,
|
||
|
*FileSize,
|
||
|
NULL
|
||
|
);
|
||
|
CloseHandle( FileHandle );
|
||
|
if (MappingHandle != NULL) {
|
||
|
FileData = MapViewOfFile( MappingHandle,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
*FileSize
|
||
|
);
|
||
|
CloseHandle( MappingHandle );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FileData;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
AreFileContentsEqual(
|
||
|
PWSTR FileName1,
|
||
|
PWSTR FileName2
|
||
|
)
|
||
|
{
|
||
|
PVOID FileData1, FileData2;
|
||
|
ULONG FileSize1, FileSize2;
|
||
|
BOOLEAN Result;
|
||
|
|
||
|
Result = FALSE;
|
||
|
if (FileData1 = MapFileForRead( FileName1, &FileSize1 )) {
|
||
|
if (FileData2 = MapFileForRead( FileName2, &FileSize2 )) {
|
||
|
if (FileSize1 == FileSize2 &&
|
||
|
RtlCompareMemory( FileData1, FileData2, FileSize1 ) == FileSize1
|
||
|
) {
|
||
|
Result = TRUE;
|
||
|
}
|
||
|
if (FileData2 != (PVOID)0xFFFFFFFF) {
|
||
|
UnmapViewOfFile( FileData2 );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), FileName2 );
|
||
|
}
|
||
|
|
||
|
if (FileData1 != (PVOID)0xFFFFFFFF) {
|
||
|
UnmapViewOfFile( FileData1 );
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DeclareError( INSTALER_CANT_ACCESS_FILE, GetLastError(), FileName1 );
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
IsNewFileSameAsBackup(
|
||
|
PFILE_REFERENCE p
|
||
|
)
|
||
|
{
|
||
|
WIN32_FIND_DATAW FindFileData;
|
||
|
HANDLE FindFileHandle;
|
||
|
PWSTR BackupFileName;
|
||
|
|
||
|
if ((FindFileHandle = FindFirstFileW( p->Name, &FindFileData )) != INVALID_HANDLE_VALUE) {
|
||
|
FindClose( FindFileHandle );
|
||
|
if (p->BackupFileAttributes != FindFileData.dwFileAttributes) {
|
||
|
p->AttributesModified = TRUE;
|
||
|
}
|
||
|
|
||
|
if (p->BackupLastWriteTime.dwLowDateTime != FindFileData.ftLastWriteTime.dwLowDateTime ||
|
||
|
p->BackupLastWriteTime.dwHighDateTime != FindFileData.ftLastWriteTime.dwHighDateTime
|
||
|
) {
|
||
|
p->DateModified = TRUE;
|
||
|
}
|
||
|
|
||
|
if (BackupFileName = FormatTempFileName( NULL, &p->BackupFileUniqueId )) {
|
||
|
if (p->BackupFileSize.LowPart != FindFileData.nFileSizeLow ||
|
||
|
p->BackupFileSize.HighPart != FindFileData.nFileSizeHigh ||
|
||
|
!AreFileContentsEqual( BackupFileName, p->Name )
|
||
|
) {
|
||
|
p->ContentsModified = TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PFILE_REFERENCE
|
||
|
FindFileReference(
|
||
|
PWSTR Name
|
||
|
)
|
||
|
{
|
||
|
PFILE_REFERENCE p;
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
|
||
|
Head = &FileReferenceListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Head != Next) {
|
||
|
p = CONTAINING_RECORD( Next, FILE_REFERENCE, Entry );
|
||
|
if (p->Name == Name) {
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DumpFileReferenceList(
|
||
|
FILE *LogFile
|
||
|
)
|
||
|
{
|
||
|
PFILE_REFERENCE p;
|
||
|
PLIST_ENTRY Head, Next;
|
||
|
|
||
|
Head = &FileReferenceListHead;
|
||
|
Next = Head->Flink;
|
||
|
while (Head != Next) {
|
||
|
p = CONTAINING_RECORD( Next, FILE_REFERENCE, Entry );
|
||
|
if (p->WriteAccess) {
|
||
|
if (!p->Deleted) {
|
||
|
if (p->BackupFileUniqueId == 0) {
|
||
|
if (p->Created) {
|
||
|
ImlAddFileRecord( pImlNew,
|
||
|
CreateNewFile,
|
||
|
p->Name,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (p->ContentsModified) {
|
||
|
if (ImlAddFileRecord( pImlNew,
|
||
|
ModifyOldFile,
|
||
|
p->Name,
|
||
|
FormatTempFileName( NULL, &p->BackupFileUniqueId ),
|
||
|
NULL,
|
||
|
0
|
||
|
)
|
||
|
) {
|
||
|
DeleteFile( FormatTempFileName( NULL, &p->BackupFileUniqueId ) );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (p->DateModified) {
|
||
|
ImlAddFileRecord( pImlNew,
|
||
|
ModifyFileDateTime,
|
||
|
p->Name,
|
||
|
NULL,
|
||
|
&p->BackupLastWriteTime,
|
||
|
p->BackupFileAttributes
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
ImlAddFileRecord( pImlNew,
|
||
|
ModifyFileAttributes,
|
||
|
p->Name,
|
||
|
NULL,
|
||
|
&p->BackupLastWriteTime,
|
||
|
p->BackupFileAttributes
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (ImlAddFileRecord( pImlNew,
|
||
|
DeleteOldFile,
|
||
|
p->Name,
|
||
|
FormatTempFileName( NULL, &p->BackupFileUniqueId ),
|
||
|
NULL,
|
||
|
0
|
||
|
)
|
||
|
) {
|
||
|
DeleteFile( FormatTempFileName( NULL, &p->BackupFileUniqueId ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Next = Next->Flink;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|