Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

5239 lines
151 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
spcopy.c
Abstract:
File copy/decompression routines for text setup.
Author:
Ted Miller (tedm) 2-Aug-1993
Revision History:
--*/
#include "spprecmp.h"
#pragma hdrstop
typedef struct _DISK_FILE_LIST {
PWSTR MediaShortname;
PWSTR Description;
PWSTR TagFile;
PWSTR Directory;
ULONG FileCount;
PFILE_TO_COPY FileList;
} DISK_FILE_LIST, *PDISK_FILE_LIST;
//
// This structure is used during an OEM preinstall.
// It is used to form the list of files that were installed in the system, that
// have a short target name, instead of the corresponding long target name.
//
typedef struct _FILE_TO_RENAME {
struct _FILE_TO_RENAME *Next;
//
// Name of the file to be copied, as it exists on the source media
// (short file name part only -- no paths).
//
PWSTR SourceFilename;
//
// Directory to which this file is to be copied.
//
PWSTR TargetDirectory;
//
// Name of file as it should exist on the target (long name).
//
PWSTR TargetFilename;
} FILE_TO_RENAME, *PFILE_TO_RENAME;
//
// List used on an OEM preinstall.
// It contains the name of the files that need to be added to $$RENAME.TXT
//
PFILE_TO_RENAME RenameList = NULL;
#define ATTR_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
PVOID FileCopyGauge;
PVOID _SetupLogFile = NULL;
PVOID _LoggedOemFiles = NULL;
VOID
SpLogOneFile(
IN PFILE_TO_COPY FileToCopy,
IN PWSTR Sysroot,
IN PWSTR DirectoryOnSourceDevice,
IN PWSTR DiskDescription,
IN PWSTR DiskTag,
IN ULONG CheckSum
);
BOOLEAN
SpRemoveEntryFromCopyList(
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR TargetDirectory,
IN PWSTR TargetFilename,
IN PWSTR TargetDevicePath,
IN BOOLEAN AbsoluteTargetDirectory
);
PVOID
SppRetrieveLoggedOemFiles(
PVOID OldLogFile
);
VOID
SppMergeLoggedOemFiles(
IN PVOID DestLogHandle,
IN PVOID OemLogHandle,
IN PWSTR SystemPartition,
IN PWSTR SystemPartitionDirectory,
IN PWSTR NtPartition
);
BOOLEAN
SppIsFileLoggedAsOemFile(
IN PWSTR FilePath
);
BOOLEAN
SpDelEnumFile(
IN PWSTR DirName,
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
OUT PULONG ret,
IN PVOID Pointer
);
VOID
SpCopyDirRecursive(
IN PWSTR SrcPath,
IN PWSTR DestDevPath,
IN PWSTR DestDirPath
);
VOID
SppMergeRenameFiles(
IN PWSTR SourceDevicePath,
IN PWSTR NtPartition,
IN PWSTR Sysroot
);
VOID
SppCopyOemDirectories(
IN PWSTR SourceDevicePath,
IN PWSTR NtPartition,
IN PWSTR Sysroot
);
VOID
SpCreateDirectory(
IN PWSTR DevicePath,
IN PWSTR RootDirectory, OPTIONAL
IN PWSTR Directory
)
/*++
Routine Description:
Create a directory. All containing directories are created to ensure
that the directory can be created. For example, if the directory to be
created is \a\b\c, then this routine will create \a, \a\b, and \a\b\c
in that order.
Arguments:
DevicePath - supplies pathname to the device on which the directory
is to be created.
RootDirectory - if specified, supplies a fixed portion of the directory name,
which must have already been created. The directory being created will be
concatenated to this value.
Directory - supplies directory to be created on the device.
Return Value:
None. Does not return if directry could not successfully be created.
--*/
{
PWSTR p,q,r,EntirePath;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE Handle;
ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
ULONG DevicePartLen;
//
// Do not bother attempting to create the root directory.
//
if((Directory[0] == 0) || ((Directory[0] == L'\\') && (Directory[1] == 0))) {
return;
}
//
// Fill up TemporaryBuffer with the full pathname
// of the directory being created.
//
p = (PWSTR)TemporaryBuffer;
*p = 0;
SpConcatenatePaths(p,DevicePath);
DevicePartLen = wcslen(p);
if(RootDirectory) {
SpConcatenatePaths(p,RootDirectory);
}
SpConcatenatePaths(p,Directory);
//
// Make a duplicate of the path being created.
//
EntirePath = SpDupStringW(p);
//
// Make q point to the first character in the directory
// part of the pathname (ie, 1 char past the end of the device name).
//
q = EntirePath + DevicePartLen;
ASSERT(*q == L'\\');
//
// Make r point to the first character in the directory
// part of the pathname. This will be used to keep the status
// line updated with the directory being created.
//
r = q;
//
// Make p point to the first character following the first
// \ in the directory part of the full path.
//
p = q+1;
do {
//
// find the next \ or the terminating 0.
//
q = wcschr(p,L'\\');
//
// If we found \, terminate the string at that point.
//
if(q) {
*q = 0;
}
do {
SpDisplayStatusText(SP_STAT_CREATING_DIRS,DEFAULT_STATUS_ATTRIBUTE,r);
//
// Create or open the directory whose name is in EntirePath.
//
INIT_OBJA(&Obja,&UnicodeString,EntirePath);
Status = ZwCreateFile(
&Handle,
FILE_LIST_DIRECTORY | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0
);
if(!NT_SUCCESS(Status)) {
BOOLEAN b = TRUE;
KdPrint(("SETUP: Unable to create dir %ws (%lx)\n", r, Status));
//
// Tell user we couldn't do it. Options are to retry or exit.
//
while(b) {
SpStartScreen(
SP_SCRN_DIR_CREATE_ERR,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
r
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_RETRY,
SP_STAT_F3_EQUALS_EXIT,
0
);
switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
case ASCI_CR:
b = FALSE;
break;
case KEY_F3:
SpConfirmExit();
break;
}
}
}
} while(!NT_SUCCESS(Status));
ZwClose(Handle);
//
// Unterminate the current string if necessary.
//
if(q) {
*q = L'\\';
p = q+1;
}
} while(*p && q); // *p catches string ending in '\'
SpMemFree(EntirePath);
}
VOID
SpCreateDirStructWorker(
IN PVOID SifHandle,
IN PWSTR SifSection,
IN PWSTR DevicePath,
IN PWSTR RootDirectory,
IN BOOLEAN Fatal
)
/*++
Routine Description:
Create a set of directories that are listed in a setup information file
section. The expected format is as follows:
[SectionName]
shortname = directory
shortname = directory
.
.
.
Arguments:
SifHandle - supplies handle to loaded setup information file.
SifSection - supplies name of section in the setup information file
containing directories to be created.
DevicePath - supplies pathname to the device on which the directory
structure is to be created.
RootDirectory - supplies a root directory, relative to which the
directory structure will be created.
Return Value:
None. Does not return if directory structure could not be created.
--*/
{
ULONG Count;
ULONG d;
PWSTR Directory;
//
// Count the number of directories to be created.
//
Count = SpCountLinesInSection(SifHandle,SifSection);
if(!Count) {
if(Fatal) {
SpFatalSifError(SifHandle,SifSection,NULL,0,0);
} else {
return;
}
}
for(d=0; d<Count; d++) {
Directory = SpGetSectionLineIndex(SifHandle,SifSection,d,0);
if(!Directory) {
SpFatalSifError(SifHandle,SifSection,NULL,d,0);
}
SpCreateDirectory(DevicePath,RootDirectory,Directory);
}
}
VOID
SpCreateDirectoryStructureFromSif(
IN PVOID SifHandle,
IN PWSTR SifSection,
IN PWSTR DevicePath,
IN PWSTR RootDirectory
)
/*++
Routine Description:
Create a set of directories that are listed in a setup information file
section. The expected format is as follows:
[SectionName]
shortname = directory
shortname = directory
.
.
.
[SectionName.<platform>]
shortname = directory
shortname = directory
.
.
.
Arguments:
SifHandle - supplies handle to loaded setup information file.
SifSection - supplies name of section in the setup information file
containing directories to be created.
DevicePath - supplies pathname to the device on which the directory
structure is to be created.
RootDirectory - supplies a root directory, relative to which the
directory structure will be created.
Return Value:
None. Does not return if directory structure could not be created.
--*/
{
PWSTR p;
//
// Create the root directory.
//
SpCreateDirectory(DevicePath,NULL,RootDirectory);
//
// Create platform-indepdenent directories
//
SpCreateDirStructWorker(SifHandle,SifSection,DevicePath,RootDirectory,TRUE);
//
// Create platform-depdenent directories
//
p = SpMakePlatformSpecificSectionName(SifSection);
SpCreateDirStructWorker(SifHandle,p,DevicePath,RootDirectory,FALSE);
SpMemFree(p);
}
VOID
SpGetFileVersion(
IN PVOID ImageBase,
OUT PULONGLONG Version
)
/*++
Routine Description:
Get the version stamp out of the VS_FIXEDFILEINFO resource in a PE
image.
Arguments:
ImageBase - supplies the address in memory where the file is mapped in.
Version - receives 64bit version number, or 0 if the file is not
a PE image or has no version data.
Return Value:
None.
--*/
{
PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
NTSTATUS Status;
ULONG IdPath[3];
ULONG ResourceSize;
struct {
USHORT TotalSize;
USHORT DataSize;
USHORT Type;
WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
VS_FIXEDFILEINFO FixedFileInfo;
} *Resource;
*Version = 0;
//
// Do this to prevent the Ldr routines from faulting.
//
ImageBase = (PVOID)((ULONG)ImageBase | 1);
IdPath[0] = (ULONG)RT_VERSION;
IdPath[1] = (ULONG)MAKEINTRESOURCE(VS_VERSION_INFO);
IdPath[2] = 0;
try {
Status = LdrFindResource_U(ImageBase,IdPath,3,&DataEntry);
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_UNSUCCESSFUL;
}
if(!NT_SUCCESS(Status)) {
return;
}
try {
Status = LdrAccessResource(ImageBase,DataEntry,&Resource,&ResourceSize);
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_UNSUCCESSFUL;
}
if(!NT_SUCCESS(Status)) {
return;
}
if((ResourceSize >= sizeof(*Resource)) && !_wcsicmp(Resource->Name,L"VS_VERSION_INFO")) {
*Version = ((ULONGLONG)Resource->FixedFileInfo.dwFileVersionMS << 32)
| (ULONGLONG)Resource->FixedFileInfo.dwFileVersionLS;
} else {
KdPrint(("SETUP: Warning: invalid version resource\n"));
}
}
NTSTATUS
SpCopyFileUsingNames(
IN PWSTR SourceFilename,
IN PWSTR TargetFilename,
IN ULONG TargetAttributes,
IN ULONG Flags
)
/*++
Routine Description:
Attempt to copy or decompress a file based on filenames.
Arguments:
SourceFilename - supplies fully qualified name of file
in the NT namespace.
TargetFilename - supplies fully qualified name of file
in the NT namespace.
TargetAttributes - if supplied (ie, non-0) supplies the attributes
to be placed on the target on successful copy (ie, readonly, etc).
Flags - bit mask specifying any special treatment necessary
for the file.
Return Value:
NT Status value indicating outcome of NtWriteFile of the data.
--*/
{
NTSTATUS Status;
HANDLE SourceHandle;
HANDLE TargetHandle;
BOOLEAN b;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION BasicFileInfo;
FILE_BASIC_INFORMATION BasicFileInfo2;
BOOLEAN GotBasicInfo;
ULONG FileSize;
PVOID ImageBase;
HANDLE SectionHandle;
BOOLEAN IsCompressed;
PWSTR TempFilename;
PFILE_RENAME_INFORMATION RenameFileInfo;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
LARGE_INTEGER LargeZero;
ULONGLONG SourceVersion;
ULONGLONG TargetVersion;
USHORT CompressionState;
BOOLEAN Moved;
BOOLEAN TargetExists;
//
// Open the source file if it's not open already.
// Note that the name may not be the actual name on disk.
// We also try to open the name with the _ appended.
//
Status = SpOpenNameMayBeCompressed(
SourceFilename,
FILE_GENERIC_READ,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
0,
&SourceHandle,
&b
);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: Unable to open source file %ws (%x)\n",SourceFilename,Status));
return(Status);
}
//
// Gather basic file info about the file. We only use the timestamp info.
// If this fails this isn't fatal (we assume that if this fails, then
// the copy will also fail; it not, the worst case is that the timestamps
// might be wrong).
//
Status = ZwQueryInformationFile(
SourceHandle,
&IoStatusBlock,
&BasicFileInfo,
sizeof(BasicFileInfo),
FileBasicInformation
);
if(NT_SUCCESS(Status)) {
GotBasicInfo = TRUE;
} else {
GotBasicInfo = FALSE;
KdPrint(("SETUP: SpCopyFileUsingNames: Warning: unable to get basic file info for %ws (%x)\n",SourceFilename,Status));
}
//
// Get the source file size, map in the file, and determine whether it's compressed.
//
Status = SpGetFileSize(SourceHandle,&FileSize);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to get size of %ws (%x)\n",SourceFilename,Status));
ZwClose(SourceHandle);
return(Status);
}
Status = SpMapEntireFile(SourceHandle,&SectionHandle,&ImageBase,FALSE);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to map file %ws (%x)\n",SourceFilename,Status));
ZwClose(SourceHandle);
return(Status);
}
IsCompressed = SpdIsCompressed(ImageBase,FileSize);
//
// Create a temporary filename to be used for the target.
//
TempFilename = SpMemAlloc((wcslen(TargetFilename)+12)*sizeof(WCHAR));
wcscpy(TempFilename,TargetFilename);
wcscpy(wcsrchr(TempFilename,L'\\')+1,L"$$TEMP$$.~~~");
//
// Allocate some space for the rename buffer.
//
RenameFileInfo = SpMemAlloc(1000);
//
// Create the temporary file. We first try to do this via a move
// if the source isn't compressed and we're going to delete the source file.
//
if(!IsCompressed && (Flags & COPY_DELETESOURCE)) {
RenameFileInfo->ReplaceIfExists = TRUE;
RenameFileInfo->RootDirectory = NULL;
RenameFileInfo->FileNameLength = wcslen(TempFilename)*sizeof(WCHAR);
wcscpy(RenameFileInfo->FileName,TempFilename);
Status = ZwSetInformationFile(
SourceHandle,
&IoStatusBlock,
RenameFileInfo,
sizeof(FILE_RENAME_INFORMATION) + RenameFileInfo->FileNameLength,
FileRenameInformation
);
Moved = TRUE;
} else {
//
// Force us to fall into the copy case below.
//
Status = STATUS_UNSUCCESSFUL;
}
INIT_OBJA(&Obja,&UnicodeString,TempFilename);
if(!NT_SUCCESS(Status)) {
Moved = FALSE;
//
// OK, move failed, try decompress/copy instead.
// Start by creating the temporary file.
//
Status = ZwCreateFile(
&TargetHandle,
FILE_GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0, // no sharing
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if(NT_SUCCESS(Status)) {
if(IsCompressed) {
Status = SpdDecompressFile(ImageBase,FileSize,TargetHandle);
} else {
//
// Guard the write with a try/except because if there is an i/o error,
// memory management will raise an in-page exception.
//
LargeZero.QuadPart = 0;
try {
Status = ZwWriteFile(
TargetHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
ImageBase,
FileSize,
&LargeZero,
NULL
);
} except(EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_IN_PAGE_ERROR;
}
}
ZwClose(TargetHandle);
}
}
SpUnmapFile(SectionHandle,ImageBase);
ZwClose(SourceHandle);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to create temporary file %ws (%x)\n",TempFilename,Status));
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
return(Status);
}
//
// At this point we have a temporary target file that is now the source.
// Open the file, map it in, and get its version.
//
Status = ZwCreateFile(
&SourceHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
0, // don't bother with attributes
0, // no sharing
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if((Status == STATUS_ACCESS_DENIED) && Moved) {
//
// The only way this could have happened is if the source file
// is uncompressed and the delete-source flag is set, since in
// that case we could have moved the source file to the temp file.
// In any other case we would have created the temp file by copying,
// and there's no problem reopening the file since we just created
// and closed it ourselves, above.
//
// Reset attributes and try again. The file might have been read-only.
// This can happen when doing a winnt32 directly from a CD since the
// RO attribute of files from the CD are preserved.
//
KdPrint(("SETUP: SpCopyFileUsingNames: for file %ws, can't reopen temp file (access deined), trying again\n",SourceFilename));
Status = ZwCreateFile(
&SourceHandle,
FILE_WRITE_ATTRIBUTES,
&Obja,
&IoStatusBlock,
NULL,
0, // don't bother with attributes
FILE_SHARE_WRITE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if(NT_SUCCESS(Status)) {
RtlZeroMemory(&BasicFileInfo2,sizeof(BasicFileInfo2));
BasicFileInfo2.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Status = ZwSetInformationFile(
SourceHandle,
&IoStatusBlock,
&BasicFileInfo2,
sizeof(BasicFileInfo2),
FileBasicInformation
);
ZwClose(SourceHandle);
if(NT_SUCCESS(Status)) {
Status = ZwCreateFile(
&SourceHandle,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&Obja,
&IoStatusBlock,
NULL,
0, // don't bother with attributes
0, // no sharing
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
}
}
}
//
// Read-only failured win out over sharing violations -- ie, we'll get back
// ACCESS_DEINED first for files that are both RO and in-use. So break out
// this block so it gets executed even if we tried again above because the
// file might be read-only.
//
if((Status == STATUS_SHARING_VIOLATION) && Moved) {
//
// The only way this can happen is if the source file is uncompressed
// and the delete-source flag is set. In this case we renamed the file
// to the temp filename and now we can't open it for write.
// In any other case we would have created the temp file by copying,
// and so there's no problem opening the file since we just closed it.
//
// Rename the temp file back to the source file and try again without
// the delete source flag set. This forces a copy instead of a move.
// The rename better work or else we're completely hosed -- because
// there's a file we can't overwrite with the name we want to use for
// the temp file for all our copy operations!
//
KdPrint(("SETUP: SpCopyFileUsingNames: temporary file %ws is in use -- trying recursive call\n",TempFilename));
Status = SpRenameFile(TempFilename,SourceFilename);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to restore temp file to %ws (%x)\n",SourceFilename,Status));
}
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
if(NT_SUCCESS(Status)) {
Status = SpCopyFileUsingNames(
SourceFilename,
TargetFilename,
TargetAttributes,
Flags & ~COPY_DELETESOURCE
);
}
return(Status);
}
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to reopen temporary file %ws (%x)\n",TempFilename,Status));
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
return(Status);
}
Status = SpGetFileSize(SourceHandle,&FileSize);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to get size of %ws (%x)\n",TempFilename,Status));
ZwClose(SourceHandle);
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
return(Status);
}
Status = SpMapEntireFile(SourceHandle,&SectionHandle,&ImageBase,FALSE);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to map file %ws (%x)\n",TempFilename,Status));
ZwClose(SourceHandle);
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
return(Status);
}
SpGetFileVersion(ImageBase,&SourceVersion);
SpUnmapFile(SectionHandle,ImageBase);
//
// See if the target file is there by attempting to open it.
// If the file is there, get its version.
//
INIT_OBJA(&Obja,&UnicodeString,TargetFilename);
Status = ZwCreateFile(
&TargetHandle,
FILE_GENERIC_READ,
&Obja,
&IoStatusBlock,
NULL,
0, // don't bother with attributes
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN, // open if exists, fail if not
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
TargetVersion = 0;
if(NT_SUCCESS(Status)) {
TargetExists = TRUE;
//
// If we're supposed to ignore versions, then keep the
// target version at 0. This will guarantee that we'll overwrite
// the target. We use the source filename here because it
// allows more flexibility (such as with HALs, which all have
// different source names but the same target name).
//
if(!(Flags & COPY_NOVERSIONCHECK)) {
Status = SpGetFileSize(TargetHandle,&FileSize);
if(NT_SUCCESS(Status)) {
Status = SpMapEntireFile(TargetHandle,&SectionHandle,&ImageBase,FALSE);
if(NT_SUCCESS(Status)) {
SpGetFileVersion(ImageBase,&TargetVersion);
SpUnmapFile(SectionHandle,ImageBase);
} else {
KdPrint(("SETUP: SpCopyFileUsingNames: warning: unable to map file %ws (%x)\n",TargetFilename,Status));
}
} else {
KdPrint(("SETUP: SpCopyFileUsingNames: warning: unable to get size of file %ws (%x)\n",TargetFilename,Status));
}
}
ZwClose(TargetHandle);
} else {
TargetExists = FALSE;
}
//
// OK, now we have a temporary source file and maybe an existing
// target file, and version numbers for both. We will replace or create
// the target file if:
//
// - The target file doesn't have version data (this also catches the case
// where the target file didn't exist)
//
// - The source version is newer than or equal to the target version.
//
// So that means we *won't* replace the target file only if both source and
// target have version info and the source is older than the target.
//
// If the target version is 0 then the source version is always >= the target
// so one simple test does everything we want.
//
if(SourceVersion >= TargetVersion) {
//
// Delete the existing target in preparation.
//
if(TargetExists) {
SpDeleteFile(TargetFilename,NULL,NULL);
}
//
// Rename temp file to actual target file.
//
RenameFileInfo->ReplaceIfExists = TRUE;
RenameFileInfo->RootDirectory = NULL;
RenameFileInfo->FileNameLength = wcslen(TargetFilename)*sizeof(WCHAR);
wcscpy(RenameFileInfo->FileName,TargetFilename);
Status = ZwSetInformationFile(
SourceHandle,
&IoStatusBlock,
RenameFileInfo,
sizeof(FILE_RENAME_INFORMATION) + RenameFileInfo->FileNameLength,
FileRenameInformation
);
SpMemFree(RenameFileInfo);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to rename temp file to target %ws (%x)\n",TargetFilename,Status));
ZwClose(SourceHandle);
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
return(Status);
}
#ifdef _X86_
//
// If this file is on the list of files whose locks need to be smashed,
// go smash locks. Note that the subroutine checks to see whether smashing
// is really necessary (ie, if we're installing uniprocessor).
//
if(Flags & COPY_SMASHLOCKS) {
BOOLEAN IsNtImage,IsValid;
ULONG Checksum;
SpValidateAndChecksumFile(SourceHandle,NULL,&IsNtImage,&Checksum,&IsValid);
//
// If the image is valid, then smash the locks
//
if(IsNtImage && IsValid) {
SpMashemSmashem(SourceHandle,NULL,NULL,NULL);
} else {
//
// It's not an nt image, or not a valid nt image,
// so set Status to avoid the forcenocomp stuff below.
//
Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
}
}
#endif
//
// If necessary, check if destination file is using NTFS compression, and
// if so, uncompress it.
//
if(NT_SUCCESS(Status) && (Flags & COPY_FORCENOCOMP)) {
Status = ZwQueryInformationFile(
SourceHandle,
&IoStatusBlock,
&BasicFileInfo2,
sizeof(BasicFileInfo2),
FileBasicInformation
);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to get basic file info on %ws (%x)\n",TargetFilename,Status));
ZwClose(SourceHandle);
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
return(Status);
}
if(BasicFileInfo2.FileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
CompressionState = 0;
Status = ZwFsControlFile(
SourceHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_SET_COMPRESSION,
&CompressionState,
sizeof(CompressionState),
NULL,
0
);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFileUsingNames: unable to make %ws uncompressed (%lx)\n",TargetFilename,Status));
ZwClose(SourceHandle);
if(Moved) {
SpRenameFile(TempFilename,SourceFilename);
}
SpMemFree(TempFilename);
return(Status);
}
}
}
SpMemFree(TempFilename);
//
// Delete the source if necessary. If the source is not
// compressed and the deletesource flag is set, then we moved
// the source file and so the source file is already gone.
//
if(IsCompressed && (Flags & COPY_DELETESOURCE)) {
SpDeleteFile(SourceFilename,NULL,NULL);
}
//
// Apply attributes and timestamp.
// Ignore errors.
//
if(!GotBasicInfo) {
RtlZeroMemory(&BasicFileInfo,sizeof(BasicFileInfo));
}
//
// Set the file attributes. Note that if the caller didn't specify any,
// then 0 value will tell the I/O system to leave the attributes alone.
//
BasicFileInfo.FileAttributes = TargetAttributes;
ZwSetInformationFile(
SourceHandle,
&IoStatusBlock,
&BasicFileInfo,
sizeof(BasicFileInfo),
FileBasicInformation
);
ZwClose(SourceHandle);
Status = STATUS_SUCCESS;
} else {
//
// Delete the temporary source.
//
ZwClose(SourceHandle);
SpDeleteFile(TempFilename,NULL,NULL);
SpMemFree(TempFilename);
SpMemFree(RenameFileInfo);
Status = STATUS_SUCCESS;
}
return(Status);
}
VOID
SpValidateAndChecksumFile(
IN HANDLE FileHandle, OPTIONAL
IN PWSTR Filename, OPTIONAL
OUT PBOOLEAN IsNtImage,
OUT PULONG Checksum,
OUT PBOOLEAN Valid
)
/*++
Routine Description:
Calculate a checksum value for a file using the standard
nt image checksum method. If the file is an nt image, validate
the image using the partial checksum in the image header. If the
file is not an nt image, it is simply defined as valid.
If we encounter an i/o error while checksumming, then the file
is declared invalid.
Arguments:
FileHandle - supplies handle of file to check (if not present, then
Filename specifies the file to be opened and checked)
Filename - supplies full NT path of file to check (if not present, then
FileHandle must be specified)
IsNtImage = Receives flag indicating whether the file is an
NT image file.
Checksum - receives 32-bit checksum value.
Valid - receives flag indicating whether the file is a valid
image (for nt images) and that we can read the image.
Return Value:
None.
--*/
{
NTSTATUS Status;
PVOID BaseAddress;
ULONG FileSize;
HANDLE hFile = FileHandle, hSection;
PIMAGE_NT_HEADERS NtHeaders;
ULONG HeaderSum;
//
// Assume not an image and failure.
//
*IsNtImage = FALSE;
*Checksum = 0;
*Valid = FALSE;
//
// Open and map the file for read access.
//
Status = SpOpenAndMapFile(
Filename,
&hFile,
&hSection,
&BaseAddress,
&FileSize,
FALSE
);
if(!NT_SUCCESS(Status)) {
return;
}
NtHeaders = SpChecksumMappedFile(BaseAddress,FileSize,&HeaderSum,Checksum);
//
// If the file is not an image and we got this far (as opposed to encountering
// an i/o error) then the checksum is declared valid. If the file is an image,
// then its checksum may or may not be valid.
//
if(NtHeaders) {
*IsNtImage = TRUE;
*Valid = HeaderSum ? (*Checksum == HeaderSum) : TRUE;
} else {
*Valid = TRUE;
}
SpUnmapFile(hSection,BaseAddress);
if(!FileHandle) {
ZwClose(hFile);
}
}
VOID
SpCopyFileWithRetry(
IN PFILE_TO_COPY FileToCopy,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice,
IN PWSTR SourceDirectory, OPTIONAL
IN PWSTR TargetRoot, OPTIONAL
IN ULONG TargetFileAttributes, OPTIONAL
IN PCOPY_DRAW_ROUTINE DrawScreen,
IN PULONG FileCheckSum, OPTIONAL
IN PBOOLEAN FileSkipped, OPTIONAL
IN ULONG Flags
)
/*++
Routine Description:
This routine copies a single file, allowing retry is an error occurs
during the copy. If the source file is LZ compressed, then it will
be decompressed as it is copied to the target.
If the file is not successfully copied, the user has the option
to retry to copy or to skip copying that file after a profuse warning
about how dangerous that is.
Arguments:
FileToCopy - supplies structure giving information about the file
being copied.
SourceDevicePath - supplies path to device on which the source media
is mounted (ie, \device\floppy0, \device\cdrom0, etc).
DirectoryOnSourceDevice - Supplies the directory on the source where
the file is to be found.
TargetRoot - if specified, supplies the directory on the target
to which the file is to be copied.
TargetFileAttributes - if supplied (ie, non-0) supplies the attributes
to be placed on the target on successful copy (ie, readonly, etc).
If not specified, the attributes will be set to FILE_ATTRIBUTE_NORMAL.
DrawScreen - supplies address of a routine to be called to refresh
the screen.
FileCheckSum - if specified, will contain the check sum of the file copied.
FileSkipped - if specified, will inform the caller if there was no attempt
to copy the file.
Flags - supplies flags to control special processing for this file, such as
deleting the source file on successful copy or skip; smashing locks;
specifying that the source file is oem; or to indicate that en oem file
with the same name should be overwritten on upgrade. This value is ORed
in with the Flags field of FileToCopy.
Return Value:
None.
--*/
{
PWSTR p = (PWSTR)TemporaryBuffer;
PWSTR FullSourceName,FullTargetName;
NTSTATUS Status;
ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
BOOLEAN IsNtImage,IsValid;
ULONG Checksum;
BOOLEAN Failure;
ULONG MsgId;
BOOLEAN DoCopy;
ULONG CopyFlags;
BOOLEAN PreinstallRememberFile;
//
// Form the full NT path of the source file.
//
wcscpy(p,SourceDevicePath);
SpConcatenatePaths(p,DirectoryOnSourceDevice);
if(SourceDirectory) {
SpConcatenatePaths(p,SourceDirectory);
}
SpConcatenatePaths(p,FileToCopy->SourceFilename);
FullSourceName = SpDupStringW(p);
//
// Form the full NT path of the target file.
//
wcscpy(p,FileToCopy->TargetDevicePath);
if(TargetRoot) {
SpConcatenatePaths(p,TargetRoot);
}
SpConcatenatePaths(p,FileToCopy->TargetDirectory);
//
// On an OEM preinstall, if the target name is a long name, then use
// the short name as a target name, and later on, if the copy succeeds,
// add the file to RenameList, so that it can be added to $$rename.txt
//
if( !PreInstall ||
( wcslen( FileToCopy->TargetFilename ) <= 8 + 1 + 3 ) ) {
SpConcatenatePaths(p,FileToCopy->TargetFilename);
PreinstallRememberFile = FALSE;
} else {
SpConcatenatePaths(p,FileToCopy->SourceFilename);
PreinstallRememberFile = TRUE;
}
FullTargetName = SpDupStringW(p);
//
// Call out to the draw screen routine to indicate that
// a new file is being copied.
//
DrawScreen(FullSourceName,FullTargetName,FALSE);
//
// Build up the copy flags value.
//
CopyFlags = Flags | FileToCopy->Flags;
do {
DoCopy = TRUE;
//
// Check the copy options field. The valid values here are
//
// - COPY_ALWAYS
// - COPY_ONLY_IF_PRESENT
// - COPY_ONLY_IF_NOT_PRESENT
// - COPY_NEVER
switch(CopyFlags & COPY_DISPOSITION_MASK) {
case COPY_ONLY_IF_PRESENT:
DoCopy = SpFileExists(FullTargetName, FALSE);
break;
case COPY_ONLY_IF_NOT_PRESENT:
DoCopy = !SpFileExists(FullTargetName, FALSE);
break;
case COPY_NEVER:
DoCopy = FALSE;
case COPY_ALWAYS:
default:
break;
}
if(!DoCopy) {
break;
}
//
// In the upgrade case, check if the file being copied
// replaces a third party file.
// If it does, then ask what the user wants to do about it
//
if( !RepairWinnt &&
( NTUpgrade == UpgradeFull ) &&
SpFileExists(FullTargetName, FALSE) ) {
//
// If necessary ask the user if he wants to overwrite the file.
// Otherwise go ahead and copy the file.
//
if(!(CopyFlags & COPY_OVERWRITEOEMFILE)) {
PWSTR TmpFilePath;
BOOLEAN OverwriteFile;
if(( TargetRoot == NULL ) ||
( wcslen( FileToCopy->TargetDirectory ) == 0 ) ) {
wcscpy( p, FileToCopy->TargetFilename );
} else {
wcscpy( p, TargetRoot );
SpConcatenatePaths( p, FileToCopy->TargetDirectory );
SpConcatenatePaths(p,FileToCopy->TargetFilename);
}
TmpFilePath = SpDupStringW(p);
OverwriteFile = TRUE;
if( ( (CopyFlags & COPY_SOURCEISOEM) == 0 ) &&
SppIsFileLoggedAsOemFile( TmpFilePath ) ) {
if( !UnattendedOperation ) {
ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F1, 0 };
BOOLEAN ActionSelected = FALSE;
// ULONG Mnemonics[] = { MnemonicOverwrite, 0 };
//
// Warn user that existing file is a third party file,
// and ask if user wants to over write the file
//
while( !ActionSelected ) {
SpStartScreen(
SP_SCRN_OVERWRITE_OEM_FILE,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
FileToCopy->TargetFilename
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_REPLACE_FILE,
SP_STAT_ESC_EQUALS_SKIP_FILE,
SP_STAT_F1_EQUALS_HELP,
0
);
switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
case ASCI_CR: // don't overwrite
OverwriteFile = TRUE;
ActionSelected = TRUE;
KdPrint(( "SETUP: OEM file %ls, will be overwritten.\n", FullTargetName ));
break;
case ASCI_ESC: // skip file
OverwriteFile = FALSE;
ActionSelected = TRUE;
break;
case KEY_F1: // display help
SpHelp( SP_HELP_OVERWRITE_OEM_FILE, NULL, SPHELP_HELPTEXT );
break;
}
}
//
// Need to completely repaint gauge, etc.
//
DrawScreen(FullSourceName,FullTargetName,TRUE);
} else {
//
// On unattended upgrade, do what is in the script file
//
OverwriteFile = UnattendedOverwriteOem;
}
}
SpMemFree( TmpFilePath );
if( !OverwriteFile ) {
KdPrint(( "SETUP: OEM file %ls, will not be overwritten.\n", FullTargetName ));
if( ARGUMENT_PRESENT( FileSkipped ) ) {
*FileSkipped = TRUE;
}
//
// Free the source and target filenames.
//
SpMemFree(FullSourceName);
SpMemFree(FullTargetName);
return;
}
}
}
//
// Copy the file. If there is a target root specified, assume
// the file is being copied to the system partition and make
// the file readonly, system, hidden.
//
Status = SpCopyFileUsingNames(
FullSourceName,
FullTargetName,
TargetFileAttributes,
CopyFlags
);
//
// If the file copied OK, verify the copy.
//
if(NT_SUCCESS(Status)) {
SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&Checksum,&IsValid);
if( ARGUMENT_PRESENT( FileCheckSum ) ) {
*FileCheckSum = Checksum;
}
//
// If the image is valid, then the file really did copy OK.
//
if(IsValid) {
Failure = FALSE;
} else {
//
// If it's an nt image, then the verify failed.
// If it's not an nt image, then the only way the verify
// can fail is if we get an i/o error reading the file back,
// which means it didn't really copy correctly.
//
MsgId = IsNtImage ? SP_SCRN_IMAGE_VERIFY_FAILED : SP_SCRN_COPY_FAILED;
Failure = TRUE;
PreinstallRememberFile = FALSE;
}
} else {
if((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (Flags & COPY_SKIPIFMISSING)) {
Failure = FALSE;
} else {
Failure = TRUE;
MsgId = SP_SCRN_COPY_FAILED;
}
PreinstallRememberFile = FALSE;
}
if(Failure) {
//
// The copy or verify failed. Give the user a message and allow retry.
//
repaint:
SpStartScreen(
MsgId,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
FileToCopy->SourceFilename
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_RETRY,
SP_STAT_ESC_EQUALS_SKIP_FILE,
SP_STAT_F3_EQUALS_EXIT,
0
);
switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
case ASCI_CR: // retry
break;
case ASCI_ESC: // skip file
Failure = FALSE;
break;
case KEY_F3: // exit setup
SpConfirmExit();
goto repaint;
}
//
// Need to completely repaint gauge, etc.
//
DrawScreen(FullSourceName,FullTargetName,TRUE);
}
} while(Failure);
if( ARGUMENT_PRESENT( FileSkipped ) ) {
*FileSkipped = !DoCopy;
}
//
// Free the source and target filenames.
//
SpMemFree(FullSourceName);
SpMemFree(FullTargetName);
//
// In the preinstall mode, add the file to RenameList
//
if( PreInstall && PreinstallRememberFile ) {
PFILE_TO_RENAME File;
File = SpMemAlloc(sizeof(FILE_TO_RENAME));
File->SourceFilename = SpDupStringW(FileToCopy->SourceFilename);
wcscpy((PWSTR)TemporaryBuffer,L"\\");
if(TargetRoot) {
SpConcatenatePaths((PWSTR)TemporaryBuffer,TargetRoot);
}
SpConcatenatePaths((PWSTR)TemporaryBuffer,FileToCopy->TargetDirectory);
File->TargetDirectory = SpDupStringW((PWSTR)TemporaryBuffer);
File->TargetFilename = SpDupStringW((PWSTR)FileToCopy->TargetFilename);
File->Next = RenameList;
RenameList = File;
}
}
VOID
SpCopyFilesScreenRepaint(
IN PWSTR FullSourcename, OPTIONAL
IN PWSTR FullTargetname, OPTIONAL
IN BOOLEAN RepaintEntireScreen
)
{
PWSTR p;
UNREFERENCED_PARAMETER(FullTargetname);
//
// Repaint the entire screen if necessary.
//
if(RepaintEntireScreen) {
SpStartScreen(SP_SCRN_SETUP_IS_COPYING,0,6,TRUE,FALSE,DEFAULT_ATTRIBUTE);
if(FileCopyGauge) {
SpDrawGauge(FileCopyGauge);
}
}
//
// Place the name of the file being copied on the rightmost
// area of the status line.
//
if(FullSourcename) {
if(RepaintEntireScreen) {
SpvidClearScreenRegion(
0,
VideoVars.ScreenHeight-STATUS_HEIGHT,
VideoVars.ScreenWidth,
STATUS_HEIGHT,
DEFAULT_STATUS_BACKGROUND
);
SpDisplayStatusActionLabel(SP_STAT_COPYING,12);
}
//
// Isolate the filename part of the sourcename.
//
if(p = wcsrchr(FullSourcename,L'\\')) {
p++;
} else {
p = FullSourcename;
}
SpDisplayStatusActionObject(p);
}
}
VOID
SpCopyFilesInCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice,
IN PWSTR TargetRoot
)
/*++
Routine Description:
Iterate the copy list for each setup source disk and prompt for
the disk and copy/decompress all the files on it.
Arguments:
SifHandle - supplies handle to setup information file.
DiskFileLists - supplies the copy list, in the form of an array
of structures, one per disk.
DiskCount - supplies number of elements in the DiskFileLists array,
ie, the number of setup disks.
SourceDevicePath - supplies the path of the device from which files
are to be copied (ie, \device\floppy0, etc).
DirectoryOnSourceDevice - supplies the directory on the source device
where files are to be found.
TargetRoot - supplies root directory of target. All target directory
specifications are relative to this directory on the target.
Return Value:
None.
--*/
{
ULONG DiskNo;
PDISK_FILE_LIST pDisk;
PFILE_TO_COPY pFile;
ULONG TotalFileCount;
ULONG CheckSum;
BOOLEAN FileSkipped;
ULONG CopyFlags;
#ifdef _FASTRECOVER_
PWSTR CopySourceDevicePath = SourceDevicePath;
#endif
//
// Compute the total number of files.
//
for(TotalFileCount=DiskNo=0; DiskNo<DiskCount; DiskNo++) {
TotalFileCount += DiskFileLists[DiskNo].FileCount;
}
//
// Create a gas gauge.
//
SpFormatMessage((PWSTR)TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_SETUP_IS_COPYING);
FileCopyGauge = SpCreateAndDisplayGauge(TotalFileCount,0,15,(PWSTR)TemporaryBuffer);
ASSERT(FileCopyGauge);
CLEAR_CLIENT_SCREEN();
SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
//
// Copy files on each disk.
//
for(DiskNo=0; DiskNo<DiskCount; DiskNo++) {
pDisk = &DiskFileLists[DiskNo];
//
// Don't bother with this disk if there are no files
// to be copied from it.
//
if(pDisk->FileCount == 0) {
continue;
}
#ifdef _FASTRECOVER_
//wfc
CopySourceDevicePath = !_wcsnicmp(pDisk->TagFile,L"\\flop",5) ? L"\\device\\floppy0"
: SourceDevicePath;
#endif
//
// Prompt the user to insert the disk.
//
SpPromptForDisk(
pDisk->Description,
#ifdef _FASTRECOVER_
CopySourceDevicePath,
#else
SourceDevicePath,
#endif
pDisk->TagFile,
FALSE, // no ignore disk in drive
FALSE, // no allow escape
TRUE, // warn multiple prompts
NULL // don't care about redraw flag
);
//
// Passing the empty string as the first arg forces
// the action area of the status line to be set up.
// Not doing so results in the "Copying: xxxxx" to be
// flush left on the status line instead of where
// it belongs (flush right).
//
SpCopyFilesScreenRepaint(L"",NULL,TRUE);
//
// Copy each file on the source disk.
//
ASSERT(pDisk->FileList);
for(pFile=pDisk->FileList; pFile; pFile=pFile->Next) {
//
// Copy the file.
//
// If the file is listed for lock smashing then we need to smash it
// if installing UP on x86 (we don't bother with the latter
// qualifications here).
//
// If there is an absolute target root specified, assume the
// file is being copied to the system partition and make it
// readonly/hidden/system.
//
// On upgrade, we need to know if the file is listed for oem overwrite.
//
CopyFlags = ( (WinntSetup && (NTUpgrade != UpgradeFull))
? COPY_DELETESOURCE : 0)
#ifdef _X86_
| (IsFileFlagSet(SifHandle,pFile->TargetFilename,FILEFLG_SMASHLOCKS) ? COPY_SMASHLOCKS : 0)
#endif
| (SkipMissingFiles ? COPY_SKIPIFMISSING : 0)
| ( ((NTUpgrade == UpgradeFull)
&& IsFileFlagSet(SifHandle,pFile->TargetFilename,FILEFLG_UPGRADEOVERWRITEOEM))
? COPY_OVERWRITEOEMFILE : 0);
if((NTUpgrade != UpgradeFull) || IsFileFlagSet(SifHandle,pFile->SourceFilename,FILEFLG_NOVERSIONCHECK)) {
CopyFlags |= COPY_NOVERSIONCHECK;
}
SpCopyFileWithRetry(
pFile,
#ifdef _FASTRECOVER_
CopySourceDevicePath,
#else
SourceDevicePath,
#endif
DirectoryOnSourceDevice,
pDisk->Directory,
pFile->AbsoluteTargetDirectory ? NULL : TargetRoot,
pFile->AbsoluteTargetDirectory ? ATTR_RHS : 0,
SpCopyFilesScreenRepaint,
&CheckSum,
&FileSkipped,
CopyFlags
);
//
// Log the file
//
if( !FileSkipped ) {
SpLogOneFile( pFile,
pFile->AbsoluteTargetDirectory ? NULL : TargetRoot,
NULL, // DirectoryOnSourceDevice,
NULL,
NULL,
CheckSum );
}
//
// Advance the gauge.
//
SpTickGauge(FileCopyGauge);
}
}
SpDestroyGauge(FileCopyGauge);
FileCopyGauge = NULL;
}
VOID
SpInitializeFileLists(
IN PVOID SifHandle,
OUT PDISK_FILE_LIST *DiskFileLists,
OUT PULONG DiskCount
)
/*++
Routine Description:
Initialize disk file lists. This involves looking in a given section
in the sectup information file and fetching information for each
disk specified there. The data is expected to be in the format
[<SifSection>]
<MediaShortname> = <Description>,<TagFile>[,,<Directory>]
...
(Note that <Directory> is the third field -- the 2 commas
are not a typo -- field 2 is unused.)
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - receives pointer to an array of disk file list
structures, one per line in SifSection. The caller must free
this buffer when finished with it.
DiskCount - receives number of elements in DiskFileLists array.
Return Value:
None.
--*/
{
unsigned pass;
PWSTR mediaShortname,description,tagFile,directory;
PDISK_FILE_LIST diskFileLists;
PWSTR SectionName;
ULONG TotalCount;
ULONG SectionCount;
ULONG i,u;
BOOLEAN Found;
diskFileLists = SpMemAlloc(0);
TotalCount = 0;
for(pass=0; pass<2; pass++) {
//
// On first pass do the platform-specific section.
//
SectionName = pass
? SIF_SETUPMEDIA
: SpMakePlatformSpecificSectionName(SIF_SETUPMEDIA);
//
// Determine the number of media specifications
// in the given section.
//
SectionCount = SpCountLinesInSection(SifHandle,SectionName);
diskFileLists = SpMemRealloc(
diskFileLists,
(TotalCount+SectionCount) * sizeof(DISK_FILE_LIST)
);
//
// Zero out the new part of the buffer we just reallocated.
//
RtlZeroMemory(
diskFileLists + TotalCount,
SectionCount * sizeof(DISK_FILE_LIST)
);
for(i=0; i<SectionCount; i++) {
//
// Fetch parameters for this disk.
//
mediaShortname = SpGetKeyName(SifHandle,SectionName,i);
if(!mediaShortname) {
SpFatalSifError(SifHandle,SectionName,NULL,i,(ULONG)(-1));
}
//
// Ignore if we've already processed a media with this
// shortname. This lets the platform-specific one override
// the platform-independent one.
//
Found = FALSE;
for(u=0; u<TotalCount; u++) {
if(!_wcsicmp(mediaShortname,diskFileLists[u].MediaShortname)) {
Found = TRUE;
break;
}
}
if(!Found) {
SpGetSourceMediaInfo(SifHandle,mediaShortname,&description,&tagFile,&directory);
//
// Initialize the disk file list structure.
//
diskFileLists[TotalCount].MediaShortname = mediaShortname;
diskFileLists[TotalCount].Description = description;
diskFileLists[TotalCount].TagFile = tagFile;
diskFileLists[TotalCount].Directory = directory;
TotalCount++;
}
}
if(!pass) {
SpMemFree(SectionName);
}
}
*DiskFileLists = diskFileLists;
*DiskCount = TotalCount;
}
VOID
SpFreeCopyLists(
IN OUT PDISK_FILE_LIST *DiskFileLists,
IN ULONG DiskCount
)
{
ULONG u;
PFILE_TO_COPY Entry,Next;
//
// Free the copy list on each disk.
//
for(u=0; u<DiskCount; u++) {
for(Entry=(*DiskFileLists)[u].FileList; Entry; ) {
Next = Entry->Next;
SpMemFree(Entry);
Entry = Next;
}
}
SpMemFree(*DiskFileLists);
*DiskFileLists = NULL;
}
BOOLEAN
SpCreateEntryInCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN ULONG DiskNumber,
IN PWSTR SourceFilename,
IN PWSTR TargetDirectory,
IN PWSTR TargetFilename,
IN PWSTR TargetDevicePath,
IN BOOLEAN AbsoluteTargetDirectory,
IN ULONG CopyFlags
)
/*++
Routine Description:
Adds an entry to a disk's file copy list after first verifying that
the file is not already on the disk copy list.
Arguments:
SifHandle - supplies handle to loaded text setup information file
(txtsetup.sif).
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
SourceFilename - supplies the name of the file as it exists on the
distribution media.
TargetDirectory - supplies the directory on the target media
into which the file will be copied.
TargetFilename - supplies the name of the file as it will exist
in the target tree.
TargetDevicePath - supplies the NT name of the device onto which the file
is to be copied (ie, \device\harddisk1\partition2, etc).
AbsoluteTargetDirectory - indicates whether TargetDirectory is a path from the
root, or relative to a root to specified later.
CopyFlags -
COPY_ALWAYS : always copied
COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
COPY_NEVER : never copied
Return Value:
TRUE if a new copy list entry was created; FALSE if not (ie, the file was
already on the copy list).
--*/
{
PDISK_FILE_LIST pDiskList;
PFILE_TO_COPY pListEntry;
UNREFERENCED_PARAMETER(DiskCount);
pDiskList = &DiskFileLists[DiskNumber];
for(pListEntry=pDiskList->FileList; pListEntry; pListEntry=pListEntry->Next) {
if(!_wcsicmp(pListEntry->TargetFilename,TargetFilename)
&& !_wcsicmp(pListEntry->SourceFilename,SourceFilename)
&& !_wcsicmp(pListEntry->TargetDirectory,TargetDirectory)
&& !_wcsicmp(pListEntry->TargetDevicePath,TargetDevicePath)
&& (pListEntry->AbsoluteTargetDirectory == AbsoluteTargetDirectory)
// && ( (pListEntry->CopyOptions == COPY_ALWAYS)
// || (CopyOptions == COPY_ALWAYS)
// || (CopyOptions == pListEntry->CopyOptions)
// )
)
{
//
// Return code indicates that we did not add a new entry.
//
return(FALSE);
}
}
//
// File not already found; create new entry
// and link into relevent disk's file list.
//
pListEntry = SpMemAlloc(sizeof(FILE_TO_COPY));
pListEntry->SourceFilename = SourceFilename;
pListEntry->TargetDirectory = TargetDirectory;
pListEntry->TargetFilename = TargetFilename;
pListEntry->TargetDevicePath = TargetDevicePath;
pListEntry->AbsoluteTargetDirectory = AbsoluteTargetDirectory;
pListEntry->Flags = CopyFlags;
pListEntry->Next = pDiskList->FileList;
pDiskList->FileList = pListEntry;
pDiskList->FileCount++;
//
// Return code indicates that we added a new entry.
//
return(TRUE);
}
VOID
SpAddMasterFileSectionToCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR TargetDevicePath,
IN PWSTR AbsoluteTargetDirectory,
IN ULONG CopyOptionsIndex
)
/*++
Routine Description:
Adds files listed in a setup information master file section to the
copy list.
Each line in the section is expected to be in a standard format:
[Section]
<source_filename> = <disk_ordinal>,
<target_directory_shortname>,
<copy_options_for_upgrade>,
<copy_options_for_textmode>,
<rename_name>
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
TargetDevicePath - supplies the NT name of the device onto which the files
are to be copied (ie, \device\harddisk1\partition2, etc).
AbsoluteTargetDirectory - If specified, supplies the directory into which the files
are to be copied on the target; overrides values specified on the lines
in [<SectionName>]. This allows the caller to specify an absolute directory
for the files instead of using indirection via a target directory shortname.
CopyOptionsIndex -
This specifies which index to look up to get the copy options field. If
the field is not present it is assumed that this this file is not to
be copied. Use:
INDEX_UPGRADE for upgrade copy options
INDEX_WINNTFILE for fresh installation copy options
--*/
{
ULONG Count,u,u1,CopyOptions;
PWSTR CopyOptionsString, sourceFilename,targetFilename,targetDirSpec,mediaShortname,TargetDirectory;
BOOLEAN fAbsoluteTargetDirectory;
PWSTR section;
unsigned i;
for(i=0; i<2; i++) {
section = i
? SpMakePlatformSpecificSectionName(SIF_FILESONSETUPMEDIA)
: SIF_FILESONSETUPMEDIA;
//
// Determine the number of files listed in the section.
// This value may be zero.
//
Count = SpCountLinesInSection(SifHandle,section);
if (fAbsoluteTargetDirectory = (AbsoluteTargetDirectory != NULL)) {
TargetDirectory = AbsoluteTargetDirectory;
}
for(u=0; u<Count; u++) {
//
// Get the copy options using the index provided. If the field
// is not present, we don't need to add this to the copy list
//
CopyOptionsString = SpGetSectionLineIndex(SifHandle,section,u,CopyOptionsIndex);
if(CopyOptionsString == NULL) {
continue;
}
CopyOptions = (ULONG)SpStringToLong(CopyOptionsString,NULL,10);
if(CopyOptions == COPY_NEVER) {
continue;
}
//
// get the source file name
//
sourceFilename = SpGetKeyName(SifHandle,section, u);
if(!sourceFilename) {
SpFatalSifError(SifHandle,section,NULL,u,0);
}
//
// get the destination target dir spec
//
targetDirSpec = SpGetSectionLineIndex(SifHandle,section,u,INDEX_DESTINATION);
if(!targetDirSpec) {
SpFatalSifError(SifHandle,section,NULL,u,INDEX_DESTINATION);
}
targetFilename = SpGetSectionLineIndex(SifHandle,section,u,INDEX_TARGETNAME);
if(!targetFilename || !(*targetFilename)) {
targetFilename = sourceFilename;
}
//
// Look up the actual target directory if necessary.
//
if(!fAbsoluteTargetDirectory) {
TargetDirectory = SpLookUpTargetDirectory(SifHandle,targetDirSpec);
}
//
// get the media shortname
//
mediaShortname = SpGetSectionLineIndex(SifHandle,section,u,INDEX_WHICHMEDIA);
if(!mediaShortname) {
SpFatalSifError(SifHandle,section,NULL,u,INDEX_WHICHMEDIA);
}
//
// Look up the disk in the disk file lists array.
//
for(u1=0; u1<DiskCount; u1++) {
if(!_wcsicmp(mediaShortname,DiskFileLists[u1].MediaShortname)) {
break;
}
}
//
// If we didn't find the media descriptor, then it's invalid.
//
if(u1 == DiskCount) {
SpFatalSifError(SifHandle,section,sourceFilename,0,INDEX_WHICHMEDIA);
}
//
// Create a new file list entry if the file is not already being copied.
//
SpCreateEntryInCopyList(
SifHandle,
DiskFileLists,
DiskCount,
u1,
sourceFilename,
TargetDirectory,
targetFilename,
TargetDevicePath,
fAbsoluteTargetDirectory,
CopyOptions
);
}
if(i) {
SpMemFree(section);
}
}
}
VOID
SpAddSingleFileToCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR SifSection,
IN PWSTR SifKey, OPTIONAL
IN ULONG SifLine,
IN PWSTR TargetDevicePath,
IN PWSTR TargetDirectory, OPTIONAL
IN ULONG CopyOptions,
IN BOOLEAN CheckForNoComp
)
/*++
Routine Description:
Adds a single file to the list of files to be copied.
The file, along with the directory into which it is to be copied
n the target and the name it is to receive on the target, is listed
in a section in the setup information file.
The filename is used to index the master file list to determine the
source media where it resides.
All this information is recorded in a structure associated with
the disk on which the file resides.
[SpecialFiles]
mpkernel = ntkrnlmp.exe,4,ntoskrnl.exe
upkernel = ntoskrnl.exe,4,ntoskrnl.exe
etc.
[MasterFileList]
ntkrnlmp.exe = d2
ntoskrnl.exe = d3
etc.
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
SifSection - supplies the name of the section that lists the file
being added to the copy list.
SifKey - if specified, supplies the keyname for the line in SifSection
that lists the file to be added to the copy list.
SifLine - if SifKey is not specified, this parameter supplies the 0-based
line number of the line in SifSection that lists the file to be added
to the copy list.
TargetDevicePath - supplies the NT name of the device onto which the file
is to be copied (ie, \device\harddisk1\partition2, etc).
TargetDirectory - If specified, supplies the directory into which the file
is to be copied on the target; overrides the value specified on the line
in SifSection. This allows the caller to specify an absolute directory
for the file instead of using indirection.
CopyOptions -
COPY_ALWAYS : always copied
COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
COPY_NEVER : never copied None.
CheckForNoComp - if true, check this file to see if it must remain uncompressed
on an NTFS system partition supporting compression.
If so, then OR the CopyOptions value with COPY_FORCENOCOMP.
Return Value:
None.
--*/
{
PWSTR sourceFilename,targetDirSpec,targetFilename;
ULONG u;
PWSTR mediaShortname;
BOOLEAN absoluteTargetDirectory;
//
// Get the source filename, target directory spec, and target filename.
//
if(SifKey) {
sourceFilename = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,0);
targetDirSpec = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,1);
targetFilename = SpGetSectionKeyIndex(SifHandle,SifSection,SifKey,2);
} else {
sourceFilename = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,0);
targetDirSpec = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,1);
targetFilename = SpGetSectionLineIndex(SifHandle,SifSection,SifLine,2);
}
//
// Validate source filename, target directory spec, and target filename.
//
if(!sourceFilename) {
SpFatalSifError(SifHandle,SifSection,SifKey,SifLine,0);
}
if(!targetDirSpec) {
SpFatalSifError(SifHandle,SifSection,SifKey,SifLine,1);
}
if(!targetFilename ||
(!_wcsicmp(SifSection, L"SCSI.Load") &&
!_wcsicmp(targetFilename,L"noload"))) {
targetFilename = sourceFilename;
}
//
// Look up the actual target directory if necessary.
//
if(TargetDirectory) {
absoluteTargetDirectory = TRUE;
} else {
absoluteTargetDirectory = FALSE;
TargetDirectory = SpLookUpTargetDirectory(SifHandle,targetDirSpec);
}
//
// Look up the file in the master file list to get
// the media shortname of the disk where the file is located.
//
mediaShortname = SpLookUpValueForFile(SifHandle,sourceFilename,INDEX_WHICHMEDIA,TRUE);
//
// Look up the disk in the disk file lists array.
//
for(u=0; u<DiskCount; u++) {
if(!_wcsicmp(mediaShortname,DiskFileLists[u].MediaShortname)) {
break;
}
}
//
// If we didn't find the media descriptor, then it's invalid.
//
if(u == DiskCount) {
SpFatalSifError(SifHandle,SIF_FILESONSETUPMEDIA,sourceFilename,0,INDEX_WHICHMEDIA);
}
//
// If necessary, check to see whether this file cannot use NTFS compression. If it cannot,
// then OR the CopyOptions with COPY_FORCENOCOMP.
//
if(CheckForNoComp && IsFileFlagSet(SifHandle,targetFilename,FILEFLG_FORCENOCOMP)) {
CopyOptions |= COPY_FORCENOCOMP;
}
//
// Create a new file list entry if the file is not already being copied.
//
SpCreateEntryInCopyList(
SifHandle,
DiskFileLists,
DiskCount,
u,
sourceFilename,
TargetDirectory,
targetFilename,
TargetDevicePath,
absoluteTargetDirectory,
CopyOptions
);
}
VOID
SpAddSectionFilesToCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR SectionName,
IN PWSTR TargetDevicePath,
IN PWSTR TargetDirectory,
IN ULONG CopyOptions,
IN BOOLEAN CheckForNoComp
)
/*++
Routine Description:
Adds files listed in a setup information file section to the copy list.
Each line in the section is expected to be in a standard format:
[Section]
<source_filename>,<target_directory_shortname>[,<target_filename>]
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
SectionName - supplies the name of the section that lists the files
being added to the copy list.
TargetDevicePath - supplies the NT name of the device onto which the files
are to be copied (ie, \device\harddisk1\partition2, etc).
TargetDirectory - If specified, supplies the directory into which the files
are to be copied on the target; overrides values specified on the lines
in [<SectionName>]. This allows the caller to specify an absolute directory
for the files instead of using indirection via a target directory shortname.
CopyOptions -
COPY_ALWAYS : always copied
COPY_ONLY_IF_PRESENT : copied only if present on the targetReturn Value:
COPY_ONLY_IF_NOT_PRESENT : not copied if present on the target
COPY_NEVER : never copied
CheckForNoComp - if true, then check each file to see if it must exist uncompressed
on an NTFS partition supporting compression (ie, NTLDR on x86).
--*/
{
ULONG Count,u;
//
// Determine the number of files listed in the section.
// This value may be zero.
//
Count = SpCountLinesInSection(SifHandle,SectionName);
for(u=0; u<Count; u++) {
//
// Add this line to the copy list.
//
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SectionName,
NULL,
u,
TargetDevicePath,
TargetDirectory,
CopyOptions,
CheckForNoComp
);
}
}
VOID
SpAddHalKrnlDetToCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR TargetDevicePath,
IN PWSTR SystemPartition,
IN PWSTR SystemPartitionDirectory,
IN BOOLEAN Uniprocessor
)
/*++
Routine Description:
Add the following files based on configuration:
- the up or mp kernel.
- the HAL
- the detect module [x86 only]
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
TargetDevicePath - supplies the NT name of the device that will hold the
nt tree.
SystemPartition - supplies the NT name of the device that will hold the
system partition.
SystemPartitionDirectoty - supplies the directory on the system partition
into which files that go on the system partition will be copied.
Uniprocessor - if true, then we are installing/upgrading a UP system.
Note that this a different question than the number of processors
in the system.
Return Value:
None.
--*/
{
PHARDWARE_COMPONENT pHw;
//
// Add the right kernel to the copy list.
//
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SPECIALFILES,
Uniprocessor ? SIF_UPKERNEL : SIF_MPKERNEL,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
//
// Add the hal to the file copy list.
// On x86 machines, the hal goes in the target winnt tree.
// On non-x86 machines, the hal goes on the system partition.
//
if( !PreInstall ||
(PreinstallHardwareComponents[HwComponentComputer] == NULL) ) {
pHw = HardwareComponents[HwComponentComputer];
} else {
pHw = PreinstallHardwareComponents[HwComponentComputer];
}
if(!pHw->ThirdPartyOptionSelected) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_HAL,
pHw->IdString,
0,
#ifdef _X86_
TargetDevicePath,
NULL,
#else
SystemPartition,
SystemPartitionDirectory,
#endif
COPY_ALWAYS,
FALSE
);
}
#ifdef _X86_
//
// If a third party computer was not specified, then there will be a
// detect module specified in the [ntdetect] section of the inf file
// for the computer.
// If a third-party computer was specified, then there may or may not
// be a detect module. If there is no detect module specified, then
// copy the 'standard' one.
//
{
PWSTR NtDetectId = NULL;
if(!pHw->ThirdPartyOptionSelected) {
NtDetectId = pHw->IdString;
} else {
if(!IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileDetect)) {
NtDetectId = SIF_STANDARD;
}
}
if(NtDetectId) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_NTDETECT,
NtDetectId,
0,
SystemPartition,
SystemPartitionDirectory,
COPY_ALWAYS,
FALSE
);
}
}
#endif
}
VOID
SpAddConditionalFilesToCopyList(
IN PVOID SifHandle,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR TargetDevicePath,
IN PWSTR SystemPartition,
IN PWSTR SystemPartitionDirectory,
IN BOOLEAN Uniprocessor
)
/*++
Routine Description:
Add files to the copy list that are copied based on the configuration
of the machine and user selections.
This may include:
- the up or mp kernel.
- abiosdsk
- vga files [x86 only]
- files for computer, keyboard, mouse, display, and layout
- scsi miniport drivers
- mouse and keyboard class drivers
- the HAL
- the detect module [x86 only]
Arguments:
SifHandle - supplies handle to loaded setup information file.
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
TargetDevicePath - supplies the NT name of the device that will hold the
nt tree.
SystemPartition - supplies the NT name of the device that will hold the
system partition.
SystemPartitionDirectoty - supplies the directory on the system partition
into which files that go on the system partition will be copied.
Uniprocessor - if true, then we are installing/upgrading a UP system.
Note that this a different question than the number of processors
in the system.
Return Value:
None.
--*/
{
ULONG i;
PHARDWARE_COMPONENT pHw;
PWSTR SectionName;
//
// Add the hal, kernel and ntdetect to the copy list
//
SpAddHalKrnlDetToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
TargetDevicePath,
SystemPartition,
SystemPartitionDirectory,
Uniprocessor
);
//
// If there are any abios disks, copy the abios disk driver.
//
if(AbiosDisksExist) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SPECIALFILES,
SIF_ABIOSDISK,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
}
//
// Always copy vga files.
//
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_VGAFILES,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
//
// Add the correct device driver files to the copy list.
//
for(i=0; i<HwComponentMax; i++) {
//
// Layout is handled elsewhere.
//
if(i == HwComponentLayout) {
continue;
}
if( !PreInstall ||
( PreinstallHardwareComponents[i] == NULL ) ) {
pHw = HardwareComponents[i];
} else {
pHw = PreinstallHardwareComponents[i];
}
for( ; pHw != NULL; pHw = pHw->Next ) {
//
// No files to copy here for third-party options.
// This is handled elsewhere.
//
if(pHw->ThirdPartyOptionSelected) {
continue;
}
//
// Get the name of the section containing files for this device.
//
SectionName = SpGetSectionKeyIndex(
SifHandle,
NonlocalizedComponentNames[i],
pHw->IdString,
INDEX_FILESECTION
);
if(!SectionName) {
SpFatalSifError(
SifHandle,
NonlocalizedComponentNames[i],
pHw->IdString,
0,
INDEX_FILESECTION
);
}
//
// Add that section's files to the copy list.
//
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SectionName,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
}
}
//
// Add the keyboard layout dll to the copy list.
//
if( !PreInstall ||
(PreinstallHardwareComponents[HwComponentLayout] == NULL) ) {
pHw = HardwareComponents[HwComponentLayout];
} else {
pHw = PreinstallHardwareComponents[HwComponentLayout];
}
//
if(!pHw->ThirdPartyOptionSelected) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_KEYBOARDLAYOUTFILES,
pHw->IdString,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
}
//
// Add scsi miniport drivers to the copy list.
// Because miniport drivers are only a single file,
// we just use the filename specified in [SCSI.Load] --
// no need for separate [files.xxxx] sections.
//
if( !PreInstall ||
( PreinstallScsiHardware == NULL ) ) {
pHw = ScsiHardware;
} else {
pHw = PreinstallScsiHardware;
}
for( ; pHw; pHw=pHw->Next) {
if(!pHw->ThirdPartyOptionSelected) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
L"SCSI.Load",
pHw->IdString,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
}
}
//
// If not being replaced by third-party ones, add keyboard and mouse
// class drivers.
// Note that in the pre-install case, keyboard and class drivers will
// be added if at least one retail mouse or keyborad driver are
// to be pre-installed.
//
if( !PreInstall ||
( PreinstallHardwareComponents[HwComponentMouse] == NULL ) ) {
pHw=HardwareComponents[HwComponentMouse];
} else {
pHw=PreinstallHardwareComponents[HwComponentMouse];
}
for( ;pHw;pHw=pHw->Next ) {
if(!pHw->ThirdPartyOptionSelected
|| !IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileClass))
{
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SPECIALFILES,
SIF_MOUSECLASS,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
//
// We don't need to continue to look at the other mouse drivers
// since we have already added the class driver
//
break;
}
}
if( !PreInstall ||
( PreinstallHardwareComponents[HwComponentKeyboard] == NULL ) ) {
pHw=HardwareComponents[HwComponentKeyboard];
} else {
pHw=PreinstallHardwareComponents[HwComponentKeyboard];
}
for( ;pHw;pHw=pHw->Next ) {
if(!pHw->ThirdPartyOptionSelected
|| !IS_FILETYPE_PRESENT(pHw->FileTypeBits,HwFileClass))
{
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SPECIALFILES,
SIF_KEYBOARDCLASS,
0,
TargetDevicePath,
NULL,
COPY_ALWAYS,
FALSE
);
//
// We don't need to continue to look at the other keyboard drivers
// since we have already added the class driver
//
break;
}
}
}
VOID
SpCopyThirdPartyDrivers(
IN PWSTR SourceDevicePath,
IN PWSTR SysrootDevice,
IN PWSTR Sysroot,
IN PWSTR SyspartDevice,
IN PWSTR SyspartDirectory,
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount
)
{
ULONG component;
PHARDWARE_COMPONENT pHw;
PHARDWARE_COMPONENT_FILE pHwFile;
FILE_TO_COPY FileDescriptor;
PWSTR TargetRoot;
PWSTR InfNameBases[HwComponentMax+1] = { L"cpt", L"vio", L"kbd", L"lay", L"ptr", L"scs" };
ULONG InfCounts[HwComponentMax+1] = { 0,0,0,0,0,0 };
WCHAR InfFilename[20];
ULONG CheckSum;
BOOLEAN FileSkipped;
ULONG TargetFileAttribs;
ULONG CopyFlags;
for(component=0; component<=HwComponentMax; component++) {
//
// If we're upgrading, then we only want to copy third-party HALs or SCSI
// drivers (if supplied)
//
if((NTUpgrade == UpgradeFull) &&
!((component == HwComponentComputer) || (component == HwComponentMax))) {
continue;
}
//
// Handle scsi specially.
//
pHw = (component==HwComponentMax) ? ( ( !PreInstall ||
( PreinstallScsiHardware == NULL )
)?
ScsiHardware :
PreinstallScsiHardware
)
:
( ( !PreInstall ||
( PreinstallHardwareComponents[component] == NULL )
)?
HardwareComponents[component] :
PreinstallHardwareComponents[component]
);
//
// Look at each instance of this component.
//
for( ; pHw; pHw=pHw->Next) {
//
// Skip this device if not a third-party selection.
//
if(!pHw->ThirdPartyOptionSelected) {
continue;
}
//
// Loop through the list of files associated with this selection.
//
for(pHwFile=pHw->Files; pHwFile; pHwFile=pHwFile->Next) {
//
// Assume the file goes on the nt drive (as opposed to
// the system partition drive) and that the target name
// is the same as the source name. Also, assume no special
// attributes (ie, FILE_ATTRIBUTE_NORMAL)
//
FileDescriptor.Next = NULL;
FileDescriptor.SourceFilename = pHwFile->Filename;
FileDescriptor.TargetDevicePath = SysrootDevice;
FileDescriptor.TargetFilename = FileDescriptor.SourceFilename;
FileDescriptor.Flags = COPY_ALWAYS;
TargetFileAttribs = 0;
switch(pHwFile->FileType) {
//
// Driver, port, and class type files are all device drivers
// and are treated the same -- they get copied to the
// system32\drivers directory.
//
case HwFileDriver:
case HwFilePort:
case HwFileClass:
TargetRoot = Sysroot;
FileDescriptor.TargetDirectory = L"system32\\drivers";
break;
//
// Dlls get copied to the system32 directory.
//
case HwFileDll:
TargetRoot = Sysroot;
FileDescriptor.TargetDirectory = L"system32";
break;
//
// Inf files get copied to the system32 directory and are
// renamed based on the component.
//
case HwFileInf:
if(InfCounts[component] < 99) {
InfCounts[component]++; // names start at 1
swprintf(
InfFilename,
L"oem%s%02d.inf",
InfNameBases[component],
InfCounts[component]
);
FileDescriptor.TargetFilename = InfFilename;
}
TargetRoot = Sysroot;
FileDescriptor.TargetDirectory = L"inf";
break;
//
// Hal files are renamed to hal.dll and copied to the system32
// directory (x86) or the system partition (non-x86).
//
case HwFileHal:
#ifdef _X86_
TargetRoot = Sysroot;
FileDescriptor.TargetDirectory = L"system32";
#else
TargetRoot = NULL;
FileDescriptor.TargetDevicePath = SyspartDevice;
FileDescriptor.TargetDirectory = SyspartDirectory;
TargetFileAttribs = ATTR_RHS;
#endif
FileDescriptor.TargetFilename = L"hal.dll";
break;
//
// Detect modules are renamed to ntdetect.com and copied to
// the root of the system partition (C:).
//
case HwFileDetect:
TargetRoot = NULL;
FileDescriptor.TargetDevicePath = SyspartDevice;
FileDescriptor.TargetDirectory = SyspartDirectory;
FileDescriptor.TargetFilename = L"ntdetect.com";
TargetFileAttribs = ATTR_RHS;
break;
}
if( !PreInstall ) {
//
// Prompt for the disk.
//
SpPromptForDisk(
pHwFile->DiskDescription,
SourceDevicePath,
pHwFile->DiskTagFile,
FALSE, // don't ignore disk in drive
FALSE, // don't allow escape
FALSE, // don't warn about multiple prompts
NULL // don't care about redraw flag
);
}
//
// Passing the empty string as the first arg forces
// the action area of the status line to be set up.
// Not doing so results in the "Copying: xxxxx" to be
// flush left on the status line instead of where
// it belongs (flush right).
//
SpCopyFilesScreenRepaint(L"",NULL,TRUE);
//
// Copy the file.
//
SpCopyFileWithRetry(
&FileDescriptor,
SourceDevicePath,
(PreInstall)? PreinstallOemSourcePath : pHwFile->Directory,
NULL,
TargetRoot,
TargetFileAttribs,
SpCopyFilesScreenRepaint,
&CheckSum,
&FileSkipped,
COPY_SOURCEISOEM
);
//
// Log the file
//
if( !FileSkipped ) {
SpLogOneFile( &FileDescriptor,
TargetRoot,
pHwFile->Directory,
pHwFile->DiskDescription,
pHwFile->DiskTagFile,
CheckSum );
}
//
// Remove the file from the copy list so that it won't be overwritten
//
SpRemoveEntryFromCopyList( DiskFileLists,
DiskCount,
FileDescriptor.TargetDirectory,
FileDescriptor.TargetFilename,
FileDescriptor.TargetDevicePath,
FileDescriptor.AbsoluteTargetDirectory );
}
}
}
#ifdef _ALPHA_
if(OemPalFilename) {
//
// Prompt for the OEM PAL disk.
//
SpPromptForDisk(
OemPalDiskDescription,
SourceDevicePath,
OemPalFilename,
FALSE, // don't ignore disk in drive
FALSE, // don't allow escape
FALSE, // don't warn about multiple prompts
NULL // don't care about redraw flag
);
SpCopyFilesScreenRepaint(L"",NULL,TRUE);
//
// Copy the file.
//
FileDescriptor.Next = NULL;
FileDescriptor.SourceFilename = OemPalFilename;
FileDescriptor.TargetFilename = FileDescriptor.SourceFilename;
FileDescriptor.Flags = COPY_ALWAYS;
FileDescriptor.TargetDevicePath = SyspartDevice;
FileDescriptor.TargetDirectory = SyspartDirectory;
SpCopyFileWithRetry(
&FileDescriptor,
SourceDevicePath,
L"",
NULL,
NULL,
ATTR_RHS,
SpCopyFilesScreenRepaint,
&CheckSum,
&FileSkipped,
COPY_SOURCEISOEM
);
//
// Log the file
//
if(!FileSkipped) {
SpLogOneFile( &FileDescriptor,
NULL,
L"",
OemPalDiskDescription,
OemPalFilename,
CheckSum
);
}
//
// Remove the file from the copy list so that it won't be overwritten
//
SpRemoveEntryFromCopyList( DiskFileLists,
DiskCount,
FileDescriptor.TargetDirectory,
FileDescriptor.TargetFilename,
FileDescriptor.TargetDevicePath,
FileDescriptor.AbsoluteTargetDirectory );
}
#endif
}
#ifdef _X86_
VOID
SpCopyNtbootddScreenRepaint(
IN PWSTR FullSourcename, OPTIONAL
IN PWSTR FullTargetname, OPTIONAL
IN BOOLEAN RepaintEntireScreen
)
{
UNREFERENCED_PARAMETER(FullSourcename);
UNREFERENCED_PARAMETER(FullTargetname);
UNREFERENCED_PARAMETER(RepaintEntireScreen);
//
// Just put up a message indicating that we are setting up
// boot params.
//
CLEAR_CLIENT_SCREEN();
SpDisplayStatusText(SP_STAT_DOING_NTBOOTDD,DEFAULT_STATUS_ATTRIBUTE);
}
VOID
SpCreateNtbootddSys(
IN PDISK_REGION NtPartitionRegion,
IN PWSTR NtPartitionDevicePath,
IN PWSTR Sysroot,
IN PWSTR SystemPartitionDevicePath
)
/*++
Routine Description:
Create c:\ntbootdd.sys if necessary.
The scsi miniport driver file fill be copied from the drivers directory
(where it was copied during the earlier file copy phase) to c:\ntbootdd.sys.
Arguments:
NtPartitionRegion - supplies the region descriptor for the disk region
onto which the user chose to install Windows NT.
NtPartitionDevicePath - supplies the nt namespace pathname for the
partition onto which the user chose to install Windows NT.
Sysroot - supplies the directory on the target partition.
SystemPartitionDevicePath - supplies the nt device path of the partition
onto which to copy ntbootdd.sys (ie, C:\).
Return Value:
None.
--*/
{
PWSTR MiniportDriverBasename;
PWSTR MiniportDriverFilename;
FILE_TO_COPY Descriptor;
PWSTR DriversDirectory,p;
ULONG CheckSum;
BOOLEAN FileSkipped;
//
// If the Nt Partition is not on a scsi disk, there's nothing to do.
//
MiniportDriverBasename = HardDisks[NtPartitionRegion->DiskNumber].ScsiMiniportShortname;
if(*MiniportDriverBasename == 0) {
return;
}
//
// If it's on a scsi disk that is visible through the BIOS,
// nothing to do.
//
p = SpNtToArc(NtPartitionDevicePath,PrimaryArcPath);
if(p) {
if(!_wcsnicmp(p,L"multi(",6) &&
!SpIsRegionBeyondCylinder1024(NtPartitionRegion)) {
SpMemFree(p);
return;
}
SpMemFree(p);
}
//
// Form the name of the scsi miniport driver.
//
wcscpy((PWSTR)TemporaryBuffer,MiniportDriverBasename);
wcscat((PWSTR)TemporaryBuffer,L".sys");
MiniportDriverFilename = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Form the full path to the drivers directory.
//
wcscpy((PWSTR)TemporaryBuffer,Sysroot);
SpConcatenatePaths((PWSTR)TemporaryBuffer,L"system32\\drivers");
DriversDirectory = SpDupStringW((PWSTR)TemporaryBuffer);
//
// When we are in upgrade mode we may or may not have the scsi
// miniport that we used for this boot of setup to recognise
// the target drive. We should check to see if this file does
// exist before trying the copy
//
if(NTUpgrade == UpgradeFull) {
PWSTR Driver;
wcscpy((PWSTR)TemporaryBuffer, NtPartitionDevicePath);
SpConcatenatePaths((PWSTR)TemporaryBuffer, DriversDirectory);
SpConcatenatePaths((PWSTR)TemporaryBuffer, MiniportDriverFilename);
Driver = SpDupStringW((PWSTR)TemporaryBuffer);
if(!SpFileExists(Driver, FALSE)) {
SpMemFree(Driver);
SpMemFree(MiniportDriverFilename);
SpMemFree(DriversDirectory);
return;
}
SpMemFree(Driver);
}
//
//
// Fill in the fields of the file descriptor.
//
Descriptor.SourceFilename = MiniportDriverFilename;
Descriptor.TargetDevicePath = SystemPartitionDevicePath;
Descriptor.TargetDirectory = L"";
Descriptor.TargetFilename = L"NTBOOTDD.SYS";
Descriptor.Flags = COPY_ALWAYS;
//
// Copy the file.
//
SpCopyFileWithRetry(
&Descriptor,
NtPartitionDevicePath,
DriversDirectory,
NULL,
NULL,
ATTR_RHS,
SpCopyNtbootddScreenRepaint,
&CheckSum,
&FileSkipped,
0
);
//
// Log the file
//
if( !FileSkipped ) {
SpLogOneFile( &Descriptor,
Sysroot,
NULL,
NULL,
NULL,
CheckSum );
}
//
// Clean up.
//
SpMemFree(MiniportDriverFilename);
SpMemFree(DriversDirectory);
}
#endif
VOID
SpCopyFiles(
IN PVOID SifHandle,
IN PDISK_REGION SystemPartitionRegion,
IN PDISK_REGION NtPartitionRegion,
IN PWSTR Sysroot,
IN PWSTR SystemPartitionDirectory,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice,
IN PWSTR ThirdPartySourceDevicePath
)
{
PDISK_FILE_LIST DiskFileLists;
ULONG DiskCount;
PWSTR NtPartition,SystemPartition;
PWSTR p;
BOOLEAN Uniprocessor;
ULONG n;
CLEAR_CLIENT_SCREEN();
Uniprocessor = !SpInstallingMp();
//
// Skip copying if directed to do so in the setup information file.
//
if((p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_DONTCOPY,0))
&& SpStringToLong(p,NULL,10))
{
KdPrint(("SETUP: DontCopy flag is set in .sif; skipping file copying\n"));
return;
}
//
// Initialize the diamond decompression engine.
//
SpdInitialize();
//
// Get the device path of the nt partition.
//
SpNtNameFromRegion(
NtPartitionRegion,
(PWSTR)TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalCurrent
);
NtPartition = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Get the device path of the system partition.
//
SpNtNameFromRegion(
SystemPartitionRegion,
(PWSTR)TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalCurrent
);
SystemPartition = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Create the system partition directory.
//
SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory);
//
// Create the nt tree.
//
SpCreateDirectoryStructureFromSif(SifHandle,SIF_NTDIRECTORIES,NtPartition,Sysroot);
//
// We may be installing into an old tree, so delete all files
// in the system32\config subdirectory (unless we're upgrading).
//
if(NTUpgrade != UpgradeFull) {
wcscpy((PWSTR)TemporaryBuffer, NtPartition);
SpConcatenatePaths((PWSTR)TemporaryBuffer, Sysroot);
SpConcatenatePaths((PWSTR)TemporaryBuffer, L"system32\\config");
p = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Enumerate and delete all files in system32\config subdirectory.
//
SpEnumFiles(p, SpDelEnumFile, &n, NULL);
SpMemFree(p);
} else {
//
// We go off and try to load the setup.log file for the
// installation we're about to upgrade. We do this because we
// need to transfer any loggged OEM files to our new setup.log.
// Otherwise, these entries would be lost in our new log file,
// and we would have an unrepairable installation if the OEM files
// lost were vital for booting.
//
ULONG RootDirLength;
NTSTATUS Status;
PVOID Inf;
//
// We first find out if the repair directory exists. If it does exist
// load setup.log from the repair directory. Otherwise, load setup.log
// from the WinNt directory
//
wcscpy((PWSTR)TemporaryBuffer, NtPartition);
SpConcatenatePaths((PWSTR)TemporaryBuffer, Sysroot);
RootDirLength = wcslen((PWSTR)TemporaryBuffer);
SpConcatenatePaths((PWSTR)TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
SpConcatenatePaths((PWSTR)TemporaryBuffer, SETUP_LOG_FILENAME);
if(!SpFileExists((PWSTR)TemporaryBuffer, FALSE)) {
((PWSTR)TemporaryBuffer)[RootDirLength] = L'\0';
SpConcatenatePaths((PWSTR)TemporaryBuffer, SETUP_LOG_FILENAME);
}
p = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Attempt to load old setup.log. If we can't, it's no big deal, We just
// won't have any old logged OEM files to merge in.
//
Status = SpLoadSetupTextFile(p, NULL, 0, &Inf, &n);
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: SpCopyFiles: can't load old setup.log (%lx)\n", Status));
} else {
//
// We found setup.log, so go and pull out anything pertinent.
//
_LoggedOemFiles = SppRetrieveLoggedOemFiles(Inf);
SpFreeTextFile(Inf);
}
SpMemFree(p);
//
// Prepare fonts for upgrade.
//
wcscpy((PWSTR)TemporaryBuffer,NtPartition);
SpConcatenatePaths((PWSTR)TemporaryBuffer,Sysroot);
SpConcatenatePaths((PWSTR)TemporaryBuffer,L"SYSTEM");
p = SpDupStringW((PWSTR)TemporaryBuffer);
SpPrepareFontsForUpgrade(p);
SpMemFree(p);
}
SpDisplayStatusText(SP_STAT_BUILDING_COPYLIST,DEFAULT_STATUS_ATTRIBUTE);
//
// Create the buffer for the log file.
//
_SetupLogFile = SpNewSetupTextFile();
if( _SetupLogFile == NULL ) {
KdPrint(("SETUP: Unable to create buffer for setup.log \n"));
}
//
// Generate media descriptors for the source media.
//
SpInitializeFileLists(
SifHandle,
&DiskFileLists,
&DiskCount
);
if(NTUpgrade != UpgradeFull) {
SpAddMasterFileSectionToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
NtPartition,
NULL,
INDEX_WINNTFILE
);
//
// Add the section of system partition files that are always copied.
//
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SYSPARTCOPYALWAYS,
SystemPartition,
SystemPartitionDirectory,
COPY_ALWAYS,
(BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
);
//
// Add conditional files to the copy list.
//
SpAddConditionalFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
NtPartition,
SystemPartition,
SystemPartitionDirectory,
Uniprocessor
);
}
else {
PHARDWARE_COMPONENT pHw;
//
// Add the section of system partition files that are always copied.
//
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_SYSPARTCOPYALWAYS,
SystemPartition,
SystemPartitionDirectory,
COPY_ALWAYS,
(BOOLEAN)(SystemPartitionRegion->Filesystem == FilesystemNtfs)
);
//
// Add the detected scsi miniport drivers to the copy list.
// Note that they are always copied to the target.
// These files have to be added to the copy list, before the ones marked
// as COPY_ONLY_IF_PRESENT. This is because in most cases, these files
// will be listed in [Files] with COPY_ONLY_IF_PRESENT set, and the
// function that creates entries in the copy list, will not create more
// than one entry for the same file. So if we add the file to the copy
// list, with COPY_ONLY_IF_PRESENT, there will be no way to replace
// or overwrite this entry in the list, and the file will end up not
// being copied.
//
// we just use the filename specified in [SCSI.Load] --
// no need for separate [files.xxxx] sections.
//
if( !PreInstall ||
( PreinstallScsiHardware == NULL ) ) {
pHw = ScsiHardware;
} else {
pHw = PreinstallScsiHardware;
}
for( ; pHw; pHw=pHw->Next) {
if(!pHw->ThirdPartyOptionSelected) {
SpAddSingleFileToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
L"SCSI.Load",
pHw->IdString,
0,
NtPartition,
NULL,
COPY_ALWAYS,
FALSE
);
}
}
//
// Add the files in the master file list with the copy options
// specified in each line on the INDEX_UPGRADE index. The options
// specify whether the file is to be copied at all or copied always
// or copied only if there on the target or not copied if there on
// the target.
//
SpAddMasterFileSectionToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
NtPartition,
NULL,
INDEX_UPGRADE
);
//
// Add the section of files that are upgraded only if it is not
// a Win31 upgrade
//
if(WinUpgradeType != UpgradeWin31) {
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_FILESUPGRADEWIN31,
NtPartition,
NULL,
COPY_ALWAYS,
FALSE
);
}
//
// Add the files for kernel, hal and detect module, these are
// handled specially because they involve renamed files (it is
// not possible to find out just by looking at the target file
// how to upgrade it).
// NOTE: This does not handle third-party HAL's (they get copied
// by SpCopyThirdPartyDrivers() below).
//
SpAddHalKrnlDetToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
NtPartition,
SystemPartition,
SystemPartitionDirectory,
Uniprocessor
);
//
// Add the new hive files so that our config stuff can get at them
// to extract new configuration information. These new hive files
// are renamed on the target so that they don't overwrite the
// existing hives.
SpAddSectionFilesToCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SIF_FILESNEWHIVES,
NtPartition,
NULL,
COPY_ALWAYS,
FALSE
);
}
//
// Copy third-party files.
// We do this here just in case there is some error in the setup information
// file -- we'd have caught it by now, before we start copying files to the
// user's hard drive.
// NOTE: SpCopyThirdPartyDrivers has a check to make sure it only copies the
// HAL and PAL if we're in an upgrade (in which case, we want to leave the other
// drivers alone).
//
SpCopyThirdPartyDrivers(
ThirdPartySourceDevicePath,
NtPartition,
Sysroot,
SystemPartition,
SystemPartitionDirectory,
DiskFileLists,
DiskCount
);
#if 0
KdPrint( ("SETUP: Sysroot = %ls \n", Sysroot ) );
KdPrint( ("SETUP: SystemPartitionDirectory = %ls \n", SystemPartitionDirectory ));
KdPrint( ("SETUP: SourceDevicePath = %ls \n", SourceDevicePath ));
KdPrint( ("SETUP: DirectoryOnSourceDevice = %ls \n", DirectoryOnSourceDevice ));
KdPrint( ("SETUP: ThirdPartySourceDevicePath = %ls \n", ThirdPartySourceDevicePath ));
// SpCreateSetupLogFile( DiskFileLists, DiskCount, NtPartitionRegion, Sysroot, DirectoryOnSourceDevice );
#endif
//
// Copy files in the copy list.
//
SpCopyFilesInCopyList(
SifHandle,
DiskFileLists,
DiskCount,
SourceDevicePath,
DirectoryOnSourceDevice,
Sysroot
);
#ifdef _X86_
//
// Take care of ntbootdd.sys.
//
SpCreateNtbootddSys(
NtPartitionRegion,
NtPartition,
Sysroot,
SystemPartition
);
#endif
if( PreInstall ) {
SppCopyOemDirectories( SourceDevicePath,
NtPartition,
Sysroot );
}
//
// Create the log file in disk
//
if( _SetupLogFile != NULL ) {
PWSTR p;
PWSTR TempName;
PWSTR Values[] = {
SIF_NEW_REPAIR_NT_VERSION
};
//
// Merge in the OEM files retrived from the previous setup.log
//
if(_LoggedOemFiles) {
SppMergeLoggedOemFiles(_SetupLogFile,
_LoggedOemFiles,
SystemPartition,
( *SystemPartitionDirectory != (WCHAR)'\0' )? SystemPartitionDirectory :
( PWSTR )L"\\",
NtPartition );
SpFreeTextFile(_LoggedOemFiles);
}
//
// Add signature
//
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_SIGNATURE,
SIF_NEW_REPAIR_VERSION_KEY,
Values,
1 );
//
// Add section that contains the paths
//
Values[0] = SystemPartition;
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_PATHS,
SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,
Values,
1 );
Values[0] = ( *SystemPartitionDirectory != (WCHAR)'\0' )? SystemPartitionDirectory :
( PWSTR )L"\\";
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_PATHS,
SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY,
Values,
1 );
Values[0] = NtPartition;
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_PATHS,
SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,
Values,
1 );
Values[0] = Sysroot;
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_PATHS,
SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY,
Values,
1 );
//
// Flush to disk
//
TempName = SpMemAlloc( ( wcslen( SETUP_REPAIR_DIRECTORY ) + 1 +
wcslen( SETUP_LOG_FILENAME ) + 1 ) * sizeof( WCHAR ) );
if( TempName != NULL ) {
wcscpy( TempName, SETUP_REPAIR_DIRECTORY );
SpConcatenatePaths(TempName, SETUP_LOG_FILENAME );
SpWriteSetupTextFile(_SetupLogFile,NtPartition,Sysroot,TempName);
} else {
KdPrint( ("SETUP: Out of memory. Unable to save = %ls \n", SETUP_LOG_FILENAME ));
}
SpMemFree( TempName );
SpFreeTextFile( _SetupLogFile );
_SetupLogFile = NULL;
}
//
// Free the media descriptors.
//
SpFreeCopyLists(&DiskFileLists,DiskCount);
SpMemFree(NtPartition);
SpMemFree(SystemPartition);
//
// Terminate diamond.
//
SpdTerminate();
}
VOID
SppDeleteFilesInSection(
IN PVOID SifHandle,
IN PWSTR SifSection,
IN PDISK_REGION NtPartitionRegion,
IN PWSTR Sysroot
)
/*++
Routine Description:
This routine enumerates files listed in the given section and deletes
them from the system tree.
Arguments:
SifHandle - supplies handle to loaded setup information file.
SifSection - section containing files to delete
NtPartitionRegion - region descriptor for volume on which nt resides.
Sysroot - root directory for nt.
Return Value:
None.
--*/
{
ULONG Count,u;
PWSTR filename, dirordinal, targetdir, ntdir;
NTSTATUS Status;
CLEAR_CLIENT_SCREEN();
//
// Get the device path of the nt partition.
//
SpNtNameFromRegion(
NtPartitionRegion,
(PWSTR)TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalCurrent
);
SpConcatenatePaths((PWSTR)TemporaryBuffer,Sysroot);
ntdir = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Determine the number of files listed in the section.
// This value may be zero.
//
Count = SpCountLinesInSection(SifHandle,SifSection);
for(u=0; u<Count; u++) {
filename = SpGetSectionLineIndex(SifHandle, SifSection, u, 0);
dirordinal = SpGetSectionLineIndex(SifHandle, SifSection, u, 1);
//
// Validate the filename and dirordinal
//
if(!filename) {
SpFatalSifError(SifHandle,SifSection,NULL,u,0);
}
if(!dirordinal) {
SpFatalSifError(SifHandle,SifSection,NULL,u,1);
}
//
// use the dirordinal key to get the path relative to sysroot of the
// directory the file is in
//
targetdir = SpLookUpTargetDirectory(SifHandle,dirordinal);
//
// display status bar
//
SpDisplayStatusText(SP_STAT_DELETING_FILE,DEFAULT_STATUS_ATTRIBUTE, filename);
//
// delete the file
//
while(TRUE) {
Status = SpDeleteFile(ntdir, targetdir, filename);
if(!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND) {
KdPrint(("SETUP: Unable to delete file %ws (%lx)\n",filename, Status));
//
// We can ignore this error since this just means that we have
// less free space on the hard disk. It is not critical for
// install.
//
if(!SpNonCriticalError(SifHandle, SP_SCRN_DELETE_FAILED, filename, NULL)) {
break;
}
}
else {
break;
}
}
}
SpMemFree(ntdir);
}
VOID
SppBackupFilesInSection(
IN PVOID SifHandle,
IN PWSTR SifSection,
IN PDISK_REGION NtPartitionRegion,
IN PWSTR Sysroot
)
/*++
Routine Description:
This routine enumerates files listed in the given section and deletes
backs them up in the given NT tree if found by renaming.
Arguments:
SifHandle - supplies handle to loaded setup information file.
SifSection - section containing files to backup
NtPartitionRegion - region descriptor for volume on which nt resides.
Sysroot - root directory for nt.
Return Value:
None.
--*/
{
ULONG Count,u;
PWSTR filename, dirordinal, backupfile, targetdir, ntdir;
WCHAR OldFile[MAX_PATH], NewFile[MAX_PATH];
NTSTATUS Status;
CLEAR_CLIENT_SCREEN();
//
// Get the device path of the nt partition.
//
SpNtNameFromRegion(
NtPartitionRegion,
(PWSTR)TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalCurrent
);
SpConcatenatePaths((PWSTR)TemporaryBuffer,Sysroot);
ntdir = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Determine the number of files listed in the section.
// This value may be zero.
//
Count = SpCountLinesInSection(SifHandle,SifSection);
for(u=0; u<Count; u++) {
filename = SpGetSectionLineIndex(SifHandle, SifSection, u, 0);
dirordinal = SpGetSectionLineIndex(SifHandle, SifSection, u, 1);
backupfile = SpGetSectionLineIndex(SifHandle, SifSection, u, 2);
//
// Validate the filename and dirordinal
//
if(!filename) {
SpFatalSifError(SifHandle,SifSection,NULL,u,0);
}
if(!dirordinal) {
SpFatalSifError(SifHandle,SifSection,NULL,u,1);
}
if(!backupfile) {
SpFatalSifError(SifHandle,SifSection,NULL,u,2);
}
//
// use the dirordinal key to get the path relative to sysroot of the
// directory the file is in
//
targetdir = SpLookUpTargetDirectory(SifHandle,dirordinal);
//
// display status bar
//
SpDisplayStatusText(SP_STAT_BACKING_UP_FILE,DEFAULT_STATUS_ATTRIBUTE, filename, backupfile);
//
// Form the complete pathnames of the old file name and the new file
// name
//
wcscpy(OldFile, ntdir);
SpConcatenatePaths(OldFile, targetdir);
wcscpy(NewFile, OldFile);
SpConcatenatePaths(OldFile, filename);
SpConcatenatePaths(NewFile, backupfile);
while(TRUE) {
if(!SpFileExists(OldFile, FALSE)) {
break;
}
if(SpFileExists(NewFile, FALSE)) {
SpDeleteFile(NewFile, NULL, NULL);
}
Status = SpRenameFile(OldFile, NewFile);
if(!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND) {
KdPrint(("SETUP: Unable to rename file %ws to %ws(%lx)\n",OldFile, NewFile, Status));
//
// We can ignore this error, since it is not critical
//
if(!SpNonCriticalError(SifHandle, SP_SCRN_BACKUP_FAILED, filename, backupfile)) {
break;
}
}
else {
break;
}
}
}
SpMemFree(ntdir);
}
VOID
SpDeleteAndBackupFiles(
IN PVOID SifHandle,
IN PDISK_REGION TargetRegion,
IN PWSTR TargetPath
)
{
//
// If we are not upgrading or installing into the same tree, then
// we have nothing to do
//
if(NTUpgrade == DontUpgrade) {
return;
}
//
// The order in which the tasks below are performed is important.
// So do not change it!!!
// This is necessary in order to upgrade 3rd party video drivers
// (eg. rename sni543x.sys to cirrus.sys, so that we only upgrade
// the driver if it was present).
//
//
// Backup files
//
SppBackupFilesInSection(
SifHandle,
(NTUpgrade == UpgradeFull) ? SIF_FILESBACKUPONUPGRADE : SIF_FILESBACKUPONOVERWRITE,
TargetRegion,
TargetPath
);
//
// Delete files
//
SppDeleteFilesInSection(
SifHandle,
SIF_FILESDELETEONUPGRADE,
TargetRegion,
TargetPath
);
}
BOOLEAN
SpDelEnumFile(
IN PWSTR DirName,
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
OUT PULONG ret,
IN PVOID Pointer
)
{
PWSTR FileName;
//
// Ignore subdirectories
//
if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
return TRUE; // continue processing
}
//
// We have to make a copy of the filename, because the info struct
// we get isn't NULL-terminated.
//
wcsncpy(
(PWSTR)TemporaryBuffer,
FileInfo->FileName,
FileInfo->FileNameLength
);
((PWSTR)TemporaryBuffer)[FileInfo->FileNameLength >> 1] = UNICODE_NULL;
FileName = SpDupStringW((PWSTR)TemporaryBuffer);
//
// display status bar
//
SpDisplayStatusText(
SP_STAT_DELETING_FILE,
DEFAULT_STATUS_ATTRIBUTE,
FileName
);
//
// Ignore return status of delete
//
SpDeleteFile(DirName, FileName, NULL);
SpMemFree(FileName);
return TRUE; // continue processing
}
VOID
SpLogOneFile(
IN PFILE_TO_COPY FileToCopy,
IN PWSTR Sysroot,
IN PWSTR DirectoryOnSourceDevice,
IN PWSTR DiskDescription,
IN PWSTR DiskTag,
IN ULONG CheckSum
)
{
PWSTR Values[ 5 ];
LPWSTR NtPath;
ULONG ValueCount;
PFILE_TO_COPY p;
WCHAR CheckSumString[ 9 ];
if( _SetupLogFile == NULL ) {
return;
}
Values[ 1 ] = CheckSumString;
Values[ 2 ] = DirectoryOnSourceDevice;
Values[ 3 ] = DiskDescription;
Values[ 4 ] = DiskTag;
swprintf( CheckSumString, ( LPWSTR )L"%lx", CheckSum );
p = FileToCopy;
#if 0
KdPrint( ("SETUP: Source Name = %ls, \t\tTargetDirectory = %ls \t\tTargetName = %ls\t\tTargetDevice = %ls, \tAbsoluteDirectory = %d \n",
p->SourceFilename,
p->TargetDirectory,
p->TargetFilename,
p->TargetDevicePath,
p->AbsoluteTargetDirectory ));
#endif
Values[0] = p->SourceFilename;
ValueCount = ( DirectoryOnSourceDevice == NULL )? 2 : 5;
if( ( Sysroot == NULL ) ||
( wcslen( p->TargetDirectory ) == 0 )
) {
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_SYSPARTFILES,
p->TargetFilename,
Values,
ValueCount );
} else {
NtPath = SpDupStringW( Sysroot );
NtPath = SpMemRealloc( NtPath,
sizeof( WCHAR ) * ( wcslen( Sysroot ) +
wcslen( p->TargetDirectory ) +
wcslen( p->TargetFilename ) +
2 + // for possible two extra back slashes
1 // for the terminating NULL
) );
SpConcatenatePaths( NtPath, p->TargetDirectory );
SpConcatenatePaths( NtPath, p->TargetFilename );
SpAddLineToSection( _SetupLogFile,
SIF_NEW_REPAIR_WINNTFILES,
NtPath,
Values,
ValueCount );
SpMemFree( NtPath );
}
}
PVOID
SppRetrieveLoggedOemFiles(
PVOID OldLogFile
)
{
PVOID NewLogFile;
BOOLEAN OldFormatSetupLogFile, FilesRetrieved = FALSE;
PWSTR SectionName[2];
ULONG FileCount, SectionIndex, i;
PWSTR TargetFileName;
PWSTR OemDiskDescription, OemDiskTag, OemSourceDirectory;
PWSTR Values[5];
//
// Create a new setup.log file to merge the OEM files into
//
NewLogFile = SpNewSetupTextFile();
if(!NewLogFile) {
KdPrint(("SETUP: Unable to create new setup.log buffer for OEM merging.\n"));
return NULL;
}
//
// Determine whether setup.log has the new or old style
//
if(OldFormatSetupLogFile = !IsSetupLogFormatNew(OldLogFile)) {
SectionName[0] = SIF_REPAIRSYSPARTFILES;
SectionName[1] = SIF_REPAIRWINNTFILES;
} else {
SectionName[0] = SIF_NEW_REPAIR_SYSPARTFILES;
SectionName[1] = SIF_NEW_REPAIR_WINNTFILES;
}
if(OldFormatSetupLogFile) {
//
// I don't know if we even want to mess with this.
// The format of setup.log in NT 3.1 makes it impossible
// to identify any OEM files except for SCSI files, and
// even then the tagfile name is lost. I would have to use
// the driver filename itself as a substitute for the tagfile
// name (which is what NT 3.1 repair did--UGGHH!!)
//
} else {
//
// Retrieve logged OEM files first from system partition, then
// from winnt directory.
//
for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
FileCount = SpCountLinesInSection(OldLogFile, SectionName[SectionIndex]);
for(i=0; i<FileCount; i++) {
OemSourceDirectory = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 2);
OemDiskTag = NULL;
if(OemSourceDirectory) {
OemDiskDescription = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 3);
if(OemDiskDescription) {
OemDiskTag = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 4);
}
}
if(OemDiskTag) { // then we have an OEM file
TargetFileName = SpGetKeyName(OldLogFile, SectionName[SectionIndex], i);
Values[0] = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 0);
Values[1] = SpGetSectionLineIndex(OldLogFile, SectionName[SectionIndex], i, 1);
Values[2] = OemSourceDirectory;
Values[3] = OemDiskDescription;
Values[4] = OemDiskTag;
SpAddLineToSection(NewLogFile,
SectionName[SectionIndex],
TargetFileName,
Values,
5
);
FilesRetrieved = TRUE;
}
}
}
}
if(FilesRetrieved) {
return NewLogFile;
} else {
SpFreeTextFile(NewLogFile);
return NULL;
}
}
VOID
SppMergeLoggedOemFiles(
IN PVOID DestLogHandle,
IN PVOID OemLogHandle,
IN PWSTR SystemPartition,
IN PWSTR SystemPartitionDirectory,
IN PWSTR NtPartition
)
{
PWSTR SectionName[2] = {SIF_NEW_REPAIR_SYSPARTFILES, SIF_NEW_REPAIR_WINNTFILES};
PWSTR FullPathNames[2] = {NULL, NULL};
ULONG FileCount, SectionIndex, i, j;
PWSTR TargetFileName;
PWSTR Values[5];
//
// First build the target path. It will be used to check if
// an existing OEM file still exists on the new installation
// (An OEM file could listed in the FilesToDelete section of txtsetup.sif)
//
wcscpy( (PWSTR)TemporaryBuffer, SystemPartition );
SpConcatenatePaths((PWSTR)TemporaryBuffer, SystemPartitionDirectory );
FullPathNames[0] = SpDupStringW((PWSTR)TemporaryBuffer);
FullPathNames[1] = SpDupStringW(NtPartition);
//
// Merge logged OEM files first from system partition, then
// from winnt directory.
//
for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
FileCount = SpCountLinesInSection(OemLogHandle, SectionName[SectionIndex]);
for(i=0; i<FileCount; i++) {
TargetFileName = SpGetKeyName(OemLogHandle, SectionName[SectionIndex], i);
//
// Find out if there's already an entry for this file. If so, then don't
// merge in the OEM file.
//
if(!SpGetSectionKeyExists(DestLogHandle, SectionName[SectionIndex], TargetFileName)) {
PWSTR p;
//
// Find out if the OEM file still exists on the target system.
// If it doesn't exist, don't merge in the OEM file.
//
wcscpy( (PWSTR)TemporaryBuffer, FullPathNames[SectionIndex] );
SpConcatenatePaths((PWSTR)TemporaryBuffer, TargetFileName );
p = SpDupStringW((PWSTR)TemporaryBuffer);
if(SpFileExists(p, FALSE)) {
for(j = 0; j < 5; j++) {
Values[j] = SpGetSectionLineIndex(OemLogHandle, SectionName[SectionIndex], i, j);
}
SpAddLineToSection(DestLogHandle,
SectionName[SectionIndex],
TargetFileName,
Values,
5
);
}
SpMemFree(p);
}
}
}
SpMemFree( FullPathNames[0] );
SpMemFree( FullPathNames[1] );
}
BOOLEAN
SppIsFileLoggedAsOemFile(
IN PWSTR TargetFileName
)
{
PWSTR SectionName[2] = {SIF_NEW_REPAIR_SYSPARTFILES, SIF_NEW_REPAIR_WINNTFILES};
ULONG FileCount, SectionIndex;
BOOLEAN FileIsOem;
// KdPrint(( "SETUP: SppIsFileLoggedAsOemFile() is checking %ls \n", TargetFileName ));
FileIsOem = FALSE;
if( _LoggedOemFiles ) {
//
// Look first in the from system partition section, then
// in the winnt section.
//
for(SectionIndex = 0; SectionIndex < 2; SectionIndex++) {
if( SpGetSectionKeyExists( _LoggedOemFiles, SectionName[SectionIndex], TargetFileName)) {
FileIsOem = TRUE;
break;
}
}
}
return( FileIsOem );
}
BOOLEAN
SpRemoveEntryFromCopyList(
IN PDISK_FILE_LIST DiskFileLists,
IN ULONG DiskCount,
IN PWSTR TargetDirectory,
IN PWSTR TargetFilename,
IN PWSTR TargetDevicePath,
IN BOOLEAN AbsoluteTargetDirectory
)
/*++
Routine Description:
Removes an entry from a disk's file copy list.
Arguments:
DiskFileLists - supplies an array of file lists, one for each distribution
disk in the product.
DiskCount - supplies number of elements in the DiskFileLists array.
TargetDirectory - supplies the directory on the target media
into which the file will be copied.
TargetFilename - supplies the name of the file as it will exist
in the target tree.
TargetDevicePath - supplies the NT name of the device onto which the file
is to be copied (ie, \device\harddisk1\partition2, etc).
AbsoluteTargetDirectory - indicates whether TargetDirectory is a path from the
root, or relative to a root to specified later.
Return Value:
TRUE if a new copy list entry was created; FALSE if not (ie, the file was
already on the copy list).
--*/
{
PDISK_FILE_LIST pDiskList;
PFILE_TO_COPY pListEntry;
ULONG DiskNumber;
for(DiskNumber=0; DiskNumber<DiskCount; DiskNumber++) {
pDiskList = &DiskFileLists[DiskNumber];
for(pListEntry=pDiskList->FileList; pListEntry; pListEntry=pListEntry->Next) {
if(!_wcsicmp(pListEntry->TargetFilename,TargetFilename)
&& !_wcsicmp(pListEntry->TargetDirectory,TargetDirectory)
&& !_wcsicmp(pListEntry->TargetDevicePath,TargetDevicePath)
&& (pListEntry->AbsoluteTargetDirectory == AbsoluteTargetDirectory)) {
pListEntry->Flags &= ~COPY_DISPOSITION_MASK;
pListEntry->Flags |= COPY_NEVER;
KdPrint(( "SETUP: SpRemoveEntryFromCopyList() removed %ls from copy list \n", TargetFilename ));
return( TRUE );
}
}
}
// KdPrint(( "SETUP: SpRemoveEntryFromCopyList() failed to remove %ls from copy list \n", TargetFilename ));
return( FALSE );
}
NTSTATUS
SpMoveFileOrDirectory(
IN PWSTR SrcPath,
IN PWSTR DestPath
)
/*++
Routine Description:
This routine attempts to move a source file or directory, to a target
file or directory.
Note: This function will fail if the source and destination paths do not
point to the same volume.
Arguments:
SrcPath: Absolute path to the source file or directory.
This path should include the path to the source device.
DestPath: Absolute path to the destination file or directory.
This path should include the path to the source device.
Return Value:
NTSTATUS
--*/
{
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING SrcName;
HANDLE hSrc;
NTSTATUS Status;
WCHAR RenameFileInfoBuffer[ MAX_PATH + 20 ];
PFILE_RENAME_INFORMATION RenameFileInfo;
//
// Initialize names and attributes.
//
INIT_OBJA(&Obja,&SrcName,SrcPath);
Status = ZwCreateFile( &hSrc,
FILE_GENERIC_READ,
&Obja,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
0,
NULL,
0 );
if( !NT_SUCCESS( Status ) ) {
KdPrint(("SETUP: Unable to open source file %ws. Status = %lx\n",SrcPath, Status));
return( Status );
}
RenameFileInfo = (PFILE_RENAME_INFORMATION)RenameFileInfoBuffer;
RenameFileInfo->ReplaceIfExists = TRUE;
RenameFileInfo->RootDirectory = NULL;
RenameFileInfo->FileNameLength = wcslen( DestPath )*sizeof( WCHAR );
RtlMoveMemory(RenameFileInfo->FileName,DestPath,(wcslen( DestPath )+1)*sizeof(WCHAR));
Status = ZwSetInformationFile( hSrc,
&IoStatusBlock,
RenameFileInfo,
sizeof(RenameFileInfoBuffer),
FileRenameInformation );
if(!NT_SUCCESS(Status)) {
KdPrint(("SETUP: unable to set attribute on %ws. Status = %lx\n",SrcPath, Status));
}
ZwClose(hSrc);
return( Status );
}
BOOLEAN
SppCopyDirRecursiveCallback(
IN PWSTR SrcPath,
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
OUT PULONG ReturnData,
IN PVOID DestPath
)
/*++
Routine Description:
This routine is called by the file enumerator as a callback for
each file or subdirectory found in the source directory.
If FileInfo represents a file, then we copy the file to the destination.
If FileInfo represents a directory, then we copy the directory recursivelly.
Arguments:
SrcPath - Absolute path to the source directory. This path should contain
the path to the source device.
FileInfo - supplies find data for a file in the source dir.
ReturnData - receives an error code if an error occurs.
We ignore errors in this routine and thus we always
just fill this in with NO_ERROR.
DestPath - Absolute path to the destination directory. This path must
contain the path to the destination device.
Return Value:
Always TRUE.
--*/
{
PWSTR p, q;
PWSTR temp;
ULONG Len;
NTSTATUS Status;
*ReturnData = NO_ERROR;
//
// Build the new SrcPath
// Note how we use the temporary buffer. Be careful if you
// change this code.
//
temp = (PWSTR)(TemporaryBuffer + (sizeof(TemporaryBuffer)/2));
Len = FileInfo->FileNameLength/sizeof(WCHAR);
wcsncpy(temp,FileInfo->FileName,Len);
temp[Len] = 0;
wcscpy((PWSTR)TemporaryBuffer,SrcPath);
SpConcatenatePaths((PWSTR)TemporaryBuffer,temp);
p = SpDupStringW((PWSTR)TemporaryBuffer);
if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
//
// This is a directory
//
if( (wcscmp( temp, L"." ) != 0) &&
(wcscmp( temp, L".." ) != 0) ) {
q = SpDupStringW(temp);
SpCopyDirRecursive( p,
(PWSTR)DestPath,
q );
SpMemFree(q);
}
} else {
//
// It is a file. Copy the file
//
wcscpy((PWSTR)TemporaryBuffer,(PWSTR)DestPath);
SpConcatenatePaths((PWSTR)TemporaryBuffer,temp);
q = SpDupStringW((PWSTR)TemporaryBuffer);
SpCopyFilesScreenRepaint(p, NULL, FALSE);
// if( SpFileExists( p, FALSE ) ) {
// SpDeleteFile( p, NULL, NULL );
// }
Status = SpCopyFileUsingNames( p, q, 0, COPY_DELETESOURCE );
if( !NT_SUCCESS( Status ) ) {
KdPrint(("SETUP: unable copy %ws. Status = %lx\n", p, Status));
SpCopyFilesScreenRepaint(L"", NULL, TRUE);
}
SpMemFree(q);
}
SpMemFree(p);
return(TRUE);
}
VOID
SpCopyDirRecursive(
IN PWSTR SrcPath,
IN PWSTR DestDevPath,
IN PWSTR DestDirPath
)
/*++
Routine Description:
This routine recursively copies a src directory to a destination directory.
Arguments:
SrcPath: Absolute path to the source directory. This path should include
the path to the source device.
DestDevPath: Path to the destination device.
DestDirPath: Path to the destination directory.
Return Value:
None.
--*/
{
ULONG n;
PWSTR p;
PWSTR r;
NTSTATUS Status;
//
// Create the target directory
//
wcscpy((PWSTR)TemporaryBuffer, DestDevPath);
SpConcatenatePaths((PWSTR)TemporaryBuffer, DestDirPath);
p = SpDupStringW((PWSTR)TemporaryBuffer);
if( !SpFileExists( p, TRUE ) ) {
//
// If the directory doesn't exist, then try to move (rename) the
// source directory.
//
Status = SpMoveFileOrDirectory( SrcPath, p );
if( NT_SUCCESS( Status ) ) {
SpMemFree(p);
return;
}
//
// If unable to rename the source directory, then create the
// target directory
//
SpCreateDirectory( DestDevPath,
NULL,
DestDirPath );
SpCopyFilesScreenRepaint(L"", NULL, TRUE);
}
//
// Enumerate and copy all files in the source directory to the
// destination directory.
//
SpEnumFiles(SrcPath, SppCopyDirRecursiveCallback, &n, p);
SpMemFree(p);
}
VOID
SppCopyOemDirectories(
IN PWSTR SourceDevicePath,
IN PWSTR NtPartition,
IN PWSTR Sysroot
)
/*++
Routine Description:
This routine recursively copies a src directory to a destination directory.
Arguments:
SourceDevicePath: Path to the device that contains the source.
NtPartition: Path to the drive that contains the system.
Systroot: Directory where the system is installed.
Return Value:
None.
--*/
{
PWSTR r, s, t;
WCHAR Drive[3];
PDISK_REGION TargetRegion;
//
// Check if the subdirectory $OEM$\\$$ exists on the source directory.
// If it exists, then tree copy the directory on top of %SystemRoot%
//
wcscpy((PWSTR)TemporaryBuffer, SourceDevicePath);
SpConcatenatePaths( (PWSTR)TemporaryBuffer, PreinstallOemSourcePath );
r = wcsrchr( (PWSTR)TemporaryBuffer, (WCHAR)'\\' );
if( r != NULL ) {
*r = (WCHAR)'\0';
}
SpConcatenatePaths( (PWSTR)TemporaryBuffer, WINNT_OEM_FILES_SYSROOT_W );
r = SpDupStringW((PWSTR)TemporaryBuffer);
if( SpFileExists( r, TRUE ) ) {
SpCopyFilesScreenRepaint(L"", NULL, TRUE);
SpCopyDirRecursive( r,
NtPartition,
Sysroot );
}
SpMemFree( r );
//
// Copy the subdirectories $OEM$\<drive letter> to the root of each
// corresponding drive.
// These directories are:
//
// $OEM$\C
// $OEM$\D
// $OEM$\E
// .
// .
// .
// $OEM$\Z
//
//
wcscpy((PWSTR)TemporaryBuffer, SourceDevicePath);
SpConcatenatePaths( (PWSTR)TemporaryBuffer, PreinstallOemSourcePath );
r = wcsrchr( (PWSTR)TemporaryBuffer, (WCHAR)'\\' );
if( r != NULL ) {
*r = (WCHAR)'\0';
}
SpConcatenatePaths( (PWSTR)TemporaryBuffer, L"\\C" );
r = SpDupStringW((PWSTR)TemporaryBuffer);
s = wcsrchr( r, (WCHAR)'\\' );
s++;
Drive[1] = (WCHAR)':';
Drive[2] = (WCHAR)'\0';
for( Drive[0] = (WCHAR)'C'; Drive[0] <= (WCHAR)'Z'; Drive[0] = Drive[0] + 1) {
//
// If the subdirectory $OEM$\<drive letter> exists on the source,
// and if there is a FAT or NTFS partition in the target machine that
// has the same drive letter specification, then tree copy
// $OEM$\<drive letter> to the corresponding partition in the target
// machine.
//
*s = Drive[0];
if( SpFileExists( r, TRUE ) ) {
if( ( ( TargetRegion = SpRegionFromDosName( Drive ) ) != NULL ) &&
TargetRegion->PartitionedSpace &&
( ( TargetRegion->Filesystem == FilesystemFat ) ||
( TargetRegion->Filesystem == FilesystemNtfs ) )
) {
SpNtNameFromRegion( TargetRegion,
(PWSTR)TemporaryBuffer,
sizeof(TemporaryBuffer),
PartitionOrdinalCurrent );
t = SpDupStringW((PWSTR)TemporaryBuffer);
SpCopyDirRecursive( r,
t,
L"" );
SpMemFree( t );
}
}
}
SpMemFree( r );
//
// Merge %SystemRoot%\$$rename.txt with $$rename.txt in the root of the
// NT partition.
//
SppMergeRenameFiles( SourceDevicePath, NtPartition, Sysroot );
}
VOID
SppMergeRenameFiles(
IN PWSTR SourceDevicePath,
IN PWSTR NtPartition,
IN PWSTR Sysroot
)
/*++
Routine Description:
This routine recursively copies a src directory to a destination directory.
Arguments:
SourceDevicePath: Path to the device that contains the source.
NtPartition: Path to the drive that contains the system.
Systroot: Directory where the system is installed.
Return Value:
None.
--*/
{
PWSTR r, s;
PDISK_REGION TargetRegion;
NTSTATUS Status;
PVOID RootRenameFile;
PVOID SysrootRenameFile;
ULONG ErrorLine;
ULONG SectionCount;
ULONG LineCount;
ULONG i,j;
PWSTR SectionName;
PWSTR NewSectionName;
PWSTR KeyName;
PWSTR Values[1];
PFILE_TO_RENAME File;
//
// Build the ful path to %sysroot%\$$rename.txt
//
wcscpy((PWSTR)TemporaryBuffer, NtPartition);
SpConcatenatePaths( (PWSTR)TemporaryBuffer, Sysroot );
SpConcatenatePaths( (PWSTR)TemporaryBuffer, WINNT_OEM_LFNLIST_W );
s = SpDupStringW((PWSTR)TemporaryBuffer);
//
// Load %sysroot%\$$rename.txt, if one exists
//
if( SpFileExists( s, FALSE ) ) {
//
// Load Sysroot\$$rename.txt
//
Status = SpLoadSetupTextFile( s,
NULL,
0,
&SysrootRenameFile,
&ErrorLine );
if( !NT_SUCCESS( Status ) ) {
KdPrint(("SETUP: Unable to load file %ws. Status = %lx \n", s, Status ));
goto merge_rename_exit;
}
} else {
SysrootRenameFile = NULL;
}
//
// If there is a $$rename.txt on sysroot, then it needs to be merged
// (or appended) to the one in the NtPartition.
// If RenameList is not empty, then the files in this list need to be
// added to $$rename.txt on the NtPartition.
// Otherwise, don't do any merge.
//
if( ( SysrootRenameFile != NULL )
|| ( RenameList != NULL )
) {
//
// Find out if the NtPartition contains a $$rename.txt
//
wcscpy((PWSTR)TemporaryBuffer, NtPartition);
SpConcatenatePaths( (PWSTR)TemporaryBuffer, WINNT_OEM_LFNLIST_W );
r = SpDupStringW((PWSTR)TemporaryBuffer);
if( !SpFileExists( r, FALSE ) ) {
//
// If the NT partition doesn't contain $$rename.txt, then
// create a new $$rename.txt in memory
//
RootRenameFile = SpNewSetupTextFile();
if( RootRenameFile == NULL ) {
KdPrint(("SETUP: SpNewSetupTextFile() failed \n"));
if( SysrootRenameFile != NULL ) {
SpFreeTextFile( SysrootRenameFile );
}
SpMemFree( r );
goto merge_rename_exit;
}
} else {
//
// Load $$rename on the NTPartition
//
Status = SpLoadSetupTextFile( r,
NULL,
0,
&RootRenameFile,
&ErrorLine );
if( !NT_SUCCESS( Status ) ) {
KdPrint(("SETUP: Unable to load file %ws. Status = %lx \n", r, Status ));
if( SysrootRenameFile != NULL ) {
SpFreeTextFile( SysrootRenameFile );
}
SpMemFree( r );
goto merge_rename_exit;
}
}
if( SysrootRenameFile != NULL ) {
//
// Add the section of Sysroot\$$rename.txt to $$rename.txt in memory
// Note that we need to prepend Sysroot to the section name
//
SectionCount = SpCountSectionsInFile( SysrootRenameFile );
for( i = 0; i < SectionCount; i++ ) {
SectionName = SpGetSectionName( SysrootRenameFile, i );
if( SectionName != NULL ) {
wcscpy((PWSTR)TemporaryBuffer, L"\\");
SpConcatenatePaths( (PWSTR)TemporaryBuffer, Sysroot);
SpConcatenatePaths( (PWSTR)TemporaryBuffer, SectionName );
NewSectionName = SpDupStringW((PWSTR)TemporaryBuffer);
LineCount = SpCountLinesInSection( SysrootRenameFile, SectionName );
for( j = 0; j < LineCount; j++ ) {
KeyName = SpGetKeyName( SysrootRenameFile, SectionName, j );
Values[0] = SpGetSectionKeyIndex( SysrootRenameFile, SectionName, KeyName, 0 );
SpAddLineToSection( RootRenameFile,
NewSectionName,
KeyName,
Values,
1 );
}
SpMemFree( NewSectionName );
}
}
//
// $$rename.txt on Sysroot is no longer needed
//
SpFreeTextFile( SysrootRenameFile );
SpDeleteFile( s, NULL, NULL );
}
//
// Add the files in RenameList to \$$rename.txt
//
if( RenameList != NULL ) {
do {
File = RenameList;
RenameList = File->Next;
Values[0] = File->TargetFilename;
SpAddLineToSection( RootRenameFile,
File->TargetDirectory,
File->SourceFilename,
Values,
1 );
SpMemFree( File->SourceFilename );
SpMemFree( File->TargetFilename );
SpMemFree( File->TargetDirectory );
SpMemFree( File );
} while( RenameList != NULL );
}
//
// Create a new \$$rename.txt
//
SpWriteSetupTextFile( RootRenameFile, r, NULL, NULL );
//
// $$rename.txt on memory is no longer needed
//
SpFreeTextFile( RootRenameFile );
}
merge_rename_exit:
SpMemFree( s );
}