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.
 
 
 
 
 
 

804 lines
18 KiB

#include "precomp.h"
#pragma hdrstop
WCHAR ValidHardDriveLetters[27];
unsigned ValidHardDriveLetterCount;
VOID
BuildValidHardDriveList(
VOID
)
/*++
Routine Description:
Determine all valid hard drives, and build up several global
variables that can be used later to optimize the determination
of whether a drive letter represents a valid hard drive.
Arguments:
None.
Return Value:
None.
ValidHardDriveLetters, ValidHardDriveLetterCount
global variables filled in.
--*/
{
WCHAR Drive;
unsigned n;
n = 0;
for(Drive=L'A'; Drive<=L'Z'; Drive++) {
if(IsHardDrive(Drive)) {
ValidHardDriveLetters[n++] = Drive;
}
}
ValidHardDriveLetters[n] = 0;
ValidHardDriveLetterCount = n;
}
BOOL
IsHardDrive(
IN WCHAR DriveLetter
)
/*++
Routine Description:
Determine whether a drive is a hard drive. This includes removable media
hard drives such as MO drives.
Arguments:
DriveLetter - supplies a drive letter for a drive to check.
Return Value:
TRUE if the drive is a hard drive. FALSE if not or an error occurs.
--*/
{
WCHAR DriveRoot[7];
HANDLE Device;
BOOL b;
NTSTATUS Status;
FILE_FS_DEVICE_INFORMATION DeviceInfo;
IO_STATUS_BLOCK IoStatusBlock;
//
// If we already know, tell the user.
//
if(ValidHardDriveLetterCount) {
return(wcschr(ValidHardDriveLetters,UPPER(DriveLetter)) != NULL);
}
wsprintf(DriveRoot,L"%c:\\",DriveLetter);
switch(GetDriveType(DriveRoot)) {
case DRIVE_FIXED:
//
// Definitely a hard drive.
//
b = TRUE;
break;
case DRIVE_REMOVABLE:
//
// Maybe a hard drive and maybe a floppy.
// Open the device for query access.
//
wsprintf(DriveRoot,L"\\\\.\\%c:",DriveLetter);
Device = CreateFile(
DriveRoot,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(b = (Device != INVALID_HANDLE_VALUE)) {
//
// Unfortunately we have to resort to NT APIs because there is no
// straightforward way to tell with Win32 IOCTLs. The query media types
// ioctl fails on hard drives and the get geometry one spins up
// floppy drives.
//
Status = NtQueryVolumeInformationFile(
Device,
&IoStatusBlock,
&DeviceInfo,
sizeof(DeviceInfo),
FileFsDeviceInformation
);
if(b = NT_SUCCESS(Status)) {
b = ((DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) == 0);
}
CloseHandle(Device);
}
break;
default:
//
// Definitely not a hard drive.
//
b = FALSE;
break;
}
return(b);
}
DWORD
AppendFile(
IN HANDLE TargetFile,
IN PCWSTR File,
IN BOOL DeleteIfSuccessful,
OUT PDWORD FileSize
)
/*++
Routine Description:
Append one file to another.
Arguments:
TargetFile - supplies an open win32 handle to an existing file
to be appended to. The file pointer position of this file
is NOT preserved.
File - supplies the win32 path of an existing file to append to
TargetFile. The file must exist and cannot be 0-length.
DeleteIfSuccessful - if successful, delete the file that was appended
to TargetFile.
FileSize - receives size of file named by the File parameter.
Return Value:
Win32 error code indicating outcome.
--*/
{
HANDLE hFile;
HANDLE hFileMapping;
DWORD fileSize;
PVOID BaseAddress;
DWORD rc;
DWORD Written;
//
// Seek to end of target file in preparation for appending.
//
if(SetFilePointer(TargetFile,0,NULL,FILE_END) == 0xffffffff) {
return(GetLastError());
}
//
// Map in the source file.
//
rc = OpenAndMapFileForRead(
File,
&fileSize,
&hFile,
&hFileMapping,
&BaseAddress
);
if(rc != NO_ERROR) {
return(rc);
}
//
// Write the file to the end of the target file.
// Guard against in-page exceptions.
//
try {
rc = WriteFile(TargetFile,BaseAddress,fileSize,&Written,NULL)
? NO_ERROR
: GetLastError();
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Error paging in from the source.
//
rc = ERROR_READ_FAULT;
}
UnmapAndCloseFile(hFile,hFileMapping,BaseAddress);
if(rc == NO_ERROR) {
if(DeleteIfSuccessful) {
DeleteFile(File);
}
*FileSize = fileSize;
}
return(rc);
}
DWORD
MapPartOfFileForRead(
IN HANDLE FileHandle,
IN HANDLE FileMapping,
IN DWORD Offset,
IN DWORD Size,
OUT PVOID *BaseAddress,
OUT PVOID *DataAddress
)
/*++
Routine Description:
Map a section of a file for read access.
Arguments:
FileHandle - supplies Win32 file handle for file to map.
Must have GENERIC_READ access.
FileMapping - supplies a file mapping handle that spans the
entire file. The mapping must be fore PAGE_READONLY access.
Offset - supplies offset within the file where mapping is to begin.
Size - supplies size of region to be mapped.
BaseAddress - if the function is successful, receives a pointer to
a base address where a section of the file has been mapped in.
This may not be where the desired data actually starts because
file mappings must be aligned properly.
DataAddress - if the function is successful, receives a pointer to
the location in memory where the caller can find the data in
the file at the given offset.
Return Value:
Win32 error code indicating outcome.
--*/
{
SYSTEM_INFO SystemInfo;
DWORD pad;
PVOID mapAddress;
//
// The offset for file mappings must be on a system allocation
// boundary. Calculate a pad value, which is for some extra bytes
// that will be mapped from the start of such a boundary to the
// actual offset of the desired region in the file.
//
GetSystemInfo(&SystemInfo);
pad = Offset % SystemInfo.dwAllocationGranularity;
//
// We need to map 'pad' extra bytes at an adjusted offset.
//
mapAddress = MapViewOfFile(
FileMapping,
FILE_MAP_READ,
0,
Offset-pad,
Size+pad
);
if(!mapAddress) {
return(GetLastError());
}
//
// Success. Fill in caller values and return.
//
*BaseAddress = mapAddress;
*DataAddress = (PUCHAR)mapAddress+pad;
return(NO_ERROR);
}
PWSTR
DuplicateUnalignedString(
IN WCHAR UNALIGNED *String
)
/*++
Routine Description:
Make a duplicate of a nul-terminated unicode string, which may
not be properly aligned. The copy is aligned.
Arguments:
String - supplies pointer to nul-terminated unicode string.
Return Value:
Copy of string, or NULL if OOM.
--*/
{
UINT Size;
WCHAR UNALIGNED *p;
WCHAR UNALIGNED *q;
PWSTR s;
//
// Locate the end of the string.
//
for(p=q=String; *q; q++) ;
//
// Calculate the size of the string in bytes.
//
Size = (q-p+1) * sizeof(WCHAR);
//
// Allocate a buffer and copy the string in.
//
if(s = _MyMalloc(Size)) {
CopyMemory(s,p,Size);
}
return(s);
}
int
CompareMultiLevelPath(
IN PCWSTR p1,
IN PCWSTR p2
)
/*++
Routine Description:
Compare two path strings. Each successive component of the paths
is lexically compared via lstrcmpi until a mismatch is found or
the end of one of the paths is found.
Arguments:
p1 - supplies first path to compare. Any leading \ is skipped.
p2 - supplies second path to compare. Any leading \ is skipped.
Return Value:
Same as lstrcmpi().
--*/
{
int i;
PWCHAR q1,q2;
WCHAR s1[MAX_PATH];
WCHAR s2[MAX_PATH];
if(*p1 == L'\\') {
p1++;
}
if(*p2 == L'\\') {
p2++;
}
i = 0;
while(!i && *p1 && *p2) {
q1 = wcschr(p1,L'\\');
if(!q1) {
q1 = wcschr(p1,0);
}
q2 = wcschr(p2,L'\\');
if(!q2) {
q2 = wcschr(p2,0);
}
//
// Note that we have to add 1 to n for lstrcpyn
// because that API always nul-terminates and we don't
// want to overwrite the last char of the copy of the components
// we're copying.
//
lstrcpyn(s1,p1,(q1-p1)+1);
lstrcpyn(s2,p2,(q2-p2)+1);
i = lstrcmpi(s1,s2);
//
// Advance pointers; skip \ if necessary.
//
if(!i) {
p1 = q1;
if(*p1) {
p1++;
}
p2 = q2;
if(*p2) {
p2++;
}
}
}
//
// Check termination. If one path simply has some extra components
// then it is deemed greater.
//
if(!i) {
if(*p1 && !*p2) {
i = 1;
} else {
if(!*p1 && *p2) {
i = -1;
}
}
}
return(i);
}
DWORD
CreatePathWithSFNs(
IN PCWSTR ShortPathSpec,
IN UINT RootRelativePathOffset,
IN PCWSTR PathSpec,
IN PCWSTR RenameListFile
)
/*++
Routine Description:
Create a multi-level directory structure. As each level is created,
a rename list is updated to map the name used into an alias. This is
useful to create a path using SFNs that is suitable for use with
OEM preinstall.
Arguments:
ShortPathSpec - supplies path to be created. The final component is
assumed to be a filename and is not created as a directory.
RootRelativePathOffset - supplies offset in chars within ShortPathSpec
of the start of the path of the file relative to the root of the
drive that the file was originally located on.
PathSpec - supplies path equivalent to ShortPathSpec, but using
LFNs.
RenameListFile - supplies the name of the file that is to contain
SFN/LFN rename information.
Return Value:
Win32 error code indicating outcome.
--*/
{
WCHAR Sfn[MAX_PATH],Lfn[MAX_PATH];
PWCHAR pS,pL;
PWCHAR qS,qL;
BOOL End;
DWORD rc;
WCHAR QuotedLFN[MAX_PATH+2];
lstrcpyn(Sfn,ShortPathSpec,MAX_PATH);
lstrcpyn(Lfn,PathSpec,MAX_PATH);
//
// Figure out the drive part of the name and skip past first path sep
// in the name.
// We allow 2 types of drivespec: x:\ and \\server\share.
//
if((Sfn[0] == L'\\') && (Sfn[1] == L'\\')) {
//
// Make sure LFN is in sync
//
MYASSERT((Lfn[0] == L'\\') && (Lfn[1] == L'\\'));
if((Lfn[0] != L'\\') || (Lfn[1] != L'\\')) {
return(ERROR_INVALID_NAME);
}
//
// Find path sep for sharename
//
pS = wcschr(Sfn+2,L'\\');
pL = wcschr(Lfn+2,L'\\');
MYASSERT(pS && pL);
if(!pS || !pL) {
return(ERROR_INVALID_NAME);
}
//
// Find next path sep, which is the start of the path/filename.
//
pS = wcschr(pS+1,L'\\');
pL = wcschr(pL+1,L'\\');
MYASSERT(pS && pL && pS[1] && pL[1]);
if(!pS || !pL || !pS[1] || !pL[1]) {
return(ERROR_INVALID_NAME);
}
pS++;
pL++;
} else {
MYASSERT((Sfn[1] == L':') && (Sfn[2] == L'\\') && Sfn[3]);
MYASSERT((Lfn[1] == L':') && (Lfn[2] == L'\\') && Lfn[3]);
if((Sfn[1] != L':') || (Sfn[2] != L'\\') || !Sfn[3]
|| (Lfn[1] != L':') || (Lfn[2] != L'\\') || !Lfn[3]) {
return(ERROR_INVALID_NAME);
}
pS = Sfn+3;
pL = Lfn+3;
}
rc = NO_ERROR;
End = FALSE;
do {
//
// Find the end of this component in the SFN.
// This delineates the full short path of the directory
// to be created on this iteration.
// Also locate the analogous end of the LFN.
//
if(qS = wcschr(pS,L'\\')) {
qL = wcschr(pL,L'\\');
MYASSERT(qL);
*qS = 0;
*qL = 0;
} else {
End = TRUE;
qS = wcschr(pS,0);
qL = wcschr(pL,0);
}
//
// If the SFN and LFN for this component are not the same
// then we need to write a rename item in the directory
// where this component is to be created.
//
if(lstrcmp(pS,pL)) {
//
// The section to use is the relative path of the
// directory in which this directory is being created.
//
*(pS-1) = 0;
//
// Extract the LFN for this component and quote it.
//
wsprintf(QuotedLFN,L"\"%s\"",pL);
//
// Write the item to the change list
// via the profile APIs.
//
if(WritePrivateProfileString(Sfn+RootRelativePathOffset,pS,QuotedLFN,RenameListFile)) {
*(pS-1) = L'\\';
} else {
End = TRUE;
rc = GetLastError();
}
}
//
// Now create this component, if it's not the filename.
//
if(!End) {
if(!CreateDirectory(Sfn,NULL)) {
rc = GetLastError();
if(rc == ERROR_ALREADY_EXISTS) {
rc = NO_ERROR;
} else {
End = TRUE;
}
}
}
//
// Restore path seps and advance pointers.
//
if(!End) {
*qS = L'\\';
*qL = L'\\';
pS = qS+1;
pL = qL+1;
}
} while(!End);
return(rc);
}
VOID
FilePathToOemPath(
IN PSYSDIFF_FILE DiffHeader,
IN PCWSTR OemRoot,
IN PCWSTR FileDirectory,
IN PCWSTR FileName,
OUT PWSTR FullTargetName,
OUT PUINT RootRelativePathOffset, OPTIONAL
OUT PWSTR RenameListFile OPTIONAL
)
/*++
Routine Description:
Translates a full pathname into the full pathname suitable for use
in an OEM preinstall server directory structure.
That directory structure is as follows:
$OEM$\$$
C
D
etc.
The $$ directory represents an NT sysroot.
The $OEM$\x directories reperesent the root directories of drive x.
Arguments:
DiffHeader - supplies header from a sysdiff package file.
Used to determine the relevent sysroot.
OemRoot - supplies directory where OEM tree structure is to be located.
The $OEM$ directory and the rest of the structure is
expected to go there.
FileDirectory - supplies full path of directory where file would be
applied with sysdiff /apply.
FileName - supplies name of file.
FullTargetName - receives location where file should be copied in order
to place it correctly in the OEM directory structure.
RootRealtivePathOffset - if specfied, receives the offset within
FullTargetName of the pathname of the file as it originally
appears on the system where the diff was carried out.
RenameListFile - if specified, receives the name of the file that will
contain rename information (ie, SFN to LFN mappings). The buffer
should be large enough to hold MAX_PATH unicode characters.
Return Value:
None.
--*/
{
int u;
WCHAR Drive[2];
DWORD rc;
//
// Some of the path is common regardless of where the
// file goes.
//
lstrcpy(FullTargetName,OemRoot);
ConcatenatePaths(FullTargetName,WINNT_OEM_DIR,MAX_PATH,NULL);
//
// If the file path indicates that the file is in the system dir,
// then the dir is $WINNT$. Otherwise it goes in the per-drive root
// directory structure.
//
u = lstrlen(DiffHeader->Sysroot);
if((lstrlen(FileDirectory) > u)
&& (FileDirectory[u] == L'\\')
&& !_wcsnicmp(FileDirectory,DiffHeader->Sysroot,u)) {
ConcatenatePaths(FullTargetName,WINNT_OEM_FILES_SYSROOT,MAX_PATH,NULL);
if(RootRelativePathOffset) {
*RootRelativePathOffset = lstrlen(FullTargetName) + 1;
}
if(RenameListFile) {
lstrcpy(RenameListFile,FullTargetName);
ConcatenatePaths(RenameListFile,WINNT_OEM_LFNLIST,MAX_PATH,NULL);
}
ConcatenatePaths(FullTargetName,FileDirectory+u,MAX_PATH,NULL);
} else {
Drive[0] = UPPER(FileDirectory[0]);
MYASSERT((Drive[0] >= L'A') && (Drive[0] <= L'Z'));
MYASSERT(FileDirectory[1] == L':');
MYASSERT(FileDirectory[2] == L'\\');
Drive[1] = 0;
ConcatenatePaths(FullTargetName,Drive,MAX_PATH,NULL);
if(RootRelativePathOffset) {
*RootRelativePathOffset = lstrlen(FullTargetName);
}
if(RenameListFile) {
lstrcpy(RenameListFile,FullTargetName);
ConcatenatePaths(RenameListFile,WINNT_OEM_LFNLIST,MAX_PATH,NULL);
}
ConcatenatePaths(FullTargetName,FileDirectory+3,MAX_PATH,NULL);
}
//
// Stick the filename on there.
//
ConcatenatePaths(FullTargetName,FileName,MAX_PATH,NULL);
}
DWORD
WriteUnicodeMark(
IN HANDLE Handle
)
/*++
Routine Description:
Writes the Unicode byte order mark into a file at the current position.
Arguments:
Handle - supplies handle to open file.
Return Value:
Win32 error code indicating outcome.
--*/
{
UCHAR UnicodeMark[2];
DWORD d;
UnicodeMark[0] = 0xff;
UnicodeMark[1] = 0xfe;
return(WriteFile(Handle,UnicodeMark,2,&d,NULL) ? NO_ERROR : GetLastError());
}